mcpField
B
bevy-capture

bevy-capture

github.com/chrisgliddonDevelopment2678 installsUpdated 9w ago
Repository

About bevy-capture

bevy-capture is a skill for recording Bevy 0.19 camera output, aimed at developers producing gameplay, cinematic, or render-test footage. It explains headless capture setup, encoder selection, and common recording pitfalls.

Key features

  1. 01Headless Camera2d and Camera3d capture
  2. 02MP4, GIF, and PNG sequence output
  3. 03OpenH264 and ffmpeg encoder choices
  4. 04Guidance on deterministic batch capture
  5. 05Troubleshooting encoder and output issues

Use cases

  1. 01Record gameplay or cinematic footage
  2. 02Capture evidence for render tests
  3. 03Choose an encoder for offline or streaming capture

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/chrisgliddon/bevy-skills --skill bevy-capture

After installing, type/bevy-capturein Claude Code to confirm it loaded.

Bundled filesreferences/compatibility.mdreferences/encoders.md

Details

From the project README

bevy-capture — recording Bevy 0.19 cameras

When to use this skill

  • Record deterministic gameplay, cinematics, or render-test evidence.
  • Capture a headless Camera2d/Camera3d to MP4, GIF, or numbered PNGs.
  • Choose between in-process OpenH264, ffmpeg, and lossless frame output.
  • Diagnose a missing encoder module, an empty output, or an unflushed recording.

bevy_capture = "0.6" natively targets Bevy 0.19. Do not carry forward the 0.4.x Bevy patch or its old CameraTargetHeadless API.

Canonical pattern

[dependencies]
bevy = "0.19"
bevy_capture = { version = "0.6", features = ["mp4_openh264"] }
use bevy::{
    app::{RunMode, ScheduleRunnerPlugin},
    camera::RenderTarget,
    prelude::*,
    render::RenderPlugin,
    winit::WinitPlugin,
};
use bevy_capture::{
    encoder::mp4_openh264::Mp4Openh264Encoder,
    Capture, CaptureBundle, CapturePlugin, RenderTargetHeadless,
};
use std::fs::{self, File};

const WIDTH: u16 = 1280;
const HEIGHT: u16 = 720;

fn main() -> AppExit {
    App::new()
        .add_plugins((
            DefaultPlugins.build().disable::<WinitPlugin>().set(RenderPlugin {
                synchronous_pipeline_compilation: true,
                ..default()
            }),
            ScheduleRunnerPlugin {
                run_mode: RunMode::Loop { wait: None },
            },
            CapturePlugin,
        ))
        .add_systems(Startup, setup)
        .add_systems(Update, record)
        .run()
}

fn setup(mut commands: Commands, mut images: ResMut<Assets<Image>>) {
    commands.spawn((
        Camera2d,
        RenderTarget::target_headless(WIDTH.into(), HEIGHT.into(), &mut images),
        CaptureBundle::default(),
    ));
}

fn record(
    mut captures: Query<&mut Capture>,
    mut waited_for_pipeline: Local<bool>,
    mut frame: Local<u32>,
) {
    // Allow the render pipeline one frame to become ready.
    if !*waited_for_pipeline {
        *waited_for_pipeline = true;
        return;
    }

    let Ok(mut capture) = captures.single_mut() else { return };
    if !capture.is_capturing() && *frame == 0 {
        fs::create_dir_all("captures").expect("create captures directory");
        let encoder = Mp4Openh264Encoder::new(
            File::create("captures/run.mp4").expect("create output"),
            WIDTH,
            HEIGHT,
        )
        .expect("initialize OpenH264");
        capture.start(encoder);
    }

    *frame += 1;
    if *frame == 300 {
        capture.stop(); // drops the encoder and finalizes the MP4
    }
}

Encoder choice

EncoderFeatureExternal programBest fit
Mp4Openh264Encodermp4_openh264NoIn-process H.264
Mp4FfmpegCliEncodermp4_ffmpeg_cliffmpegShort/offline clips
Mp4FfmpegCliPipeEncodermp4_ffmpeg_cli_pipeffmpegLong streaming captures
GifEncodergifNoSmall previews
FramesEncodernoneNoLossless PNG sequence

See encoder details before choosing a production codec or distribution model.

Gotchas

  • RenderTargetHeadless is implemented for RenderTarget; call RenderTarget::target_headless(...). The old helper on Camera is stale.
  • Attach Camera2d/Camera3d, the headless RenderTarget, and CaptureBundle to the same entity.
  • Wait at least one frame before starting. Synchronous pipeline compilation improves deterministic batch capture but can increase startup time.
  • Encoder modules are feature-gated. Enable exactly the features you import.
  • Capture::stop() or dropping Capture finalizes encoders. Abrupt process termination can leave an invalid MP4 or GIF.
  • The ffmpeg encoders require ffmpeg on PATH; constructors return Result.
  • Match the encoder dimensions to the headless target. OpenH264 takes u16.
  • Browser WASM has no ordinary filesystem or child processes. Design an explicit JS download/streaming path instead of assuming these encoders work.

See also

Comments

Markdown supported