170 lines
6.0 KiB
JavaScript
170 lines
6.0 KiB
JavaScript
|
|
/* ============================================================
|
||
|
|
qft-variations.mjs — render a curated set of variations.
|
||
|
|
Single base seed (geometry held constant); each variation
|
||
|
|
overrides per-field hue / sat / light / opacity + gradient mode
|
||
|
|
+ substrate (or arbitrary paperOverride RGB) + cross-field
|
||
|
|
link colours.
|
||
|
|
Output → output/qft/sketch02/
|
||
|
|
============================================================ */
|
||
|
|
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/sketch02';
|
||
|
|
const SIZE = 1800;
|
||
|
|
mkdirSync(OUT_DIR, { recursive: true });
|
||
|
|
|
||
|
|
const F = (hueStart, hueEnd, saturation, lightness, opacity) =>
|
||
|
|
({ hueStart, hueEnd, saturation, lightness, opacity });
|
||
|
|
|
||
|
|
const variations = [
|
||
|
|
{
|
||
|
|
name: '01_anchor-vintage', label: 'Anchor · warm vintage muted',
|
||
|
|
overrides: {
|
||
|
|
substrate: 'vintage', gradientMode: 'along-edge',
|
||
|
|
fields: {
|
||
|
|
cubic: F(0.08, 0.05, 0.30, 0.52, 0.65),
|
||
|
|
schlegel: F(0.10, 0.10, 0.20, 0.48, 0.55),
|
||
|
|
e8: F(0.10, 0.16, 0.65, 0.60, 0.92),
|
||
|
|
links: F(0.10, 0.04, 0.90, 0.62, 0.95), // bright amber
|
||
|
|
},
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: '02_ember-triad', label: 'Ember triad · warm fire band',
|
||
|
|
overrides: {
|
||
|
|
substrate: 'vintage', gradientMode: 'along-edge',
|
||
|
|
fields: {
|
||
|
|
cubic: F(0.04, 0.10, 0.65, 0.55, 0.75),
|
||
|
|
schlegel: F(0.96, 0.03, 0.55, 0.50, 0.65),
|
||
|
|
e8: F(0.12, 0.18, 0.85, 0.62, 0.90),
|
||
|
|
links: F(0.02, 0.10, 0.95, 0.62, 0.95), // deep red→orange
|
||
|
|
},
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: '03_aurora-void', label: 'Aurora · cool spectral on void',
|
||
|
|
overrides: {
|
||
|
|
substrate: 'void', gradientMode: 'along-edge', vign: 0.55,
|
||
|
|
fields: {
|
||
|
|
cubic: F(0.50, 0.72, 0.70, 0.60, 0.85),
|
||
|
|
schlegel: F(0.40, 0.55, 0.55, 0.58, 0.75),
|
||
|
|
e8: F(0.78, 0.92, 0.85, 0.65, 0.90),
|
||
|
|
links: F(0.55, 0.85, 0.95, 0.70, 0.95), // cyan → violet bright
|
||
|
|
},
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: '04_spectrum-cream', label: 'Spectrum · one rainbow field on cream',
|
||
|
|
overrides: {
|
||
|
|
substrate: 'cream', gradientMode: 'along-edge',
|
||
|
|
fields: {
|
||
|
|
cubic: F(0.00, 0.95, 0.80, 0.48, 0.80),
|
||
|
|
schlegel: F(0.0, 0.0, 0.05, 0.30, 0.50),
|
||
|
|
e8: F(0.0, 0.16, 0.55, 0.42, 0.75),
|
||
|
|
links: F(0.55, 0.05, 0.85, 0.45, 0.95), // cyan → red — spans the spectrum too
|
||
|
|
},
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: '05_verdigris', label: 'Verdigris · oxidised copper / patina',
|
||
|
|
overrides: {
|
||
|
|
substrate: 'vintage', gradientMode: 'along-edge',
|
||
|
|
fields: {
|
||
|
|
cubic: F(0.42, 0.50, 0.50, 0.55, 0.75),
|
||
|
|
schlegel: F(0.06, 0.02, 0.45, 0.45, 0.65),
|
||
|
|
e8: F(0.32, 0.45, 0.55, 0.55, 0.85),
|
||
|
|
links: F(0.04, 0.10, 0.85, 0.58, 0.95), // copper highlights
|
||
|
|
},
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: '06_radial-sunrise', label: 'Radial · cool centre → warm edges',
|
||
|
|
overrides: {
|
||
|
|
substrate: 'vintage', gradientMode: 'radial',
|
||
|
|
fields: {
|
||
|
|
cubic: F(0.55, 0.06, 0.60, 0.55, 0.78),
|
||
|
|
schlegel: F(0.55, 0.06, 0.50, 0.55, 0.65),
|
||
|
|
e8: F(0.55, 0.06, 0.70, 0.60, 0.88),
|
||
|
|
links: F(0.55, 0.06, 0.90, 0.62, 0.95), // shares the radial gradient
|
||
|
|
},
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: '07_magenta-family', label: 'Magenta family on cream',
|
||
|
|
overrides: {
|
||
|
|
substrate: 'cream', gradientMode: 'along-edge',
|
||
|
|
fields: {
|
||
|
|
cubic: F(0.85, 0.93, 0.50, 0.45, 0.75),
|
||
|
|
schlegel: F(0.78, 0.88, 0.42, 0.42, 0.65),
|
||
|
|
e8: F(0.92, 0.00, 0.60, 0.48, 0.88),
|
||
|
|
links: F(0.92, 0.78, 0.85, 0.40, 0.95), // saturated pink → purple
|
||
|
|
},
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: '08_per-field-mono', label: 'Per-field monochrome',
|
||
|
|
overrides: {
|
||
|
|
substrate: 'vintage', gradientMode: 'along-edge',
|
||
|
|
fields: {
|
||
|
|
cubic: F(0.55, 0.55, 0.55, 0.55, 0.70),
|
||
|
|
schlegel: F(0.88, 0.88, 0.55, 0.55, 0.70),
|
||
|
|
e8: F(0.12, 0.12, 0.75, 0.60, 0.92),
|
||
|
|
links: F(0.34, 0.34, 0.80, 0.55, 0.95), // mono green accent — a 4th distinct hue
|
||
|
|
},
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: '09_cyanotype', label: 'Cyanotype · Anna Atkins',
|
||
|
|
overrides: {
|
||
|
|
substrate: 'cyanotype', gradientMode: 'along-edge',
|
||
|
|
fields: {
|
||
|
|
cubic: F(0.55, 0.50, 0.30, 0.80, 0.85),
|
||
|
|
schlegel: F(0.55, 0.55, 0.20, 0.85, 0.75),
|
||
|
|
e8: F(0.48, 0.42, 0.50, 0.78, 0.92),
|
||
|
|
links: F(0.55, 0.50, 0.30, 0.92, 0.95), // near-white connectors
|
||
|
|
},
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: '10_single-bright-void', label: 'Single bright · E8 rainbow on void',
|
||
|
|
overrides: {
|
||
|
|
substrate: 'void', gradientMode: 'along-edge', vign: 0.55,
|
||
|
|
fields: {
|
||
|
|
cubic: F(0.0, 0.0, 0.05, 0.40, 0.45),
|
||
|
|
schlegel: F(0.0, 0.0, 0.05, 0.42, 0.40),
|
||
|
|
e8: F(0.0, 0.95, 0.95, 0.62, 0.98),
|
||
|
|
links: F(0.0, 0.95, 0.95, 0.70, 0.98), // bright rainbow connectors
|
||
|
|
},
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: '11_mauve-fog-custom', label: 'Bonus · custom mauve paper',
|
||
|
|
overrides: {
|
||
|
|
gradientMode: 'along-edge',
|
||
|
|
paperOverride: { flat: [82, 76, 92], glowIn: [108, 98, 118], glowOut: [58, 52, 70] },
|
||
|
|
vignOverride: [22, 18, 28],
|
||
|
|
featureOverride: [200, 190, 215],
|
||
|
|
fields: {
|
||
|
|
cubic: F(0.00, 0.95, 0.50, 0.72, 0.80),
|
||
|
|
schlegel: F(0.0, 0.0, 0.05, 0.85, 0.55),
|
||
|
|
e8: F(0.55, 0.85, 0.65, 0.72, 0.92),
|
||
|
|
links: F(0.55, 0.85, 0.85, 0.78, 0.95), // pastel cyan → violet
|
||
|
|
},
|
||
|
|
},
|
||
|
|
},
|
||
|
|
];
|
||
|
|
|
||
|
|
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}/`);
|