[object Object]

← back to Wild Wallcoverings

GO-bar flow: local pending selections, batch save on GO, nothing persists until pressed

5cf4e01aa9a5c689566d1c1b98b7dcb9c14d8933 · 2026-07-22 20:13:48 -0700 · Steve Abrams

Files touched

Diff

commit 5cf4e01aa9a5c689566d1c1b98b7dcb9c14d8933
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Wed Jul 22 20:13:48 2026 -0700

    GO-bar flow: local pending selections, batch save on GO, nothing persists until pressed
---
 data/choices.json                         |  43 +--------------------------
 data/designs.json                         |   9 +++---
 output/designs/lagoon-legends-v2-sdxl.png | Bin 73494 -> 88546 bytes
 output/designs/lagoon-legends-v3-sdxl.png | Bin 83727 -> 88724 bytes
 output/designs/plumbline-v4-nano.png      | Bin 38600 -> 47873 bytes
 public/index.html                         |  47 ++++++++++++++++++++++++++++--
 server.js                                 |  21 +++++++++++++
 7 files changed, 71 insertions(+), 49 deletions(-)

diff --git a/data/choices.json b/data/choices.json
index 5cad0fc..0967ef4 100644
--- a/data/choices.json
+++ b/data/choices.json
@@ -1,42 +1 @@
-{
-  "mod-orbit": {
-    "variant": "mod-orbit-v1-nano.png",
-    "chosen_at": "2026-07-23T00:24:38.492Z"
-  },
-  "dream-clouds": {
-    "variant": "dream-clouds-v5-nano.png",
-    "chosen_at": "2026-07-23T01:31:00.321Z"
-  },
-  "campfire-toile": {
-    "variant": "campfire-toile-v5-nano.png",
-    "chosen_at": "2026-07-23T01:31:26.692Z"
-  },
-  "circle-fields": {
-    "variant": "circle-fields-v6-nano.png",
-    "chosen_at": "2026-07-23T01:31:38.459Z"
-  },
-  "daily-dose": {
-    "variant": "daily-dose-v3-sdxl.png",
-    "chosen_at": "2026-07-23T01:31:46.356Z"
-  },
-  "arcade-memory": {
-    "variant": "none",
-    "chosen_at": "2026-07-23T01:31:57.661Z"
-  },
-  "regatta-day": {
-    "variant": "regatta-day-v1-nano.png",
-    "chosen_at": "2026-07-23T01:32:08.410Z"
-  },
-  "fungi-skyline": {
-    "variant": "fungi-skyline-v1-nano.png",
-    "chosen_at": "2026-07-23T01:32:13.914Z"
-  },
-  "lagoon-legends": {
-    "variant": "lagoon-legends-v2-sdxl.png",
-    "chosen_at": "2026-07-23T01:32:24.771Z"
-  },
-  "plumbline": {
-    "variant": "plumbline-v6-nano.png",
-    "chosen_at": "2026-07-23T01:32:33.486Z"
-  }
-}
\ No newline at end of file
+{}
diff --git a/data/designs.json b/data/designs.json
index 0526be5..f02c619 100644
--- a/data/designs.json
+++ b/data/designs.json
@@ -2065,7 +2065,8 @@
      "acceptable": false
     },
     "tile": {
-     "verdict": "FAIL"
+     "verdict": "EDGES-FAIL",
+     "healed": true
     }
    },
    {
@@ -2133,8 +2134,8 @@
      "acceptable": false
     },
     "tile": {
-     "verdict": "FAIL",
-     "max": null
+     "verdict": "EDGES-FAIL",
+     "healed": true
     },
     "copycheck": "CLEAN"
    },
@@ -2881,7 +2882,7 @@
  },
  {
   "id": "campfire-toile",
-  "title": "Campfire Waltz",
+  "title": "Wilderness Waltz",
   "theme": "modern camping toile de jouy",
   "description": "Camping (theme only)",
   "size": "24\" x 25\"",
diff --git a/output/designs/lagoon-legends-v2-sdxl.png b/output/designs/lagoon-legends-v2-sdxl.png
index 948290b..a7f71cf 100644
Binary files a/output/designs/lagoon-legends-v2-sdxl.png and b/output/designs/lagoon-legends-v2-sdxl.png differ
diff --git a/output/designs/lagoon-legends-v3-sdxl.png b/output/designs/lagoon-legends-v3-sdxl.png
index e1f3af6..8f6e510 100644
Binary files a/output/designs/lagoon-legends-v3-sdxl.png and b/output/designs/lagoon-legends-v3-sdxl.png differ
diff --git a/output/designs/plumbline-v4-nano.png b/output/designs/plumbline-v4-nano.png
index 0af7466..72e7a23 100644
Binary files a/output/designs/plumbline-v4-nano.png and b/output/designs/plumbline-v4-nano.png differ
diff --git a/public/index.html b/public/index.html
index e5d9729..d18ddb2 100644
--- a/public/index.html
+++ b/public/index.html
@@ -52,6 +52,16 @@
   #lightbox { position: fixed; inset: 0; background: #000d; display: none;
               align-items: center; justify-content: center; z-index: 9; cursor: zoom-out; }
   #lightbox img { max-width: 92vw; max-height: 92vh; }
