aether-renderer-core 0.5.0

Render PNG image sequences to transparent WebM (VP9), ProRes 4444 MOV, GIF or MP4 with ffmpeg
Documentation
# ๐Ÿชผ Aether Renderer Core

**Turn a folder (or zip) of transparent PNG frames into a WebM, MOV, GIF or MP4, with the transparency intact.**

[![Crates.io](https://img.shields.io/crates/v/aether-renderer-core.svg)](https://crates.io/crates/aether-renderer-core)
[![Downloads](https://img.shields.io/crates/d/aether-renderer-core.svg)](https://crates.io/crates/aether-renderer-core)
[![CI](https://github.com/madspaaskesen/aether-renderer-core/actions/workflows/ci.yml/badge.svg)](https://github.com/madspaaskesen/aether-renderer-core/actions/workflows/ci.yml)
[![docs.rs](https://docs.rs/aether-renderer-core/badge.svg)](https://docs.rs/aether-renderer-core)
[![License](https://img.shields.io/crates/l/aether-renderer-core.svg)](LICENSE)

Exported an animation from Blender, After Effects, a canvas or an AI tool as a PNG
sequence and need it on a website, in a video editor or in a chat? One command:

```bash
aether-renderer-core -i frames/ -o animation.webm
```

![Example animation](https://mp-it.dk/images/aether-renderer/sacred-stars-preview.gif)

**[Project page](https://mp-it.dk/projects/aether-renderer)** ยท
[Download](https://github.com/madspaaskesen/aether-renderer-core/releases) ยท
[GUI app](https://github.com/madspaaskesen/aether-renderer-gui) ยท
[Changelog](CHANGELOG.md)

---

## โœจ Features

- ๐Ÿซง **Transparent output** in WebM (VP9), MOV (ProRes 4444) and GIF; MP4 for when you don't need alpha
- ๐Ÿ“ฆ Frames from a **folder or a ZIP** (macOS `__MACOSX` / `._` files are skipped)
- ๐Ÿ”ข Frames in **natural order**: `frame_2.png` comes before `frame_10.png`, with or without zero padding
- ๐ŸŒ— **Fade in / fade out** that fades to *transparent*, not to black
- ๐ŸŽ›๏ธ Options on the command line, in a **JSON or TOML config**, or both (the command line wins)
- ๐Ÿ–ผ๏ธ **Preview** a single frame without rendering
- ๐Ÿ’ป macOS, Linux and Windows, with prebuilt binaries
- ๐Ÿฆ€ Also a **Rust library**: the [Aether Renderer GUI]https://github.com/madspaaskesen/aether-renderer-gui is built on it

## Which format should I use?

| Format | Transparency | Best for |
|---|---|---|
| `webm` *(default)* | โœ… | Websites (Chrome, Firefox, Edge), small files |
| `mov` | โœ… full quality | Video editors: Premiere, DaVinci Resolve, Final Cut, After Effects |
| `gif` | โœ… on/off per pixel | Chat, email, README files, anywhere video isn't allowed |
| `mp4` | โŒ | Everything else, social media, maximum compatibility |

The format is taken from the output file name (`-o loop.gif` renders a GIF), or set it with `--format`.

> Safari does not play transparent WebM. For transparent video on Safari, use a GIF,
> or serve a HEVC-with-alpha version next to the WebM (on the roadmap).

---

## ๐Ÿ“ฆ Install

You need [ffmpeg](https://ffmpeg.org/download.html) on your `PATH`:

```bash
brew install ffmpeg            # macOS
sudo apt install ffmpeg        # Ubuntu / Debian
winget install Gyan.FFmpeg     # Windows
```

Then either download a binary from [Releases](https://github.com/madspaaskesen/aether-renderer-core/releases)
(macOS Apple Silicon and Intel, Linux, Windows), or install with Cargo:

```bash
cargo install aether-renderer-core
```

---

## ๐Ÿ”ง Usage

```bash
# folder of PNGs -> transparent WebM at 30 fps
aether-renderer-core -i frames/ -o out.webm

# from a zip, as a GIF at 24 fps
aether-renderer-core -i frames.zip -o out.gif --fps 24

# for a video editor, with a soft 1 second fade in and out
aether-renderer-core -i frames/ -o out.mov --fade-in 1 --fade-out 1

# higher quality WebM (lower crf = better, default 30)
aether-renderer-core -i frames/ -o out.webm --crf 20

# only some files, or a numbered sequence
aether-renderer-core -i renders/ -o scene1.webm --file-pattern 'scene1_*.png'
aether-renderer-core -i renders/ -o out.webm --file-pattern 'frame_%04d.png'

# check a frame first: saves the middle frame (or frame 12) as out.png
aether-renderer-core -i frames/ -o out.webm --preview
aether-renderer-core -i frames/ -o out.webm --preview 12
```

### All options

| Option | Default | Description |
|---|---|---|
| `-i, --input` | *required* | Folder or `.zip` with the frames |
| `-o, --output` | `output.<format>` | Output file |
| `--format` | from the output extension, else `webm` | `webm`, `mov`, `gif` or `mp4` |
| `--fps` | `30` | Frames per second |
| `--file-pattern` | `*.png` | Glob (`scene_*.png`) or numbered sequence (`frame_%04d.png`) |
| `--fade-in` | `0` | Seconds to fade in from transparent (from black for mp4) |
| `--fade-out` | `0` | Seconds to fade out at the end |
| `--crf` | webm `30`, mp4 `23` | Constant quality, lower is better (webm 0โ€“63, mp4 0โ€“51) |
| `--bitrate` | | Target bitrate instead, e.g. `2M` (if both are set, `--crf` wins) |
| `--preview [N]` | | Save frame `N` (default: the middle frame) as a PNG instead of rendering |
| `--open` | | Open the result when done |
| `-c, --config` | | JSON or TOML config file, see below |
| `-v, --verbose` | | Details and a progress spinner |
| `--verbose-ffmpeg` | | Show ffmpeg's own output |

If ffmpeg fails, the error shows ffmpeg's own explanation, and no half-written file is left behind.

### Config files

Every option can live in a `.json` or `.toml` file; anything you also pass on the
command line overrides the file. Handy for keeping a project's settings next to its
frames:

```toml
# render.toml
input = "frames"
output = "loop.webm"
fps = 24
fade_in = 0.5
fade_out = 0.5
crf = 24
```

```bash
aether-renderer-core --config render.toml
aether-renderer-core --config render.toml --fps 60 -o draft.mov   # override
```

The same in JSON: [examples/example_config.json](examples/example_config.json).
Relative paths are relative to the folder you run the command from.

---

## ๐Ÿฆ€ As a library

```toml
[dependencies]
aether-renderer-core = "0.5"
```

```rust
use aether_renderer_core::config::PartialConfig;

let cfg = PartialConfig {
    input: Some("frames".into()),
    output: Some("out.webm".into()),
    fps: Some(24),
    ..Default::default()
}
.into_config()?;

let report = aether_renderer_core::render(cfg)?;
println!("{}", report.summary());
```

`RenderConfig::from_file("render.toml")` loads a config file, and
`aether_renderer_core::preview_frame` extracts a single frame.

---

## ๐Ÿงช Development

```bash
cargo test                      # ffmpeg tests are skipped when ffmpeg is missing
cargo clippy --all-targets -- -D warnings
cargo fmt
```

The tests render real transparent, odd-sized frames to every format and check the
result with `ffprobe`: size, frame rate, codec and alpha. CI runs them on Linux, macOS
and Windows.

### Benchmark

A single frame duplicated N times, rendered to WebM:

| Frames | Total time (s) | Avg time/frame (ms) |
| ------ | -------------- | ------------------- |
| 1      | 1.17           | 1173.9              |
| 100    | 1.79           | 17.9                |
| 1000   | 13.13          | 13.1                |
| 10000  | 112.07         | 11.2                |

*Measured with 0.4 (VP8). 0.5 uses VP9, which in our tests takes about 20% longer and
gives files about 40% smaller at better quality.*

---

## ๐Ÿชผ Aether Renderer GUI

Prefer drag and drop? The [Aether Renderer GUI](https://github.com/madspaaskesen/aether-renderer-gui)
is a desktop app built on this crate.

![Aether Renderer GUI](https://mp-it.dk/images/aether-renderer/aether-renderer-gui-preview-v0.1.1-light-dark-fade.gif)

Download the installer from the [GUI releases](https://github.com/madspaaskesen/aether-renderer-gui/releases).

## ๐Ÿ“ฆ Example frames

Try it with [sacred-stars.zip](https://mp-it.dk/images/aether-renderer/sacred-stars.zip):

```bash
aether-renderer-core -i sacred-stars.zip -o stars.webm
```

---

## ๐Ÿ”ฎ Roadmap

- [x] WebM with alpha, MP4, GIF
- [x] Bitrate / CRF quality control, fades
- [x] Preview a single frame
- [x] GUI version with Tauri
- [x] ProRes 4444 MOV, TOML config, config + CLI override, Windows-safe input (0.5)
- [ ] Safari-ready transparent video (HEVC with alpha) and a `--format web` that writes both
- [ ] Resize and crop (`--width`, `--height`)
- [ ] Frames from stdin, for piping from canvas and AI tools

Ideas and bug reports are welcome in [issues](https://github.com/madspaaskesen/aether-renderer-core/issues).

---

## ๐ŸŒฟ License & author

MIT. Built and maintained by Mads Paaskesen, Hardcore Websmith at
[MP-IT](https://mp-it.dk), with ๐Ÿ’› from [Sacred-AI](https://sacred-ai.com).

Need custom rendering pipelines, video automation or a Rust/Node.js backend?
[Get in touch](https://mp-it.dk/contact).

[![mySiteChart](https://badges.mysitechart.com/github-project/madspaaskesen/aether-renderer-core?site=COM)](https://mysitechart.com/In?github-project=madspaaskesen%2Faether-renderer-core)