[object Object]

← back to Wallco Ai

designs: butterfly+trellis batch generator + 10 new designs

9a13b0a258f692e3e90e28ed03f0b69bcc672ca6 · 2026-05-13 11:09:11 -0700 · Steve

scripts/generate-butterfly-trellis-batch.js — one-off Gemini 2.5 Flash Image
edit-mode script. Seeded by three Steve-supplied TIFs in Downloads/:
  - LomitaButterflies.tif (cane trellis + butterflies, original)
  - BH90210-900 Butterfly Dream.tif (Beverly Hills banana-leaf / butterflies)
  - BH90214-24IN-150DPI.tif (clean cane lattice, no butterflies)

10 variations generated, all 10 succeeded (8.4s avg per call):
  1. Cane Trellis · Original Palette        (id=3275)
  2. Cane Trellis · Blush Butterflies        (id=3276)
  3. Cane Trellis · Monochrome Navy          (id=3277)
  4. Cane Trellis · Gold on Emerald          (id=3278)
  5. Trellis Dream · Leaves Removed          (id=3279)  ← banana fronds stripped
  6. Trellis Dream · Watercolor Pastel       (id=3280)
  7. Trellis Dream · Black Ink               (id=3283)
  8. Clean Trellis · Add Soft Butterflies    (id=3289)
  9. Clean Trellis · Iridescent Jewels       (id=3290)
 10. Clean Trellis · Champagne on Midnight   (id=3291)

All rows inserted into spoon_all_designs with category='butterfly-trellis',
motifs=['butterfly','trellis','lattice'], is_published=true, generator=
'gemini-2.5-flash-image-edit'. Cost-tracker hooked, every call logged.

Files touched

Diff

commit 9a13b0a258f692e3e90e28ed03f0b69bcc672ca6
Author: Steve <steve@designerwallcoverings.com>
Date:   Wed May 13 11:09:11 2026 -0700

    designs: butterfly+trellis batch generator + 10 new designs
    
    scripts/generate-butterfly-trellis-batch.js — one-off Gemini 2.5 Flash Image
    edit-mode script. Seeded by three Steve-supplied TIFs in Downloads/:
      - LomitaButterflies.tif (cane trellis + butterflies, original)
      - BH90210-900 Butterfly Dream.tif (Beverly Hills banana-leaf / butterflies)
      - BH90214-24IN-150DPI.tif (clean cane lattice, no butterflies)
    
    10 variations generated, all 10 succeeded (8.4s avg per call):
      1. Cane Trellis · Original Palette        (id=3275)
      2. Cane Trellis · Blush Butterflies        (id=3276)
      3. Cane Trellis · Monochrome Navy          (id=3277)
      4. Cane Trellis · Gold on Emerald          (id=3278)
      5. Trellis Dream · Leaves Removed          (id=3279)  ← banana fronds stripped
      6. Trellis Dream · Watercolor Pastel       (id=3280)
      7. Trellis Dream · Black Ink               (id=3283)
      8. Clean Trellis · Add Soft Butterflies    (id=3289)
      9. Clean Trellis · Iridescent Jewels       (id=3290)
     10. Clean Trellis · Champagne on Midnight   (id=3291)
    
    All rows inserted into spoon_all_designs with category='butterfly-trellis',
    motifs=['butterfly','trellis','lattice'], is_published=true, generator=
    'gemini-2.5-flash-image-edit'. Cost-tracker hooked, every call logged.
---
 scripts/generate-butterfly-trellis-batch.js | 156 ++++++++++++++++++++++++++++
 1 file changed, 156 insertions(+)

