The current release is 0.1.0.
@lgs1920/video-builder is a provider-based video composition core. It reads a
serializable timeline containing video, Cesium, overlay, widget, text, and audio
tracks, resolves the active clips for every output frame, and gives providers a
deterministic render and encode boundary.
The package currently provides the timeline model, frame resolver, render plan, presentation resolution, dry-run validation, lossless sequential frame sinks, and session lifecycle. Studio integrations for Cesium rendering, media decode, widget rendering, audio mixing, compositing, and concrete encoders are provider responsibilities and are intentionally kept outside this dependency-free core.
bun add @lgs1920/video-builderimport {renderVideoBuilder} from '@lgs1920/video-builder'
const artifact = await renderVideoBuilder({
duration: 4,
output: {width: 1920, height: 1080, fps: 30},
tracks: [
{id: 'scene', type: 'cesium', clips: [{id: 'map', start: 0, duration: 4}]},
{id: 'titles', type: 'text', clips: [{id: 'title', start: 1, duration: 2, data: {value: 'Flight'}}]},
{id: 'voice', type: 'audio', clips: [{id: 'narration', start: 0, duration: 4}]},
],
}, {
renderFrame: async frame => renderStudioLayers(frame),
encodeFrame: async (renderedFrame, frame) => encodeOutput(renderedFrame, frame),
writeFrame: async (encodedFrame, frame) => writeFrameToEncoder(encodedFrame, frame),
finalize: async encodedFrames => createVideoArtifact(encodedFrames),
dispose: async () => releaseStudioResources(),
})The plan exposes index, frameCount, frameInterval, isFirst, and
isLast on every frame. Each active clip also exposes its clipTime,
normalized progress, source localTime, and resolved presentation. Video
clips are also available through frame.videoClips, so a media provider can
seek or decode them at the exact output timestamp. A clip
presentation contains serializable values and optional time-based keyframes:
{
values: {opacity: 0, transform: {x: 0}},
keyframes: [
{time: 0, values: {opacity: 0, transform: {x: 0}}},
{time: 1, values: {opacity: 1, transform: {x: 100}}, easing: 'ease-out'},
],
}Use renderVideoBuilder(definition, providers, {dryRun: true}) to validate the
timeline and call the optional validateFrame provider for every frame without
rendering or encoding. A writeFrame provider is called sequentially after
encoding; this gives Studio a bounded encoder boundary without retaining every
encoded frame in memory. The session waits for each write to finish, so a slow
encoder creates backpressure instead of silently dropping frames.
Audio is planned separately in plan.audio. createVideoBuilderAudioPlan()
returns the complete audio clip ranges, source ranges, gains, and fades, and
resolveVideoBuilderAudioAtTime() is available for a sample or mixer clock.
Audio providers should mix or encode this continuous plan and pass the result
to the final muxer; they should not recreate audio by sampling one audio value
per video frame.
For the complete boundary and Studio integration direction, read
docs/VIDEO-BUILDER-ARCHITECTURE.md and
docs/STUDIO-MIGRATION.md.
bun install
bun run verify
bun run demo:serveThe package uses the LGS1920 Bun build and npm publication workflow. Preview a
version increment with bun run publish -- --patch --preview; publication is a
separate release action and is never performed by verification.
MIT © LGS1920