/* ============================================================ qft-infinite-sweep.mjs — workshop the cartesian grid as INFINITE space: wide/deep/shallow slabs + camera pushed into the lattice + exaggerated perspective, so the field bleeds off every edge and rushes to a vanishing point rather than reading as a closed cube. Usage: node tools/qft-infinite-sweep.mjs [size] ============================================================ */ 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 SIZE = +(process.argv[2] || 1200); const OUT = 'output/qft/infinite'; mkdirSync(OUT, { recursive: true }); const SEED = 'LATTICE-1003'; const D = Math.PI / 180; const F = (h0, h1, s, l, o, st) => ({ hueStart: h0, hueEnd: h1, saturation: s, lightness: l, opacity: o, stroke: st }); const OFF = F(0, 0, 0, 0.5, 0, 0); const BASE = { substrate: 'cream', showHeader: false, glow: 0.16, vign: 0.14, photonCyclesPerUnit: 6, segmentsPerEdge: 10, stroke: 1.0, cubicRot: 0, linkCount: 0, e8Count: 0, fields: { cubic: F(0.52, 0.57, 0.6, 0.38, 1.0, 1.0), schlegel: OFF, e8: OFF, ripple: OFF, links: OFF }, }; // each: nx/ny/nz extents, camera, scale, originY (vertical placement) const V = (name, label, o) => ({ name, label, o }); const SWEEP = [ V('01_floor-to-horizon', 'flat floor · low pitch · rushes to a horizon', { nx: 9, ny: 0, nz: 20, yaw: 0, pitch: 13 * D, persp: 1.4, dist: 1.6, scale: 1.0, oy: 0.28 }), V('02_floor-three-quarter', 'floor · 3/4 view · vanishing to the side', { nx: 11, ny: 0, nz: 18, yaw: -26 * D, pitch: 18 * D, persp: 1.25, dist: 1.9, scale: 0.9, oy: 0.22 }), V('03_tunnel-inside', 'camera INSIDE · walls/floor/ceiling rush inward', { nx: 4, ny: 4, nz: 18, yaw: 0, pitch: 0, persp: 1.5, dist: 1.5, zShift: 7, scale: 0.62, oy: 0 }), V('04_corridor-3q', 'corridor · slight angle · one-point-ish', { nx: 5, ny: 3, nz: 18, yaw: -18 * D, pitch: 7 * D, persp: 1.4, dist: 1.7, zShift: 3, scale: 0.72, oy: 0.05 }), V('05_exaggerated-bleed', 'full lattice · strong persp · near corner blows off-page', { nx: 5, ny: 5, nz: 6, yaw: -40 * D, pitch: 30 * D, persp: 1.7, dist: 1.25, scale: 0.8, oy: 0 }), V('06_diagonal-rush', 'diagonal rush across the frame', { nx: 9, ny: 2, nz: 18, yaw: 33 * D, pitch: 22 * D, persp: 1.5, dist: 1.55, scale: 0.82, oy: 0.05 }), V('07_vaulted-ceiling', 'looking UP · ceiling lattice vaulting away', { nx: 9, ny: 0, nz: 18, yaw: 0, pitch: -15 * D, persp: 1.35, dist: 1.7, scale: 1.0, oy: -0.26 }), V('08_deep-floor-strong', 'widest, deepest floor · strongest vanishing', { nx: 13, ny: 0, nz: 24, yaw: 0, pitch: 10 * D, persp: 1.6, dist: 1.35, scale: 1.0, oy: 0.3 }), ]; console.log(`Infinite-field sweep (${SWEEP.length}) → ${OUT}/ seed=${SEED}`); for (const v of SWEEP) { const o = v.o; const p = { ...paramsFromSeed(SEED), ...BASE, cubicNx: o.nx, cubicNy: o.ny, cubicNz: o.nz, cubicYaw: o.yaw ?? 0, cubicPitch: o.pitch ?? 0, cubicRoll: o.roll ?? 0, cubicPersp: o.persp ?? 0, cubicDist: o.dist ?? 3.4, cubicZShift: o.zShift ?? 0, cubicScale: o.scale ?? 1.0, cubicOriginX: o.ox ?? 0, cubicOriginY: o.oy ?? 0, }; writeFileSync(`${OUT}/${v.name}.svg`, renderQFTSVG(generateQFTScene(p), p, SIZE)); console.log(` ${v.name} — ${v.label}`); } const cap = (v) => `${v.name.replace(/^\d+_/, '').replace(/-/g, ' ')} · ${v.label}`; const m = `
${SWEEP.map(v => `
${cap(v)}
`).join('\n')}
`; writeFileSync(`${OUT}/m.html`, m); console.log(`contact sheet -> ${OUT}/m.html`);