Files
bubblechambersimart/tools/qft-infinite-sweep.mjs

72 lines
4.2 KiB
JavaScript
Raw Normal View History

/* ============================================================
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 = `<!DOCTYPE html><html><head><meta charset="utf-8">
<style>html,body{margin:0;background:#222}.grid{display:grid;grid-template-columns:repeat(2,1fr);gap:8px;padding:10px;width:2000px}figure{margin:0;position:relative;background:#fff;overflow:hidden}img{width:100%;display:block}figcaption{position:absolute;left:0;bottom:0;right:0;padding:6px 10px;font:13px ui-monospace,monospace;color:#fff;background:linear-gradient(transparent,#000d)}</style></head><body>
<div class="grid">
${SWEEP.map(v => `<figure><img src="${v.name}.svg"><figcaption>${cap(v)}</figcaption></figure>`).join('\n')}
</div></body></html>`;
writeFileSync(`${OUT}/m.html`, m);
console.log(`contact sheet -> ${OUT}/m.html`);