Library / SDK
annulusgames/LitMotion avatar
annulusgames/LitMotion

annulusgames/LitMotion: a zero-allocation tween library that installs from a git URL

Lightning-fast and Zero Allocation Tween Library for Unity.

2,325 stars163 forksC#MIT

At a glance

What is it?
A Unity tween library built around structs and DOTS packages, with motion handles, sequences, UniTask and R3 integration, and an Inspector package for authoring animations without code. The documented install takes the default branch rather than the newest release tag, and that is worth understanding before you adopt it.
Who is it for?
Adopt LitMotion if per-frame allocation and edit-time playback matter to you, because the struct-based design, the MotionHandle lifecycle and the 128-byte text path are all built around that, and the README states it runs two to twenty times faster than other tween libraries, which is a claim from the author rather than a measurement you can check here.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 13 days ago.
What is it written in?
Mainly C#, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What zero allocation at creation time does to the API shape

The central claim is that creating a tween allocates nothing, and that claim is architectural rather than incremental. It comes from a struct-based design, so a motion is a value rather than an object handed to you, and the implementation is optimised using DOTS packages. The README states the library is two to twenty times faster than other tween libraries, and that no allocation at all happens when creating a tween. Those are the author's figures and they are not independently verifiable from the repository, but the design consequences are visible in the API, which is where the interesting part is. Every motion is built by a chain of With-modifiers and a terminal Bind, and the modifiers are free functions returning a struct rather than method calls on a heap object. That is why the extension points are named IMotionOptions and IMotionAdapter: extending the library means supplying a pair of type parameters to a generic builder, not subclassing something. The trade is a fluent API that cannot take arbitrary callbacks in most positions. You can bind a lambda, and you can be told to cancel on an exception inside the bind, but the shape of a motion is fixed at the type level.

Four requirements, three of them DOTS packages

The requirements list is short enough to seem careless and specific enough to be the real cost. Unity 2021.3 or later, Burst 1.6.0 or later, Collection 1.5.1 or later and Mathematics 1.0.0 or later. For a library whose entire job is moving a value from A to B over two seconds, requiring the compiler, the collections package and the mathematics package is a strong statement about where the speed comes from. The zero-allocation claim and the DOTS dependency are the same decision, and you cannot take one without the other. Practically, this means a project on an older Unity cannot use the library at all, and a project on a modern Unity that has deliberately kept its dependency set small has to accept three more packages for animation. Whether that is a good trade depends entirely on your project, and the case is strongest where a large number of small motions run every frame, which is precisely the scenario the optimisation targets and the one the 128-byte text path and the per-character TextMeshPro example are built for. On a project with twenty animations in a menu, the dependency cost buys nothing you would notice.

The documented install tracks the branch, not the v2.0.2 tag

Installation goes through the Package Manager by adding a package from a git URL, and the alternative is editing Packages/manifest.json directly:

json
{
    "dependencies": {
        "com.annulusgames.lit-motion": "https://github.com/annulusgames/LitMotion.git?path=src/LitMotion/Assets/LitMotion"
    }
}

Look closely at that URL. It selects a subdirectory with the path parameter, which is what makes the package layout inside a larger repository work, and it names no branch, tag or commit. So the package manager resolves the default branch of the repository, which is main, rather than the newest release. The release history is v2.0.0 from 2024-12-25, v2.0.1 from 2025-02-09 and v2.0.2 from 2026-05-10, and the last push was on 2026-09-18, so main has been moving for more than four months past that tag. This is a deliberate trade that many git-installed packages make, and it is defensible: you get fixes without an upgrade step. It also means the version you are running is not the version you would cite in a bug report, and that a breaking change can reach you without a version bump. If you pin, you have to edit the URL to name a tag yourself, which the README does not document. That single line is the most consequential thing in the setup section.

MotionHandle, AddTo, and the destroyed-object problem

Every tween library eventually writes to an object that no longer exists, and this one handles that case explicitly in three separate ways. First, AddTo(gameObject) ties a motion to a GameObject so it is cancelled when the object is destroyed, which is the line that stops the classic null reference in a frame callback. Second, if you do not want a binding, RunWithoutBinding returns a MotionHandle struct, a value you can hold. From that handle you get IsActive() to test whether the motion is still playing, Cancel() to stop it, and Complete() to finish it. Third, completion is awaitable in whatever concurrency model you already use. In a coroutine the handle exposes ToYieldInteraction(); under UniTask you can await the handle directly, or call ToUniTask with a CancellationToken; and if you use R3 or UniRx the library converts motions into observables. That last point is the design argument for the whole library, or at least the part of it that matters most: it does not own your asynchronous model, it adapts into whichever one you picked. A consequence worth noting is that there is a WithCancelOnError modifier, but the README describes it as cancelling when an exception occurs within the bind, so it is not a general safety net for a background failure.

The 128-byte text path and the cost of animating characters one at a time

