72 lines
4.2 KiB
JavaScript
72 lines
4.2 KiB
JavaScript
/* ============================================================
|
|
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`);
|