Skip to content
dmtrKovalenkoPublic

About

programmatic video rendering framework that is actually fast

Topics

Resources

Stars

3.1k stars

Watchers

56 watching

Forks

Latest commit

 

History

304 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

fframes

Video vibe coding framework that is actually fast.

crates.io docs.rs MIT license @fframes_rust on X

fframes-intro-1080p.mp4

What is it for

fframes is a framework for rendering videos from code. Assuming you are not going to write the thousands lines of code fora video yourself our goal is quick and efficient iteration speed for your AI agent, great and useful real time preview for you, and fastest in industry rendering speed (we are over 30x faster than remotion).

Get started

Start with a skill and ask your favorite AI agent to make something you want. Then iterate.

npx skills add https://fframes.studio

Here is how your videos composed in the code

Every frame is an SVG tree returned by a Rust function, written with the svgr! macro. From examples/hello-world, shortened: a square moves along a timeline and a line of text prints the current frame.

Show the code
impl Video for HelloWorldVideo<'_> {
    const FPS: usize = 30;
    const WIDTH: usize = 1920;
    const HEIGHT: usize = 1080;

    fn duration(&self) -> fframes::Duration<'_> {
        fframes::Duration::Seconds(30.)
    }

    fn audio(&self) -> AudioMap<'_> {
        AudioMap::none()
    }

    fn render_frame(&self, frame: Frame, ctx: &FFramesContext) -> fframes::Svgr<'_> {
        fframes::svgr!(
            <svg
                xmlns="http://www.w3.org/2000/svg"
                viewBox="0 0 1920 1080"
                width={ctx.current_video_size.width}
                height={ctx.current_video_size.height}
            >
                <rect
                    x="400"
                    y="400"
                    width="200"
                    height="200"
                    fill="blue"
                    transform={frame.animate(fframes::timeline!(
                        at 0., animate Transform::translate(0, 0) => Transform::translate(200, 480), Easing::Linear,
                        at 2. => 6.0, animate Transform::translate(200, 480) => Transform::translate(750, -400), Easing::Linear,
                        at 6.0 => 10.0, animate Transform::translate(750, -400) => Transform::translate(1310, 480), Easing::Linear,
                    ))}
                />

                <text
                    x="100"
                    y="440"
                    font-family="JetBrains Mono"
                    font-size="74"
                    font-weight="500"
                    fill="#3b5563"
                >
                    {format!("This frame index: {}, second: {:.2}", frame.index, frame.seconds())}
                </text>
            </svg>
        )
    }
}

Inspiration

Here is a list of some of the examples we store in the repo. Feel free to inspire steal them for your videos. Click an example name to browse its source, or a poster for a preview.

The 128 second launch video, everything placed on the beat grid of its soundtrack.

Watch fframes-intro

A 20 second promo with pixel objects, a perspective carousel, thermal shaders and per-exposure vector ink, an adaptation of a reference film.

Watch made-of-motion

A simple "hello world" video. A good start if you want to really read the code.

Watch hello-world

An animated robo arm movement video using 3D capabilities.

Watch arm

A 24 second motion study: product UI, data storytelling and a technical explainer.

Watch signal-lab

A complicated multi-scene example (our beta announce video).

Watch beta

Our announcement video from 2021. With audio visualization.

Watch marketing

GPU shader layers composed with SVG: an SkSL background and a Shadertoy raymarcher clipped into a card.

Watch shaders

A 31-second shader promo with reference audio, a moving panel wall, native preview footage and 18 GPU shader programs, rendered with Skia on Metal or Vulkan.

The preview is silent: its soundtrack is not in the repository.

Watch shader-mode

A minimal shader clip built to make banding and motion artifacts easy to spot.

Watch neon-triangle

An svgr UI on the screen of a turning 3D monitor, showing a 3D cube with the svgr logo: four nested levels of SVG and 3D that never leave the GPU.

Watch svg-in-3d

A showcase of different effects available for Captions module in fframes

Caption presets and custom word highlights

Beautiful sound waves audio visualization + subtitles for your video.

Watch audio-announce

An audio visualization for a podcast placeholder video.

Watch podcast

Teej's podcast with 2 speakers video and chapters visualization.

Watch teej-podcast

A TikTok-like vertical video with audio visualization

Watch tiktok

An 18 second vertical launch video for Lottie support: every animation is a Lottie file and the music is synthesized in Rust.

Watch lottie

One splash screen per conference talk, rendered in batch.

Watch conference-splash-screen

A renderer stress test: animal art with a lot of polygons.

Watch low-poly-art

My dog's memorial video generator (totally randomized).

Watch pixel-memory

Without an agent

cargo install --locked cargo-fframes
cargo fframes new my-video
cd my-video && cargo run --release -- preview

The preview timeline sits below landscape and square videos and to the left of portrait videos. Drag the filmstrip to scrub, or click a scene marker to pause on its first frame. Use [ and ] to jump between scenes and , and . to step one frame. Press Space to play or pause, or T to hide the timeline and expand the video.

On macOS the studio tries VideoToolbox for supported source videos and falls back to software for unsupported formats. preview --software-decode uses the CPU for decoding while keeping the selected drawing backend. Playback and filmstrip workers release idle source decoders. The GPU preview draws each scene through Skia directly into the window drawable or swapchain. The default buffer holds up to four prepared scene trees, and only the frame under the pointer is prepared while you drag the timeline. Decoders reuse the pixel buffers of frames that no scene tree holds any more. The CPU backend draws directly into the window buffer.

cargo fframes new takes --template single-scene|multi-scene, --format landscape|portrait|square|uhd, --fps, --title and --backend. On macOS and Linux (arm64, x86_64) the first build downloads prebuilt Skia and ffmpeg libraries and takes under a minute on a fast machine; other targets and feature combinations compile them from source (up to ~20 minutes). Later builds take seconds. --backend cpu skips Skia (no preview window, slower renders). To track main, install with --git https://github.com/dmtrKovalenko/fframes.

Requirements

Rust and, for working on the editor, NodeJS. fframes links ffmpeg's libav libraries statically. A prebuilt build is downloaded for macOS and Linux (arm64 and x86_64) and compiled from source for other targets or FFMPEG_FORCE_BUILD=1; either way the system encoders they link against have to be installed.

The examples enable fframes/build-portable on native non-Windows targets. CI builds the whole workspace, combining the examples' x264, x265, VPX and Opus features; no published FFmpeg archive currently matches that combination, so it falls back to a source build. Without build-portable, that build uses -march=native -mtune=native. Caching it and restoring it on a runner with a different CPU can cause SIGILL (illegal instruction). The feature omits those flags for source builds while keeping matching prebuilt downloads enabled, and also applies to FFmpeg used by the compile-time media macro.

Within this workspace, use the same setting for native builds that will be cached or run on other machines:

[target.'cfg(not(any(target_arch = "wasm32", windows)))'.dependencies]
fframes = { workspace = true, features = ["build-portable"] }

build-portable also enables FFmpeg's source-build support, so the examples exclude Windows (which links a shared FFmpeg installation) and browser targets. Setting FFMPEG_MARCH or FFMPEG_MTUNE, even to an empty string, bypasses prebuilt downloads; prefer the feature when you want portable source fallbacks and prebuilt downloads.

macOS
brew install pkg-config ffmpeg x264 x265 opus nasm ninja
Linux

for debian based distros:

sudo apt-get install -y yasm nasm ffmpeg libx264-dev libx265-dev libopus-dev libclang-dev clang ninja-build libvpx-dev libasound2-dev

for arch based distros:

sudo pacman -S ninja yasm nasm ffmpeg x264 x265 opus clang

for nix users:

nix-shell
Windows

On Windows ffmpeg is not compiled from source. Instead fframes links a prebuilt FFmpeg 9.0 shared build (for example ffmpeg-n9.0-latest-win64-gpl-shared-9.0.zip from BtbN/FFmpeg-Builds) and needs LLVM for bindgen:

winget install LLVM.LLVM
# unzip the ffmpeg build somewhere, then point the build to it:
$env:FFMPEG_DIR = "C:\ffmpeg-n9.0-latest-win64-gpl-shared-9.0"
$env:LIBCLANG_PATH = "C:\Program Files\LLVM\bin"
# the ffmpeg DLLs must be reachable when building (proc macros load them) and running
$env:PATH = "$env:FFMPEG_DIR\bin;$env:PATH"

vcpkg install ffmpeg works as well instead of FFMPEG_DIR. Codecs come from the prebuilt build, so leave the codec features (h264, h265, ...) off: they request a from-source ffmpeg build which is not supported on Windows.

Codecs

Cargo features of the fframes crate choose which codecs and hardware acceleration libraries are linked:

[dependencies]
# this will enable and try to link libx264 during the build
fframes = { version = "1", features = ["h264", "libav-agree-gpl"] }

All the build and linking of codecs and other system libs are leveraging the ffmpeg build system, so for troubleshooting please refer the ffmpeg compilation guide.

Troubleshooting
  • Build fails in ffmpeg-sys-fframes: a system library from the list above is missing (nasm, pkg-config, the codec packages).
  • Build fails in the Skia bindings with a bindgen or libclang error (only when Skia is compiled from source, e.g. with both metal and vulkan enabled): point LIBCLANG_PATH at a working libclang, on macOS Xcode's: export LIBCLANG_PATH=$(xcode-select -p)/Toolchains/XcodeDefault.xctoolchain/usr/lib.
  • Text renders in the wrong font: inspect reports No match for ... font-family; put the font file in the project's media/ folder and use its exact family name.

Working on fframes

Agents working on fframes itself should start from AGENTS.md. For humans, install the just command runner and init the repo:

npm install --global pnpm # the package manager for the nodejs based editor
cargo install --locked just cargo-watch wasm-bindgen-cli wasm-pack
just init-repo
just watch-editor # in a separate terminal, to work on the editor

License

fframes is released under the MIT License.

About

programmatic video rendering framework that is actually fast

Topics

Resources

Stars

3.1k stars

Watchers

56 watching

Forks

Releases

Packages

Contributors

Languages