Sprint goal: Close Phase 1 wiki quality debt — stereotype correction, data integrity fixes, and atlas regressions — so the wiki stands correct before Phase 1 UI work begins. 26 tickets: copy (18), client (5), server (3). Epics #638, #683, #738 closed. #766 deferred (own sprint). Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
7.5 KiB
Sprint 30: Clean Slate — Client Tasks
Goal: Close Phase 1 wiki quality debt — stereotype correction, data integrity fixes, and atlas regressions — so the wiki stands correct before Phase 1 UI work begins.
Branch: client
Agents: Stig (dev), Tyre (arch), Hoshe (QA)
New Tickets
| # | Title | Priority | Blocked by |
|---|---|---|---|
| #718 | Persist CharacterVisualDescriptor on new game start | high | — |
| #674 | Star map insert module — concentric hop-ring view | medium | — |
| #712 | Add BoneAttachment3D marker above Head bone for floating icons | medium | — |
| #719 | Hair highlight: add descriptor field or make swatch read-only | medium | — |
| #720 | Replace DirAccess asset scanning with manifest JSON for export builds | medium | — |
Use tooling/db/ticket show <id> for full details.
Key Decisions
decisions/architecture.md— D-134 (full character customisation: hair, clothing, colors at tile scale), D-146 (character preview: tile-scale sprite, no separate portrait), D-043 (art direction: functional warmth), D-044 (visual hierarchy)decisions/scope.md— D-114 (Phase 4 deliverable: player viewport with final-version assets)
Notes
Existing code to understand first
Before starting any ticket, read:
client/ui/character_creation.gd— the character creation screen. ManagesCharacterVisualDescriptor, layer selectors, color swatches, preview pane, and manifest loading.client/assets/characters/manifest.json— asset manifest listing available body types, heads, hair, facial hair, clothing, accessories. Partially populated (heads array is empty).client/scripts/autoloads/game_state.gd— player entity ID and session state. CharacterVisualDescriptor will be stored here on new game start.client/scripts/rendering/entity_renderer.gd— current entity sprite system. Integration point for #718 (persisted descriptor must survive into gameplay rendering).
#718 — Persist CharacterVisualDescriptor on new game start
When the player confirms the character creation screen, the client sends a CharacterVisualDescriptor to the server. The server must receive it and persist it so the descriptor survives save/load cycles and is included in ObserverSnapshot. This ticket is the client side: wire the confirmed descriptor from character_creation.gd through to the new-game IPC call. Verify the descriptor reaches the server (coordinate with server team if the server-side storage is not yet implemented — server ticket is out of scope this sprint unless added separately).
What to deliver:
- On confirm in
character_creation.gd, serialize descriptor and include it in the new-game start message to the server - Store descriptor in
GameStateso it persists across scene transitions - After load, confirm descriptor is restored from server snapshot (integration test: start game, check descriptor fields match what was entered)
File locations:
client/ui/character_creation.gd— add serialization + send callclient/scripts/autoloads/game_state.gd— add descriptor field + restore from snapshotclient/protocol/— may need a new message type for descriptor transmission
#712 — BoneAttachment3D marker above Head bone
Add an empty Marker3D node anchored as a BoneAttachment3D to the Head bone in the player character skeleton scene. Offset approximately 0.3m above the Head bone origin. This node is the anchor point for floating UI elements — status indicators, thought bubbles, alert markers, speech icons.
What to deliver:
- Locate the skeleton scene (likely
client/assets/characters/skeleton/or similar based on the Sprint 28 asset pipeline) - Add
BoneAttachment3Dwith bone_name = "Head", childMarker3Dat offset Vector3(0, 0.3, 0) - Export a
@exportvar or named node path from the character root so other systems can reference the marker node without hardcoded paths - No functional systems need to use this marker yet — the ticket is infrastructure for future floating UI work
Gotcha: BoneAttachment3D must be a child of the skeleton, not the character root. If the skeleton is a Skeleton3D inside a scene, the attachment must be added inside that scene, not the parent.
#719 — Hair highlight: add descriptor field or make swatch read-only
The hair highlight swatch in the character creation screen accepts user input but the override is a no-op. CharacterVisualDescriptor has no hair_highlight_tint field, and _on_hair_highlight_changed in character_creation.gd does not write to the descriptor. Two valid resolutions:
Option A (preferred if adding the field is low-risk): Add hair_highlight_tint: Color to CharacterVisualDescriptor and wire _on_hair_highlight_changed to write it. The compositor must then read and apply it. This is the fuller fix.
Option B (if the compositor cannot accept it yet): Make the swatch non-interactive — visually show the derived highlight color (_derive_hair_highlight(descriptor.hair_tint)) but remove the ColorPickerButton and replace with a plain ColorRect labeled "Auto". Add a # TODO: ticket #719 comment noting the deferred field.
Decide which option to implement based on compositor readiness. If the compositor already supports hair_highlight_tint (check client/scripts/rendering/character_compositor.gd if it exists), go with Option A. Otherwise Option B.
#720 — Replace DirAccess with manifest JSON
The character creation screen uses DirAccess.open("res://...") in two fallback functions (around lines 1849 and 1868 in character_creation.gd) to scan for available assets. This approach fails in exported PCK builds because DirAccess cannot enumerate res:// paths inside a PCK archive.
The manifest approach is already partially implemented — _load_manifest(), _manifest_array(), and MANIFEST_PATH are in place. The manifest file at client/assets/characters/manifest.json exists and is partially populated.
What to deliver:
- Remove the two
DirAccess.open()fallback scanning functions (lines ~1849-1868) - Populate
manifest.jsonfully: add all available asset IDs for heads, hair, clothing, accessories, and body_types by scanning the actual asset directories once (during development) and encoding the result into JSON - Add a
tooling/script orMakefiletarget that regeneratesmanifest.jsonfrom the asset directories, so it stays in sync as artists add assets — this prevents the manifest going stale - Verify: in an exported build (or by disabling DirAccess manually), the character creation screen populates all tabs correctly from the manifest alone
Note: manifest.json currently has "heads": [] — the heads array is empty. If head assets exist in client/assets/characters/heads/, add them. If none exist yet, leave empty but document in a comment that the manifest is the source of truth.
Dependency Chain
#718 (persist descriptor) — standalone, no client-side blockers
#719 (hair highlight) — standalone, read compositor state first
#720 (manifest JSON) — standalone
#712 (bone marker) — standalone
#674 (star map) — standalone
All five tickets are parallel tracks. No cross-dependencies within this sprint.
PR Workflow
When ready to submit, create a PR with tea CLI. All flags are required to avoid TTY prompts (see CLAUDE.md "Gitea access" section):
tea pr create --repo jpmschweitzer/settled-reach --login schweitz --title "feat(client): Sprint 30 character and UI fixes" --description "body" --base main --head client