374 lines
15 KiB
JavaScript
374 lines
15 KiB
JavaScript
|
|
/* ============================================================
|
||
|
|
qft-variations-craft.mjs — sketch 06.
|
||
|
|
Each variation isolates ONE craft idea so the effect is
|
||
|
|
readable on its own. Five blocks:
|
||
|
|
|
||
|
|
A · Cubic origin plays — push origin off-page or into the
|
||
|
|
viewer's space along the (isometric) Z axis
|
||
|
|
B · Multi-rosettes — offset origins, varied scales
|
||
|
|
C · Lighter-on-midtone — paper at MID tone so a brighter
|
||
|
|
rosette can actually read as lighter-than-ground
|
||
|
|
D · Plain white on light — bold white strokes on warm paper
|
||
|
|
E · Schlegel plays — weight / origin / shifted axes
|
||
|
|
(outerR · innerR · rot3D)
|
||
|
|
============================================================ */
|
||
|
|
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/sketch06';
|
||
|
|
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]],
|
||
|
|
});
|
||
|
|
const WHITE = (op = 0.95) => F(0, 0, 0, 0.97, op);
|
||
|
|
|
||
|
|
const variations = [
|
||
|
|
// ─────────────────────── BLOCK A · cubic origin plays ───────────────────────
|
||
|
|
{
|
||
|
|
name: 'A1_cubic-origin-far-right',
|
||
|
|
label: 'A1 · cubic origin pushed off-page right — orthogonal mesh streams in from the right edge',
|
||
|
|
overrides: {
|
||
|
|
paperOverride: paper([225, 215, 200]),
|
||
|
|
vignOverride: [70, 60, 45], featureOverride: [60, 45, 30],
|
||
|
|
stroke: 1.8, gradientMode: 'linear-x',
|
||
|
|
cubicScale: 1.4, cubicOriginX: 1.45, cubicOriginY: 0, // mostly off-screen to the right
|
||
|
|
schlegelScale: 0.65,
|
||
|
|
distStrength: 0, // disable distortion when origin is offset
|
||
|
|
e8Origins: [{ x: -0.45, y: 0, scale: 0.42 }], // counterweight rosette left
|
||
|
|
linkCount: 4,
|
||
|
|
fields: {
|
||
|
|
cubic: F(0.55, 0.08, 0.65, 0.35, 0.78),
|
||
|
|
schlegel: F(0.10, 0.08, 0.45, 0.40, 0.55),
|
||
|
|
e8: F(0.10, 0.04, 0.65, 0.45, 0.88),
|
||
|
|
links: F(0.05, 0.10, 0.70, 0.40, 0.55),
|
||
|
|
},
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: 'A2_cubic-zoom-toward-viewer',
|
||
|
|
label: 'A2 · cubic zoomed in (Z toward viewer) — we are INSIDE the lattice',
|
||
|
|
overrides: {
|
||
|
|
paperOverride: paper([225, 215, 198]),
|
||
|
|
vignOverride: [60, 50, 35], featureOverride: [70, 55, 30],
|
||
|
|
stroke: 2.4,
|
||
|
|
cubicScale: 3.2, // huge — fills well past the frame
|
||
|
|
schlegelScale: 0,
|
||
|
|
distStrength: 0,
|
||
|
|
e8Origins: [{ x: 0.55, y: 0.55, scale: 0.32 }], // single small rosette one corner
|
||
|
|
linkCount: 3,
|
||
|
|
fields: {
|
||
|
|
cubic: F(0.04, 0.13, 0.65, 0.32, 0.80),
|
||
|
|
schlegel: F(0, 0, 0, 0.5, 0),
|
||
|
|
e8: F(0.05, 0.12, 0.65, 0.45, 0.88),
|
||
|
|
links: F(0.06, 0.12, 0.65, 0.40, 0.55),
|
||
|
|
},
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: 'A3_cubic-origin-upper-left',
|
||
|
|
label: 'A3 · cubic origin pushed upper-left, rest of canvas opens to lower-right',
|
||
|
|
overrides: {
|
||
|
|
paperOverride: paper([232, 222, 205]),
|
||
|
|
vignOverride: [70, 55, 40], featureOverride: [60, 50, 35],
|
||
|
|
stroke: 1.6, gradientMode: 'radial',
|
||
|
|
cubicScale: 1.6, cubicOriginX: -0.85, cubicOriginY: -0.85,
|
||
|
|
schlegelScale: 0.55, schlegelOriginX: -0.30, schlegelOriginY: -0.30,
|
||
|
|
distStrength: 0,
|
||
|
|
e8Origins: [{ x: 0.40, y: 0.40, scale: 0.45 }], // rosette in opposing corner
|
||
|
|
linkCount: 4,
|
||
|
|
fields: {
|
||
|
|
cubic: F(0.55, 0.05, 0.65, 0.36, 0.80),
|
||
|
|
schlegel: F(0.58, 0.10, 0.45, 0.40, 0.60),
|
||
|
|
e8: F(0.06, 0.12, 0.70, 0.45, 0.88),
|
||
|
|
links: F(0.05, 0.10, 0.65, 0.40, 0.55),
|
||
|
|
},
|
||
|
|
},
|
||
|
|
},
|
||
|
|
|
||
|
|
// ─────────────────────── BLOCK B · multi-rosettes ────────────────────────────
|
||
|
|
{
|
||
|
|
name: 'B1_three-rosettes-horizontal',
|
||
|
|
label: 'B1 · three rosettes along a horizontal axis',
|
||
|
|
overrides: {
|
||
|
|
paperOverride: paper([232, 222, 205]),
|
||
|
|
vignOverride: [60, 50, 35], featureOverride: [55, 45, 30],
|
||
|
|
stroke: 1.8,
|
||
|
|
cubicScale: 1.3, schlegelScale: 0,
|
||
|
|
e8Origins: [
|
||
|
|
{ x: -0.55, y: 0, scale: 0.32 },
|
||
|
|
{ x: 0.00, y: 0, scale: 0.42 },
|
||
|
|
{ x: 0.55, y: 0, scale: 0.32 },
|
||
|
|
],
|
||
|
|
linkCount: 6,
|
||
|
|
fields: {
|
||
|
|
cubic: F(0.50, 0.10, 0.45, 0.40, 0.35),
|
||
|
|
schlegel: F(0, 0, 0, 0.5, 0),
|
||
|
|
e8: F(0.55, 0.05, 0.55, 0.48, 0.85),
|
||
|
|
links: F(0.06, 0.12, 0.65, 0.42, 0.55),
|
||
|
|
},
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: 'B2_triangular-rosette-cluster',
|
||
|
|
label: 'B2 · three rosettes in a triangle · varied sizes',
|
||
|
|
overrides: {
|
||
|
|
paperOverride: paper([222, 210, 220]),
|
||
|
|
vignOverride: [55, 40, 60], featureOverride: [65, 45, 75],
|
||
|
|
stroke: 1.6,
|
||
|
|
cubicScale: 1.4, schlegelScale: 0.65,
|
||
|
|
e8Origins: [
|
||
|
|
{ x: 0.00, y: -0.45, scale: 0.50 },
|
||
|
|
{ x: -0.45, y: 0.30, scale: 0.32 },
|
||
|
|
{ x: 0.45, y: 0.30, scale: 0.32 },
|
||
|
|
],
|
||
|
|
linkCount: 6,
|
||
|
|
fields: {
|
||
|
|
cubic: F(0.78, 0.92, 0.50, 0.38, 0.40),
|
||
|
|
schlegel: F(0.82, 0.92, 0.40, 0.40, 0.50),
|
||
|
|
e8: F(0.82, 0.95, 0.55, 0.46, 0.85),
|
||
|
|
links: F(0.85, 0.96, 0.65, 0.42, 0.55),
|
||
|
|
},
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: 'B3_five-rosettes-quincunx',
|
||
|
|
label: 'B3 · quincunx: 4 corners + centre · five rosettes total',
|
||
|
|
overrides: {
|
||
|
|
paperOverride: paper([232, 222, 205]),
|
||
|
|
vignOverride: [60, 50, 35], featureOverride: [55, 45, 30],
|
||
|
|
stroke: 1.6,
|
||
|
|
cubicScale: 1.3, schlegelScale: 0,
|
||
|
|
e8Origins: [
|
||
|
|
{ x: -0.50, y: -0.50, scale: 0.26 },
|
||
|
|
{ x: 0.50, y: -0.50, scale: 0.26 },
|
||
|
|
{ x: 0.00, y: 0.00, scale: 0.42 },
|
||
|
|
{ x: -0.50, y: 0.50, scale: 0.26 },
|
||
|
|
{ x: 0.50, y: 0.50, scale: 0.26 },
|
||
|
|
],
|
||
|
|
linkCount: 8,
|
||
|
|
fields: {
|
||
|
|
cubic: F(0.10, 0.16, 0.40, 0.40, 0.35),
|
||
|
|
schlegel: F(0, 0, 0, 0.5, 0),
|
||
|
|
e8: F(0.10, 0.16, 0.60, 0.45, 0.85),
|
||
|
|
links: F(0.06, 0.12, 0.65, 0.42, 0.55),
|
||
|
|
},
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: 'B4_central-large-plus-orbit',
|
||
|
|
label: 'B4 · one large central rosette + smaller orbiting satellites',
|
||
|
|
overrides: {
|
||
|
|
paperOverride: paper([225, 215, 198]),
|
||
|
|
vignOverride: [60, 50, 35], featureOverride: [55, 45, 30],
|
||
|
|
stroke: 1.6, gradientMode: 'radial',
|
||
|
|
cubicScale: 1.4, schlegelScale: 0,
|
||
|
|
e8Origins: [
|
||
|
|
{ x: 0.00, y: 0.00, scale: 0.70 },
|
||
|
|
{ x: 0.55, y: -0.55, scale: 0.18 },
|
||
|
|
{ x: -0.55, y: -0.55, scale: 0.18 },
|
||
|
|
{ x: 0.00, y: 0.62, scale: 0.18 },
|
||
|
|
],
|
||
|
|
linkCount: 6,
|
||
|
|
fields: {
|
||
|
|
cubic: F(0.55, 0.05, 0.55, 0.38, 0.35),
|
||
|
|
schlegel: F(0, 0, 0, 0.5, 0),
|
||
|
|
e8: F(0.55, 0.05, 0.55, 0.46, 0.85),
|
||
|
|
links: F(0.06, 0.12, 0.70, 0.42, 0.55),
|
||
|
|
},
|
||
|
|
},
|
||
|
|
},
|
||
|
|
|
||
|
|
// ────────────────── BLOCK C · lighter-on-midtone ─────────────────────────────
|
||
|
|
{
|
||
|
|
name: 'C1_lighter-on-deep-cream',
|
||
|
|
label: 'C1 · lighter rosette on DEEP-cream midtone',
|
||
|
|
overrides: {
|
||
|
|
paperOverride: paper([180, 165, 140]), // mid-tone deep cream
|
||
|
|
vignOverride: [90, 70, 45], featureOverride: [240, 230, 215],
|
||
|
|
stroke: 2.4,
|
||
|
|
cubicScale: 1.45, schlegelScale: 0.75,
|
||
|
|
e8Origins: [{ x: 0, y: 0, scale: 0.78 }],
|
||
|
|
fields: {
|
||
|
|
cubic: F(0.06, 0.13, 0.30, 0.38, 0.55),
|
||
|
|
schlegel: F(0.08, 0.10, 0.30, 0.38, 0.50),
|
||
|
|
e8: F(0.08, 0.13, 0.20, 0.88, 0.80), // LIGHTER than the midtone paper
|
||
|
|
links: F(0.06, 0.12, 0.40, 0.92, 0.85),
|
||
|
|
},
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: 'C2_lighter-on-warm-grey',
|
||
|
|
label: 'C2 · lighter rosette on warm-grey midtone',
|
||
|
|
overrides: {
|
||
|
|
paperOverride: paper([155, 150, 140]), // warm grey midtone
|
||
|
|
vignOverride: [80, 70, 55], featureOverride: [235, 230, 220],
|
||
|
|
stroke: 2.6,
|
||
|
|
cubicScale: 1.55, schlegelScale: 0,
|
||
|
|
e8Origins: [{ x: -0.20, y: 0, scale: 0.55 },
|
||
|
|
{ x: 0.20, y: 0, scale: 0.55 }],
|
||
|
|
fields: {
|
||
|
|
cubic: F(0.06, 0.12, 0.20, 0.40, 0.55),
|
||
|
|
schlegel: F(0, 0, 0, 0.5, 0),
|
||
|
|
e8: F(0.06, 0.12, 0.18, 0.90, 0.80), // pale ivory on grey
|
||
|
|
links: F(0.06, 0.12, 0.30, 0.94, 0.85),
|
||
|
|
},
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: 'C3_lighter-on-sage',
|
||
|
|
label: 'C3 · lighter rosette on sage-grey midtone',
|
||
|
|
overrides: {
|
||
|
|
paperOverride: paper([155, 165, 145]), // sage midtone
|
||
|
|
vignOverride: [55, 70, 50], featureOverride: [225, 235, 215],
|
||
|
|
stroke: 2.4,
|
||
|
|
cubicScale: 1.4, schlegelScale: 0.75,
|
||
|
|
e8Origins: [{ x: 0, y: 0, scale: 0.82 }],
|
||
|
|
fields: {
|
||
|
|
cubic: F(0.40, 0.48, 0.30, 0.42, 0.55),
|
||
|
|
schlegel: F(0.42, 0.48, 0.25, 0.40, 0.50),
|
||
|
|
e8: F(0.40, 0.48, 0.22, 0.90, 0.80),
|
||
|
|
links: F(0.40, 0.50, 0.35, 0.94, 0.85),
|
||
|
|
},
|
||
|
|
},
|
||
|
|
},
|
||
|
|
|
||
|
|
// ────────────────── BLOCK D · plain white on light ───────────────────────────
|
||
|
|
{
|
||
|
|
name: 'D1_thick-white-on-cream',
|
||
|
|
label: 'D1 · bold WHITE strokes on warm cream — embossed',
|
||
|
|
overrides: {
|
||
|
|
paperOverride: paper([222, 210, 188]),
|
||
|
|
vignOverride: [70, 55, 35], featureOverride: [60, 50, 35],
|
||
|
|
stroke: 3.4, // thick
|
||
|
|
cubicScale: 1.45, schlegelScale: 1.20,
|
||
|
|
e8Origins: [{ x: 0, y: 0, scale: 0.72 }],
|
||
|
|
fields: {
|
||
|
|
cubic: WHITE(0.85),
|
||
|
|
schlegel: WHITE(0.65),
|
||
|
|
e8: WHITE(0.92),
|
||
|
|
links: WHITE(0.78),
|
||
|
|
},
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: 'D2_white-on-pale-rose',
|
||
|
|
label: 'D2 · plain white rosettes on pale rose',
|
||
|
|
overrides: {
|
||
|
|
paperOverride: paper([232, 210, 210]),
|
||
|
|
vignOverride: [80, 55, 55], featureOverride: [90, 55, 55],
|
||
|
|
stroke: 3.2,
|
||
|
|
cubicScale: 1.35, schlegelScale: 0,
|
||
|
|
e8Origins: [{ x: 0, y: 0, scale: 0.95 },
|
||
|
|
{ x: 0, y: 0, scale: 0.60 },
|
||
|
|
{ x: 0, y: 0, scale: 0.30 }],
|
||
|
|
linkCount: 0,
|
||
|
|
fields: {
|
||
|
|
cubic: WHITE(0.40), // very subtle cubic atmosphere
|
||
|
|
schlegel: F(0, 0, 0, 0.5, 0),
|
||
|
|
e8: WHITE(0.95), // strong solid white rosettes
|
||
|
|
links: WHITE(0.5),
|
||
|
|
},
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: 'D3_white-on-pale-blue',
|
||
|
|
label: 'D3 · white schlegel + white rosette on pale blue',
|
||
|
|
overrides: {
|
||
|
|
paperOverride: paper([190, 215, 230]),
|
||
|
|
vignOverride: [40, 55, 70], featureOverride: [30, 50, 75],
|
||
|
|
stroke: 3.0,
|
||
|
|
cubicScale: 1.0, schlegelScale: 1.50, // schlegel prominent
|
||
|
|
e8Origins: [{ x: 0, y: 0, scale: 0.65 }],
|
||
|
|
fields: {
|
||
|
|
cubic: WHITE(0.45),
|
||
|
|
schlegel: WHITE(0.85), // bold white tesseract
|
||
|
|
e8: WHITE(0.92),
|
||
|
|
links: WHITE(0.55),
|
||
|
|
},
|
||
|
|
},
|
||
|
|
},
|
||
|
|
|
||
|
|
// ────────────────── BLOCK E · schlegel plays ─────────────────────────────────
|
||
|
|
{
|
||
|
|
name: 'E1_schlegel-thin-nested',
|
||
|
|
label: 'E1 · Schlegel: deep nesting (tiny inner cube) · thin lines',
|
||
|
|
overrides: {
|
||
|
|
paperOverride: paper([232, 222, 200]),
|
||
|
|
vignOverride: [60, 50, 40], featureOverride: [60, 50, 35],
|
||
|
|
stroke: 1.4,
|
||
|
|
cubicScale: 0.55, schlegelScale: 1.40,
|
||
|
|
schlegelInnerR: 0.08, // very small inner cube → strong perspective
|
||
|
|
schlegelRot3D: 0.20,
|
||
|
|
e8Origins: [{ x: 0, y: 0, scale: 0.42 }],
|
||
|
|
fields: {
|
||
|
|
cubic: F(0.58, 0.62, 0.30, 0.45, 0.40),
|
||
|
|
schlegel: F(0.60, 0.68, 0.50, 0.32, 0.78), // schlegel is the subject
|
||
|
|
e8: F(0.55, 0.65, 0.50, 0.45, 0.78),
|
||
|
|
links: F(0.58, 0.66, 0.65, 0.42, 0.55),
|
||
|
|
},
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: 'E2_schlegel-shifted-axis-thick',
|
||
|
|
label: 'E2 · Schlegel with strongly rotated 4D axis · thick lines',
|
||
|
|
overrides: {
|
||
|
|
paperOverride: paper([222, 212, 195]),
|
||
|
|
vignOverride: [70, 55, 40], featureOverride: [60, 45, 30],
|
||
|
|
stroke: 3.0, // thick
|
||
|
|
cubicScale: 0.65, schlegelScale: 1.55,
|
||
|
|
schlegelInnerR: 0.42, // larger inner cube — less perspective, more parallel
|
||
|
|
schlegelRot3D: 1.10, // strong rotation — looking at the tesseract from different angle
|
||
|
|
schlegelOriginX: 0.15,
|
||
|
|
e8Origins: [{ x: -0.45, y: -0.45, scale: 0.32 }],
|
||
|
|
fields: {
|
||
|
|
cubic: F(0.06, 0.12, 0.35, 0.40, 0.40),
|
||
|
|
schlegel: F(0.06, 0.13, 0.55, 0.32, 0.85),
|
||
|
|
e8: F(0.08, 0.16, 0.65, 0.45, 0.85),
|
||
|
|
links: F(0.06, 0.12, 0.65, 0.40, 0.55),
|
||
|
|
},
|
||
|
|
},
|
||
|
|
},
|
||
|
|
{
|
||
|
|
name: 'E3_dual-schlegels-rotated',
|
||
|
|
label: 'E3 · BIG schlegel offset · faint thin counter-rotated cubic',
|
||
|
|
overrides: {
|
||
|
|
paperOverride: paper([200, 200, 215]), // pale lavender-grey midtone
|
||
|
|
vignOverride: [60, 55, 75], featureOverride: [40, 40, 60],
|
||
|
|
stroke: 2.6,
|
||
|
|
cubicScale: 1.6, cubicRot: 0.80, // cubic strongly rotated
|
||
|
|
schlegelScale: 1.85, // schlegel very large bleeding
|
||
|
|
schlegelInnerR: 0.55, // inner cube larger
|
||
|
|
schlegelRot3D: -0.30, // negative rotation — opposite angle
|
||
|
|
schlegelOriginX: -0.10, schlegelOriginY: 0.10,
|
||
|
|
e8Origins: [{ x: 0.40, y: -0.40, scale: 0.32 },
|
||
|
|
{ x: -0.40, y: 0.40, scale: 0.32 }],
|
||
|
|
fields: {
|
||
|
|
cubic: F(0.62, 0.70, 0.30, 0.55, 0.35),
|
||
|
|
schlegel: F(0.62, 0.72, 0.55, 0.32, 0.78),
|
||
|
|
e8: F(0.65, 0.75, 0.60, 0.45, 0.85),
|
||
|
|
links: F(0.62, 0.78, 0.70, 0.42, 0.55),
|
||
|
|
},
|
||
|
|
},
|
||
|
|
},
|
||
|
|
];
|
||
|
|
|
||
|
|
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}`);
|
||
|
|
}
|
||
|
|
console.log(`\nrendered ${variations.length} variations → ${OUT_DIR}/`);
|