import { failCommand, requestCliExit } from "../utils/commandResult.js"; import { defineCommand } from "citty"; import type { Example } from "./_examples.js"; import { mkdirSync, readdirSync, readFileSync, statSync, writeFileSync, rmSync } from "node:fs"; import { createRenderPlan, resolveBrowserGpuForCli, type RenderFormat } from "./render/plan.js"; import { presentRenderPlan } from "./render/present.js"; import { executeRenderPlan, renderLintContinuationHint } from "./render/execute.js"; // Test-only seams retained at the command boundary for render behavior tests. export { resolveBrowserGpuForCli, renderLintContinuationHint }; export const examples: Example[] = [ ["Render to MP4", "hyperframes render --output output.mp4"], ["Render a specific composition", "hyperframes render -c compositions/intro.html -o intro.mp4"], [ "Upsample any composition to 4K (supersamples via Chrome DPR)", "hyperframes render --resolution 4k --output 4k.mp4", ], ["Render transparent overlay (ProRes)", "hyperframes render --format mov --output overlay.mov"], ["Render transparent WebM overlay", "hyperframes render --format webm --output overlay.webm"], [ "Render animated GIF for PRs/docs", "hyperframes render --format gif --fps 15 --gif-loop 0 --output demo.gif", ], [ "Render PNG sequence (RGBA frames for AE/Nuke/Fusion)", "hyperframes render --format png-sequence --output frames/", ], ["High quality at 60fps", "hyperframes render --fps 60 --quality high --output hd.mp4"], ["Deterministic render via Docker", "hyperframes render --docker --output deterministic.mp4"], ["Parallel rendering with 6 workers", "hyperframes render --workers 6 --output fast.mp4"], ["Opt out of browser GPU render", "hyperframes render --no-browser-gpu --output cpu.mp4"], [ "Relocate frame cache off C: (Windows) or another small partition", "hyperframes render --frames-cache-dir D:/hf-cache --output out.mp4", ], ["HDR output (auto-detected)", "hyperframes render --output hdr-output.mp4"], [ "Override composition variables (parametrized render)", 'hyperframes render --variables \'{"title":"Q4 Report","theme":"dark"}\' --output q4.mp4', ], [ "Variables from a JSON file", "hyperframes render --variables-file ./vars.json --output out.mp4", ], [ "Batch render one output per variables row", 'hyperframes render --batch rows.json --output "renders/{name}.mp4"', ], ]; import { freemem, tmpdir } from "node:os"; import { resolve, dirname, join, basename } from "node:path"; import { execFileSync, spawn } from "node:child_process"; import { loadProducer } from "../utils/producer.js"; import { c } from "../ui/colors.js"; import { formatBytes, formatRenderSummaryDetail, errorBox } from "../ui/format.js"; import { warnIfWebmAlphaDropped } from "../utils/webmAlphaCheck.js"; import { renderProgress } from "../ui/progress.js"; import { trackRenderComplete, trackRenderError, trackRenderObservation, } from "../telemetry/events.js"; import { maybePromptRenderFeedback } from "../telemetry/feedback.js"; import { readConfigFresh, recordRecentRender, writeConfig, type HyperframesConfig, } from "../telemetry/config.js"; import { shouldTrack } from "../telemetry/client.js"; import { renderJobObservabilityTelemetryPayload } from "../telemetry/renderObservability.js"; import { bytesToMb } from "../telemetry/system.js"; import { VERSION } from "../version.js"; import { isDevMode } from "../utils/env.js"; import { buildDockerRunArgs, resolveDockerPlatform } from "../utils/dockerRunArgs.js"; import { normalizeErrorMessage } from "../utils/errorMessage.js"; import { runEnvironmentChecks } from "../browser/preflight.js"; import { detectH264EncoderMode } from "../browser/ffmpeg.js"; import { chromeLaunchRemediation } from "../browser/linuxDeps.js"; import { macosOldChromeCrashRemediation } from "../browser/macosOldChromeCrash.js"; import { killOrphanedProcesses } from "../utils/orphanCleanup.js"; import { markRenderSucceeded, runPostRenderStep, runPostRenderStepAsync, } from "../utils/render-success-state.js"; import type { ProducerLogger, RenderJob } from "@hyperframes/producer"; import { EXTRACT_CACHE_DIR_DISABLED_ALIASES, type VideoFrameFormat } from "@hyperframes/engine"; import { checkOutputResolutionCompatibility, suggestMatchingPreset, fpsToNumber, type CanvasResolution, type OutputResolutionIssueKind, type Fps, } from "@hyperframes/core"; export default defineCommand({ meta: { name: "render", description: "Render a composition to MP4, WebM, MOV, GIF, or a PNG sequence", }, args: { dir: { type: "positional", description: "Project directory", required: false, }, composition: { type: "string", alias: "c", description: "Render a specific composition file instead of index.html (e.g. compositions/intro.html). " + "Sub-compositions using