Files
bubblechambersimart/tools/qft-bc-composite.mjs

60 lines
2.6 KiB
JavaScript
Raw Permalink Normal View History

/* ============================================================
qft-bc-composite.mjs quick play: a QFT field plate UNDERNEATH
a bubble-chamber plate. Both render to standalone SVG; we embed
each as a self-contained data-URI <image> in one outer SVG (no
defs/id collisions), and put the bubble chamber on top with
mix-blend-mode:multiply the lightbox metaphor: the field glows
underneath, the dark ink darkens it, the light paper drops out.
Usage:
node tools/qft-bc-composite.mjs [qftSeed] [bcSeed] [out.html] [size]
============================================================ */
import { writeFileSync } from 'node:fs';
// --- QFT side ---
import { generateQFTScene } from '../src/qft/scene.js';
import { paramsFromSeed as qftParams } from '../src/qft/params.js';
import { renderQFTSVG } from '../src/qft/renderer.js';
// --- bubble chamber side ---
import { generateScene } from '../src/scene/scene.js';
import { renderSVG } from '../src/render/svgVector.js';
import { paramsFromSeed as bcParams } from '../src/scene/params.js';
import { GROUPS, TOGGLES, FIXED } from '../src/ui/controls.js';
const argv = process.argv.slice(2);
const qftSeed = argv[0] || 'VACUUM-5113';
const bcSeed = argv[1] || 'LAMBDA-2648';
const out = argv[2] || '/tmp/qft-bc.html';
const SIZE = +(argv[3] || 1600);
// pale QFT substrate so it reads as a luminous ground under the ink
const qp = qftParams(qftSeed);
qp.substrate = 'cream'; // force a light ground so the multiply'd BC ink reads
qp.glow = 0.6;
// bubble chamber: default mono, light cream paper → multiply lets the field through
const bp = { ...FIXED, ...bcParams(bcSeed) };
for (const g of GROUPS) for (const c of g.controls) if (!(c.id in bp)) bp[c.id] = c.value;
for (const t of TOGGLES) if (!(t.id in bp)) bp[t.id] = t.value;
const qftSvg = renderQFTSVG(generateQFTScene(qp), qp, SIZE);
const bcSvg = renderSVG(generateScene(bp), bp, SIZE);
const dataUri = (svg) => 'data:image/svg+xml;base64,' + Buffer.from(svg).toString('base64');
const composite =
`<svg xmlns="http://www.w3.org/2000/svg" width="${SIZE}" height="${SIZE}" viewBox="0 0 ${SIZE} ${SIZE}">
<image x="0" y="0" width="${SIZE}" height="${SIZE}" href="${dataUri(qftSvg)}"/>
<image x="0" y="0" width="${SIZE}" height="${SIZE}" href="${dataUri(bcSvg)}" style="mix-blend-mode:multiply"/>
</svg>`;
const html =
`<!doctype html><meta charset="utf-8">
<style>html,body{margin:0;background:#222}img,svg{display:block}</style>
${composite}`;
writeFileSync(out, html);
writeFileSync(out.replace(/\.html$/, '.svg'), composite);
console.log(`composite -> ${out} (qft=${qftSeed} ${qp.archetype}, bc=${bcSeed}, ${SIZE}px)`);