PSZ Spec
OverviewArchitectureAssetsJourneyAutopilotMechanicsStatesHierarchiesEngineering

Character Customize

Purpose

Multi-step flow after class selection: customize appearance, enter a name, and confirm. Uses the PSZ theme throughout.

Steps

Class Select — slat rendering (normative)

The preceding Class Select step lays the 14 classes out as horizontal slats. Each slat holds a full-bleed class cutout (PNG art) and grows when selected. The cutout rendering MUST obey the following so the selection animation reads as a clean reveal, not a jittering image (issue #380 — the HUcast / HUcaseal cutouts visibly wobbled on navigation):

  • Each class cutout MUST be cropped object-fit: cover, anchored center-top (parity with SlatsView.tsx objectPosition: 'center top'), so heads are never clipped.
  • The slat-width transition (selected stretch ratio 5, unselected 1, 0.32s cubic ease-out) MUST animate only the revealed width of the cutout. It MUST NOT shift the visible crop origin of any cutout — the cover-crop is solved once against a width-stable reference frame, and the animating slat merely clips more or less of that fixed-size cutout.
  • The reference frame width MUST be derived from the content-area width (selected reference = content_width × 5 / total_ratio), not a hardcoded pixel value, so framing is consistent across resolutions and aspect ratios.

Rationale: a per-frame cover-crop solved against the container's integer-rounded, fractional slat widths shifts the crop origin ±1px as 14 widths re-round each animation frame. With mipmaps disabled, that moved high-contrast translucent pixels in the edge-to-edge Cast arts and read as a wobble. Pinning the crop to a constant-size frame removes the re-crop entirely.

Appearance

Left panel with 4 rows — labels adapt for Cast classes (Head Parts, Body Color A/B/C). Right side shows a live 3D preview in a SubViewport. Right analog stick rotates the model.

  • Head Type — variation_index (4 options)
  • Hair Color — hair_color_index (3 colors: Blonde, Brown, Black)
  • Costume Color — body_color_index (5 colors)
  • Skin Tone — skin_tone_index (3 tones: Light, Medium, Dark)

Skin tone ordering (normative)

The Skin Tone row MUST read lightest → darkest as the index increases: index 0 = Light, 1 = Medium, 2 = Dark. This is the order in PlayerConfig.SKIN_TONES, and the rendered model MUST match the selected label.

Most classes bake their three skin textures in that same slot order, so the UI index maps straight through to the texture's tens digit. HUmarl is the lone exception: its source textures are scrambled (texture slot 0 = medium, slot 1 = darkest, slot 2 = lightest), so the index→slot map for HUmarl is [2, 0, 1]. PlayerConfig.get_texture_path() applies this per-class remap so every class renders Light→Medium→Dark in label order. Casts have no skin tone (their fourth row is Body Color C, a hue choice, not a light→dark ramp) and are unaffected.

Audio feedback (normative)

Both customization steps MUST give the same menu audio as the rest of the menu chrome (parity with Class Select / Character Select):

  • Move (change row or cycle a value) → menu_move.wav
  • Confirm (advance a step) → menu_select.wav
  • Cancel (back out a step) → menu_back.wav

Name Entry

Centered panel with a LineEdit, max 16 characters. Submitting with an empty name does nothing. On submit, character is created immediately (no separate confirm step in current build).

After Creation

Character is saved, active slot set, and the game transitions to the city office (city_office.tscn) with the "intro" spawn key.

Previous

← Create Character (Class Select)

Next

City →