252 lines
9.6 KiB
JavaScript
252 lines
9.6 KiB
JavaScript
/* ============================================================
|
||
qft-variations-fine.mjs — sketch 05.
|
||
Two new mechanics exercised:
|
||
(a) DENSER cubic mesh (cubicN=2 → 125 vertices / ~300 edges)
|
||
+ finer photon waves (photonCyclesPerUnit ↑) → "even
|
||
finer oscillating sub-grid with each line another hue
|
||
in a gradient"
|
||
(b) LARGER softer rosettes — E8 cluster scaled 0.55–0.85
|
||
with lightness pushed ABOVE the paper's lightness and
|
||
opacity dropped to 0.35–0.55 → the rosette becomes a
|
||
soft luminous halo rather than a focal jewel.
|
||
Plus fewer / dimmer cross-field links so they punctuate
|
||
instead of dominate.
|
||
Output → output/qft/sketch05/
|
||
============================================================ */
|
||
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/sketch05';
|
||
const SIZE = 1800;
|
||
mkdirSync(OUT_DIR, { recursive: true });
|
||
|
||
const F = (hueStart, hueEnd, saturation, lightness, opacity) =>
|
||
({ hueStart, hueEnd, saturation, lightness, opacity });
|
||
|
||
const paper = (flat, glowInDelta = [18, 16, 14], glowOutDelta = [-25, -22, -20]) => ({
|
||
flat,
|
||
glowIn: [flat[0] + glowInDelta[0], flat[1] + glowInDelta[1], flat[2] + glowInDelta[2]],
|
||
glowOut: [flat[0] + glowOutDelta[0], flat[1] + glowOutDelta[1], flat[2] + glowOutDelta[2]],
|
||
});
|
||
|
||
// shared base for the new sketches
|
||
// Dense cubic (300 edges) needs MUCH thinner strokes than sketch04, otherwise it
|
||
// piles into solid wallpaper and buries the soft rosettes. Stroke 1.0 + cubic
|
||
// opacity ~0.45 leaves room for the rosette + schlegel to read.
|
||
const FINE_BASE = {
|
||
cubicN: 2, // 5³=125 vertices / ~300 edges
|
||
photonCyclesPerUnit: 22, // finer waves than default (12)
|
||
segmentsPerEdge: 10,
|
||
linkCount: 5, // fewer cross-field links (was 8)
|
||
stroke: 1.0, // thin so the dense mesh stays atmospheric, not opaque
|
||
};
|
||
|
||
const variations = [
|
||
{
|
||
name: '01_spectral-comb-pearl',
|
||
label: 'Spectral comb · pearl · dense cubic + radial spectrum + soft rosette',
|
||
overrides: {
|
||
...FINE_BASE,
|
||
paperOverride: paper([240, 235, 230]),
|
||
vignOverride: [80, 70, 65], featureOverride: [80, 70, 60],
|
||
gradientMode: 'radial',
|
||
cubicScale: 1.40, schlegelScale: 0, // no schlegel — let cubic + rosette breathe
|
||
e8Origins: [{ x: 0, y: 0, scale: 0.72 }], // single large central rosette
|
||
fields: {
|
||
cubic: F(0.55, 0.04, 0.65, 0.45, 0.30), // cool centre → warm corners
|
||
schlegel: F(0, 0, 0, 0.5, 0), // off
|
||
e8: F(0.55, 0.08, 0.55, 0.48, 0.85), // very pale tinted-white halo (L > paper)
|
||
links: F(0.04, 0.10, 0.55, 0.45, 0.55), // dim warm links
|
||
},
|
||
},
|
||
},
|
||
{
|
||
name: '02_dense-radial-cream',
|
||
label: 'Dense radial spectrum · cream · large pale rosette',
|
||
overrides: {
|
||
...FINE_BASE,
|
||
substrate: 'cream',
|
||
gradientMode: 'radial',
|
||
cubicScale: 1.55, schlegelScale: 0.85,
|
||
e8Origins: [{ x: 0, y: 0, scale: 0.78 }],
|
||
fields: {
|
||
cubic: F(0.58, 0.05, 0.70, 0.40, 0.30),
|
||
schlegel: F(0.10, 0.05, 0.35, 0.45, 0.55),
|
||
e8: F(0.08, 0.04, 0.55, 0.48, 0.85), // pale warm halo on cream
|
||
links: F(0.05, 0.10, 0.60, 0.45, 0.55),
|
||
},
|
||
},
|
||
},
|
||
{
|
||
name: '03_linear-horizon-ivory',
|
||
label: 'Linear horizon · ivory · dense cubic with left→right gradient',
|
||
overrides: {
|
||
...FINE_BASE,
|
||
paperOverride: paper([232, 224, 202]),
|
||
vignOverride: [70, 55, 40], featureOverride: [60, 50, 35],
|
||
gradientMode: 'linear-x',
|
||
cubicScale: 1.65, schlegelScale: 0.90,
|
||
e8Origins: [{ x: -0.35, y: 0.25, scale: 0.55 },
|
||
{ x: 0.35, y: 0.25, scale: 0.55 }], // twin pale rosettes lower
|
||
fields: {
|
||
cubic: F(0.58, 0.04, 0.65, 0.36, 0.30),
|
||
schlegel: F(0.60, 0.08, 0.40, 0.40, 0.55),
|
||
e8: F(0.55, 0.10, 0.55, 0.48, 0.85),
|
||
links: F(0.06, 0.12, 0.60, 0.40, 0.55),
|
||
},
|
||
},
|
||
},
|
||
{
|
||
name: '04_twin-rosettes-mauve',
|
||
label: 'Twin overlapping rosettes · pale mauve · soft & atmospheric',
|
||
overrides: {
|
||
...FINE_BASE,
|
||
paperOverride: paper([222, 205, 224]),
|
||
vignOverride: [55, 35, 60], featureOverride: [75, 50, 90],
|
||
gradientMode: 'along-edge',
|
||
cubicScale: 1.45, schlegelScale: 0, // no schlegel
|
||
e8Origins: [{ x: -0.20, y: 0, scale: 0.65 },
|
||
{ x: 0.20, y: 0, scale: 0.65 }],
|
||
fields: {
|
||
cubic: F(0.72, 0.92, 0.55, 0.38, 0.30),
|
||
schlegel: F(0, 0, 0, 0.5, 0),
|
||
e8: F(0.78, 0.92, 0.55, 0.48, 0.85), // pale lighter-than-mauve glow
|
||
links: F(0.82, 0.95, 0.65, 0.40, 0.55),
|
||
},
|
||
},
|
||
},
|
||
{
|
||
name: '05_finest-waves-linen',
|
||
label: 'Finest photon waves · linen · super-dense cubic + soft halo',
|
||
overrides: {
|
||
...FINE_BASE,
|
||
paperOverride: paper([225, 210, 178]),
|
||
vignOverride: [85, 60, 35], featureOverride: [80, 55, 30],
|
||
photonCyclesPerUnit: 30, // even finer ripples than the FINE_BASE
|
||
cubicScale: 1.50, schlegelScale: 0.75,
|
||
e8Origins: [{ x: 0, y: 0, scale: 0.82 }],
|
||
fields: {
|
||
cubic: F(0.08, 0.14, 0.60, 0.35, 0.30),
|
||
schlegel: F(0.04, 0.10, 0.40, 0.35, 0.55),
|
||
e8: F(0.10, 0.06, 0.55, 0.48, 0.85),
|
||
links: F(0.06, 0.10, 0.60, 0.40, 0.55),
|
||
},
|
||
},
|
||
},
|
||
{
|
||
name: '06_big-mandala-pale-blue',
|
||
label: 'Big central mandala · pale blue · single huge rosette',
|
||
overrides: {
|
||
...FINE_BASE,
|
||
paperOverride: paper([190, 215, 230]),
|
||
vignOverride: [40, 55, 70], featureOverride: [30, 50, 75],
|
||
gradientMode: 'radial',
|
||
cubicScale: 1.50, schlegelScale: 0.80,
|
||
e8Origins: [{ x: 0, y: 0, scale: 0.92 }], // very large central rosette
|
||
fields: {
|
||
cubic: F(0.60, 0.66, 0.65, 0.25, 0.30),
|
||
schlegel: F(0.58, 0.62, 0.45, 0.28, 0.55),
|
||
e8: F(0.55, 0.65, 0.55, 0.48, 0.85), // near-white tinted-blue halo
|
||
links: F(0.58, 0.66, 0.65, 0.32, 0.55),
|
||
},
|
||
},
|
||
},
|
||
{
|
||
name: '07_dense-ghostly-schlegel-bone',
|
||
label: 'Dense cubic + ghostly large Schlegel · bone china',
|
||
overrides: {
|
||
...FINE_BASE,
|
||
paperOverride: paper([234, 230, 222]),
|
||
vignOverride: [80, 70, 60], featureOverride: [70, 60, 50],
|
||
gradientMode: 'radial',
|
||
cubicScale: 1.55, schlegelScale: 1.85, // big BUT...
|
||
e8Origins: [{ x: 0, y: 0, scale: 0.72 }],
|
||
fields: {
|
||
cubic: F(0.55, 0.05, 0.65, 0.38, 0.30),
|
||
schlegel: F(0.62, 0.10, 0.25, 0.92, 0.35), // ...made ghostly: pale + low opacity
|
||
e8: F(0.10, 0.06, 0.55, 0.48, 0.85),
|
||
links: F(0.06, 0.10, 0.55, 0.40, 0.50),
|
||
},
|
||
},
|
||
},
|
||
{
|
||
name: '08_atmospheric-mint',
|
||
label: 'Atmospheric · pale mint · large soft rosette dominant',
|
||
overrides: {
|
||
...FINE_BASE,
|
||
paperOverride: paper([210, 225, 208]),
|
||
vignOverride: [30, 55, 35], featureOverride: [40, 70, 45],
|
||
stroke: 1.6, // thinner — let the rosette breathe
|
||
cubicScale: 1.30, schlegelScale: 0,
|
||
e8Origins: [{ x: 0, y: 0, scale: 0.85 }],
|
||
fields: {
|
||
cubic: F(0.42, 0.50, 0.45, 0.36, 0.30),
|
||
schlegel: F(0, 0, 0, 0.5, 0),
|
||
e8: F(0.40, 0.50, 0.55, 0.48, 0.85),
|
||
links: F(0.12, 0.18, 0.55, 0.42, 0.55),
|
||
},
|
||
},
|
||
},
|
||
{
|
||
name: '09_all-dense-layered-pearl',
|
||
label: 'Everything dense and layered · pearl · 4 rosettes, full spectrum',
|
||
overrides: {
|
||
...FINE_BASE,
|
||
paperOverride: paper([240, 235, 230]),
|
||
vignOverride: [80, 70, 65], featureOverride: [80, 70, 60],
|
||
gradientMode: 'radial',
|
||
cubicScale: 1.60, schlegelScale: 1.20,
|
||
e8Origins: [
|
||
{ x: -0.30, y: -0.30, scale: 0.42 },
|
||
{ x: 0.30, y: -0.30, scale: 0.42 },
|
||
{ x: -0.30, y: 0.30, scale: 0.42 },
|
||
{ x: 0.30, y: 0.30, scale: 0.42 },
|
||
],
|
||
linkCount: 8,
|
||
fields: {
|
||
cubic: F(0.55, 0.05, 0.65, 0.40, 0.30),
|
||
schlegel: F(0.58, 0.10, 0.35, 0.42, 0.55),
|
||
e8: F(0.55, 0.08, 0.55, 0.48, 0.85),
|
||
links: F(0.06, 0.10, 0.55, 0.42, 0.55),
|
||
},
|
||
},
|
||
},
|
||
{
|
||
name: '10_concentric-rosettes-pale-rose',
|
||
label: 'Concentric nested rosettes · pale rose · all centred',
|
||
overrides: {
|
||
...FINE_BASE,
|
||
paperOverride: paper([232, 210, 210]),
|
||
vignOverride: [80, 55, 55], featureOverride: [90, 55, 55],
|
||
gradientMode: 'radial',
|
||
cubicScale: 1.30, schlegelScale: 0,
|
||
e8Origins: [
|
||
{ x: 0, y: 0, scale: 0.95 }, // outermost
|
||
{ x: 0, y: 0, scale: 0.62 }, // middle
|
||
{ x: 0, y: 0, scale: 0.30 }, // innermost
|
||
],
|
||
linkCount: 0, // no links — the nested rosettes are the picture
|
||
fields: {
|
||
cubic: F(0.95, 0.03, 0.55, 0.38, 0.30),
|
||
schlegel: F(0, 0, 0, 0.5, 0),
|
||
e8: F(0.92, 0.05, 0.55, 0.48, 0.85),
|
||
links: F(0.9, 0.05, 0.55, 0.42, 0.50),
|
||
},
|
||
},
|
||
},
|
||
];
|
||
|
||
const base = paramsFromSeed(BASE_SEED);
|
||
for (const v of variations) {
|
||
const params = { ...base, ...v.overrides };
|
||
if (v.overrides.fields) params.fields = v.overrides.fields;
|
||
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}/`);
|