diff --git a/apps/mapgen-studio/.interface-design/system.md b/apps/mapgen-studio/.interface-design/system.md index f5f23c604b..5131f1af41 100644 --- a/apps/mapgen-studio/.interface-design/system.md +++ b/apps/mapgen-studio/.interface-design/system.md @@ -252,9 +252,10 @@ supersedes the Pass-4 dock placement, keeps the console split + icon contract: geometry — regular pointy-top hexes on the odd-R row-offset lattice (the hex-convention audit proved `tile.hexOddQ` mislabels that grid; the model's column-offset projection is not a regular tiling, hence the "squished" - look it produced). Tile borders use ONE graphite ink (`#0d0d11`, α200) in - both themes — dark seams against the fills; never a mid-luminance color - that competes with the data palette. Unfilled tiles draw nothing. + look it produced). Border ink: see the Y-wave amendment below — the X6 + constant-graphite ink (`#0d0d11`, α200) is superseded by the fill-derived + border rule (a page-colored seam dissolved the lattice into dots at fit + zoom). Unfilled tiles draw nothing (unchanged). ## DAG-tab amendment (2026-06-12, handoff-mandated): stage views @@ -278,3 +279,42 @@ Decisions (see `openspec/changes/mapgen-studio-dag-tab/design.md`): view activation, staleTime ∞) — fetch on first activation, cached per recipe; pipeline selection/expansion live in `viewStore` as pipeline-prefixed fields, distinct from map-explore selection. + +## Y-wave amendment (2026-06-12, user-grounded): tile border rule, flat config accordion, selector drift + +- **The one tile-border RULE (supersedes X6's constant ink):** a tile's + border is its OWN fill pulled toward black (`fill × 0.55`, fully opaque) — + self-grout, owned by `tileBorderColorForFill` in `presentation.ts`. The X6 + page-substrate constant was invisible between dark fills at fit zoom + (Huge-map tiles are a few pixels wide), dissolving the tessellation into + dots; a fill-derived seam is darker than its fill BY CONSTRUCTION, so the + lattice reads at every zoom, both themes, every palette — and still + recedes like etched grout up close. Unfilled tiles still draw nothing. +- **Default layer preference: the map studio defaults to the MAP.** When + layer selection resets (step/stage switch, fresh manifest), prefer the + step's tile-space GRID layer over whichever layer the worker emitted + first (points/mesh). Owned by `useVizState`'s selection fallback. +- **The graticule is CANVAS substrate, not layer furniture.** Once a + manifest exists, the background grid follows the user's grid toggle on + EVERY stage — kind-independent, including steps with no visible layers + (the canvas stays a ready survey field, never dead space); a layer may + opt out via `meta.showGrid: false`. The old points/segments-only gate + made the grid vanish on most stage switches. Pre-manifest, the + awaiting-matter overlay carries its own graticule. +- **Flat config accordion (supersedes the Pass-3 stage CARD):** top-level + config objects lay flat on the panel — full-bleed disclosure rows, + hairline dividers (`divide-border-subtle`), zero inter-item margin, no + card chrome. Expanding opens a RECESSED slab (`bg-surface-sunken/60`, + hairline top) — the interaction reads as a door opening INTO the + graphite, never a card lifting off it. Group wells keep their one + machined-slot tier inside the slab; the Pass-3 4/8px field rhythm is + unchanged; the 12px inter-card step is retired. +- **Selector drift affordance (categorical):** any selector that names a + source of truth (saved game config; world/map config) must SHOW when the + current state has drifted from that source — warning(orange) ring on the + control + a warning "Modified" pill whose click re-applies the source + (sync back). Drift for a saved game config = "re-applying the file would + change the state" (`studioSetupDriftsFromSavedConfig`): the file governs + the options it specifies + its player options; ungoverned keys never count + as drift. The game-setup dropdowns may never silently supersede a selected + saved config. diff --git a/apps/mapgen-studio/src/features/configOverrides/rjsfTemplates.tsx b/apps/mapgen-studio/src/features/configOverrides/rjsfTemplates.tsx index 81e4a7e489..dfe641e268 100644 --- a/apps/mapgen-studio/src/features/configOverrides/rjsfTemplates.tsx +++ b/apps/mapgen-studio/src/features/configOverrides/rjsfTemplates.tsx @@ -33,7 +33,6 @@ export type BrowserConfigFormContext = { // is gone. The theme now follows the single `.dark` class via design-system // tokens (`card`/`muted`/`border`/`accent`/…), so there is no `lightMode` read. const FORM = { - card: "bg-card border-border", // Group well: nesting is a surface, not an indent (Pass-3 config-surface // spec). One recess below the stage card — tinted toward the page token so // groups read as machined slots in the slate. `background` sits below `card` @@ -56,12 +55,12 @@ const FORM = { groupHeading: "text-label font-semibold uppercase tracking-wider text-muted-foreground", subGroupHeading: "text-label font-semibold uppercase tracking-wider text-muted-foreground/70", // Rhythm on the 4px base (Pass-3): 4px inside a field block, 8px between - // sibling fields, 12px between groups/stage sections. Group wells carry - // `my-1`, which composes with the sibling gap to the 12px group step. + // sibling fields. Stage sections carry NO inter-item rhythm (Y4 flatten): + // the accordion is tight — hairline dividers separate rows, not margins. + // Group wells carry `my-1`, composing with the sibling gap inside a slab. rhythm: { field: "gap-1", siblings: "gap-2", - sections: "gap-3", groupPull: "my-1", }, } as const; @@ -207,8 +206,11 @@ export function BrowserConfigObjectFieldTemplate( const textClass = FORM.text; if (isRoot) { + // Y4 flatten: the stage list is a TIGHT accordion — flush rows separated + // by hairlines, no inter-card margins, no card chrome. Expansion is the + // only volume change (a recessed slab opens under the row). return ( -
+
{properties.filter((p) => !p.hidden).map((p) => p.content)}
); @@ -236,11 +238,14 @@ export function BrowserConfigObjectFieldTemplate( ); if (isStage) { + // Y4 flatten: stage objects lay FLAT on the panel — no card chrome, no + // raised surface. The header is a full-bleed disclosure row; expanding it + // opens a RECESSED slab (`surface-sunken` — below the panel, toward the + // page) so the interaction reads as a door opening into the graphite, + // not a card inflating off it. Group wells keep their one machined-slot + // tier inside the slab. return ( -
+
{collapse ? ( ) : ( -
+
{prettyTitle}
{renderGsComments({ schema, className: labelClass })} {description ?
{description}
: null}
)} {expanded ? ( -
+
{collapse ? ( -
+
{renderGsComments({ schema, className: labelClass })} {description ?
{description}
: null}
) : null} -
{content}
) : null} diff --git a/docs/projects/mapgen-studio-redesign/00-GOAL.md b/docs/projects/mapgen-studio-redesign/00-GOAL.md index ecaefcf0d2..eefcbca6f7 100644 --- a/docs/projects/mapgen-studio-redesign/00-GOAL.md +++ b/docs/projects/mapgen-studio-redesign/00-GOAL.md @@ -462,3 +462,48 @@ addressed to this lane effect core — adopting v3 platform now buys a guaranteed second migration. Full evidence + revisit triggers: `research/04-effect-native-substrate-spike.md`. + +## Studio fixes wave Y (2026-06-12, user-reported) + +- [x] **Y1 — "Waiting for Proof" zombie (run-in-game proof never matched).** + Root cause: `gen:maps` runs inside turbo's CACHED `build` task and + `SWOOPER_STUDIO_RUN_ID` was never declared in `turbo.json` — strict env + mode stripped it / the cache replayed a bundle without it, so the deployed + map script logged `[mapgen-proof] {"requestId":null,…}` (observed live) + and the marker waiter could never match: every Run in Game sat the full + 90s log timeout in "Waiting for Proof" while the game reached turn green. + Fix: `turbo.json` `build.env: ["SWOOPER_STUDIO_RUN_ID"]` (cache-correct: + the output genuinely differs) + a post-deploy fail-fast guard + (`mapScriptEmbedsRequestId`, code `run-request-id-not-materialized`) so a + missing embedded id can never masquerade as a proof wait again. Verified + live end-to-end: Run in Game → Complete, proof line carries the request id. +- [x] **Y2 — saved-config precedence affordance.** Verified the suspected + partial overwrite is NOT real (dropdown changes merge cleanly); the real + gap was silent drift. New categorical rule (system.md Y-wave amendment): + drift = "re-applying the saved file would change the state" + (`studioSetupDriftsFromSavedConfig`; governed keys + player options only); + the header selector gets a warning ring + orange "Modified" pill, click + re-applies the saved config. 5 new drift pins. Verified live (Speed → + Quick → pill; click → Standard restored, pill cleared). +- [x] **Y3 — tile grid restored on every stage.** X6's constant graphite + border ink (#0d0d11 = the page substrate) was invisible between dark fills + at fit zoom — Huge-map tiles are a few px wide, so the tessellation + dissolved into dots everywhere except the Delaunay mesh (its own slate + ink), i.e. "the grid disappears for every stage besides the first". Fix: + the one tile-border RULE — border = own fill × 0.55, opaque + (`tileBorderColorForFill`), legible at every zoom/palette/theme. Plus: + layer-selection default now prefers the step's tile-space GRID layer over + first-emitted (the map studio defaults to the map). New border-rule pin; + verified live across stages 2/10/13 (contiguous lattice at fit zoom). + Second user report ("when I switch stages, the grid goes away") exposed + the OTHER grid: the canvas graticule was gated on layer kind + (points/segments only), so it vanished for tile/mesh selections — i.e. on + most stage switches. New rule: the graticule is CANVAS substrate — once a + manifest exists it follows the grid toggle on every stage (including + zero-layer steps like Placement); layers may opt out via meta. Verified + live across stages 1/2/10/13/17. +- [x] **Y4 — flat config accordion.** Stage cards retired: top-level config + objects are full-bleed disclosure rows with hairline dividers and zero + inter-item margin; expansion opens a recessed `surface-sunken` slab (door + INTO the graphite); wells keep their one tier inside. Verified live, dark + + light. system.md Y-wave amendment carries all three design rules.