Namespace Serenity.Editor.AnimationHub.Engine
Classes
AnimationClipBindingCatalog
Wraps UnityEditor.AnimationUtility.GetAnimatableBindings(UnityEngine.GameObject,UnityEngine.GameObject) to answer "what could I bind next on this ONE
GameObject" for the add-binding affordance in the curve editor. Deliberately scoped to a single target
rather than the whole character hierarchy: GetAnimatableBindings called with the hierarchy root as
its own target returns every animatable property on every descendant — thousands of candidates for a
rigged character — which is useless as a flat picker. The caller instead re-enumerates per selected
GameObject (a transform picked in the scene or a hierarchy tree), and this type gets to cache each of
those single-target queries instead of re-walking Unity's reflection-based animatable-property scan
every time the picker repaints.
AnimationClipBindingLabels
Maps a curve binding's raw propertyName (as Unity persists it, e.g. "m_LocalPosition.x" or
"blendShape.Smile") to a human-readable group and axis for display. Pure string mapping, no Unity
dependency beyond the plain string in, AnimationClipBindingLabels.Label out contract — every input is a
value already read off a real binding elsewhere, so this type never needs to touch an asset itself.
The curve-name normalization lesson from ModelClipCreatorTests is the source of the exact strings
this maps from: Unity persists localScale.x as m_LocalScale.x, and a rotation curve as
localEulerAnglesRaw.*.
AnimationClipBindingLabels.Label
One property's display label — get-only, constructor-built, the same DTO idiom every other hub result type uses.
AnimationClipCopyEngine
"Make Editable Copy": duplicates an UnityEngine.AnimationClip that cannot be edited in place (an
FBX-embedded clip, or any clip AnimationClipEditability otherwise blocks) out to a
standalone .anim asset, then — optionally — repoints every state and blend tree in an
UnityEditor.Animations.AnimatorController that used the source clip to the new copy via
ReplaceMotion(AnimatorController, Motion, Motion). Shares the Input/SerenityCreationValidationResult/Result triple
and Serenity.Global.Infrastructure.Editor.SerenityAssetCreationTransaction rollback idiom
ModelClipCreator and
Serenity.GameSave.Infrastructure.Editor.Builder.GameSaveCreator already establish; this supersedes
ModelClipCreator.DuplicateEmbeddedClip/DuplicateClip for the clip-editor flow specifically
because it also closes the rewire gap those two leave open — after a plain duplicate, every state that
used to play the original still does, and the new copy sits unused until someone rewires it by hand.
AnimationClipCopyEngine.Input
Everything Create(Input) needs.
AnimationClipCopyEngine.Result
Outcome of Create(Input).
AnimationClipCurveEditingEngine
Curve-level CRUD over an UnityEngine.AnimationClip's bindings: a display-friendly read of every bound property (ReadBindings(AnimationClip)), whole-curve reads and writes, and individual key edits. Every mutation runs inside an AnimationClipEditScope, mirroring the undo/dirty bracketing Write(AnimationClip, ClipSettingsView, string) already established for the settings block — the caller remains responsible for UnityEditor.AssetDatabase.SaveAssets once its own gesture is done.
AnimationClipCurveEditingEngine.AddBindingInput
AnimationClipCurveEditingEngine.AddBindingResult
AnimationClipCurveEditingEngine.KeyEditResult
AnimationClipCurveEditingEngine.Result
AnimationClipCurveEditingEngine.WriteCurveInput
AnimationClipEditScope
One user gesture's worth of undo/dirty bracketing around a native curve mutation on an
UnityEngine.AnimationClip. Uses UnityEditor.Undo.RegisterCompleteObjectUndo(UnityEngine.Object,System.String)
deliberately instead of UnityEditor.Undo.RecordObject(UnityEngine.Object,System.String): the AnimationUtility.SetEditorCurve family
mutates the clip's native serialized curve data in one bulk native call, entirely outside the small set of
managed fields RecordObject's diff recorder tracks between a "record" and a later modification — only
RegisterCompleteObjectUndo's full-object snapshot actually captures the before/after state those
calls produce. Write(AnimationClip, ClipSettingsView, string) already established this same idiom for the
clip's settings block; every curve-mutating call in AnimationClipCurveEditingEngine wraps
itself in exactly one of these scopes — one scope per user gesture, never shared across several.
AnimationClipEditability
Decides whether an UnityEngine.AnimationClip's curves can be written from inside the hub, and why not
when they cannot. Evaluate(string, HideFlags, bool, bool, bool) is the pure seam — a plain
decision table over five facts, with no AssetDatabase or UnityEditor access — so the same
rules run in a plain NUnit test as they do against a real asset through the
Evaluate(AnimationClip) overload, the same split ModelAnimationValidator
draws between its pure rules and the scanner that gathers their inputs.
AnimationClipPreviewSampling
Pure decision logic behind AnimationClipPreviewScrubber's per-repaint sampling: whether a resample
is due, where the playhead clamps to, and how well the previewed instance's hierarchy actually covers the
clip's authored binding paths. Kept free of UnityEngine.Object.Instantiate(UnityEngine.Object)/SampleAnimation
so the decision itself stays testable without a live preview session.
AnimationClipSettingsEngine
Reads and writes the settings block of an UnityEngine.AnimationClip — frame rate, loop behavior,
cycle offset, start/stop trim, wrap mode and (read-only) length and legacy status — plus its animation
events, mirroring the same read/write split ModelClipCreator
draws between validating an Input and mutating an asset.
AnimatorControllerClipRewirer
Repoints every reference to one UnityEngine.Motion inside an UnityEditor.Animations.AnimatorController to another
— the controller-side half of "Make Editable Copy" (see AnimationClipCopyEngine, which
creates the standalone copy and calls into this type before committing). Walks every layer's state
machine at arbitrary nesting depth, and every blend tree at arbitrary nesting depth, the same recursive
shapes ModelAnimationScanner.CollectStatesAndTransitions and
ModelAnimationScanner.CollectBlendTreeClips already use to read this exact structure.
FindStatesUsing(AnimatorController, Motion) is the read-only counterpart for a "3 states use this clip" banner before
a caller commits to a rewire.
BindingView
One curve binding's read-only display facts, built once per ReadBindings(AnimationClip)
call — the same constructor-built, get-only DTO idiom Verdict and ClipSettingsView already use.
Candidate
One animatable-but-not-yet-bound property on a target GameObject, ready to hand to AddBinding(AddBindingInput) — the same constructor-built, get-only DTO idiom BindingView already uses for the bindings that DO exist on a clip.
ClipSettingsView
Reads as a flat, editor-friendly view of an UnityEngine.AnimationClip's settings.
ProceduralStateKeyCollector
Enumerates every UnityStateKey a ProceduralAnimatorProfileSO references,
across its rules, layers, actions and weight providers — including keys buried inside a rule's
[SerializeReference] condition tree (AndCondition/OrCondition/NotCondition nesting
arbitrarily deep). A typed walk would need one case per condition subtype and would silently miss a new
one added later; instead each referenced object is walked with UnityEditor.SerializedObject and
UnityEditor.SerializedProperty.Next(System.Boolean), which finds every UnityEditor.SerializedPropertyType.ObjectReference
field regardless of what serialized it — [SerializeReference] included — for free.
RewireResult
Outcome of ReplaceMotion(AnimatorController, Motion, Motion) — which states and blend trees were actually repointed, or why nothing was touched at all.
Verdict
Outcome of an editability check — constructor-built and get-only, the same DTO idiom ClipEntry and ModelClipCreator.Result already use.
Structs
ProceduralStateKeyBinding
One UnityStateKey asset a profile reads, with its display name and effective value range — the shape an in-hub simulator's slider UI needs, one row per key.
StateKeyPulse
Pure math behind the state-key simulator's "Pulse" button: replays the same 0-1-0 parabolic arc gameplay controllers write onto a pulse-style state key over a traversal (e.g. RailShooter's EnemyBehaviorController driving an airborne/roll/hit key), so the simulator reproduces real gameplay timing — a slow manual slider drag cannot cross a TriggerAction rule's threshold condition the way an actual pulse does.
Enums
EditabilityReason
Why an UnityEngine.AnimationClip can or cannot have its curves written from inside the hub.