// topo.jsx — generative topographic contour-line backgrounds
// Deterministic pseudo-random based on a string seed
function seededRng(seed) {
let h = 2166136261 >>> 0;
for (let i = 0; i < seed.length; i++) {
h ^= seed.charCodeAt(i);
h = Math.imul(h, 16777619);
}
return () => {
h += 0x6D2B79F5;
let t = h;
t = Math.imul(t ^ (t >>> 15), t | 1);
t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
};
}
// Build a "topographic" SVG: a stack of irregular closed contour rings,
// each one nudged slightly so they look like elevation lines on a map.
function TopoSVG({ seed = "everest", width = 600, height = 400, stroke = "rgba(252,250,244,.18)", strokeBold = "rgba(252,250,244,.32)", rings = 14, peakX, peakY }) {
const rand = seededRng(seed);
const cx = peakX != null ? peakX : (0.35 + rand() * 0.3) * width;
const cy = peakY != null ? peakY : (0.45 + rand() * 0.25) * height;
// a couple of "wind" lobes to push contours into non-circular shapes
const lobes = [];
const nLobes = 3 + Math.floor(rand() * 3);
for (let i = 0; i < nLobes; i++) {
lobes.push({
angle: rand() * Math.PI * 2,
strength: 0.15 + rand() * 0.35,
sharpness: 1 + rand() * 2.5,
});
}
const paths = [];
const baseR = Math.min(width, height) * 0.12;
const ringSpacing = (Math.max(width, height) * 0.95) / rings;
for (let r = 0; r < rings; r++) {
const radius = baseR + r * ringSpacing * 0.45;
const steps = 96;
let d = "";
for (let i = 0; i <= steps; i++) {
const t = (i / steps) * Math.PI * 2;
let rr = radius;
// apply lobes
for (const L of lobes) {
const a = Math.cos(t - L.angle);
rr += L.strength * radius * Math.sign(a) * Math.pow(Math.abs(a), L.sharpness);
}
// micro jitter (consistent per ring + step)
const jrng = seededRng(seed + "|" + r + "|" + i);
rr += (jrng() - 0.5) * radius * 0.06;
const x = cx + Math.cos(t) * rr;
const y = cy + Math.sin(t) * rr * 0.78; // squish vertically
d += (i === 0 ? "M" : "L") + x.toFixed(1) + "," + y.toFixed(1) + " ";
}
d += "Z";
paths.push({ d, bold: r % 4 === 0 });
}
return (
);
}
// Full-page faint topo lines (paper)
function TopoBackdrop() {
return (
);
}
// Inline SVG paper-colored backdrop (light contour lines on paper)
function TopoSVGPaper() {
const rand = seededRng("paper-2026");
const cx = 1100;
const cy = 380;
const rings = 22;
const baseR = 60;
const lobes = [
{ angle: 0.4, strength: 0.32, sharpness: 1.6 },
{ angle: 2.1, strength: 0.22, sharpness: 2.0 },
{ angle: 4.4, strength: 0.18, sharpness: 1.2 },
];
const paths = [];
for (let r = 0; r < rings; r++) {
const radius = baseR + r * 60;
const steps = 120;
let d = "";
for (let i = 0; i <= steps; i++) {
const t = (i / steps) * Math.PI * 2;
let rr = radius;
for (const L of lobes) {
const a = Math.cos(t - L.angle);
rr += L.strength * radius * Math.sign(a) * Math.pow(Math.abs(a), L.sharpness);
}
const jrng = seededRng("paper|" + r + "|" + i);
rr += (jrng() - 0.5) * radius * 0.04;
const x = cx + Math.cos(t) * rr;
const y = cy + Math.sin(t) * rr * 0.78;
d += (i === 0 ? "M" : "L") + x.toFixed(1) + "," + y.toFixed(1) + " ";
}
d += "Z";
paths.push({ d, bold: r % 5 === 0 });
}
return (
{paths.map((p, i) => (
))}
);
}
Object.assign(window, { TopoSVG, TopoBackdrop });