Files
last-hearth/docs/character-creator.md
2026-11-05 09:57:11 -05:00

102 lines
5.7 KiB
Markdown
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Woodland traveler character creator
Use `/character` at any time while connected, or open **Character appearance**
from the inventory. Creation is opt-in: joining restores the saved appearance
without opening the creator. Existing location selection and field-note join
forms retain priority.
## A quiet traveler, not a costume catalogue
All choices are inclusive and independent, with no gender, identity or stat
fields. Compact, lean, balanced, broad and sturdy silhouettes have identical
mechanics, height, camera, collision, reach, movement and held-tool anchors.
Hair, layered field clothes, cloaks, belt gear and packs use original low-poly
geometry with hand-drawn, muted woodland pixel art.
Four tabs keep the 14 × 11 form manageable:
| Tab | Choices |
| --- | --- |
| Face | 5 body silhouettes, 6 skin tones, 5 face-line patterns, 5 eye colors |
| Hair | 10 styles, 6 shared hair/facial-hair colors, 7 facial-hair styles |
| Clothing | 7 garments, 8 cloth colors, 4 trousers, 3 boot leathers |
| Finishing | 9 accents, 8 accent colors, 5 face-detail patterns |
Dropdowns use readable names, not gender categories or free-form colors. Cloth
and accent palettes are sage, teal, slate, mauve, ochre, rust, linen and charcoal.
Transparent `none` layers and colors under absent hair/accents mean the raw
selection combinations are not all visually distinct; no uniqueness count is
claimed.
## Preview and explicit consent
The form contains a real Luanti `model[]` preview, not a screenshot, external
browser or URL. It uses one composited 64 × 64 texture and the selected B3D.
The preview turns continuously and supports mouse dragging; Front, Profile and
Back reset its camera angle. These controls never rotate the actual player.
Changing a dropdown, switching tabs, **Randomize** and **Reset draft** affect
only a private session draft. Randomize chooses from every fixed allowlist using
bounded `math.random`; it is not security randomness and introduces no secrets.
Reset copies the defaults rather than modifying shared state. **Cancel** or
Escape discards the draft, preserving both the real appearance and saved bytes.
Only **Save / Apply** commits. No need, inventory, identity or physics values
are changed. Drafts disappear when the session ends.
## Version-1 storage and recovery
The only new persistent value is the engine-owned player metadata string
`hearth:appearance`. It is independent of the existing global save schema and
world/mod storage. A complete flat JSON object contains exactly `version:1` and
these string selections:
`body`, `skin`, `face`, `eyes`, `hair`, `hairColor`, `beard`, `garment`, `cloth`,
`trousers`, `boots`, `accent`, `accentColor`, `detail`.
Defaults match the [authoritative art contract](art-direction.md): balanced,
sand, calm, hazel, sidepart, chestnut, none, tunic, teal, earth, walnut, scarf,
sage, none. An absent value uses defaults without writing metadata. Invalid,
unknown-version, missing/extra-field, malformed, nested or over-2048-byte values
show safe defaults and a fixed warning. Original corrupt bytes are **not
overwritten**, and appearance errors never kick a player. Only an explicit
successful Apply replaces that value. Back up the world before manual recovery.
Encoding and decoding use `core.write_json` / `core.parse_json(raw,nil,true)`;
parser errors do not log player payloads. There is no executable deserialization,
custom path, uploaded texture or free-form hexadecimal color. Every mesh and
layer filename is built solely from fixed IDs. Compositing order is skin, face,
eyes, garment, trousers, boots, hair, beard, accent, detail; accents layer above
hair so a selected hood frames and covers it. The model includes an original
draped mantle, belt, pack, projecting nose and ears. Face overlays are
skin-neutral; there is no global color tint.
The held-tool material remains the existing compatibility texture.
Apply serializes and checks the roundtrip, then writes metadata **before**
publishing `mesh` and `textures`. A thrown/false metadata write or serialization
failure keeps the previous published appearance and saved session selection,
leaving the draft available to retry. Engine metadata durability still follows
normal engine player saving; this is not a new disk transaction service.
## Integration and validation boundary
[The factory](../mods/hearth/character.lua) receives `(hearth, api)`, registers
its own command/receive-fields callback, and exports `apply`, `on_join`, `show`,
`handle`, `defaults`, `options`, `validate`, `decode`, `encode`, `preview` and
snapshot-only `state`. Bootstrap instantiates it before the interface and
players; the player join handler calls it after base property initialization.
Only the current engine-supplied connected player object and its own session can
edit an open draft. Target names, arbitrary fields, hidden-tab selections and
invalid dropdown indices are rejected as a whole event. All displayed data is
formspec-escaped; text and input sizes are bounded.
CodeGuard input/storage guidance was applied: allowlisted keys and selections,
bounded parsing, session ownership, preserved corrupt data and sanitized errors.
No credentials, certificate handling, cryptography, network calls or dependencies
are introduced. No authentication or database infrastructure is changed.
Focused offline Lua harnesses cover character behavior, player join integration,
inventory navigation and bootstrap order. Mocks model native JSON through
registered exact fixture strings, not executable Lua. Native engine rendering,
mouse behavior and visual fit still require client review; no full-engine or
live-world test is claimed by this change.