D-244 ratifies what the character architecture (D-159..D-164, runtime CharacterVisualDescriptor compositing) and the Trellis env pipeline already implied but no decision had recorded: the in-world view renders 3D objects directly; the only flattened 2D content is textures + flat 2D artwork (paintings/flags/billboards/signage). There is no per-object sprite layer. Roots out the drift: the early-spike 3D->2D sprite pipeline (#541) and the sprite-centric docs/assets/visual catalog were never cleaned out when the project went 3D, so the 2026-06-12 fable-ous audit read them as live and re-injected the dead sprite model into T-1049/T-1050. Fix: - docs/assets/visual/README.md + docs/assets/README.md re-scoped to 3D models + textures + flat artwork (dropped the sprites/tilesets-as-entities framing). - /sprite-gen + renderer/README repurposed as the 2D-artwork generator (paintings/flags/ billboards/signage), not the in-world object format; legacy 4-direction object-sprite mode flagged as retired. - T-961/T-1049/T-1050 already held in backlog pending this. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Settled Reach — 2D Artwork Render Pipeline
Repurposed (D-244). This offline Godot renderer is not the in-world object format. Per [D-244] the in-world view renders 3D objects directly (props via Trellis
.glb//glb-gen; characters via the Quaternius pipeline +CharacterVisualDescriptor); the only flattened 2D content is textures and flat 2D artwork (paintings, flags, billboards, signage). This pipeline began as the #541 3D-to-2D sprite spike and now serves that flat artwork. The "render every entity/object/wall to sprites" framing below is legacy (the retired object-sprite use); the camera / lighting / resolution mechanics remain usable for flat-artwork rendering.
Offline Godot 4 renderer. Produces flat 2D artwork (and, in its legacy mode, 3D-to-2D sprites) at three resolutions from a fixed camera angle, with outlines applied at working resolution.
Camera Specification (D-019)
- Angle: -72.5° from horizontal (= 17.5° from vertical, the midpoint of the 15-20° from vertical range)
- Projection: Orthographic (
size = 1.4) - Position:
(0, 3, 1)— above and slightly in front of the model origin - Godot Transform3D:
Transform3D(1, 0, 0, 0, 0.30071, 0.95372, 0, -0.95372, 0.30071, 0, 3, 1)
This is "the angle" per D-019 amendment (2026-02-12). All entity, object, and wall sprites for v0.1 are rendered at this angle. The Godot gameplay camera is purely orthographic — this tilt is an art convention expressed through the 3D render.
Lighting Rig
Three-point studio rig. All lights have shadow_enabled = false — sprites are shape templates, no baked shadows or directional lighting. The Godot runtime PointLight2D pipeline provides all scene lighting at runtime (D-043).
| Light | Energy | Direction | Purpose |
|---|---|---|---|
| KeyLight | 1.0 | Matches camera angle (-72.5° from horizontal) | Main illumination; ensures front face is lit as the camera sees it |
| FillLight | 0.4 | 45° from right side (-45° pitch, +90° yaw) | Fills shadow opposite the key; no deep-black patches on right face |
| RimLight | 0.3 | 45° from behind (-45° pitch, +180° yaw) | Back-edge accent; defines silhouette boundary for outline processing |
Rationale: Even 3-light coverage ensures no black patches on a convex mesh, keeping surface colors flat and readable for the outline processing step.
Resolution Chain (D-043, D-044)
1024×1024 — source PNG, full fidelity for outline processing
↓ bilinear resize
256×256 — working PNG, outline applied at 4-8px, color #333340
↓ bilinear resize
64×64 — runtime PNG, deployed to client/assets/sprites/
Outline implementation: alpha-mask dilation + flat color fill. Outline width in render_export.gd: outline_width_px = 4 (at 256px = 1px effective at 64px).
Entity Footprint Spec (D-044, D-066)
- Entity sprites occupy a 24×32px footprint within the 64×64 visual tile
- Entities render across a 2×2 sim tile sprite footprint (D-066)
- Visual tile = 64×64px at runtime; sim tile = 32×32px (0.5m)
- NPC model scale:
CapsuleMesh(radius=0.25, height=0.62)at camera size 1.4 produces ~24×32px apparent size in the 64px output tile
Usage
Command Line
# From the repository root
godot --path renderer/ --headless --quit-after 1200 res://render_scene.tscn -- <model_name>
The /sprite-gen skill wraps this command and handles output placement.
Adding a New Model
- Create
renderer/models/<model_name>.tscn— root node is aMeshInstance3D(orNode3Dwith children) - Center the mesh at the origin
- Use a flat
StandardMaterial3D(no baked shadows — just albedo color + roughness) - Run:
godot --path renderer/ --headless --quit-after 1200 res://render_scene.tscn -- <model_name> - Output: 12 PNGs in
renderer/output/(4 directions × 3 resolutions) - Runtime sprites: copy 64px variants to
client/assets/sprites/
Material Guidelines
- Entity sprites: neutral flat material (albedo Color(0.5, 0.5, 0.5)). D-033 relationship color tinting applied at runtime by the client's entity renderer. Outline color (#333340 per D-043) is compatible with all D-033 tint colors — the dark blue-grey outline remains visible against teal, green, amber, and red entity tints.
- Structural sprites: use zone-appropriate texture (
textures/wall_institutional_era1.png, etc.) - No specularity:
metallic = 0.0,roughness = 0.9 - No emission, no normal maps — shape is the signal
Models
| Model | File | Type | Notes |
|---|---|---|---|
wall_structural |
models/wall_structural.tscn |
Structure | 1.0×0.8×0.2 box, institutional era-1 texture |
wall_bar_green |
models/wall_bar_green.tscn |
Structure | 1.0×0.8×0.2 box, green panel texture (model only — no sprites rendered yet) |
npc_generic |
models/npc_generic.tscn |
Entity | Capsule silhouette, neutral grey, 24×32px footprint. Rotationally symmetric — north/south and east/west pairs are near-identical by design (asymmetric silhouettes come from named NPC models with identifying features per D-044). |
Output Naming Convention
<model_name>_<direction>_<resolution>.png
wall_structural_north_64.png
npc_generic_south_256.png
Directions: north, east, south, west (model rotated 0°, 90°, 180°, 270° around Y axis).
Runtime Sprite Path
64px sprites are deployed to: client/assets/sprites/
Naming convention at the client side matches the pipeline output: <model_name>_<direction>_64.png. The 1024 and 256 variants stay in renderer/output/ as pipeline intermediates (gitignored).
Design Constraints
- No baked lighting: sprites are shape templates. Lighting is applied at runtime by Godot's PointLight2D per D-046.
- No baked shadows: shadow direction would conflict with runtime point lights at arbitrary positions.
- No baked mood: flat materials, three-point neutral rig. Zone atmosphere comes from runtime CanvasModulate.
- Outline applied at 256px, not 64px: ensures outline is crisp after bilinear downscale.
- Transparent background:
SubViewport.transparent_bg = true— sprites are PNG with alpha, composited at runtime.
Cross-References
- D-019: Camera angle spec and amendment
- D-043: Art direction — "functional warmth," resolution chain, outline color
- D-044: Visual hierarchy, entity footprint spec
- D-049: Z-level rendering stack (sprites land on layers 2-3)
- D-066: Dual-scale grid, 2×2 sim tile entity footprint