[object Object]

← back to Quadrille Showroom

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

e4cdbacc6a801e51ee56b0fde3b7662e54af1cb5 · 2026-06-28 08:19:13 -0700 · Steve

Files touched

Diff

commit e4cdbacc6a801e51ee56b0fde3b7662e54af1cb5
Author: Steve <steve@designerwallcoverings.com>
Date:   Sun Jun 28 08:19:13 2026 -0700

    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
---
 proto/shots/new-mechanics-contact.png | Bin 0 -> 8898295 bytes
 public/js/showroom.js                 |  43 +++++++++++++++++++++++-----------
 2 files changed, 29 insertions(+), 14 deletions(-)

diff --git a/proto/shots/new-mechanics-contact.png b/proto/shots/new-mechanics-contact.png
new file mode 100644
index 0000000..958bca5
Binary files /dev/null and b/proto/shots/new-mechanics-contact.png differ
diff --git a/public/js/showroom.js b/public/js/showroom.js
index a941940..9dd27cb 100644
--- a/public/js/showroom.js
+++ b/public/js/showroom.js
@@ -1355,9 +1355,12 @@ const imageTexCache = {};
 // ---- FullDesign tileability gate (JS port of skills/fulldesign test_fulldesign.py) ----
 const _fdCanvas = document.createElement('canvas');
 function detectFullDesign(img) {
-  const STRIP = 3, THRESH = 30;
-  const w = Math.min(400, img.naturalWidth || 400);
-  const h = Math.min(800, img.naturalHeight || 800);
+  // Small detection canvas (200×400) — the L/R seam comparison needs only the leading
+  // and trailing 2px columns, so scaling the full Shopify JPEG down to 200×400 instead
+  // of 400×800 quarters the main-thread drawImage cost (the per-flip texture stall).
+  const STRIP = 2, THRESH = 30;
+  const w = Math.min(200, img.naturalWidth || 200);
+  const h = Math.min(400, img.naturalHeight || 400);
   if (w < STRIP * 2) return { isFullDesign: false, lrScore: 999 };
   _fdCanvas.width = w; _fdCanvas.height = h;
   const ctx = _fdCanvas.getContext('2d', { willReadFrequently: true });
@@ -1487,23 +1490,35 @@ function loadWingBook(pivot, onDone) {
 
   const img = new Image();
   img.onload = () => {
-    const isFD = (product && product.isSeamlessTile) ? true : detectFullDesign(img).isFullDesign;
+    // Build + show the texture IMMEDIATELY with a seamless-tile assumption (most China Seas
+    // designs are), so the design appears on the click frame. The seamless DETECTION
+    // (detectFullDesign — a main-thread drawImage+getImageData) is deferred to idle so it
+    // never stalls the flip; if it turns out non-seamless we re-fit + flag a frame later.
     const t = new THREE.Texture(img);
     t.minFilter = THREE.LinearMipmapLinearFilter; t.magFilter = THREE.LinearFilter; t.generateMipmaps = true;
     t.anisotropy = maxAniso; srgb(t);
-    if (isFD) {
-      const { rx, ry } = computeRepeat(wingW, product, img);
-      t.wrapS = t.wrapT = THREE.RepeatWrapping;
-      t.repeat.set(Math.max(1, rx), ry);   // full board span, tiled at true scale
-    } else {
-      // Non-seamless catalog photo: contain-fit the WHOLE image across the board face.
-      t.wrapS = t.wrapT = THREE.ClampToEdgeWrapping;
-      t.repeat.set(1, 1);
-    }
+    const { rx, ry } = computeRepeat(wingW, product, img);
+    t.wrapS = t.wrapT = THREE.RepeatWrapping;
+    t.repeat.set(Math.max(1, rx), ry);
     t.needsUpdate = true;
-    const cached = { texture: t, isFullDesign: isFD };
+    const cached = { texture: t, isFullDesign: true };
     imageTexCache[imageUrl] = cached;
     apply(cached);
+    // Deferred seamless verification — refine repeat + red banner off the critical path.
+    const verify = () => {
+      if (product && product.isSeamlessTile) return;          // gen tiles are known seamless
+      const isFD = detectFullDesign(img).isFullDesign;
+      cached.isFullDesign = isFD;
+      if (product) product.isFullDesign = isFD;
+      if (!isFD) {                                            // non-seamless → contain-fit + flag
+        t.wrapS = t.wrapT = THREE.ClampToEdgeWrapping;
+        t.repeat.set(1, 1); t.needsUpdate = true;
+        setWingBanner(pivot, true);
+      }
+    };
+    if (window.requestIdleCallback) requestIdleCallback(verify, { timeout: 500 });
+    else setTimeout(verify, 120);
+    if (onDone) onDone();
   };
   img.onerror = () => { if (onDone) onDone(); };
   img.src = src;

← 6241da8 auto-save: 2026-06-28T08:13:35 (4 files) — proto/shots/v10-c  ·  back to Quadrille Showroom  ·  Off-thread texture decode (fetch+createImageBitmap) kills th e40b519 →