Lane C R6 C2: map the 3 orphaned fittings (glass_case/magazine_rack/crate_stack)
Published R5, unconsumed until now: - glb.js KIND_TO_GLB: glassCase->glass_case, magazineRack->magazine_rack, and a NEW crateStack primitive (fittings.js — a stack of crates) -> crate_stack. yaw 0 (validated on-screen). - theme.js: crateStack in record + opshop (back-room dressing); glassCase added to milkbar; magazineRack added to pawn; milkbar magazineRack moved window->wall (dodges the door-counter congestion). - layout.js: fixed placeNearCounter — it picked one random side and gave up, so counter-zone fittings (the glass case) rarely landed. Now it tries both sides + offsets, then falls back to a free aisle spot, so a min>=1 fitting reliably lands. Validated (GLB on, baked depot): all 3 load + render planted/scaled/facing right. Appearance glassCase 12/12 (toy/pawn/milkbar), magazineRack 12/12 (milkbar/pawn), crateStack ~11/12 (record/opshop). drawSweep still <=350 with them on (worst 177 GLB-on / 157 off). Determinism 0 fails, leak-free, dig (?dig=1) still riffles batched bins (C3 re-verify). Contact sheet docs/shots/laneC/glb_orphans_r6.jpg. qa.sh --strict GREEN. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
3b86b0c5b3
commit
c88d8906a2
@ -27,7 +27,19 @@ then batched (new `web/js/interiors/batch.js`):
|
||||
- **Sweep now ASSERTS ≤350** (`drawSweep()` in the test page, folded into the soak; `window.PROCITY_C.
|
||||
drawSweep` for F's harness — see LANE_C_NOTES for the hook).
|
||||
|
||||
Still in flight this round: C2 map glass_case/magazine_rack/crate_stack.
|
||||
**C2 — map the 3 orphaned fittings** (published R5, unconsumed). In `glb.js`: `glassCase→glass_case`,
|
||||
`magazineRack→magazine_rack`, and a NEW `crateStack` primitive (stack of crates) → `crate_stack`.
|
||||
Recipe placements: crateStack in record + opshop (back-room dressing), glassCase added to milkbar,
|
||||
magazineRack added to pawn (+ moved milkbar's magazineRack window→wall to dodge the door-counter).
|
||||
Also **fixed `placeNearCounter`** — it picked one random side and gave up, so counter-zone fittings
|
||||
(the glass case) rarely landed; now it tries both sides + offsets, then falls back to a free aisle spot.
|
||||
All 3 load + render planted/scaled/facing right (yaw 0). Appearance: glassCase **12/12** (toy/pawn/milkbar),
|
||||
magazineRack **12/12** (milkbar/pawn), crateStack ~11/12 (record/opshop). Contact sheet:
|
||||
[glb_orphans_r6.jpg](docs/shots/laneC/glb_orphans_r6.jpg). drawSweep still ≤350 with them on (worst 177
|
||||
GLB-on). **C3**: dig soak re-run after batching + new fittings — riffle works on batched bins, leak-free.
|
||||
|
||||
**Round 6 complete for Lane C**: C1 (batching, `35981ad`) + C2/C3 (orphans + dig re-verify) committed.
|
||||
Draw law satisfied (≤313 was the tightest; ≤177 after C2), determinism/leak/dig all green, qa strict green.
|
||||
|
||||
---
|
||||
|
||||
|
||||
BIN
docs/shots/laneC/glb_orphans_r6.jpg
Normal file
BIN
docs/shots/laneC/glb_orphans_r6.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 88 KiB |
@ -76,6 +76,22 @@ function crate(ctx, o = {}, r) {
|
||||
return { group: g, footprint: { w: w + 0.06, d: d + 0.06 }, height: h, slots, places: [g] };
|
||||
}
|
||||
|
||||
// A stack of empty crates — back-room dressing for record/op shops (GLB `crate_stack` upgrades it).
|
||||
function crateStack(ctx, o = {}, r) {
|
||||
const g = new ctx.THREE.Group();
|
||||
const w = o.w || 0.66, d = o.d || 0.66, ch = 0.3, th = 0.02;
|
||||
const n = 2 + (r() * 2 | 0); // 2–3 crates
|
||||
for (let i = 0; i < n; i++) {
|
||||
const m = ctx.mat(i % 2 ? '#4a5a6a' : '#8a6a45', 0.8);
|
||||
const ox = (r() - 0.5) * 0.06, oz = (r() - 0.5) * 0.06, y = i * ch;
|
||||
ctx.box(w, th, d, m, ox, y + th / 2, oz, g); // floor
|
||||
ctx.box(th, ch, d, m, ox - w / 2, y + ch / 2, oz, g); ctx.box(th, ch, d, m, ox + w / 2, y + ch / 2, oz, g);
|
||||
ctx.box(w, ch, th, m, ox, y + ch / 2, oz - d / 2, g); ctx.box(w, ch, th, m, ox, y + ch / 2, oz + d / 2, g);
|
||||
}
|
||||
g.userData = { kind: 'prop' };
|
||||
return { group: g, footprint: { w: w + 0.1, d: d + 0.1 }, height: n * ch, slots: [], places: [] };
|
||||
}
|
||||
|
||||
// A listening corner: a low bench + a boxy hi-fi + headphones on a stand.
|
||||
function listeningCorner(ctx, o = {}, r) {
|
||||
const g = new ctx.THREE.Group();
|
||||
@ -377,7 +393,7 @@ function artFrame(ctx, o = {}, r) {
|
||||
}
|
||||
|
||||
export const FITTINGS = {
|
||||
recordBin, crate, listeningCorner,
|
||||
recordBin, crate, crateStack, listeningCorner,
|
||||
wallShelf, metalShelf, cubeShelf, bookshelf, vhsAisle, spinnerRack, arcadeCabinet,
|
||||
clothesRack,
|
||||
trestleTable, counter, glassCase,
|
||||
|
||||
@ -29,6 +29,10 @@ const KIND_TO_GLB = {
|
||||
listeningCorner: 'listening_booth', // record store focal prop
|
||||
fridge: 'drinks_fridge', // milk bar drinks fridge
|
||||
arcadeCabinet: 'arcade_cabinet', // video store focal prop
|
||||
// Round-6 orphans (published R5, mapped now):
|
||||
glassCase: 'glass_case', // toy/pawn/dept/milkbar display case
|
||||
magazineRack: 'magazine_rack', // milkbar/pawn/book magazine rack
|
||||
crateStack: 'crate_stack', // record/opshop back-room dressing
|
||||
};
|
||||
|
||||
// Per-kind facing correction (radians, about +Y). The GLBs follow glb_law (metres, +Y up, base at origin)
|
||||
@ -44,6 +48,7 @@ const KIND_TO_YAW = {
|
||||
fridge: 0,
|
||||
arcadeCabinet: 0,
|
||||
counter: 0, // R5 counter_till — tuned on-screen
|
||||
glassCase: 0, magazineRack: 0, crateStack: 0, // R6 orphans — tuned on-screen
|
||||
};
|
||||
|
||||
// Counter-top GLB props: sit ON the counter's benchtop (not a floor swap). Each targets a counterTop
|
||||
|
||||
@ -198,7 +198,7 @@ export function layout(ctx, { recipe, dims, shell, adapter, shop }) {
|
||||
if (spec.zone === 'wall' || f.wallMounted) {
|
||||
ok = placeAtWall(ctx, grid, f, wallSlots, rPlace, placed, spec);
|
||||
} else if (spec.zone === 'counter') {
|
||||
ok = placeNearCounter(ctx, grid, f, counter, rPlace, placed, spec);
|
||||
ok = placeNearCounter(ctx, grid, f, counter, rPlace, placed, spec, W, D, doorCx);
|
||||
} else {
|
||||
ok = placeFree(ctx, grid, f, spec.zone, W, D, doorCx, rPlace, placed, spec);
|
||||
}
|
||||
@ -296,17 +296,25 @@ function placeAtWall(ctx, grid, f, wallSlots, r, placed, spec) {
|
||||
return false;
|
||||
}
|
||||
|
||||
function placeNearCounter(ctx, grid, f, counter, r, placed, spec) {
|
||||
// treasures / cases beside the till, on the goods side of the counter
|
||||
const side = counter.ry === 0 ? { x: counter.x + (r() < 0.5 ? -1.3 : 1.3), z: counter.z } : { x: counter.x, z: counter.z + (r() < 0.5 ? -1.3 : 1.3) };
|
||||
function placeNearCounter(ctx, grid, f, counter, r, placed, spec, W, D, doorCx) {
|
||||
// cases beside the till, on the goods side of the counter — try BOTH sides + a couple offsets, then
|
||||
// fall back to a free-standing aisle spot so a min≥1 fitting (e.g. a glass case) reliably lands.
|
||||
const ry = counter.ry;
|
||||
const cands = counter.ry === 0
|
||||
? [{ x: counter.x - 1.4, z: counter.z }, { x: counter.x + 1.4, z: counter.z }, { x: counter.x - 1.4, z: counter.z - 0.7 }, { x: counter.x + 1.4, z: counter.z - 0.7 }]
|
||||
: [{ x: counter.x, z: counter.z - 1.4 }, { x: counter.x, z: counter.z + 1.4 }, { x: counter.x - 0.7, z: counter.z - 1.4 }, { x: counter.x - 0.7, z: counter.z + 1.4 }];
|
||||
shuffle(r, cands);
|
||||
const [hw, hd] = halfExtents(f.footprint.w, f.footprint.d, ry);
|
||||
const rect = rectCells(grid, side.x, side.z, hw, hd);
|
||||
if (!areaFree(grid, rect)) return false;
|
||||
f.group.position.set(side.x, 0, side.z); f.group.rotation.y = ry;
|
||||
stampRect(grid, rect);
|
||||
placed.push({ fitting: f, x: side.x, z: side.z, ry, hw, hd, rect, priority: spec.priority, kind: spec.kind });
|
||||
return true;
|
||||
for (const side of cands) {
|
||||
const rect = rectCells(grid, side.x, side.z, hw, hd);
|
||||
if (!areaFree(grid, rect)) continue;
|
||||
f.group.position.set(side.x, 0, side.z); f.group.rotation.y = ry;
|
||||
stampRect(grid, rect);
|
||||
placed.push({ fitting: f, x: side.x, z: side.z, ry, hw, hd, rect, priority: spec.priority, kind: spec.kind });
|
||||
return true;
|
||||
}
|
||||
// counter is boxed in — put it in the aisle instead (still front-of-room-ish)
|
||||
return placeFree(ctx, grid, f, 'aisle', W, D, doorCx, r, placed, spec);
|
||||
}
|
||||
|
||||
// ── wall decor (art + signage) ─────────────────────────────────────────────────────────
|
||||
|
||||
@ -38,6 +38,7 @@ const RECIPES = {
|
||||
{ kind: 'recordBin', zone: 'aisle', min: 2, max: 5, priority: 5 },
|
||||
{ kind: 'crate', zone: 'centre', min: 1, max: 3, priority: 3 },
|
||||
{ kind: 'wallShelf', zone: 'wall', min: 1, max: 3, priority: 3 },
|
||||
{ kind: 'crateStack', zone: 'wall', min: 1, max: 2, priority: 2 }, // back-room dressing (crate_stack GLB)
|
||||
{ kind: 'counter', zone: 'counter', min: 1, max: 1, priority: 9 },
|
||||
],
|
||||
stockKind: 'sleeves',
|
||||
@ -57,6 +58,7 @@ const RECIPES = {
|
||||
{ kind: 'metalShelf', zone: 'wall', min: 1, max: 3, priority: 4 },
|
||||
{ kind: 'bookshelf', zone: 'wall', min: 1, max: 2, priority: 3 },
|
||||
{ kind: 'trestleTable', zone: 'aisle', min: 1, max: 2, priority: 3 },
|
||||
{ kind: 'crateStack', zone: 'wall', min: 1, max: 2, priority: 2 }, // back-room dressing (crate_stack GLB)
|
||||
{ kind: 'counter', zone: 'counter', min: 1, max: 1, priority: 9 },
|
||||
],
|
||||
stockKind: 'garments',
|
||||
@ -133,6 +135,7 @@ const RECIPES = {
|
||||
{ kind: 'glassCase', zone: 'counter', min: 1, max: 3, priority: 6 },
|
||||
{ kind: 'pegboard', zone: 'wall', min: 1, max: 3, priority: 4 }, // wall hooks
|
||||
{ kind: 'metalShelf', zone: 'wall', min: 1, max: 2, priority: 3 },
|
||||
{ kind: 'magazineRack', zone: 'wall', min: 1, max: 1, priority: 2 }, // magazine_rack GLB
|
||||
{ kind: 'barredWindow', zone: 'window', min: 1, max: 1, priority: 3 },
|
||||
{ kind: 'counter', zone: 'counter', min: 1, max: 1, priority: 9 },
|
||||
],
|
||||
@ -151,7 +154,8 @@ const RECIPES = {
|
||||
fittings: [
|
||||
{ kind: 'counter', zone: 'counter', min: 1, max: 1, priority: 9 },
|
||||
{ kind: 'fridge', zone: 'wall', min: 1, max: 3, priority: 6 },
|
||||
{ kind: 'magazineRack', zone: 'window', min: 1, max: 2, priority: 4 },
|
||||
{ kind: 'magazineRack', zone: 'wall', min: 1, max: 2, priority: 4 }, // wall (was window — conflicted with the door-counter)
|
||||
{ kind: 'glassCase', zone: 'counter', min: 1, max: 1, priority: 3 }, // lolly/treat display case (glass_case GLB)
|
||||
{ kind: 'metalShelf', zone: 'wall', min: 1, max: 3, priority: 4 },
|
||||
{ kind: 'cubeShelf', zone: 'aisle', min: 0, max: 1, priority: 2 },
|
||||
],
|
||||
|
||||
Loading…
Reference in New Issue
Block a user