← back to Wallco Ai
pairings: Dunn-Edwards + Sherwin-Williams paint chip suggestions
e54cb626af7220d5d6ad5d1a080dc1177d9deb0f · 2026-05-13 08:27:51 -0700 · SteveStudio2
Adds 'paint' suggestion type to the per-design pairing panel. For every
design's dominant_hex, finds the 2 closest Dunn-Edwards chips + 2 closest
Sherwin-Williams chips by HSL distance — paintable wall behind the
wallcovering, or trim/ceiling pickup.
- data/paint_chips.json: curated ~110 popular chips with public hex codes
(DE Whisper / Swiss Coffee / Antique Brass / Plunge Pool / Bison Beige
/ Heliotrope...; SW Alabaster / Agreeable Gray / Tricorn Black / Naval
/ Real Red / Hidden Garden / Garden Spot...). Source: dunnedwards.com
+ sherwin-williams.com public color libraries. Expand over time.
- src/review.js: paintChipMatches(hex) + cache loader; wired into
generatePairings() between colorSwatches() and materialSuggestions().
pinKey('paint') = p:brand:code so moodboard pins persist.
- server.js render: new pair-card variant 'paint-card' with brand-coded
left stripe (DE red, SW navy), chip code badge bottom-left of thumb.
Mini fan-deck aesthetic.
Cache busted (pairings.json -> {}) so all designs regenerate with paint
chips on next /api/pairings/:id hit.
Smoke-tested design 2681 (#413b31): DE Ottertail #3e342a + DE Bison
Beige + SW Iron Ore + SW Virtual Taupe — close on the dominant, with
2 brand-name trim options at higher saturation.
Files touched
A data/paint_chips.jsonM server.jsM src/review.js
Diff
commit e54cb626af7220d5d6ad5d1a080dc1177d9deb0f
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date: Wed May 13 08:27:51 2026 -0700
pairings: Dunn-Edwards + Sherwin-Williams paint chip suggestions
Adds 'paint' suggestion type to the per-design pairing panel. For every
design's dominant_hex, finds the 2 closest Dunn-Edwards chips + 2 closest
Sherwin-Williams chips by HSL distance — paintable wall behind the
wallcovering, or trim/ceiling pickup.
- data/paint_chips.json: curated ~110 popular chips with public hex codes
(DE Whisper / Swiss Coffee / Antique Brass / Plunge Pool / Bison Beige
/ Heliotrope...; SW Alabaster / Agreeable Gray / Tricorn Black / Naval
/ Real Red / Hidden Garden / Garden Spot...). Source: dunnedwards.com
+ sherwin-williams.com public color libraries. Expand over time.
- src/review.js: paintChipMatches(hex) + cache loader; wired into
generatePairings() between colorSwatches() and materialSuggestions().
pinKey('paint') = p:brand:code so moodboard pins persist.
- server.js render: new pair-card variant 'paint-card' with brand-coded
left stripe (DE red, SW navy), chip code badge bottom-left of thumb.
Mini fan-deck aesthetic.
Cache busted (pairings.json -> {}) so all designs regenerate with paint
chips on next /api/pairings/:id hit.
Smoke-tested design 2681 (#413b31): DE Ottertail #3e342a + DE Bison
Beige + SW Iron Ore + SW Virtual Taupe — close on the dominant, with
2 brand-name trim options at higher saturation.
---
data/paint_chips.json | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++
server.js | 18 +++++++
src/review.js | 50 +++++++++++++++++--
3 files changed, 195 insertions(+), 3 deletions(-)
diff --git a/data/paint_chips.json b/data/paint_chips.json
new file mode 100644
index 0000000..f49a4b7
--- /dev/null
+++ b/data/paint_chips.json
@@ -0,0 +1,130 @@
+{
+ "note": "Curated popular Dunn-Edwards + Sherwin-Williams paint colors with public hex codes. Used by /design/:id pairing panel to surface nearest paint chips to a design's dominant_hex. Expand over time.",
+ "sources": ["dunnedwards.com color collection", "sherwin-williams.com color library"],
+ "colors": [
+ { "brand": "Dunn-Edwards", "code": "DEW380", "name": "Whisper", "hex": "#f4ecdf" },
+ { "brand": "Dunn-Edwards", "code": "DEW340", "name": "Swiss Coffee", "hex": "#efeae0" },
+ { "brand": "Dunn-Edwards", "code": "DEW341", "name": "White Sand", "hex": "#f0e8d6" },
+ { "brand": "Dunn-Edwards", "code": "DEW360", "name": "Cool December", "hex": "#e8e6dd" },
+ { "brand": "Dunn-Edwards", "code": "DET625", "name": "Pebbled Path", "hex": "#cfc3a8" },
+ { "brand": "Dunn-Edwards", "code": "DEC793", "name": "Birch Bark", "hex": "#d9cdb6" },
+ { "brand": "Dunn-Edwards", "code": "DET668", "name": "Antique Brass", "hex": "#b69a64" },
+ { "brand": "Dunn-Edwards", "code": "DET636", "name": "Toasted Almond", "hex": "#b08d65" },
+ { "brand": "Dunn-Edwards", "code": "DEC761", "name": "Sand Trail", "hex": "#bca57f" },
+ { "brand": "Dunn-Edwards", "code": "DE6121","name": "Soft Pumice", "hex": "#8a8475" },
+ { "brand": "Dunn-Edwards", "code": "DE6391","name": "Bullion Bag", "hex": "#867159" },
+ { "brand": "Dunn-Edwards", "code": "DE6118","name": "Bison Beige", "hex": "#8b7a5e" },
+ { "brand": "Dunn-Edwards", "code": "DE6076","name": "Bonsai Trunk", "hex": "#594433" },
+ { "brand": "Dunn-Edwards", "code": "DEC783", "name": "Ottertail", "hex": "#3e342a" },
+ { "brand": "Dunn-Edwards", "code": "DE6386","name": "Black Bean", "hex": "#262321" },
+
+ { "brand": "Dunn-Edwards", "code": "DET694", "name": "Tea Bag", "hex": "#8c5c40" },
+ { "brand": "Dunn-Edwards", "code": "DET684", "name": "Ground Sienna", "hex": "#a55a3f" },
+ { "brand": "Dunn-Edwards", "code": "DE5125","name": "Spiced Cider", "hex": "#a8533b" },
+ { "brand": "Dunn-Edwards", "code": "DE5081","name": "Red Gerbera", "hex": "#b73a35" },
+ { "brand": "Dunn-Edwards", "code": "DEA138","name": "Anjou Pear", "hex": "#b6a458" },
+ { "brand": "Dunn-Edwards", "code": "DET498", "name": "Bistro Olive", "hex": "#7b6b3a" },
+ { "brand": "Dunn-Edwards", "code": "DE5559","name": "Caper Berry", "hex": "#5d6939" },
+ { "brand": "Dunn-Edwards", "code": "DET504", "name": "Tatami Mat", "hex": "#b9a36a" },
+ { "brand": "Dunn-Edwards", "code": "DEA177","name": "Treasure Trove", "hex": "#d6b569" },
+
+ { "brand": "Dunn-Edwards", "code": "DE5566","name": "Sage Tea", "hex": "#8d9b80" },
+ { "brand": "Dunn-Edwards", "code": "DET515", "name": "Coastal Trail", "hex": "#7e8a6e" },
+ { "brand": "Dunn-Edwards", "code": "DE5621","name": "Aphid Green", "hex": "#a3ad7d" },
+ { "brand": "Dunn-Edwards", "code": "DE5728","name": "Mountain Range", "hex": "#5f6e5e" },
+ { "brand": "Dunn-Edwards", "code": "DE5740","name": "Hidden Forest", "hex": "#465040" },
+ { "brand": "Dunn-Edwards", "code": "DE5635","name": "Dill Seed", "hex": "#a7a567" },
+ { "brand": "Dunn-Edwards", "code": "DET543", "name": "Hidden Meadow", "hex": "#6c8568" },
+
+ { "brand": "Dunn-Edwards", "code": "DE5759","name": "Spruced Up", "hex": "#4d6c63" },
+ { "brand": "Dunn-Edwards", "code": "DE5770","name": "Plunge Pool", "hex": "#2c5a5d" },
+ { "brand": "Dunn-Edwards", "code": "DET561", "name": "Open Seas", "hex": "#4b6f7a" },
+ { "brand": "Dunn-Edwards", "code": "DE5818","name": "Splashy", "hex": "#5e7a8e" },
+ { "brand": "Dunn-Edwards", "code": "DET587", "name": "Watery", "hex": "#a0bcc7" },
+ { "brand": "Dunn-Edwards", "code": "DET602", "name": "Blue Caspian", "hex": "#365e7a" },
+ { "brand": "Dunn-Edwards", "code": "DEC798", "name": "Below Zero", "hex": "#c4d5d8" },
+ { "brand": "Dunn-Edwards", "code": "DEA170","name": "Tropical Skies", "hex": "#3a8aa8" },
+
+ { "brand": "Dunn-Edwards", "code": "DE5921","name": "Deep River", "hex": "#283a55" },
+ { "brand": "Dunn-Edwards", "code": "DE5871","name": "Egyptian Nile", "hex": "#2c557a" },
+ { "brand": "Dunn-Edwards", "code": "DE5897","name": "Royal Navy", "hex": "#2c3a5e" },
+ { "brand": "Dunn-Edwards", "code": "DE5908","name": "Twilight Zone", "hex": "#16203a" },
+
+ { "brand": "Dunn-Edwards", "code": "DET582", "name": "Lavender Beads", "hex": "#9b8db2" },
+ { "brand": "Dunn-Edwards", "code": "DEA135","name": "Hippie Pink", "hex": "#c25b86" },
+ { "brand": "Dunn-Edwards", "code": "DE5044","name": "Roman Plaster", "hex": "#e9c0a8" },
+ { "brand": "Dunn-Edwards", "code": "DE5005","name": "Just Peachy", "hex": "#e69d8a" },
+ { "brand": "Dunn-Edwards", "code": "DEA122","name": "Burnt Sienna", "hex": "#9c4b2b" },
+ { "brand": "Dunn-Edwards", "code": "DE5012","name": "Apple Wine", "hex": "#8a3a45" },
+ { "brand": "Dunn-Edwards", "code": "DE6041","name": "Heliotrope", "hex": "#604168" },
+
+ { "brand": "Dunn-Edwards", "code": "DEW398", "name": "Beach House", "hex": "#e2dad0" },
+ { "brand": "Dunn-Edwards", "code": "DEC754", "name": "Greta Garbo", "hex": "#cbc4b5" },
+ { "brand": "Dunn-Edwards", "code": "DEC756", "name": "Hopsack", "hex": "#b6ad95" },
+
+ { "brand": "Sherwin-Williams", "code": "SW7008", "name": "Alabaster", "hex": "#ede9df" },
+ { "brand": "Sherwin-Williams", "code": "SW7005", "name": "Pure White", "hex": "#edece4" },
+ { "brand": "Sherwin-Williams", "code": "SW7551", "name": "Greek Villa", "hex": "#e9e0ce" },
+ { "brand": "Sherwin-Williams", "code": "SW7012", "name": "Creamy", "hex": "#ecdfca" },
+ { "brand": "Sherwin-Williams", "code": "SW6385", "name": "Dover White", "hex": "#ece1c6" },
+ { "brand": "Sherwin-Williams", "code": "SW7036", "name": "Accessible Beige", "hex": "#cdc1ab" },
+ { "brand": "Sherwin-Williams", "code": "SW7044", "name": "Amazing Gray", "hex": "#aaa194" },
+ { "brand": "Sherwin-Williams", "code": "SW7029", "name": "Agreeable Gray", "hex": "#d0c8b8" },
+ { "brand": "Sherwin-Williams", "code": "SW7039", "name": "Virtual Taupe", "hex": "#8b7c69" },
+ { "brand": "Sherwin-Williams", "code": "SW7641", "name": "Collonade Gray", "hex": "#bcb3a3" },
+ { "brand": "Sherwin-Williams", "code": "SW7016", "name": "Mindful Gray", "hex": "#a59e91" },
+ { "brand": "Sherwin-Williams", "code": "SW7018", "name": "Dovetail", "hex": "#71696a" },
+ { "brand": "Sherwin-Williams", "code": "SW7068", "name": "Grizzle Gray", "hex": "#666260" },
+ { "brand": "Sherwin-Williams", "code": "SW7069", "name": "Iron Ore", "hex": "#4a4845" },
+ { "brand": "Sherwin-Williams", "code": "SW6258", "name": "Tricorn Black", "hex": "#22201f" },
+
+ { "brand": "Sherwin-Williams", "code": "SW6093", "name": "Familiar Beige", "hex": "#c4a78a" },
+ { "brand": "Sherwin-Williams", "code": "SW6118", "name": "Leather Bound", "hex": "#6e503c" },
+ { "brand": "Sherwin-Williams", "code": "SW6041", "name": "Otter", "hex": "#594538" },
+ { "brand": "Sherwin-Williams", "code": "SW6048", "name": "Terra Brun", "hex": "#3a2a23" },
+ { "brand": "Sherwin-Williams", "code": "SW6328", "name": "Fireweed", "hex": "#a3422e" },
+ { "brand": "Sherwin-Williams", "code": "SW6332", "name": "Coral Reef", "hex": "#d97a5e" },
+ { "brand": "Sherwin-Williams", "code": "SW6868", "name": "Real Red", "hex": "#bc2c2f" },
+ { "brand": "Sherwin-Williams", "code": "SW7589", "name": "Habanero Chile", "hex": "#7e2e26" },
+
+ { "brand": "Sherwin-Williams", "code": "SW6406", "name": "Honey Bees", "hex": "#e6c465" },
+ { "brand": "Sherwin-Williams", "code": "SW6398", "name": "Lemon Twist", "hex": "#f0c93e" },
+ { "brand": "Sherwin-Williams", "code": "SW6385", "name": "Dover White", "hex": "#ece1c6" },
+ { "brand": "Sherwin-Williams", "code": "SW6128", "name": "Blonde", "hex": "#e6d3a9" },
+
+ { "brand": "Sherwin-Williams", "code": "SW6206", "name": "Oyster Bay", "hex": "#8aa087" },
+ { "brand": "Sherwin-Williams", "code": "SW6184", "name": "Austere Gray", "hex": "#a8a695" },
+ { "brand": "Sherwin-Williams", "code": "SW6438", "name": "Garden Gate", "hex": "#506b46" },
+ { "brand": "Sherwin-Williams", "code": "SW6432", "name": "Garden Spot", "hex": "#5d7a4e" },
+ { "brand": "Sherwin-Williams", "code": "SW6453", "name": "Argyle", "hex": "#3a4e3e" },
+ { "brand": "Sherwin-Williams", "code": "SW6177", "name": "Softened Green", "hex": "#9aa78d" },
+ { "brand": "Sherwin-Williams", "code": "SW6189", "name": "Opaline", "hex": "#a9b5a1" },
+ { "brand": "Sherwin-Williams", "code": "SW6451", "name": "Hidden Garden", "hex": "#86997a" },
+ { "brand": "Sherwin-Williams", "code": "SW6452", "name": "Inland", "hex": "#577557" },
+ { "brand": "Sherwin-Williams", "code": "SW7741", "name": "Willow Tree", "hex": "#9da280" },
+
+ { "brand": "Sherwin-Williams", "code": "SW6231", "name": "Rock Candy", "hex": "#cad9d8" },
+ { "brand": "Sherwin-Williams", "code": "SW7621", "name": "Silvermist", "hex": "#a5b7b7" },
+ { "brand": "Sherwin-Williams", "code": "SW9135", "name": "Niebla Azul", "hex": "#7e94a0" },
+ { "brand": "Sherwin-Williams", "code": "SW6230", "name": "Rainwashed", "hex": "#a7c1c4" },
+ { "brand": "Sherwin-Williams", "code": "SW6225", "name": "Sleepy Blue", "hex": "#a3c0c4" },
+ { "brand": "Sherwin-Williams", "code": "SW6244", "name": "Naval", "hex": "#2c3e4e" },
+ { "brand": "Sherwin-Williams", "code": "SW6243", "name": "Distance", "hex": "#3a5066" },
+ { "brand": "Sherwin-Williams", "code": "SW6250", "name": "Granite Peak", "hex": "#56676d" },
+
+ { "brand": "Sherwin-Williams", "code": "SW6961", "name": "Indulgent", "hex": "#1f2c4a" },
+ { "brand": "Sherwin-Williams", "code": "SW6962", "name": "Hyper Blue", "hex": "#1d3b6e" },
+ { "brand": "Sherwin-Williams", "code": "SW6258", "name": "Tricorn Black", "hex": "#22201f" },
+
+ { "brand": "Sherwin-Williams", "code": "SW6296", "name": "Plumage", "hex": "#634a6e" },
+ { "brand": "Sherwin-Williams", "code": "SW6286", "name": "Mature Grape", "hex": "#4f3d56" },
+ { "brand": "Sherwin-Williams", "code": "SW6555", "name": "Loyal Blue", "hex": "#2a4a7e" },
+ { "brand": "Sherwin-Williams", "code": "SW6840", "name": "Exuberant Pink", "hex": "#cd397b" },
+ { "brand": "Sherwin-Williams", "code": "SW6606", "name": "Begonia", "hex": "#e57e7f" },
+ { "brand": "Sherwin-Williams", "code": "SW6346", "name": "Sockeye", "hex": "#d36043" },
+ { "brand": "Sherwin-Williams", "code": "SW6604", "name": "Youthful Coral", "hex": "#ec8b86" },
+ { "brand": "Sherwin-Williams", "code": "SW6063", "name": "Quartzite", "hex": "#aa8270" },
+ { "brand": "Sherwin-Williams", "code": "SW9176", "name": "Iron Mountain", "hex": "#564f4d" },
+ { "brand": "Sherwin-Williams", "code": "SW7607", "name": "Rosy Outlook", "hex": "#e1a89b" }
+ ]
+}
diff --git a/server.js b/server.js
index f96bd08..4e3e532 100644
--- a/server.js
+++ b/server.js
@@ -3129,6 +3129,12 @@ ${_isAdmin ? `
.pair-card .pair-pin:hover { color:#d2b15c; border-color:#d2b15c; }
.pair-card.pinned { border-color:var(--chip-hot); background:#1f1b13; }
.pair-card.pinned .pair-pin { color:#d2b15c; background:#d2b15c33; border-color:#d2b15c; }
+ /* Paint-chip variant — left thumb shows the chip color with brand code laid */
+ /* on top in mini-fan-deck style. Brand stripe accents on the left edge. */
+ .pair-card.paint-card .paint-thumb { position:relative; box-shadow: inset 0 0 0 1px rgba(0,0,0,.18); }
+ .pair-card.paint-card .paint-code { position:absolute; left:4px; bottom:3px; font-family:ui-monospace,monospace; font-size:9px; padding:1px 4px; background:rgba(0,0,0,.55); color:#fff; border-radius:2px; letter-spacing:.04em; }
+ .pair-card.paint-card.paint-de { border-left:3px solid #c84a3a; }
+ .pair-card.paint-card.paint-sw { border-left:3px solid #1a4f9c; }
.pair-card .pair-vision-badge { display:inline-block; font-size:9px; padding:0 5px; border:1px solid #3a3631; border-radius:2px; color:#888; margin-left:6px; text-transform:uppercase; letter-spacing:.05em; }
#pair-vision-read { background:#1a1816; padding:8px 12px; margin:0 18px 8px; border:1px solid #2a2825; border-radius:2px; font-size:11px; color:#bba; line-height:1.45; font-style:italic; }
#pair-vision-read.hidden { display:none; }
@@ -3563,6 +3569,18 @@ ${_isAdmin ? `
'<div class="pair-title">' + escapeHTML(s.label) + '</div>' +
'<div class="pair-reason">' + escapeHTML(s.reason) + '</div></div>' + pinBtn + '</div>';
}
+ if (s.type === 'paint') {
+ // Paint chip — left half is the chip color block with the brand-style
+ // label tucked underneath. Lets the room be specified end-to-end
+ // (wallcovering + matching wall paint).
+ const brandClass = (s.brand || '').toLowerCase().includes('dunn') ? 'paint-de' : 'paint-sw';
+ return '<div class="pair-card paint-card ' + brandClass + pinned + '" data-pin-key="' + escapeAttr(s.pin_key) + '">' +
+ '<div class="pair-thumb paint-thumb" style="background:' + (s.hex||'#888') + '">' +
+ '<span class="paint-code">' + escapeHTML(s.code||'') + '</span></div>' +
+ '<div class="pair-body"><span class="pair-type">paint · ' + escapeHTML(s.brand||'') + '</span>' +
+ '<div class="pair-title">' + escapeHTML(s.name||'') + '<span class="pair-hexcode">'+escapeHTML(s.hex||'')+'</span></div>' +
+ '<div class="pair-reason">' + escapeHTML(s.reason||'') + '</div></div>' + pinBtn + '</div>';
+ }
// material / object
return '<div class="pair-card' + pinned + '" data-pin-key="' + escapeAttr(s.pin_key) + '">' +
'<div class="pair-thumb material">' + (s.icon || '✦') + '</div>' +
diff --git a/src/review.js b/src/review.js
index 1cd7a4a..e944a11 100644
--- a/src/review.js
+++ b/src/review.js
@@ -252,6 +252,48 @@ function catalogMatches(design, designs) {
return out;
}
+// paint chip matches — nearest 2 Dunn-Edwards + nearest 2 Sherwin-Williams
+// from data/paint_chips.json, ranked by HSL distance. Surfaces brand-name
+// paint chips as part of the pairing panel so the room can be specified
+// end-to-end: wallcovering + matching wall paint.
+let _PAINT_CHIPS_CACHE = null;
+function loadPaintChips() {
+ if (_PAINT_CHIPS_CACHE) return _PAINT_CHIPS_CACHE;
+ try {
+ const file = path.join(__dirname, '..', 'data', 'paint_chips.json');
+ _PAINT_CHIPS_CACHE = JSON.parse(fs.readFileSync(file, 'utf8')).colors || [];
+ } catch { _PAINT_CHIPS_CACHE = []; }
+ return _PAINT_CHIPS_CACHE;
+}
+function paintChipMatches(hex) {
+ if (!hex) return [];
+ const chips = loadPaintChips();
+ if (!chips.length) return [];
+ const ranked = chips
+ .map(c => ({ ...c, _d: hexDistance(c.hex, hex) }))
+ .sort((a, b) => a._d - b._d);
+ const top = { 'Dunn-Edwards': [], 'Sherwin-Williams': [] };
+ for (const r of ranked) {
+ if (top[r.brand] && top[r.brand].length < 2) top[r.brand].push(r);
+ if (top['Dunn-Edwards'].length === 2 && top['Sherwin-Williams'].length === 2) break;
+ }
+ const out = [];
+ for (const brand of ['Dunn-Edwards', 'Sherwin-Williams']) {
+ for (const c of top[brand] || []) {
+ out.push({
+ type: 'paint',
+ brand: c.brand,
+ code: c.code,
+ name: c.name,
+ hex: c.hex,
+ label: `${c.brand} ${c.code} · ${c.name}`,
+ reason: `Nearest ${c.brand} chip — paintable wall behind the wallcovering, or trim/ceiling pickup`,
+ });
+ }
+ }
+ return out;
+}
+
// color swatches: complement + analogous
function colorSwatches(hex) {
if (!hex) return [];
@@ -339,15 +381,16 @@ Respond as JSON only, no preamble: [{"label":"specific material/finish (≤5 wor
}
async function generatePairings(design, allDesigns) {
- const [matches, colors, materials] = await Promise.all([
+ const [matches, colors, paints, materials] = await Promise.all([
Promise.resolve(catalogMatches(design, allDesigns)),
Promise.resolve(colorSwatches(design.dominant_hex)),
+ Promise.resolve(paintChipMatches(design.dominant_hex)),
materialSuggestions(design),
]);
// load existing moodboard for this design so pins survive cache regen
const moodboards = loadJSON(MOODBOARD_FILE, {});
const pinnedKeys = new Set((moodboards[design.id] || []).map(p => p.pin_key));
- const allSuggestions = [...matches, ...colors, ...materials].map((s, i) => ({
+ const allSuggestions = [...matches, ...colors, ...paints, ...materials].map((s, i) => ({
...s,
idx: i,
pin_key: pinKey(s, design.id),
@@ -366,7 +409,8 @@ async function generatePairings(design, allDesigns) {
// Stable identifier for a suggestion so pins survive regenerations.
function pinKey(s, designId) {
if (s.type === 'design') return `d:${s.design_id}`;
- if (s.type === 'color') return `c:${(s.hex || '').toLowerCase()}`;
+ if (s.type === 'color') return `c:${(s.hex || '').toLowerCase()}`;
+ if (s.type === 'paint') return `p:${(s.brand||'').toLowerCase()}:${(s.code||'').toLowerCase()}`;
return `m:${(s.label || '').toLowerCase().replace(/[^a-z0-9]+/g,'-')}`;
}
← d8b7aa1 stoned-animals v2 — every animal must have joint AT lips
·
back to Wallco Ai
·
/designs: infinite scroll, replace pagination links 65dcd74 →