Skip to content

Character workshop

The character workshop is a permanent development page at character-workshop.html (entry script src/review/astra-review.ts). It loads characters through the same AstraCharacter loader and animation runtime (src/animation/astra-character.ts) that the game’s WebGPU player and NPC visuals use, so what you tune here is what ships.

The companion pages cover the Model settings panel (export, import, reset) and the Animation & grip tuning panel (weapon grips, per-clip pose offsets, publishing).

Terminal window
npm run review:assets

This starts Vite on 127.0.0.1:5186 and opens /character-workshop.html?asset=meshy. Any Vite dev server works; the page reads these query parameters:

/character-workshop.html # the registered Grey (default)
/character-workshop.html?base=grey-female-v1 # another registered character base
/character-workshop.html?asset=fixture # the body/gear/cloth fitting fixture
/character-workshop.html?model=/path/object.glb # static GLB inspection
/character-workshop.html?manifest=/path/manifest.json&body=standard
/character-workshop.html?clothBackend=cpu # force the CPU reference cape

Without asset=fixture the page loads a registered base (default grey-v2) and writes the chosen base back into the URL. The registered bases and their manifest paths are in CHARACTER_BASES in src/character/character-assets.ts. A static GLB keeps its scene transforms, is scaled to fit the stage and reports its source dimensions; all character controls are disabled in that mode. The Open an asset form in the sidebar (just above Wings) builds the model or manifest URL for you.

Character manifests must follow the body/gear binding and the semantic bone names the runtime expects; the workshop is not a retargeter for arbitrary rigs. The preview renderer accepts at most 64 palette joints and 32 simultaneous morph targets (src/character/character-preview-renderer.ts).

The sticky shortcut row jumps to Motion, Tuning, Body, Stance, Eyes, Wings, Surface, Physics, Fabrics and Outfit. Directly below it, Model selects the character base and the mesh detail (full, or the 30,000-triangle NPC mesh when the source has one), followed by the Model settings panel.

  • Body proportions: 27 morph sliders for the Grey, grouped as Frame, Arms and hands, Legs and feet, and Head and neck, plus a body preset list (Original Grey, Slender, Athletic, Stocky, Heavy, Tall) and a Link fullness to frame toggle. Each group has its own reset.
  • Stance and foot pose: arm spacing (-18 to 25 degrees), leg spread (-8 to 18), left and right toe-out (-25 to 45) and left and right toe bend (-20 to 45). These are rotation offsets layered on top of the clip; they never change bone lengths.
  • Eyes: edit both eyes or one side. Pupil shape (round, cat-eye slit, crescent, four-point star, three-lobed), iris pattern, colour preset, iris and outer-eye colours, iris and pupil size, horizontal iris offset, vein strength and colour, gaze (yaw ±28, pitch ±22 degrees) with Look forward, and a per-eye condition (clear, clouded, cataracted). The Iris, pupil & vein detail group adds a per-eye seed, pigment colour, fibre, mottle, pupil and vein controls.
  • Hand states: each hand follows the animation or is held relaxed, open, fist, grip or point. These rotate the finger joints on top of the body animation.
  • Surface inspection: lit material, geometry normals, base colour only, or clay. Toggle Baked normal detail to tell a bake error from a mesh deformation. Show skeleton draws the animated, proportion-adjusted joints; Show cloth colliders draws the cape collision shapes.
  • Camera: ¾, Front, Side, Back, Feet, Face, Left hand and Right hand views. Face and hand views focus a bone. Camera follows animation is on by default; turn it off to hold the framing while a clip travels.
  • Character: name (with Randomize name), skin tint, detail colour, Save character, Load saved and Play this character, which saves the character as the player and opens the game with ?workshopCharacter.

Edits are kept as a local draft automatically. Only Save character (or Play this character) writes the player save. Use Reload asset after a rebuild; if a load fails the button becomes Retry model and the last valid character stays on screen.

The Wings panel equips any item whose definition carries equip.wing (four designs in src/game/items/item-defs.ts), previews the motion (follow character, folded, flap, soar, dive), sets the growth level (1 to 20), and fits an offset, rotation and scale per axis. Wings have their own skeleton, pass through the cape without joining its collision set, and their fitting is included in Export all settings. Reset wings leaves eyes, clothing and weapon work alone. scripts/verify-workshop-wings.mjs is the browser check (it expects a dev server on port 5188).

Terminal window
npm run assets:grey-v2

scripts/build-grey-v2.mjs rebuilds the Grey from Meshy source art that is already on disk: it never calls the Meshy API or spends credits, and it stops with an error if mesh/mesh.glb or rig/rig.glb is missing from the profile’s source folder. It needs Blender 5.2 or later; set BLENDER_EXE unless Blender 5.2 is installed at its default Windows location.

