149 lines
4.9 KiB
JavaScript
149 lines
4.9 KiB
JavaScript
|
|
/* ============================================================
|
||
|
|
qft-variations-positions.mjs — sketch 03.
|
||
|
|
Hold the palette CONSTANT (per-field monochrome — each field
|
||
|
|
one clear hue so the eye can track its position) and vary
|
||
|
|
only origin / scale per field. Some fields deliberately
|
||
|
|
extend past the canvas edge (scale > 1).
|
||
|
|
Output → output/qft/sketch03/
|
||
|
|
============================================================ */
|
||
|
|
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 BASE_SEED = 'FEYNMAN-7167';
|
||
|
|
const OUT_DIR = 'output/qft/sketch03';
|
||
|
|
const SIZE = 1800;
|
||
|
|
mkdirSync(OUT_DIR, { recursive: true });
|
||
|
|
|
||
|
|
const F = (hueStart, hueEnd, saturation, lightness, opacity) =>
|
||
|
|
({ hueStart, hueEnd, saturation, lightness, opacity });
|
||
|
|
|
||
|
|
// HELD CONSTANT: per-field monochrome palette so each field's position is legible
|
||
|
|
// cyan cubic · magenta Schlegel · amber E8 · green cross-field links
|
||
|
|
const COLORS = {
|
||
|
|
cubic: F(0.55, 0.55, 0.55, 0.58, 0.72),
|
||
|
|
schlegel: F(0.88, 0.88, 0.55, 0.55, 0.68),
|
||
|
|
e8: F(0.12, 0.12, 0.75, 0.62, 0.92),
|
||
|
|
links: F(0.34, 0.34, 0.80, 0.55, 0.95),
|
||
|
|
};
|
||
|
|
const SUBSTRATE = 'vintage';
|
||
|
|
const BASE_OVERRIDES = { substrate: SUBSTRATE, gradientMode: 'along-edge', fields: COLORS };
|
||
|
|
|
||
|
|
const variations = [
|
||
|
|
{
|
||
|
|
name: '01_centered-reference',
|
||
|
|
label: 'Reference · everything centred at default scale',
|
||
|
|
overrides: {}, // no position/scale overrides — defaults
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: '02_cubic-left-schlegel-right',
|
||
|
|
label: 'Cubic to the left, Schlegel to the right',
|
||
|
|
overrides: {
|
||
|
|
cubicOriginX: -0.45, cubicOriginY: 0,
|
||
|
|
schlegelOriginX: 0.40, schlegelOriginY: 0,
|
||
|
|
e8Count: 3, e8OriginRadius: 0.30,
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: '03_huge-cubic-bleed',
|
||
|
|
label: 'Cubic blown up beyond the frame · others normal',
|
||
|
|
overrides: {
|
||
|
|
cubicScale: 1.85,
|
||
|
|
schlegelScale: 0.65,
|
||
|
|
e8Count: 3, e8Scale: 0.14, e8OriginRadius: 0.55,
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: '04_huge-schlegel-bleed',
|
||
|
|
label: 'Schlegel dominating · cube-in-cube extends past edges',
|
||
|
|
overrides: {
|
||
|
|
cubicScale: 0.45,
|
||
|
|
schlegelScale: 1.85,
|
||
|
|
e8Count: 2, e8Scale: 0.14, e8OriginRadius: 0.30,
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: '05_tiny-lots-of-paper',
|
||
|
|
label: 'Tiny lattices, lots of paper — a small island',
|
||
|
|
overrides: {
|
||
|
|
cubicScale: 0.42,
|
||
|
|
schlegelScale: 0.32,
|
||
|
|
e8Count: 2, e8Scale: 0.09, e8OriginRadius: 0.18,
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: '06_e8-cluster-lower-right',
|
||
|
|
label: 'A single large E8 cluster in the lower-right',
|
||
|
|
overrides: {
|
||
|
|
cubicScale: 0.85, cubicOriginX: -0.25, cubicOriginY: -0.20,
|
||
|
|
schlegelScale: 0.70, schlegelOriginX: -0.30, schlegelOriginY: -0.25,
|
||
|
|
e8Origins: [{ x: 0.45, y: 0.40, scale: 0.42 }],
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: '07_e8-quartet-at-corners',
|
||
|
|
label: 'Four E8 clusters near the corners',
|
||
|
|
overrides: {
|
||
|
|
cubicScale: 0.85,
|
||
|
|
schlegelScale: 0.70,
|
||
|
|
e8Origins: [
|
||
|
|
{ x: -0.65, y: -0.65, scale: 0.20 },
|
||
|
|
{ x: 0.65, y: -0.65, scale: 0.20 },
|
||
|
|
{ x: -0.65, y: 0.65, scale: 0.20 },
|
||
|
|
{ x: 0.65, y: 0.65, scale: 0.20 },
|
||
|
|
],
|
||
|
|
linkCount: 12,
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: '08_composition-shifted-upper-left',
|
||
|
|
label: 'Whole composition pushed to upper-left · negative space lower-right',
|
||
|
|
overrides: {
|
||
|
|
compositionOffsetX: -0.32, compositionOffsetY: -0.32,
|
||
|
|
cubicScale: 0.85, schlegelScale: 0.78,
|
||
|
|
e8Count: 3, e8Scale: 0.16, e8OriginRadius: 0.55,
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: '09_vertical-stack',
|
||
|
|
label: 'Vertical stack · cubic top, Schlegel middle, E8 bottom',
|
||
|
|
overrides: {
|
||
|
|
cubicScale: 0.55, cubicOriginX: 0, cubicOriginY: -0.45,
|
||
|
|
schlegelScale: 0.55, schlegelOriginX: 0, schlegelOriginY: 0,
|
||
|
|
e8Origins: [{ x: -0.25, y: 0.50, scale: 0.18 }, { x: 0.25, y: 0.50, scale: 0.18 }],
|
||
|
|
linkCount: 10,
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: '10_triptych-corners',
|
||
|
|
label: 'Triptych · each field in its own corner',
|
||
|
|
overrides: {
|
||
|
|
cubicScale: 0.55, cubicOriginX: -0.40, cubicOriginY: -0.40,
|
||
|
|
schlegelScale: 0.55, schlegelOriginX: 0.40, schlegelOriginY: -0.40,
|
||
|
|
e8Origins: [{ x: 0, y: 0.45, scale: 0.25 }],
|
||
|
|
linkCount: 12,
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: '11_inverse-scales',
|
||
|
|
label: 'Bonus · inverted scales (tiny cubic, giant Schlegel)',
|
||
|
|
overrides: {
|
||
|
|
cubicScale: 0.30,
|
||
|
|
schlegelScale: 1.70,
|
||
|
|
e8Count: 3, e8Scale: 0.20, e8OriginRadius: 0.65,
|
||
|
|
},
|
||
|
|
},
|
||
|
|
];
|
||
|
|
|
||
|
|
const base = paramsFromSeed(BASE_SEED);
|
||
|
|
for (const v of variations) {
|
||
|
|
const params = { ...base, ...BASE_OVERRIDES, ...v.overrides };
|
||
|
|
params.fields = COLORS;
|
||
|
|
const svg = renderQFTSVG(generateQFTScene(params), params, SIZE);
|
||
|
|
const path = `${OUT_DIR}/${v.name}.svg`;
|
||
|
|
writeFileSync(path, svg);
|
||
|
|
console.log(`ok ${v.name} · ${v.label}`);
|
||
|
|
}
|
||
|
|
console.log(`\nrendered ${variations.length} variations → ${OUT_DIR}/`);
|