Rust API
Use the engine directly from Rust: look up effects, render their frames, step live instances, composite, hash and export.
Crates
The crates are not on crates.io yet. Depend on them by path or git:
[dependencies]
pixfx-core = { path = "../pixfx-rs/crates/pixfx-core" }
pixfx-effects = { path = "../pixfx-rs/crates/pixfx-effects" }
pixfx-export = { path = "../pixfx-rs/crates/pixfx-export" }
They need the nightly toolchain pinned in the repository's rust-toolchain.toml, edition 2024, and forbid unsafe.
Example
This program is checked to compile and run against the current source.
use std::path::Path;
use pixfx_core::{Frame, Instance, Layer, OptValue, Options, composite, frame_hash, hex, render_frames};
use pixfx_export::{write_gif, write_sheet};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let fx = pixfx_effects::effect("fire/campfire").ok_or("fire/campfire is not registered")?;
// render one loop with options, glow room and no edge fade
let mut opts = Options { seed: Some(7), light: 1.2, ..Options::default() };
opts.palette = Some(vec![hex("#0d1033")?, hex("#3a62e0")?, hex("#ffffff")?]);
opts.extra.insert("height".into(), OptValue::Num(30.0));
let rendered = render_frames(fx, &opts, fx.meta().glow_margin());
let out = Path::new("out");
let files = write_sheet(&rendered, fx.meta(), out, "blue_campfire")?;
write_gif(&out.join("blue_campfire.gif"), &rendered, 3)?;
println!("{}", files.json.display());
// live: step an instance and draw it into a frame you own
let meta = fx.meta();
let mut inst = Instance::new(fx, Options {
x: f64::from(meta.origin.0),
y: f64::from(meta.origin.1),
..Options::default()
});
let mut frame = Frame::new(meta.size.0, meta.size.1, 0, 0);
inst.update(1.0 / 60.0);
frame.clear();
inst.draw(&mut frame, Layer::Both);
let mut rgba = vec![0u8; frame.w as usize * frame.h as usize * 4];
composite(&frame, &mut rgba, None);
println!("hash {:016x}", frame_hash(&frame));
Ok(())
}
pixfx-effects
| Item | What it is |
EFFECTS: &[&'static dyn Effect] | Every effect, in registry order. |
effect(id) -> Option<&'static dyn Effect> | Look one up by id. |
fire::CANDLE, fire::CAMPFIRE, fire::BRAZIER | The effects as statics. |
pixfx-core
Effect, Meta, Options
| Item | What it is |
trait Effect | meta() -> &Meta and spawn(&Options, seed) -> Box<dyn EffectState>. See Write an effect. |
trait EffectState | update(dt) for one simulation sub-step (default: nothing) and draw(&mut Painter, t, Layer). |
struct Meta | id, name, desc, tags, size, origin, duration, looping, fps, seed; is_screen() and glow_margin(). See Concepts. |
struct Options | x, y, flip, angle, seed: Option<u64>, light, palette: Option<Vec<Rgba>>, extra: BTreeMap<String, OptValue>. Default is origin (0, 0), no flip, angle 0, effect seed, light 1, effect palette. |
enum OptValue | Num(f64) or Ramp(Vec<Rgba>): an effect's own option. |
Options::palette_or, ramp_or, num_or | For effects: resolve an option against its default (ramps resampled to the default's length). |
enum Layer | Back, Front, Both. |
find(list, id) | Find an effect by id in any list. |
Instance
| Method | Does |
Instance::new(effect, opts) | Spawn with opts.seed or the effect's seed. opts.x, opts.y place the origin in frame space. |
update(dt) | Advance by at most MAX_DT (0.25 s) in sub-steps of at most 1/120 s. A step failing valid_dt (NaN, infinite, negative) is ignored. |
draw(&mut Frame, Layer) | Draw at the current time on top of what is in the frame. Clear the frame first for a fresh image. |
stop(), done(), t() | As in Concepts. |
Frames and output
| Item | What it is |
struct Frame { w, h, ox, oy, color, light } | w×h pixels whose top-left is at (ox, oy) in world space. color: ABGR words. light: xBGR words. Frame::new, clear(). |
render_frames(effect, &opts, margin) -> Rendered | Every frame of one loop or one-shot at the effect's fps, at its origin whatever opts.x/y say. Margin 0 eases light out at the edge. |
struct Rendered { w, h, fps, margin, frames } | The result. |
composite(&frame, &mut out, bg) | Colour over an optional RGBA background, plus light, into RGBA8 bytes (w × h × 4). |
composite_px(c, l, ground) | One pixel of composite. |
edge_fade(&mut frame) | Ease light out over the last 8 pixels of the frame. |
frame_hash(&frame) -> u64 | FNV-1a 64 over colour then light words, little-endian: a stable fingerprint for golden tests. |
Colour, math, painter
color: Rgba(r, g, b, a) with pack/unpack (ABGR words), hex, to_hex, mix, scale, luma, ramp helpers fit, at, blend.
math: JavaScript-exact helpers (js_round, js_min, js_max, to_int32, to_uint32), easing and shaping (clamp, lerp, smooth, bump, seg, ...), hashing and noise (hash, rand, noise, noise2), and the seeded Rng.
painter: Painter, the drawing API effects use. See Write an effect.
sim: constants shared by simulated effects, such as SMOKE_RAMP.
pixfx-export
| Item | What it is |
write_sheet(&rendered, &meta, out_dir, name) -> Result<SheetFiles, ExportError> | Write <name>.png, _color.png, _light.png and .json, creating out_dir. See Sprite sheet format. |
write_gif(path, &rendered, scale) -> Result<(), ExportError> | A looping GIF over a dark backdrop, each pixel scale×scale. |
Grid, beanfx_json, FileNames | The pure layout and JSON functions behind write_sheet. |
enum ExportError | Io, Png, Gif, Json, or TooBig { w, h, scale } when a scaled image exceeds the format's size field. |