Skip to content

Character workshop tuning

The character workshop lists every clip the loaded character publishes, plus the bind pose, and lets you tune how each held item sits in the hand and how each clip is posed. The panels are src/review/character-motion-panel.ts and src/review/character-tuning-panel.ts; the tuning schema and its validation are in src/animation/character-tuning.ts.

The Motion section has:

  • Equipped weapon: every held item the character’s manifest fits to the hand. For the Grey that is the iron sword, steel blade, war axe, hunter’s bow, iron spear, walking cane, iron dagger, and a torch for either hand.
  • A search box and a category filter (all clips, equipped weapon, movement, standing idles, emotes, sitting and sleeping, air and water, weapons, punches and kicks, reactions). Choosing a weapon switches the filter to that weapon’s actions.
  • Previous and Next, a timeline scrubber, Repeat clip, a pause button and a playback speed slider. The info line shows the clip count, the clip’s duration and, for Meshy clips, the Meshy action id.

Pick what to edit with Edit:

  • Weapon default · all animations: grip-local position X/Y/Z in centimetres (-100 to 100), rotation in degrees (-180 to 180) and per-axis scale (0.2 to 3). It applies to every clip for that item.
  • Weapon + current animation: a second grip adjustment for this item and this clip only, applied after the weapon default. Other items and clips keep theirs.
  • Current animation pose: for clips with a recorded source, a playback rate (0.25 to 2), an animation Y offset in centimetres, per-foot footprint contact offsets and toe angle, and a constant local rotation (-90 to 90 degrees per axis) for the pelvis, torso, neck, head, and each side’s upper arm, forearm, wrist, thigh, knee and foot. These are whole-clip offsets, not a keyframe editor.

Also in the panel:

  • Model ground offset (cm) raises or lowers the whole model for every clip, with its own reset.
  • Show grip axes draws red X, green Y and blue Z at the final grip transform.
  • Reset this adjustment restores the published default for the selected scope.
  • Export JSON, Import JSON and Copyable settings round-trip the CharacterTuning profile (planets-character-tuning.json). A rejected import leaves the current tuning in place.

Every edit is saved at once as a browser tuning draft, keyed by rig family, body and revision, and separate from the player’s appearance save. The draft is restored over the published defaults on the next workshop load. Export before clearing browser data.

The profile records the body binding and the source checksum of every weapon and clip it adjusts; a profile that names a stale source or holds an out-of-range transform is rejected. The workshop, the character creator and the game player all apply published tuning through the same runtime. Grips are placed relative to the morphed hand’s grip pivot, so a tuned weapon follows body proportion changes.

The tracked default tuning for the Grey is assets/character/grey-character-tuning.json (weapon-wide grip defaults for all nine held items, one per-clip grip adjustment for the hunter’s bow in bow-shot, and no pose overrides). Prepared source grip placement is in assets/character/grey-held-items.json.

To publish a tuning export without touching any approved mesh, texture or animation:

Terminal window
node scripts/publish-character-tuning.mjs --tuning=path/to/planets-character-tuning.json

The script accepts either a CharacterTuning file or a full workshop export (it takes settings.tuning from the latter). It validates the profile against the current publication in .gear-work/meshy-grey (override with --source=), samples every body preset with every held item through idle, walk and that item’s actions, and writes a private candidate to .gear-work/character-tuning-candidate (override with --out=). After reviewing the candidate, run the command again with --source=.gear-work/character-tuning-candidate --out=.gear-work/meshy-grey to advance the live publication. Earlier publications are kept, and saved characters stay pinned to the publication they were created with; test tuning changes with a new character or a fresh browser profile.

Then pack and publish the runtime files for production:

Terminal window
npm run assets:character-runtime
npm run assets:character-publish

Related commands:

  • npm run assets:character-actions (scripts/import-character-actions.mjs) turns cached Meshy action downloads into an animation-only candidate. It makes no provider call; acquisition is the separate, budgeted meshy:recipe command.
  • npm run assets:character-weapons (scripts/build-character-weapons.mjs) fits the held items to the body and validates a private candidate in .gear-work/character-weapons-candidate. It takes --tuning=, --source= and --out=.
  • npm run assets:character runs the full production chain and replaces the publication only after every stage passes.

Every animated clip that ships must have a recorded source. npm run build runs scripts/check-animation-provenance.mjs, which fails on any Mixamo animation data and on any runtime clip that does not resolve to a recorded Meshy source, a retarget of one, or an entry in assets/character/character-clip-provenance.json.

Terminal window
npm run test:character-weapons
npm run test:character-walk-clearance
npm run test:character-animation
node scripts/verify-character-workshop-tuning.mjs
node scripts/verify-character-weapon-tuning-gpu.mjs

The first three are CPU checks. The two browser scripts expect a dev server on 127.0.0.1:5187. verify-character-weapon-tuning-gpu.mjs checks the production WebGPU path against .gear-work/character-weapons-candidate by default; pass --published and --manifest=/.gear-work/character-tuning-candidate/manifest.json to test real published tuning instead of synthetic transforms. Reports go to .gear-work/character-validation/weapons/.

Written by release:site-sync from docs/character-workshop-tuning.md at v2026.10.04. Edit the engine document, not this page.