docs(decisions): add Sprint 28 character visuals decisions
D-148 through D-157: camera angle, live 3D characters, inverted hull outline, server facings, performance LOD, player indistinction, cardinal rotation, faction colors as narrative, alarm clock game start. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+2
-2
@@ -10,10 +10,10 @@ Cross-domain decisions live in one file with cross-reference notes in related fi
|
||||
|
||||
| File | Domain | Decisions |
|
||||
|------|--------|-----------|
|
||||
| [architecture.md](architecture.md) | Technical foundation | D-008, D-009, D-010, D-012, D-020, D-026, D-030, D-031, D-041, D-042, D-054, D-055, D-066, D-068, D-073, D-085, D-088, D-094, D-096, D-097, D-099, D-100, D-101, D-102, D-103, D-106, D-108, D-109, D-113, D-133, D-134, D-135, D-136, D-137 |
|
||||
| [architecture.md](architecture.md) | Technical foundation | D-008, D-009, D-010, D-012, D-020, D-026, D-030, D-031, D-041, D-042, D-054, D-055, D-066, D-068, D-073, D-085, D-088, D-094, D-096, D-097, D-099, D-100, D-101, D-102, D-103, D-106, D-108, D-109, D-113, D-133, D-134, D-135, D-136, D-137, D-141, D-148, D-149, D-150, D-151, D-152 |
|
||||
| [perception.md](perception.md) | Player observation | D-011, D-015, D-016, D-017, D-018, D-019, D-033, D-035, D-043, D-044, D-045, D-046, D-047, D-048, D-049, D-052, D-056, D-057, D-058, D-059, D-060, D-061, D-067, D-069, D-070, D-071, D-072, D-076, D-077, D-078, D-086 |
|
||||
| [content.md](content.md) | NPC, dialogue, templates | D-023, D-024, D-025, D-028, D-029, D-032, D-034, D-035, D-036, D-037, D-050, D-062, D-063, D-064, D-074, D-075, D-084, D-090, D-092, D-093, D-095, D-098, D-104, D-105, D-107, D-121, D-122, D-123, D-124, D-125, D-126, D-127, D-128, D-129, D-130, D-131, D-132, D-138, D-139, D-140, D-142, D-147 |
|
||||
| [scope.md](scope.md) | Game concept, prototype | D-001, D-003, D-005, D-006, D-007, D-013, D-014, D-027, D-038, D-039, D-051, D-053, D-065, D-087, D-089, D-091, D-114, D-115, D-116, D-117, D-118, D-119, D-120, D-145, D-146 |
|
||||
| [scope.md](scope.md) | Game concept, prototype | D-001, D-003, D-005, D-006, D-007, D-013, D-014, D-027, D-038, D-039, D-051, D-053, D-065, D-087, D-089, D-091, D-114, D-115, D-116, D-117, D-118, D-119, D-120, D-145, D-146, D-153, D-154, D-155, D-156, D-157 |
|
||||
| [process.md](process.md) | Team, workflow | D-004, D-021, D-022, D-040 |
|
||||
| [questions.md](questions.md) | Open questions (index) | Q-001 through Q-054 |
|
||||
| [questions-architecture.md](questions-architecture.md) | Technical questions | Q-001, Q-006, Q-009, Q-018–Q-023, Q-029, Q-030, Q-046 |
|
||||
|
||||
@@ -492,4 +492,54 @@ Technical foundation decisions that constrain implementation: engine, client-ser
|
||||
|
||||
---
|
||||
|
||||
*39 decisions. Last updated: 2026-03-13 (D-141 added — PlatformInfo OS abstraction)*
|
||||
### D-148: 30° low-angle camera with 45° map rotation — supersedes D-019
|
||||
- **Date:** 2026-03-17
|
||||
- **Decision:** The default gameplay camera is an orthographic Camera3D at **30° tilt** (60° from horizontal) with the tile map rotated **45°** into a diamond grid. Not faked in art — an actual Camera3D tilt. Art direction reference: Hades, Divinity: Original Sin. Camera tilt cycle (T key in prototype): top-down → 45° isometric → 30° low-angle. 30° is the confirmed default. The 45° map rotation gives natural depth cues and the classic diamond-grid isometric layout.
|
||||
- **Rationale:** The 30° angle (versus 45° or top-down) gives significantly more character front visibility and wall depth. Players can see faces, clothing, and character detail rather than primarily hat and shoulder. The diamond grid provides natural spatial depth cues without requiring Z-ordering hacks. The T-key prototype confirmed 30° as the most readable angle at gameplay scale.
|
||||
- **Architecture note:** Unlike D-019's amendment (which faked tilt in sprite art), this is a real Camera3D setting. The 45° map rotation is a Transform3D applied to the tile grid root — it does not affect simulation coordinates, which remain axis-aligned. Vision cone math and all server-side systems remain in unrotated space; the client applies the visual rotation.
|
||||
- **Raised by:** Team Leader (Jeroen) — confirmed during Sprint 28 character visuals spike review
|
||||
- **Dissent:** None
|
||||
- **Supersedes:** [D-019](perception.md#d-019-top-down-confirmed-as-primary-camera-3d-cutscenes-for-key-moments)
|
||||
- **Cross-reference:** [D-149](#d-149-3d-characters-rendered-live-in-scene--not-pre-rendered-sprites) (3D rendering), [D-151](#d-151-direction-count--8-server-side-facings-4-visual-groups-client-sprint-28) (direction count)
|
||||
|
||||
### D-149: 3D characters rendered live in scene — not pre-rendered sprites
|
||||
- **Date:** 2026-03-17
|
||||
- **Decision:** Characters are rendered as live 3D models in the Godot scene using a `CharacterCompositor` (Node3D). The camera is a real Camera3D at 30° tilt (D-148). Characters are not pre-rendered 2D sprite sheets. The 3D model is rotated to match the server-tracked 8-direction facing; the camera and lighting remain fixed. Clothing, hair, and accessories are separate mesh layers composited at runtime.
|
||||
- **Rationale:** The Sprint 28 spike used CSG placeholder characters (cylinders, spheres) and confirmed that even crude 3D shapes read as recognizable people at isometric scale — silhouette, proportion, and facing direction are all legible. Pre-rendered sprites would require 8× (or 4×) separate renders per outfit combination; live 3D compositing gives unlimited clothing/color combinations at negligible extra render cost. Direction changes are a model rotation, not a sprite swap. Future animation is natural.
|
||||
- **Architecture note:** The existing `EntityRenderer` (`client/scripts/rendering/entity_renderer.gd`) currently uses a single `Sprite2D` per entity. Under this decision, `EntityRenderer` is extended to instantiate a `CharacterCompositor` scene (Node3D subtree) instead. The compositor API is specified in `docs/design/compositor-api-spec.md`.
|
||||
- **Raised by:** Team Leader (Jeroen) — spike prototype confirmed; Sprint 28 workshop decision
|
||||
- **Dissent:** None
|
||||
- **Cross-reference:** [D-148](#d-148-30-low-angle-camera-with-45-map-rotation--supersedes-d-019), [D-150](#d-150-character-outline--inverted-hull-method), [D-151](#d-151-direction-count--8-server-side-facings-4-visual-groups-client-sprint-28), [D-152](#d-152-character-lod--performance-driven-budget-not-distance-threshold), ticket #693 (compositor implementation)
|
||||
|
||||
### D-150: Character outline — inverted hull method
|
||||
- **Date:** 2026-03-17
|
||||
- **Decision:** Character outlines are rendered via the **inverted hull method** (GPU vertex extrusion on a back-face-only render pass). Color: `#1e1e24` (very dark blue-grey) for all characters, always — not pure black. Specified by Araminta (art direction, Sprint 28 Round 2). No screen-space outline system. At LOD tier 2 (billboard impostor), the outline is baked into the impostor sprite — no separate draw call needed at that tier.
|
||||
- **Rationale:** Inverted hull is GPU-cheap, works correctly in 3D space, and produces clean consistent outlines. Screen-space methods (e.g., Sobel filter) are more expensive and produce artifacts at isometric angles. The billboard LOD tier naturally subsumes the outline into the baked sprite, so the system degrades gracefully under performance pressure without special outline handling.
|
||||
- **Raised by:** Sprint 28 workshop consensus (Tyre technical, Jeroen confirmed)
|
||||
- **Dissent:** None
|
||||
- **Cross-reference:** [D-149](#d-149-3d-characters-rendered-live-in-scene--not-pre-rendered-sprites), [D-152](#d-152-character-lod--performance-driven-budget-not-distance-threshold), [D-154](scope.md#d-154-character-outline-is-not-a-relationship-indicator--uniform-dark)
|
||||
|
||||
### D-151: Direction count — 8 server-side facings, 4 visual groups client Sprint 28
|
||||
- **Date:** 2026-03-17
|
||||
- **Decision:** The server tracks **8 facing directions** for all characters (N, NE, E, SE, S, SW, W, NW) — full resolution, future-proof. The client renders **4 visual groups** for Sprint 28: North (covers N, NW), East (covers NE, E), South (covers SE, S), West (covers SW, W). The 3D model is rotated to the true 8-direction angle; only the visual mesh/asset groups are 4-way. E and W groups share mirrored assets. Post-Sprint 28: additional direction-specific mesh variants can be authored for diagonal facings without protocol changes.
|
||||
- **Critical distinction — perception vs. rendering:** The 8 server facings are **perception system input** (fog-of-war, vision cone direction, all simulation logic). The 4 visual groups are **rendering output** (what the player sees). These are not the same thing. Diagonal facings (NE, NW, SE, SW) do not exist as visible character states — a character facing NE renders as East. EntityRenderer maps the server's 8-direction value to a 4-group CharacterFacing before calling the compositor. ModelRoot body rotation uses the true 8-direction angle for subtle lean.
|
||||
- **Rationale:** Hybrid approach (Tyre): 8 server facings ensures the data model never needs migration. 4 client visual groups keeps Sprint 28 asset authoring cost manageable — each new clothing item needs 2 unique meshes (N, E) plus mirroring, not 4 or 8. The 3D rotation to true angle (before the visual group snap) gives subtle body lean and positioning cues even within a visual group. Characters snap to nearest cardinal with smooth rotation interpolation.
|
||||
- **Raised by:** Tyre (hybrid proposal), confirmed by Team Leader (Jeroen) — Sprint 28 Round 2
|
||||
- **Dissent:** None
|
||||
- **Cross-reference:** [D-148](#d-148-30-low-angle-camera-with-45-map-rotation--supersedes-d-019), [D-149](#d-149-3d-characters-rendered-live-in-scene--not-pre-rendered-sprites)
|
||||
|
||||
### D-152: Character LOD — performance-driven budget, not distance threshold
|
||||
- **Date:** 2026-03-17
|
||||
- **Decision:** Character LOD degrades based on GPU **frame budget**, not distance or fixed character count. Three tiers:
|
||||
- **Tier 0 (full):** All characters at full 3D detail with all compositor layers active.
|
||||
- **Tier 1 (simplified mesh):** Reduced-poly model; clothing layers merged into combined mesh; inverted hull still active.
|
||||
- **Tier 2 (billboard impostor):** Flat sprite impostor. Outline baked in. Must visually preserve: (1) body size tier (slim/average/stocky silhouette), (2) dominant clothing color (`cloth_primary`). Applied to characters furthest from player first.
|
||||
LOD trigger is **proactive on projected character count**, not reactive on frame drop. Reactive triggering produces visible hitches; proactive demotion is invisible. LOD demotes characters outward from player: nearest characters always stay at Tier 0 longest. When paused, render budget is fully freed and all characters restore to Tier 0 — player can inspect the scene at leisure. In a chaotic moment (400+ characters on screen), peripheral detail naturally degrades, which matches the cognitive experience of chaos.
|
||||
- **Rationale:** A fixed distance or count threshold would produce visually jarring sudden LOD pops when character density changes (a crowd gathering). Performance-driven budget is adaptive and invisible to the player. The "paused = full detail" design is a deliberate player affordance — it makes the pause button feel powerful.
|
||||
- **Raised by:** Sprint 28 workshop (Jeroen — Q2 resolution)
|
||||
- **Dissent:** None
|
||||
- **Cross-reference:** [D-149](#d-149-3d-characters-rendered-live-in-scene--not-pre-rendered-sprites), [D-150](#d-150-character-outline--inverted-hull-method)
|
||||
|
||||
---
|
||||
|
||||
*44 decisions. Last updated: 2026-03-17 (D-148–D-152 added — Sprint 28 Character Visuals workshop: camera, 3D rendering, outline, direction count, LOD)*
|
||||
|
||||
@@ -76,7 +76,7 @@ How the player observes and interacts with the world: camera, fog, line-of-sight
|
||||
- **v0.1:** Screen-space stereo for close + visual fog-edge indicators for medium. Long-range insert alerts as stretch goal.
|
||||
- **Raised by:** Full team discussion.
|
||||
|
||||
### D-019: Top-down confirmed as primary camera, 3D cutscenes for key moments
|
||||
### D-019: Top-down confirmed as primary camera, 3D cutscenes for key moments [SUPERSEDED by D-148]
|
||||
- **Date:** 2026-02-09
|
||||
- **Decision:** Top-down is the gameplay camera. Final. 3D cutscenes can be used for significant narrative moments (wormhole traversal, Dyson barrier opening, first contact, major reveals).
|
||||
- **Rationale after full honest review:**
|
||||
@@ -90,6 +90,7 @@ How the player observes and interacts with the world: camera, fog, line-of-sight
|
||||
- **v0.1:** Top-down only. No cutscenes. Those are milestone features.
|
||||
- **Amendment (2026-02-12, Art Direction Workshop):** Camera angle specified as **~15-20° from vertical** ("the angle"), rendered in sprite art via orthographic camera. Sprites are drawn as if viewed from a shallow tilt (south-facing front faces visible on objects, entities, and walls), but the Godot camera is purely orthographic — the perspective is an art convention, not a camera setting. Tile grid remains square/orthogonal (64x64). Vision cone math remains pure 2D. 3D render pipeline uses Camera3D at -72.5° from horizontal (midpoint of range) to produce sprites with mathematically correct perspective. Matches Rimworld's approach: orthographic camera, tilt faked entirely in art. Internally referred to as "the angle."
|
||||
- **Raised by:** Team Leader (Jeroen), after full team review of tradeoffs in Round 12. Angle amendment: Team Leader, endorsed unanimously in Art Direction Workshop Round 3.
|
||||
- **Superseded by:** [D-148](architecture.md#d-148-30-low-angle-camera-with-45-map-rotation--supersedes-d-019) — Sprint 28 confirmed 30° low-angle with 45° map rotation as default gameplay camera; 3D live rendering replaces sprite art approach.
|
||||
|
||||
### D-033: Entity color = relationship to player
|
||||
- **Date:** 2026-02-11
|
||||
@@ -106,6 +107,7 @@ How the player observes and interacts with the world: camera, fog, line-of-sight
|
||||
- **Cross-reference:** Internal monologue ([D-016](#d-016-internal-monologue-as-core-perceptionatmosphere-system)), THE FRIEND pattern ([D-034](content.md#d-034-the-friend--production-level-npc-pattern))
|
||||
- **Raised by:** Araminta (Round 1 proposal, color palette design), project lead (approved, directive #2)
|
||||
- **Dissent:** None
|
||||
- **Amendment (2026-03-17, Sprint 28 workshop):** Entity relationship color is NOT displayed via character outlines in normal gameplay. The D-033 color palette (#4a9ebb, #6bc9a6, etc.) is valid within the insert/perception mode overlay only. Normal gameplay renders all characters with uniform dark outlines. See [D-154](scope.md#d-154-character-outline-is-not-a-relationship-indicator--uniform-dark).
|
||||
|
||||
### D-035: Symmetric shadowcasting (Albert Ford) selected for LOS computation
|
||||
- **Date:** 2026-02-11
|
||||
|
||||
+44
-1
@@ -300,4 +300,47 @@ What we're building: game concept, design pillars, prototype definition, map spe
|
||||
|
||||
---
|
||||
|
||||
*26 decisions (17 active, 9 superseded). Last updated: 2026-03-17 (D-146 tile-scale heavy zoom)*
|
||||
### D-153: Player character not visually distinct from NPCs
|
||||
- **Date:** 2026-03-17
|
||||
- **Decision:** The player character uses the same 3D models, same body types, same clothing variety, and same uniform outlines as all other characters. The only visual difference between the player character and NPCs comes from what gear the player chose and bought in-game. No protagonist glow, no saturation boost, no special outline color, no distinct tint.
|
||||
- **Rationale:** This is a life-sim, not an action game. The player character is not a hero with a visual aura — they are a person among people. Visual distinctness would undermine the asymmetric information design: the player's privileged knowledge comes from the insert and perception layers, not from being visually flagged in the world. Immersion requires the player to feel like they live in the world, not observe it from above.
|
||||
- **Raised by:** Team Leader (Jeroen) — Sprint 28 Round 1 overrule
|
||||
- **Dissent:** None (Round 1 proposal for protagonist distinction overruled)
|
||||
- **Cross-reference:** [D-154](#d-154-character-outline-is-not-a-relationship-indicator--uniform-dark), [D-149](architecture.md#d-149-3d-characters-rendered-live-in-scene--not-pre-rendered-sprites)
|
||||
|
||||
### D-154: Character outline is not a relationship indicator — uniform dark
|
||||
- **Date:** 2026-03-17
|
||||
- **Decision:** All character outlines are uniform dark gray/black (#1a1a1a) at all times in normal gameplay. The outline is a rendering artifact (inverted hull) — it carries zero semantic information. Relationship information lives on the minimap, name bubbles, and optionally in a dedicated insert/perception mode overlay. The entity relationship color system (D-033) remains valid within the insert/perception mode context but is NOT displayed via the character outline in normal gameplay.
|
||||
- **Rationale:** If outline color encodes relationship, the player must consciously parse color to extract meaning — this competes with the scene's primary readability job (who is where). The insert is the designed channel for relationship and social data. The outline's only job is silhouette separation from the background.
|
||||
- **Amendment note for D-033:** D-033's entity color palette (#4a9ebb, #6bc9a6, etc.) remains valid as an insert/perception mode overlay, not as the default entity rendering. Normal gameplay shows uniform dark outlines only.
|
||||
- **Raised by:** Team Leader (Jeroen) — Sprint 28 Round 1 overrule
|
||||
- **Dissent:** None (Round 1 proposal for relationship-colored outlines overruled)
|
||||
- **Cross-reference:** [D-033](perception.md#d-033-entity-color--relationship-to-player) (amended — perception mode only), [D-150](architecture.md#d-150-character-outline--inverted-hull-method)
|
||||
|
||||
### D-155: Character editor rotation — cardinal directions only, no free-spin
|
||||
- **Date:** 2026-03-17
|
||||
- **Decision:** The character creation/editor screen allows rotation of the character preview using N/E/S/W cardinal direction buttons only. No free-spin (drag to rotate). The four directions match the four client visual groups from D-151.
|
||||
- **Rationale:** Free-spin would expose intermediate angles that don't correspond to any in-game facing, giving a misleading preview of how the character will actually look during gameplay. Cardinal directions match the visual groups the player will see in-game and build correct expectations. The isometric cognitive model is reinforced, not undermined, by the editor.
|
||||
- **Raised by:** Team Leader (Jeroen) — Sprint 28 Round 1 overrule
|
||||
- **Dissent:** None (free-spin proposal overruled)
|
||||
- **Cross-reference:** [D-151](architecture.md#d-151-direction-count--8-server-side-facings-4-visual-groups-client-sprint-28), [D-146](#d-146-character-creation-preview--tile-scale-sprite-with-heavy-zoom)
|
||||
|
||||
### D-156: Faction colors are narrative, not a visual compositor concern
|
||||
- **Date:** 2026-03-17
|
||||
- **Decision:** Faction affiliation is not encoded in character rendering by the compositor. A faction may optionally adopt shared clothing colors as an emergent narrative pattern (members choose to dress alike), but this emerges from character choices — the compositor does not pipeline faction data into color overrides. No "faction color slot" in the compositor API.
|
||||
- **Rationale:** The game is a life-sim with emergent narrative, not an RTS with team colors. Visual homogeneity within a faction can emerge naturally from shared cultural tastes and social norms (via D-147, aesthetic taste trait), not from a forced compositor rule. Hard-coded faction colors would undermine per-character identity.
|
||||
- **Raised by:** Team Leader (Jeroen) — Sprint 28 Round 1 overrule
|
||||
- **Dissent:** None
|
||||
- **Cross-reference:** [D-147](content.md#d-147-aesthetic-taste-as-character-personality-trait--shared-root-for-cosmetic-and-environmental-expression) (aesthetic taste as shared root), [D-149](architecture.md#d-149-3d-characters-rendered-live-in-scene--not-pre-rendered-sprites)
|
||||
|
||||
### D-157: Game start sequence — alarm clock fade from black, not camera pull-back
|
||||
- **Date:** 2026-03-17
|
||||
- **Decision:** The game begins with a **fade from black** + alarm clock sound, the player character waking up in their apartment. The character creation screen is a separate prior context that does not transition directly into gameplay via a cinematic. No camera pull-back from the editor into the game world.
|
||||
- **Rationale:** The first game moment (D-136: auto-generated apartment + insert activation) is a designed experience — an alarm clock wake-up reinforces the life-sim context and grounds the player in their character's daily reality. A camera pull-back from a creation screen to a game world is a cinematic convention from RPGs where the player is a hero arriving somewhere. The Settled Reach player is already somewhere.
|
||||
- **Raised by:** Team Leader (Jeroen) — Sprint 28 Round 1 overrule
|
||||
- **Dissent:** None (camera pull-back proposal overruled)
|
||||
- **Cross-reference:** [D-136](architecture.md#d-136-first-settled-reach-moment--auto-generated-apartment--insert-activation) (first game moment), [D-146](#d-146-character-creation-preview--tile-scale-sprite-with-heavy-zoom) (character creation as separate context)
|
||||
|
||||
---
|
||||
|
||||
*31 decisions (22 active, 9 superseded). Last updated: 2026-03-17 (D-153–D-157 added — Sprint 28 Character Visuals workshop: player distinctness, outline, editor rotation, faction colors, game start)*
|
||||
|
||||
Reference in New Issue
Block a user