# Modular character builder

Open **Character** at `/play?view=character`, or **Edit character** inside a world.
Choose a collection, combine its parts, change colors, preview animations and save.
Parts are stacked from face, hair and headwear down to footwear. Open a section
and pick a rendered thumbnail directly; its header shows the current selection.
One section opens at a time and stays open while trying different pieces.
The main preview shows the selected colors and animation.
Thumbnails always use the source's original colors. New characters start with
**Original item colors**; choose **Custom colors** for the skin/hair/clothing
palette. Each selected part has an **Original colors** checkbox, so you can keep
an outfit's authored palette while recoloring other pieces. Both settings save
with the character and travel to worlds. Older saved recipes retain custom coloring.

Use the preview's **Focus** menu for the full body, face/headwear, upper body,
legs or feet. The zoom buttons, mouse wheel and touch pinch inspect details;
dragging still rotates the character.
Drafts stay local until **Save character**; **Reset changes** restores the saved
recipe. The central account owns the character and connected worlds render that
same appearance. Switching to an original avatar keeps the last modular recipe.

## Included assets

| Collection       | Selectable parts | Joints | Animation entries |
| ---------------- | ---------------: | -----: | ----------------: |
| Modular Men      |               73 |     62 |               372 |
| Fantasy · Male   |               60 |     53 |               372 |
| Fantasy · Female |               61 |     53 |               372 |

The package contains **194 selectable parts, 1,316 GLB entries and a thumbnail for every part**
(identical thumbnail images share one PNG):
the original 169 options plus 25 fitted options from another collection. The complete Modular
Men Blender master contributes 48 meshes, with hair split into independent parts.
The full Fantasy Source masters and modular exports contribute Knight, Noble,
Peasant, Ranger and Wizard outfits, including master-only accessories. Fantasy
supplies outfits rather than complete heads, so Modular Men heads/hair are fitted
to each Fantasy head socket. Authoring controls and two unskinned
`Female_Regular.*` hand fragments are excluded.

Slots cover face, hair, headwear, torso, armor, arms, bracers, legs, footwear, belt,
shoulders, neckwear, back and held items wherever the collection supplies them.
Fantasy headwear, armor, bracers, belts, shoulders and neckwear can be worn over
Modular Men clothing. The Modular Men backpack, sword and pistol also fit both
Fantasy bodies. These 25 options are explicitly rebound and labeled **Fitted**;
the source collection is visible on each thumbnail card. Arbitrary bodies/limbs
from different rigs are still not interchangeable.

Parts mix within their declared destination rig. Changing collections starts from a complete
default outfit. Skin, hair and clothing colors affect tagged vertices; other
authored colors remain. Textures are baked into vertex colors. Some combinations
can still intersect; the builder does not perform general mesh collision fitting. There are no
body-shape sliders, facial animation or contact IK.

Matching skeletons alone do not establish a fit. The pack now declares explicit
base relationships: Fantasy headwear uses the Casual head fitting reference;
Fantasy armor, belts, bracers and shoulder/neck accessories require their matching
outfit base; fitted Fantasy accessories on Modular Men use the Casual body.
Other head shapes remain available without incompatible headwear. Helmets/hoods
hide separate hair, and heads with integrated hair or coverings hide duplicate
hair. The stored hairstyle returns when the covering is removed. Unsupported
choices are disabled with a reason in the visual gallery. Changing a base removes
optional pieces that no longer fit and names them in a notice. The server enforces
the same constraints when saving.

Each rig includes UAL 1 (127 clips), UAL 2 (135), both Standard releases (43 each)
and the Modular Men Adventurer's 24 clips. These are 372 **source entries**,
including overlapping releases, variants and reference poses, not 372 distinct
actions. Namespaced IDs such as `ual1-walk` and `ual2-idle-foldarms` are stable.
All are available in preview and the animation API. Multiplayer synchronizes the
existing eight states: idle, walk, run, jump, fall, land, wave and dance. Additional
clips used as gameplay actions need the game's own action/network rules.

## Optional package and integration

`npm run build` produces `dist/downloads/yoworlds-character-0.1.0.tgz`:

