← back to Wallco Ai
YOLO R5 — surface design's stored dominant_hex vs extracted palette[0] in iso modal. New iso-dominant row above palette block showing canonical DB hex + SW match with closeness chip. Header copy makes the distinction explicit ('stored hex; may differ from extracted' / 'top-6 from image pixels'). renderIsoDominant() gracefully hides when no dominant_hex stored.
a9a18acb9365b44504dbf2babff0dffba56afaaa · 2026-05-12 00:56:23 -0700 · Steve Abrams
Files touched
M YOLO_BACKLOG.mdM server.js
Diff
commit a9a18acb9365b44504dbf2babff0dffba56afaaa
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Tue May 12 00:56:23 2026 -0700
YOLO R5 — surface design's stored dominant_hex vs extracted palette[0] in iso modal. New iso-dominant row above palette block showing canonical DB hex + SW match with closeness chip. Header copy makes the distinction explicit ('stored hex; may differ from extracted' / 'top-6 from image pixels'). renderIsoDominant() gracefully hides when no dominant_hex stored.
---
YOLO_BACKLOG.md | 5 +++--
server.js | 42 +++++++++++++++++++++++++++++++++++++++++-
2 files changed, 44 insertions(+), 3 deletions(-)
diff --git a/YOLO_BACKLOG.md b/YOLO_BACKLOG.md
index fd09c4a..5cc7008 100644
--- a/YOLO_BACKLOG.md
+++ b/YOLO_BACKLOG.md
@@ -30,7 +30,7 @@ User ask verbatim: "show final patterns and 1 room setting on https://wallco.ai/
- [x] **R2 · ΔE closeness bands** — 2026-05-12 00:58 · added `closenessBand(deltaE, kind)` to shared color-isolate.js. Bands: 0-5 exact / 5-15 close / 15-30 approximate / 30+ weak (kind='sw' → "no SW analogue", kind='design' → "different color family"). Wired into `nearestSW` (sw.closeness) + `coordinatingDesigns` (each result.closeness). API `/api/isolate/:id` returns closeness on all 4 surfaces: palette[].sw, dominant_sw, coordinating_hexes[].sw, coordinating_designs[]. Rendered as colored chips on wallco-ai (/designs iso modal) AND thesetdecorator (/best-sellers/:id). +12 unit tests (was 15, now 27 all green). `/age-themes` doesn't use ΔE (uses APCA Lc) so no change there — architect's mention was stale. Cross-project: shared canonical, mirrored to wallco-ai/src + thesetdecorator/lib + _shared.
- [x] **R3 · Adult band diff-chip clarity** — 2026-05-12 00:48 · resolved differently than architect spec'd. Adult band IS visually subtle (only body 13→15 changes) but renders TWO swatches because the body delta is real. Added explicit `diff-bar` chip strip above every band's compare grid showing each changed prop in `key from → to` format (e.g. Adult: "1 change: body 13 → 15"; Teen: "3 changes: font/body/h"). Diff detection auto-derived from `Object.keys(b.best).filter(k => b.current[k] !== b.best[k])` — single source of truth, no hardcoded annotations. Bands with zero diffs (none today) would render "no change recommended" placeholder. Verified live for all 8 bands.
- [x] **R4 · Isolate keyboard shortcuts** — 2026-05-12 00:52 · added scoped keydown handler inside iso-modal (fires only when modal is open). W=wallpaper mode, P=paint mode (both require Isolate button to have been clicked first, else toast nudges user). C=copy primary hex (palette[0].hex via navigator.clipboard with success/fail toast). ? toast shows full shortcut list. Doesn't conflict with global K/R/P card handler because that one early-returns when any modal is open. Verified handler is in served HTML.
-- [ ] **R5 · Isolate modal: source-design SW label** — currently the palette[0] hex shows its SW match, but the design's stored `dominant_hex` (which may differ from extraction) isn't labeled. Show both: "Design's `dominant_hex` = X (SW Y)" + "Extracted palette[0] = Z (SW W)".
+- [x] **R5 · Isolate modal: source-design SW label** — 2026-05-12 01:02 · added new `iso-dominant` row ABOVE the extracted palette block. Shows the design's stored `dominant_hex` (canonical, persisted in DB) with its full SW match {code, name, ΔE, closeness chip}. Header copy makes the distinction explicit: "Design's dominant color (stored hex; may differ from extracted)" vs "Extracted palette (top-6 from image pixels)". `renderIsoDominant()` hides the row when design has no stored dominant_hex; shows "no SW match available" when SW DB empty. Verified live.
### Visual polish
@@ -71,4 +71,5 @@ TICK · TIMESTAMP · ITEM · STATUS · COMMIT
- T9 · 2026-05-12 00:42 · R9 AI-language scrub · done · 9 public surfaces · admin banner kept per validation-loop · 9faa35b
- T10 · 2026-05-12 00:48 · R3 Adult diff-chip · done · auto-detect changed props per band, render diff-bar above compare grid · 04c43b4
- T11 · 2026-05-12 00:52 · R4 isolate W/P/C shortcuts · done · scoped keydown handler, toast feedback, clipboard for primary hex · b204703
-- T12 · 2026-05-12 00:58 · R2 ΔE closeness bands · done · 4 bands · 4 surfaces in API · chips on both wallco + tsd · 12 new unit tests
+- T12 · 2026-05-12 00:58 · R2 ΔE closeness bands · done · 4 bands · 4 surfaces in API · chips on both wallco + tsd · 12 new unit tests · 8c653d7 + ef39b82 + 035592b
+- T13 · 2026-05-12 01:02 · R5 source-design SW row · done · new "Design's dominant color" block above palette · stored hex vs extracted distinction explicit
diff --git a/server.js b/server.js
index 44be79a..657143f 100644
--- a/server.js
+++ b/server.js
@@ -1315,6 +1315,14 @@ ${_isAdmin ? `
.iso-sw .sw-code { font-size:10px; color:#d2b15c; text-align:center; letter-spacing:.04em; }
.iso-sw .sw-name { font-size:10px; color:#888; text-align:center; line-height:1.2; }
.iso-sw .sw-empty { font-size:10px; color:#555; text-align:center; font-style:italic; }
+ .iso-dominant-row { margin-bottom:14px; padding-bottom:14px; border-bottom:1px dashed #2a2825; }
+ .iso-dominant-card { display:flex; align-items:center; gap:14px; padding:10px 14px; background:#1a1816; border:1px solid #2a2825; border-radius:3px; }
+ .iso-dominant-card .dot { width:46px; height:46px; border-radius:3px; border:1px solid rgba(255,255,255,.15); flex-shrink:0; }
+ .iso-dominant-card .info { flex:1; min-width:0; }
+ .iso-dominant-card .info .hex { font:13px/1.2 ui-monospace, Menlo, monospace; color:#e8e2d6; letter-spacing:.02em; }
+ .iso-dominant-card .info .sw { font:11px/1.3 -apple-system, system-ui, sans-serif; color:#d2b15c; margin-top:3px; }
+ .iso-dominant-card .info .sw .sw-name { color:#bba; }
+ .iso-dominant-card .info .nosw { font-size:11px; color:#666; font-style:italic; }
.iso-sw .sw-closeness { display:inline-block; margin-top:4px; padding:1px 6px; border-radius:8px; font:9px/1.2 ui-monospace, Menlo, monospace; text-transform:uppercase; letter-spacing:.05em; }
.sw-close-exact { background:#1f3a1f; color:#5fbf6e; }
.sw-close-close { background:#1f2f3a; color:#5fa8bf; }
@@ -1391,8 +1399,12 @@ ${_isAdmin ? `
</header>
<div id="iso-body">
<div id="iso-hero"></div>
+ <div id="iso-dominant" class="iso-dominant-row" style="display:none">
+ <h4 style="font-size:11px;color:#d2b15c;letter-spacing:.08em;text-transform:uppercase;margin:0 0 8px">Design's dominant color <span style="color:#666;font-weight:normal;text-transform:none;letter-spacing:0">(stored hex; may differ from extracted)</span></h4>
+ <div class="iso-dominant-card" id="iso-dominant-card"></div>
+ </div>
<div>
- <h4 style="font-size:11px;color:#d2b15c;letter-spacing:.08em;text-transform:uppercase;margin:0 0 8px">Palette</h4>
+ <h4 style="font-size:11px;color:#d2b15c;letter-spacing:.08em;text-transform:uppercase;margin:0 0 8px">Extracted palette <span style="color:#666;font-weight:normal;text-transform:none;letter-spacing:0">(top-6 from image pixels)</span></h4>
<div class="iso-palette" id="iso-palette"><div class="iso-loading">extracting…</div></div>
</div>
<div class="iso-action">
@@ -1805,6 +1817,8 @@ ${_isAdmin ? `
const hero = $('#iso-hero');
hero.style.backgroundImage = imageUrl ? "url('" + imageUrl + "')" : 'none';
$('#iso-palette').innerHTML = '<div class="iso-loading">extracting palette…</div>';
+ $('#iso-dominant').style.display = 'none';
+ $('#iso-dominant-card').innerHTML = '';
$('#iso-grid-wallpaper').innerHTML = '<div class="iso-loading">loading…</div>';
$('#iso-grid-paint').innerHTML = '';
$('#iso-mode-toggle').classList.remove('visible');
@@ -1822,12 +1836,38 @@ ${_isAdmin ? `
}
const data = await r.json();
CURRENT_ISO_DATA = data;
+ renderIsoDominant(data.design, data.dominant_sw);
renderIsoPalette(data.palette || []);
} catch (e) {
$('#iso-palette').innerHTML = '<div class="iso-loading">error: ' + escapeHTML(e.message) + '</div>';
}
}
+ // R5 — render the design's STORED dominant hex (canonical, persisted in DB)
+ // alongside its nearest SW. Sits ABOVE the extracted-palette block so the user
+ // sees the source-of-truth color and how it compares to what extractPalette found.
+ function renderIsoDominant(design, dominantSW) {
+ const card = $('#iso-dominant-card');
+ if (!design || !design.dominant_hex) {
+ $('#iso-dominant').style.display = 'none';
+ return;
+ }
+ const hex = design.dominant_hex;
+ const closenessChip = (dominantSW && dominantSW.closeness)
+ ? ' <span class="sw-closeness sw-close-' + dominantSW.closeness.band + '" title="' + escapeAttr(dominantSW.closeness.note) + '">' + dominantSW.closeness.band + '</span>'
+ : '';
+ const swInfo = dominantSW
+ ? '<div class="sw"><strong>' + escapeHTML(dominantSW.code) + '</strong> <span class="sw-name">' + escapeHTML(dominantSW.name) + '</span> · ΔE ' + dominantSW.deltaE + closenessChip + '</div>'
+ : '<div class="nosw">no Sherwin-Williams match available</div>';
+ card.innerHTML =
+ '<div class="dot" style="background:' + escapeAttr(hex) + '"></div>' +
+ '<div class="info">' +
+ '<div class="hex">' + escapeHTML(hex) + '</div>' +
+ swInfo +
+ '</div>';
+ $('#iso-dominant').style.display = 'block';
+ }
+
function renderIsoPalette(palette) {
if (!palette || !palette.length) {
$('#iso-palette').innerHTML = '<div class="iso-loading">no palette extracted</div>';
← 957e20b YOLO R2 — ΔE closeness bands in src/color-isolate. closeness
·
back to Wallco Ai
·
YOLO R7 — promote why-chip from subtle pill to prominent cur 3b36790 →