/* ============================================================ qft-variations-fine.mjs — sketch 05. Two new mechanics exercised: (a) DENSER cubic mesh (cubicN=2 → 125 vertices / ~300 edges) + finer photon waves (photonCyclesPerUnit ↑) → "even finer oscillating sub-grid with each line another hue in a gradient" (b) LARGER softer rosettes — E8 cluster scaled 0.55–0.85 with lightness pushed ABOVE the paper's lightness and opacity dropped to 0.35–0.55 → the rosette becomes a soft luminous halo rather than a focal jewel. Plus fewer / dimmer cross-field links so they punctuate instead of dominate. Output → output/qft/sketch05/ ============================================================ */ 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/sketch05'; const SIZE = 1800; mkdirSync(OUT_DIR, { recursive: true }); const F = (hueStart, hueEnd, saturation, lightness, opacity) => ({ hueStart, hueEnd, saturation, lightness, opacity }); 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]], }); // shared base for the new sketches // Dense cubic (300 edges) needs MUCH thinner strokes than sketch04, otherwise it // piles into solid wallpaper and buries the soft rosettes. Stroke 1.0 + cubic // opacity ~0.45 leaves room for the rosette + schlegel to read. const FINE_BASE = { cubicN: 2, // 5³=125 vertices / ~300 edges photonCyclesPerUnit: 22, // finer waves than default (12) segmentsPerEdge: 10, linkCount: 5, // fewer cross-field links (was 8) stroke: 1.0, // thin so the dense mesh stays atmospheric, not opaque }; const variations = [ { name: '01_spectral-comb-pearl', label: 'Spectral comb · pearl · dense cubic + radial spectrum + soft rosette', overrides: { ...FINE_BASE, paperOverride: paper([240, 235, 230]), vignOverride: [80, 70, 65], featureOverride: [80, 70, 60], gradientMode: 'radial', cubicScale: 1.40, schlegelScale: 0, // no schlegel — let cubic + rosette breathe e8Origins: [{ x: 0, y: 0, scale: 0.72 }], // single large central rosette fields: { cubic: F(0.55, 0.04, 0.65, 0.45, 0.30), // cool centre → warm corners schlegel: F(0, 0, 0, 0.5, 0), // off e8: F(0.55, 0.08, 0.55, 0.48, 0.85), // very pale tinted-white halo (L > paper) links: F(0.04, 0.10, 0.55, 0.45, 0.55), // dim warm links }, }, }, { name: '02_dense-radial-cream', label: 'Dense radial spectrum · cream · large pale rosette', overrides: { ...FINE_BASE, substrate: 'cream', gradientMode: 'radial', cubicScale: 1.55, schlegelScale: 0.85, e8Origins: [{ x: 0, y: 0, scale: 0.78 }], fields: { cubic: F(0.58, 0.05, 0.70, 0.40, 0.30), schlegel: F(0.10, 0.05, 0.35, 0.45, 0.55), e8: F(0.08, 0.04, 0.55, 0.48, 0.85), // pale warm halo on cream links: F(0.05, 0.10, 0.60, 0.45, 0.55), }, }, }, { name: '03_linear-horizon-ivory', label: 'Linear horizon · ivory · dense cubic with left→right gradient', overrides: { ...FINE_BASE, paperOverride: paper([232, 224, 202]), vignOverride: [70, 55, 40], featureOverride: [60, 50, 35], gradientMode: 'linear-x', cubicScale: 1.65, schlegelScale: 0.90, e8Origins: [{ x: -0.35, y: 0.25, scale: 0.55 }, { x: 0.35, y: 0.25, scale: 0.55 }], // twin pale rosettes lower fields: { cubic: F(0.58, 0.04, 0.65, 0.36, 0.30), schlegel: F(0.60, 0.08, 0.40, 0.40, 0.55), e8: F(0.55, 0.10, 0.55, 0.48, 0.85), links: F(0.06, 0.12, 0.60, 0.40, 0.55), }, }, }, { name: '04_twin-rosettes-mauve', label: 'Twin overlapping rosettes · pale mauve · soft & atmospheric', overrides: { ...FINE_BASE, paperOverride: paper([222, 205, 224]), vignOverride: [55, 35, 60], featureOverride: [75, 50, 90], gradientMode: 'along-edge', cubicScale: 1.45, schlegelScale: 0, // no schlegel e8Origins: [{ x: -0.20, y: 0, scale: 0.65 }, { x: 0.20, y: 0, scale: 0.65 }], fields: { cubic: F(0.72, 0.92, 0.55, 0.38, 0.30), schlegel: F(0, 0, 0, 0.5, 0), e8: F(0.78, 0.92, 0.55, 0.48, 0.85), // pale lighter-than-mauve glow links: F(0.82, 0.95, 0.65, 0.40, 0.55), }, }, }, { name: '05_finest-waves-linen', label: 'Finest photon waves · linen · super-dense cubic + soft halo', overrides: { ...FINE_BASE, paperOverride: paper([225, 210, 178]), vignOverride: [85, 60, 35], featureOverride: [80, 55, 30], photonCyclesPerUnit: 30, // even finer ripples than the FINE_BASE cubicScale: 1.50, schlegelScale: 0.75, e8Origins: [{ x: 0, y: 0, scale: 0.82 }], fields: { cubic: F(0.08, 0.14, 0.60, 0.35, 0.30), schlegel: F(0.04, 0.10, 0.40, 0.35, 0.55), e8: F(0.10, 0.06, 0.55, 0.48, 0.85), links: F(0.06, 0.10, 0.60, 0.40, 0.55), }, }, }, { name: '06_big-mandala-pale-blue', label: 'Big central mandala · pale blue · single huge rosette', overrides: { ...FINE_BASE, paperOverride: paper([190, 215, 230]), vignOverride: [40, 55, 70], featureOverride: [30, 50, 75], gradientMode: 'radial', cubicScale: 1.50, schlegelScale: 0.80, e8Origins: [{ x: 0, y: 0, scale: 0.92 }], // very large central rosette fields: { cubic: F(0.60, 0.66, 0.65, 0.25, 0.30), schlegel: F(0.58, 0.62, 0.45, 0.28, 0.55), e8: F(0.55, 0.65, 0.55, 0.48, 0.85), // near-white tinted-blue halo links: F(0.58, 0.66, 0.65, 0.32, 0.55), }, }, }, { name: '07_dense-ghostly-schlegel-bone', label: 'Dense cubic + ghostly large Schlegel · bone china', overrides: { ...FINE_BASE, paperOverride: paper([234, 230, 222]), vignOverride: [80, 70, 60], featureOverride: [70, 60, 50], gradientMode: 'radial', cubicScale: 1.55, schlegelScale: 1.85, // big BUT... e8Origins: [{ x: 0, y: 0, scale: 0.72 }], fields: { cubic: F(0.55, 0.05, 0.65, 0.38, 0.30), schlegel: F(0.62, 0.10, 0.25, 0.92, 0.35), // ...made ghostly: pale + low opacity e8: F(0.10, 0.06, 0.55, 0.48, 0.85), links: F(0.06, 0.10, 0.55, 0.40, 0.50), }, }, }, { name: '08_atmospheric-mint', label: 'Atmospheric · pale mint · large soft rosette dominant', overrides: { ...FINE_BASE, paperOverride: paper([210, 225, 208]), vignOverride: [30, 55, 35], featureOverride: [40, 70, 45], stroke: 1.6, // thinner — let the rosette breathe cubicScale: 1.30, schlegelScale: 0, e8Origins: [{ x: 0, y: 0, scale: 0.85 }], fields: { cubic: F(0.42, 0.50, 0.45, 0.36, 0.30), schlegel: F(0, 0, 0, 0.5, 0), e8: F(0.40, 0.50, 0.55, 0.48, 0.85), links: F(0.12, 0.18, 0.55, 0.42, 0.55), }, }, }, { name: '09_all-dense-layered-pearl', label: 'Everything dense and layered · pearl · 4 rosettes, full spectrum', overrides: { ...FINE_BASE, paperOverride: paper([240, 235, 230]), vignOverride: [80, 70, 65], featureOverride: [80, 70, 60], gradientMode: 'radial', cubicScale: 1.60, schlegelScale: 1.20, e8Origins: [ { x: -0.30, y: -0.30, scale: 0.42 }, { x: 0.30, y: -0.30, scale: 0.42 }, { x: -0.30, y: 0.30, scale: 0.42 }, { x: 0.30, y: 0.30, scale: 0.42 }, ], linkCount: 8, fields: { cubic: F(0.55, 0.05, 0.65, 0.40, 0.30), schlegel: F(0.58, 0.10, 0.35, 0.42, 0.55), e8: F(0.55, 0.08, 0.55, 0.48, 0.85), links: F(0.06, 0.10, 0.55, 0.42, 0.55), }, }, }, { name: '10_concentric-rosettes-pale-rose', label: 'Concentric nested rosettes · pale rose · all centred', overrides: { ...FINE_BASE, paperOverride: paper([232, 210, 210]), vignOverride: [80, 55, 55], featureOverride: [90, 55, 55], gradientMode: 'radial', cubicScale: 1.30, schlegelScale: 0, e8Origins: [ { x: 0, y: 0, scale: 0.95 }, // outermost { x: 0, y: 0, scale: 0.62 }, // middle { x: 0, y: 0, scale: 0.30 }, // innermost ], linkCount: 0, // no links — the nested rosettes are the picture fields: { cubic: F(0.95, 0.03, 0.55, 0.38, 0.30), schlegel: F(0, 0, 0, 0.5, 0), e8: F(0.92, 0.05, 0.55, 0.48, 0.85), links: F(0.9, 0.05, 0.55, 0.42, 0.50), }, }, }, ]; 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}/`);