← back to Wallco Ai
wallco.ai: /designs cards show DW SKU + color name + AI-Designed badge + style; density slider 1-12 default 6; wisteria-animals prompt library
f582e1231b34393a8fd73d4e08bbf0f0f2dc854e · 2026-05-13 11:59:20 -0700 · SteveStudio2
Files touched
M public/css/site.cssA scripts/wisteria_animal_prompts.jsM server.js
Diff
commit f582e1231b34393a8fd73d4e08bbf0f0f2dc854e
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date: Wed May 13 11:59:20 2026 -0700
wallco.ai: /designs cards show DW SKU + color name + AI-Designed badge + style; density slider 1-12 default 6; wisteria-animals prompt library
---
public/css/site.css | 61 ++++++++++--
scripts/wisteria_animal_prompts.js | 192 +++++++++++++++++++++++++++++++++++++
server.js | 25 ++++-
3 files changed, 269 insertions(+), 9 deletions(-)
diff --git a/public/css/site.css b/public/css/site.css
index 5b1b3e5..7a7e3cd 100644
--- a/public/css/site.css
+++ b/public/css/site.css
@@ -287,7 +287,7 @@ main { padding-top: 73px; }
padding: 24px 12px 40px; /* tight side gutters — cards stretch wider */
}
.featured-grid { --cols: 4; }
-.catalog-grid { --cols: var(--cols, 3); } /* default to 3-up (wider cards) */
+.catalog-grid { --cols: var(--cols, 6); } /* default 6-up; density slider runs 1–12 */
.design-card {
display: block;
@@ -361,19 +361,66 @@ main { padding-top: 73px; }
.card-meta {
display: flex;
- align-items: center;
- gap: 8px;
- padding: 10px 12px;
+ flex-direction: column;
+ align-items: stretch;
+ gap: 3px;
+ padding: 8px 10px 10px;
border-top: 1px solid var(--line);
}
.card-title {
- flex: 1;
font-family: var(--serif);
font-size: 13px;
color: var(--ink);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
+ line-height: 1.2;
+}
+.card-sku {
+ font: 9px/1 ui-monospace, Menlo, monospace;
+ letter-spacing: 0.06em;
+ color: var(--ink-faint);
+ text-transform: uppercase;
+}
+.card-colorname {
+ display: inline-flex;
+ align-items: center;
+ gap: 5px;
+ font-size: 10px;
+ color: var(--ink-soft, #555);
+ text-transform: capitalize;
+ line-height: 1.2;
+}
+.card-hex {
+ font: 9px/1 ui-monospace, Menlo, monospace;
+ color: var(--ink-faint);
+ letter-spacing: 0.04em;
+}
+.card-tags {
+ display: inline-flex;
+ align-items: center;
+ gap: 5px;
+ flex-wrap: wrap;
+ margin-top: 2px;
+}
+.card-ai-badge {
+ display: inline-block;
+ font: 600 8.5px/1 var(--sans, system-ui);
+ letter-spacing: 0.07em;
+ text-transform: uppercase;
+ color: var(--accent, #0d0d0d);
+ background: var(--gold, #c9a14b);
+ padding: 3px 6px 2px;
+ border-radius: 3px;
+}
+.card-style {
+ font: 9px/1 var(--sans, system-ui);
+ letter-spacing: 0.07em;
+ text-transform: uppercase;
+ color: var(--ink-faint);
+ padding: 3px 6px 2px;
+ border: 1px solid var(--line);
+ border-radius: 3px;
}
.card-cat {
font-size: 10px;
@@ -382,10 +429,12 @@ main { padding-top: 73px; }
color: var(--ink-faint);
}
.color-dot {
- width: 10px; height: 10px;
+ width: 9px; height: 9px;
border-radius: 50%;
flex-shrink: 0;
border: 1px solid var(--line);
+ display: inline-block;
+ vertical-align: middle;
}
/* ── CTA BAND */
diff --git a/scripts/wisteria_animal_prompts.js b/scripts/wisteria_animal_prompts.js
new file mode 100644
index 0000000..8b09273
--- /dev/null
+++ b/scripts/wisteria_animal_prompts.js
@@ -0,0 +1,192 @@
+#!/usr/bin/env node
+/**
+ * Wisteria + drunk/stoned animals prompt library — drinking animals hanging
+ * from cascading wisteria racemes with bamboo-leaf canopy. All animals MUST
+ * face UP (chin tipped toward sky / racemes / leaf canopy). Inherits the
+ * butterfly-trellis aesthetic palette (heritage botanical, refined, no Warhol
+ * neon) rather than the pop-art drunk-animals palette.
+ *
+ * IMPORTANT — legal note: drunk-animals had a standing FLOWERS-ONLY rule
+ * ("NO leaves, NO foliage, NO bamboo") to dodge Hinson/Cole banana-leaf
+ * trademark waters. This brief intentionally overrides that with BAMBOO
+ * LEAVES + WISTERIA at Steve's direction. Bamboo-leaf prints are non-
+ * trademarkable as a motif so the risk is low, but anything resembling
+ * an existing commercial pattern (Schumacher Chiang Mai, Hinson
+ * Beverly Hills Banana, Brunschwig Le Singe) needs designer eyes
+ * before publish. Generator outputs go in as is_published=false until
+ * a human approves.
+ *
+ * Used by:
+ * - scripts/generate-wisteria-animals-batch.js (10 hand-curated designs)
+ * - direct CLI: node scripts/wisteria_animal_prompts.js 100 (dump 100 ideas)
+ */
+
+// Drinking states — drunk = sloshed/swaying, stoned = blissed-out/half-lidded.
+// All tableaux force "face/chin tipped UP toward the racemes" because the
+// brief is non-negotiable on that.
+const DRUNK_TABLEAUX = [
+ 'chin tipped up to the racemes, mouth wide, mid-guzzle from a long-stemmed wine glass — burgundy sloshing down its throat',
+ 'face turned skyward, draining a frosted vodka bottle held in both paws, condensation dripping onto its chest',
+ 'looking straight up at the wisteria, mid-toast with a champagne flute, golden bubbles cascading',
+ 'head tilted back, gulping from an emerald-green beer bottle, foam sliding down its chin',
+ 'gazing up through the petals, sipping rosé from a coupe glass, pink liquid clinging to its lip',
+ 'mouth agape toward the canopy, pouring a martini directly into its open jaw, two olives mid-air',
+ 'snout aimed at the sky, draining a crystal whiskey tumbler, last amber drops trailing',
+ 'chin up, both paws gripping a tequila bottle, lime wedge falling from its lips',
+ 'tipsy, head lolled back staring at racemes, half-empty cognac snifter dangling',
+ 'face skyward, mid-swig from a stout pint, cream head smeared across its muzzle',
+];
+
+const STONED_TABLEAUX = [
+ 'eyes half-closed and turned upward to the racemes, slow contented sip from a coupe glass',
+ 'face beatifically upturned to the canopy, slow-motion drink from a wine glass, dreamy smile',
+ 'chin lifted toward the petals, blissed-out, savoring a slow pour of amber whiskey down its throat',
+ 'eyes lidded, gazing up through the wisteria, languid sip from a tall pilsner',
+ 'mellow, head tilted back, slow guzzle from a frosted vodka bottle, deeply at peace',
+ 'face dreamily upturned, sucking on a long curly straw rooted in a magnum of champagne',
+ 'eyes soft and skyward, savoring a slow sip from a martini glass, cheeks rosy',
+ 'tranquil, gazing up, both paws hugging a bottle of rosé tipped into its mouth',
+ 'mouth lazily open to the racemes, slow sip from a cognac snifter, blissful trance',
+ 'eyes closed, chin up, contented sigh mid-sip from a champagne flute',
+];
+
+// Wisteria-only botanical anchors, varied by color. Bamboo leaves are added
+// separately in BAMBOO_LAYER so each prompt always carries both.
+const WISTERIA_COLORS = [
+ 'cascading lavender-purple wisteria racemes, dense pendulous clusters',
+ 'pale-blush pink wisteria racemes, soft and ethereal',
+ 'deep amethyst wisteria racemes, almost violet, regal',
+ 'ivory-white wisteria racemes streaked with faint lilac',
+ 'butter-yellow wisteria racemes (Japanese golden chain hybrid), warm honey tones',
+ 'soft sky-blue wisteria racemes, dusted with periwinkle',
+ 'rose-coral wisteria racemes, sunset-toned',
+ 'jade-green wisteria racemes, unusual and exotic',
+ 'antique champagne wisteria racemes, pale gold-tinged ivory',
+ 'rich plum wisteria racemes shading to violet at the petal tips',
+];
+
+const BAMBOO_LAYER =
+ 'set behind a delicate canopy of bamboo leaves — long lanceolate green blades arching above the wisteria, the leaves layered but never crowding the animals, soft dappled light filtering through';
+
+// Refined heritage-botanical palettes — inherited from butterfly-trellis,
+// NOT the Warhol drunk-animals neon palette.
+const PALETTES = [
+ 'emerald and bone-ivory background, gold-leaf accents, archival watercolor',
+ 'sage green and cream, blush-pink highlights, soft dusty rose accents',
+ 'deep navy ink on bone white, monochromatic indigo gradient',
+ 'champagne on midnight navy, subtle metallic shimmer',
+ 'forest green with iridescent jewel-tone accents — sapphire, amethyst, emerald, ruby',
+ 'soft watercolor pastels — peach, lavender, mint, sky blue — on warm cream',
+ 'antique gold and matte black, ivory background',
+ 'powder blue and parchment, faded sepia accents',
+ 'oxblood and cream, dark olive accents',
+ 'pale-celadon green on bone-white, faded coral accents, vintage botanical',
+];
+
+// Composition cues — emphasizes the UP-facing rule and seamless repeat.
+const COMPOSITIONS = [
+ 'allover seamless repeat, animals scattered among the wisteria racemes, ALL faces tipped UP toward the leaf canopy',
+ 'half-drop repeat, animals nested in pendulous racemes, ALL chins lifted upward',
+ 'tight 24-inch tile repeat, dense scatter of upward-gazing animals among bamboo blades',
+ 'mirrored axis repeat, animals in pairs facing skyward, kaleidoscopic wisteria',
+ 'cascading vertical repeat following raceme drops, animals climbing and looking up',
+ 'tossed-bouquet repeat, animals interspersed with cut wisteria stems, all faces lifted',
+ 'large-scale mural repeat, hero animal centered face-up, racemes radiating',
+ 'striped column repeat, animals in vertical bands gazing upward through bamboo',
+ 'diagonal flow repeat, racemes guiding the eye upward, animals turned to follow',
+ 'allover botanical repeat with breathing space, every animal’s gaze tilted toward the petals above',
+];
+
+const STYLES = [
+ 'fine archival watercolor in the style of a 19th-century botanical plate',
+ 'gouache illustration with crisp ink linework, gallery-quality',
+ 'hand-pulled silkscreen wallpaper, soft layered tones, refined repeat',
+ 'chinoiserie-inspired brushwork on aged silk, mineral pigment',
+ 'block-printed wallpaper feel, hand-carved edges, archival paper grain',
+ 'pen-and-watercolor garden journal aesthetic, refined and personal',
+ 'mid-century botanical lithograph, slight halftone, archival print',
+ 'modern fine-art illustration with luminous color washes, no neon',
+ 'painterly gouache with confident brushwork, fabric-pattern feel',
+ 'antique decorator wallpaper, bone-paper texture, slightly faded',
+];
+
+const ANIMALS_FACE_UP = [
+ 'long-armed Bornean orangutan hanging by one arm, chin tipped UP',
+ 'small gibbon dangling from a raceme, face skyward',
+ 'fluffy red panda balancing on a bamboo culm, gazing up through petals',
+ 'spider monkey looped by its prehensile tail, mouth open to the canopy',
+ 'capuchin monkey perched on a bamboo node, head tilted back',
+ 'sloth hugging a bamboo stem, slow blink upward at the wisteria',
+ 'lemur with ringed tail wrapped around a stem, ears forward, looking up',
+ 'small lar gibbon swinging from a raceme, face turned to the sky',
+ 'colobus monkey draped over a bamboo branch, gaze tipped upward',
+ 'wide-eyed tarsier clinging to a bamboo node, neck craned skyward',
+ 'koala wedged in a wisteria-bamboo cradle, face turned up',
+ 'tipsy raccoon balancing on a bamboo node, snout up, eyes on the racemes',
+];
+
+function pickRand(arr, exclude = new Set()) {
+ for (let tries = 0; tries < 50; tries++) {
+ const v = arr[Math.floor(Math.random() * arr.length)];
+ if (!exclude.has(v)) return v;
+ }
+ return arr[Math.floor(Math.random() * arr.length)];
+}
+
+// Build a single prompt — `state` is 'drunk' | 'stoned'; defaults to random.
+function buildPrompt({ state = null, seed = null } = {}) {
+ const rng = (seed != null)
+ ? (() => { let s = seed >>> 0; return () => { s = (s * 1664525 + 1013904223) >>> 0; return s / 2 ** 32; }; })()
+ : Math.random;
+ const pick = arr => arr[Math.floor(rng() * arr.length)];
+ const s = state || (rng() < 0.5 ? 'drunk' : 'stoned');
+ const tableau = s === 'drunk' ? pick(DRUNK_TABLEAUX) : pick(STONED_TABLEAUX);
+ return [
+ pick(ANIMALS_FACE_UP),
+ tableau,
+ `cascading from ${pick(WISTERIA_COLORS)}`,
+ BAMBOO_LAYER,
+ `palette: ${pick(PALETTES)}`,
+ pick(STYLES),
+ pick(COMPOSITIONS),
+ 'CRITICAL: every animal MUST be facing UP toward the wisteria canopy — chin lifted, eyes/snout skyward, no animals looking down or sideways',
+ 'seamless wallpaper repeat, archival quality, refined heritage botanical aesthetic, no neon, no text, no watermark',
+ ].join(', ');
+}
+
+function buildN(n, opts = {}) {
+ const out = [];
+ const usedAnimals = new Set();
+ const usedWisteria = new Set();
+ for (let i = 0; i < n; i++) {
+ if (usedAnimals.size >= ANIMALS_FACE_UP.length - 1) usedAnimals.clear();
+ if (usedWisteria.size >= WISTERIA_COLORS.length - 1) usedWisteria.clear();
+ const animal = pickRand(ANIMALS_FACE_UP, usedAnimals); usedAnimals.add(animal);
+ const wisteria = pickRand(WISTERIA_COLORS, usedWisteria); usedWisteria.add(wisteria);
+ const state = opts.state || (Math.random() < 0.5 ? 'drunk' : 'stoned');
+ const tableau = state === 'drunk' ? pickRand(DRUNK_TABLEAUX) : pickRand(STONED_TABLEAUX);
+ out.push([
+ animal, tableau,
+ `cascading from ${wisteria}`,
+ BAMBOO_LAYER,
+ `palette: ${pickRand(PALETTES)}`,
+ pickRand(STYLES),
+ pickRand(COMPOSITIONS),
+ 'CRITICAL: every animal MUST be facing UP toward the wisteria canopy — chin lifted, eyes/snout skyward',
+ 'seamless wallpaper repeat, archival quality, refined heritage botanical, no neon, no text, no watermark',
+ ].join(', '));
+ }
+ return out;
+}
+
+module.exports = {
+ buildPrompt, buildN,
+ DRUNK_TABLEAUX, STONED_TABLEAUX, WISTERIA_COLORS, BAMBOO_LAYER,
+ PALETTES, STYLES, COMPOSITIONS, ANIMALS_FACE_UP,
+};
+
+if (require.main === module) {
+ const n = parseInt(process.argv[2] || '100', 10);
+ const prompts = buildN(n);
+ for (const p of prompts) console.log('---\n' + p + '\n');
+}
diff --git a/server.js b/server.js
index 39eac53..cf4c2bf 100644
--- a/server.js
+++ b/server.js
@@ -3109,6 +3109,21 @@ app.get('/designs', (req, res) => {
const createdMs = Date.parse(d.created_at || '') || 0;
const isNew = createdMs && (Date.now() - createdMs < 72 * 3600 * 1000);
const newBadge = isNew ? `<span class="card-new-badge" aria-label="Newly added">NEW</span>` : '';
+ // DW-style SKU — derived from the design id with a stable two-letter prefix
+ // for the wallco.ai sub-label (WC). Designer Wallcoverings catalog convention
+ // is DW-<vendor-code>-<numeric>, so wallco.ai pieces become DW-WC-####.
+ const sku = `DW-WC-${String(d.id).padStart(4, '0')}`;
+ // Color name — interior-designer-skill style: derive a poetic color name
+ // from the dominant_hex by binning into the same hue buckets the page
+ // filter uses, then prefer the leading word of the title (Honey/Amber/
+ // Rose/Sage/…) when the generator already gave us one — that's the
+ // canonical color family per the prompt library. Falls back to the
+ // hue bucket if the title doesn't lead with one.
+ const colorNameFromTitle = (String(d.title || '').match(/^(Honey|Amber|Rose|Sage|Olive|Marine|Sapphire|Mauve|Plum|Neutral|Bone|Champagne|Ivory|Emerald|Navy|Coral|Blush|Indigo|Charcoal)/i) || [])[1];
+ const colorName = colorNameFromTitle || (hueBucketOf(d.dominant_hex) || 'neutral').replace(/^./, c => c.toUpperCase());
+ // Style tag — category is the closest thing to a style category in the
+ // data model (damask, butterfly-trellis, stoned-animals, mural-scenic).
+ const styleTag = String(d.category || 'mixed').replace(/-/g, ' ');
return `
<a href="/design/${d.id}" class="design-card${roomKey ? ' has-room' : ''}${isNew ? ' is-new' : ''}" aria-label="${cardAriaLabel(d)}" data-design-id="${d.id}">
<button type="button" class="fav-btn" data-fav-id="${d.id}" aria-pressed="false" aria-label="Save ${d.title} to favorites" title="Favorite"><span class="fav-icon"></span></button>
@@ -3116,8 +3131,12 @@ app.get('/designs', (req, res) => {
<div class="card-img" style="background-image:url('${d.image_url}')" role="img" aria-label="${d.title} pattern thumbnail">${roomOverlay}</div>
<div class="card-meta">
<span class="card-title">${d.title}</span>
- <span class="card-cat">${d.category}</span>
- <span class="color-dot" style="background:${d.dominant_hex}" aria-hidden="true"></span>
+ <span class="card-sku" title="DW catalog SKU">${sku}</span>
+ <span class="card-colorname">${colorName} <span class="color-dot" style="background:${d.dominant_hex}" aria-hidden="true"></span><span class="card-hex">${(d.dominant_hex || '').toUpperCase()}</span></span>
+ <span class="card-tags">
+ <span class="card-ai-badge" title="AI-designed pattern">✦ AI-Designed</span>
+ <span class="card-style">${styleTag}</span>
+ </span>
</div>
</a>`;
}
@@ -3304,7 +3323,7 @@ ${cat === 'mural-scenic' ? `
}).join('')}
</div>
<label class="density-label" style="display:inline-flex;align-items:center;gap:8px;font:11px var(--sans);text-transform:uppercase;letter-spacing:.1em;color:var(--ink-faint)">Density
- <input type="range" id="density-slider" min="1" max="8" step="1" value="3" class="density-range" style="flex:0 0 110px">
+ <input type="range" id="density-slider" min="1" max="12" step="1" value="6" class="density-range" style="flex:0 0 140px">
</label>
<button type="button" id="surprise-btn" class="filter-select"
style="background:var(--gold,#c9a14b);color:var(--accent,#0d0d0d);border:0;font-weight:500;padding:8px 14px;cursor:pointer;border-radius:6px;letter-spacing:.04em"
← da2aabc wallco.ai homepage: pin newest 6 butterflies above Featured,
·
back to Wallco Ai
·
wisteria-animals: drop bamboo from brief; wisteria racemes a 09ad34c →