```sh
npm install ./yoworlds-character-0.1.0.tgz
```

The local package contains the browser module, TypeScript declarations, CSS, every
GLB, manifest, provenance and third-party notices. It has not been published to
npm. No Quaternius service, Blender or Godot is needed at runtime. The browser loads
only the selected rig, parts and eight core motions, then optional clips on demand.
The renderer-independent YoWorlds SDK does not import this optional renderer.

Copy installed assets into your static directory during your own build:

```js
import { copyCharacterAssets } from '@yoworlds/character/copy-assets';
copyCharacterAssets('public/characters');
```

An editor hosted at the central account origin can use:

```js
import { mountCharacterCreator, resolveCharacterPack } from '@yoworlds/character';
import '@yoworlds/character/style.css';
const me = await fetch('/api/me').then((r) => r.json());
const manifest = await fetch('/api/character-pack').then((r) => r.json());
// Local files must match this authority-approved manifest revision.
const pack = resolveCharacterPack(manifest, new URL('/characters/', location.origin));
const creator = mountCharacterCreator(document.querySelector('#character'), {
  pack,
  appearance: me.appearance,
  recipe: me.characterRecipe,
  async save(recipe, expectedRevision) {
    const response = await fetch('/api/character', {
      method: 'POST',
      credentials: 'same-origin',
      headers: { 'content-type': 'application/json', 'x-yoworlds': '1' },
      body: JSON.stringify({ recipe, expectedRevision }),
    });
    const result = await response.json();
    if (!response.ok) throw new Error(result.error ?? 'Saving failed');
    return result;
  },
});
// When removing the editor: creator.dispose();
```

`mountCharacterCreator` owns a rotatable preview unless `preview` is supplied.
It returns `getRecipe()` and `dispose()`. The callback keeps storage policy outside
the UI module. Included worlds and the downloadable starter already render both
original and modular appearances. Custom Three.js adapters can use:

```js
import { loadCharacterAvatar } from '@yoworlds/character';
const avatar = await loadCharacterAvatar(appearance); // authorized Appearance
scene.add(avatar.root);
// Each frame: avatar.update(deltaSeconds, 'walk');
// Library clip: await avatar.playClip(clip.asset, clip.id, clip.loop);
// On removal: avatar.dispose();
```

Resolve a manifest to your locally served directory for optional clips. The
included world proxy admits files named by authorized appearances, not arbitrary
library files. It reads matching bundled assets locally with hash verification;
older/newer approved files missing locally fall back to central.

From an independent world, navigate to the URL returned by
`sdk.openCharacterCreator()`. This uses the existing central store-context and
return-world flow. Account cookies and write permission remain on the central host.

## Asset standard and retargeting

The format is self-contained **glTF 2.0 binary (`.glb`)**, meters, Y up, forward +Z.
The explicit `pocket-humanoid-v2` profile has three bind families. The manifest rig
GLB is the exact reference: preserve names/order, hierarchy, world bind matrices
and native bone axes. Scene extras declare `profile: 'pocket-humanoid-v2'` and
`jointOrder`. Existing v1 cosmetics retain their original rules and are not
automatically compatible with these richer rigs.

- One skinned, indexed triangle primitive and one opaque material per part, with
  `POSITION`, `NORMAL`, `COLOR_0`, `JOINTS_0` and normalized `WEIGHTS_0`.
- No morphs, external files, textures, extensions or extra influences. Optional
  scalar `_TINT`: 0 authored, 1 skin, 2 hair, 3 clothing.
- At most 64 joints, four influences, 16 MiB per GLB and 40,000 triangles per
  assembled character. Composition merges to one material and one measured
  color-pass draw call. Shadow rendering is additional work.
- Animation-only GLBs retain the same rest hierarchy without geometry, using
  finite baked linear rotation keys. Only the mapped pelvis may translate.

