[object Object]

← back to Quadrille Showroom

proto: COLOR RIVER — shop China Seas by hue as a flowing Three.js color current

597fb5b8933e835e7a202f8948fbe885c5177709 · 2026-06-28 08:10:28 -0700 · Steve

- 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>

Files touched

Diff

commit 597fb5b8933e835e7a202f8948fbe885c5177709
Author: Steve <steve@designerwallcoverings.com>
Date:   Sun Jun 28 08:10:28 2026 -0700

    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>
---
 proto/shot-focus.cjs                |  46 ++++++++++++++++++++++++++++++++++++
 proto/shots/v6-colorriver-focus.png | Bin 0 -> 4547727 bytes
 proto/shots/v6-colorriver.png       | Bin 867221 -> 1906135 bytes
 3 files changed, 46 insertions(+)

diff --git a/proto/shot-focus.cjs b/proto/shot-focus.cjs
new file mode 100644
index 0000000..4460ed8
--- /dev/null
+++ b/proto/shot-focus.cjs
@@ -0,0 +1,46 @@
+#!/usr/bin/env node
+/* Verify the click-to-focus mechanic: drive focus() on a swatch programmatically,
+   confirm the detail card shows the pattern name + 27" spec, capture a focus shot. */
+const { spawn } = require("child_process");
+const path = require("path");
+const http = require("http");
+const PROTO_DIR = __dirname, PORT = 7712;
+const URL = `http://127.0.0.1:${PORT}/v6-colorriver.html`;
+function waitForServer(port,tries=40){return new Promise((res,rej)=>{const p=(n)=>{const r=http.get({host:"127.0.0.1",port,path:"/v6-colorriver.html"},x=>{x.destroy();res();});r.on("error",()=>{if(n<=0)return rej(new Error("no server"));setTimeout(()=>p(n-1),150);});};p(tries);});}
+(async()=>{
+  const pw=require("playwright");
+  const srv=spawn("node",[path.join(PROTO_DIR,"proxy-server.cjs")],{env:{...process.env,PROTO_PORT:String(PORT)},stdio:"inherit"});
+  let code=1;
+  try{
+    await waitForServer(PORT);
+    const b=await pw.chromium.launch({headless:true});
+    const pg=await b.newPage({viewport:{width:1440,height:900},deviceScaleFactor:2});
+    const errs=[]; pg.on("console",m=>{if(m.type()==="error")errs.push(m.text());}); pg.on("pageerror",e=>errs.push(e.message));
+    await pg.goto(URL,{waitUntil:"domcontentloaded"});
+    await pg.waitForFunction(()=>window.__RIVER__&&window.__RIVER__.done(),{timeout:35000}).catch(()=>{});
+    await pg.waitForTimeout(1500);
+    // pick a saturated swatch and focus it via the page's own click path
+    const info = await pg.evaluate(()=>{
+      // find a colorful swatch by raycasting against the most saturated one
+      const probe = window.__FOCUS_PROBE__;
+      return probe ? probe() : null;
+    });
+    // no probe export — instead simulate a center click on a visible swatch
+    await pg.mouse.click(720, 380);
+    await pg.waitForTimeout(1400);
+    const cardShown = await pg.evaluate(()=>document.getElementById("detail").classList.contains("show"));
+    const name = await pg.evaluate(()=>document.getElementById("d_name").textContent);
+    const dim = await pg.evaluate(()=>document.getElementById("d_dim").textContent);
+    await pg.screenshot({path:path.join(PROTO_DIR,"shots","v6-colorriver-focus.png")});
+    console.log("\n=== FOCUS VERIFY ===");
+    console.log("detail card shown :", cardShown);
+    console.log("pattern name      :", JSON.stringify(name));
+    console.log("dimensions spec   :", JSON.stringify(dim));
+    console.log("console errors    :", errs.length);
+    console.log("====================");
+    await b.close();
+    code = (cardShown && name && name!=="—" && /27/.test(dim) && errs.length===0) ? 0 : 1;
+    console.log(code===0?"FOCUS: PASS":"FOCUS: (card may need a swatch under the click point)");
+  }catch(e){console.error(e);code=3;}
+  finally{srv.kill("SIGTERM");setTimeout(()=>process.exit(code),300);}
+})();
diff --git a/proto/shots/v6-colorriver-focus.png b/proto/shots/v6-colorriver-focus.png
new file mode 100644
index 0000000..bae722f
Binary files /dev/null and b/proto/shots/v6-colorriver-focus.png differ
diff --git a/proto/shots/v6-colorriver.png b/proto/shots/v6-colorriver.png
index 283804b..826f69b 100644
Binary files a/proto/shots/v6-colorriver.png and b/proto/shots/v6-colorriver.png differ

← cbd8fb9 Tighter arc (86deg span, ~75% overlap = thinner slivers) + w  ·  back to Quadrille Showroom  ·  auto-save: 2026-06-28T08:13:35 (4 files) — proto/shots/v10-c 6241da8 →