Text animation is where the allocation claim is either true or fiction, and the library makes the trade visible. Rather than generating strings every frame, the entry point is LMotion.String.Create128Bytes, which takes a fixed 128-byte buffer, and the binding goes to a TextMeshPro text component with rich text enabled and a scramble mode that fills unseen characters at random. The reason is straightforward: building a string per character per frame is exactly the garbage a zero-allocation library is trying to avoid, so the buffer is fixed instead. The consequence is equally straightforward, and the README does not soften it. The buffer is 128 bytes, and the excerpt gives no alternative entry point for longer strings, so a paragraph of text is outside what this path can do without a different approach. The second text example is a cost you pay in code rather than in memory. To animate characters individually you loop over textInfo.characterCount and create one motion per character, each with WithDelay of i times a tenth of a second, one binding the colour and another binding the position. That is two motions per character, so a hundred-character string is two hundred live motions for a typewriter effect. The library makes it possible and the example makes it easy, and neither is free.

Two packages when you want to author animations in the Inspector

Version 2 added two things, and one of them is a separate package. The first is Sequence, for combining multiple motions, exposed as LSequence in the feature list, which is the primitive you were missing if you were chaining motions manually. The second is the LitMotion.Animation package, which exists to create tween animations directly from the Inspector. That is a different product from the runtime library, with a different release cadence and its own articles in the documentation, and a project that wants visual authoring has to take both. The runtime library also has its own Inspector integration, through a generic SerializableMotionSettings type that takes a settings type and an options type, so a motion can be configured in the Inspector and run without a hand-written builder chain. Alongside that there is a LitMotion Debugger window and a debugging API, and the samples directory contains a LitMotion.Samples project. One small signal about the project's centre of gravity: the repository root carries both README.md and README_JA.md, and the documentation site is a GitHub Pages URL, so Japanese is the authoring language and the English README is the translation. That affects who files issues in which language more than it affects the code.

Where this stops being the right choice

The competing options named in the README are the author's previous library, Magic Tween, and two feature peers, DOTween Pro and PrimeTween, against which it claims to be as powerful or more so. The real differences are narrower than that comparison. Magic Tween is the predecessor this one was designed from, so migrating is a rewrite of your call sites rather than an incremental change. DOTween Pro is a commercial asset, and the difference that follows from that is where the code lives: LitMotion is MIT, installs from a git URL, and has an Inspector package you can read. The limits are easier to state than the advantages. If you need long text animation, the 128-byte fixed buffer is a ceiling you will hit. If you are on Unity before 2021.3, it is not available. If you want a released, versioned dependency rather than a moving branch, the documented install will not give you one. And if your project is not running many motions per frame, the Burst, Collections and Mathematics requirements are a cost with no measurable return. The README's own performance claim is scoped to situations involving lots of tweens, and that scoping is the honest version of the pitch.

Editorial conclusion

Adopt LitMotion if per-frame allocation and edit-time playback matter to you, because the struct-based design, the MotionHandle lifecycle and the 128-byte text path are all built around that, and the README states it runs two to twenty times faster than other tween libraries, which is a claim from the author rather than a measurement you can check here. Before you add it, read the install line again, because the documented git URL has no ref and therefore tracks main rather than the v2.0.2 tag, and decide deliberately whether you want that. If your animations involve long text, check the fixed 128-byte buffer limit of the String entry point first. If you need per-editor authoring with a visual timeline, LitMotion.Animation is a separate package, so budget for two dependencies. And if you are on Unity 2021.3 or later with Burst, Collections and Mathematics already in your project, this fits; if you are not, the requirement list is longer than a tween library usually justifies.

Frequently asked questions

How do I install annulusgames/LitMotion in Unity?

Open the Package Manager, use Add package from git URL, and enter https://github.com/annulusgames/LitMotion.git?path=src/LitMotion/Assets/LitMotion. You can also add that URL to the dependencies block in Packages/manifest.json under the name com.annulusgames.lit-motion.

What are the requirements for LitMotion?

Unity 2021.3 or later, Burst 1.6.0 or later, Collection 1.5.1 or later and Mathematics 1.0.0 or later. Three of those four are the DOTS packages the library is optimised with.

Does the LitMotion install give me the latest release tag?

Not by default. The documented git URL names no branch, tag or commit, so the package manager resolves the default branch, which is main. The newest release is v2.0.2 from 2026-05-10 and the last push was 2026-09-18.

How do I cancel a LitMotion tween when a GameObject is destroyed?

Call AddTo(gameObject) on the motion, which cancels it when the object is destroyed. If you do not want a binding, RunWithoutBinding returns a MotionHandle, and that handle offers IsActive(), Cancel() and Complete().

Is LitMotion compatible with UniTask and UniRx?

The feature list states async and await support through UniTask, including awaiting a MotionHandle directly or calling ToUniTask with a CancellationToken, and conversion to observables through UniRx or R3. Coroutines are also supported through ToYieldInteraction.

Official sources

  1. annulusgames/LitMotion on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/annulusgames-litmotion.svg)](https://hysenlabs.com/projects/annulusgames-litmotion)