← back to Quadrille Showroom
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
f75fcc78a34166b7ef0d76883eedb824efdd2bc9 · 2026-06-28 07:50:14 -0700 · Steve
Files touched
M public/js/showroom.jsM public/js/versions.js
Diff
commit f75fcc78a34166b7ef0d76883eedb824efdd2bc9
Author: Steve <steve@designerwallcoverings.com>
Date: Sun Jun 28 07:50:14 2026 -0700
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
---
public/js/showroom.js | 31 ++++++++++++++++++++-----------
public/js/versions.js | 6 ++++--
2 files changed, 24 insertions(+), 13 deletions(-)
diff --git a/public/js/showroom.js b/public/js/showroom.js
index 3aaa444..32b64d7 100644
--- a/public/js/showroom.js
+++ b/public/js/showroom.js
@@ -752,7 +752,7 @@ function buildLighting() {
key.position.set(2.4, CONFIG.room.height + 1.4, 2.2);
key.target.position.set(0, 1.0, -CONFIG.room.depth / 2);
key.castShadow = true;
- key.shadow.mapSize.set(2048, 2048); // 4× the texels → crisp-yet-soft contact shadows
+ key.shadow.mapSize.set(1536, 1536); // crisp-yet-soft; smaller than 2048 for rebake headroom
const sc = key.shadow.camera;
sc.near = 0.5; sc.far = 14; sc.left = -5; sc.right = 5; sc.top = 4; sc.bottom = -3;
key.shadow.bias = -0.0004;
@@ -1160,7 +1160,11 @@ function buildWingWall() {
// raycast + loadWingBook plumbing keeps working with no per-leaf split.)
const face = new THREE.Mesh(BG.face, poolMat);
face.position.set(faceOffX, yC, 0);
- face.castShadow = true; face.receiveShadow = true;
+ // Closed packed boards DON'T cast into the shadow map — their contact-shadow sprite
+ // grounds them, and casting 18 tightly-packed 6-ft boards doubles every shadow rebake
+ // (key+pic lights) for almost no visible gain. Only the OPEN hero casts (toggled on
+ // focus in isolateBoard). Big nav-FPS win; the rack still reads grounded.
+ face.castShadow = false; face.receiveShadow = true;
face.userData = { isWingFace: true, parentPivot: pivot, leaf: 'F' };
pivot.add(face);
// Per-board light gradient + sheen overlay, tracking the single face.
@@ -1587,21 +1591,26 @@ function focusOnWing(pivot) {
document.getElementById('info-text').textContent = `${product.pattern_name || product.name} · ${product.vendor} | ◀ Back / Next ▶ to flip through`;
}
-// Isolate the focused board — hide the others so the open design is presented alone,
-// dead-centre. Restored on exit / window rebuild.
+// Isolate the focused board — the PJ way: the hero swings OPEN and presents its design,
+// while the rest of the arc STAYS VISIBLE as the packed sliver backdrop (NOT hidden) —
+// exactly the reference photo (open boards amid the fanned slivers). The hero is the
+// only board that casts into the shadow map (toggled here), so it reads as a real
+// lifted-forward panel without the cost of 18 cast-shadow boards.
function isolateBoard(pivot) {
- if (window._requestShadowUpdate) window._requestShadowUpdate(6); // visibility changed → rebake
+ if (window._requestShadowUpdate) window._requestShadowUpdate(6);
wingBoards.forEach(p => {
- p.visible = (p === pivot);
- // Hide every wall drop-shadow in focus/hero mode: the other boards are hidden (their
- // shadow would float), and the focused board swings forward off the wall (so it no
- // longer casts directly behind itself). They come back in restoreBoards().
+ p.visible = true; // keep the sliver arc — do NOT hide
+ if (p.userData.face) p.userData.face.castShadow = (p === pivot); // only the hero casts
if (p.userData.wallDrop) p.userData.wallDrop.visible = false;
});
}
function restoreBoards() {
- wingBoards.forEach(p => { p.visible = true; if (p.userData.wallDrop) p.userData.wallDrop.visible = true; });
- if (window._requestShadowUpdate) window._requestShadowUpdate(6); // visibility changed → rebake
+ wingBoards.forEach(p => {
+ p.visible = true;
+ if (p.userData.face) p.userData.face.castShadow = false; // back to no-cast slivers
+ if (p.userData.wallDrop) p.userData.wallDrop.visible = false; // arc has no flat wall behind
+ });
+ if (window._requestShadowUpdate) window._requestShadowUpdate(6);
}
// Next / Back — flip to the next/previous wingboard (pages window edges, endless).
diff --git a/public/js/versions.js b/public/js/versions.js
index 97e81ba..44161fe 100644
--- a/public/js/versions.js
+++ b/public/js/versions.js
@@ -643,8 +643,10 @@ function boot() {
const safeBoot = { V1: 1, V6: 1, V7: 1, V8: 1, V9: 1, V10: 1 };
const saved = localStorage.getItem('qh_version');
const bootKey = (saved && VERSIONS[saved] && safeBoot[saved]) ? saved : 'V1';
- // Defer the build a beat so viewmodes.js has finished its own boot (it sets Hero).
- setTimeout(() => setVersion(bootKey, true), 900);
+ // Defer the build so BOTH the showroom's guided auto-focus (~700ms) AND viewmodes.js's
+ // boot ('hero', ~1200ms) have settled — then the version build OWNS the final scene
+ // state (otherwise the guided focus re-isolates the boards under V1's establishing shot).
+ setTimeout(() => setVersion(bootKey, true), 1800);
// Overlay restore (default OFF — the locked simple boot).
if (localStorage.getItem('qh_overlay') === '1') setTimeout(() => setOverlay(true), 1400);
← fecd0e8 auto-save: 2026-06-28T07:43:27 (4 files) — public/css/showro
·
back to Quadrille Showroom
·
V1 establishing arc (matches pj-dallas-showroom.png) + V2 st 5954106 →