For Developers
Add custom modules and embed Tween Sequences in your own components
Assembly References
The core namespace and assembly are both Evo.Tween. If your code uses an assembly definition, add a reference to the core and any module assemblies it calls:
| Assembly | Bindings |
|---|---|
Evo.Tween | Core API, Transforms, audio, standard rendering, physics, and video. |
Evo.Tween.Modules.UGUI | RectTransform, CanvasGroup, and Unity UI. |
Evo.Tween.Modules.TMP | TextMeshPro. |
Evo.Tween.Modules.EvoUI | Procedural Shapes and Evo UI interaction integration. |
Evo.Tween.Modules.RenderPipelines | Render pipeline Volumes. |
Keep editor integrations in an Editor assembly. The Timeline Window and recording interfaces live in Evo.Tween.Editor.
Add a Custom Module
For a single value, derive from a base such as FloatModule<TTarget>, Vector2Module<TTarget>, Vector3Module<TTarget>, ColorModule<TTarget>, IntModule<TTarget>, or BoolModule<TTarget> in Evo.Tween.Modules.
These bases already handle From Current, explicit values, interpolation, and restoration. Add [Serializable] and [ModuleMenu("Category/Name")] to expose the concrete module in the clip menu.
using System;
using UnityEngine;
using Evo.Tween;
using Evo.Tween.Modules;
[Serializable]
[ModuleMenu("Custom/Audio Low Pass/Cutoff")]
public sealed class LowPassCutoffModule : FloatModule<AudioLowPassFilter>
{
protected override float Read() => Target.cutoffFrequency;
protected override void Write(float value)
{
Target.cutoffFrequency = Mathf.Clamp(value, 10f, 22000f);
}
}After Unity compiles the script, choose Custom -> Audio Low Pass -> Cutoff from the clip menu. Assign an AudioLowPassFilter or leave the clip target empty to resolve one on the owner.
The module also works with the code API:
TweenHandle handle = EvoTween.Create(22000f, 800f, 0.5f)
.Bind<LowPassCutoffModule>(filter);Implement a Custom Lifecycle
Derive directly from TweenModule when your behavior doesn't fit a single-value base.
| Member | Purpose |
|---|---|
TargetType | Component type accepted by the module. |
OnCapture() | Caches runtime references and the values needed for restoration. Return false if the target can't be animated. |
OnStart() | Optional hook when the clip actually begins, after its delay. |
OnEvaluate(float easedTime) | Applies the animation. Eased time can overshoot the usual 0–1 range. |
OnRestore() | Restores captured values for preview or explicit restoration. |
OnRelease() | Clears runtime references without resetting the displayed result. |
Use CapturedTarget, Duration, and NormalizedTime in these hooks. Keep runtime-only state non-serialized. Use ModuleField attributes to group serialized values and identify From Current, From, and Target controls; unannotated fields appear under Settings.
The default Clone() copies serialized fields. Override it when mutable reference data needs an independent deep copy. Custom modules aren't automatically allocation-free: review their cloning and lifecycle work, then profile them. Built-in value bases support typed configuration copying, while unfamiliar added fields can fall back to cloning.
Implement IValueModule<T> if a direct TweenModule subclass should accept values from EvoTween.Create(...).Bind(target, module). A public parameterless constructor is required for the generic Bind<TModule>(target) overload.
Embed a Sequence
A serialized TweenSequence field lets a component own its animation data. TweenSequenceSampler applies that data at an absolute time without adding a playback clock.
using UnityEngine;
using Evo.Tween;
public class ScrubbableAnimation : MonoBehaviour
{
[SerializeField] private TweenSequence sequence = new();
private TweenSequenceSampler sampler;
private void Awake()
{
sampler = new TweenSequenceSampler(gameObject, sequence, cacheClips: true);
sampler.Prepare();
}
public void SetProgress(float progress)
{
sampler.Sample(sampler.Duration * Mathf.Clamp01(progress));
}
private void OnDisable() => sampler?.Restore();
private void OnDestroy() => sampler?.Dispose();
}Keep the default cloneInlineClips: true unless your sampler exclusively owns the sequence's runtime state. Use Refresh(normalizedTime) after editing prepared definitions. Release() keeps the sampled result; Restore() puts captured values back; Dispose() restores and releases resources.
The Timeline Window can discover serialized sequences on components. From a custom editor, Evo.Tween.Editor.TimelineWindow.Open(component, "sequence") opens a specific serialized property path.
Add Recording Support
Custom playback and preview don't automatically provide property recording. To integrate with the Timeline Window's Record mode, implement ITweenRecordingProvider and supply TweenRecordingBinding entries from an Editor assembly. The included module recording providers show how to identify a property channel, read values, create modules, and set their endpoints.