Added QFT

This commit is contained in:
2026-05-29 15:40:42 -04:00
parent e59b024b62
commit 56c59a1f9c
148 changed files with 428741 additions and 7 deletions

60
src/qft/palette.js Normal file
View File

@@ -0,0 +1,60 @@
/* ============================================================
qft/palette.js — per-field hue gradients + substrate variants.
Each FIELD (one lattice) is parameterised as a slider:
hueStart, hueEnd, saturation, lightness, opacity
The renderer asks for the colour at a t∈[0,1] along an edge (or
at an (x,y) position when the gradient mode is radial/linear).
"Hue gradient over time" = per-edge progression, the QFT analog
of the bubble-chamber lifecycle palette.
Self-contained: no dependency on the bubble-chamber palette
registry. Reuses only the generic hslToRgb util.
============================================================ */
import { hslToRgb } from '../render/palette.js';
const clamp = (v, lo, hi) => Math.max(lo, Math.min(hi, v));
/* Substrate variants — the "chemistry" the lattices sit on. */
export const SUBSTRATES = {
vintage: { paper: { flat: [42, 32, 22], glowIn: [62, 48, 32], glowOut: [22, 16, 10] },
vign: [10, 7, 4], feature: [178, 138, 78] },
void: { paper: { flat: [10, 10, 14], glowIn: [22, 22, 30], glowOut: [3, 3, 6] },
vign: [0, 0, 0], feature: [150, 150, 180] },
cream: { paper: { flat: [207, 200, 180], glowIn: [226, 219, 199], glowOut: [179, 170, 146] },
vign: [56, 46, 32], feature: [42, 30, 20] },
selenium: { paper: { flat: [190, 181, 197], glowIn: [210, 201, 217], glowOut: [156, 146, 166] },
vign: [42, 38, 54], feature: [58, 50, 72] },
cyanotype:{ paper: { flat: [22, 48, 82], glowIn: [38, 70, 110], glowOut: [10, 22, 44] },
vign: [6, 12, 22], feature: [180, 210, 235] },
};
export function resolveSubstrate(id = 'vintage') {
return SUBSTRATES[id] || SUBSTRATES.vintage;
}
/* Sample the gradient parameter s ∈ [0, 1] for a point on an edge.
- along-edge: s = t (the per-edge t the renderer passes in)
- radial: s = min(1, |(x, y)|) (centre → 0, corners → 1)
- linear-x: s = (x + 1) / 2 (left → 0, right → 1)
- linear-y: s = (y + 1) / 2 (top → 0, bottom → 1) */
export function gradientS(t, x, y, mode = 'along-edge') {
switch (mode) {
case 'radial': return clamp(Math.hypot(x, y), 0, 1);
case 'linear-x': return clamp((x + 1) / 2, 0, 1);
case 'linear-y': return clamp((y + 1) / 2, 0, 1);
case 'along-edge':
default: return clamp(t, 0, 1);
}
}
/* Compute the colour for a field at gradient parameter s. Hue rotates from
hueStart → hueEnd by the SHORT way around the circle (so a small Δ stays
small even when crossing 1.0). */
export function fieldColor(field, s) {
let dh = field.hueEnd - field.hueStart;
// wrap to shortest-path delta (-0.5 .. +0.5)
if (dh > 0.5) dh -= 1;
if (dh < -0.5) dh += 1;
const h = field.hueStart + s * dh;
return hslToRgb(h, field.saturation, field.lightness);
}