--- name: bevy-bsn description: Reference for Bevy Scene Notation (BSN) — the bsn! macro for defining inline scenes with components, children, relationships, observers, and dynamic props. metadata: crate: bevy_scene bevy: "0.19" --- ## Basic usage `bsn!` spawns an entity with components inline: ```rust #[derive(Component, Clone, Default)] struct Ship; #[derive(Component, Clone, Default)] struct Player { score: usize } fn spawn_scene(mut commands: Commands) { commands.spawn_scene(bsn! { Player Ship }); } ``` ## Reusable scenes Functions returning `impl Scene` compose together: ```rust fn button() -> impl Scene { bsn! { Button Node { width: px(100) } } } fn main() { App::new() .add_plugins(DefaultPlugins) .add_systems(Startup, my_button.spawn()) .run(); } ``` ## Inline expressions as field values Use `{expr}` for dynamic values: ```rust fn increment_score(current_points: usize) -> impl Scene { bsn! { Player { score: {current_points + 10} } } } ``` ## Scene merging (component combination) Two scenes defining the same component are merged field by field: ```rust fn button() -> impl Scene { bsn! { Button Node { width: px(100) } } } fn my_button() -> impl Scene { bsn! { button() Node { height: px(100) } } } // my_button produces Node with both width: px(100) and height: px(100) ``` ## Entity separation: commas vs whitespace - **Whitespace**: components on the same entity - **Commas**: separates entities ```rust // One child with A and B Children [ A B ] // Two children, one with A, one with B Children [ A, B ] // Two children, clearer with parentheses Children [ (A B), C ] ``` ## Scene and SceneList A `bsn!` expression implements the `Scene` trait and describes a single root entity. A `bsn_list!` (or a scene list inside `Children [...]`) implements `SceneList`, where each entry becomes its own entity. Enums are special: BSN needs a default for every variant, which deriving `VariantDefaults` (or `FromTemplate`) generates as `default_{variant_lower}` methods. ## SceneComponent derive `#[derive(SceneComponent)]` aggregates components under a name with a `scene` method. A props struct is declared with `#[scene(Props)]` and passed into the scene function: ```rust #[derive(SceneComponent, Default, Clone)] #[scene(CarConfig)] struct Car { boost: f32 } impl Car { fn scene(props: CarConfig) -> impl Scene { let wheels: Box = match props.wheels { WheelSize::Standard => Box::new(bsn! { SlimWheels }), WheelSize::Wide => Box::new(bsn! { WideWheels }), }; bsn! { Transform { translation: Vec3 { x: 10. } } wheels Children [ FrontWheel, BackWheel, ] } } } ``` Spawning with the `@` prefix in `bsn!`. Props also use `@` to distinguish them from the component's own fields (`boost` here is a normal `Car` field, while `@wheels` is a prop consumed by `Car::scene`): ```rust fn spawn_car(mut commands: Commands) { commands.spawn_scene(bsn! { @Car { @wheels: WheelSize::Wide, boost: 100., } }); } ``` ## Props struct ```rust #[derive(Default)] struct CarConfig { wheels: WheelSize, } #[derive(Default)] enum WheelSize { #[default] Standard, Wide, } ``` ## Named entity references Prefix a `#` to name an entity (via its `Name` component), then reference it in the same scene: ```rust #[derive(Component, FromTemplate)] struct EmployedBy(Entity); fn boss() -> impl Scene { bsn! { #Boss Children [ #Joe EmployedBy(#Boss) ] } } ``` Works in `bsn_list!` too: ```rust fn employees() -> impl SceneList { bsn_list! [ (#Joe ReportsTo(#Jane)), (#Jane ReportsTo(#Joe)), ] } ``` ## Observers inline Attach observers with the `on` keyword: ```rust fn button() -> impl Scene { bsn! { Node { width: px(100), height: px(50) } on(|press: On>| { info!("button pressed!") }) } } ``` ## Children Use `Children` to nest entities: ```rust fn spawn_scene(mut commands: Commands) { commands.spawn_scene(bsn! { Player Children [ Sword, Shield, ] }); } ``` Also works with custom relationships via the `relationship` or `related!` APIs (see [relationships skill](/bevy-relationships)).