36 lines
3.7 KiB
JavaScript
36 lines
3.7 KiB
JavaScript
|
|
/* qft-perspgrid.mjs — sweep the perspective depth grid (VP off-horizon),
|
||
|
|
plus a dual blur/fine plate deck. Usage: node tools/qft-perspgrid.mjs [size] */
|
||
|
|
import { writeFileSync, mkdirSync } from 'node:fs';
|
||
|
|
import { perspectiveGridSVG } from '../src/qft/perspgrid.js';
|
||
|
|
|
||
|
|
const SIZE = +(process.argv[2] || 1400);
|
||
|
|
const ROOT = 'output/qft/perspgrid';
|
||
|
|
mkdirSync(`${ROOT}/explore`, { recursive: true });
|
||
|
|
mkdirSync(`${ROOT}/deck`, { recursive: true });
|
||
|
|
const D = Math.PI / 180;
|
||
|
|
|
||
|
|
const EXPLORE = [
|
||
|
|
{ name: '01_center-funnel', label: 'VP centre · full radial funnel', o: { vp: [0, 0], spread: Math.PI * 2, rays: 30, depthLines: 16 } },
|
||
|
|
{ name: '02_high-vp-fan', label: 'VP high (sky) · fan downward', o: { vp: [0, -0.55], dir: 95 * D, spread: 150 * D, rays: 26 } },
|
||
|
|
{ name: '03_low-vp-into-sea', label: 'VP low (in the sea) · fan upward', o: { vp: [0, 0.5], dir: -90 * D, spread: 150 * D, rays: 26 } },
|
||
|
|
{ name: '04_corner-upper-left', label: 'VP off-frame upper-left · diagonal', o: { vp: [-1.3, -1.1], dir: 35 * D, spread: 60 * D, rays: 22, rMax: 3.4 } },
|
||
|
|
{ name: '05_offright-corridor', label: 'VP off-frame right · corridor', o: { vp: [1.4, -0.1], dir: 178 * D, spread: 70 * D, rays: 22, rMax: 3.2 } },
|
||
|
|
{ name: '06_center-tight-tunnel', label: 'VP centre · tight crowded tunnel', o: { vp: [0.1, -0.1], spread: Math.PI * 2, rays: 40, depthLines: 22, depthPow: 3.0 } },
|
||
|
|
{ name: '07_upper-cone-wide', label: 'VP upper · wide shallow cone', o: { vp: [0.2, -0.8], dir: 100 * D, spread: 120 * D, rays: 24, depthPow: 1.8 } },
|
||
|
|
{ name: '08_teal-mandala', label: 'VP centre · teal radial mandala-grid', o: { vp: [0, -0.05], spread: Math.PI * 2, rays: 36, depthLines: 18, hue: 0.5, hue2: 0.55, sat: 0.5 } },
|
||
|
|
];
|
||
|
|
console.log(`perspgrid · explore (${EXPLORE.length}) → ${ROOT}/explore/`);
|
||
|
|
for (const v of EXPLORE) { writeFileSync(`${ROOT}/explore/${v.name}.svg`, perspectiveGridSVG(SIZE, { ...v.o, mode: 'solid' })); console.log(` ${v.name} — ${v.label}`); }
|
||
|
|
writeFileSync(`${ROOT}/explore/m.html`, `<!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:2100px}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">${EXPLORE.map(v => `<figure><img src="${v.name}.svg"><figcaption>${v.name.replace(/^\d+_/, '').replace(/-/g, ' ')} · ${v.label}</figcaption></figure>`).join('')}</div></body></html>`);
|
||
|
|
|
||
|
|
// dual deck: back (thick, will be blurred in composite) + front (fine, crisp), VP slightly nudged → parallax
|
||
|
|
const deckBase = { mode: 'plate', vp: [0.05, -0.12], spread: 150 * D, dir: 95 * D, rays: 26, depthLines: 16, hue: 0.55, hue2: 0.5, sat: 0.45 };
|
||
|
|
writeFileSync(`${ROOT}/deck/P2_back.svg`, perspectiveGridSVG(SIZE, { ...deckBase, salt: 'pA', stroke: 2.2, strokeFar: 0.8, vp: [0.02, -0.14] }));
|
||
|
|
writeFileSync(`${ROOT}/deck/P1_front.svg`, perspectiveGridSVG(SIZE, { ...deckBase, salt: 'pB', stroke: 1.0, strokeFar: 0.36, vp: [0.08, -0.10] }));
|
||
|
|
writeFileSync(`${ROOT}/deck/stack.html`, `<!DOCTYPE html><html><head><meta charset="utf-8">
|
||
|
|
<style>html,body{margin:0;background:#0c0c0c}.stage{position:relative;width:${SIZE}px;height:${SIZE}px;margin:24px auto;background:rgb(226,219,199)}.stage img{position:absolute;inset:0;width:100%;height:100%}.b{filter:blur(2.2px);opacity:.55}.f{opacity:.95}</style></head><body>
|
||
|
|
<div class="stage"><img class="b" src="P2_back.svg"><img class="f" src="P1_front.svg"></div></body></html>`);
|
||
|
|
console.log(`deck -> ${ROOT}/deck/stack.html ; explore -> ${ROOT}/explore/m.html`);
|