Compare commits

...
5 Commits
Author SHA1 Message Date
jpmschweitzerandClaude Fable 5 bea6c5fc4f chore(meta): update changelog
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 20:52:27 +02:00
jpmschweitzer 3351c595ab Merge remote-tracking branch 'origin/main' into visual-asset-catalog 2026-07-25 20:48:59 +02:00
jpmschweitzerandClaude Fable 5 2ca70d0228 docs(assets): PR #211 review fixes — ratified glazing tokens, D-257, manifest skip contract
Review round (Hoshe + Tyre, both REQUEST_CHANGES) fully addressed:
palette.md's glass carve-out re-keyed from retired never-shipped tokens
(precision_glass/smart_facade) to the ratified glass_curtain_wall (wall)
+ industrial_glazing (facade); the toon/PBR treatment promoted from a
docs-only ruling to D-257 (architecture, cross-refs D-235/D-244/D-043/
D-044/D-033) with palette.md §2 now citing it as authority; D-149 +
D-257 added to decision_refs; manifest.json _comment gains the explicit
underscore-prefix loader skip contract; master pipeline table Visual row
Stub -> Active; conventions.md mask pointer Section 3 -> 5; pre-existing
broken D-066 links in the mood-board transcript repaired (leave-cleaner).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 20:36:47 +02:00
jpmschweitzerandClaude Fable 5 7d5a774fa5 docs(assets): Phase-4 visual style bible in palette.md (T-1052)
Authors the full style bible: camera table separating D-148 gameplay from
D-019 offline-renderer use; the delegated toon-vs-PBR ruling (environment
props share the character toon treatment, with a minimal-PBR carve-out for
glass/polished metal so sightlines read truthfully under occlusion-based
perception); a color/material register for every D-235 ObjectTag (hue,
grain, D-217-keyed weathering); and explicit supersession notes both ways
with visual-grammar-v01.md and the mood-board workshop transcript.
Includes branch-side pql changelog rows (T-1050/T-1052 -> review); the
worktree pre-commit export step failed benignly (write-through had
already refreshed the files) so they are staged explicitly here.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 20:20:21 +02:00
jpmschweitzerandClaude Fable 5 f77e15d075 docs(assets): 3D-model+texture catalog, glb-gen production path, conventions (T-1050)
Instantiates the five D-244 catalog files (models/textures/artwork/icons/
effects — icons carries the 13 as-built SVGs, stance icons traced to their
consumer and marked final), creates client/assets/models/{furniture,props}
with a schema-documented manifest.json mirroring the character manifest,
fixes glb-gen SKILL.md's stale 'path does not exist' paragraph, and authors
docs/assets/visual/conventions.md: category-first model naming (araminta
ruling), mask sidecars per the character convention, D-235-token-keyed
texture naming, footprint_tiles as manifest metadata. Door-state and
TileSet conventions are recorded as explicit deferrals (Phase-5 owned).
visual/README.md carries both this ticket's count/link updates and
T-1052's palette-section rewrite (shared file, committed here).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-25 20:20:04 +02:00
20 changed files with 805 additions and 23 deletions
+8 -5
View File
@@ -95,11 +95,14 @@ Always mirror the category/subcategory path across stages so you can trace
Final game-ready assets are copied to `spikes/3dpipeline/models/` for spike
testing. For production, character GLBs go to `client/assets/characters/`
(already in active use — see its `bodies/`, `clothing/`, `hair/`,
`skeleton/`, etc. subdirectories). `client/assets/models/` does not exist —
there is no established production path yet for non-character categories
(furniture, props); that's a Phase-5 concern (Player control & in-world
rendering, per CLAUDE.md's Development Cascade). Until then, keep
non-character output staged under `.tmp/glb-gen/postproc/`.
`skeleton/`, etc. subdirectories). Non-character categories (furniture,
props) go to `client/assets/models/{furniture,props}/` — register every
promoted asset in `client/assets/models/manifest.json` (schema documented
inline in that file; mirrors the character manifest's per-item pattern).
Promotion = repo-canonical (D-241): an asset entering the manifest AND
`client/assets/models/` **is** the promotion act — nothing stays "promoted"
in `spikes/`. Naming, mask-sidecar, and texture conventions are in
`docs/assets/visual/conventions.md`.
## Post-process in Blender
@@ -2322,6 +2322,7 @@ INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, chang
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPV39JX54HYP83RZJFDM', 'status', 'backlog', 'in_progress', NULL, '2026-07-25 18:11:42', '2026-07-25 18:11:42.948', '2026-07-25 18:11:42.948', NULL, '613156e91577043373205250f21a72cd', 2) ON CONFLICT(hash) DO NOTHING;
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPJ910NNR5T2R9F9NWQR', 'assigned_to', NULL, 'justine', NULL, '2026-07-25 18:11:45', '2026-07-25 18:11:45.571', '2026-07-25 18:11:45.571', NULL, '7fe3851d234f1cafb2b4fc70c1f5eed8', 2) ON CONFLICT(hash) DO NOTHING;
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPV39JX54HYP83RZJFDM', 'assigned_to', NULL, 'araminta', NULL, '2026-07-25 18:11:46', '2026-07-25 18:11:46.095', '2026-07-25 18:11:46.095', NULL, '0d1336d72b0807fe85c054696e914350', 2) ON CONFLICT(hash) DO NOTHING;
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPV39JX54HYP83RZJFDM', 'status', 'in_progress', 'review', NULL, '2026-07-25 18:17:34', '2026-07-25 18:17:34.364', '2026-07-25 18:17:34.364', NULL, 'a903761710732a5f62b742cc7ca4acac', 2) ON CONFLICT(hash) DO NOTHING;
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPJ910NNR5T2R9F9NWQR', 'status', 'in_progress', 'review', NULL, '2026-07-25 18:19:48', '2026-07-25 18:19:48.053', '2026-07-25 18:19:48.053', NULL, '2fa6ce22c32b396a2ea7ac1dd6f64dc0', 2) ON CONFLICT(hash) DO NOTHING;
INSERT INTO ticket_history (ticket_record_id, field, old_value, new_value, changed_by, changed_at, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FSHSYM96N2M9GJTQMF58E4WC', 'description', 'Flagged by stig during the T-1189/T-1192 round (2026-07-25): test_step_canvas_viewer.gd has no injected disk-cache-root seam (unlike test_step_canvas_request.gd, which injects a disposable root), so viewer tests that exercise the disk-cache path against a real-looking body_id (e.g. GJ1c) read/write the REAL user://atlas_cache/ shared across runs — a stale real entry from earlier manual sessions can leak into test behavior. Current mitigation (used by the new T-1189/T-1192 tests and the existing sweep smoke test): distinctive synthetic body_ids. Proper fix: give the viewer suite the same injectable cache-root seam the request suite has (constructor/setter injection through StepCanvasRequest), and migrate the synthetic-body_id tests onto it. Small, test-only.', 'Flagged by stig during the T-1189/T-1192 round (2026-07-25): test_step_canvas_viewer.gd has no injected disk-cache-root seam (unlike test_step_canvas_request.gd, which injects a disposable root), so viewer tests that exercise the disk-cache path against a real-looking body_id (e.g. GJ1c) read/write the REAL user://atlas_cache/ shared across runs — a stale real entry from earlier manual sessions can leak into test behavior. Current mitigation (used by the new T-1189/T-1192 tests and the existing sweep smoke test): distinctive synthetic body_ids. Proper fix: give the viewer suite the same injectable cache-root seam the request suite has (constructor/setter injection through StepCanvasRequest), and migrate the synthetic-body_id tests onto it. Small, test-only.
+49
View File
@@ -3568,6 +3568,55 @@ archiving/marking those superseded, or by palette.md stating exactly what it inh
Lead note (batch-5 activation): the toon-vs-PBR treatment call for environment props is delegated to
araminta (art seat) this batch — her ruling lands in palette.md with rationale; surfaced to Jeroen in
the batch report for cheap veto. VERDICT: READY.', 'in_progress', 'medium', 'araminta', 'visual', 'D-235', '2026-06-12 10:40:59', '2026-07-25 18:11:46.095', NULL, '4df3e92b2bc003a7b73f860dd47704f2', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPV39JX54HYP83RZJFDM', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Write the Phase-4 visual style bible into docs/assets/visual/palette.md', '(description follows in first append)
Refinement (batch-5 Si pass, 2026-07-25) — READY.
CURRENT STATE: docs/assets/visual/palette.md exists as a STUB (correctly re-scoped by D-244 — no
sprite-era content survives in it) — 4 bullets: camera angle (D-019, now superseded by D-148 for
gameplay — palette.md''s bullet is stale and must be corrected), entity colors (D-033), environmental
neutrality (D-045), "functional warmth." It explicitly defers to "art direction workshop synthesis and
first visual sprint" — this ticket IS that synthesis pass for Phase 4.
WHAT D-235 ALREADY FIXES (do not re-litigate): the building-exterior material/roof/facade/street
vocabulary (WallMaterial/RoofForm/FacadeRhythm/StreetSurface, ratified as the 28-template
architecture_trait_catalog.toml / wiki/economics/object_tag_vocabulary.toml) and the fallback-to-generic
mechanism. D-235 is the LOGICAL token layer ("what material is this wall") — Phase 4+ scope per its own
Implementation note ("textured render + the bulk of the theme library are Phase 5+"). T-1052 is the
RENDERED-LOOK layer on top: given a WallMaterial token, what does concrete_wall actually look like
(hue range, texture grain, weathering baseline) when art is eventually produced against it.
WHAT T-1052 MUST STILL AUTHOR (net-new, no existing decision covers this):
- Correct the camera-angle bullet: D-148 (30 deg low-angle Camera3D, supersedes D-019) is the GAMEPLAY
camera; D-019''s -72.5 deg survives only for the offline renderer (2D-artwork / retired sprite mode,
per renderer/README.md). palette.md''s current bullet conflates these — fix it to name both and
which applies where.
- A concrete color/material register for the D-235 token vocabulary: not new tokens, but the RANGE
each token maps to (e.g. "stone_wall reads as warm grey-tan, not cool grey" / "corrugated_metal
weathers to rust-orange, not staying silver") — the thing D-235 explicitly parked for Phase 5+ art
production but which a style bible can pre-specify so future asset generation has a target.
- Reconcile with docs/design/visual-grammar-v01.md and docs/workshops/art-direction-mood-board/
workshop-outcomes.md (both pre-cascade, v0.1-era, sprite-framed) — extract what survives (color
relationships, "functional warmth" identity, D-033 palette) vs what''s superseded by D-235/D-244
(era-based material ladder — explicitly retired by D-235''s own text: "Era is NOT a material filter
here"). Do not leave two contradictory style documents live without a note in one pointing at the
other''s supersession.
- Texture "grain"/rendering treatment for the D-244 3D-object reality: since objects are lit 3D meshes
now (not flat sprite fills), the style bible should say something about the toon/PBR balance —
precedent exists in client/assets/characters/shaders/ (toon.gdshader, toon_masked.gdshader,
outline.gdshader) and the glb-gen postprocess convention (roughness=1.0/specular=0.0 "for toon
compatibility" per .claude/skills/glb-gen/SKILL.md''s setup_materials() note). Confirm whether
environment props share this toon treatment with characters, or diverge — this is a real open
question the style bible should answer, not assume.
ACCEPTANCE: docs/assets/visual/palette.md is no longer a stub; camera-angle bullet corrected;
color/material register for D-235 tokens documented; toon-vs-PBR treatment for props stated;
supersession relationship to visual-grammar-v01.md / workshop-outcomes.md is explicit (either by
archiving/marking those superseded, or by palette.md stating exactly what it inherits from each).
Lead note (batch-5 activation): the toon-vs-PBR treatment call for environment props is delegated to
araminta (art seat) this batch — her ruling lands in palette.md with rationale; surfaced to Jeroen in
the batch report for cheap veto. VERDICT: READY.', 'review', 'medium', 'araminta', 'visual', 'D-235', '2026-06-12 10:40:59', '2026-07-25 18:17:34.364', NULL, '580bf084c1ac42555f672f44b96b6b4a', 2) ON CONFLICT(record_id) DO UPDATE SET type=excluded.type, parent_record_id=excluded.parent_record_id, title=excluded.title, description=excluded.description, status=excluded.status, priority=excluded.priority, assigned_to=excluded.assigned_to, team=excluded.team, decision_ref=excluded.decision_ref, updated_at=excluded.updated_at, deleted_at=excluded.deleted_at, hash=excluded.hash, canonical_version=excluded.canonical_version WHERE excluded.updated_at > tickets.updated_at OR (excluded.updated_at = tickets.updated_at AND excluded.hash > tickets.hash);
INSERT INTO tickets (record_id, type, parent_record_id, title, description, status, priority, assigned_to, team, decision_ref, created_at, updated_at, deleted_at, hash, canonical_version) VALUES ('06FBPTXPJ910NNR5T2R9F9NWQR', 'task', '06FB0TNSRZXCHGS16BFHSSGSV4', 'Create the visual production-status catalog; fix glb-gen production path + naming conventions', '(description follows in first append)
---
+3
View File
@@ -7,6 +7,8 @@ Format based on [Keep a Changelog](https://keepachangelog.com/).
## [Unreleased]
### Added
- **The visual asset pipeline has a production home** (D-244, T-1050) — the 3D-model/texture/artwork/icon/effect catalogs are instantiated with live status tables (the icon set's 13 as-built SVGs inventoried with their real wiring), `client/assets/models/` exists as the promotion target for glb-gen output with a schema-documented manifest, and a single conventions document fixes model naming (category-first), mask sidecars, and D-235-token texture naming — with door-state and TileSet conventions recorded as explicit Phase-5 deferrals rather than silent gaps
- **The Phase-4 visual style bible** (D-257, T-1052) — palette.md is no longer a stub: gameplay vs offline-render cameras untangled, a rendered-look register for every ratified building material/roof/facade/street tag (hue range, grain, weathering), and the newly-recorded D-257 rendering treatment — environment props share the character toon look, with a minimal-PBR carve-out for glazing so glass reads truthfully about sightlines. Exactly one live style authority remains; the superseded v0.1 documents now say so themselves
- **The Atlas can be driven by agents** (D-226, T-971) — a named-intent control channel (AtlasAgentInterface) lets automated QA agents navigate the real Atlas UI through the exact same handlers a click calls: open/select/descend, jump straight to any world coordinate at any zoom step, toggle overlays, and read back a summary of what's on screen — turning the hand-scripted verification drives into a first-class, repeatable QA capability. In-process consumers only for now; a shipped reference driver replaces the ad-hoc scripts
### Changed
@@ -15,6 +17,7 @@ Format based on [Keep a Changelog](https://keepachangelog.com/).
- **Internal: legacy map-window field retired** (T-1159) — the obsolete duplicate zoom-granularity field was removed from the map wire protocol and caches; no player-visible change
### Fixed
- **Map viewer unit tests no longer flake against a warm map cache** (T-1193 first slice) — the viewer test suites rode the machine-shared on-disk atlas cache, so a live play or capture session visiting the same body could flip "nothing has arrived yet" tests in any later test run; viewers under test now pin an isolated cache root through a proper injection seam
- **One coastline at every zoom step** (T-1160) — the whole-body and Region views drew a structurally different coastline than the closer zoom steps (they skipped the deterministic coast-detail warp — about 5% of coastal cells disagreed, displaced up to ~19 km). All six zoom steps now draw the same coastline at their own density: zooming in refines the line instead of moving it. (Game version → 0.4.3: old on-disk map caches refresh automatically)
- **Climate now respects latitude on both hemispheres** (T-1186) — a sign-convention bug made every northern hemisphere read as polar (+90°) and the southern hemisphere read as compressed northern tropics: temperate lakes at 76°S, ice only at the top of the world map. Temperature baselines, glaciation, and everything derived from them now band correctly north AND south of the equator — the same spot near the antarctic circle that used to derive as an 18 °C ice-free lake now comes out at 2 °C under light glaciation
- **Lakes deepen from the shore** (T-1188) — lake shorelines no longer render as hard flat-blue step-edges: every lake cell now carries its settled-hydrology depth band, and the map shades lakes from pale at the water's edge to dark at the deepest point of the basin — the same visual grammar ocean coastlines already had — each lake shaded relative to its own deepest point, so shallow ponds and deep basins both read correctly. (Game version 0.4.0 → 0.4.2: old on-disk map caches refresh automatically)
+24
View File
@@ -0,0 +1,24 @@
{
"_comment": "Environment prop/furniture manifest — schema mirrors client/assets/characters/manifest.json's per-item entry pattern (see docs/architecture/character-asset-organization.md). Keyed by asset name (matches the .glb basename, no extension). One entry per asset, NOT per-body-type variant — environment props are not body-fitted (D-244). An asset entering this manifest AND client/assets/models/ IS the promotion act (D-241); nothing stays 'promoted' in spikes/. Naming/mask-sidecar/texture conventions: docs/assets/visual/conventions.md. CONTRACT: any top-level key prefixed with '_' (this key, '_fields', '_example_only_not_a_real_asset') is metadata/documentation, not an asset category — loaders MUST skip '_'-prefixed keys and must not iterate them as if they were real category/asset entries.",
"_fields": {
"name": "string — asset name, matches the manifest key and the .glb basename",
"category": "string — 'furniture' | 'props' (matches the subdirectory)",
"source_model": "string — path to the .glb under client/assets/models/, e.g. 'furniture/table_baroque.glb'",
"subdirectory": "string — 'furniture' | 'props' (same as category; kept as its own field to match the character-manifest precedent of not deriving one field from another)",
"status": "string — planned | in-progress | placeholder | final (docs/assets/README.md vocab — shared with the catalog tables so manifest and catalog never disagree)",
"footprint_tiles": "[width, height] — multi-tile sim footprint in whole tiles (1 tile = 1m, D-243). Omit (or [1, 1]) for single-tile props.",
"mask": "string, optional — path to the recolor mask sidecar, e.g. 'furniture/table_baroque_mask.png'. Omit if the asset has no tintable region."
},
"_example_only_not_a_real_asset": {
"table_baroque": {
"category": "furniture",
"source_model": "furniture/table_baroque.glb",
"subdirectory": "furniture",
"status": "planned",
"footprint_tiles": [2, 1],
"mask": "furniture/table_baroque_mask.png"
}
},
"furniture": {},
"props": {}
}
View File
+3 -2
View File
@@ -14,7 +14,7 @@ Centralized tracking for all production assets across pipelines. Each pipeline h
| Pipeline | Index | Palette | Status |
|----------|-------|---------|--------|
| [Audio](audio/README.md) | [audio/README.md](audio/README.md) | [audio/palette.md](audio/palette.md) | Active — Sprint 7 |
| [Visual](visual/README.md) | [visual/README.md](visual/README.md) | [visual/palette.md](visual/palette.md) | Stub |
| [Visual](visual/README.md) | [visual/README.md](visual/README.md) | [visual/palette.md](visual/palette.md) | Active — catalog + style bible instantiated (T-1050/T-1052) |
| [Video](video/README.md) | [video/README.md](video/README.md) | [video/palette.md](video/palette.md) | Stub |
## Structure
@@ -24,7 +24,7 @@ docs/assets/
README.md # This file — master index
_templates/
audio.md # Row template + detailed entry template for audio
sprite.md # LEGACY object-sprite row template (D-244 retired sprites; model/texture/artwork template TBD)
sprite.md # LEGACY object-sprite row template (D-244 retired sprites; model/texture/artwork rows are inline in each visual/*.md file, T-1050)
video.md # Row template + detailed entry template for video
audio/
README.md # Audio pipeline index — categories, status summary
@@ -40,6 +40,7 @@ docs/assets/
artwork.md # Flat 2D art — paintings, flags, billboards, signage (via /sprite-gen)
icons.md # UI icons, status indicators (UI layer)
effects.md # Shaders, particles, overlays
conventions.md # Model naming, mask sidecars, D-235-keyed texture naming, footprint metadata (T-1050)
video/
README.md # Video pipeline index
palette.md # Motion/editing style guide
+9 -3
View File
@@ -7,7 +7,8 @@ status: active
# Visual Asset Pipeline
Status: **Stub** — awaiting first visual sprint.
Status: **Active** — catalog structure instantiated (T-1050); awaiting first
model/texture/artwork/effects production sprint.
Per **[D-244](../../../governance/decisions/architecture.md#d-244)**: the in-world view renders **3D objects directly**. The only flattened 2D content is **textures** (PBR maps on 3D surfaces) and **flat 2D artwork** (paintings, flags, billboards, signage) applied as textures/decals on flat surfaces *within* the 3D world. **There is no per-object sprite layer** — game objects are not pre-rendered to sprites.
@@ -19,12 +20,17 @@ Per **[D-244](../../../governance/decisions/architecture.md#d-244)**: the in-wor
| Characters | — | — | 3D meshes composited at runtime via `CharacterVisualDescriptor` — see [character-asset-organization.md](../../architecture/character-asset-organization.md) |
| Textures | [textures.md](textures.md) | 0 | PBR surface maps (BaseColor / Normal / Roughness) for 3D models |
| Artwork | [artwork.md](artwork.md) | 0 | Flat 2D art — paintings, flags, billboards, signage, screen content — applied as textures/decals (via the `/sprite-gen` 2D-artwork generator) |
| Icons | [icons.md](icons.md) | 0 | UI icons, status indicators (2D, UI layer only) |
| Icons | [icons.md](icons.md) | 13 | UI icons, status indicators (2D, UI layer only) — as-built inventory of `client/assets/icons/` |
| Effects | [effects.md](effects.md) | 0 | Shaders, particles, overlays |
Naming, mask-sidecar, D-235-keyed texture, and multi-tile footprint
conventions: [conventions.md](conventions.md).
## Palette
See [palette.md](palette.md) for art direction, "the angle", and colour relationships.
See [palette.md](palette.md) for art direction: camera (D-148 gameplay / D-019
offline-render), the toon-vs-PBR rendering treatment for environment props, the
D-235 ObjectTag color/material register, and entity colour relationships (D-033).
## Pipeline
+41
View File
@@ -0,0 +1,41 @@
---
title: "Artwork — Visual Assets"
description: "Flat 2D artwork asset catalog — paintings, flags, billboards, signage, screen content"
type: design
status: active
---
# Artwork — Visual Assets
Flat 2D art — paintings, flags, billboards, signage, screen content — that
lives as a texture/decal on a flat surface *within* the 3D world. This is one
of the two flattened-2D exceptions under D-244 (the other is
[textures.md](textures.md)); it is not a sprite layer.
## Generation Approach
Produced via the `/sprite-gen` skill's **repurposed 2D-artwork role**
(`renderer/README.md`) — the offline Godot renderer originally built for the
retired object-sprite pipeline (#541 spike), now serving flat-artwork
rendering. Camera/lighting/resolution mechanics from that pipeline are
reused; the "render every entity/object/wall to sprites" framing in
`renderer/README.md` is legacy and does not apply here.
Output is promoted to `client/assets/artwork/` (per `renderer/README.md`'s
own note: flat-artwork output goes to `client/assets/textures` or
`client/assets/artwork`, never `client/assets/sprites/`).
## Assets
| ID | Filename | Status | Type | Notes | Sprint/Ticket |
|----|----------|--------|------|-------|---------------|
No artwork has entered production yet — this table is intentionally empty at
initial creation (T-1050).
## Cross-References
- [conventions.md](conventions.md)
- `renderer/README.md` — repurposed 2D-artwork render pipeline
- `.claude/skills/sprite-gen/SKILL.md`
- [D-244](../../../governance/decisions/architecture.md#d-244-asset-rendering--3d-objects-in-world-2d-limited-to-textures--flat-artwork)
+164
View File
@@ -0,0 +1,164 @@
---
title: "Visual Asset Conventions"
description: "Model naming, mask sidecars, D-235-keyed texture naming, and multi-tile footprint metadata for the 3D asset pipeline"
type: design
status: active
---
# Visual Asset Conventions
Single home for 3D-model and texture naming conventions (D-244 — the in-world
view renders 3D objects directly; there is no per-object sprite layer). This
file is the cross-link target from `.claude/skills/glb-gen/SKILL.md` and the
catalog files in `docs/assets/visual/`.
---
## 1. Model naming
Format: `<category>_<descriptor>.glb`
Examples: `table_baroque.glb`, `chair_modernist.glb`, `door_sliding.glb`.
**Ruling (delegated to Araminta, art seat, batch-5 activation — T-1052):
category-first, not descriptor-first.** Rationale: category-first matches
the shipped, in-active-use character-asset clothing convention
(`<category>_<descriptor>` — `jacket_modern.glb`, `boots_modern.glb`,
`pants_formal.glb`, all live under `client/assets/characters/clothing/`) and
gives every future asset browser/manifest a stable alphabetical grouping by
type (all tables sort together, all chairs sort together). The 3dpipeline
spike's descriptor-first naming (`baroque_table.glb`, `modernist_chair.glb`,
`spikes/3dpipeline/README.md`) was pre-convention scratch work, not a
precedent to preserve — D-241 already treats spike naming as disposable at
promotion time. **Surfaced to Jeroen for cheap veto** (lead delegation note,
T-1050).
`category` is the subdirectory-agnostic object type (`table`, `chair`,
`door`, `lamp`, `statue`); `descriptor` distinguishes style/variant
(`baroque`, `modernist`, `sliding`). Category is not required to match the
`furniture`/`props` subdirectory name — a `statue` and a `table` can both be
`furniture` or both be `props` depending on where they land; the manifest's
`category` field, not the filename, is authoritative for that split.
---
## 2. Mask sidecars
Convention: `<model>_mask.png`, single-channel (R-only greyscale), sitting
next to the GLB — per the character-asset convention (Section 5,
`docs/architecture/character-asset-organization.md`). White = tintable
region, black = preserve original texture (`hint_default_black`: no mask
loaded = no tinting; assets without a mask render with their original
Trellis/authored texture).
Example: `table_baroque.glb` + `table_baroque_mask.png` (this is the existing
Trellis convention already proven in the 3dpipeline spike, just re-ordered to
category-first per Section 1's ruling).
**Multi-region tinting.** If a single-channel mask is insufficient (an item
needs more than one independently-tintable region), follow the RGBA
channel-routed convention from `character-asset-organization.md` Section 11
(T-1089) — R/G/B/A → four independent tints, cross-fading correctly under
bilinear filtering — rather than reinventing a greyscale-band scheme (that
approach was tried for clothing and rejected; see that doc's Section 5
correction). This is the same mechanism, not a parallel one: environment
props reuse the clothing pipeline's multi-region shader family rather than
inventing a props-specific one.
---
## 3. Texture naming (D-235 tokens)
PBR surface maps for building-exterior and environment surfaces are named by
the ratified **ObjectTag vocabulary** (D-235 amendment, T-995,
`wiki/economics/object_tag_vocabulary.toml`), **not** the retired
`renderer/README.md` `<model>_<direction>_<resolution>.png` scheme. That
scheme is direction-indexed for the retired 4-direction sprite render
(`renderer/README.md`'s now-legacy object-sprite mode) and does not apply to
PBR texture maps at all — there is no "direction" for a texture, only **map
type** (basecolor / normal / roughness).
Format: `<object_tag>_<map_type>.png`
Map types: `basecolor`, `normal`, `roughness`. (`metallic` and `ao` may be
added if a material needs them; keep the same `<object_tag>_<map_type>`
shape.)
Examples, drawn from the D-235 ratified tags:
- `concrete_wall_basecolor.png`, `concrete_wall_normal.png`, `concrete_wall_roughness.png`
- `pitched_roof_normal.png`
- `stone_wall_basecolor.png`
- `generic_wall_basecolor.png` (fallback-terminal placeholder — D-235's
fallback hierarchy: every specific tag degrades to a `generic_*` parent
until the specific texture ships, then upgrades in place)
The full ratified axis lists (wall/roof/facade/street + the four `generic_*`
fallback terminals) live in `wiki/economics/object_tag_vocabulary.toml` —
this doc does not duplicate that list; it names the file-naming convention
that keys off it.
---
## 4. Multi-tile footprint metadata
A table or couch spans multiple sim tiles regardless of whether it's
rendered as a sprite or a 3D model — this requirement survived the D-244
pivot unchanged. It is **not** expressed as a filename convention (a
sprite-era assumption); it is a `manifest.json` field:
```json
"footprint_tiles": [2, 1]
```
`[width, height]` in whole tiles (1 tile = 1m, D-243's voxel unit). Single
Sunday-tile props omit the field or set it to `[1, 1]`. See
`client/assets/models/manifest.json`'s `_fields` block for the authoritative
field definition alongside the rest of the per-asset schema.
---
## 5. Deferred — door state handling (NOT authored here)
**Do not port a state-frame suffix convention** (e.g. `door_open.glb` /
`door_closed.glb`). An earlier draft of this ticket (2026-06-16, since
superseded) proposed exactly that — baked open/closed GLB variants — which is
sprite-era thinking (baked state = baked frame) carried over from the retired
object-sprite model.
For a 3D object, the door's open/closed/locked/sealed state (T-979/T-998's
`DoorSpec`: `Open` / `Closed` / `TemporalWindow` / `Locked` / `Sealed`) is a
**runtime transform/animation on one door `.glb`**, not separate baked
models. The actual mechanism — `AnimationPlayer` swing vs. procedural hinge
rotation vs. a door-model convention with a named "open" bone — is a
**Phase-5 rendering decision** (player control + in-world rendering, per the
cascade), not a Phase-4 asset-catalog concern.
This doc records only the negative constraint above (no state-frame suffix
files). The positive mechanism is deferred to whichever Phase-5 ticket
handles door rendering — do not invent a runtime convention here.
---
## 6. Deferred — Godot TileSet resource organization (OUT OF SCOPE)
A `<tileset>/<tile_id>.tres` convention is **out of scope for this doc and
this phase**, removed from the ticket that spawned this file. Reason:
`client/scripts/rendering/tile_renderer.gd`'s `TileSet` is an
explicitly-labeled placeholder ("programmatic TileSet with placeholder
colored rectangles," D-014), and the cascade rule (`CLAUDE.md`) states the
current in-world rendering code is "left as-is until Phase 5 — do not build
on it or rip it out before then." Authoring a `.tres` resource-organization
convention now would mean building on Phase-5-owned code from Phase 4. This
section is intentionally not written; a future Phase-5 ticket owns it.
---
## Cross-References
- [D-244](../../../governance/decisions/architecture.md#d-244-asset-rendering--3d-objects-in-world-2d-limited-to-textures--flat-artwork) — 3D objects in-world; 2D limited to textures + flat artwork.
- [D-241](../../../governance/decisions/process.md#d-241-spike-binary-artifacts-are-local-only--gitignored-never-tracked) — spike binaries local-only; promotion = repo-canonical.
- [D-235](../../../governance/decisions/architecture.md#d-235-building-exterior-visual-grammar-and-material-vocabulary) — ObjectTag vocabulary, ratified in `wiki/economics/object_tag_vocabulary.toml` (T-995).
- [D-243](../../../governance/decisions/architecture.md#d-243) — spatial scale ladder (1m voxel/tile unit for `footprint_tiles`).
- `docs/architecture/character-asset-organization.md` — Sections 3, 5, 11 (mask sidecar precedent, multi-region RGBA convention).
- `client/assets/models/manifest.json` — the schema this doc's naming/metadata conventions feed.
- `.claude/skills/glb-gen/SKILL.md` — the production pipeline that writes to `client/assets/models/`.
+41
View File
@@ -0,0 +1,41 @@
---
title: "Effects — Visual Assets"
description: "Shader, particle, and overlay asset catalog"
type: design
status: active
---
# Effects — Visual Assets
Shaders, particles, and overlays — the visual-effects layer distinct from
models/textures/artwork/icons. Includes both 3D-scene shaders (toon,
recolor-mask, outline) and 2D `CanvasLayer` overlays (fog, cognitive-delay
cues).
## Generation Approach
Hand-authored GDShader files, proven in the 3dpipeline and quaternius-
aesthetic spikes (`toon.gdshader`, `toon_masked.gdshader`,
`outline.gdshader`, `toon_garment.gdshader` — see
`docs/architecture/character-asset-organization.md` Sections 2 and 11 for
the shader family already in production use under
`client/assets/characters/shaders/`). New effects (particles, screen-space
overlays) are authored per-need; there is no generation pipeline analogous to
`/glb-gen`/`/sprite-gen` for this category.
## Assets
| ID | Filename | Status | Type | Notes | Sprint/Ticket |
|----|----------|--------|------|-------|---------------|
This table intentionally excludes the character shader family already
tracked and documented in `character-asset-organization.md` (`toon.gdshader`,
`toon_masked.gdshader`, `outline.gdshader`, `toon_garment.gdshader`) — that
doc is their canonical home. This file catalogs effects/particles/overlays
that don't already have a home elsewhere; none exist yet (T-1050 initial
creation).
## Cross-References
- `docs/architecture/character-asset-organization.md` — character shader family (canonical home, not duplicated here)
- [D-244](../../../governance/decisions/architecture.md#d-244-asset-rendering--3d-objects-in-world-2d-limited-to-textures--flat-artwork)
+50
View File
@@ -0,0 +1,50 @@
---
title: "Icons — Visual Assets"
description: "UI icon asset catalog — as-built inventory of client/assets/icons/"
type: design
status: active
---
# Icons — Visual Assets
UI icons and status indicators. 2D, UI layer only — not part of the D-244 3D
in-world pivot (icons render on `CanvasLayer`, not in the 3D scene).
## Generation Approach
Hand-authored SVGs, tinted at runtime via `res://shaders/icon_tint.gdshader`
(see `client/ui/stance_indicator.gd` for the tint-shader integration
pattern).
## Assets
13 SVGs already exist in `client/assets/icons/` — this is the as-built
inventory, not a zero-start table.
| ID | Filename | Status | Category | Notes | Sprint/Ticket |
|----|----------|--------|----------|-------|---------------|
| ICO-001 | `icon_stance_walk.svg` | final | Stance | Wired into `client/ui/stance_indicator.gd` (`StanceIndicator` icon map), tinted via `icon_tint.gdshader`. | — |
| ICO-002 | `icon_stance_sprint.svg` | final | Stance | Wired into `stance_indicator.gd`. | — |
| ICO-003 | `icon_stance_careful.svg` | final | Stance | Wired into `stance_indicator.gd`. | — |
| ICO-004 | `icon_stance_crouch.svg` | final | Stance | Wired into `stance_indicator.gd`. | — |
| ICO-005 | `icon_action_examine.svg` | placeholder | Action | SVG exists; not yet wired into a script/scene. | — |
| ICO-006 | `icon_action_follow.svg` | placeholder | Action | SVG exists; not yet wired into a script/scene. | — |
| ICO-007 | `icon_action_observe.svg` | placeholder | Action | SVG exists; not yet wired into a script/scene. | — |
| ICO-008 | `icon_action_talk.svg` | placeholder | Action | SVG exists; not yet wired into a script/scene. | — |
| ICO-009 | `icon_item_access_token.svg` | placeholder | Item | SVG exists; not yet wired into a script/scene. | — |
| ICO-010 | `icon_item_comm_log.svg` | placeholder | Item | SVG exists; not yet wired into a script/scene. | — |
| ICO-011 | `icon_item_manifest.svg` | placeholder | Item | SVG exists; not yet wired into a script/scene. | — |
| ICO-012 | `icon_status_health.svg` | placeholder | Status | SVG exists; not yet wired into a script/scene. | — |
| ICO-013 | `icon_status_perception.svg` | placeholder | Status | SVG exists; not yet wired into a script/scene. | — |
`Status` here follows the shared vocab (`docs/assets/README.md`):
`final` = shipped and wired into a consuming script/scene; `placeholder` =
asset exists on disk but has no confirmed runtime consumer yet. If a
teammate wires one of the placeholder icons into a script, flip its row to
`final` and note the consumer, matching the `icon_stance_*` rows above.
## Cross-References
- `client/assets/icons/` — the SVG files this table catalogs
- `client/ui/stance_indicator.gd` — the one confirmed consumer (stance icons)
- `res://shaders/icon_tint.gdshader` — runtime tint shader
+48
View File
@@ -0,0 +1,48 @@
---
title: "Models — Visual Assets"
description: "3D object/furniture/prop asset catalog — status table for the Trellis glb-gen pipeline"
type: design
status: active
---
# Models — Visual Assets
3D objects and furniture/props rendered directly in-world as `.glb` meshes
(D-244 — no per-object sprite layer). Produced via the Trellis image→3D
pipeline (`/glb-gen`), promoted per D-241 into `client/assets/models/`.
## Generation Approach
- **Concept image:** `/image-gen` produces a concept PNG (square, plain dark
background, single object centered, 3/4 front view — see
`.claude/skills/glb-gen/SKILL.md` "Input Requirements").
- **Image → 3D:** Trellis (`tower-of-joy:11510`) converts the concept image
to a raw `.glb` (`/glb-gen`).
- **Post-process:** Blender normalizes scale, centers the mesh, generates the
recolor mask sidecar, and sets up materials for toon rendering
(`.claude/skills/glb-gen/scripts/postprocess_glb.py`).
- **Promotion:** the finished `.glb` (+ mask, if tintable) lands in
`client/assets/models/{furniture,props}/` and is registered in
`client/assets/models/manifest.json` — that registration + placement act
**is** the promotion (D-241); it does not stay a "promoted" spike artifact.
Naming, mask-sidecar, and multi-tile footprint conventions:
[conventions.md](conventions.md).
## Assets
| ID | Filename | Status | Category | Footprint | Notes | Sprint/Ticket |
|----|----------|--------|----------|-----------|-------|---------------|
No models have entered production yet — this table is intentionally empty at
initial creation (T-1050). Rows are added as assets are promoted into
`client/assets/models/manifest.json`; keep this table's `Status` column in
sync with the manifest's `status` field (shared vocab: planned /
in-progress / placeholder / final, `docs/assets/README.md`).
## Cross-References
- [conventions.md](conventions.md) — naming, mask sidecars, footprint metadata
- `client/assets/models/manifest.json` — the machine-readable per-asset registry
- `.claude/skills/glb-gen/SKILL.md` — production pipeline
- [D-244](../../../governance/decisions/architecture.md#d-244-asset-rendering--3d-objects-in-world-2d-limited-to-textures--flat-artwork), [D-241](../../../governance/decisions/process.md#d-241-spike-binary-artifacts-are-local-only--gitignored-never-tracked)
+283 -10
View File
@@ -1,23 +1,296 @@
---
title: "Visual Palette"
description: "Art direction guide covering camera angle, entity colours, environmental neutrality, and functional warmth"
description: "Phase-4 visual style bible — camera, entity colours, environmental neutrality, D-235 material register, toon/PBR rendering treatment"
type: design
status: active
decision_refs: [D-019, D-033, D-045, D-148, D-149, D-217, D-232, D-235, D-244, D-257]
author: "Araminta"
updated: 2026-07-25
---
# Visual Palette
Status: **Stub** — reference art direction workshop output for current guidance.
Status: **Active** — Phase-4 style bible (T-1052). This document is the current
source of truth for rendered-look art direction. It supersedes the framing (not
every individual data point) of the two documents listed in
[Superseded documents](#superseded-documents) below.
See `docs/workshops/art-direction-mood-board/` for the established visual identity.
---
## Key Decisions
## 1. Camera
- **Camera angle:** 15-20deg from vertical ("the angle"), rendered via orthographic Camera3D at -72.5deg from horizontal (D-019)
- **Entity colors:** Relationship-based per D-033 (green = known/friendly, amber = neutral, red = hostile, etc.)
- **Environmental neutrality:** Spaces don't visually shift with narrative state (D-045)
- **Functional warmth:** Industrial infrastructure that people made livable — not military, not luxury
Two camera records exist and apply to **different surfaces** — this was
previously conflated in this document; corrected here.
## Style Guide
| Camera | Angle | Where it applies | Status |
|--------|-------|-------------------|--------|
| **D-148** | 30° low-angle `Camera3D` tilt (−30° from horizontal in the confirmed preset convention — see D-148's 2026-07-06 editorial note), 45° static map rotation | **Gameplay** — the default in-world camera, Phase 5+ | Active, confirmed default |
| **D-019** | −72.5° from horizontal (midpoint of the old "15–20° from vertical" sprite-tilt range) | **Offline renderer only** — the retired 2D-sprite production pipeline (`renderer/`, now repurposed per D-244 as the flat-2D-artwork generator; see `renderer/README.md`) | Superseded for gameplay by D-148; survives only as an offline-render setting |
To be populated from art direction workshop synthesis and first visual sprint.
**Why both survive:** D-148 replaced D-019 as the *gameplay* camera when the
project pivoted to live 3D rendering (D-149) and then to fully 3D objects
(D-244) — there are no more pre-rendered sprites to view "at the angle" during
play. D-019's −72.5° Camera3D setting doesn't disappear, though: it is still
the correct setting for the **offline** render rig that produces flat 2D
artwork (paintings, flags, billboards, signage — the D-244(b) content class),
because that pipeline still renders a 3D scene down to a flat texture and
needs a camera angle to do it. Two different cameras, two different jobs:
one drives what the player sees, the other bakes a flat image asset.
Do not describe D-019's angle as "the gameplay camera" anywhere — that
sentence is what this document is correcting.
---
## 2. Rendering Treatment — Toon vs. PBR
**Authority: [D-257](../../../governance/decisions/architecture.md#d-257)**
(environment props share the character toon shading treatment; minimal-PBR
carve-out for glazing). This section is the practical guidance derived from
that record — the binding decision and its full rationale live in D-257, not
here.
**Environment props and furniture share the character toon treatment.** One
shader family, one look, across the whole in-world scene — with a single,
narrow, explicitly-named exception for glass and polished/mirror-finish metal,
which get a distinct minimal-PBR material rather than being forced through
the flat toon response.
### 2.1 What "sharing the toon treatment" means concretely
- Environment `.glb` models use the same shader family as characters:
`toon.gdshader` (flat lit/shadow-band ALBEDO, no PBR lighting response) or
`toon_masked.gdshader` (recolor-mask variant, for props that need
runtime tint — e.g. a favorite-color object, a faction-liveried crate)
where a tintable variant is needed. `outline.gdshader` (inverted-hull) applies
to entities and to any prop the visual hierarchy calls out for emphasis (see
§4 tie-in below) — not universally to every static prop, matching the
existing entity > object > structure outline-weight hierarchy.
- glb-gen's postprocess convention of forcing `roughness=1.0` / `specular=0.0`
"for toon compatibility" (`postprocess_glb.py::setup_materials()`) is
**correct and should stay the default** for furniture, crates, signage,
street furniture, wall/roof/facade instances — i.e. the D-235 ObjectTag
vocabulary's bulk. These are flat-lit like characters; PBR specular
highlights on a stucco wall or a wooden table would read as wet/glossy and
contradict the toon language players already learn from characters.
- **Exception — glass and polished/mirror metal:** the ratified D-235 glazing
tokens — `glass_curtain_wall` (wall axis) and `industrial_glazing` (facade
axis) — and any deliberately reflective/polished metal prop (chrome
fixture, mirror, glossy display case) get a **separate minimal-PBR
material**: `roughness` in the 0.05–0.2
range and non-zero `specular`/`metallic` as appropriate, layered so the toon
shadow-band lighting model still governs the base surface response but a
specular highlight and partial reflection are allowed through. This is not
a full PBR material (no environment-map reflections, no fresnel-driven
rim lighting stack) — it is "toon base + a controlled specular term,"
the smallest change that makes glass/chrome read as glass/chrome instead
of matte plastic.
### 2.2 Rationale
- **Visual grammar principle (mine, standing):** consistency compounds. A
station built from one shader family reads as one coherent object, the way
a real Rimworld or Hades scene does. Mixing a toon character against a
PBR-lit room breaks the "one world" read the moment the player looks at
their own hands next to a table.
- **The postprocess default already assumes this.** `setup_materials()`'s
comment ("for toon compatibility") was written for the character pipeline
but Trellis is the *same* generator for environment `.glb`s — there was
never a second postprocess path. Diverging environment props onto full PBR
would mean either forking the postprocess script or hand-overriding every
environment asset's material after generation. Sharing the treatment means
the existing pipeline is already correct and needs no new work.
- **The exception is functionally forced, not a taste call.** A flat-lit
`roughness=1.0` glass pane doesn't read as glass — it reads as a frosted
grey panel, which actively misleads the player about sightlines (can I see
through this?) in a game whose core mechanic is occlusion-based perception.
Where "can the player see through/into this" is gameplay-load-bearing
(`glass_curtain_wall`, `industrial_glazing`, shop windows, interior
partitions), the material needs to look transparent/reflective enough to answer that
question at a glance. This is a narrow, named carve-out — it does not
reopen "should props be PBR," it closes the one case where toon-only
actively lies to the player.
- **Scale check:** this holds at boxes-with-labels (a labelled box has no
material response either way, so the ruling is inert today) and at full
art fidelity (the shader assignment is a material-slot choice per asset,
not a structural decision that needs revisiting later).
### 2.3 What this does NOT change
- D-235's material/token vocabulary (§3) is unaffected — this ruling is about
shader/material *response*, not which WallMaterial/RoofForm tokens exist.
- The character shader files (`toon.gdshader`, `toon_masked.gdshader`,
`toon_garment.gdshader`, `outline.gdshader`) are not modified by this
ruling — environment props reuse them as-is or via a near-identical
environment-scoped shader variant if slot/uniform needs differ
(implementation detail for whoever writes the first environment shader,
not an art-direction fork).
---
## 3. Color / Material Register — D-235 ObjectTag Vocabulary
D-235 (amended 2026-07-07, T-995) ratified the **logical** token vocabulary —
`wiki/economics/object_tag_vocabulary.toml`, 4 axes (wall/roof/facade/street),
32 specific tags + 4 generic fallback parents. D-235's own Implementation note
explicitly parks the **rendered look** of those tokens for "Phase 5+ and
post-launch" art production. This section is that pre-specification: not new
tokens, but the register each shipped tag should render into once art exists,
so asset generation has a target from day one instead of drifting per-artist.
**How to read this table:** "Hue range" is a rendered-look target for the
BaseColor map's dominant tone, expressed relative to D-235's existing rule
that *color is template-bounded* (a cultural palette cue, seed-selected within
range, "always within the template's register") — this section does not
override that; it gives the physically-plausible hue family each material
naturally sits in, which the template's seed then picks within. "Weathering
baseline" describes how the D-217 condition bands (Intact/Worn/Cracked/Broken,
driven by `prosperity_score`) should visually read for that material — i.e.
what "Worn" looks like on brick vs. on corrugated metal.
### 3.1 Wall materials
| Tag | Hue range | Grain / texture character | Weathering baseline (D-217 bands) |
|-----|-----------|---------------------------|-----------------------------------|
| `concrete_wall` | Neutral grey, warm-leaning (`#8a8680`–`#6e6a64`) — never blue-grey/cool-grey | Fine aggregate speckle, subtle formwork seams | Intact: even matte. Worn: rain-streak staining, hairline cracks. Cracked: spalling at edges, exposed aggregate. Broken: structural cracking, rebar-stain bleed. |
| `steel_frame` | Dark warm charcoal (`#3a3632`) frame, infill panel per adjacent tag | Visible bolted/riveted joints, slight surface oxidation tint even when "new" | Intact: factory-primer flat. Worn: surface rust bloom at joints/edges only. Cracked: running rust streaks below joints. Broken: structural rust-through, buckling. |
| `brick_wall` | Warm terracotta-to-ochre (`#9c5a3c`–`#c48a52`), never cool/pink brick | Visible coursing + mortar joint shadow, slight color variance per brick (batch variation) | Intact: crisp mortar lines. Worn: mortar erosion, efflorescence (white mineral bloom). Cracked: spalled brick faces, missing mortar. Broken: collapsed coursing, exposed cavity. |
| `rendered_wall` | Whatever the template's color_range picks — this tag is a **finish**, not a hue driver; render surface is smooth and matte regardless of picked hue | Smooth, minimal grain, occasional hairline render-crack pattern at Worn+ | Intact: clean flat. Worn: surface staining/streaking under sills and joints. Cracked: render cracking, patches of exposed substrate. Broken: large render loss, substrate fully exposed. |
| `stone_wall` | Warm grey-tan (`#a89e8c`–`#8c8172`) — **explicitly not cool grey**; this is the D-235 fallback-graph's flagship "gets it wrong if literal" case | Visible coursing, natural stone color variance tile-to-tile, tool-marked or rough-cut surface depending on template | Intact: clean-cut edges. Worn: lichen/mineral staining in shadowed recesses. Cracked: mortar loss between courses, chipped arrises. Broken: displaced/missing stone units. |
| `timber_wall` | Warm mid-brown (`#7a5c3e`–`#9c7a52`), never grey-driftwood unless template explicitly calls for weathered/coastal register | Visible grain direction, board/plank joint lines | Intact: sealed/painted finish. Worn: graying at exposed edges, finish wear. Cracked: splitting along grain, missing sealant. Broken: rot, structural failure at joints. |
| `stucco_wall` | Warm off-white to sand (`#d8cfc0`–`#c4b89e`) — whitewashed per the tag description, not pure white | Smooth, slight hand-applied texture variance | Intact: clean whitewash. Worn: staining streaks below any protrusion. Cracked: hairline cracking, patch-color mismatch. Broken: large loss exposing substrate. |
| `glass_curtain_wall` | Neutral-to-cool tint on the glass itself (`#c8d4dc` @ low opacity) — see §2.1 PBR exception, this tag needs the specular/transparency carve-out to read correctly | Minimal — reflection/transparency IS the surface character | Intact: clean, full reflectivity. Worn: dust film, reduced reflectivity. Cracked: visible cracked panes, some opacity/frosting. Broken: missing panes, boarded sections. |
| `composite_panel` | Whatever the template picks — this is a **prefab finish** tag like `rendered_wall`, hue is template-driven, not material-driven | Flat, uniform, visible panel-seam grid (regular rhythm, unlike masonry coursing) | Intact: crisp seams, clean finish. Worn: seam staining, minor panel discoloration. Cracked: panel warping, seam gaps. Broken: missing/detached panels. |
| `rammed_earth_wall` | Warm ochre-to-umber banding (`#8a6a48`–`#6e5236`) | Strong horizontal layer banding (the construction method's signature texture) | Intact: crisp banding. Worn: surface erosion softening band edges. Cracked: vertical cracking across bands. Broken: section collapse/erosion loss. |
### 3.2 Roof forms
| Tag | Hue range | Grain / texture character | Weathering baseline |
|-----|-----------|---------------------------|----------------------|
| `flat_roof` | Neutral dark grey (`#4a4844`) membrane | Flat, minimal detail, visible seam lines on membrane roofing | Intact→Broken: ponding stains, membrane cracking, vegetation growth at Broken. |
| `pitched_roof` | Warm dark grey-brown (`#4e463e`) generic shingle/slate register unless a specific tag (below) narrows it | Directional shingle/slate coursing | Moss/lichen accumulation in shadowed pitches as condition drops; missing units at Cracked+. |
| `corrugated_roof` | Weathers to **rust-orange** (`#a65c34` at Worn+), starts galvanized silver-grey (`#a8aaa8`) when Intact — **explicitly does not stay silver**, this is D-235's own worked example | Strong linear corrugation shadow pattern | Intact: clean galvanized sheen. Worn: rust bleeding from fastener points. Cracked: broad rust staining, sheet lifting at edges. Broken: rust-through holes, missing sheets. |
| `clay_tile_roof` | Warm terracotta (`#b56a3e`–`#c8825a`) | Individual tile coursing, slight per-tile hue variance | Moss/lichen in valleys, cracked/slipped/missing tiles as condition drops. |
| `terraced_roof` | Match the deck surface (paved/planted per template), not a distinct roof hue | Flat deck texture, visible rail/parapet line | Surface wear on deck material, planter/rail deterioration at lower bands. |
| `vaulted_roof` | Match wall material register (masonry vaults read as an extension of the wall) | Strong directional shadow from the vault curvature | Standard masonry weathering (see stone/brick wall rows). |
| `green_roof` | Vegetated green, seasonally variable — the one roof tag where hue is intentionally NOT template-locked | Organic, irregular, canopy-like from above | Condition reads as vegetation health/coverage, not surface damage — sparse/patchy at low prosperity, not "broken" in the structural sense. |
### 3.3 Facade rhythms
Facade tags are about **pattern**, not hue — they inherit the wall tag's
color register. Grain/weathering guidance:
| Tag | Grain / texture character | Weathering note |
|-----|---------------------------|-------------------|
| `regular_facade` | Even punched-window grid, no added ornament | Weathers uniformly with the wall tag beneath it. |
| `ornamental_facade` | Raised/carved detail catches shadow distinctly from the flat wall plane | Ornament erodes/chips *before* the flat wall does — detail loss is the earliest visible sign of Worn. |
| `industrial_glazing` | Regular steel-mullion grid, factory-sash proportions (wide, short panes) | Mullion rust (if `steel_frame`) precedes glazing damage. |
| `arcade_facade` | Strong repeating vertical shadow rhythm from the colonnade | Ground-level wear concentrates at column bases (foot traffic), not evenly. |
| `shuttered_facade` | Shutters as a distinct, often higher-saturation accent color against the wall's muted register — this is the one facade tag allowed a saturation bump (bounded by §5's object-tier ceiling below) | Shutter paint fades/peels faster than the wall behind it — a secondary, faster weathering clock on the same building. |
| `screen_facade` | Fine repeating perforation/louvre pattern, strong dappled shadow | Screen material (usually metal or timber lattice) weathers per its own material, independent of the wall plane behind. |
| `colonnade` | Freestanding column rhythm, deep shadow gaps between wall plane and columns | Column bases weather fastest (ground contact, foot traffic) — same principle as arcade_facade. |
| `lattice_screen` | Fine timber/metal lattice, mashrabiya-register — highest facade information-density texture in the set | Individual lattice elements can go missing at Cracked+ without the whole screen reading as "broken." |
### 3.4 Street surfaces
| Tag | Hue range | Grain / texture character | Weathering baseline |
|-----|-----------|---------------------------|----------------------|
| `paved` | Neutral grey (`#66645e`) | Fine asphalt/poured texture, minimal joint pattern | Cracking, pothole pattern, patch-color mismatch (repairs never quite match original pour age). |
| `cobble` | Warm grey-tan, matches `stone_wall`'s register | Strong individual-unit texture, visible mortar/sand joints | Displaced/missing setts at low condition, not surface cracking (it's a unit system, not a monolithic pour). |
| `packed_earth` | Warm ochre-brown (`#7a6248`) | Irregular, rutted, no joint pattern | Erosion channels, puddling, vegetation encroachment at edges as condition drops (or rises — an unmaintained packed-earth street can look "worse" toward Intact-adjacent if it's simply less used, this tag is condition-light). |
| `canal_way` | Water surface — hue driven by reflection/sediment, not a fixed material hue | N/A — water plane, not a solid surface | Water clarity/debris accumulation stands in for the condition ladder here. |
| `elevated_walkway` | Match structural material used (steel_frame/timber/composite per template) | Grated or planked, visible support structure below | Structural weathering per the material tag, plus grate/plank gap wear from foot traffic. |
| `heavy_haul` | Neutral dark grey (`#4e4c48`), reinforced-surface register | Deep rut/track wear pattern, wider joint spacing than `paved` | Track-line wear concentrates on wheel paths, not the full surface — an asymmetric wear pattern unlike `paved`'s even cracking. |
| `boardwalk` | Warm grey-brown weathered timber (`#8a7a64`), coastal/wetland register — assume some grey weathering even at Intact, unlike `timber_wall` | Plank coursing, visible gap joints | Individual plank replacement creates natural color patchwork even at high condition — this is the one street tag where slight inconsistency reads as *authentic*, not neglected. |
### 3.5 Generic fallback placeholders
`generic_wall` / `generic_roof` / `generic_facade` / `generic_street` render
as a **flat, neutral, low-saturation grey** (`#6e6c68`, roughly the mean of
the specific tags' hue ranges above) with **no grain and no weathering
variation** — condition bands still apply structurally (a generic-fallback
wall can still be "Broken" in silhouette/damage terms) but carry no material
texture, so the player reads "this is a wall, its specific material hasn't
loaded yet" rather than mistaking it for a deliberate concrete/stone choice.
This is the visual expression of D-235's fallback chain — a placeholder must
look *unfinished*, not like a legitimate flat concrete building, or its
eventual upgrade-in-place would read as an inconsistent hue reskin instead of
"detail arriving."
---
## 4. What Survives from Prior Documents
Per D-244 (2026-06-16) and this ticket's acceptance criteria, the following
principles from the pre-cascade documents are **inherited**, restated here in
current (3D, D-235-token) terms rather than the old (2D sprite, era-ladder)
terms they were originally written in:
| Inherited principle | Original source | Current expression |
|----------------------|------------------|----------------------|
| **D-033 entity color = relationship to player** | visual-grammar-v01.md §3 | Unchanged — still the live decision, still the single most important color system in the game. Applies to entities regardless of render fidelity (rectangle, sprite, or 3D mesh). |
| **"Functional warmth"** — industrial infrastructure that people made livable, not military/not luxury | workshop-outcomes.md visual identity statements + Gore's naming | Standing mood target for the whole D-235 register above: hue ranges lean warm (terracotta, ochre, warm grey) rather than cool/clinical by default; the *cool* end of the palette is reserved for deliberately institutional template registers, not the default. |
| **Environmental neutrality — strict zero shift (D-045)** | workshop-outcomes.md §1.10 | Unchanged, still active. The D-235 material register above is diegetic/static — condition bands (D-217) shift with simulated `prosperity_score`, never with narrative/investigation state. This document adds no new exception to D-045. |
| **Entity always wins visual ties** (visual hierarchy: entity > object > structure) | visual-grammar-v01.md §1.4 / workshop-outcomes.md §1.4 | Survives as a rendering-order and saturation-hierarchy principle. In 3D terms: entity materials/outlines render at the highest effective saturation and are never occluded in a way that reads ambiguous against a similarly-toned prop. The saturation ceiling table (below) replaces the old sprite-outline-weight table. |
| **Object favorite-color saturation ceiling** | visual-grammar-v01.md §3.6 | Restated: entity colors (D-033) remain the highest-saturation elements in any scene; object/prop colors (including the `shuttered_facade` accent exception in §3.3) stay moderate; structure/material register (§3) stays lowest. Same three-tier ceiling, now anchored to D-235 tags instead of "Era 1/2/3" object palettes. |
| **Readability over beauty** | workshop-outcomes.md Principle 1 | Standing design principle, unchanged, applies to 3D rendering exactly as it applied to sprites. |
| **Lighting-driven atmosphere, not baked mood** | workshop-outcomes.md Principle 2 / visual-grammar-v01.md's "sprites are shape templates" | Re-expressed in §2 above: toon shading gives shape + local shadow-band response; scene lighting (not baked texture darkening) still carries mood. The specific mechanism (Light2D CanvasModulate) is retired with the sprite pipeline, but the principle — materials stay neutral, the lighting rig does the emotional work — carries forward to whatever 3D lighting setup Phase 5 builds. |
---
## 5. Superseded Documents
Two earlier documents overlap this one. Both are **explicitly marked
superseded** here (and should carry a pointer back to this section) so no two
contradictory style documents stay live at the same time:
- **`docs/design/visual-grammar-v01.md`** — already carries its own
superseded banner (2026-06-12, pointing at D-235/D-228 +
character-visuals-spec.md). That banner is correct and unchanged by this
ticket. What's **specifically superseded**: the entire sprite-era
production model (§2 entity sprite dimensions, §4 z-level stack as sprite
layers, §5 typography-for-sprite-canvas sizing, §6 two-tier animation
frame-count tables, §9 resolution chain / Nano Banana workflow, and the
**three-construction-era material ladder** (§1.2–§1.4's Era 1/2/3 zone
palettes) — the era ladder is the exact thing D-235 retired by name
("Era is NOT a material filter here"). What's **not superseded, just
relocated**: D-033 entity color values and D-045 environmental neutrality,
both restated current in §4 above.
- **`docs/workshops/art-direction-mood-board/workshop-outcomes.md`** — this
is a workshop transcript (type: workshop, status: archived) and correctly
stays archived as a historical record; it is **not** live style guidance
and should not be read as such. Its **candidate decisions** (D-042 through
D-051 as originally proposed in §7) were formally recorded as the
perception.md decisions cited throughout this document (D-033, D-043,
D-044, D-045, D-046 etc.) — those decision records are the living
artifact, not the workshop prose. Its **three-construction-era material
system** (§1.8) is superseded by D-235 for the same reason as above. Its
**camera angle content** (§1.2, §9.3) is superseded by D-148 per §1 above.
Everything else in it (lighting three-reference model, fog cone shape,
two-tier animation, insert overlay bloom spec, z-stack layer *concept* —
not its sprite-specific implementation detail) remains valid design
intent, inherited into current decisions rather than into this document
directly.
**Going forward:** this document (`palette.md`) is the single live style
bible for Phase 4+ rendered look. New style guidance should land here, not in
a new parallel document, unless it's genuinely a different concern (e.g. the
model-naming/manifest conventions living in `docs/assets/visual/conventions.md`,
authored separately under T-1050).
---
## Appendix — Decision Cross-References
| Decision | Relevance |
|----------|-----------|
| D-019 | Original top-down camera + offline-renderer −72.5° angle. Superseded for gameplay by D-148; survives for the offline 2D-artwork render rig. |
| D-033 | Entity color = relationship to player. Unchanged, still the primary information-bearing color system. |
| D-045 | Environmental neutrality — strict zero shift. Governs how the D-235 material register (§3) may and may not respond to game state. |
| D-148 | 30° low-angle gameplay `Camera3D`, supersedes D-019 for gameplay. |
| D-149 | 3D characters rendered live in scene, not pre-rendered sprites. Backing precedent for §1's camera reasoning (no more sprites to render "at the angle" during play) and for §2's shared-shader-family argument (characters and environment props come off the same live-3D pipeline). |
| D-217 | Tile condition thresholds (prosperity_score bands) — the weathering-baseline mechanism referenced throughout §3. |
| D-232 | Trait-template catalog — era reframed as maintenance/wear + past-vogue holdover, not a material-tech ladder. Backing rationale for retiring the Era 1/2/3 ladder in §5. |
| D-235 | Building exterior visual grammar + ratified ObjectTag vocabulary (`object_tag_vocabulary.toml`). §3 is this document's rendered-look layer on top of D-235's logical tokens; §2's glazing carve-out names its ratified `glass_curtain_wall`/`industrial_glazing` tokens. |
| D-244 | 3D objects in-world; 2D limited to textures + flat artwork. Establishes the toon-shader-family context for §2 and retires the sprite catalog framing this document used to have. |
| D-257 | Environment props share the character toon shading treatment; minimal-PBR carve-out for glazing. The binding authority for §2 — this document states the practical guidance, D-257 is the decision record. |
+42
View File
@@ -0,0 +1,42 @@
---
title: "Textures — Visual Assets"
description: "PBR surface map asset catalog for 3D model and building-exterior surfaces"
type: design
status: active
---
# Textures — Visual Assets
PBR surface maps (BaseColor / Normal / Roughness) applied to 3D model and
building-exterior surfaces. The only flattened 2D content besides flat
artwork (D-244) — a texture has no "direction," only map type.
## Generation Approach
- **Building-exterior surfaces:** named by the ratified ObjectTag vocabulary
(D-235 amendment, T-995, `wiki/economics/object_tag_vocabulary.toml`) — see
[conventions.md](conventions.md) §3 for the naming convention and the
fallback-hierarchy note (every specific tag degrades to a `generic_*`
parent until its specific texture ships).
- **Model surfaces:** Trellis bakes a texture atlas directly onto the mesh
during `/glb-gen` (no separate texture-authoring step for most
furniture/props) — see [models.md](models.md). This file tracks
**standalone** PBR maps: building-exterior materials and any surface asset
authored or generated independent of a specific model.
## Assets
| ID | Filename | Status | Map Type | ObjectTag | Notes | Sprint/Ticket |
|----|----------|--------|----------|-----------|-------|---------------|
No textures have entered production yet — this table is intentionally empty
at initial creation (T-1050). Per D-235, the texture library itself is
Phase 5+/post-launch work (behind the fallback chain); this file exists now
so the catalog structure is in place ahead of that work landing.
## Cross-References
- [conventions.md](conventions.md) — D-235-keyed texture naming
- [models.md](models.md) — model-baked textures (Trellis atlas bakes)
- [D-235](../../../governance/decisions/architecture.md#d-235-building-exterior-visual-grammar-and-material-vocabulary) — ObjectTag vocabulary + fallback hierarchy
- `wiki/economics/object_tag_vocabulary.toml` — the ratified tag registry
+11 -1
View File
@@ -8,9 +8,19 @@ decision_refs: [D-033, D-043, D-044, D-045, D-046, D-047, D-048, D-049, D-052, D
author: "Araminta"
created: 2026-02-19
updated: 2026-02-20
superseded_by: "D-235/D-228"
superseded_by: "D-235/D-228, docs/assets/visual/palette.md"
---
> **SUPERSEDED (2026-06-12, cascade-refocus sweep):** superseded by D-235/D-228 (generated-world visual grammar) + docs/design/character-visuals-spec.md (character rules). Kept as historical record; do not build against it.
>
> **Style-bible pointer (2026-07-25, T-1052):** the live Phase-4 style bible is
> `docs/assets/visual/palette.md`. Its §4/§5 spell out exactly what survives from
> this document (D-033 colors, "functional warmth," the visual-hierarchy/saturation
> principles) versus what's superseded (the sprite-era production model: entity
> sprite sizing, the 8-layer sprite z-stack, sprite typography sizing, animation
> frame counts, the resolution chain, and — specifically — the **three-construction-era
> material ladder** in §1.2–§1.4, which D-235 retired by name: "Era is NOT a material
> filter here"). Read palette.md first; come back here only for historical
> attribution.
# The Settled Reach — v0.1 Visual Grammar
@@ -18,6 +18,17 @@ decision_refs: [D-015, D-019, D-024, D-031, D-033, D-035, D-041, D-042, D-043, D
**Rounds:** 3 + Closing + Post-workshop technical session (Tyre, Araminta, Stig)
**Status:** Complete — all items resolved, ready for formal decision recording. Pipeline test in progress.
> **Archived transcript, not live style guidance (2026-07-25, T-1052):** this is a
> workshop record — read it for attribution and reasoning history, not as current
> art direction. Its candidate decisions (§7) were formally recorded as the
> perception.md/architecture.md decisions cited throughout (D-033, D-043–D-051); those
> D-records are the living artifact. Its camera-angle content (§1.2, §9.3) is
> superseded by [D-148](../../../governance/decisions/architecture.md#d-148-30-low-angle-camera-with-45-map-rotation--supersedes-d-019).
> Its three-construction-era material system (§1.8) is superseded by
> [D-235](../../../governance/decisions/architecture.md#d-235) ("Era is NOT a material
> filter here"). The current Phase-4 style bible is
> [`docs/assets/visual/palette.md`](../../assets/visual/palette.md) — start there.
---
## Visual Identity Statements
@@ -79,7 +90,7 @@ Each participant's one-sentence answer to "What is this game's visual identity?"
### 1.3 World Composition — Tile-Based
**Dual-scale grid: 0.5m sim tiles, 1m visual tiles (2x retina factor, [D-066](../../decisions/architecture.md#d-066-dual-scale-grid--05m-simulation-1m-visual-2x-retina-factor)). Visual tiles are 64x64px.**
**Dual-scale grid: 0.5m sim tiles, 1m visual tiles (2x retina factor, [D-066](../../../governance/decisions/architecture.md#d-066-dual-scale-grid--05m-simulation-1m-visual-2x-retina-factor)). Visual tiles are 64x64px.**
- Structural tiles (walls, floors, doors): 64x64px per visual tile (= 2x2 sim tiles), muted, minimal outlines, zone palette + era differentiation
- Object tiles (furniture, equipment, containers): 64x64px per visual tile, medium outline (1px), Rimworld object detail as target. All world geometry is 2x2 sim tile minimum.
@@ -108,7 +119,7 @@ Each participant's one-sentence answer to "What is this game's visual identity?"
### 1.5 Entity System
**24x32 pixel footprint within 64x64px visual tiles. Entities occupy 1x1 sim tiles (0.5m) but render across a 2x2 sim tile sprite footprint per [D-066](../../decisions/architecture.md#d-066-dual-scale-grid--05m-simulation-1m-visual-2x-retina-factor).**
**24x32 pixel footprint within 64x64px visual tiles. Entities occupy 1x1 sim tiles (0.5m) but render across a 2x2 sim tile sprite footprint per [D-066](../../../governance/decisions/architecture.md#d-066-dual-scale-grid--05m-simulation-1m-visual-2x-retina-factor).**
- Entity smaller than visual tile = clear figure-ground relationship
- D-033 color as primary information signal
+1
View File
@@ -322,6 +322,7 @@ line in place — keep the Q-record for the audit trail rather than deleting it.
- [D-254: Standalone Atlas companion app — `make atlas`, dual-connection reader](decisions/architecture.md#d-254-standalone-atlas-companion-app--make-atlas-dual-connection-reader) — _architecture_
- [D-255: Body Map Viewer — stepped Atlas render architecture (supersedes the T-1143 continuous-ladder mechanism)](decisions/architecture.md#d-255-body-map-viewer--stepped-atlas-render-architecture-supersedes-the-t-1143-continuous-ladder-mechanism) — _architecture_
- [D-256: Canonical sampling convention — one absolute-metre derive core; the batch layer is a survey raster](decisions/architecture.md#d-256-canonical-sampling-convention--one-absolute-metre-derive-core-the-batch-layer-is-a-survey-raster) — _architecture_
- [D-257: Environment props share the character toon shading treatment; minimal-PBR carve-out for glazing](decisions/architecture.md#d-257-environment-props-share-the-character-toon-shading-treatment-minimal-pbr-carve-out-for-glazing) — _architecture_
## Open questions
+14
View File
@@ -2313,4 +2313,18 @@ Technical foundation decisions that constrain implementation: engine, client-ser
---
### D-257: Environment props share the character toon shading treatment; minimal-PBR carve-out for glazing
- **Date:** 2026-07-25
- **Decision:** Environment props and furniture (the D-235 ObjectTag vocabulary's rendered assets — walls, roofs, facades, street furniture, and freestanding furniture/prop `.glb`s produced via `/glb-gen`) render with the **same toon shader family already used for characters** (`toon.gdshader` / `toon_masked.gdshader`, per `client/assets/characters/shaders/`), not a distinct PBR material response. The glb-gen postprocess convention of forcing `roughness=1.0`/`specular=0.0` ("for toon compatibility," `postprocess_glb.py::setup_materials()`) is confirmed as the correct default for this vocabulary's bulk.
- **Named carve-out — glass and polished/mirror metal.** The ratified glazing tokens — **`glass_curtain_wall`** (D-235 wall axis) and **`industrial_glazing`** (D-235 facade axis) — plus any deliberately reflective/polished-metal prop (chrome fixture, mirror, glossy display case), get a **minimal-PBR material** layered over the toon base: `roughness` in the 0.05–0.2 range with non-zero `specular`/`metallic`, not a full PBR stack (no environment-map reflections, no fresnel-driven rim lighting). The toon shadow-band lighting model still governs the base surface response; only a controlled specular/transparency term is added.
- This binds all future environment-shader and glb-gen-postprocess work; it is not a per-asset style suggestion.
- **Rationale:** Consistency compounds — a station built from one shader family reads as one coherent object; mixing a toon character against a PBR-lit room breaks the "one world" read the instant the player looks at their own hands next to a table (D-043/D-044 visual-hierarchy principles: entities and objects share one legible material language, distinguished by outline weight and saturation tier, not by rendering technology). The postprocess default already assumes this — `setup_materials()`'s "for toon compatibility" comment was written against the one Trellis pipeline that produces both character and environment `.glb`s, so sharing the treatment requires no new postprocess fork. The glazing carve-out is functionally forced, not a taste call: a flat-lit `roughness=1.0` glass pane reads as a frosted grey panel, which actively misleads the player about sightlines in a game whose core mechanic is occlusion-based perception (D-033's asymmetric-information model depends on the player correctly judging what they can and cannot see through). The carve-out is narrow and named — it closes only the case where toon-only actively lies to the player about transparency, and does not reopen "should props be PBR" generally.
- **Raised by:** Araminta (T-1052, delegated art-direction ruling), reviewed by Tyre (PR #211 — flagged the original carve-out's use of retired pre-amendment example tokens `precision_glass`/`smart_facade`, corrected here to the ratified D-235 tokens).
- **Implementation:** `docs/assets/visual/palette.md` §2 (practical guidance, cites this record as authority). Applies to all environment-prop material setup from Phase 4 asset production onward; no existing shipped assets to migrate as of this record's date.
- **Cross-reference:** [D-235](#d-235) (ratified ObjectTag vocabulary — `glass_curtain_wall`/`industrial_glazing` are its tokens, not this record's invention), [D-244](#d-244) (3D objects in-world; establishes the shared Trellis/glb-gen pipeline this record's postprocess argument depends on), [D-043/D-044](perception.md#d-043-art-direction--visual-style-functional-warmth) (visual-hierarchy/"functional warmth" rationale — entity/object/structure share one material language), [D-033](perception.md#d-033-entity-color--relationship-to-player) (the occlusion/asymmetric-information rationale for the glazing carve-out).
- **Dissent:** None.
---
*110 decisions (D-001 through D-256, excluding gaps). Last updated: 2026-07-24 (D-256 — canonical sampling convention: one absolute-metre derive core (`derive_at_metres` family), batch pseudo-grid re-scoped as `SurveyCellPos` survey raster (real newtype), thin-wrapper unification fixing the three-latitude inconsistency and the region-(0,0) climate collapse, exact-position feature judgments, step-canvas fencing; discharges the T-1174 blocker on D-255's T-1181 envelope).*