diff --git a/scripts/generate-butterfly-trellis-batch.js b/scripts/generate-butterfly-trellis-batch.js
new file mode 100644
index 0000000..ddc5e4d
--- /dev/null
+++ b/scripts/generate-butterfly-trellis-batch.js
@@ -0,0 +1,156 @@
+#!/usr/bin/env node
+/**
+ * One-off: generate 10 butterfly + trellis wallpaper variations using
+ * Gemini 2.5 Flash Image, seeded by three reference TIFs Steve dropped in
+ * Downloads/. The Beverly-Hills banana-leaf source gets its leaves stripped
+ * out; the clean cane-trellis source gets butterflies added; the original
+ * butterfly-on-cane source gets palette + style swaps.
+ *
+ * Outputs land in ~/Projects/wallco-ai/data/generated/ and a row is inserted
+ * into spoon_all_designs (is_published=true) so they show up on /designs.
+ *
+ * Run once:  cd ~/Projects/wallco-ai && node scripts/generate-butterfly-trellis-batch.js
+ */
+'use strict';
+require('dotenv').config({ path: require('path').join(__dirname, '..', '.env') });
+const fs = require('fs');
+const path = require('path');
+const crypto = require('crypto');
+const { execSync, spawnSync } = require('child_process');
+
+const KEY = process.env.GEMINI_API_KEY;
+if (!KEY) { console.error('GEMINI_API_KEY missing'); process.exit(1); }
+const SRC = '/tmp/wallco-sources';
+const OUT_DIR = path.join(__dirname, '..', 'data', 'generated');
+fs.mkdirSync(OUT_DIR, { recursive: true });
+
+const DB = process.env.WALLCO_DB || 'dw_unified';
+const PSQL = (process.platform === 'linux')
+  ? `sudo -n -u postgres psql ${DB} -At -q`
+  : `psql ${DB} -At -q`;
+function psql(sql) { return execSync(PSQL, { input: sql, encoding: 'utf8' }).trim(); }
+function esc(v) { if (v == null) return 'NULL'; return "'" + String(v).replace(/'/g, "''") + "'"; }
+
+// 10 variations — each picks one source + a per-variation aesthetic.
+// Prompts ALL include the constraint: remove plants/leaves/trees, keep butterflies + trellis.
+const SHARED = [
+  'Remove every plant, leaf, vine, branch, palm, banana frond, tree, or any other vegetation.',
+  'The output must contain ONLY a trellis / lattice / caning grid pattern and stylized butterflies on top.',
+  'Seamless tile, repeating wallpaper pattern, no edge artifacts, no signature, no watermark, no text.',
+  'High detail, archival quality, square crop, fabric-pattern aesthetic.',
+].join(' ');
+
+const VARIATIONS = [
+  { src: 'LomitaButterflies.jpg',                title: 'Cane Trellis · Original Palette',
+    prompt: 'Keep the existing emerald cane trellis and the existing butterfly placements. Sharpen the trellis lines. Slightly increase butterfly contrast. Make the cream background warmer (bone/ivory).' },
+  { src: 'LomitaButterflies.jpg',                title: 'Cane Trellis · Blush Butterflies',
+    prompt: 'Recolor the trellis to a soft sage green. Recolor every butterfly to dusty blush pink with deep wine accents. Keep the cream background.' },
+  { src: 'LomitaButterflies.jpg',                title: 'Cane Trellis · Monochrome Navy',
+    prompt: 'Recolor the trellis to deep navy ink. Recolor every butterfly to varying shades of navy and indigo on white. Pure monochrome.' },
+  { src: 'LomitaButterflies.jpg',                title: 'Cane Trellis · Gold on Emerald',
+    prompt: 'Recolor the cane trellis to dark emerald with gilt highlights. Recolor every butterfly to antique gold leaf with matte black bodies. Background remains ivory.' },
+  { src: 'BH90210-900 Butterfly Dream.jpg',      title: 'Trellis Dream · Leaves Removed',
+    prompt: 'CRITICAL: completely erase every banana leaf, palm frond, and stem in the source. Reveal and keep only the bamboo trellis underneath plus the butterflies. Keep the original butterfly colors (yellow, red, blue, monarch orange).' },
+  { src: 'BH90210-900 Butterfly Dream.jpg',      title: 'Trellis Dream · Watercolor Pastel',
+    prompt: 'Erase every leaf and plant. Keep the bamboo trellis (lighten it). Repaint the butterflies in soft watercolor pastel (peach, lavender, sky blue, mint). Background warm cream.' },
+  { src: 'BH90210-900 Butterfly Dream.jpg',      title: 'Trellis Dream · Black Ink',
+    prompt: 'Erase every leaf and plant. Keep the bamboo trellis but redraw it in pure black ink linework. Redraw the butterflies in pure black ink, fine etching style. Background bone white.' },
+  { src: 'BH90214-24IN-150DPI.jpg',              title: 'Clean Trellis · Add Soft Butterflies',
+    prompt: 'Keep this clean emerald cane lattice exactly. Add scattered stylized butterflies (small, varying species, soft warm tones — yellow, peach, cream, dusty rose) resting on the trellis. Do not add any plants or leaves anywhere.' },
+  { src: 'BH90214-24IN-150DPI.jpg',              title: 'Clean Trellis · Iridescent Jewels',
+    prompt: 'Keep the cane lattice (slightly darken to forest green). Add scattered iridescent jewel-tone butterflies — sapphire, amethyst, emerald, ruby — with subtle metallic shimmer. No plants, no leaves.' },
+  { src: 'BH90214-24IN-150DPI.jpg',              title: 'Clean Trellis · Champagne on Midnight',
+    prompt: 'Recolor the lattice to deep midnight navy. Add scattered champagne / pale gold butterflies with subtle highlights. Sophisticated, evening palette. No plants, no leaves.' },
+];
+
+async function generateOne(v, idx) {
+  const srcPath = path.join(SRC, v.src);
+  if (!fs.existsSync(srcPath)) throw new Error(`source not found: ${srcPath}`);
+  const imageB64 = fs.readFileSync(srcPath).toString('base64');
+  const fullPrompt = v.prompt + ' ' + SHARED;
+  const body = {
+    contents: [{
+      parts: [
+        { inline_data: { mime_type: 'image/jpeg', data: imageB64 } },
+        { text: fullPrompt }
+      ]
+    }],
+    generationConfig: { responseModalities: ['IMAGE'] }
+  };
+  const url = `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-image:generateContent?key=${KEY}`;
+  const t0 = Date.now();
+  const r = await fetch(url, {
+    method: 'POST',
+    headers: { 'Content-Type': 'application/json' },
+    body: JSON.stringify(body),
+  });
+  if (!r.ok) throw new Error(`HTTP ${r.status}: ${await r.text()}`);
+  const j = await r.json();
+  // Cost-tracker hook
+  try {
+    const { logGemini } = require(require('os').homedir() + '/.claude/skills/cost-tracker/scripts/log-gemini.js');
+    logGemini(j, { app: 'wallco-ai', note: 'butterfly-trellis-batch', model: 'gemini-2.5-flash-image' });
+  } catch {}
+  const part = j.candidates?.[0]?.content?.parts?.find(p => p.inline_data || p.inlineData);
+  const data = part?.inline_data?.data || part?.inlineData?.data;
+  if (!data) {
+    const text = j.candidates?.[0]?.content?.parts?.find(p => p.text)?.text;
+    throw new Error(`no image returned (${j.candidates?.[0]?.finishReason || 'unknown'}): ${text || ''}`);
+  }
+  const seed = crypto.randomInt(1, 2 ** 31 - 1);
+  const filename = `bt_${Date.now()}_${seed}.png`;
+  const outPath = path.join(OUT_DIR, filename);
+  fs.writeFileSync(outPath, Buffer.from(data, 'base64'));
+  const elapsed = ((Date.now() - t0) / 1000).toFixed(1);
+
+  // Palette extraction
+  const py = spawnSync('python3', ['-c', `
+from PIL import Image
+from collections import Counter
+import json, sys
+img = Image.open(sys.argv[1]).convert('RGB')
+img.thumbnail((300, 300))
+pal = img.quantize(colors=5, method=Image.Quantize.MEDIANCUT).convert('RGB')
+pixels = list(pal.getdata())
+cnt = Counter(pixels)
+total = sum(cnt.values())
+palette = [{'hex':'#{:02x}{:02x}{:02x}'.format(*rgb), 'pct':round(n/total*100,2)} for rgb,n in cnt.most_common(5)]
+print(json.dumps(palette))
+`, outPath], { encoding: 'utf8' });
+  let palette = []; let dominant = null;
+  try { palette = JSON.parse(py.stdout.trim()); dominant = palette[0]?.hex; } catch {}
+
+  // Insert into DB
+  const promptEsc = (v.title + ' — ' + v.prompt).replace(/'/g, "''");
+  const palJson = JSON.stringify(palette).replace(/'/g, "''");
+  const insertSql = `INSERT INTO spoon_all_designs
+    (kind, width_in, height_in, generator, prompt, seed, dominant_hex, palette,
+     local_path, image_url, category, motifs, tags, is_published, request_text)
+    VALUES ('seamless_tile', 24, 24, 'gemini-2.5-flash-image-edit',
+      '${promptEsc}', ${seed},
+      ${dominant ? "'" + dominant + "'" : 'NULL'},
+      '${palJson}'::jsonb,
+      ${esc(outPath)}, ${esc('/designs/img/' + filename)},
+      'butterfly-trellis',
+      ARRAY['butterfly', 'trellis', 'lattice']::text[],
+      ARRAY['butterfly', 'trellis', 'lattice', 'cane', 'pattern']::text[],
+      TRUE, ${esc('butterfly-trellis batch #' + (idx + 1) + ': ' + v.title)})
+    RETURNING id;`;
+  const id = parseInt(psql(insertSql), 10);
+  console.log(`  [${idx + 1}/10] ${v.title}  →  id=${id}  ${elapsed}s  ${filename}`);
+  return { id, title: v.title, image_url: '/designs/img/' + filename };
+}
+
+(async () => {
+  console.log(`\nGenerating ${VARIATIONS.length} butterfly+trellis variants…\n`);
+  const results = [];
+  for (let i = 0; i < VARIATIONS.length; i++) {
+    try { results.push(await generateOne(VARIATIONS[i], i)); }
+    catch (e) { console.error(`  [${i + 1}/10] FAIL — ${e.message.slice(0, 200)}`); }
+  }
+  console.log(`\nDone. ${results.length}/${VARIATIONS.length} succeeded.`);
+  if (results.length) {
+    console.log('\nNew design ids:', results.map(r => r.id).join(', '));
+    console.log('Live at: http://localhost:9792/designs?cat=butterfly-trellis (admin) or refresh /designs');
+  }
+})();

← 5bb011a /api/generator/refresh-orders: stop hanging on the broken-pi  ·  back to Wallco Ai  ·  snapshot: include gemini-2.5-flash-image-edit generator (10 bfb6108 →