pub struct Scenario {Show 16 fields
pub version: String,
pub video: VideoConfig,
pub audio: AudioValue,
pub fonts: Vec<FontEntry>,
pub scenes: Vec<SceneEntry>,
pub composition: Option<Vec<View>>,
pub config: Option<HashMap<String, VariableDefinition>>,
pub backgrounds: HashMap<String, Value>,
pub components: HashMap<String, ComponentTemplateDef>,
pub annotations: Vec<Annotation>,
pub bpm: Option<f64>,
pub beat_offset: f64,
pub duration: Option<f64>,
pub timing: TimingMode,
pub snap: Option<SnapMode>,
pub vars: VarSet,
}Expand description
Deliberately not #[derive(Deserialize)] — see
[ScenarioDe]/impl From<ScenarioDe> for Scenario just below for why:
this type needs a post-deserialize pass (propagating bpm/beat_offset/
timing/snap down onto every reachable Scene) that a plain derive
can’t express, and every call site that builds a Scenario from JSON
(loader.rs, include.rs’s own included-file loading) is outside this
workstream’s owned files this wave — the propagation has to happen
inside Scenario::deserialize itself so those callers need no changes.
Fields§
§version: String§video: VideoConfig§audio: AudioValueFile-based tracks ("audio": [...], unchanged since before issue
#331) or, for a scenario that synthesises its own soundtrack, a
single object carrying both ("audio": {"tracks": [...], "voices": {...}, "score": [...], "master": {...}}) — see AudioValue.
fonts: Vec<FontEntry>§scenes: Vec<SceneEntry>§composition: Option<Vec<View>>Composition: a sequence of views (slide or world). Mutually exclusive with top-level scenes.
config: Option<HashMap<String, VariableDefinition>>Config definitions for structural components. Each config entry has a type and default value.
backgrounds: HashMap<String, Value>Named background templates that scenes can reference via $ref.
components: HashMap<String, ComponentTemplateDef>Reusable component template definitions — "components": { "name": { "params": {...}, "template": {...} } }, instantiated from a
children entry via {"use": "name", "props": {...}} (see
ComponentTemplateDef). Documented in CLAUDE.md’s
“Factorisation” section.
This field exists so the exported JSON Schema (rustmotion schema)
declares the shape the engine actually accepts — it is not how
components is consumed at runtime. rustmotion_core::expand:: expand_directives (a sibling workstream’s file, outside this one’s
scope) resolves every for-each/use against this block and then
removes the key entirely, before this struct is ever deserialized
— the same way variables::apply_variables consumes config’s
$name placeholders without config disappearing from the struct.
The practical difference: config stays meaningful after expansion
(Scenario::config is read elsewhere), while components is spent
in full during expansion, so this field is always empty by the time
any code outside schema/ could read it.
annotations: Vec<Annotation>Studio feedback annotations. Persisted in the scenario but never read by the renderer or the geometry validator. Skipped on serialization when empty.
bpm: Option<f64>Beats per minute for this scenario’s beat grid (issue #336). None
(default) means no grid exists: any TimePoint beat (b) unit
then fails to resolve with unresolved_beat_unit (schema:
crate::schema::TimeError::NoBpm).
beat_offset: f64Where beat 0 sits on the scenario’s absolute timeline, in seconds.
The grid is beat_offset + n * 60 / bpm — not decoration: a reel
whose first beat lands at 2.2s anchors its grid there, not at 0.
duration: Option<f64>Optional override of the scenario’s total rendered duration, in
seconds. Reserved for downstream consumers (audio/export tooling);
the frame-task scheduler in rustmotion’s encode module does not
read it — under timing: "v2" the total is always at_last + duration_last, computed from the scenes themselves.
timing: TimingModeScene-placement semantics. See TimingMode.
snap: Option<SnapMode>Rounds resolved times onto a grid before scheduling. See SnapMode.
vars: VarSetScenario-level variables (issue #329): a scalar declared once,
animated on the scenario’s absolute timeline, and readable from any
expression in any scene as $name. Visible everywhere; shadowed by
a scene’s own Scene::vars of the same name. See
rustmotion_core::vars for the resolver and the Scope
implementation that reads this.
Trait Implementations§
Source§impl<'de> Deserialize<'de> for Scenario
impl<'de> Deserialize<'de> for Scenario
Source§fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>where
D: Deserializer<'de>,
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>where
D: Deserializer<'de>,
Source§impl JsonSchema for Scenario
impl JsonSchema for Scenario
Source§fn schema_name() -> String
fn schema_name() -> String
Source§fn schema_id() -> Cow<'static, str>
fn schema_id() -> Cow<'static, str>
Source§fn json_schema(generator: &mut SchemaGenerator) -> Schema
fn json_schema(generator: &mut SchemaGenerator) -> Schema
Source§fn is_referenceable() -> bool
fn is_referenceable() -> bool
$ref keyword. Read moreAuto Trait Implementations§
impl !RefUnwindSafe for Scenario
impl !UnwindSafe for Scenario
impl Freeze for Scenario
impl Send for Scenario
impl Sync for Scenario
impl Unpin for Scenario
impl UnsafeUnpin for Scenario
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more