data(assets): promote the four spike GLBs — first production environment assets (T-1204)
table_baroque, chair_modernist, desk_scifi (furniture, with mask sidecars) and lion_statue (props, non-tintable) enter client/assets/models/ under the category-first convention, byte- identical to the spike sources (MD5-verified; spikes/ untouched, vw_beetle excluded per the Q-067 deferral). Postprocess verified already-applied by Blender node-graph inspection (mat_primary, roughness=1.0/specular=0.0 shader inputs — the convenience properties read stale defaults, the graph is authoritative), so not re-run. All four registered in manifest.json at 'planned' with footprint_tiles [1,1] (a flagged judgment call — normalized spike geometry erases real-world scale; the brief ruling goes to araminta in review). In-engine proof: clean headless import + ResourceLoader load + instantiate for all four. Discovery documented in conventions.md §2 + glb-gen SKILL.md: Godot externalizes the GLB's embedded texture as a <model>_Image_0.png sidecar referenced by binary UID — it must be committed or loading breaks with an undiscoverable dependency error. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@@ -104,6 +104,18 @@ Promotion = repo-canonical (D-241): an asset entering the manifest AND
|
||||
in `spikes/`. Naming, mask-sidecar, and texture conventions are in
|
||||
`docs/assets/visual/conventions.md`.
|
||||
|
||||
**Promotion commits three files per tintable model, two for non-tintable.**
|
||||
Copying the `.glb` (+ `_mask.png`, if the asset is tintable) into
|
||||
`client/assets/models/{furniture,props}/` is not the last step — run a
|
||||
headless import (`godot4 --headless --path client --import`) after copying,
|
||||
which generates a third required file, `<model>_Image_0.png`, next to the
|
||||
`.glb`. Godot's scene importer externalizes the GLB's embedded texture to
|
||||
this loose file and the compiled scene references it by UID even with
|
||||
`gltf/embedded_image_handling=3` set (confirmed Godot 4.6, T-1204). It must be
|
||||
committed with the rest — see `conventions.md` §2 for the full failure mode
|
||||
(deleting it breaks `ResourceLoader` loading with a binary UID dependency
|
||||
error that no text search of the compiled `.scn` will surface).
|
||||
|
||||
## Post-process in Blender
|
||||
|
||||
Normalize scale, center, generate recolor mask, adjust materials:
|
||||
|
||||
|
After Width: | Height: | Size: 981 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 1.2 MiB |
|
After Width: | Height: | Size: 45 KiB |
|
After Width: | Height: | Size: 1.0 MiB |
|
After Width: | Height: | Size: 80 KiB |
@@ -19,6 +19,39 @@
|
||||
"mask": "furniture/table_baroque_mask.png"
|
||||
}
|
||||
},
|
||||
"furniture": {},
|
||||
"props": {}
|
||||
"furniture": {
|
||||
"table_baroque": {
|
||||
"category": "furniture",
|
||||
"source_model": "furniture/table_baroque.glb",
|
||||
"subdirectory": "furniture",
|
||||
"status": "planned",
|
||||
"footprint_tiles": [1, 1],
|
||||
"mask": "furniture/table_baroque_mask.png"
|
||||
},
|
||||
"chair_modernist": {
|
||||
"category": "furniture",
|
||||
"source_model": "furniture/chair_modernist.glb",
|
||||
"subdirectory": "furniture",
|
||||
"status": "planned",
|
||||
"footprint_tiles": [1, 1],
|
||||
"mask": "furniture/chair_modernist_mask.png"
|
||||
},
|
||||
"desk_scifi": {
|
||||
"category": "furniture",
|
||||
"source_model": "furniture/desk_scifi.glb",
|
||||
"subdirectory": "furniture",
|
||||
"status": "planned",
|
||||
"footprint_tiles": [1, 1],
|
||||
"mask": "furniture/desk_scifi_mask.png"
|
||||
}
|
||||
},
|
||||
"props": {
|
||||
"lion_statue": {
|
||||
"category": "props",
|
||||
"source_model": "props/lion_statue.glb",
|
||||
"subdirectory": "props",
|
||||
"status": "planned",
|
||||
"footprint_tiles": [1, 1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
After Width: | Height: | Size: 1.3 MiB |
@@ -7,8 +7,8 @@ status: active
|
||||
|
||||
# Visual Asset Pipeline
|
||||
|
||||
Status: **Active** — catalog structure instantiated (T-1050); awaiting first
|
||||
model/texture/artwork/effects production sprint.
|
||||
Status: **Active** — catalog structure instantiated (T-1050); first models
|
||||
promoted (T-1204); textures/artwork/effects production still pending.
|
||||
|
||||
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.
|
||||
|
||||
@@ -16,7 +16,7 @@ Per **[D-244](../../../governance/decisions/architecture.md#d-244)**: the in-wor
|
||||
|
||||
| Category | File | Count | Description |
|
||||
|----------|------|-------|-------------|
|
||||
| Models | [models.md](models.md) | 0 | 3D objects/props (`.glb`) via Trellis (`/glb-gen`), promoted per [D-241] |
|
||||
| Models | [models.md](models.md) | 4 | 3D objects/props (`.glb`) via Trellis (`/glb-gen`), promoted per [D-241] |
|
||||
| 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) |
|
||||
|
||||
@@ -65,6 +65,27 @@ 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.
|
||||
|
||||
**Extracted-texture sidecar (`_Image_0.png`) — generated, must be committed.**
|
||||
On first Godot import of a promoted `.glb`, the scene importer externalizes
|
||||
the model's embedded texture to a loose file next to it,
|
||||
`<model>_Image_0.png` (e.g. `table_baroque_Image_0.png`), and the compiled
|
||||
`.godot/imported/*.scn` references that file by **UID**, as an external
|
||||
dependency — this happens even with `gltf/embedded_image_handling=3` (embed
|
||||
uncompressed) set in `project.godot`, confirmed on Godot 4.6 (T-1204
|
||||
promotion). This file is **machine-generated, never hand-edited** — if it is
|
||||
lost or deleted, a clean re-import (delete the stale `.glb.import` +
|
||||
`.godot/imported/*.scn` cache entry, then re-run `godot4 --headless --import`)
|
||||
regenerates it deterministically. But it **must be committed alongside the
|
||||
`.glb`** it belongs to: deleting it after import breaks loading with
|
||||
`ERROR: Can't load dependency` / `Resource file not found` at `ResourceLoader`
|
||||
time, and critically, **a text grep of the compiled `.scn` will not reveal
|
||||
this dependency** — the reference is a binary-encoded UID (`uid://...`), not
|
||||
a literal path string, so searching the `.scn` for the filename finds
|
||||
nothing. Losing this file costs a full debug cycle (re-copy the source `.glb`,
|
||||
clear the stale `.import`/`.scn` cache, re-import, re-verify) to rediscover
|
||||
what the UID reference actually pointed to — treat it as a required sidecar
|
||||
from the moment of promotion, not disposable import cache.
|
||||
|
||||
---
|
||||
|
||||
## 3. Texture naming (D-235 tokens)
|
||||
|
||||
@@ -33,12 +33,25 @@ Naming, mask-sidecar, and multi-tile footprint conventions:
|
||||
|
||||
| ID | Filename | Status | Category | Footprint | Notes | Sprint/Ticket |
|
||||
|----|----------|--------|----------|-----------|-------|---------------|
|
||||
| table_baroque | `furniture/table_baroque.glb` | planned | furniture | [1, 1] | Promoted from spike (`baroque_table.glb`, renamed category-first); mask sidecar present; spike README flags the mask as "too aggressive — tints the whole model bright white", not yet re-tuned | T-1204 |
|
||||
| chair_modernist | `furniture/chair_modernist.glb` | planned | furniture | [1, 1] | Promoted from spike (`modernist_chair.glb`, renamed category-first); mask sidecar present | T-1204 |
|
||||
| desk_scifi | `furniture/desk_scifi.glb` | planned | furniture | [1, 1] | Promoted from spike (`scifi_desk.glb`, renamed category-first); mask sidecar present | T-1204 |
|
||||
| lion_statue | `props/lion_statue.glb` | planned | props | [1, 1] | Promoted from spike as-is (no rename); "fixed" mode, non-tintable — no mask sidecar per brief §3 | T-1204 |
|
||||
|
||||
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`).
|
||||
These four rows are the first promoted assets (T-1204, `furniture-props.md`
|
||||
brief's first acceptance) — the 3 in-scope spike furniture GLBs plus
|
||||
`lion_statue`, already Blender-postprocessed (`mat_primary`,
|
||||
roughness=1.0/specular=0.0 confirmed via Blender headless inspection) in the
|
||||
spike, so no re-run of `postprocess_glb.py` was needed at promotion time.
|
||||
`vw_beetle.glb` stays excluded (Q-067 car deferral). Footprint is `[1, 1]`
|
||||
for all four — the spike GLBs are Blender-normalized to `target-width=1.0`
|
||||
(max dimension ≤ 1m on every axis after normalization), so none of the actual
|
||||
promoted meshes has real-world geometry spanning more than one tile; the
|
||||
brief's `[2, 1]` table example is illustrative of the convention, not a
|
||||
derived value for these specific assets. Further rows are added as new
|
||||
assets are promoted/generated; 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
|
||||
|
||||
|
||||