Quadrille Showroom

repo: ~/Projects/quadrille-showroom · 175 commits · 0 in last 24h, 0 in last 7d ·

Search the build

175 commits indexed

  1. 17535f5 2026-07-03 chore: macstudio3 migration — reconcile from mac2 + repoint paths (stevestudio2→macstudio3, node/npm/npx→/opt/homebrew)
  2. e7f3b0f 2026-07-02 auto-save: 2026-07-02T11:47:40 (2 files) — public/js/rack.js public/js/showroom.js
  3. a156052 2026-07-02 5x sweep 1: keep bottom-corner panels clear of the centre pager (fix #g-next occlusion)
  4. b657af0 2026-07-02 auto-save: 2026-07-02T10:47:21 (3 files) — package-lock.json public/js/dock.js public/showroom.html
  5. bf8db8a 2026-07-02 chore: v1.3.2 (session close — furniture style selector + art direction)
  6. 02b4e0a 2026-07-02 furniture FIX 2: Transitional now unmistakably distinct from Contemporary
  7. 6bdf2b5 2026-07-02 furniture FIX 1: onload = clean empty room + table+chair only (no room-type dressing on boot)
  8. 0a7d7ab 2026-07-02 furniture: art-direction fixes — concrete-grey Brutalist, warm-wood Transitional, visible walnut Traditional
  9. 646f4b9 2026-07-02 auto-save: 2026-07-02T09:46:55 (1 files) — public/js/showroom.js
  10. 20c04ec 2026-07-02 chore: v1.3.1 (session close — thumb/proxy upstream hardening + ContrarianGo)
  11. 97b809a 2026-07-02 ContrarianGo iter1: shared fetchUpstreamBuffered for BOTH thumb + proxy; split transient/permanent; warn-log
  12. b6f8daf 2026-07-02 5x sweeps 2-5: upstream concurrency cap + placeholder fail-safe for sliver thumbs
  13. aec52fe 2026-07-02 auto-save: 2026-07-02T08:46:35 (30 files) — data/thumb-cache/099160b17f710e570c5aa9ac.jpg data/thumb-cache/0b9c68a67796dd1ccce90a5a.jpg data/thumb-cache/2ba7e03368ff27763d2ef6a1.jpg data/thumb-cache/3f441bb0f30a6e1d2e049c99.jpg data/thumb-cache/44fbcf466a13d44c920bf876.jpg
  14. d9cf3b2 2026-07-02 5x sweep 1: retry transient upstream in /api/thumb (cold-cache burst 502s)
  15. 3ac09a0 2026-07-02 chore: lint, refactor, v1.3.0 (session close)
  16. fb869a9 2026-07-02 Wire the George email picker for sample requests (sending gated)
  17. 38c4172 2026-07-02 Build sample-request submit: endpoint + tray form + admin cards (steps 1-3)
  18. cc9d428 2026-07-02 Scope the sample-request submit endpoint (age rides along)
  19. d6a840c 2026-07-01 chore: refactor + v1.2.2 (session close)
  20. df1dc51 2026-07-01 auto-save: 2026-07-01T11:11:52 (2 files) — public/js/showroom.js scripts/_reverify.mjs
  21. 59eede3 2026-07-01 Capture visitor age as a plain data point on the Sample Tray (replaces Age View)
  22. 88e4cd8 2026-07-01 chore: v1.2.0 → v1.2.1 (session close — /5x fixes + verification suite)
  23. e4d7eca 2026-07-01 Remove Age View / age-adaptive theming entirely (per Steve's call)
  24. e0bed2f 2026-07-01 verify: At-the-Table behavioral test (nook hide/restore + seated set + sample-add) + verify-all runner
  25. 4840661 2026-07-01 5x follow-up: WebGL scene-correctness + FPS verifier (closes the biggest coverage gap)
  26. 504a0ed 2026-07-01 5x sweep 3 (contrarian-driven): persist sort+density to localStorage (standing rule) + repeatable reload test
  27. f043317 2026-07-01 auto-save: 2026-07-01T10:11:20 (2 files) — public/js/showroom.js scripts/verify-sort-density-persist.mjs
  28. da29667 2026-07-01 5x: prove sort/density reachable+functional via ☰→Controls (selectOption OK, density OK, 0 errors) — closes the false-positive gap
  29. 682e04f 2026-07-01 5x: REPORT.md — six-way GREEN after sweep 2 (6/6, 0 console errors, cross-browser); dup-id fixed; sort-in-dock false-positive documented + design question surfaced
  30. 604475e 2026-07-01 5x sweep 1: fix duplicate id=density-wrap (7x → class); document sort/density-in-dock false-positives
  31. bb091f8 2026-07-01 Age View Phase-5.5 (contrarian pass): coalesce avatar rebuild, tighten in-page gate, capture screenshots
  32. d4295bd 2026-07-01 Age View Phase-5.3: cross-engine render gate (Chromium/Firefox/WebKit)
  33. 1ea5d2b 2026-07-01 Age View Phase-5 gate: fix under-spec type sizes on Senior/Elder bands + add re-runnable verifier
  34. e034910 2026-07-01 auto-save: 2026-07-01T09:10:58 (1 files) — public/js/dock.js
  35. 842a1dc 2026-07-01 showroom polish (070126A): wrap consultation nook in a group + hide it in the At-the-Table view (only the centre table shows), restore on exit
  36. 90fe8f0 2026-07-01 showroom: boot = first-person user standing in the doorway at the entrance end, stopped (no auto-walk); uniform same-size control pills + small pills on the bottom bar
  37. 8dfe072 2026-07-01 showroom P3: At-the-Table view — seated avatar + click-pattern-to-center + add/drag/remove samples on the table (basket persisted); fix addSample null-deref + table recorder
  38. 0fb3c6b 2026-06-30 auto-save: 2026-06-30T21:43:31 (2 files) — public/js/showroom.js public/js/viewmodes.js
  39. 5388cf1 2026-06-30 showroom P2: 5 room types (bedroom/office/living/lobby/gallery) + hybrid furniture (2 real GLB heroes + primitives) + flooring/room pickers + adjustable room; null empty model slots (no 404s)
  40. 02a9c21 2026-06-30 auto-save: 2026-06-30T20:43:13 (9 files) — public/js/showroom.js public/js/viewmodes.js public/showroom.html public/js/GLTFLoader.js public/models/
  41. bc32b4a 2026-06-30 showroom P1: remove angled/orbit/topdown, boot=walk-through-center, macro=2.5ft, carousel=continuous parade, compare=user-choosable two designs
  42. 2b90e02 2026-06-30 spec: 5 room types for showroom room-preview
  43. 6c84fb0 2026-06-30 add boot-walk + carousel screen-recording harnesses
  44. c66a587 2026-06-30 fix Wing° control: VIEW_OPEN was set by the slider but never read — now rakes the focused open board live (+re-ease nudge)
  45. 4bb3eba 2026-06-30 chore: lint, refactor, v1.2.0 (session close)
  46. de7d9e4 2026-06-30 Avatar nav: comfortable centred boot framing + grounded scroll/arrow walk, drag-turn, and always-available Return to Center
  47. b81c393 2026-06-30 chore: vN minor bump (session close — Age View bands, walls-on-Next, dock fixes)
  48. 66c765f 2026-06-29 Loop ledger iter5: two clean clickthrough sweeps + visual confirmation of bar-legibility fix
  49. 67caf4d 2026-06-29 Age View bar legibility: fix invisible readout text on light-panel bands + add per-band bar-legibility gate
  50. 796c25f 2026-06-29 walls-on-next: add Age-View-ON regression pass (paging under senior band still clads all 4 walls)
  51. 71784da 2026-06-29 Add measured env-morph verifier: asserts real rendered wall-luminance delta (35 vs 85), not just intensity scalars
  52. 08a8479 2026-06-29 Age View FPS gate: measure steady-state by discarding morph-rebuild transient window (floor unchanged)
  53. e40c08a 2026-06-29 Feature: Next/Prev book-page renders the new design on all 4 walls
  54. c378473 2026-06-29 Age View band-differentiation: split young/adult/established into 3 hue families
  55. c4fd7f2 2026-06-29 dock polish: stow pager on boot (P1), cascade first-open (P2), auto-close menu on launch (P3), Controls first-open height (P5)
  56. 95724fe 2026-06-29 Arrow keys (left/right) page prev/next pattern on the wings; body-turn moves to A/D
  57. 2bef6b4 2026-06-29 /5x REPORT: 2 dock.js bugs fixed, 2 clean sweeps
  58. b3ca21a 2026-06-29 /5x: showroom-aware clickthrough + fix 2 real dock.js bugs it caught
  59. 52d16fc 2026-06-29 snapshot: clickthrough script + 5x report from review pass
  60. d598030 2026-06-29 Next/Previous step one pattern across all 883 + keep pager visible while walking
  61. 3b94ca1 2026-06-29 Hamburger dock: stow all panels on load + launch each as movable modal; hide first-person avatar in framed views
  62. a785d8a 2026-06-29 Center book starts open at 20 degrees (was 65)
  63. 80267e9 2026-06-29 Center book: open leaves FORWARD at 65° + wire Open° slider to live splay
  64. 6145090 2026-06-29 auto-save: 2026-06-29T15:24:16 (3 files) — public/js/showroom.js public/js/dock.js public/js/modal-rig.js
  65. f1439ea 2026-06-29 Fix center-book leaf orientation: leaves face the viewer (drop the PI group flip)
  66. fa8ee90 2026-06-29 Default view = walk the avatar + single centered mirrored book + minimal caption bar
  67. 04948ab 2026-06-29 Phase 5.5 /contrarian final pass: prove the AVATAR half + fix 2 weak non-senior CTAs
  68. 71a067a 2026-06-29 Phase 5.3 cross-engine verifier: Age View slider PASS on WebKit + Firefox
  69. d84af5b 2026-06-29 Phase 5 senior-usability HARD gate: measured verifier + 3 cascade/wiring fixes
  70. fc2441f 2026-06-29 Age View: continuous avatar age-morph (ageRigParams + upperRig stoop sub-group) + default-off age slider with banded UI/env snap + senior-opaque APCA gate
  71. 3048f97 2026-06-29 AGE-VIEWS-SPEC: apply /contrarian plan-gate fixes (opaque HUD backing for senior APCA-over-WebGL, gate the slider at 85, upperRig sub-group for stoop, differentiate bands 21/28, per-band env FPS profiling)
  72. bdcbe78 2026-06-29 Add AGE-VIEWS-SPEC.md — overseer plan for 10 age-adaptive avatar showroom views (12-85)
  73. f94d966 2026-06-29 High-end versions batch 3: V18 Infinity Mirror + V19 Conservatory Garden + V20 Penthouse Dusk — ALL 10 high-end versions (V12-V21) now built + registered in the picker
  74. c4480af 2026-06-29 High-end versions batch 2: V13 Atrium Daylight + V14 Velvet Lounge + V15 Brutalist Concrete + V17 Japanese Tatami (protos + registered in picker; 7/10 high-end versions live)
  75. 607b67f 2026-06-29 auto-save: 2026-06-29T06:19:10 (4 files) — public/proto/v13-atrium-daylight.html public/proto/v14-velvet-lounge.html public/proto/v15-brutalist-concrete.html public/proto/v17-tatami.html
  76. fad82ea 2026-06-29 Register V12 Gallery Noir + V16 Art-Deco Salon + V21 Garcia Room in the version picker (overlay entries + VERSION_ORDER + element lists for the code system)
  77. fbe4548 2026-06-29 High-end versions: add V12 Gallery Noir + V16 Art-Deco Brass/Marble + V21 Garcia Room proto scenes (PBR/PMREM/ACES, real China Seas textures, 0 errors)
  78. 1c4a04e 2026-06-28 Avatar polish: lighten 1st-person sweater 0x2e3138->0x3d424d (look-down readability, /contrarian note)
  79. 09cf8ad 2026-06-28 Chunk K (first-person Steve avatar, yaw-only rig) + Chunk A′ (20'×20' room)
  80. 33391a6 2026-06-28 Boot raycaster race fix: queue pre-ready canvas clicks + replay on ready (durable)
  81. 1303c94 2026-06-28 Finalize definitive build: remove dev 30s auto-reload scaffolding from showroom.html (contrarian whole-build sign-off polish)
  82. 18497fa 2026-06-28 auto-save: 2026-06-28T21:16:50 (125 files) — cta/rec/chrome.mp4 cta/shots/chrome/all-designs-after.png cta/shots/chrome/all-designs-before.png cta/shots/chrome/auto-tour-after.png cta/shots/chrome/auto-tour-before.png
  83. 229a7b0 2026-06-28 Slice3 gate hygiene: annotate headless FPS flag as HEADLESS-SKIPPED + commit real-GPU artifact (scripts/slice3-fps-realgpu-result.json — M2 Max Metal 72fps, gate55_met:true) — one authoritative truth source per /contrarian
  84. 0979b2b 2026-06-28 Slice-3 F: FPS.ms.draws HUD readout + off-thread wall-clad decode (kills the select-moment dip)
  85. 1b5eb93 2026-06-28 Slice-3 H: globally-unique element build codes (1000QH<version>)
  86. c4a14bb 2026-06-28 Slice-2 contrarian fixes: HOLE-3 detail starts COLLAPSED on every fresh selection (drop localStorage override footgun) + spec-legal proof harness (real ArrowL/R yaw to +/-72 clamp, NO mode switch). HOLE-1/HOLE-2 verified already-correct: hero opens flip=0.999 / 6.02x neighbour width; clad walls visible front (252 cells) + side at clamp (680/643 cells); posDelta 0; 16/16 assertions pass, errorCount 0.
  87. 34871bc 2026-06-28 auto-save: 2026-06-28T18:16:07 (2 files) — public/js/showroom.js scripts/diag-probe.mjs
  88. 0e9e564 2026-06-28 Open-face clean: hero board pushes forward + re-centres so the open 30x6 face reads full-bleed edge-to-edge with NO neighbour slat-bars/frames crossing the pattern
  89. f0eacf1 2026-06-28 auto-save: 2026-06-28T17:45:58 (1 files) — SHOWROOM-REFERENCE-FROM-VIDEOS.md
  90. 6b2e201 2026-06-28 Slice 2 (D+E) verified: click=selection (board opens flat, detail card collapsed-by-default, expandable to 27x27 China Seas specs) + every selection clads ALL 4 walls (front wall now in roomWalls[], wallsAutoClad default ON, clad unconditional on focus, 27in repeat). Boot stays Slice-1 clean: no selection/panel, neutral walls (cladToken race-guard + _qhBootSettled boot-guard prevents transient Hero-focus leak). 4/4 walls assert PASS, posDelta 0, yaw clamp +/-72 intact, errorCount 0. V1-V11 + V11 seated overlay untouched.
  91. 15572c3 2026-06-28 Add Playwright carousel verifier + npm verify-carousel script (Chunk I proof harness)
  92. 396a02d 2026-06-28 Chunk I: dry-cleaner/tie-rack carousel — click any sliver conveyor-shifts the whole rack so the clicked board eases to the dead-front centre slot, then fans open (camera stays fixed-centre)
  93. 0ae67ed 2026-06-28 snapshot before carousel build: Slice-2 boot-guard (_qhBootSettled) + cladToken + verify-slice2 artifacts
  94. 966628f 2026-06-28 auto-save: 2026-06-28T17:15:46 (1 files) — public/js/showroom.js
  95. 13c193b 2026-06-28 snapshot before Slice 2: cladToken boot-race guard (in-flight onload invalidation)
  96. 04ca167 2026-06-28 /5x sweep-1 report: Slice-1 build verified clean (HTTP/render/3-browser/0-errors/real-controls); clickthrough failures = harness vocabulary mismatch, not app defects
  97. 2c946ef 2026-06-28 Slice1 fix-it: 72° yaw clamp (non-empty), 50 boards, ~36° resting-open middle
  98. 37affeb 2026-06-28 Slice 1: open-angle slider (qh_open_angle, 45° default, 20-90°, live re-rake) + middle board opens at measured 45° on boot; bump density max to 50
  99. c38484d 2026-06-28 auto-save: 2026-06-28T16:15:32 (1 files) — LIQUID-UI-SPEC.md
  100. 1fbedd2 2026-06-28 Slice 1 (A+B+C): 14x14 room, fixed-centre yaw-spin camera (clamped), 50 wings w/ ~2in slivers + middle open-at-angle on boot
  101. 8c6da3e 2026-06-28 auto-save: 2026-06-28T15:45:20 (1 files) — cta/
  102. 49978bc 2026-06-28 auto-save: 2026-06-28T10:44:13 (5 files) — data/thumb-cache/143b196e361cfcabac432402.jpg data/thumb-cache/2592d7f617769f8a4a430efd.jpg data/thumb-cache/607c51b820948e86e419768a.jpg data/thumb-cache/66509ef89fd93c999d240cba.jpg data/thumb-cache/ee078617ded1664759e51f12.jpg
  103. 731f06d 2026-06-28 auto-save: 2026-06-28T10:14:06 (1 files) — data/thumb-cache/c987c8b51e74d135d6c0670b.jpg
  104. d9c5d8c 2026-06-28 Wire Sample Table into the version picker as V11 (Add Sample drops swatch on the table; full-screen overlay + Back + numbered elements)
  105. 61fe1e2 2026-06-28 auto-save: 2026-06-28T09:43:58 (3 files) — public/js/showroom.js server.js data/thumb-cache/
  106. 765e004 2026-06-28 Proto V6-V10: refresh final verification screenshots (0 console errors each)
  107. 27c72af 2026-06-28 V10 Concierge Nook: boards now genuinely LIE on the table — share the table's exact perspective + 58deg rake + vanishing point (coplanar with the wood), counter-rotate ONLY the placard so labels stay readable, in-plane foreshortened cast shadows seat each board on the felt; placard color dot grounded on enrichment hue
  108. cbee4bb 2026-06-28 V9 Walk-In Room: photo-real depth — soft contact shadows ground sofa/rug/lamp, vertex-baked corner AO modulated by window light (bright near window, deep far), procedural paper bump for surface tooth; killed the stacked-multiply black wedge by softening + offsetting layers
  109. 7f3989c 2026-06-28 V8 Swipe Tower: keep biases the queue via enrichment taste model (family/bucket/hue affinity) — shuffle deck on load so bias is observable, soft re-rank on every verdict, FREEZE=3 protects visible stack, 1-in-4 exploration curveball so it curates without a filter bubble; legible 'More like X' + 'change of pace' badges. Proven: keep 3 blue -> blue top-20 share 15%->65%, 4/20 explore cards
  110. 206ff85 2026-06-28 auto-save: 2026-06-28T09:13:51 (4 files) — public/js/rack.js public/js/showroom.js public/proto/v7-moodboard.html public/proto/shots/v7-moodboard.png
  111. f541de6 2026-06-28 Sample Table: add-sample drops the square swatch onto the consultation table
  112. b271af4 2026-06-28 V6 Color River: ground hue on enrichment.json; bridge the neutral mid-river pause — density-steer neutrals into thin chromatic stretches, lift gap neutrals up as stepping stones in the stream, add legible near-edge waterline + per-swatch flow bob
  113. e142ff7 2026-06-28 auto-save: 2026-06-28T08:43:43 (1 files) — public/js/versions.js
  114. 1223514 2026-06-28 Docs: VERSIONS.md — close the V6-V10 fork; document the integrated 10 (real mechanics as full-screen overlays + integration test)
  115. 51ceefa 2026-06-28 Clean stale proxy-server comment in v10 proto (now served same-origin from public/proto)
  116. 962e2f7 2026-06-28 Enrichment: coarsen patternBase family to first-word family (778 -> 121 families, 99 multi-colorway) for pairs-well-with; regroup in-place preserving hue; add family key to enrich.js
  117. 3fb5596 2026-06-28 Wire V6-V10 as real full-screen mechanic overlays (Color River, Mood-Board, Swipe Tower, Walk-In, Concierge); proto-chrome Back+legend bridge; integration test passes 72fps/0 errors
  118. e40b519 2026-06-28 Off-thread texture decode (fetch+createImageBitmap) kills the rapid-nav stall: senior 69/72, 2min 72/72, 0 errors. + smaller FullDesign detect canvas. Both FPS gates now rock-solid above 50.
  119. e4cdbac 2026-06-28 Data enrichment: hue/color_bucket (878/883) + patternBase/room sidecar (data/enrichment.json) + 5 new-mechanic prototypes (Color River/Mood-Board/Swipe Tower/Walk-In Room/Concierge) in proto/, all contrarian-gated
  120. 6241da8 2026-06-28 auto-save: 2026-06-28T08:13:35 (4 files) — proto/shots/v10-concierge.png proto/v10-concierge.html proto/verify-v10.cjs public/js/showroom.js
  121. 597fb5b 2026-06-28 proto: COLOR RIVER — shop China Seas by hue as a flowing Three.js color current
  122. cbd8fb9 2026-06-28 Tighter arc (86deg span, ~75% overlap = thinner slivers) + warmer cream plaster + calmer exposure to match PJ photo; gates hold (senior 50/69, 2min 69/71, 0 err)
  123. 72bd476 2026-06-28 proto v7: mood-board table — drag swatches, build palette, pairs-well-with
  124. 0ecda36 2026-06-28 Thin slivers (reveal 70 / steeper rake) + walls stay cream plaster like the PJ photo (auto-clad off) → senior FPS 51/69, 2min 69/71, 0 errors; rapid-nav hitch gone
  125. 47aa29a 2026-06-28 auto-save sync: showroom.html (font link + versions.js script wiring)
  126. e6c14ec 2026-06-28 Add V1-vs-reference comparison + 10-version contact sheet; document build status + flag contrarian V6-V10 fork
  127. 5954106 2026-06-28 V1 establishing arc (matches pj-dallas-showroom.png) + V2 step-driven conveyor + rail layout
  128. f75fcc7 2026-06-28 Perf + PJ-accurate isolate: hero stays AMID the sliver arc (not hidden); only hero casts shadow; shared board geometry + cached placards + shadow-rebake budget → 2min FPS 57/68, 0 errors, specs intact
  129. fecd0e8 2026-06-28 auto-save: 2026-06-28T07:43:27 (4 files) — public/css/showroom.css public/js/showroom.js public/js/versions.js scripts/test-versions.js
  130. 1a31ad6 2026-06-28 10 VERSIONS system: V1-V10 picker rail + numbered-element overlay + Chosen Elements tray
  131. c421efa 2026-06-28 Contrarian pass: corrected 10 to genuinely-distinct mechanics (killed 5 reskins; added Color River / Mood-Board Table / Swipe Tower / Walk-In Room / Concierge Nook)
  132. c499d15 2026-06-28 Consultation nook (round table + 2 boucle chairs + plant + swatch cards) in arc foreground; 18-board packed arc; reveal slider verified live (20/62/90)
  133. f51220a 2026-06-28 PJ arc rack v1: single-vertical-hinge boards on a curved brass rail (rack.js), reveal slider, flip-to-open hero; replaces flat-wall butterfly
  134. 6593c48 2026-06-28 VERSIONS.md: 10 numbered showroom versions w/ numbered elements for in-UI select-and-choose; + card-wall/conveyor/fan/carousel specs
  135. 24bbad7 2026-06-28 auto-save: 2026-06-28T07:13:19 (1 files) — WINGBOARD-SPEC.md
  136. 360b17f 2026-06-28 Lock PJ wingboard-rack spec (Image #6 Dallas showroom) + save reference: arc rack of sliver-packed wingboards, bronze frames, flip-to-open, consultation nook, user-adjustable reveal
  137. cd16d7f 2026-06-28 Perf: on-demand shadow maps (autoUpdate off, rebake only on geometry/light/visibility change) — p95 render-ms ~0.9ms→0.5ms, zero visual change; wire requestShadowUpdate into focus/flip/theme/mode changes
  138. afcaf8b 2026-06-28 auto-save: 2026-06-28T06:13:03 (3 files) — public/js/showroom.js public/js/viewmodes.js scripts/test-views.js
  139. 52f212e 2026-06-28 Add 10 switchable view modes + 6 lighting themes + toggleable perf readout (View/Theme panel)
  140. c1cf76b 2026-06-28 TEMP dev aid: auto-reload open tab every 30s (idle-guarded 6s; skips Playwright/webdriver so tests aren't disrupted)
  141. 4df383e 2026-06-28 Detail popup starts COLLAPSED on load (chevron to expand, persisted); step camera back on focus (board fills ~70% of frame with margin, was overfilling/too close)
  142. 155681c 2026-06-27 REVIEW.md: pass 7 — senior-first guided nav + subtle bloom, gates passed
  143. ed4ad46 2026-06-27 Realism: subtle additive-blend bloom halo on ceiling cove strips (no postproc stack); FPS-neutral (min 65)
  144. 2b0c269 2026-06-27 Senior-first Guided Mode: big no-keyboard nav (Prev/Next/Auto Tour/All Designs), Explore toggle off by default, large title+instruction
  145. d7f73cb 2026-06-27 REVIEW.md: pass 6 — gap A blocked (no hi-res source, 1000px ceiling), gap B dominant key done
  146. ffa75d5 2026-06-27 Dominant key light: ambient 0.72→0.5, hemi 0.58→0.45, key 0.7→1.05 — committed to one warm key for photographic modelling/direction; fill kept high enough swatches stay true+legible. FPS 72, specs intact
  147. fb6800c 2026-06-27 REVIEW.md: FINAL pass-5 section — honest B- grade (up from D+ at pass 1) vs a real Phillip Jeffries showroom photo. Documents what the per-board lighting pass resolved (gradient+sheen / wall drop-shadow / real picture-light shadows, all measured) and the top 2 remaining gaps: swatch-tile resolution (source-side) + commit-to-one-dominant-key lighting authoring.
  148. ac87a36 2026-06-27 REAL PICTURE-LIGHT SHADOWS: enable castShadow on the gallery picture-light spot so each board casts a soft, physically-correct shadow onto the wall behind it (and faintly onto neighbours) — genuine depth the fake drop-sprite can't give, esp. on the focused hero board. Tight shadow camera (near 0.4/far 3.6) + 1024 map + wide PCF radius keeps cost low. MEASURED: 2-min soak min 59 / avg 68 FPS (holds the >=55 real-shadow gate, with margin), walkthrough 72 FPS, errorCount 0, specs intact (27x27, China Seas). 2nd shadow-casting light, lights still 6.
  149. ce3b7f3 2026-06-27 BOARD WALL DROP-SHADOW: each board casts a faint soft shadow onto the back wall behind it (shared soft-box sprite, dropped down+left to match the upper-right key light, opacity 0.34, just in front of the wall surface) so boards have real depth OFF the wall — not flush decals. Cheap: pure sprite, no shadow-map/light cost. Auto-hides on focus/isolate (board swings forward off the wall) and restores on close. FPS 72, errorCount 0, specs intact (27x27, China Seas)
  150. 433800b 2026-06-27 PER-BOARD LIGHT GRADIENT: each 6-ft board face gets a baked top-to-bottom luminance falloff + faint warm specular sheen band (shared RGBA gradient overlay parented per-leaf, NormalBlending, low alpha) so boards read as physical objects in a lit room, not evenly-lit decals. Plus modest board-material specular (roughness 0.85->0.6, envMap up) so the picture-light grazes the face. Swatch colour stays TRUE + legible (neutral mid-band, never crushed). Works for pool AND focused loadWingBook materials. FPS 72, errorCount 0, specs intact (27x27, China Seas)
  151. b44c0aa 2026-06-27 auto-save: 2026-06-27T12:39:11 (1 files) — public/js/showroom.js
  152. d2c6df4 2026-06-27 PHOTOGRAPHIC DEPTH: subtle CSS vignette + soft top-down directional gradient over the canvas (multiply blend, z-index 5 under HUD, pointer-events none) — adds photographic corner falloff + depth with ZERO GL/render cost (does not touch the WebGL pipeline). Light touch per ART-DIRECTION, not a heavy post stack. FPS 72, errorCount 0
  153. c49c3db 2026-06-27 CONTACT GROUNDING: soft radial-gradient contact shadows on the floor under each wingboard + the planter + the console — a shared warm-charcoal alpha sprite (no light/shadow-map cost, depthWrite off, polygonOffset). Boards now sit IN the room instead of floating ON it — the #1 'is it real' tell after the shell. FPS 72, errorCount 0, specs intact (27x27, China Seas)
  154. 7dcf846 2026-06-27 CEILING: replace crude 64px procedural grid (read as a wireframe) with a clean, bright, EVEN soft warm off-white gallery ceiling + two slim emissive recessed warm-light strips (no light cost, no harsh lines). Reads like a real gallery ceiling. FPS 72, errorCount 0
  155. bb93cda 2026-06-27 WALL realism: derive subtle normal+roughness maps from wall-limewash.png (scripts/derive-wall-maps.py, $0 local PIL+numpy) — apply to MAT.wall + MAT.brick at normalScale 0.2 so limewash plaster has faint trowel relief catching grazing light, no longer a flat tiled photo. FPS 72, errorCount 0, specs intact
  156. a38c66c 2026-06-27 NOW VIEWING navigator HUD: museum media-player strip (swatch thumb + serif name + tracked colorway + 27x27 spec + Back/Peruse-play-pause/Next + 'N of N' brass progress). Vanilla CSS/HTML, brass-hairline museum glass per ART-DIRECTION; reuses gotoBoardOffset+togglePeruse, syncs play glyph to tour state. FPS 72/min51, errorCount 0. Figma/Magic MCP design phase tool-gated this session (noted)
  157. 1e55735 2026-06-27 PJ hero framing: narrow FOV (55->30) on focus + back off proportionally so the 6ft board fills the frame flat/dead-on with no perspective flare; restore FOV on unfocus. Distance solved from fillH=2*d*tan(fov/2). FPS 72, errorCount 0
  158. df96412 2026-06-27 Floor normal+roughness maps derived locally from floor-oak.png (scripts/derive-floor-maps.py): plank grain now catches grazing light, satin sheen breaks across boards. $0 local. FPS 72, errorCount 0
  159. b1e3c75 2026-06-27 PJ hero framing: focused board presents FLAT/dead-on (near-flat default) not a 65° V; add user-adjustable Wing° angle slider (0-90°, persisted, live); keep splay as walk-up browse gesture
  160. a08b36a 2026-06-27 PJ polish: true hi-res (4096px) engraved-brass wall wordmark, fix stale book-match comments
  161. e7268c6 2026-06-27 Photoreal room (SDXL warm-oak floor + limewash plaster walls), brighter white-box light, CONTINUOUS open-board design (L=U0-0.5 / R=U0.5-1, no mirror), HUD copy
  162. 1793384 2026-06-27 Add 2-min soak-test recorder (walk/open/Back-Next/Peruse; logs console errors + FPS)
  163. 6e2efdd 2026-06-27 Usable view: 6ft back + dead-centre + 65° open + ISOLATE (hide other boards); replace Fan with Back/Next board nav; remove 'fanning' wording
  164. 80afbd8 2026-06-27 Add 30s captioned how-to-use demo recorder
  165. 15f8c33 2026-06-27 Clean+clear pass: bright even gallery lighting, true-colour crisp swatches (low env wash), hi-res brass CHINA SEAS plaque + hi-res placards
  166. 575ee37 2026-06-27 Scene luxury pass 1: limewash plaster left wall (was brick), warm wide-plank oak floor, removed TV/medallion rug/sphere plants/framed art, single olive in stone planter, brass frame + gallery placard per board, picture-light graze on board wall, cognac-leather chairs
  167. 5921951 2026-06-27 Boards 30"×6ft (real sample wings, 8/wall + paging); fan-out opens the board's L/R panels to present 1 design; Peruse 4ft-centered, 5s dwell
  168. a76a8f6 2026-06-27 Add automated Playwright walkthrough recorder (move-around screen-record + scene stats + spec-card proof)
  169. 72bec59 2026-06-27 China Seas specs (27"×27" / Grasscloth 36") + spec-sheet detail card + graphics pass (soft 2048 shadows, rim light, richer env, exposure 1.06)
  170. 8a47897 2026-06-26 Realism pass + proximity book-match wings
  171. c208bf2 2026-06-26 auto-save: 2026-06-26T12:33:24 (1 files) — server.js
  172. 98df95d 2026-06-26 Wall-cladding: focused/perused wing renders its pattern onto all room walls at architectural scale (toggle in HUD)
  173. b98ec59 2026-06-26 Record DTD hosting verdict (C: keep local, defer deploy; Option A when remote need is concrete)
  174. 6ae51b8 2026-06-26 Image-model pipeline: $0 local seamless tiles + Gemini room backdrops (gated, cost-shown); window-handle refresh; README
  175. 592fa6a 2026-06-26 Quadrille House Endless Wings showroom — fused engine + 883 wallcoverings, peruse loop, FullDesign tiling, windowed paging

Authors

Agents used

  • none detected

Skills used

  • /showroom19
  • /thumb-cache12
  • /shots8
  • /proto7
  • /contrarian6
  • /chrome6
  • /thumb4
  • /rack3
  • /dock3
  • /proxy3
  • /viewmodes3
  • /right3
  • /v7-moodboard3
  • /image2
  • /sample-requests2
  • /pending2
  • /verify-sort-density-persist2
  • /density2
  • /room2
  • /established2
  • /sliders2
  • /near-black2
  • /white2
  • /legs2
  • /feet2
  • /walls2
  • /render2
  • /versions2
  • /v10-concierge2
  • /light2

Creative ideas + design notes

Commits with substantial prose (≥120 chars) — the rationale behind each move.

02b4e0a · 2026-07-02 · furniture FIX 2: Transitional now unmistakably distinct from Contemporary
Chair upholstery moved OFF cream/greige to a deep sage-olive (mattMat env-0 so the
~1.6x showroom light-lift can't wash it back to cream) so the CHAIR — the dominant
visual mass — reads clearly green vs Contemporary's white seat. Table wood darkened
to a matte mid-oak (env-0) so it reads as solid wood, not pale blonde. Also gates the
resizeRoom re-dress: a resize only re-dresses if the user had actively chosen a room
type, preserving the FIX-1 clean-empty-room boot invariant.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
6bdf2b5 · 2026-07-02 · furniture FIX 1: onload = clean empty room + table+chair only (no room-type dressing on boot)
Boot no longer builds a fully-dressed 'living' room type (sofa/lamps/wingchair/
rug/sculpture/plant). Room-type dressing now appears ONLY when the user clicks a
room-type chip; a returning user also boots to the clean empty room. Verified via
probe-boot-scene: currentRoomType null, no roomType group, 1 furnitureRoot (table+chair).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
0a7d7ab · 2026-07-02 · furniture: art-direction fixes — concrete-grey Brutalist, warm-wood Transitional, visible walnut Traditional
- Brutalist recolored to raw béton-brut concrete grey (dark bases that read ~#8a8a86 on
  camera under the bright showroom light) + board-form groove lines; no longer white foam
- Contemporary table now crisp white lacquer + steel blade legs (was warm oak)
- Transitional table warm honey-oak + soft rounded barrel-back upholstered chair, so it
  reads clearly distinct from Contemporary (material + silhouette)
- Traditional chair reworked: matte no-env walnut frame + tall curved upholstered back +
  crown rail so the walnut tone and curved back read from the default camera
- Added mattMat() + buildBoardFormLines() helpers

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
20c04ec · 2026-07-02 · chore: v1.3.1 (session close — thumb/proxy upstream hardening + ContrarianGo)
server.js hardening (retry + concurrency cap + placeholder fail-safe + shared
fetchUpstreamBuffered for both /api/thumb and /api/proxy/image) already passed
/5x (5 sweeps, clean twice cold) + /contrarian (cleared the bar) this session.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
97b809a · 2026-07-02 · ContrarianGo iter1: shared fetchUpstreamBuffered for BOTH thumb + proxy; split transient/permanent; warn-log
Closes the 3 contrarian holes in the 5x sliver-thumb fix:
- /api/proxy/image (open hero) now shares the SAME cap+retry hardening as /api/thumb
  via one fetchUpstreamBuffered() helper — no more fixing only the tested endpoint.
- fallback distinguishes transient (blip) from PERMANENT (dead 4xx) and console.warns
  every fallback so a dead upstream leaves a trail a canary can grep — not a silent gray lie.
- both routes de-duplicated onto the shared helper (the twin functions collapsed).
Verified: healthy hero serves real 124KB image (no fallback header); permanent 404 →
placeholder 200 + logged PERMANENT; clickthrough CLEAN twice cold; verify-all 0 failures.
Adds /ContrarianGo skill (this loop).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
b6f8daf · 2026-07-02 · 5x sweeps 2-5: upstream concurrency cap + placeholder fail-safe for sliver thumbs
Cold-cache concurrent sliver-thumb bursts tripped transient cdn.shopify.com 502s
surfacing as browser console errors. Fix in /api/thumb url= path:
- upstream-concurrency cap (6) so a ~24-thumb cold burst doesn't hammer the CDN
- retries 1->3 w/ exponential backoff (transient only, never a real 4xx)
- neutral-placeholder fail-safe: serve quiet 200 (X-Thumb-Fallback) on exhaustion
  instead of a console-erroring 502 — decorative slivers must fail-safe.
Verified: 0 dead URLs across all 883 catalog images; healthy images still serve the
real thumb; clickthrough CLEAN twice on cold cache; verify-all all green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3ac09a0 · 2026-07-02 · chore: lint, refactor, v1.3.0 (session close)
- hoist crypto require to module top (drop 2 inline requires)
- age handler == null -> === null (strict-equality consistency)
- version 1.2.2 -> 1.3.0 (sample-request submit feature landed this session)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
fb869a9 · 2026-07-02 · Wire the George email picker for sample requests (sending gated)
- scripts/send-sample-request-emails.js: reads data/sample-request-emails.jsonl,
  sends each pending row via George (POST /api/send, Basic auth from GEORGE_BASIC_AUTH
  or dw-agents Keychain, optional X-Send-Approval), from steve-office. Marks rows
  sent/sent_at/message_id; idempotent. --dry-run previews; --health probes George.
- npm run send-sample-emails.
- Safe by default: refuses to send unless SAMPLE_REQUEST_EMAIL_TO is set; NOT scheduled.
Verified: George reachable from Mac2 (status ready), health + dry-run + gated-refusal
all pass without sending; queued row stays sent:false.
Still gated: recipient inbox (SAMPLE_REQUEST_EMAIL_TO) + SAMPLE_REQUEST_EMAIL=on + consent copy.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
38c4172 · 2026-07-02 · Build sample-request submit: endpoint + tray form + admin cards (steps 1-3)
- POST /api/sample-request: validated (samples 1..50, age 0..120, email, 32kb cap),
  server-stamped created_at, append-only data/sample-requests.jsonl persist.
- Email via George gated behind SAMPLE_REQUEST_EMAIL env (default off) -> queue file only.
- Sample Tray: name/email/phone/notes fields + Request Samples button (disabled when
  empty) + consent line + confirmation UX that keeps input on failure. Age rides along.
- Admin /admin/sample-requests: card list with created date+time chip (standing rule).
Verified: curl (ok+400s+GET), Playwright load (7 elements, button gated, 0 console errors).
Gated/pending: consent wording + email recipient (spec steps 4-5).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
d6a840c · 2026-07-01 · chore: refactor + v1.2.2 (session close)
javascript-pro refactor pass on the session's age-field code found + fixed a real
edge case in initHUD(): restoring a stored age of 0 from localStorage coerced to null
(parseInt('0')||null → null) while the input still showed '0'. Now uses
parseInt(saved,10) + Number.isFinite guard, mirroring the live input handler. Re-verified
(Playwright): 67 persists across reload, and the 0-case now restores as 0, 0 console errors.
No linter configured in repo — lint gate had no toolchain to run.
59eede3 · 2026-07-01 · Capture visitor age as a plain data point on the Sample Tray (replaces Age View)
Per Steve's call: age is no longer an in-showroom control — it's a plain field on the
sample-request surface. Added an optional 'Your age' number input to the Sample Tray
(#tray-age), persisted to localStorage('qh_visitor_age'), clamped 0–120, exposed via
window._qh.visitorAge so a future request submit can include it. Styled to match the tray.

Also fixed a PRE-EXISTING bug this surfaced: the dock stows #sample-tray on boot with
.qh-stowed (display:none!important), which the tray's own .visible (display:block) could
never override — so the Sample Tray never actually appeared even when samples were added.
updateSampleTray() now clears qh-stowed when populated (re-adds it when empty).

Verified (Playwright): field renders + is visible when the tray populates; value persists
across reload; _qh.visitorAge reflects it; clamps 999→120; blank clears the key to null;
0 console errors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
e4d7eca · 2026-07-01 · Remove Age View / age-adaptive theming entirely (per Steve's call)
Age becomes a plain signup data point (signup flow to be scoped separately) — not an
in-showroom control. Ripped out the whole apparatus:
 • deleted public/js/ageview.js + its <script> tag
 • deleted all 6 scripts/verify-ageview-*.mjs + AGE-VIEWS-SPEC.md
 • removed the _qh Age View control surface (setAvatarAge/coalesceAvatarAge/avatarAge/
   ageRigParams export/upperRigState/setEnvForAge/resetEnv) from showroom.js
 • dropped the '#btn-ageview' dock entry + clickthrough selector; removed the
   Age-View-ON pass from verify-walls-on-next; dropped the two ageview npm scripts

KEPT byte-for-byte: the baseline age-28 avatar. buildAvatar()/ageRigParams() are the
normal showroom body's own material/dimension helpers (isBaseline fast-paths) and predate
Age View — nothing can now drive a non-28 age or age-tint the env.

Verified: fresh Playwright smoke — _ageview undefined, no levers, no #btn-ageview,
avatar present (6 children), 50 wings, 0 console errors; verify-walls-on-next still PASS.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
e0bed2f · 2026-07-01 · verify: At-the-Table behavioral test (nook hide/restore + seated set + sample-add) + verify-all runner
scripts/verify-table-view.mjs (npm run verify-table-view) drives window._viewmode.set('table'),
asserts the consultation nook hides (only centre table shows), the table+chair set and seated avatar
appear, addSample() grows the basket, then exits and asserts the nook is restored — 9/9 pass, 0 console
errors. Covers the newest committed feature (842a1dc). Added npm run verify-all to chain the 4 headless verifiers.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
4840661 · 2026-07-01 · 5x follow-up: WebGL scene-correctness + FPS verifier (closes the biggest coverage gap)
scripts/verify-scene-render.mjs (npm run verify-scene-render) asserts the Three.js scene actually
renders the wallcoverings — not just 'canvas drew something': 50 wing boards in the arc, 639 meshes
/227 textured (maps loaded), centre book present + book-matched (L mirrored/R normal), renderer
draw calls>0, frame loop alive. FPS measured avg 72 headless Chrome (>=55 spec target; real hw higher),
0 console errors. Closes the contrarian's #3 (24KB screenshot proves nothing) + the Age View Phase-5.1 FPS gate.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
504a0ed · 2026-07-01 · 5x sweep 3 (contrarian-driven): persist sort+density to localStorage (standing rule) + repeatable reload test
/contrarian gate caught a real bug the six-way suite can't: sort (currentSort) and density (windowSize)
never persisted to localStorage though the standing sort+density rule requires it — every other slider did.
Fixed: init from qh_sort/qh_density, write on change, reflect into the select/slider on boot. Proven with
scripts/verify-sort-density-persist.mjs (npm run verify-sort-density-persist) — sets sort=newest+density=30,
RELOADS, asserts both localStorage + restored control values survive. ✅ passes.
Report updated with an honest coverage boundary (WebGL scene correctness / FPS / mobile NOT covered here).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
604475e · 2026-07-01 · 5x sweep 1: fix duplicate id=density-wrap (7x → class); document sort/density-in-dock false-positives
Six-way verify: 5/6 + 0 console errors. The 2 clickthrough/E2E failures are false positives —
#bottom-bar and #window-bar(sort/density) are intentionally stowed into the hamburger dock at boot
(dock.js progressive-disclosure UX), verified reachable via ☰→Controls with zero console errors.
Real defect fixed: 7 duplicate density-wrap ids → .density-wrap class + CSS selector update.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
bb091f8 · 2026-07-01 · Age View Phase-5.5 (contrarian pass): coalesce avatar rebuild, tighten in-page gate, capture screenshots
Contrarian final gate found three real holes; fixed the two code ones:
 1. setAvatarAge() rebuilt the whole primitive avatar on EVERY slider input tick →
    dozens of full teardown/rebuilds per second mid-drag (the real FPS-gate failure
    mechanism). Now coalesced to ≤1 rebuild/animation-frame via coalesceAvatarAge();
    buildAvatar() stays synchronous + byte-for-byte (boot + OFF-reset call it directly).
 2. In-page seniorGate() used coarse type-size steps and never checked HEAD size — a
    softer bar than the spec, so its 'all-pass' would've been green even before the
    band type-size fix. Retightened to the interpolated 65→85 bar incl. heads, matching
    verify-ageview-gate.mjs. Still all-pass (the bands genuinely meet the stricter bar).
 3. Cross-engine harness now captures a screenshot per engine/age (was counters-only).

Re-ran both verifiers post-edit (validation-loop): static gate ALL 10 PASS; cross-engine
PASS on Chromium/Firefox/WebKit, 0 console errors, tightened seniorGate all-pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
d4295bd · 2026-07-01 · Age View Phase-5.3: cross-engine render gate (Chromium/Firefox/WebKit)
Playwright harness drives the live showroom, turns Age View on, sets the REAL
#av-slider to ages 12/45/85, and asserts per engine: 0 console errors, in-page
seniorGate() all-pass (APCA + type/target on 65/75/85 + slider85), and China Seas
wing wall intact. RESULT: PASS on all 3 engines, 0 console errors anywhere, readouts
correct (12→Tween, 45→Connoisseur, 85→Legacy).

FPS is reported but advisory only — headless uses software GL (swiftshader/llvmpipe)
so it under-represents real-hardware FPS; the 5.1 FPS gate still needs a real-browser
run on-device. npm run verify-ageview-crossengine (exit 1 on hard fail).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1ea5d2b · 2026-07-01 · Age View Phase-5 gate: fix under-spec type sizes on Senior/Elder bands + add re-runnable verifier
Ran the spec's HARD senior-usability gate (APCA + target-size + type-size) measured
against the real BANDS tokens. APCA contrast passed everywhere with wide margins, but
the two mid-senior bands were short on type size once the 65→85 requirement is
interpolated to the oldest age each band serves:
  • Senior (≤70): body 20→22, head 30→34
  • Elder  (≤80): body 22→26, head 32→42
Re-ran the gate post-edit (validation-loop): all 10 bands PASS. Added
scripts/verify-ageview-gate.mjs (npm run verify-ageview-gate, exit 1 on fail).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
4bb3eba · 2026-06-30 · chore: lint, refactor, v1.2.0 (session close)
- refactor: reset _dragTurned in onCanvasPointerDown discard path (prevents a stale flag swallowing the next click after toggling explore off)
- lint: log unfocusWing failures instead of silently swallowing
- node --check clean; nav re-verified green in headed Chrome (wheel/C-key/Center button, 0 errors)
de7d9e4 · 2026-06-30 · Avatar nav: comfortable centred boot framing + grounded scroll/arrow walk, drag-turn, and always-available Return to Center
- Boot: pull eye back to z=0.7 + BOOT_PITCH -0.12 so the open book frames with headroom (was 'way too close')
- Single-ownership nav: disable OrbitControls rotate/pan/zoom in both modes (killed the dolly-too-close / aerial-tilt / behind-furniture vectors)
- Scroll wheel + arrows walk; drag or A/D turns (vertical drag ignored = always grounded); eye height never changes = never aerial
- Grounded walkable box clamp excludes the closet/rack/nook/olive keep-outs (no walking behind the closet)
- Add ⊕ Center button + C/Home key + recenterView() glide back to middle, facing forward
- All-ages hint copy refreshed across HUD + guided instruction
e40c08a · 2026-06-29 · Feature: Next/Prev book-page renders the new design on all 4 walls
In BOOK_MODE (the default landing) gotoBoardOffset→pageCenterBook flipped the open book
but never clad the room. Added cladWalls(imageUrl) in setCenterBook — the single funnel for
book paging + load — so every Next/Prev renders the NEW design onto all 4 sides
(back/left/right/front), gated on wallsAutoClad so 'Walls: neutral' still wins. Initial
landing stays neutral (clean cream walls) by design; the design appears on first Next.

Verified: scripts/verify-walls-on-next.mjs — next×3 + prev all clad all 4 sides
(SKU advances 703346→703446→703546), 0 console errors, screenshot confirms.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
c378473 · 2026-06-29 · Age View band-differentiation: split young/adult/established into 3 hue families
Contrarian residual #4: adult(28)/established(40) were ~90% identical (both blue-grey,
violet CTA, gap 12). Now three distinct identities on palette + CTA hue + density:
 - young(21) Emerging Adult: electric VIOLET #7c3aed, purple-dark, gap 10 (energetic)
 - adult(28) Young Pro: dashboard BLUE #1d4ed8 (Lc 87), cool blue-grey, gap 12 (modern)
 - established(40) Established: deep TEAL #155e75 (Lc 90), teal-slate, gap 9 (dense/assured)
All CTAs white-text + contrast-verified. Also drop #guided-bar from clickthrough PANELS
(Steve made it a permanent fixture, not a dock panel).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
b3ca21a · 2026-06-29 · /5x: showroom-aware clickthrough + fix 2 real dock.js bugs it caught
The generic /3x clickthrough can't open the dock hamburger, so it false-failed on
intentionally-stowed controls. Built scripts/clickthrough-showroom.mjs that drives the
app like a user (open hamburger → launch each panel → exercise sort/sliders/nav → proxy
every tool). It caught 2 GENUINE defects the blind clickthrough never could:

1. dock.js quote-in-selector: TOOLS entries '#top-bar [data-section="wings"]' / '...overview'
   were interpolated raw into data-tool="..." (inner quotes close the attr) and into
   reflectMenu's querySelector('[data-tool="..."]') (throws 'not a valid selector'). Wings +
   Overview were unreachable from the menu and reflectMenu threw 14× PAGEERROR. Fix: key tools
   by index (data-tool-idx), resolve TOOLS[idx].sel in JS.

2. dock.js launched panels showed EMPTY: launch() removed qh-stowed from the wrapper but not
   from the panel element, so every launched panel's CONTENT stayed display:none!important —
   only the header bar showed (sort select measured 0×0, which is why selectOption timed out).
   Fix: el.classList.remove('qh-stowed') on launch. Panels now render their real content
   (verified by screenshot: Versions list + Controls sort/sliders visible).

Sweep 4 clean: sort all 5 options, all ranges, all nav, all 10 tools, 0 console errors.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
f1439ea · 2026-06-29 · Fix center-book leaf orientation: leaves face the viewer (drop the PI group flip)
The PI group rotation pointed each leaf's textured +Z front AWAY from the spawn and put
the right leaf on the -x side. Removed it -- the plane's +Z front already faces the +Z
viewer -- and splayed each leaf's OUTER edge back so the book opens as a gentle V toward
the avatar. Verified: both leaves normalZ ~+0.95, R worldX +0.36 / repeat.x +1, L worldX
-0.36 / repeat.x -1 (true horizontal mirror).
fa8ee90 · 2026-06-29 · Default view = walk the avatar + single centered mirrored book + minimal caption bar
- Walking is now the default: exploreMode ON + persisted; arrows = up/down walk along
  facing dir, left/right turn the body. Avatar rig + camera move together, clamped to room.
- Spawn dead-centre, stationary, facing the wing -- no boot auto-fly (enterFixedCentre /
  enterGuidedDefault are no-ops in book mode).
- SKU display is now a quiet fixed #wing-caption strip (Pattern . Colorway . SKU . Vendor),
  never pops/animates; the old wing-detail popup card is suppressed in book mode.
- The view is ONE open sample book centred on -Z with two leaves hinged at the spine;
  left leaf is a horizontal MIRROR of the right (repeat.x flipped). The 50-board arc is
  hidden. [ ] / N-P page the catalog.
- Consultation table+chairs nudged so the furnished 20x20 room reads in the scene.
04948ab · 2026-06-29 · Phase 5.5 /contrarian final pass: prove the AVATAR half + fix 2 weak non-senior CTAs
Contrarian (correctly) flagged the Phase-5 gate verified only the HUD half and proved
regression on a phantom hook. Closes both:

- scripts/verify-ageview-avatar.mjs — proves the avatar morph on the REAL _qh hooks
  (avatarAge getter + upperRigState): eye-height arc 1.40→1.62→1.61→1.58→1.48m,
  stoop monotonic rotX 0@28 → -0.070@65 → -0.209@85, regression OFF==age28 rotX=0,
  + look-down body screenshots at 12/28/45/65/85 (setSpin to PITCH_MIN). 0 errors.
- ageview.js BANDS: teen CTA #ff2fd6/near-black (APCA 47) -> #c01a9e/white (Lc 81);
  young CTA #a855f7/near-black (APCA 38, a real miss for the 21-yo band) -> #7c3aed/white
  (Lc 83). Same neon/violet identity, legible filled buttons.

Validation-loop re-run after edits: FPS floor 67 all 11 bands, senior 65/75/85 PASS,
regression PASS, cross-engine PASS, avatar PASS, 0 console errors.

Residual (honest, non-blocking): env-morph per-band is implemented + FPS-safe but
asserted by intensity values, not a measured rendered-luminance delta; adult(28)/
established(40) bands still ~90% identical (plan-gate fallback: merge or differentiate).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
71a067a · 2026-06-29 · Phase 5.3 cross-engine verifier: Age View slider PASS on WebKit + Firefox
scripts/verify-ageview-3x.mjs drives the 12/45/85 anchors in Safari(WebKit) and
Gecko(Firefox): scene built (50 boards), bands snap (tween/connoisseur/legacy),
postMessage bridge intact, 0 console errors in both. Chrome/Blink covered by the
real-GPU phase5 verifier. All 3 engines green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
d84af5b · 2026-06-29 · Phase 5 senior-usability HARD gate: measured verifier + 3 cascade/wiring fixes
Add scripts/verify-ageview-phase5.mjs — measures RENDERED composited hex (not
declared tokens) over the live WebGL scene on real-GPU Chrome, the contrarian
fix #1 requirement. It caught 3 real gaps the in-code seniorGate() self-test
passes:
 1. CTA dead: #g-tour is a .g-btn, so '#guided-bar .g-btn' (color:--av-fg)
    out-specified the '#g-tour' cta rule -> CTA text rendered in --av-fg over
    --av-cta (APCA 9/9/0). Fix: name both ids to win the cascade (Lc now 99/99/101).
 2. Body type-size vars set but never applied to #guided-instruction (stayed 18px).
    Fix: wire --av-body/--av-head onto the real text elements (now 20/22/28 + 30/32/44).
 3. #btn-ageview (36px) + #av-slider track (18px) under the senior target floor.
    Fix: grow to >=48px (65/75) / >=56px (85).

Measured verdict: FPS>=67 all 11 bands, senior 65/75/85 PASS, regression OFF==age28,
0 console errors.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
09cf8ad · 2026-06-28 · Chunk K (first-person Steve avatar, yaw-only rig) + Chunk A′ (20'×20' room)
K: first-person body built from THREE primitives (capsule limbs + boxes, $0, no
GLTF) — torso/shoulders/two arms+hands/legs/feet, charcoal sweater + indigo jeans +
dark shoes, NO head mesh (camera is the eyes). Parented to a YAW-ONLY rig
(avatarRig.rotation.y = spinYaw, position pinned under lockedSpinEye) so the body
turns with yaw but NEVER tilts with pitch — look down (PITCH_MIN deepened -0.62→-1.05,
~60°) and you see a stationary torso/lap/hands/legs/feet on the floor (BE Steve);
straight-ahead the body sits below the sight line so the wing bank reads clean.
updateAvatarRig() runs every frame after the spin pose; camera.position untouched.

A′: CONFIG.room 4.27→6.10 (20'×20'); arc re-fit arcRadius 2.2→3.2, arcCenter.z
0.4→0.5 so the 50-board bank still fans with ~2" slivers at a comfortable ~8.9'
distance; consultation nook relocated proportionally (1.25,-0.55)→(1.78,-0.78), same
+66° yaw inside the ±72° clamp. buildRoom/walls/baseboards/crown scale off CONFIG.

QH API: avatarPresent / avatarState() / setSpin() verification surface.
Proof bar (real-GPU Chrome, scripts/shot-chunkK-avatar.mjs): posDelta yaw 0, rigPitch
0 across all poses, 50 boards, clad 4 walls on click, errorCount 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
33391a6 · 2026-06-28 · Boot raycaster race fix: queue pre-ready canvas clicks + replay on ready (durable)
The canvas click listener is wired at init() but wingBoards stays empty until the
async loadProducts()->buildWingWall() chain finishes (~2-3s). A click in that window
used to silently no-op (empty raycaster targets) — to a 65-year-old that reads as
'it's broken.' Now:

- wingWallReady flips true the instant the full 50-board bank is wired into the
  raycaster (end of buildWingWall).
- onCanvasClick, when not ready, QUEUES the click coords (latest wins) and shows a
  gentle 'Loading the collection — your selection is queued…' cue via the existing
  loader status — never a dead click.
- drainBootClick() replays the queued click as the FINAL boot action (+2600ms, after
  the version engine's boot-time V1 apply), through the exact onCanvasClick path, so
  the board the user pointed at is selected + conveyored-to-front + 4-wall clad +
  detail shown. Their click WINS, durably.
- enterGuidedDefault / enterFixedCentre yield to a consumed/pending boot click during
  the boot window (_bootClickConsumed / _bootFixedCentreYield) so the resting-middle
  re-asserts and the versions.js V1 build cannot stomp the user's selection.

No Slice-1/2/3 regression: slice1 PASS (resting-middle, posDelta 0, clamp ±72°, 50
boards, errorCount 0), slice2 PASS (boot no-clad, select allFourClad, posDelta 0).
Proof: scripts/verify-bootrace.mjs — pre-ready click queued+cue shown, replay selects
board durably (allFourClad, detail visible), normal click no-regression, errorCount 0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
0979b2b · 2026-06-28 · Slice-3 F: FPS.ms.draws HUD readout + off-thread wall-clad decode (kills the select-moment dip)
MEASURE: added window._perf {fps,ms,draws,pixelRatio} + 'N FPS . M ms . D draws'
readout to the bottom HUD (measurable on demand; read by the proof harness).
Real-GPU (Apple M2 Max ANGLE/Metal via system Chrome) nav sweep BEFORE fix held
72 FPS everywhere EXCEPT one 51-FPS select-moment dip (4-wall clad upload + hero
flip on the same frame). FIX (low-risk): cladWalls() now decodes the wall image
OFF-thread via createImageBitmap (was a main-thread new Image()), mirroring the
hero path; applyWallImage uses CanvasTexture for ImageBitmap sources (correct
flipY — walls verified right-side-up). AFTER: nav sweep pins at 72 FPS / 13.9ms
on EVERY sample incl. the select frame — gate >=55 met, errorCount 0.

Headless SwiftShader can't measure real FPS so the gate is verified on real GPU;
the headless harness gates the structural H + Slice 1/2 invariants.
1b5eb93 · 2026-06-28 · Slice-3 H: globally-unique element build codes (1000QH<version>)
assignElementCodes() runs once at registry load — iterates VERSION_ORDER, each
version's elements by ascending n, handing out base-1000 global seq across all 11
builds; stamps elt.code (e.g. seq 0 + QH + V2 -> 1000QHV2). Deterministic + stable.
BUILD_CODE='QH' isolated to one swappable constant. Pin identity, Chosen tray, and
Copy-as-text now key on the durable global code, not the version-local 'V1.4' key
(which collided across versions). Pins show the code chip + friendly badge n.
qh_chosen localStorage migrates old key-only rows (backfills code, never crashes).
0e9e564 · 2026-06-28 · Open-face clean: hero board pushes forward + re-centres so the open 30x6 face reads full-bleed edge-to-edge with NO neighbour slat-bars/frames crossing the pattern
Root cause: an open hero stayed in the rail plane at the same depth as its raked
neighbours, so their tilted sliver faces + dark frame bars projected IN FRONT of
the open face (the gray/colored vertical bars crossing the pattern). The left-hinge
face-offset also pushed the open face halfWidth to the right of dead-front.

Fix (rack.js flipUpdate): the opening hero now (1) slides forward along the inward
normal toward the room centre (OPEN_FORWARD_M=0.42m, flip-scaled) so it sits clearly
in front of every raked neighbour — normal depth-testing then occludes them, nothing
crosses the pattern; (2) shifts left by faceHalf*flip so the 30in face is centred
dead-front (same pattern left & right of the open middle). placeBoard records the rail
base pos + inward normal + faceHalf; relayout re-reads the clean base each carousel frame.

Proof (verify-openface.mjs occlusion raycast): 25/25 grid points over the open face
hit the hero FIRST, 0 offenders, real texture full-bleed, face-centre world-X ~0,
errorCount 0. Carousel/clad/fixed-centre invariants intact (verify-carousel green,
now measuring the face centre not the left-hinge pivot).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2c946ef · 2026-06-28 · Slice1 fix-it: 72° yaw clamp (non-empty), 50 boards, ~36° resting-open middle
FIX-1 YAW_CLAMP 105°→72° + nook pulled forward (yaw +66°, within clamp) so
boards + side wall stay in frame at both clamps; never an empty void.
FIX-2 wing.totalCount 20→50 so the real data path fans all 50 slivers.
FIX-3 OPEN_ANGLE_DEG 45→37 → resting-open middle sits ~36° off dead-on
(restFlip 0.51), foreshortened ~24" — unmistakably angled, not flat,
no detail panel/selection. verify-slice1 tightened to gate non-empty clamp.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
597fb5b · 2026-06-28 · proto: COLOR RIVER — shop China Seas by hue as a flowing Three.js color current
- v6-colorriver.html: client-side hue extraction (sat-weighted, ground-aware),
  swatches laid out along a continuous spectrum riverbed with undulating flow,
  hue-rail navigation, click-to-focus big swatch + 27x27 spec card
- headless playwright verifiers: 120/120 swatches, sorted-by-hue, 0 console errors,
  click-to-focus surfaces real pattern name + spec
- proto/ only; touches nothing in public/ or shared app files

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
72bd476 · 2026-06-28 · proto v7: mood-board table — drag swatches, build palette, pairs-well-with
Standalone proto/v7-moodboard.html: designer's felt table where swatch cards
drag from a tray onto the board (free-position + rotation + overlap), emit an
aggregated color palette, and surface PAIRS WELL WITH (same pattern-family
colorways + same color bucket) that are themselves draggable onto the table.
Pulls from /api/showroom/products?limit=120. Verified headless: 120 swatches,
2-card pointer-drag, pairs render, palette aggregates, 0 console errors.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
e6c14ec · 2026-06-28 · Add V1-vs-reference comparison + 10-version contact sheet; document build status + flag contrarian V6-V10 fork
- recordings/shots/ver-V1-vs-reference.png: side-by-side of pj-dallas-showroom.png vs V1 build
- recordings/shots/ver-contact-sheet.png: all 10 versions in one grid (distinct looks)
- VERSIONS.md: BUILT note + OPEN FORK flag — built original V1-V10; contrarian-pass
  V6-V10 mechanic upgrade is a per-preset swap when Steve wants it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
5954106 · 2026-06-28 · V1 establishing arc (matches pj-dallas-showroom.png) + V2 step-driven conveyor + rail layout
- V1: wide establishing shot (high front-right, FOV 64) showing the sliver-packed
  corner arc + consultation nook + warm oak floor like the reference photo, instead of
  isolating one board. restoreBoards()+revertWalls()+open middle; boot defers to 1800ms
  so it wins the race vs the guided auto-focus (which was re-isolating to 1 board).
- V2 conveyor: real step controller (NOT auto-spin) — user dead-centre+stationary, the
  RACK yaws so each product rotates INTO centre; ArrowRight/Left + guided Next/Prev step
  one board at a time (capture-phase intercept while V2 active only), eased anim, idle =
  zero shadow rebakes. Verified: ArrowRight steps fwd, ArrowLeft steps back.
- setVersion now calls the prior version's exit() (conveyor key/click/frame cleanup).
- Rail layout: anchored top-right + max-height capped so it never collides with the
  bottom-right Chosen tray (was overlapping at 1600x900); collapse transform fixed.
- test-versions samples steady-state FPS (after settle) — all 10 versions hold 72fps;
  earlier sub-50 reads were camera-fly/texture-upload settling frames. 0 errors.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1a31ad6 · 2026-06-28 · 10 VERSIONS system: V1-V10 picker rail + numbered-element overlay + Chosen Elements tray
- versions.js: bolt-on module (DTD verdict A) talking only through window._qh; each
  version = preset {name, build(), elements:[{n,label,anchor}]}. V1 PJ arc rack, V2
  dry-clean conveyor, V6 flat gallery (current) built for real; V3-V5/V7-V10 scaffolded
  by composing existing view-modes/themes so all 10 appear in the picker.
- Persistent V1..V10 rail (right-centre), big tabular V-numbers + serif names, brass
  active state; collapsible w/ pull-out tab. Remembers last version.
- Numbered-element overlay: circled-number pins projected onto each element via new
  _qh.projectToScreen/boardWorldPos/namedAnchor hooks + overlayHook in animate loop;
  click a pin -> Chosen Elements tray (chips like 'V1.4 Flip-to-open'), copy-as-text
  export, remove/clear, chosen pins show check state, persists to localStorage.
- PERF fix: carousel/V2 was 31fps (full scene.traverse + per-frame shadow rebake each
  frame); cached wall group + throttled shadow to ~6/s -> 56fps.
- Cormorant Garamond webfont for serif version names (ART-DIRECTION).
- LOCKED features verified intact: senior Next/Back/Auto-Tour, collapsed popup, 27x27
  China Seas specs, photoreal surfaces, on-demand shadows. test-versions.js + test-senior.js
  both pass: 0 errors, FPS 56-73, all 10 apply, overlay+tray work.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
8a47897 · 2026-06-26 · Realism pass + proximity book-match wings
Renderer/materials/lighting → PBR:
- antialias on, adaptive pixelRatio (1.5→1.0 auto-ratchet guard), sRGB output,
  exposure 1.2→1.0, PCF shadow map (1024) — real key-light contact shadows
- MeshLambert/Phong → MeshStandard across floor/walls/chrome/wood/furniture
- PMREM studio-gradient environment for believable chrome/floor reflections
- color maps tagged sRGB + max anisotropy (kills slat moiré)

Wings rebuilt as two-leaf BOOK-MATCH boards (thin boxes, cast+receive shadow):
- walk within 4 ft (1.22m) of the wall → nearest wing opens like a sample book,
  left leaf mirrored / right leaf normal across a center spine
- updateBooks() proximity driver; focused/clicked wing also opens
- B key + book HUD toggle to enable/disable; loadWingBook() applies the
  normal+mirrored texture pair (cached per URL)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

File tree

379 files tracked. Click any to browse the source at HEAD.

Other build journals

← Quadrille Room Credit Enrich  ·  all 4 projects  ·  Raffiawallcoverings →

Export

commits.csv · feed.atom · project.json · commits.json

rendered in 1ms