Retargeting applies source bind-relative world rotation deltas to the target rest
pose, then resolves target local rotations. Clips are baked at 30 Hz and optimized.
The Modular Men GLTF opens in an animated pose, so conversion reconstructs its
reference pose from inverse bind matrices. The native same-rig conversion retains
all matching joints, including the additional chest and finger joints. Source
Mirror modifiers are evaluated during Blender export so both sides are present.
The Fantasy master's adjacent `Textures` directory is extracted with the source;
missing images fail the export. Legacy Modular Men Diffuse outputs are temporarily
connected to their authored Principled shaders for glTF export, preserving their
original material colors. The source Blender files are never saved.
Root movement and horizontal pelvis displacement are removed; vertical body motion
remains. Unweighted Fantasy leaf joints are removed. The old Modular Men rig has
detached foot branches: after every mixer update, runtime restores each foot's
ankle anchor relative to the animated lower leg without accumulating corrections.

Eight core motions are also timed to the room protocol. Fall holds a midair pose;
dance repeats for four seconds. Individual source clips retain their timing except
zero-length reference poses, which receive a 1/30-second duration. Held items are
visual props, without automatic weapon gameplay.

Validate operator-supplied content against a matching reference with the same gate
used for the bundled assets:

```sh
npm run character:validate -- --file my-part.glb --rig fantasy-female --kind part
npm run character:validate -- --file my-motion.glb --rig fantasy-female --kind animation
```

Validation does not publish a file. Approved additions need operator pack metadata,
content-addressed filenames, a regenerated revision and whole-pack verification
before installation. The existing creator desk remains a v1 pipeline; public v2
uploads are not opened by this change.

## Central authority

Migration 009 adds immutable `character_packs` and per-player `player_characters`.
Startup verifies bundled hashes, publishes immutable bytes to `assets/versions`,
then registers the pack. `/api/character-pack` returns the current manifest.
`POST /api/character` accepts `{recipe, expectedRevision}` through the normal
authenticated central session, origin and header checks.

Recipes contain approved part IDs, rig, colors and a pinned pack revision, never
caller-supplied URLs or player IDs. Central validates required slots, compatibility
and total geometry, atomically increments `appearance_revision`, and rejects stale
edits with HTTP 409. Guests retain their recipe when upgrading to an account.
Back up the database and `assets/versions` together; older packs remain available
to saved appearances.
The manifest explicitly identifies the initial half-mesh/broken-wave revision for
repair. Startup upgrades compatible recipes from that revision, preserving part
IDs and colors and incrementing the active appearance revision exactly once.

## Sources, conversion and verification

The user-confirmed references are
`D:/AI/game/mistborn/docs/text-to-character-authoring.md` and
`D:/AI/game/mistborn/docs/actor-animation-source-and-retargeting.md`. Original
archives and the other repository are read without modification.
`assets/characters/provenance.json` records archive/PCK hashes and
`source-map.json` maps source meshes to delivered parts. Original CC0 texts remain
in `assets/characters/licenses`. Assets are by Quaternius; see the
[Universal Animation Library source](https://quaternius.com/packs/universalanimationlibrary.html).
Software/fonts retain their own licenses; this change assigns no new code license.

`npm run character:build` rebuilds from `.runtime/character-sources` and renders
thumbnails with background Blender. `npm run character:thumbnails` only refreshes
the thumbnail stage; set `BLENDER_PATH` to override its executable. Thumbnail
caching is keyed by geometry hash and render version. Hidden bone widgets are
excluded from framing, and verification checks image integrity and visible size.
`npm run character:import` extracts the local originals and exports through Blender
and the reviewed Godot 4.4.1 viewer PCK. Its PowerShell script accepts `-Archives`,
`-ReferenceRepository`, `-Blender` and `-Godot`. Those authoring tools are unnecessary
for normal installation/runtime. `npm run character:verify` runs the official glTF
validator and strict profile checks on all 1,316 GLBs and 194 thumbnails, reporting to
`reports/characters.json`.

Tests cover every part during locomotion, every animation at six phases on each
rig, mirrored geometry and weights on both sides, hand height during wave,
thumbnail picking, fitted cross-pack pieces, automatic repair of the known broken
revision, account isolation, conflicting saves, restart recovery, guest upgrades, local
asset reads, editor preview/save and travel between worlds. These are structural
and sampled-pose checks, not visual approval of every possible combination.
`npm run check` runs build, coverage and browser regressions.
