stemedb/applications/video-renderer/src/render-pitch.ts
jordan 157dbbb9eb feat: Complete Aphoria Phase 8-9 + UAT suite (90/90 tests passing)
## Phase 8: Enterprise Extractor Improvements 
- 14 security extractors (TLS, JWT, SQL injection, XSS, etc.)
- 10 framework-specific extractors (Spring, Django, Rails, etc.)
- Config file security detection (YAML, TOML)

## Phase 9: Autonomous Extractor Generation 
- Shadow mode executor with TP/FP tracking
- Graduation pipeline with confidence thresholds
- Auto-rollback on regression detection
- Cross-project pattern syncing

## UAT Suite Complete (14 scripts, 90 tests)
- test-core-detection.sh (6 tests)
- test-declarative-extractors.sh (5 tests)
- test-domain-frameworks.sh (5 tests)
- test-domain-unreal.sh (3 tests)
- test-llm-extraction.sh (6 tests)
- test-eval-harness.sh (5 tests)
- test-cross-language.sh (3 tests)
- test-precommit-performance.sh (4 tests)
- test-output-formats.sh (8 tests)
- test-drift-detection.sh (6 tests)
- test-exit-codes.sh (12 tests)
+ 3 more scripts

## Other Changes
- Updated roadmap to mark Phase 8-9 complete
- Added .gitignore entries for build artifacts
- Updated pre-commit: 800 line limit, exclude tests/data/cmd

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-06 22:50:55 -07:00

77 lines
2.2 KiB
TypeScript

/**
* Pitch Video Render Script
*
* Programmatic rendering of pitch videos via Remotion API.
* Usage: pnpm render:pitch:api [script.json] [output.mp4]
*/
import { bundle } from '@remotion/bundler';
import { renderMedia, selectComposition } from '@remotion/renderer';
import path from 'path';
import fs from 'fs';
import { stemedbPitchScript } from './data/stemedb-pitch';
import { calculateTotalDuration } from './types/pitch-script';
import type { PitchScript } from './types/pitch-script';
async function main() {
const args = process.argv.slice(2);
const scriptPath = args[0];
const outputPath = args[1] || 'out/stemedb-pitch.mp4';
// Load script from file or use default
let script: PitchScript;
if (scriptPath && fs.existsSync(scriptPath)) {
console.log(`Loading script from ${scriptPath}`);
script = JSON.parse(fs.readFileSync(scriptPath, 'utf-8'));
} else {
console.log('Using default StemeDB pitch script');
script = stemedbPitchScript;
}
// Calculate total duration
const totalDuration = calculateTotalDuration(script.blocks);
console.log(`Total duration: ${(totalDuration / 1000).toFixed(1)}s (${script.blocks.length} blocks)`);
// Bundle the Remotion project
console.log('Bundling...');
const bundleLocation = await bundle({
entryPoint: path.resolve(__dirname, './index.ts'),
webpackOverride: (config) => config,
});
// Select the composition
const composition = await selectComposition({
serveUrl: bundleLocation,
id: 'PitchVideo',
inputProps: { script },
});
// Ensure output directory exists
const outputDir = path.dirname(outputPath);
if (!fs.existsSync(outputDir)) {
fs.mkdirSync(outputDir, { recursive: true });
}
// Render the video
console.log(`Rendering to ${outputPath}...`);
await renderMedia({
composition,
serveUrl: bundleLocation,
codec: 'h264',
outputLocation: outputPath,
inputProps: { script },
onProgress: ({ progress }) => {
const percent = Math.round(progress * 100);
process.stdout.write(`\rProgress: ${percent}%`);
},
});
console.log('\nDone!');
console.log(`Output: ${path.resolve(outputPath)}`);
}
main().catch((err) => {
console.error(err);
process.exit(1);
});