// Generative cover art for /writing. Inline SVG so it inherits the theme CSS // variables (adapts to dark/light automatically). One cohesive abstract visual // language across all articles, in the vein AI labs use for their own writing: // soft gradient fields + thin geometric line work, seeded per topic. // // Public: // --- deterministic pseudo-random, seeded by slug (so a cover never reshuffles) --- function artHash(s) { let h = 2166136261; for (let i = 0; i < (s || "").length; i++) { h ^= s.charCodeAt(i); h = Math.imul(h, 16777619); } return h >>> 0; } function artRng(seed) { let a = seed >>> 0; return function () { a = (a + 0x6d2b79f5) | 0; let t = Math.imul(a ^ (a >>> 15), 1 | a); t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t; return ((t ^ (t >>> 14)) >>> 0) / 4294967296; }; } // motif + tone per article. tone: cool=accent blue, warm=amber, mix=both. const ART_MAP = { "predictions-2026": { m: "orbit", t: "mix" }, "what-stays-human": { m: "bloom", t: "warm" }, "future-of-jobs": { m: "strata", t: "warm" }, "on-intelligence": { m: "bloom", t: "cool" }, "turing-test": { m: "interfere", t: "cool" }, "world-simulators": { m: "grid", t: "cool" }, "responsibility-of-dialogue": { m: "interfere", t: "warm" }, "incompleteness-of-ethics": { m: "loop", t: "cool" }, "backpropagation-intuition": { m: "field", t: "cool" }, "the-analog-spark": { m: "bloom", t: "mix" }, "how-to-implement-ai-in-your-company": { m: "lattice", t: "cool" }, "cum-implementez-ai-in-companie-ghid": { m: "lattice", t: "cool" }, "ai-automation-for-business-what-is-worth-automating": { m: "field", t: "cool" }, "automatizari-ai-pentru-companii-ce-merita-automatizat": { m: "field", t: "cool" }, "ai-development-romania": { m: "lattice", t: "warm" }, "dezvoltare-ai-romania": { m: "lattice", t: "warm" }, "what-is-a-machine-learning-solution": { m: "strata", t: "cool" }, "ce-este-o-solutie-machine-learning": { m: "strata", t: "cool" }, }; const ART_MOTIFS = ["bloom", "orbit", "grid", "interfere", "loop", "field", "lattice", "strata"]; const ART_TONES = ["cool", "warm", "mix"]; function artMeta(slug) { if (ART_MAP[slug]) return ART_MAP[slug]; const h = artHash(slug || "x"); return { m: ART_MOTIFS[h % ART_MOTIFS.length], t: ART_TONES[(h >> 5) % ART_TONES.length] }; } function artColors(tone) { if (tone === "warm") return { a: "var(--warm)", b: "var(--warm)" }; if (tone === "mix") return { a: "var(--accent)", b: "var(--warm)" }; return { a: "var(--accent)", b: "var(--accent)" }; } // ---- motif renderers: each returns { defs, body } for the 600x375 canvas ---- function motifBloom(id, rnd, col) { const orbs = []; const n = 3; for (let i = 0; i < n; i++) { orbs.push({ cx: 120 + rnd() * 360, cy: 80 + rnd() * 215, r: 150 + rnd() * 130, fill: i === 1 ? "b" : "a", o: 0.5 + rnd() * 0.35, }); } const dots = []; for (let i = 0; i < 22; i++) dots.push({ x: rnd() * 600, y: rnd() * 375, r: 0.7 + rnd() * 1.1 }); return { defs: ( ), body: ( {orbs.map((o, i) => ( ))} {dots.map((d, i) => )} ), }; } function motifOrbit(id, rnd, col) { const cx = 470, cy = 300; const rings = [60, 120, 185, 255, 330]; const fan = []; for (let i = 0; i < 13; i++) { const ang = (Math.PI * 1.05) + (i / 12) * (Math.PI * 0.95); fan.push({ x: cx + Math.cos(ang) * 360, y: cy + Math.sin(ang) * 360 }); } const nodes = rings.map((r, i) => { const ang = Math.PI + rnd() * Math.PI * 0.9; return { x: cx + Math.cos(ang) * r, y: cy + Math.sin(ang) * r, big: i % 2 === 0 }; }); return { defs: ( ), body: ( {fan.map((p, i) => )} {rings.map((r, i) => )} {nodes.map((nd, i) => )} ), }; } function motifGrid(id, rnd, col) { const hzY = 150, vx = 300; const verts = []; for (let i = -7; i <= 7; i++) { verts.push({ x1: vx + i * 22, y1: hzY, x2: vx + i * 95, y2: 400 }); } const horis = []; for (let i = 1; i <= 9; i++) { const t = i / 10; horis.push(hzY + Math.pow(t, 1.9) * 250); } return { defs: ( ), body: ( {verts.map((v, i) => )} {horis.map((y, i) => )} ), }; } function motifInterfere(id, rnd, col) { const a = { x: 195, y: 165 }, b = { x: 410, y: 215 }; const ringsA = [], ringsB = []; for (let i = 1; i <= 9; i++) { ringsA.push(i * 26); ringsB.push(i * 26); } return { defs: null, body: ( {ringsA.map((r, i) => )} {ringsB.map((r, i) => )} ), }; } function motifLoop(id, rnd, col) { const cx = 300, cy = 188, r = 110; // an almost-complete ring with a gap (the unclosed argument) const gap = 0.42; // radians of opening const start = -Math.PI / 2 + gap / 2; const end = -Math.PI / 2 - gap / 2 + Math.PI * 2; const x1 = cx + Math.cos(start) * r, y1 = cy + Math.sin(start) * r; const x2 = cx + Math.cos(end) * r, y2 = cy + Math.sin(end) * r; const d = "M " + x1 + " " + y1 + " A " + r + " " + r + " 0 1 1 " + x2 + " " + y2; return { defs: ( ), body: ( ), }; } function motifField(id, rnd, col) { // streamlines flowing down toward a basin (gradient descent) const basin = { x: 330, y: 330 }; const lines = []; for (let i = 0; i < 16; i++) { const sx = i * 40 - 20; const sy = 30 + rnd() * 40; const c1x = sx + 60, c1y = sy + 120; const ex = basin.x + (rnd() - 0.5) * 70; const ey = basin.y - 6 - rnd() * 14; lines.push("M " + sx + " " + sy + " C " + c1x + " " + c1y + " " + (ex - 60) + " " + (ey - 40) + " " + ex + " " + ey); } return { defs: ( ), body: ( {lines.map((d, i) => )} ), }; } function motifLattice(id, rnd, col) { const nodes = []; for (let i = 0; i < 11; i++) nodes.push({ x: 60 + rnd() * 480, y: 50 + rnd() * 275 }); const edges = []; for (let i = 0; i < nodes.length; i++) { for (let j = i + 1; j < nodes.length; j++) { const dx = nodes[i].x - nodes[j].x, dy = nodes[i].y - nodes[j].y; if (Math.sqrt(dx * dx + dy * dy) < 175) edges.push([i, j]); } } return { defs: ( ), body: ( {edges.map((e, i) => ( ))} {nodes.map((nd, i) => ( ))} ), }; } function motifStrata(id, rnd, col) { // stacked topographic contour bands const bands = []; const count = 6; for (let b = 0; b < count; b++) { const baseY = 70 + b * 48; const amp = 16 + rnd() * 16; const phase = rnd() * 6.28; let d = "M 0 " + (baseY + Math.sin(phase) * amp); for (let x = 60; x <= 600; x += 60) { d += " Q " + (x - 30) + " " + (baseY + Math.sin(phase + x / 70) * amp) + " " + x + " " + (baseY + Math.sin(phase + x / 55) * amp); } bands.push({ d, b }); } return { defs: ( ), body: ( {bands.map((bd, i) => )} ), }; } const MOTIF_FN = { bloom: motifBloom, orbit: motifOrbit, grid: motifGrid, interfere: motifInterfere, loop: motifLoop, field: motifField, lattice: motifLattice, strata: motifStrata, }; function CoverArt({ slug, variant }) { const meta = artMeta(slug); const col = artColors(meta.t); const id = "ca-" + (slug || "x").replace(/[^a-z0-9]/gi, "").slice(0, 24); const rnd = artRng(artHash(slug || "x")); const fn = MOTIF_FN[meta.m] || motifBloom; const { defs, body } = fn(id, rnd, col); return ( ); } Object.assign(window, { CoverArt });