web interface

This commit is contained in:
2026-06-02 19:17:19 -04:00
parent 52453fba67
commit 219eb6632c
140 changed files with 2793 additions and 40 deletions

61
tools/perspective4.mjs Normal file
View File

@@ -0,0 +1,61 @@
/* ============================================================
perspective4.mjs — Field 2 reborn as a STRAIGHT perspective floor
grid (one/two-point), through the grouped schema. Constructed space
receding to a vanishing point, under the decoupled sun + collision.
Usage: node tools/perspective4.mjs [size]
============================================================ */
import { writeFileSync, mkdirSync } from 'node:fs';
import { renderComposition } from '../src/compose/composition.js';
const SIZE = +(process.argv[2] || 1500);
const OUT = 'output/layering/perspective4';
mkdirSync(OUT, { recursive: true });
const D = Math.PI / 180;
const merge = (a, b) => { const o = { ...a }; for (const k in b) o[k] = (b[k] && typeof b[k] === 'object' && !Array.isArray(b[k])) ? merge(a[k] || {}, b[k]) : b[k]; return o; };
const BASE = {
size: SIZE, seed: 'MESON-5113',
background: { color: 'rgb(229,222,203)', film: { opacity: 0.6, density: 0.5, seed: 8 }, aging: { opacity: 0.5, scratches: 5, dust: 0.45, foxing: 0.5, seed: 5 }, grain: { opacity: 0.42, intensity: 0.42, seed: 19 } },
fieldSea: { enabled: true, transform: { x: 0, y: 0, rotation: 0, scale: 1 }, seed: 'VACUUM-5113', color: { hueBack: 0.54, hueFront: 0.47, sat: 0.6 }, layers: 3, blurPerLayer: [2.6, 1.1, 0], chaos: 0.3, blips: 0.7, mound: 0.3, horizonY: 0.36, lines: 46 },
fieldGrid: {
enabled: true, pos: 'over', style: 'floor', transform: { x: 0, y: 0, rotation: 0, scale: 1 },
color: { hue: 0.56, hue2: 0.5, sat: 0.26, lightNear: 0.32, lightFar: 0.64 }, opacity: 0.4,
pitch: 28 * D, yaw: 0, persp: 1.0, dist: 3.0, nx: 16, nz: 24, originY: 0.34,
ripple: { amp: 0 }, layers: 2, blurPerLayer: [1.1, 0],
},
disk: { enabled: true, transform: { x: 0, y: -0.26, rotation: 0, scale: 0.78 }, hue: 0.06, sat: 0.82, size: 0.16, pressure: 0.85 },
bubble: { enabled: true, transform: { x: 0.28, y: -0.1, rotation: 10, scale: 0.78 }, palette: 'magentarise', saturation: 1.05, primaries: 18, sweepers: 5, eloss: 0.34 },
fiduciaries: { enabled: true, label: 'No 001', pencil: '#39312a', width: 1.0, arrow: true },
};
const mk = (name, over) => ({ name, comp: merge(BASE, over) });
const V = [
// 1 — a floor receding to its OWN horizon, below the sea's: two horizons.
mk('01_second-horizon', { fieldGrid: { originY: 0.46, pitch: 22 * D, nz: 28, opacity: 0.4 }, bubble: { transform: { x: 0.3, y: -0.08 } } }),
// 2 — a two-point room: the event measured in built space.
mk('02_two-point-room', { fieldGrid: { yaw: 24 * D, pitch: 26 * D, dist: 2.8, opacity: 0.44 }, fiduciaries: { corners: true } }),
// 3 — the floor itself tilted (field-layer rotation) under a low sun.
mk('03_tilted-floor', { fieldGrid: { transform: { rotation: 9, scale: 1.05 }, pitch: 30 * D, opacity: 0.42 }, disk: { transform: { x: -0.04, y: -0.24 } }, bubble: { transform: { x: 0.26, y: -0.06, rotation: -6 } } }),
// 4 — ghost floor behind the sea: constructed space half-sunk.
mk('04_ghost-floor-behind', { fieldGrid: { pos: 'behind', opacity: 0.36, pitch: 24 * D, originY: 0.4 } }),
// 5 — steep tight tiles crowding toward a low vanishing point.
mk('05_steep-tiles', { fieldGrid: { pitch: 46 * D, dist: 2.4, nx: 14, nz: 20, originY: 0.2, opacity: 0.44 }, disk: { transform: { x: 0, y: 0.05, scale: 0.7 } }, bubble: { transform: { x: 0.22, y: 0.16 } } }),
// 6 — the floor breathes: a gentle ripple, still legibly a grid.
mk('06_gentle-rippled-floor', { fieldGrid: { ripple: { amp: 0.55, freqI: 0.5, freqK: 0.35, phase: 0.4 }, pitch: 26 * D, opacity: 0.42 } }),
// 7 — coordinate-system dwarfs the event: zoomed grid, tiny far ember.
mk('07_zoomed-grid-tiny-event', { fieldGrid: { transform: { scale: 1.45, x: -0.08 }, pitch: 24 * D, dist: 2.6, opacity: 0.42 }, disk: { transform: { x: 0.44, y: -0.4, scale: 0.42 }, hue: 0.0 }, bubble: { transform: { x: 0.4, y: -0.3, scale: 0.42 } }, fiduciaries: { from: [0.1, -0.2] } }),
// 8 — teal built-space, magenta event: cool/warm two-colour.
mk('08_teal-grid-magenta', { fieldGrid: { color: { hue: 0.5, hue2: 0.55, sat: 0.34, lightNear: 0.34, lightFar: 0.62 }, opacity: 0.46, pitch: 26 * D, yaw: 14 * D } }),
// 9 — two-point, vanishing off to the side; the event near the far VP.
mk('09_two-point-shifted', { fieldGrid: { yaw: -28 * D, pitch: 22 * D, originX: 0.18, dist: 2.6, opacity: 0.44 }, disk: { transform: { x: -0.35, y: -0.22, scale: 0.62 } }, bubble: { transform: { x: 0.34, y: -0.04 } }, fiduciaries: { from: [-0.3, -0.34] } }),
// 10 — the floor dissolving into the paper: a warm near-blank coordinate ghost.
mk('10_dissolving-floor', { fieldGrid: { color: { hue: 0.1, hue2: 0.08, sat: 0.16, lightNear: 0.46, lightFar: 0.68 }, opacity: 0.3, pitch: 20 * D, nz: 30, originY: 0.42 }, disk: { hue: 0.04 } }),
];
console.log(`perspective4 — straight floor grid · ${V.length} schema comps → ${OUT}/`);
for (const v of V) { writeFileSync(`${OUT}/${v.name}.svg`, renderComposition(v.comp, SIZE)); console.log(` ${v.name}`); }
const cap = (v) => v.name.replace(/^\d+_/, '').replace(/-/g, ' ');
writeFileSync(`${OUT}/m.html`, `<!DOCTYPE html><html><head><meta charset="utf-8"><title>perspective4 · straight floor grid</title>
<style>html,body{margin:0;background:#1a1a1a}.grid{display:grid;grid-template-columns:repeat(2,1fr);gap:8px;padding:10px;width:2400px}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:14px ui-monospace,monospace;color:#fff;background:linear-gradient(transparent,#000d)}</style></head><body>
<div class="grid">${V.map(v => `<figure><img src="${v.name}.svg"><figcaption>${cap(v)}</figcaption></figure>`).join('')}</div></body></html>`);
console.log(`-> ${OUT}/m.html`);