Rust walkthrough#
Rust is a first-class authoring path. You can use ordinary synchronous functions
and loops with BlockingScene; async syntax is not required for this lesson.
The following source is included directly from the repository, so the guide does
not keep an independent copy of its API calls.
The complete synchronous lesson#
//! A complete synchronous lesson using ordinary helpers and shared resources.
//!
//! The paired Python source is `web/python/examples/first_lesson.py`. Native
//! execution is `cargo run -p noon-native --example first_lesson`; the same source
//! exports with `cargo run -p noon-export --example first_lesson -- lesson.mp4`.
use crate::{
AnimationOptions, BlockingScene, Color, MathTypst, MobjectFamily, RateFunction, ScriptError,
Text, Vec2,
};
fn step(scene: &BlockingScene, shapes: &MobjectFamily) -> Result<(), ScriptError> {
scene.play_with(
shapes.animate().shift(Vec2::new(0.75, 0.0)),
AnimationOptions::new()
.run_time(0.5)
.rate_func(RateFunction::Linear),
)
}
/// Construct two seconds of text, math and grouped motion without async syntax.
pub fn construct(scene: &BlockingScene) -> Result<(), ScriptError> {
let title = scene.text(
Text::new("One scene, ordinary functions")
.with_font_size(36.0)
.shift(Vec2::new(0.0, 2.7)),
)?;
let equation = scene.math_typst(
MathTypst::new("x(t) = x_0 + v t")
.with_font_size(48.0)
.shift(Vec2::new(0.0, 1.6)),
)?;
scene.add(&title)?;
scene.add(&equation)?;
let square = scene.square(0.8)?;
let circle = scene.circle(0.4)?;
scene.set_fill(&square, Color::BLUE, 1.0)?;
scene.set_fill(&circle, Color::ORANGE, 1.0)?;
scene.shift(&square, Vec2::new(-0.8, -0.4))?;
scene.shift(&circle, Vec2::new(0.8, -0.4))?;
let shapes = scene.family([&square, &circle])?;
scene.add(&shapes)?;
scene.wait(0.5)?;
for _ in 0..2 {
step(scene, &shapes)?;
}
// This resource is constructed after execution has started. The same Scene
// admits it atomically; the source never needs raw storage or host plumbing.
let caption = scene.text(
Text::new("Two steps, one shared scene")
.with_font_size(24.0)
.shift(Vec2::new(0.0, -2.0)),
)?;
scene.add(&caption)?;
scene.wait(0.5)
}
What the code owns#
BlockingScene exposes the scene-authoring operations. The step helper receives
that scene and a typed family handle. It returns Result<(), ScriptError> so
errors propagate through ordinary Rust error handling. It does not allocate or
manage a separate renderer or event loop.
scene.family groups the shape handles. The animation builder describes a shift;
AnimationOptions supplies its duration and rate function. scene.play_with
waits at the engine's logical completion boundary before the loop continues.
The title, formula and final caption use the same scene resource path.
Run in a native window#
cargo run -p noon-native --example first_lesson
The host runner accepts the scene constructor and owns the native window and event loop. See Rust library details for a complete application and current checkout dependency setup. Do not copy a public registry dependency name before the package name is finalized.
Export the unchanged constructor#
cargo run -p noon-export --example first_lesson -- lesson.mp4
cargo run -p noon-export --example first_lesson -- --png lesson-images
These commands run the same finite lesson through the native export host. An installed FFmpeg is needed for MP4, and rendering needs a supported native GPU backend. See exporting visuals for restrictions and output policy.
Rust in a browser#
Rust source compiled to WASM uses the same semantic, runtime, and renderer responsibilities. Browser integration supplies the canvas and event loop; Python is optional, not a mandatory bridge between the Rust layers. Follow browser integration for the existing direct Rust/WASM examples. Source changes require a rebuild rather than entering Rust into the Python editor.
API and asynchronous authoring#
The generated Rust API contains compiler-produced
signatures and trait relationships. The implementation reference
also explains Scene::script, async completion boundaries, ordinary callbacks,
and the timing difference between Rust animation builders and Python .animate.
Both interfaces reach the same shared engine; choose according to the host and
control flow you need.