/* ============================================================ qft-variations-light.mjs — sketch 04. Lighter backgrounds, larger field scales (most bleed past the frame), per-edge hue GRADIENTS within each field, and noticeably THICKER strokes than previous sketches. Custom paperOverride RGB for the more unusual pale grounds. Output → output/qft/sketch04/ ============================================================ */ import { writeFileSync, mkdirSync } from 'node:fs'; import { generateQFTScene } from '../src/qft/scene.js'; import { paramsFromSeed } from '../src/qft/params.js'; import { renderQFTSVG } from '../src/qft/renderer.js'; const BASE_SEED = 'FEYNMAN-7167'; const OUT_DIR = 'output/qft/sketch04'; const SIZE = 1800; mkdirSync(OUT_DIR, { recursive: true }); const F = (hueStart, hueEnd, saturation, lightness, opacity) => ({ hueStart, hueEnd, saturation, lightness, opacity }); // helper: build a paperOverride from one RGB and derive sensible glow stops const paper = (flat, glowInDelta = [18, 16, 14], glowOutDelta = [-25, -22, -20]) => ({ flat, glowIn: [flat[0] + glowInDelta[0], flat[1] + glowInDelta[1], flat[2] + glowInDelta[2]], glowOut: [flat[0] + glowOutDelta[0], flat[1] + glowOutDelta[1], flat[2] + glowOutDelta[2]], }); // dark header/vignette tones to read against light paper const DARK_FEATURE = [60, 48, 36]; const DARK_VIGN = [70, 55, 40]; const variations = [ { name: '01_warm-sunset-cream', label: 'Warm sunset · cream · huge cubic bleeding past frame', overrides: { substrate: 'cream', stroke: 2.6, cubicScale: 1.75, schlegelScale: 0.85, e8Count: 3, e8Scale: 0.22, e8OriginRadius: 0.55, fields: { cubic: F(0.10, 0.02, 0.65, 0.40, 0.82), // amber → red schlegel: F(0.13, 0.06, 0.45, 0.38, 0.65), // gold → orange e8: F(0.05, 0.13, 0.75, 0.42, 0.92), // red → gold links: F(0.95, 0.04, 0.85, 0.38, 0.96), // pink → red bright }, }, }, { name: '02_pale-verdigris-linen', label: 'Pale verdigris · linen ground · large scales', overrides: { paperOverride: paper([222, 210, 184]), vignOverride: DARK_VIGN, featureOverride: DARK_FEATURE, stroke: 2.4, cubicScale: 1.55, schlegelScale: 1.35, e8Count: 3, e8Scale: 0.24, e8OriginRadius: 0.48, fields: { cubic: F(0.44, 0.50, 0.55, 0.34, 0.82), // teal → cyan schlegel: F(0.06, 0.10, 0.55, 0.38, 0.66), // copper accents e8: F(0.35, 0.46, 0.60, 0.32, 0.90), // sage → teal links: F(0.04, 0.10, 0.80, 0.38, 0.95), }, }, }, { name: '03_rose-peach', label: 'Rose pastel on peach paper · huge cubic', overrides: { paperOverride: paper([232, 200, 175]), vignOverride: [90, 50, 40], featureOverride: [110, 60, 50], stroke: 2.8, cubicScale: 1.65, schlegelScale: 0.75, schlegelOriginX: 0.20, e8Count: 2, e8Scale: 0.28, e8OriginRadius: 0.52, fields: { cubic: F(0.92, 0.04, 0.55, 0.42, 0.82), schlegel: F(0.88, 0.94, 0.45, 0.40, 0.66), e8: F(0.96, 0.06, 0.65, 0.42, 0.92), links: F(0.90, 0.04, 0.85, 0.38, 0.96), }, }, }, { name: '04_pale-sky-ivory', label: 'Pale sky · ivory · huge Schlegel tesseract', overrides: { paperOverride: paper([232, 222, 200]), vignOverride: [60, 50, 40], featureOverride: DARK_FEATURE, stroke: 2.4, cubicScale: 0.70, schlegelScale: 1.95, // massive — bleeds significantly e8Count: 3, e8Scale: 0.20, e8OriginRadius: 0.60, fields: { cubic: F(0.58, 0.66, 0.55, 0.30, 0.80), // blue → violet schlegel: F(0.62, 0.72, 0.55, 0.32, 0.66), // indigo → violet e8: F(0.55, 0.70, 0.65, 0.30, 0.92), links: F(0.60, 0.80, 0.85, 0.32, 0.96), }, }, }, { name: '05_mint-gold-pale', label: 'Mint & gold · pale-mint ground', overrides: { paperOverride: paper([210, 225, 208]), vignOverride: [30, 55, 35], featureOverride: [40, 70, 45], stroke: 2.6, cubicScale: 1.50, schlegelScale: 1.25, e8Count: 3, e8Scale: 0.26, e8OriginRadius: 0.48, fields: { cubic: F(0.40, 0.50, 0.55, 0.30, 0.82), // mint teal schlegel: F(0.10, 0.16, 0.60, 0.36, 0.66), // gold e8: F(0.13, 0.20, 0.80, 0.40, 0.92), links: F(0.08, 0.14, 0.85, 0.40, 0.96), }, }, }, { name: '06_bone-radial-gradient', label: 'Bone china · radial gradient (cool centre → warm edges)', overrides: { paperOverride: paper([234, 230, 222]), vignOverride: [70, 60, 50], featureOverride: DARK_FEATURE, stroke: 2.6, gradientMode: 'radial', cubicScale: 1.55, schlegelScale: 1.30, e8Count: 3, e8Scale: 0.22, e8OriginRadius: 0.55, fields: { cubic: F(0.55, 0.06, 0.62, 0.36, 0.82), // cyan centre → orange edges schlegel: F(0.58, 0.04, 0.50, 0.34, 0.70), e8: F(0.55, 0.05, 0.72, 0.40, 0.92), links: F(0.55, 0.05, 0.85, 0.40, 0.96), }, }, }, { name: '07_pale-mauve-violet', label: 'Pale mauve fog · violet → pink gradients · thick', overrides: { paperOverride: paper([222, 205, 224]), vignOverride: [55, 35, 60], featureOverride: [75, 50, 90], stroke: 3.0, cubicScale: 1.85, // bleeds heavily schlegelScale: 0.90, e8Count: 3, e8Scale: 0.22, e8OriginRadius: 0.50, fields: { cubic: F(0.74, 0.92, 0.55, 0.34, 0.84), schlegel: F(0.78, 0.86, 0.50, 0.32, 0.68), e8: F(0.82, 0.96, 0.65, 0.38, 0.92), links: F(0.78, 0.95, 0.85, 0.36, 0.96), }, }, }, { name: '08_faded-blueprint', label: 'Faded blueprint · pale cyan paper · huge Schlegel', overrides: { paperOverride: paper([186, 214, 228]), vignOverride: [40, 55, 70], featureOverride: [30, 50, 75], stroke: 2.8, cubicScale: 0.80, schlegelScale: 1.90, e8Count: 3, e8Scale: 0.22, e8OriginRadius: 0.55, fields: { cubic: F(0.60, 0.66, 0.60, 0.22, 0.86), // dark blue → navy schlegel: F(0.58, 0.62, 0.55, 0.20, 0.66), e8: F(0.62, 0.72, 0.70, 0.28, 0.92), links: F(0.58, 0.68, 0.85, 0.28, 0.96), }, }, }, { name: '09_linen-sepia-large', label: 'Linen · warm sepia gradients · everything LARGE · thickest strokes', overrides: { paperOverride: paper([226, 210, 178]), vignOverride: [80, 55, 30], featureOverride: [85, 55, 30], stroke: 3.4, // chunkiest of the set cubicScale: 1.65, schlegelScale: 1.55, e8Count: 3, e8Scale: 0.28, e8OriginRadius: 0.50, fields: { cubic: F(0.06, 0.12, 0.55, 0.30, 0.86), schlegel: F(0.10, 0.03, 0.45, 0.28, 0.70), e8: F(0.08, 0.16, 0.70, 0.36, 0.92), links: F(0.02, 0.12, 0.85, 0.30, 0.96), }, }, }, { name: '10_pearl-pastel-spectrum', label: 'Pearl · pastel rainbow (per-field hue families)', overrides: { paperOverride: paper([240, 235, 230]), vignOverride: [70, 65, 60], featureOverride: [80, 70, 60], stroke: 2.8, cubicScale: 1.50, schlegelScale: 1.40, e8Count: 3, e8Scale: 0.24, e8OriginRadius: 0.55, fields: { cubic: F(0.55, 0.70, 0.50, 0.42, 0.80), // cyan → violet pastel schlegel: F(0.08, 0.18, 0.45, 0.42, 0.62), // gold → yellow pastel e8: F(0.86, 0.04, 0.55, 0.42, 0.86), // pink → red pastel links: F(0.38, 0.55, 0.70, 0.40, 0.94), // green → cyan pastel }, }, }, ]; const base = paramsFromSeed(BASE_SEED); for (const v of variations) { const params = { ...base, ...v.overrides }; if (v.overrides.fields) params.fields = v.overrides.fields; const svg = renderQFTSVG(generateQFTScene(params), params, SIZE); const path = `${OUT_DIR}/${v.name}.svg`; writeFileSync(path, svg); console.log(`ok ${v.name} · ${v.label}`); } console.log(`\nrendered ${variations.length} variations → ${OUT_DIR}/`);