← back to Wallco Ai
Add dedicated Monterey/California-coast scenic mural batch generator (new landmarks, real-textile ground, settlement-gated, stages unpublished)
bb95dd71c34f07a83de86d9c49b7d3709d67a27d · 2026-06-03 23:06:54 -0700 · Steve
Files touched
A scripts/generate-monterey-mural-batch.js
Diff
commit bb95dd71c34f07a83de86d9c49b7d3709d67a27d
Author: Steve <steve@designerwallcoverings.com>
Date: Wed Jun 3 23:06:54 2026 -0700
Add dedicated Monterey/California-coast scenic mural batch generator (new landmarks, real-textile ground, settlement-gated, stages unpublished)
---
scripts/generate-monterey-mural-batch.js | 230 +++++++++++++++++++++++++++++++
1 file changed, 230 insertions(+)
diff --git a/scripts/generate-monterey-mural-batch.js b/scripts/generate-monterey-mural-batch.js
new file mode 100644
index 0000000..0bd5371
--- /dev/null
+++ b/scripts/generate-monterey-mural-batch.js
@@ -0,0 +1,230 @@
+#!/usr/bin/env node
+// ── generate-monterey-mural-batch.js ─────────────────────────────────────────
+// One-off, CONTROLLED batch generator for NEW original Monterey / California-coast
+// scenic mural panels. NOT a loop, NOT the all-night night-builder, NOT the dog
+// pipeline (drunk_animals_tick / wallco-generator are intentionally stopped —
+// this does not touch them).
+//
+// Reuses the proven monterey-mural recipe from night-builder.js:
+// - composeMontereyMuralPrompt() pattern (4-color hue-sync, panoramic vertical
+// panel, single-layer stencil silhouette, hand-painted-silk register)
+// - generate_designs.js --kind mural_panel --width 144 --height 108
+// --category monterey-mural (mural_panel, NEVER seamless_tile — per
+// lib/mural-categories.js assertMuralKind + CLAUDE.md hard rule)
+// - lands is_published=FALSE — every roll requires curator approval at
+// /admin/design-curator?category=monterey-mural (Steve hot-or-not pass)
+//
+// IMPROVEMENTS over the night-builder monterey track (this batch only):
+// - FRESH landmark subjects Steve named (Bixby Bridge, Pfeiffer Beach,
+// Point Lobos, 17-Mile Drive cypress tunnel, Big Sur coastline, Monterey
+// wharf, + more), NOT reprocessings of the existing Lone Cypress /
+// Cannery Row / Point Pinos / Carmel Mission set already in the catalog.
+// - REAL natural-textile ground (grasscloth/sisal/raffia/…) injected from the
+// shared TEXTURE_GROUNDS library so the scene is painted ON a real DW
+// natural-material substrate (CLAUDE.md hard rule #7 — flat "ivory paper"
+// ground is a regression). The night-builder monterey track used a flat
+// colorway ground; this fixes that.
+//
+// Settlement: the monterey scenic prompts contain no Part-B elements (no
+// bananas/grapes/birds/butterflies) and no directional-leaf tropical foliage —
+// they are coastal landscapes. settlementOK() is run inline per prompt; the
+// full settlement skill gate is also verified out-of-band before the run.
+//
+// Usage:
+// node scripts/generate-monterey-mural-batch.js # full 24 (6 subj × 4 cw)
+// node scripts/generate-monterey-mural-batch.js --limit 8 # first 8 combos
+// node scripts/generate-monterey-mural-batch.js --dry-run # print prompts, no gen
+//
+// Env: respects GEN_BACKEND / COMFY_URL from .env (default comfy → Mac2 ComfyUI).
+// Override COMFY_URL to the tailscale prod backend when generating remotely.
+
+require('dotenv').config({ path: require('path').join(__dirname, '..', '.env') });
+const { spawnSync, execSync } = require('child_process');
+const fs = require('fs');
+const path = require('path');
+const SHARED = require('./drunk_motif_shared');
+
+const ROOT = path.join(__dirname, '..');
+const PSQL = '/opt/homebrew/opt/postgresql@14/bin/psql';
+const DB = 'dw_unified';
+function psql(sql) {
+ return execSync(`${PSQL} ${DB} -At -c "${sql.replace(/"/g, '\\"')}"`, { encoding: 'utf8' }).trim();
+}
+
+// ── CLI ──────────────────────────────────────────────────────────────────────
+const ARGS = process.argv.slice(2);
+const DRY = ARGS.includes('--dry-run');
+const LIMIT = (() => {
+ const i = ARGS.indexOf('--limit');
+ return i >= 0 ? parseInt(ARGS[i + 1], 10) : Infinity;
+})();
+const COOLDOWN_MS = 4000;
+
+// ── NEW California-coast landmark subjects (fresh — not in existing catalog) ──
+// Existing monterey-mural set (do NOT repeat): Lone Cypress, Cannery Row,
+// Point Pinos Lighthouse, Carmel Mission, Bixby (had ONE), Monterey Bay kelp.
+// These are NEW landmark scenes Steve called out.
+const MONTEREY_SUBJECTS = [
+ 'Bixby Creek Bridge at golden hour — the iconic arched concrete span leaping across the steep Big Sur canyon mouth, the Pacific opening to the west, coastal scrub and a lone cypress on the bluff, hand-painted scenic register',
+ 'Pfeiffer Beach purple-sand cove — the dramatic Keyhole Arch sea-stack with a shaft of sunset light piercing through the rock window, surf swirling around the base, headland cliffs framing the cove',
+ 'Point Lobos State Reserve — granite coves and twisted Monterey cypress clinging to the headland, sea-lion rocks offshore, kelp-strewn tide pools, fog drifting over the pines',
+ '17-Mile Drive cypress tunnel — an arching canopy of windswept Monterey cypress forming a natural tunnel over the coastal road, dappled light, the Pacific glimpsed at the end of the tunnel',
+ 'Big Sur coastline panorama — the rugged Santa Lucia mountains plunging into the Pacific, McWay-style ribbon of cliff, redwood-lined canyons inland, a sweeping headland curve',
+ 'Old Fishermans Wharf Monterey — the historic wooden wharf on pilings over the bay, moored fishing boats with masts and rigging, the curve of the harbor breakwater, Monterey hills rising behind',
+ 'McWay Falls at Julia Pfeiffer Burns — the 80-foot waterfall dropping onto the secluded cove beach, turquoise water, the cliff-framed inlet, cypress on the overlook',
+ 'Garrapata bluff wildflower headland — spring lupine and California poppy carpeting the coastal bluff, the Pacific surf below, a single cypress silhouette, layered headland ridges',
+];
+
+// ── Seasonal colorways (carried verbatim from night-builder monterey track) ──
+const SEASONAL_COLORWAYS = [
+ { season: 'spring', name: 'Spring Bloom', ground: '#A8B79A', figure: '#F2EADB', tone: 'sage-mint' },
+ { season: 'summer', name: 'Summer Surf', ground: '#3E6B82', figure: '#F2EADB', tone: 'bay-blue' },
+ { season: 'fall', name: 'Autumn Saddle', ground: '#7A4A28', figure: '#F2EADB', tone: 'cypress-burnt-umber' },
+ { season: 'winter', name: 'Winter Fog', ground: '#9CA09B', figure: '#3A2A1C', tone: 'pacific-mist' },
+];
+
+// ── Shared art-direction tail (mirrors night-builder SHARED_ARTDIR intent for
+// murals — sparse, refined, single-layer stencil, hard clean edges, no ghost
+// layer, hand-painted-silk scenic register). ──────────────────────────────────
+const MURAL_ARTDIR = (
+ 'Single-layer stencil silhouette only — NO ghost layer, NO faded background copies, ' +
+ 'NO atmospheric gradient sky, NO halftone, NO watercolor wash. Sky/atmosphere stays in ' +
+ 'the solid ground tone (a flat field, not a gradient). Hard clean razor-sharp edges, ' +
+ 'every figure region one flat color. Reference aesthetic: high-end hand-painted-silk ' +
+ 'scenic panel register (panoramic-scenic & Cie / hand-blocked scenic spirit — emulate ' +
+ 'the elegance, copy nothing). Strictly NOT Haeckel, NOT Audubon, NOT botanical-plate, ' +
+ 'NOT cartoon, NOT 3D render. No watermark, no signature, no text, no logos.'
+);
+
+function composeMontereyMuralPrompt(subject, cw, tex) {
+ return (
+ `Monterey, California west-coast scenic mural panel — ${subject}. ` +
+ `${cw.season.charAt(0).toUpperCase() + cw.season.slice(1)} colorway: ${cw.name}. ` +
+ // REAL natural-textile substrate UNDER the tinted ground (CLAUDE.md rule #7)
+ `Substrate: real ${tex.slug} (${tex.voice.replace(/^rendered on /, '')}). ` +
+ `Ground: solid ${cw.tone} (${cw.ground}) tinted over the natural-fiber substrate so the ` +
+ `weave/slubs/flecks of the real textile still read through. Figure: ${cw.figure} single-ink. ` +
+ `Composition: panoramic vertical panel, the scene anchored center-bottom, sky/atmosphere ` +
+ `extending up the panel in the solid ground tone (NOT a sky gradient), generous breathing room. ` +
+ `This is a FULL-ROOM MURAL — width = full wall, height = full ceiling. Compose for a ` +
+ `12'-wide × 9'-tall wall; the customer picks 24"/36"/54" print-panel widths at order time. ` +
+ `4-COLOR PALETTE WITH HUE SYNC — all four colors share the same hue family (no warm/cool mixing): ` +
+ `ground + figure as the two main tones; one HIGHLIGHT for small accents (sun-glint, foam-caps, ` +
+ `poppy/lupine blooms); one SHADOW under cliffs/cypress/headlands — highlight + shadow stay in ` +
+ `the same hue family. ` +
+ MURAL_ARTDIR
+ );
+}
+
+// ── Inline settlement check (same logic as night-builder.js settlementOK) ─────
+function settlementOK(prompt) {
+ let p = String(prompt || '').toLowerCase();
+ p = p
+ .replace(/\b(?:no|not|without|excluding|never|avoid)\b[^.,;]*(?:banana|bird|butterfl|grape|leaf|leaves|frond|palm|foliage|tropical)[^.,;]*[.,;]?/g, ' ')
+ .replace(/\bwithout\b[^.,;]*[.,;]/g, ' ')
+ .replace(/\bexcluding\b[^.,;]*[.,;]/g, ' ');
+ const partB = [
+ /\bbanana(?:s|\s+pods?)?\b/,
+ /\bplantains?\b/,
+ /\bgrapes?\b/,
+ /\bbirds?\b/,
+ /\bbutterfl(?:y|ies)\b/,
+ ];
+ for (const rx of partB) if (rx.test(p)) return false;
+ return true;
+}
+
+// ── Build the combo list (subject × 3 rotated colorways), capped by --limit ──
+// 8 subjects × 3 colorways = 24 (Steve's explicit 15-30 reviewable window, DTD
+// verdict B). For each subject we drop ONE seasonal colorway, rotating which one
+// is dropped per subject so all 4 seasonal palettes stay well-represented across
+// the batch (no single season is over- or under-weighted). --cwall forces the
+// full 4-per-subject (32) if Steve later wants the wider set.
+function buildCombos() {
+ const FULL = ARGS.includes('--cwall');
+ const combos = [];
+ MONTEREY_SUBJECTS.forEach((subject, si) => {
+ const cws = FULL
+ ? SEASONAL_COLORWAYS
+ : SEASONAL_COLORWAYS.filter((_, ci) => ci !== (si % SEASONAL_COLORWAYS.length));
+ for (const cw of cws) {
+ const tex = SHARED.TEXTURE_GROUNDS[Math.floor(Math.random() * SHARED.TEXTURE_GROUNDS.length)];
+ combos.push({ subject, cw, tex });
+ }
+ });
+ return combos.slice(0, LIMIT);
+}
+
+function generateOne(combo) {
+ const prompt = composeMontereyMuralPrompt(combo.subject, combo.cw, combo.tex);
+ if (!settlementOK(prompt)) {
+ return { ok: false, settlementBlock: true };
+ }
+ if (DRY) {
+ return { ok: true, dry: true, prompt };
+ }
+ // mural_panel — 144"×108" room scale (NEVER seamless_tile).
+ const r = spawnSync('node', [
+ path.join(__dirname, 'generate_designs.js'),
+ '--n', '1',
+ '--kind', 'mural_panel',
+ '--width', '144',
+ '--height', '108',
+ '--category', 'monterey-mural',
+ '--prompts', prompt,
+ ], { cwd: ROOT, encoding: 'utf8', env: process.env });
+
+ if (r.status !== 0) {
+ return { ok: false, stderr: (r.stderr || r.stdout || '').slice(0, 300) };
+ }
+ const summary = (r.stdout || '').match(/IDs:\s*(\d+(?:,\s*\d+)*)/);
+ const perLine = (r.stdout || '').match(/✓\s*#(\d+)/);
+ const idStr = summary ? summary[1].split(/,\s*/)[0] : (perLine ? perLine[1] : null);
+ const id = idStr ? parseInt(idStr, 10) : null;
+
+ // Re-assert UNPUBLISHED (defensive — generate_designs.js default is FALSE).
+ if (id) {
+ try { psql(`UPDATE spoon_all_designs SET is_published=FALSE WHERE id=${id} AND is_published=TRUE;`); } catch (_) {}
+ }
+ return { ok: true, id, colorway: combo.cw.name };
+}
+
+// ── Main ──────────────────────────────────────────────────────────────────────
+(async () => {
+ const combos = buildCombos();
+ const stamp = new Date().toISOString();
+ console.log(`[${stamp}] monterey-mural batch — ${combos.length} combos (${MONTEREY_SUBJECTS.length} subjects, rotated colorways)`);
+ console.log(` backend=${process.env.GEN_BACKEND || 'stub'} comfy=${process.env.COMFY_URL || '(default)'} dry=${DRY}`);
+ const state = { ok: 0, fail: 0, settlementBlock: 0, ids: [] };
+
+ for (let i = 0; i < combos.length; i++) {
+ const c = combos[i];
+ const label = `${c.subject.slice(0, 40)}… / ${c.cw.name}`;
+ if (DRY) {
+ console.log(`\n[${i + 1}/${combos.length}] ${label}\n PROMPT: ${composeMontereyMuralPrompt(c.subject, c.cw, c.tex).slice(0, 280)}…`);
+ continue;
+ }
+ process.stdout.write(`[${i + 1}/${combos.length}] ${label} … `);
+ const r = generateOne(c);
+ if (r.settlementBlock) {
+ state.settlementBlock++;
+ console.log('SETTLEMENT-BLOCK (skipped)');
+ } else if (r.ok) {
+ state.ok++;
+ state.ids.push(r.id);
+ console.log(`OK #${r.id} (unpublished)`);
+ } else {
+ state.fail++;
+ console.log(`FAIL: ${r.stderr || 'unknown'}`);
+ await new Promise(rs => setTimeout(rs, 8000));
+ }
+ if (i < combos.length - 1) await new Promise(rs => setTimeout(rs, COOLDOWN_MS));
+ }
+
+ console.log(`\nDONE — ok=${state.ok} fail=${state.fail} settlementBlock=${state.settlementBlock}`);
+ if (state.ids.length) {
+ console.log(`IDS: ${state.ids.join(',')}`);
+ console.log(`Review at: /admin/design-curator?category=monterey-mural (unpublished rolls appear in the grid)`);
+ }
+ process.exit(0);
+})();
← c85a001 Feature murals prominently on home: pinned Shop Murals quick
·
back to Wallco Ai
·
damask line batch-2: 6 heritage damasks live on prod (feed+P cdbae9e →