+  #gobar { position: fixed; bottom: 0; left: 0; right: 0; background: #161f1a;
+           border-top: 1px solid #2e4638; padding: 12px 24px; display: flex;
+           align-items: center; gap: 18px; z-index: 8; }
+  #gobar .info { color: #9dc7b0; font-size: 14px; }
+  #gobtn { background: #4caf7d; color: #08130d; border: none; border-radius: 10px;
+           padding: 12px 40px; font-size: 16px; font-weight: 700; letter-spacing: .08em;
+           cursor: pointer; }
+  #gobtn:disabled { background: #2a3a30; color: #567; cursor: not-allowed; }
+  #gomsg { color: #f0c060; font-size: 13px; }
+  body { padding-bottom: 70px; }
 </style>
 </head>
 <body>
@@ -71,6 +81,11 @@
   <label>Density <input type="range" id="density" min="1" max="4" value="3"></label>
 </div>
 <div id="board"></div>
+<div id="gobar">
+  <button id="gobtn" onclick="go()" disabled>GO</button>
+  <span class="info" id="goinfo">Select a version on each design, then hit GO — nothing is saved until you do.</span>
+  <span id="gomsg"></span>
+</div>
 <div id="lightbox" onclick="this.style.display='none'"><img></div>
 <script>
 const fmtDate = iso => new Date(iso).toLocaleString(undefined,
@@ -152,15 +167,41 @@ function zoom(src) {
   lb.style.display = 'flex';
 }
 
-async function choose(id, variant) {
-  await fetch('/api/choose', { method: 'POST', body: JSON.stringify({ id, variant }) });
+// selections stay LOCAL (pending) until GO is pressed
+let pending = JSON.parse(localStorage.getItem('whimsical.pending') || '{}');
+
+function choose(id, variant) {
+  if (pending[id] === variant) delete pending[id];   // click again to unselect
+  else pending[id] = variant;
+  localStorage.setItem('whimsical.pending', JSON.stringify(pending));
   const d = designs.find(x => x.id === id);
-  d.choice = { variant };
+  d.choice = pending[id] ? { variant: pending[id] } : null;
+  updateGo();
   render();
 }
 
+function updateGo() {
+  const n = Object.keys(pending).length;
+  document.getElementById('gobtn').disabled = n === 0;
+  document.getElementById('gobtn').textContent = n ? `GO — save ${n} pick${n>1?'s':''}` : 'GO';
+}
+
+async function go() {
+  const btn = document.getElementById('gobtn');
+  btn.disabled = true;
+  const r = await fetch('/api/choose-batch', { method: 'POST',
+    body: JSON.stringify({ choices: pending }) });
+  const res = await r.json();
+  document.getElementById('gomsg').textContent =
+    res.ok ? `✓ ${res.saved} picks saved ${new Date().toLocaleTimeString()} — Claude takes it from here.` : 'save failed — try again';
+  updateGo();
+  btn.disabled = false;
+}
+
 async function load() {
   designs = await (await fetch('/api/designs')).json();
+  designs.forEach(d => { if (pending[d.id]) d.choice = { variant: pending[d.id] }; });
+  updateGo();
   render();
 }
 sortSel.onchange = render;
diff --git a/server.js b/server.js
index 29e4612..eff506a 100644
--- a/server.js
+++ b/server.js
@@ -33,6 +33,27 @@ const server = http.createServer((req, res) => {
     return res.end(JSON.stringify(designs));
   }
 
+  if (url.pathname === '/api/choose-batch' && req.method === 'POST') {
+    let body = '';
+    req.on('data', c => body += c);
+    req.on('end', () => {
+      try {
+        const { choices } = JSON.parse(body); // { id: variantFileOr'none', ... }
+        const out = {};
+        const now = new Date().toISOString();
+        for (const [id, variant] of Object.entries(choices)) {
+          out[id] = { variant, chosen_at: now };
+        }
+        fs.writeFileSync(CHOICES, JSON.stringify(out, null, 2));
+        res.writeHead(200, { 'Content-Type': 'application/json' });
+        res.end(JSON.stringify({ ok: true, saved: Object.keys(out).length }));
+      } catch (e) {
+        res.writeHead(400); res.end(String(e));
+      }
+    });
+    return;
+  }
+
   if (url.pathname === '/api/choose' && req.method === 'POST') {
     let body = '';
     req.on('data', c => body += c);

← 3dd966b Wilderness Waltz -> Campfire Waltz (no wild-root words)  ·  back to Wild Wallcoverings  ·  auto-save: 2026-07-22T20:16:30 (4 files) — data/designs.json a572e80 →