feat(tools): AI detail plates from the reference photography; fix floating windows

Adds Tools/facade_detail_concepts.py: generates architectural detail plates from a
local reference photograph through OpenRouter's image models. Spec-driven (eight
studies: door recess, entrance, column order, entablature/cornice, parapet/motto,
window rhythm, street wall, banner), never overwrites (writes -vN), writes a
.refgen.json sidecar (model, prompt, source photo, SHA-256) per image, and keeps
all output under the gitignored Art/reference/facade-details/ - local only, never
shipped. Stdlib only; http 429/5xx back-off; refuses to write a sidecar containing
the token. 11 tests cover the study table, prompt assembly, next-free naming,
data-URL decoding (both response shapes plus a refusal) and the local-only rule.

Measurement pass on the plates: the hero window panes were at Y -1.98, i.e. 1.44 m
in FRONT of the wall (Y -0.50) and ahead of the column line, so the glazing floated
in the colonnade instead of reading as openings behind it. Moved to Y -0.56; hero
rebuilt, re-imported, DemoMap rebuilt, full screenshot set re-rendered.

Docs: Tools/README row, Screenshots README known-issues entry now records the fix.
This commit is contained in:
zwitschi committed 2026-11-08 17:27:27 +01:00
1 parent 8851b2272e
commit abace2ad05
32 files changed
+487 -45

No files matched your search

+8 -1
View File
@@ -245,10 +245,17 @@ def build():
# --- windows -----------------------------------------------------------
# Two ranks of windows between the columns and behind the colonnade.
# Y must sit on the wall plane: the mass front face is at Y -0.50 and the
# columns stand proud to -1.02. These were at -1.98, i.e. 1.44 m in FRONT of
# the wall and ahead of the column line, so the glazing floated in the
# colonnade instead of reading as openings behind it (visible in the
# review-hero-facade-* shots). WINDOW_Y puts the pane 6 cm proud of the wall,
# safely behind the columns.
WINDOW_Y = -0.56
for rank, z in enumerate((4.4, 8.2), start=1):
for i, x in enumerate(col_xs[:-1], start=1):
wx = x + COLUMN_BAY / 2.0
cube(f"Hero_Window_{rank}_{i}", wx, -1.98, z, 2.0, 0.08, 1.9, glass)
cube(f"Hero_Window_{rank}_{i}", wx, WINDOW_Y, z, 2.0, 0.08, 1.9, glass)
note("Hero_Window_x10", (2.0, 0.08, 1.9), "photographs: window bands behind the colonnade")
return parts, lines