Files
settled-reach/docs/sprints/sprint-30/client.md
T
jpmschweitzerandClaude Sonnet 4.6 4722598017 chore(meta): plan Sprint 30: Clean Slate
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>
2026-04-03 19:28:20 +02:00

104 lines
7.5 KiB
Markdown

# 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. Manages `CharacterVisualDescriptor`, 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 `GameState` so 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 call
- `client/scripts/autoloads/game_state.gd` — add descriptor field + restore from snapshot
- `client/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 `BoneAttachment3D` with bone_name = "Head", child `Marker3D` at offset Vector3(0, 0.3, 0)
- Export a `@export` var 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.json` fully: 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 or `Makefile` target that regenerates `manifest.json` from 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):
```bash
tea pr create --repo jpmschweitzer/settled-reach --login schweitz --title "feat(client): Sprint 30 character and UI fixes" --description "body" --base main --head client
```