diff --git a/assets/femm.svg b/assets/femm.svg
index 3271172..d2f8281 100644
--- a/assets/femm.svg
+++ b/assets/femm.svg
@@ -1,5 +1,125 @@
-
-
\ No newline at end of file
+
+
diff --git a/crates/femm-app/Cargo.toml b/crates/femm-app/Cargo.toml
index 24e02a3..f568250 100644
--- a/crates/femm-app/Cargo.toml
+++ b/crates/femm-app/Cargo.toml
@@ -15,3 +15,6 @@ femm-doc-mag = { workspace = true }
iced = { version = "0.14", features = ["canvas", "svg", "tokio"] }
rfd = "0.17"
meval = "0.2"
+tokio = { version = "1", features = ["rt", "rt-multi-thread"] }
+libc = "0.2"
+tiny-skia = "0.11"
diff --git a/crates/femm-app/src/doc_canvas.rs b/crates/femm-app/src/doc_canvas.rs
index 8af57f7..501dc04 100644
--- a/crates/femm-app/src/doc_canvas.rs
+++ b/crates/femm-app/src/doc_canvas.rs
@@ -8,7 +8,7 @@ use iced::widget::canvas::{
};
use iced::{Color, Element, Length, Point, Radians, Rectangle, Renderer, Theme, Vector, mouse};
-const PADDING_PX: f32 = 24.0;
+const PADDING_PX: f32 = 48.0;
const NODE_RADIUS: f32 = 3.0;
const STROKE_WIDTH: f32 = 1.2;
const LABEL_TICK_PX: f32 = 6.0;
@@ -29,9 +29,9 @@ const FLUX_LINE_COLOR: Color = Color::from_rgba(0.0, 0.0, 0.0, 0.85);
const FLUX_LINE_STROKE: f32 = 0.6;
const BAND_COUNT: usize = 20;
const FLUX_LINE_COUNT: usize = 19;
-const GRID_COLOR: Color = Color::from_rgba(0.5, 0.5, 0.5, 0.25);
-const GRID_STROKE: f32 = 0.5;
-const GRID_MIN_PX_SPACING: f32 = 4.0;
+const GRID_COLOR: Color = Color::from_rgba(0.55, 0.65, 0.85, 0.55);
+const GRID_STROKE: f32 = 0.6;
+const GRID_MIN_PX_SPACING: f32 = 5.0;
/// field-plot mode applied on top of the FE solution.
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
diff --git a/crates/femm-app/src/export.rs b/crates/femm-app/src/export.rs
new file mode 100644
index 0000000..f7356f3
--- /dev/null
+++ b/crates/femm-app/src/export.rs
@@ -0,0 +1,423 @@
+//! offline RGBA frame renderer piping to an ffmpeg VP9 encoder.
+
+use std::collections::HashMap;
+use std::io::{Read, Write};
+use std::path::PathBuf;
+use std::process::{Command, Stdio};
+use std::sync::{Arc, Mutex};
+use std::thread;
+
+use femm_doc_mag::FemmDoc;
+use femm_doc_mag::ans::MagSolution;
+use tiny_skia::{Color, FillRule, Paint, PathBuilder, Pixmap, Stroke, Transform};
+
+use crate::kinematic::{self, Track};
+
+const BAND_COUNT: usize = 20;
+const FLUX_LINE_COUNT: usize = 19;
+const PADDING_PX: f64 = 48.0;
+
+pub struct ExportInput {
+ pub dest: PathBuf,
+ pub base_doc: FemmDoc,
+ pub tracks: Vec