← back to Quadrille Showroom
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
37affeb4205ee6d43b0205b7b4566007787330d4 · 2026-06-28 16:20:08 -0700 · Steve
Files touched
M public/js/showroom.jsM public/showroom.html
Diff
commit 37affeb4205ee6d43b0205b7b4566007787330d4
Author: Steve <steve@designerwallcoverings.com>
Date: Sun Jun 28 16:20:08 2026 -0700
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
---
public/js/showroom.js | 46 +++++++++++++++++++++++++++++++++++++++++-----
public/showroom.html | 5 ++++-
2 files changed, 45 insertions(+), 6 deletions(-)
diff --git a/public/js/showroom.js b/public/js/showroom.js
index 7524ebe..4dbf7c9 100644
--- a/public/js/showroom.js
+++ b/public/js/showroom.js
@@ -12,7 +12,7 @@ const CONFIG = {
wing: {
height: 1.8288, // 6 ft tall (real sample-board height)
boardWidthM: 0.762, // 30" wide (real sample-board width)
- totalCount: 20, // boards in the arc at once — packed slivers; Peruse pages the 883
+ totalCount: 50, // boards in the arc at once — packed slivers; Peruse pages the 883
wallMargin: 0.3,
animSpeed: 0.06,
panelOpen: 1.35,
@@ -71,6 +71,16 @@ let VIEW_OPEN = (function () {
return (v >= 0 && v <= 90 ? v : 8) * Math.PI / 180;
})();
+// OPEN-ANGLE SLIDER (Slice-1 spec) — the resting MIDDLE board's open angle on boot.
+// Measured in DEGREES the board has swung off its packed closed-rake toward open-flat
+// (0°=fully closed/raked, rake°=fully open/flat-to-centre). Default 45°, range 20°–90°,
+// persisted to localStorage('qh_open_angle'). updateBooks converts this to a per-board
+// flip fraction (deg / board-rake-deg) so the open hero rakes to exactly this angle live.
+let OPEN_ANGLE_DEG = (function () {
+ const v = parseFloat(localStorage.getItem('qh_open_angle'));
+ return (v >= 20 && v <= 90) ? v : 45;
+})();
+
// REVEAL SLIDER (Steve's explicit ask) — how much of each closed board's pattern shows
// in the packed arc. Drives the per-board closed RAKE angle in QHRack (smaller reveal =
// wider sliver = more pattern per board / fewer boards; larger reveal = thinner slivers =
@@ -2062,7 +2072,7 @@ function onCanvasMouseMove(event) {
// ============================================================
const SPIN_YAW_SPEED = 1.6; // rad/s of yaw under held arrow
const SPIN_PITCH_SPEED = 0.9; // rad/s of pitch under held arrow
-const YAW_CLAMP = 105 * Math.PI / 180; // ±105° off wing-facing (-z) — never behind the wings
+const YAW_CLAMP = 72 * Math.PI / 180; // ±72° off wing-facing (-z) — the look-vector z stays negative so the leftmost/rightmost boards + side wall stay in frame; never an empty room, never behind the wings
const PITCH_MIN = -0.62; // look down ~36° (to the sample table)
const PITCH_MAX = 0.30; // look up ~17°
const TARGET_DIST = 2.0; // distance the look-target sits ahead of the fixed camera
@@ -2159,10 +2169,17 @@ function updateBooks(dt) {
// Lazy-load the open board's full design the moment it begins to swing open.
if (openPivot && !openPivot.userData.imageLoaded) { openPivot.userData.imageLoaded = true; loadWingBook(openPivot); }
- // A real focus opens fully flat (hero); the resting-open middle eases to a partial
- // angle (0.62) so it reads as "open at an angle", not a flat selected hero.
+ // A real focus opens fully flat (hero); the resting-open middle eases to the
+ // slider-controlled OPEN_ANGLE_DEG (default 45°) so it reads as "open at an angle",
+ // not a flat selected hero. flip = openAngle / rake (both in radians), so the board's
+ // actual swing off closed equals OPEN_ANGLE_DEG; clamp to [0,1].
const isRestingOnly = (openPivot && openPivot === restingOpenWing && openPivot !== focusedWing);
- const moved = QHRack.flipUpdate(wingBoards, openPivot, dt, isRestingOnly ? 0.8 : 1);
+ let restFlip = 1;
+ if (isRestingOnly) {
+ const rake = openPivot.userData.rake || (73 * Math.PI / 180);
+ restFlip = Math.max(0, Math.min(1, (OPEN_ANGLE_DEG * Math.PI / 180) / rake));
+ }
+ const moved = QHRack.flipUpdate(wingBoards, openPivot, dt, restFlip);
// SHADOW REBAKE BUDGET: don't rebake the (2 lights × 238-mesh) shadow maps EVERY
// moving frame — that's the dominant nav cost. Rebake once when a flip STARTS (catch
// the first frame of motion) and once when it SETTLES (motion→still), not in between.
@@ -2683,6 +2700,25 @@ function initHUD() {
});
}
+ // OPEN-ANGLE slider (Slice-1) — the resting MIDDLE board's open angle on boot.
+ // Live: updateBooks re-derives the resting board's flip from OPEN_ANGLE_DEG every
+ // frame, so dragging this re-rakes the open hero in real time. Persisted to
+ // localStorage('qh_open_angle'). Range 20°–90°, default 45°.
+ const opn = document.getElementById('open-range');
+ const opnVal = document.getElementById('open-val');
+ if (opn) {
+ opn.value = Math.round(OPEN_ANGLE_DEG);
+ if (opnVal) opnVal.textContent = opn.value + '°';
+ opn.addEventListener('input', () => {
+ OPEN_ANGLE_DEG = parseInt(opn.value) || 45;
+ if (opnVal) opnVal.textContent = OPEN_ANGLE_DEG + '°';
+ localStorage.setItem('qh_open_angle', OPEN_ANGLE_DEG);
+ // Nudge the resting board out of its settled state so flipUpdate re-eases to the
+ // new target this frame (flipUpdate only moves boards whose flip != target).
+ if (restingOpenWing && window._requestShadowUpdate) window._requestShadowUpdate(6);
+ });
+ }
+
// ---- GUIDED MODE wiring (senior-first big buttons) ----
const gPrev = document.getElementById('g-prev');
const gNext = document.getElementById('g-next');
diff --git a/public/showroom.html b/public/showroom.html
index 3c0cd88..71be014 100644
--- a/public/showroom.html
+++ b/public/showroom.html
@@ -286,7 +286,7 @@
<option value="book">Book</option>
</select>
<span id="density-wrap" title="Wings per wall">
- <span>Boards</span><input type="range" id="density-range" min="10" max="24" step="2" value="18">
+ <span>Boards</span><input type="range" id="density-range" min="10" max="50" step="2" value="50">
</span>
<span id="density-wrap" title="Open-board angle (0°=flat, dead-on)">
<span>Wing°</span><input type="range" id="angle-range" min="0" max="90" step="5" value="8"><span id="angle-val">8°</span>
@@ -294,6 +294,9 @@
<span id="density-wrap" title="How much of each closed board's pattern shows — wider edges = fewer boards, thinner slivers = more boards in the arc">
<span>Reveal</span><input type="range" id="reveal-range" min="0" max="100" step="5" value="70"><span id="reveal-val">70</span>
</span>
+ <span id="density-wrap" title="Open angle of the resting middle board (45° = the boot hero rake)">
+ <span>Open°</span><input type="range" id="open-range" min="20" max="90" step="5" value="45"><span id="open-val">45°</span>
+ </span>
</div>
<!-- NOW VIEWING navigator — museum media-player strip (shown only on focus).
← c38484d auto-save: 2026-06-28T16:15:32 (1 files) — LIQUID-UI-SPEC.md
·
back to Quadrille Showroom
·
Slice1 fix-it: 72° yaw clamp (non-empty), 50 boards, ~36° re 2c946ef →