Follow-up to #43: animation ergonomics — named clips, Anim.play, frame events, fluent Tween chains #48
Labels
No labels
area:ci
area:docs
area:input
area:net
area:rendering
area:repo
area:stdlib
area:tooling
area:types
cleanup
dx
priority:high
priority:low
priority:medium
proposal
status:in-progress
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: workshopsoft/ludic#48
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Follow-up to #43, which shipped the engine-owned-system hook and the two components it drives (
b014333): a system the engine inserts into the frame loop over a component a game merely declares and carries —SpriteAnim { ticks, fps, frames, mode, frame }(auto-advanced spritesheet frame, loop/once/pingpong) andMotion { ticks, dur, from, to, ease, value, done }(auto-advanced value tween). That was the dependency #43 named as blocking ("Ludic has no auto-injected systems over user components yet"); it now exists, is deterministic, and is spliced only when a game declares the component. Seeruntime/native/systems.ludic,examples/library/anim_ecs.ludic, and the Engine-owned systems section of LANGUAGE.md.This tracks the ergonomic layer on top, deliberately separate because it needs a clip/asset registry and codegen rather than the pure per-frame tick that shipped:
Sprite.sheet(...)/Sprite.clip(name, frames, fps, loop)andAnim.play(entity, "run")resolving a name to the SpriteAnim fields — needs a compile-time clip registry keyed by name.Anim.play(entity, fps, frames, mode)/Motion.to(entity, from, to, dur, ease)namespace sugar over the component writes (today a game sets the fields directly inspawn).eventon a given frame (footstep, hitbox-active) — needs a system to emit an event mid-tick.Tween.chain/Tween.parallel/delay, a disposable handle the engine advances beyond a singleMotion.Related: #43 (the shipped hook + components), #47 (the other consumer of the same hook).
Shipped in
1f5e3c1(feat(anim): animation ergonomics, #48). The ergonomic layer over the engine-owned SpriteAnim/Motion systems (#43), all integer + deterministic so animation and motion reproduce exactly under replay/lockstep.Anim.clip("run", frames, fps, mode)registers a clip by name (a name-keyed registry insystems.ludic, up to 32 clips), andAnim.play(entity, "run")resolves the name to the SpriteAnim fields and plays it.Anim.play/Motion.tonamespace sugar:Anim.play(entity, fps, frames, mode)sets the clip directly and rewinds it;Motion.to(entity, from, to, dur, ease)starts a value tween over the Motion component — both one call over the reflection-ABI writes, instead of setting the fields inspawnby hand.Anim.on_frame(entity, frame)arms optionalSpriteAnimevent_frame/event_firedfields; the engine flagsevent_firedon the tick the clip first lands on that frame, andAnim.fired(entity)reads it. The engine detects the boundary and gameplay owns the reaction (emit its own event, spawn a hitbox, footstep) — which keeps it inside Ludic's no-runtime-dispatch event model (emitdesugars to direct calls, so a generic runtime system can't fire a game event itself).runtime/native/tween.ludic—Tween.tostarts a disposable handle,Tween.chain/Tween.delayappend segments for a sequence, andTween.value/Tween.done/Tween.parallel/Tween.stopread and control it. Handles are advanced by a new engine-owned systemesys_tween, inserted into the Update phase (gated ong_uses_tween_rtrather than a component). The 1-argTween.done(handle)is disambiguated from the existing 2-arg pureTween.done(timer, dur).Worked example + regression:
examples/library/anim_sugar.ludic(4 8 2 1 0 100 100 0 0 1 20 20 30 0 1). Twelve new docs pages (Anim, a new Motion namespace, the Tween handles). Full suite 77 passed, self-host C-free fixpoint intact, no golden drift.