← 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
A proto/shots/new-mechanics-contact.pngM public/js/showroom.js
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 →