Files
settled-reach/docs/assets/briefs/furniture-props.md
T
jpmschweitzerandClaude Fable 5 82d44cf483 docs(assets): codify the authored-footprint rule (araminta ruling, PR #214)
footprint_tiles is an authored value, never derived from normalized
mesh geometry — [1,1] defaults only for plausibly-single-tile classes;
ordinarily-multi-tile classes require an explicitly stated footprint at
promotion. Her exact wording in furniture-props.md §3; conventions.md
§4 gains the authored-not-derived sentence pointing at the full rule
(and a pre-existing 'Single Sunday-tile' typo fixed in passing). The
[1,1] values shipped for the four promoted items stand as ruled.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-26 13:03:55 +02:00

132 lines
7.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: "Asset Brief — Furniture / Props"
description: "Interior furniture and small props — manifest categories furniture|props, spike prior art exists unpromoted"
type: design
status: active
ticket: ""
decision_refs: [D-241, D-244, D-257]
author: "Araminta"
created: 2026-07-25
updated: 2026-07-25
---
# Asset Brief — Furniture / Props
One page. Gates its child story — the story does not enter `in_progress`
without this brief attached.
---
## 1. Scope
Freestanding interior objects — the manifest's two categories, `furniture`
(tables, chairs, storage — occupies a footprint, usually multi-tile) and
`props` (smaller/decorative objects — usually single-tile). No D-235
ObjectTag axis applies (that vocabulary is building-exterior only); this
class is closest in spirit to D-235's incremental-content *mechanism*
(specific-to-generic fallback) without the ratified vocabulary itself — an
open question this brief does not resolve (see §5, T-995's ObjectTag
extension). **Real prior art exists and is unpromoted**: the spike's
`models/` tree holds **five** GLBs total — 3 at `spikes/3dpipeline/models/
furniture/` (`furniture`-category) and 2 at `spikes/3dpipeline/models/
props/` (`props`-category: `lion_statue.glb`, mode "fixed", non-tintable;
and `vw_beetle.glb`, a car). Of these five, **four are in this brief's
scope** (3 furniture + `lion_statue`) — this brief's first job is promoting
that spike output through the now-real production path (`client/assets/
models/`, `manifest.json`), not generating from zero. `vw_beetle.glb` is
explicitly **excluded**: it is a vehicle, covered by the Q-067 car deferral
in `deferred.md`, not this brief, regardless of sitting in the same spike
`props/` directory as `lion_statue.glb`. Out of scope: walls, doors, floors
(separate briefs); vehicles (Q-067, deferred — `vw_beetle.glb` per above);
the four `deferred.md` classes (lamp posts, TVs, billboards, barns — those
are furniture-*tier* objects but are formally deferred by name, not folded
into this brief).
## 2. Visual Reference
`palette.md` §2 — furniture and props are explicitly named as sharing the
character toon treatment (`toon.gdshader`/`toon_masked.gdshader`,
`roughness=1.0`/`specular=0.0` default from `postprocess_glb.py::
setup_materials()`), **with the standing glazing/polished-metal carve-out**
(§2.1) applying to any prop that is deliberately glass or mirror-finish
(a display case, a chrome fixture) — minimal-PBR (`roughness` 0.05–0.2,
controlled specular), same rule as building glazing, not a new one. §4's
"functional warmth" mood target and the object-tier saturation ceiling
(entity > object > structure, §4 table) both apply directly: furniture/prop
colors stay moderate saturation, below entity color but the class is allowed
more personality than the structural material register (the
`shuttered_facade` accent-color precedent is the closest analogue — object-
tier is where a saturation bump is permitted, unlike wall/roof/street).
## 3. Naming
`<category>_<descriptor>.glb` per `conventions.md` §1 — the spike's existing
furniture files (`baroque_table.glb`, `modernist_chair.glb`) are
**descriptor-first** and must be **renamed to category-first**
(`table_baroque.glb`, `chair_modernist.glb`) at promotion time;
`conventions.md` §1 explicitly rules the spike naming "pre-convention scratch
work, not a precedent to preserve." `lion_statue.glb` is already
category-first as named and needs no rename. Mask sidecar: `<model>_mask
.png`, single-channel, per §2 — the existing Trellis convention, just
reordered for the renamed furniture items; `lion_statue.glb` is non-tintable
("fixed" mode in the spike) and ships with **no mask sidecar** at all, not an
empty one — `conventions.md` §2's `hint_default_black` default already
covers "no mask loaded = no tinting" for this case. `footprint_tiles` in the
manifest for any furniture with a real multi-tile footprint (a table spanning
`[2, 1]`); most `props`-category items, including `lion_statue`, omit the
field or set `[1, 1]`.
**Footprint for normalized assets** (araminta ruling, PR #214).
Blender-normalized GLBs (`target-width=1.0` postprocess, the spike default)
lose real-world scale — footprint cannot be derived from geometry after
normalization. `footprint_tiles` is therefore an **authored** value, not a
measured one: default `[1, 1]` only holds when the object's real-world class
is plausibly single-tile (chairs, stools, small props, compact desks). Any
item whose class is ordinarily multi-tile (dining tables seating 4+, couches,
beds, wardrobes) needs the promoting author to state an intended real-world
footprint explicitly (in the promotion commit/PR, or a per-item scale note in
the brief) — never left to infer from the normalized mesh.
## 4. Generation Path
Two paths, depending on whether the spike asset is being promoted or a new
one generated: (a) **Promotion path** for the 4 in-scope existing spike
GLBs (3 furniture + `props/lion_statue.glb`) — rename per §3 (furniture
items only; `lion_statue` keeps its name), run through Blender postprocess
if not already toon-compatible, place in `client/assets/models/furniture/`
or `client/assets/models/props/` per actual category, register in
`manifest.json`. This IS the promotion act (D-241) — nothing stays
"promoted" in `spikes/`. `props/vw_beetle.glb` does **not** take this path;
it stays out of scope per §1 (Q-067 car deferral). (b) **New-asset path**,
standard: `/image-gen` concept → `/glb-gen` (Trellis) → Blender postprocess
→ `client/assets/models/{furniture,props}/` + `manifest.json`. Both paths
converge on the same manifest registration step.
## 5. Acceptance
**4 promotable GLBs** enter `models.md` + `manifest.json` at `planned`: the
3 existing spike furniture GLBs (`spikes/3dpipeline/models/furniture/`),
promoted and renamed per §3, plus `spikes/3dpipeline/models/props/
lion_statue.glb`, promoted as-is (no rename, no mask). This satisfies
acceptance without generating anything new, since the prior art already
exists and simply hasn't crossed the promotion boundary. **Excluded from
this count:** `spikes/3dpipeline/models/props/vw_beetle.glb` — a car, held
under the Q-067 deferral in `deferred.md`, not promoted by this brief's
story. Note for the story: whether a `generic_furniture`/`generic_prop`
placeholder parent becomes a formal fallback-chain member (mirroring D-235's
wall/roof/facade/street pattern) is exactly Q-119's open question ("generic
door/floor/furniture parents") — **milestone-0 IF Q-119 resolves yes**, not
resolved by this brief.
---
## Cross-References
- `docs/assets/visual/conventions.md` §1, §2, §4 — category-first naming ruling, mask sidecar, footprint metadata
- `docs/assets/visual/palette.md` §2, §4 — toon/PBR treatment, saturation-ceiling hierarchy
- `docs/assets/visual/models.md` — target catalog
- `client/assets/models/manifest.json`
- `spikes/3dpipeline/models/furniture/` — existing unpromoted prior art (3 GLBs)
- `spikes/3dpipeline/models/props/` — existing unpromoted prior art; `lion_statue.glb` in scope (this brief), `vw_beetle.glb` excluded (Q-067 car deferral, see `deferred.md`)
- D-241 — spike binaries local-only; promotion = repo-canonical