Skip to content

Repository files navigation

@lgs1920/video-builder

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.

Install

bun add @lgs1920/video-builder

Basic usage

import {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.

Development

bun install
bun run verify
bun run demo:serve

The 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.

License

MIT © LGS1920

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages