Skip to content

feat(game): ship the Synty characters — bots are no longer the generated one - #42

Merged
ralyodio merged 1 commit into
mainfrom
feat/synty-fighters
Jul 30, 2026
Merged

ralyodio merged 1 commit into
mainfrom
feat/synty-fighters

Conversation

@ralyodio

Copy link
Copy Markdown
Contributor

This is the "people look identical" fix.

The bots have used the generated character.glb since the beginning, because the Synty animation retarget did not work. It works now650e8a2 solved it and said so in its own commit message — but it was never wired in, so nothing on screen changed.

The documented blocker did not exist

retarget_mocap.py's header said dropping the result into Opponents made bots invisible, and that the next step was to instrument what placeAnimated returns. I did that with NullEngine, and found no bug in placeAnimated:

generated synty (new)
container rootNodes __root__ __root__
picked root
clip keys after split("_").pop() death, fire, idle, run, walk idle, run, walk
meshes under root 3 1

The multi-root theory was about the old import_synty.py output. retarget_mocap.py exports a single target_rig root, so the wiring that failed before simply works.

Measured on the animated mesh rather than the bind pose: 1.72 m tall, 0.57 m across — arms down, not the 2.03 m T-pose that broke both earlier attempts.

Wiring

fighter_insurgent → Directorate, fighter_soldier → Nightcell. The generated character stays as a fallback, so a failed licensed load degrades to a working bot rather than to none. Shell budget 7.84 MB against the 9 MB guard.

Clips are MoCap Online's rifle set — in-place (IPC) variants deliberately, since the server owns movement and root motion would fight the simulation.

Two honest gaps, recorded not glossed

1. The animation licence is unconfirmed, and it blocks commercial release. The pack contains no licence, EULA or terms file — only format notes. It appears to be MoCap Online's free sample pack, but "appears to be" is not provenance, and CLAUDE.md requires provenance for every public asset. Fine for a dev build; not fine for a paid episode. Swapping the clips is a --clips argument, not a code change.

2. No death animation exists in the pack. Opponents.play() already tolerates a missing clip by stopping every group, so a killed bot freezes in place rather than erroring. Imperfect, and the truth until a death clip exists.

Verification, including what I could not verify

  • ✅ Both GLBs requested and loaded in the real game, zero page/console errors
  • NullEngine: mesh present, clips resolve, dimensions correct
  • ✅ 263 tests, full pnpm check green
  • A bot visibly on screen. Headless SwiftShader runs at ~1 FPS, so the bot sim barely advances and none walked into frame during capture. Photo mode returns before opponents are created, so the capture tool cannot show them either.

Given I have twice this session claimed a visual result I had not actually seen, I am flagging that last point rather than implying otherwise.

…ted one

The bots have used the generated character.glb since the beginning because the
Synty animation retarget did not work. It works now (650e8a2 solved it and
said so), but it was never wired in, so nothing on screen changed. This wires
it.

The documented next step was to instrument what placeAnimated returns for the
licensed container. Done, with NullEngine, and it found no bug there at all:
the retargeted container behaves exactly like the generated character — one
__root__, the picked root correct, name.split("_").pop() resolving to
idle/walk/run, the mesh present beneath it.

The multi-root theory in the handoff was about the OLD import_synty.py output.
retarget_mocap.py exports a single target_rig root, so the wiring that failed
before simply works. Measured on the animated mesh, not the bind pose: 1.72 m
tall, 0.57 m across — arms down, not the 2.03 m T-pose that broke both earlier
attempts.

  fighter_insurgent -> Directorate     fighter_soldier -> Nightcell

The generated character stays as a fallback, so a failed licensed load
degrades to a working bot rather than to none.

Clips are MoCap Online's rifle set, in-place variants deliberately: the server
owns movement, so root motion would fight the simulation. Shell budget 7.84 MB
against the 9 MB guard.

Two honest gaps, both recorded in PROVENANCE.md rather than glossed:

  - The pack ships NO licence, EULA or terms file. It appears to be the free
    sample pack, but "appears to be" is not provenance and CLAUDE.md requires
    provenance for every public asset. Fine for a dev build, blocks a paid
    episode. Swapping clips is a --clips argument, not a code change.
  - No death animation exists in the pack. Opponents.play() already tolerates
    a missing clip by stopping every group, so a killed bot freezes rather
    than erroring — imperfect, and the truth until a death clip exists.

Verified: both GLBs load in the real game over the network with zero page or
console errors; NullEngine confirms mesh, clips and dimensions. NOT verified: a
bot visibly on screen — headless SwiftShader runs at ~1 FPS, so no bot walked
into frame during capture.

263 tests.

Co-Authored-By: Claude Opus 4.8 <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 df9e743 into main Jul 30, 2026
6 checks passed
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