Skip to content

[Enhancement]Add animation playback helpers for synchronized gameplay and hold non-looping final poses #1314

Description

@untoldengine

Problem

ImmersiveGol needs to replay a one-shot kicking animation and release a Jolt ball when playback crosses the foot-contact time. It also needs to align the shooter with the ball by sampling the contact joint before playback, without changing the visible pose.

The existing animation API needs explicit support for restarting an already selected clip, reading playback time, and sampling a joint in world space. The compiled sampler also wraps non-looping clips at their duration, causing a completed kick to jump back to its initial pose. Restarting should preserve warmed compiled animation caches when the clip configuration has not changed.

Local implementation to integrate

The following demo-related changes are currently uncommitted and unstaged in the local engine checkout:

  • Sources/UntoldEngine/Systems/AnimationSystem.swift
    • restartAnimation(entityId:name:repeats:withPause:): restart from time zero, including when the same clip is already selected; apply to matching animated descendants, cancel transitions, and reset root-motion history. Preserve compiled caches unless the looping configuration changes.
    • getAnimationPlaybackTime(entityId:): return the selected clip's current time from the first animated part of a root/split character, or nil when unavailable.
    • sampleAnimationJointPosition(entityId:name:jointName:time:): sample a named joint in world space using the compiled pose, joint hierarchy, rest scales, and entity world transform. Preserve current playback time and pause state; return nil for an unavailable joint.
  • Sources/UntoldEngine/Animation/ClipSampler.swift: clamp non-repeating clip time to its duration; retain wrapping for repeating clips.
  • Tests/UntoldEngineTests/AnimationCompiledSamplerTests.swift: add coverage for final-pose holding, restarting the selected clip, sampling under world translation/rotation/scale without changing playback, and preserving/invalidation of compiled caches according to looping changes.

The staged shadow/shader/render-pass changes and compiled Metal libraries in the same working tree are outside this issue's scope.

Demo integration and evidence

The demo uses forwardstrike.untoldanim; the reviewed foot-contact sample is frame 13 (about 0.433 seconds at 30 fps), rather than frame 15. It samples RightToeBase to align the player in X/Z while keeping the ball on the floor, then releases the ball when actual animation playback reaches the contact time. A countdown precedes each kick, and repeated kicks use the restart helper.

Headset testing confirmed that the grounded ball and frame-13 launch work. Earlier validation passed all 18 focused animation sampler tests, including the four added tests, and the demo's visionOS simulator build passed. These results are from prior validation; engine tests were not rerun when creating this issue.

The helpers preserve compiled caches to avoid unnecessary recompilation. Fast glove movement still has a separately reported disappearance/stuttering problem; its cause has not been established, and this change does not claim to resolve it.

Acceptance criteria

  • Review and integrate the three local animation-file changes without including unrelated staged work.
  • Repeated one-shot restarts begin at time zero, with no unconditional cache invalidation.
  • Non-looping clips hold their final pose; looping clips continue to wrap.
  • Joint sampling returns the expected world-space position without changing displayed playback state.
  • Document the public helpers, update-thread requirement, nil behavior, and first-animated-part semantics for playback time.
  • Validate the focused animation tests and synchronized repeated kicks before merging.

Activity

  1. changed the title [-]Add animation playback helpers for synchronized gameplay and hold non-looping final poses[/-] [+][Enhancement]Add animation playback helpers for synchronized gameplay and hold non-looping final poses[/+] on Oct 6, 2026
  2. added a commit that references this issue on Oct 7, 2026
    b2b6706
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions