Skip to content

Stop shipping misshapen characters; keep the retarget work - #25

Merged
ralyodio merged 1 commit into
mainfrom
fix/unbreak-play
Jul 26, 2026
Merged

Stop shipping misshapen characters; keep the retarget work#25
ralyodio merged 1 commit into
mainfrom
fix/unbreak-play

Conversation

@ralyodio

Copy link
Copy Markdown
Contributor

/play was rendering splayed, misshapen figures. Bots go back to the generated character, which renders correctly.

The Synty models are committed and load fine — the fault is my retargeter. It constrained each target bone to the source bone's absolute world rotation, which is only correct when both skeletons share rest poses. Synty uses Unreal's axis convention and our clips use another, so every bone sat at its rest-pose difference and the error compounded down each limb.

Measured: 1.90 × 2.00 × 2.47 m against roughly 0.6 × 0.4 × 1.8 for a standing figure.

import_synty.py now carries the corrected relation:

target.matrix = source.matrix @ (source.rest⁻¹ @ target.rest)

so what transfers is the source's motion away from its own rest, not its raw orientation. That maths runs, but its manually keyed actions don't survive the glTF export the way nla.bake's did — all five clips collapse into one named after the object. Until that's resolved the Synty characters can't ship animated, so they aren't shipped.

Swapping back is two lines in opponents.ts, noted there.

201 tests pass.

🤖 Generated with Claude Code

/play was rendering splayed, misshapen figures. The bots go back to the
generated character, which renders correctly.

The Synty models are committed and load fine; the fault is my retargeter. It
constrained each target bone to the source bone's *absolute* world rotation,
which is only correct when both skeletons share rest poses. Synty uses Unreal's
axis convention and our clips use another, so every bone sat at its rest-pose
difference and the error compounded down each limb — measured at
1.90 x 2.00 x 2.47 m against roughly 0.6 x 0.4 x 1.8 for a standing figure.

import_synty.py now carries the corrected relation:

    target.matrix = source.matrix @ (source.rest⁻¹ @ target.rest)

so what transfers is the source's motion away from its own rest rather than its
raw orientation. That maths runs, but its manually keyed actions do not survive
the glTF export the way `nla.bake`'s did — all five clips collapse into one
named after the object. Until that is resolved the Synty characters cannot ship
animated, so they are not shipped.

Swapping back is two lines in opponents.ts, noted there.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

vu1nz Security Review

0 finding(s) in PR #?

No security issues found.

@ralyodio
ralyodio merged commit 9885785 into main Jul 26, 2026
6 checks passed
@ralyodio
ralyodio deleted the fix/unbreak-play branch July 26, 2026 15:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant