vibed with codex 5.5
Created this for situations where you want to give something an animation, but animation clips and animators felt too bulky.
Jiggle an object in a satisfying way when the player hovers it.
This is great for that.
Recording.2026-06-05.195552.mp4
The object is just a handful of animations curves, so the main lift was creating a nice editor to make authoring these curves not such a chore.
I tried to have roughly the same feature set as the multi-curve-editor featured in Unity's particle systems.
You can play the curves targeting a transform.
public CurveClip clip;
public CurveClipPlayback playback;
public void ThingHappened()
{
playback = clip.Play(transform);
}
public void CancelTheThing()
{
playback.Cancel()
}You can play multiple clips on a single transform and they will additively mix.
public void CancelAllClips()
{
CurveClip.Cancel(transform);
}
It's important to note that position can't be normalized across objects as simply as rotation & scale. How should a bounce on the Y axis behave across many differently size and shaped objects?
For this a few methods to scale the position curves are provided.
// scale the position curves by a flat value
clip.Play(transform, 2f);
// scale the position curves individually
clip.Play(transform, new Vector3(1f, 2f, 1f));
// scale the position curves based on the bounds of a renderer
clip.Play(transform, renderer);
// scale the position curves based on the bounds of all renderers on a gameObject
clip.Play(transform, gameObject);Custom curve values are delivered through a sample callback:
clip.Play(transform, sample =>
{
foreach (CustomCurveSample custom in sample.CustomCurves)
Debug.Log($"{custom.Name} = {custom.Value}");
});sample.CustomCurves is a pooled list that is only valid for the duration of the callback. Copy the values out if you need to keep them.
- Clips are advanced by a single hidden runner
MonoBehaviour; there are no coroutines. - Per-frame sampling is allocation free. Each playback borrows one custom curve list from Unity's
ListPooland returns it when the playback ends. CurveClip.Evaluate(float)allocates a fresh list for convenience. UseEvaluate(float, List<CustomCurveSample>)on hot paths, or passnullto skip custom curves.- Playback objects are still allocated per
Playcall. Should eventually pool those inline with howhttps://github.com/Less3Design/L3-tweenworks