34 lines
1.5 KiB
JavaScript
34 lines
1.5 KiB
JavaScript
|
|
#!/usr/bin/env node
|
||
|
|
/* stack-render.mjs — render an acrylic-stack plan to per-plane SVGs.
|
||
|
|
usage: node tools/stack-render.mjs <plan.mjs> [outDir]
|
||
|
|
Writes plane-NN-<sheet>-<face>.svg + manifest.json for the simulator
|
||
|
|
(fable/stack/simulator.html?c=<id>). */
|
||
|
|
import { mkdirSync, writeFileSync } from 'node:fs';
|
||
|
|
import { resolve } from 'node:path';
|
||
|
|
import { pathToFileURL } from 'node:url';
|
||
|
|
import { renderStack, planeDepths } from '../src/render/stack.js';
|
||
|
|
|
||
|
|
const [planPath, outArg] = process.argv.slice(2);
|
||
|
|
if (!planPath) { console.error('usage: node tools/stack-render.mjs <plan.mjs> [outDir]'); process.exit(1); }
|
||
|
|
|
||
|
|
const plan = (await import(pathToFileURL(resolve(planPath)).href)).default;
|
||
|
|
const outDir = resolve(outArg || `fable/stack/candidates/${plan.id}`);
|
||
|
|
mkdirSync(outDir, { recursive: true });
|
||
|
|
|
||
|
|
const { planes } = renderStack(plan);
|
||
|
|
const zmm = planeDepths(plan);
|
||
|
|
|
||
|
|
const manifest = {
|
||
|
|
id: plan.id, title: plan.title || plan.id, seed: plan.seed,
|
||
|
|
geometry: { thickness: plan.geometry?.thickness ?? 3, gap: plan.geometry?.gap ?? 6 },
|
||
|
|
planes: [],
|
||
|
|
};
|
||
|
|
planes.forEach((p, i) => {
|
||
|
|
const file = `plane-${String(i).padStart(2, '0')}-${p.sheet}-${p.face}.svg`;
|
||
|
|
writeFileSync(`${outDir}/${file}`, p.svg);
|
||
|
|
manifest.planes.push({ file, sheet: p.sheet, face: p.face, zmm: zmm[i], label: p.label });
|
||
|
|
console.log(` ${file} z=${zmm[i]}mm ${p.label}`);
|
||
|
|
});
|
||
|
|
writeFileSync(`${outDir}/manifest.json`, JSON.stringify(manifest, null, 2));
|
||
|
|
console.log(`→ ${outDir} (${planes.length} planes)`);
|