Files
blumia a237a7c604 Add one-line score visualizer with 3D orb and MP4 export
- Verovio single-system engraving, MuseScore audio/MIDI from the same source
- React + Remotion player with live camera, colour and orb controls
- Express pipeline, render queue and local H.264/AAC export
- MIT license plus third-party notices for the reference skill
2026-11-05 11:38:25 +08:00

45 lines
1.5 KiB
TypeScript

import fs from 'node:fs';
import {buildScrollKeys} from '../src/shared/scroll.js';
import type {RenderData, VisualSettings} from '../src/shared/types.js';
/** Builds Remotion still props for a finished job, using exactly its saved settings. */
const id = process.argv[2];
if (!id) throw new Error('usage: tsx scripts/props-from-job.ts <jobId> [outFile]');
const out = process.argv[3] ?? 'data/check/p-job.json';
const data = JSON.parse(fs.readFileSync(`data/jobs/${id}/score.json`, 'utf8')) as RenderData;
const job = JSON.parse(fs.readFileSync(`data/jobs/${id}/job.json`, 'utf8')) as {
settings?: Partial<VisualSettings>;
};
const settings: VisualSettings = {...data.settings, ...(job.settings ?? {})};
const displayHeight = settings.height * settings.scoreHeightRatio;
const displayScale = displayHeight / Math.max(1, data.meta.svgHeight);
const viewWidthScore = settings.width / displayScale;
const maxLeft = Math.max(0, data.meta.svgWidth - viewWidthScore);
const scroll = buildScrollKeys(
data.events,
settings.scrollLead,
viewWidthScore,
maxLeft,
data.meta.musicDuration,
);
fs.writeFileSync(
out,
JSON.stringify(
{
data: {
...data,
settings,
scroll,
svgUrl: `http://127.0.0.1:3001/jobs/${id}/score.svg`,
audioUrl: `http://127.0.0.1:3001/jobs/${id}/audio.wav`,
},
},
null,
2,
),
);
console.log(`${out}: ${settings.width}x${settings.height} tiltX=${settings.tiltX} tiltZ=${settings.tiltZ}`);