Options (after --):

  • --profile=FILE picks a source profile, as a path from the repository root (default assets/character/sources/grey-male-v2.json; the others sit in the same folder). The profile names every input and output folder.
  • --through=clean|anatomy|refine|bake|review stops after that stage.
  • --rebuild-surface forces the surface cleanup to run again.
  • --rebake forces the texture bake to run again.

The surface cleanup runs only when its report is missing or --rebuild-surface is given. The UV, anatomy and bake stages keep a receipt of their input hashes and rerun only when an input changed; the refine, check and review steps run every time. The Grey profile reads its source art from art-input/meshy/grey-base-v2 and writes its intermediates under .gear-work/; both folders are ignored by Git.

Paid generation is a separate command, npm run meshy:recipe, which runs node scripts/astra-meshy.mjs <recipe.json> --through <stage>. It resumes existing tasks from the recipe’s pipeline-state.json, refuses a run whose estimate exceeds --max-credits (default 40), and never retries an uncertain paid request automatically. --status and --plan report without submitting. Reuse existing task outputs before generating again.

For the default Grey profile, in order:

  1. scripts/blender/clean-character-surface.py rebuilds a continuous body from the high-detail source (voxel remesh, then QuadriFlow by default, about 18,000 quads) and transfers normalised weights from the original rig.
  2. scripts/blender/unwrap-character.py builds anatomical UV charts with minimum-stretch unwrapping, flip prevention and padded island packing.
  3. scripts/blender/build-character-anatomy.py restores eyelid detail, cuts the eye apertures and builds the inner sockets. Eye positions and radii come from the authored assets/character/grey-refinement.json.
  4. scripts/prepare-grey-bake.mjs prepares the static bake surface.
  5. scripts/refine-meshy-grey.mjs keeps Meshy’s animation coordinate frames, adds fingers, eyes and toe tips, and writes the morph targets with matching rest-joint offsets and the stance definitions.
  6. scripts/blender/bake-meshy-detail.py bakes base colour, material maps and normal detail at 2048 pixels from the high-detail source through a character cage.
  7. Checks: scripts/test-grey-refinement.mjs, scripts/verify-character-source.mjs and scripts/blender/validate-character-proportions.py (rest-pose pelvis intersection checks at full fullness, full belly and the Stocky and Heavy presets).
  8. scripts/prepare-meshy-review.mjs writes the manifest, eye parts, maps and animation GLBs to the profile’s publication folder (.gear-work/meshy-grey for the Grey), which the workshop loads in development.

The Grey-specific projection cage and authored landmarks are fitted to this source; refine-meshy-grey.mjs refuses a source whose hash does not match the refinement file. Other sources get their own profile, landmarks and calibration steps. The review publication is written only in the last step, so a failed stage leaves the previous publication in place.

The full production chain (outfit, crouch, actions, held items and tuning) is npm run assets:character. npm run assets:character-runtime then packs the publication’s resources into public/models/character-runtime/, and npm run assets:character-publish writes the manifests into public/models/characters/<id>/ (default id grey-v2), which production builds load.

Morph geometry and rig offsets are generated from the same profile. Each character keeps its own morph weights and adjusted bind palette, while geometry and morph buffers can be shared between characters.

The Grey uses dual-quaternion skinning (extras.astra.skinning in the body GLB) to keep volume through blended joint rotations. The runtime falls back to matrix skinning when the palette cannot be expressed that way, for example under non-rigid scale. Stature and body shape come from morph geometry and matching rest joints, never from non-uniform animated bone scaling. CPU skin sampling follows the same skinning choice as the preview shader.

Fullness, hip width and limb volume must vary continuously through the pelvis midline. Offsets that switch on the sign of X can fold inner-thigh triangles across each other even when the base mesh is a single closed shell, so check deformed meshes as well as base topology.

Terminal window
npx tsc --noEmit
node scripts/test-grey-refinement.mjs
node scripts/verify-astra-browser.mjs "http://127.0.0.1:5186/character-workshop.html?asset=meshy"

test-grey-refinement.mjs reads .gear-work/grey-refined/body.glb, so run it after a local build. verify-astra-browser.mjs launches headless Edge or Chrome (set CHROME_EXE to choose) with a throwaway profile against a running dev server, checks clips and controls, and captures material and geometry comparisons. Reports land under .gear-work/.

The surface report, UV and bake report, rest-pose proportion checks and animation checks cover different failure modes. Finite-number checks alone do not prove that extreme proportions are free of intersections; extreme body combinations still need art review and corrective shapes.

Source art, editable Blender files and generated intermediates are not in Git. Keep the approved source library backed up separately; the authored profiles, scripts and published runtime files are what the repository versions.

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