← back to Wallco Ai
ui: surface ALL styles + populated color dots on /designs grid — drop motif slice(0,12), expand hue palette from 10 to 32 named buckets with finer hue ranges + lightness subtypes (blush/coral/butter/lime/sky/lavender/burgundy/terracotta/chocolate/cream/linen/ivory/stone/charcoal/ink/black/white)
9cf8d04a78eeaf2716c61c816a6c31596d58b87d · 2026-05-20 10:25:21 -0700 · Steve Abrams
Files touched
Diff
commit 9cf8d04a78eeaf2716c61c816a6c31596d58b87d
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Wed May 20 10:25:21 2026 -0700
ui: surface ALL styles + populated color dots on /designs grid — drop motif slice(0,12), expand hue palette from 10 to 32 named buckets with finer hue ranges + lightness subtypes (blush/coral/butter/lime/sky/lavender/burgundy/terracotta/chocolate/cream/linen/ivory/stone/charcoal/ink/black/white)
---
server.js | 62 +++++++++++++++++++++++++++++++++++++++++++-------------------
1 file changed, 43 insertions(+), 19 deletions(-)
diff --git a/server.js b/server.js
index a54db42..f39ba5a 100644
--- a/server.js
+++ b/server.js
@@ -3512,24 +3512,40 @@ app.get('/designs', (req, res) => {
if (!hex || !/^#[0-9a-fA-F]{6}$/.test(hex)) return null;
const r = parseInt(hex.slice(1,3),16)/255, g = parseInt(hex.slice(3,5),16)/255, b = parseInt(hex.slice(5,7),16)/255;
const max = Math.max(r,g,b), min = Math.min(r,g,b);
- if (max === min) return 'neutral';
+ const l = (max + min) / 2;
+ const s = max === min ? 0 : (max - min) / (l > 0.5 ? 2 - max - min : max + min);
+ // ── achromatic / near-neutral first, by lightness ────────────────────
+ if (s < 0.12) {
+ if (l < 0.08) return 'black';
+ if (l < 0.18) return 'ink';
+ if (l < 0.32) return 'charcoal';
+ if (l < 0.50) return 'stone';
+ if (l < 0.72) return 'neutral';
+ if (l < 0.86) return 'linen';
+ if (l < 0.94) return 'cream';
+ return 'white';
+ }
+ // ── chromatic — finer hue ranges + lightness-based subtypes ──────────
let h = 0; const d = max - min;
if (max === r) h = (g-b)/d + (g<b?6:0);
else if (max === g) h = (b-r)/d + 2;
else h = (r-g)/d + 4;
h = (h * 60 + 360) % 360;
- const l = (max + min) / 2;
- const s = (max - min) / (l > 0.5 ? 2 - max - min : max + min);
- if (s < 0.1) return 'neutral';
- if (h < 15 || h >= 345) return 'rose';
- if (h < 40) return 'amber';
- if (h < 60) return 'honey';
- if (h < 90) return 'olive';
- if (h < 160) return 'sage';
- if (h < 200) return 'marine';
- if (h < 250) return 'sapphire';
- if (h < 290) return 'mauve';
- return 'plum';
+ if (h < 12 || h >= 350) return l > 0.65 ? 'blush' : (l < 0.30 ? 'burgundy' : 'rose');
+ if (h < 22) return l < 0.30 ? 'chocolate' : (l > 0.65 ? 'coral' : 'terracotta');
+ if (h < 38) return l > 0.70 ? 'butter' : 'amber';
+ if (h < 50) return l > 0.70 ? 'butter' : (l < 0.40 ? 'chocolate' : 'honey');
+ if (h < 62) return l > 0.70 ? 'butter' : (l < 0.40 ? 'olive' : 'gold');
+ if (h < 80) return l > 0.70 ? 'lime' : 'olive';
+ if (h < 130) return l > 0.70 ? 'lime' : (l < 0.35 ? 'olive' : 'sage');
+ if (h < 160) return l < 0.35 ? 'emerald' : 'sage';
+ if (h < 180) return 'teal';
+ if (h < 205) return l > 0.65 ? 'sky' : 'marine';
+ if (h < 230) return l > 0.65 ? 'sky' : 'sapphire';
+ if (h < 260) return l < 0.35 ? 'indigo' : 'sapphire';
+ if (h < 285) return l > 0.70 ? 'lavender' : 'mauve';
+ if (h < 320) return l > 0.65 ? 'lavender' : (l < 0.35 ? 'plum' : 'plum');
+ return l > 0.55 ? 'magenta' : 'burgundy';
}
// Hard filter — never render a card whose image file isn't on disk OR whose
// id is in the blank-guard. /api/designs already does this; mirror it on the
@@ -3586,16 +3602,24 @@ app.get('/designs', (req, res) => {
.filter(c => c && !VENDOR_DENYLIST.test(c))
.sort();
- // Top motifs across full catalog (not filtered)
+ // ALL motifs/styles across full catalog (was limited to 12 — show every style with ≥1 design)
const motifCounts = {};
DESIGNS.forEach(d => (d.motifs || []).forEach(m => { motifCounts[m] = (motifCounts[m]||0) + 1; }));
- const topMotifs = Object.entries(motifCounts).sort((a,b)=>b[1]-a[1]).slice(0,12);
+ const topMotifs = Object.entries(motifCounts).sort((a,b)=>b[1]-a[1]); // no slice — show all
+ // Populated hue palette — every named hue bucket gets a dot (was 10, now full spectrum)
const HUE_DEFS = [
- ['rose', '#e08291'], ['amber', '#c97b3a'], ['honey', '#d2a44a'],
- ['olive', '#8a8c4a'], ['sage', '#8aa17a'], ['marine', '#6aa6b6'],
- ['sapphire', '#5a82a8'], ['mauve', '#a08bbf'], ['plum', '#8e5887'],
- ['neutral', '#b8b3a8']
+ ['rose', '#e08291'], ['blush', '#e8b5b8'], ['coral', '#e6856b'],
+ ['amber', '#c97b3a'], ['honey', '#d2a44a'], ['gold', '#caa75a'],
+ ['butter', '#e8d585'], ['olive', '#8a8c4a'], ['lime', '#a8c45a'],
+ ['sage', '#8aa17a'], ['emerald', '#3a8a5a'], ['teal', '#4a8a8a'],
+ ['marine', '#6aa6b6'], ['sky', '#7ab8d8'], ['sapphire', '#5a82a8'],
+ ['indigo', '#4a4a8a'], ['mauve', '#a08bbf'], ['lavender', '#c8bce0'],
+ ['plum', '#8e5887'], ['magenta', '#b04a7a'], ['burgundy', '#7a2838'],
+ ['terracotta','#a85a3a'], ['chocolate', '#5a3826'], ['cream', '#ede6d0'],
+ ['linen', '#dccfb6'], ['ivory', '#f0e8d8'], ['neutral', '#b8b3a8'],
+ ['stone', '#8a847a'], ['charcoal', '#3a3a3a'], ['ink', '#1a1816'],
+ ['white', '#f8f6f0'], ['black', '#0a0808']
];
const hueCounts = {};
DESIGNS.forEach(d => { const b = hueBucketOf(d.dominant_hex); if (b) hueCounts[b] = (hueCounts[b]||0)+1; });
← b4ba6e1 rename: Magic → Curated across all customer-facing copy on w
·
back to Wallco Ai
·
wallco mural: viewport 20:11 + cover-fit init at zoom 1 615bf37 →