Your First Bevy 0.19 BSN Scene - One Evening 2026

Spawning a nested Bevy UI tree used to feel like writing a packing list for a camping trip you did not want to take - every asset handle, every child tuple, every ..Default::default(), threaded through setup systems that knew too much. Bevy 0.19 (released June 19, 2026 per the official release notes) finally ships Next Generation Scenes and BSN (Bevy Scene Notation) so you can describe entity trees in a Rust-like bsn! macro and spawn them with spawn_scene instead of manual ECS soup.
This is a beginner-first evening tutorial, not an engine adoption lock and not a schedule-debug playbook. It teaches one honest path: install 0.19, write a bsn! scene, spawn it, understand Children and scene functions, then file a receipt. It also states the caveat release notes put in bold - Bevy 0.19 does not ship a first-party .bsn asset loader yet. Code-driven BSN is the 0.19 workflow; asset files come later.
Why this matters now: BSN is the headline of 0.19's scene rewrite. Feathers widgets migrated to BSN. Community coverage is already framing 0.19 as a Godot-contender moment for Rust indies. Micro-studios that wait for the .bsn loader before trying the macro miss the part that is already useful tonight.
Evidence note: Primary keyword bevy bsn. Demand signals include Bevy's GitHub engagement and 0.19 BSN-focused video coverage. SERP gap: official notes and migration guides explain the system; beginners need a one-evening path with the loader caveat, a UI spawn example, and gates - not another Bevy 0.17 platformer weekend or schedule hitch debug.
Non-repetition: Distinct from 0.17 required-components platformer work and from fest-demo schedule debugging. This URL owns 0.19 BSN first evening.
Who this evening is for
| Audience | Outcome |
|---|---|
| Creators / beginners | A zero-to-window path with bsn!, Children, and .spawn() |
| Developers | spawn_scene vs queue_spawn_scene, patches, SceneComponent intro, migration rename notes |
| Companies | Diligence language for "we adopted BSN code-first; asset loader still pending" |
| Search | Primary keyword bevy bsn with Bevy 0.19 and bsn! secondary intent |
Time: about 2-3 hours for a first scene, including reading the caveats twice. Prerequisites: Rust toolchain, cargo, willingness to use Bevy 0.19 (not 0.17), and a blank project. If you are still on 0.17 required-components headaches, keep the required-components panic help nearby - different problem, different night.
What BSN is (30-second answer)
BSN (Bevy Scene Notation) is an ergonomic Rust-like scene syntax. In 0.19 you define it in Rust with the bsn! macro. The same notation is designed for future .bsn asset files, but the first-party asset loader is not in 0.19 yet (Next Generation Scenes notes and the source release notes).
A bsn! expression is essentially a list of components (and relationships) for an entity. Unlike a plain Bundle, BSN adds optional fields without ..Default::default(), first-class Children, composable patches, scene functions, templates for asset paths, and more.
Direct answer: Tonight you write bsn! { ... }, return impl Scene or impl SceneList, and spawn with commands.spawn_scene(...) or .spawn() on a scene function - you do not wait for a .bsn file on disk.
Prerequisites checklist
- [ ] Rust + cargo installed
- [ ] New crate with
bevy = "0.19"(exact patch per crates.io when you start) - [ ] Read the 0.18 → 0.19 migration guide if upgrading an existing project
- [ ] Accept the no first-party
.bsnloader limit for this release - [ ] A named evening owner who will file the receipt
Beginner path - one evening to a spawned BSN scene
Step 1 - Create the project
cargo new bevy_bsn_evening
cd bevy_bsn_evening
In Cargo.toml:
[dependencies]
bevy = "0.19"
Run cargo build once so you feel the compile wall early, not at 11pm.
Step 2 - Minimal app with a SceneList
Bevy 0.19 ships a helper that turns a function returning Scene or SceneList into a Startup system via .spawn(). The official release notes show a fully self-contained pattern:
use bevy::prelude::*;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, level.spawn())
.run();
}
fn level() -> impl SceneList {
bsn_list![
Camera2d,
// Add your first scene entities here
]
}
bsn_list! builds a list of entities. bsn! builds one entity. Start with a camera so the window is not a black void of confusion.
Step 3 - Your first bsn! entity with Children
Add a simple custom component and a child - this is the "I get it" moment from the official docs:
#[derive(Component, Default, Clone)]
struct Player {
score: usize,
coins: usize,
}
#[derive(Component, Default, Clone)]
struct Sword;
#[derive(Component, Default, Clone)]
struct Shield;
fn player() -> impl Scene {
bsn! {
Player { score: 0 }
Children [
Sword,
Shield,
]
}
}
Optional fields matter: you set score only; coins takes its default. No ..Default::default() ceremony.
Wire it into the level:
fn level() -> impl SceneList {
bsn_list![
Camera2d,
{ player() },
]
}
Or spawn from a Commands system if you prefer the explicit form shown throughout the release notes:
fn setup(mut commands: Commands) {
commands.spawn_scene(player());
}
Step 4 - A UI-shaped Node tree (still code-driven)
BSN is especially nice for Bevy UI. Field position supports ergonomic helpers like px(2) for values that convert into UI types. A teaching-shaped panel (adjust exact UI components to match your 0.19 patch docs if names shift):
fn hud() -> impl Scene {
bsn! {
Node {
width: percent(100),
height: percent(100),
justify_content: JustifyContent::Center,
align_items: AlignItems::Center,
}
Children [
Node {
width: px(240),
height: px(64),
justify_content: JustifyContent::Center,
align_items: AlignItems::Center,
}
BackgroundColor(Color::srgb(0.15, 0.2, 0.35))
Children [
Text::new("Hello BSN"),
]
]
}
}
If Text::new vs Text("...") differs in your exact crate version, follow the compiler and the Bevy 0.19 notes Feathers examples - the point is the Children nesting, not winning a syntax trivia fight.
Add { hud() } to your bsn_list! and run:
cargo run
Pass: window opens, camera exists, Player/Sword/Shield hierarchy is queryable, HUD nodes appear. Fail: compile errors about missing Default/Clone on components - derive them; BSN templates lean on those for pass-through types.
Step 5 - File the evening receipt
Do not call the night done because the window opened. File bevy_019_bsn_scene_receipt_v1.json (schema below) and latch bevy_bsn_ok only when gates B1–B6 are green.
Observing events inside BSN
BSN can embed observer-style callbacks in the scene declaration. Official release notes show a button that logs on pointer press:
fn pressable_panel() -> impl Scene {
bsn! {
Node { width: px(100), height: px(50) }
on(|press: On<Pointer<Press>>| {
info!("panel pressed!");
})
}
}
That matters for indie evenings because it keeps "what exists" and "what happens on click" in one place instead of a spawn call plus a separate .observe(...) chain three functions away. Feathers widgets in 0.19 follow the same idea - caption, extra components, and observers can live in one bsn! block (Feathers + BSN section).
Teaching shape (names follow release-note examples - confirm against your patch):
bsn! {
@FeathersCheckbox {
@caption: bsn! { Text("Enable shadows") ThemedText }
}
MyCheckbox
on(|change: On<ValueChange<bool>>, mut config: ResMut<ShadowConfig>| {
config.enabled = change.value;
})
}
You do not need Feathers to finish tonight. Treat this as the "evening two" preview once player() and hud() are green.
Entity references and Name shortcuts
BSN can name entities with #FirstPlayer syntax, which is sugar for a Name component and also enables references elsewhere in the same bsn! scope:
bsn! {
#Root
Children [
// Custom component holding an Entity - requires FromTemplate when not Default+Clone pass-through
]
}
Use this when you are building small graphs (A points to B points to A) with bsn_list!. For night one, stick to Children. Reach for #Name when you catch yourself spawning anonymous entities you cannot find in a debugger.
Troubleshooting compile and runtime fails
| Symptom | Likely cause | Fix |
|---|---|---|
| Missing Template / FromTemplate errors | Component lacks Default+Clone and needs richer templates |
Derive Default, Clone first; derive FromTemplate only when you need template features |
| Scene asset path fails at spawn | Using :"player.bsn" without a loader |
Stay code-driven in 0.19; do not fake asset files |
| Hierarchy empty after spawn | Spawned a Bundle path by mistake, or forgot Children syntax | Confirm spawn_scene / .spawn() and Children [ ... ] |
| UI invisible | No camera, zero-size Node, or wrong color contrast | Keep Camera2d in the bsn_list!; give Nodes explicit px sizes |
| Upgrade project will not compile | Old scene crate names / glTF path assumptions | Follow 0.18→0.19 migration; keep old serialization for round-trips |
Also keep Bevy hot-reload PNG watcher help bookmarked if your evening expands into sprite assets - that is a 0.17-era symptom that still bites iteration loops.
BSN vs Bundle - when to switch
| Situation | Prefer |
|---|---|
| New UI tree or prefab with Children | BSN |
| One-off three-component spawn in a tight system | Bundle / tuple still fine |
| Need asset path strings inside the declaration | BSN templates |
| Need World round-trip serialize today | Old serialization path (migration guide) |
| Need glTF scene spawn today | Old glTF path until ported to BSN |
Rule for this evening: every new nested hierarchy you write after reading this post should be BSN unless you have a documented exception in the receipt.
Developer path - gates B1–B6
B1 - Version truth
| Check | Pass | Fail |
|---|---|---|
| Bevy version | 0.19.x | 0.17/0.18 with "we'll pretend" |
| Fresh vs migrate | New crate or migration guide followed | Random plugin soup from 0.17 tutorials |
B2 - Loader honesty
| Check | Pass | Fail |
|---|---|---|
| Workflow | Code-driven bsn! |
"We'll just drop a .bsn file in assets/" |
| Team message | Asset loader pending upstream | Promising editor .bsn round-trips in 0.19 |
Official language: 0.19 supports scene assets functionally, but does not ship a first-party .bsn loader yet. queue_spawn_scene waiting on "player.bsn" only helps once a loader exists (or you write one).
B3 - Spawn API choice
| API | Use when |
|---|---|
commands.spawn_scene(scene) |
Immediate spawn; fails if scene asset deps are not loaded |
commands.queue_spawn_scene(scene) |
Wait until dependencies load |
level.spawn() on Startup |
Scene/SceneList function as a system |
Do not mix "I expected queue semantics" with spawn_scene and then blame BSN.
B4 - Hierarchy and patches
Confirm:
- Children appear under the parent in the ECS relationship sense.
- A layered scene patch merges fields (official button width/height layering example).
- You did not reintroduce Bundle soup for the same tree.
B5 - Migration rename awareness (upgraders)
The 0.18 → 0.19 migration guide notes that the old scene crate space was reworked to make room for BSN. Round-trip World serialization and glTF scene loading still rely on the older path for now. If your project still needs glTF scene spawn the old way, do not delete that path because you learned bsn! tonight.
B6 - Receipt + latch
File the JSON. Set bevy_bsn_ok: true only when B1–B5 are honest.
Scene functions, patches, and why this beats Bundle soup
Reusable scene functions
fn player(name: &str) -> impl Scene {
bsn! {
Name(name)
Player
}
}
Call sites stop threading AssetServer through every helper just to build a tree. Templates can resolve asset paths like Sprite { image: "player.png" } when you are ready for assets - the World-aware Template system is why BSN can accept a path string instead of a preloaded handle in scene declarations (release notes).
Patches compose
fn button() -> impl Scene {
bsn! {
Button
Node { width: px(100) }
}
}
fn my_button() -> impl Scene {
bsn! {
button()
Node { height: px(100) }
}
}
my_button ends up with both width and height on Node - scenes are patches layered on defaults, not full replacements that wipe sibling fields.
SceneComponent (preview, not required tonight)
When a Player component should guarantee a full scene (hands, mesh, etc.) is present whenever the component exists, look up SceneComponent in the release notes. Spawning @Player { score: 10 } associates the component with Player::scene(). That is the idiomatic answer to "how do I know the whole prefab is there?" - save it for evening two if tonight is your first bsn!.
Common mistakes
- Expecting
.bsnfiles to load out of the box in 0.19 - they do not with a first-party loader yet. - Using
spawn_scenewith unloaded asset deps - usequeue_spawn_scenewhen deps matter. - Skipping
Default+Cloneon simple components - pass-through templates need them. - Copying 0.17 Bundle tutorials into 0.19 - different scene era; prefer BSN for new UI trees.
- Confusing this with schedule hitch debugging - different URL, different problem (0.17 schedule debug).
- Promising partners an official Bevy Editor
.bsnround-trip this quarter - editor editing of.bsnis roadmap language, not 0.19 shipped fact.
Trend discussion - what changed for Rust indies
Three motions matter:
- Scenes became a first-class language - BSN is not a niche macro; it is the centerpiece of 0.19's scene rewrite.
- UI and tooling are moving onto BSN - Feathers widgets migrated, which signals where Bevy wants widget authors to live.
- Asset-driven scenes are intentionally staged - code-first now,
.bsnloader next. Studios that wait for the loader miss months of hierarchy ergonomics.
If you are still evaluating Bevy versus Godot for an editor-first workflow, be honest: 0.19 improves code-driven scenes dramatically; it does not yet replace a shipped visual .bsn editor pipeline.
Company / diligence paragraph
For a publisher or tech diligence zip, say:
- Engine: Bevy 0.19.x
- Scene authoring: code-driven BSN (
bsn!/spawn_scene) - Asset scenes: first-party
.bsnloader not shipped in 0.19 - tracked upstream - Evidence:
bevy_019_bsn_scene_receipt_v1.jsonwith gates B1–B6 - Related iteration resources: 25 free Bevy Rust resources and 15 free Bevy 0.17 iteration resources (update versions in your own notes when you fully leave 0.17)
Receipt schema - bevy_019_bsn_scene_receipt_v1.json
{
"schema": "bevy_019_bsn_scene_receipt_v1",
"bevy_version": "0.19.x",
"project_name": "bevy_bsn_evening",
"workflow": "code_driven_bsn",
"first_party_bsn_loader": false,
"gates": {
"B1_version": "green | red",
"B2_loader_honesty": "green | red",
"B3_spawn_api": "green | red",
"B4_hierarchy_patches": "green | red",
"B5_migration_awareness": "green | red | na_new_project",
"B6_receipt_filed": "green | red"
},
"smoke": {
"window_opened": true,
"camera_spawned": true,
"player_children_present": true,
"hud_nodes_present": true
},
"sources": [
"https://bevy.org/news/bevy-0-19/",
"https://bevy.org/learn/migration-guides/0-18-to-0-19/",
"https://github.com/bevyengine/bevy/blob/release-0.19.0/_release-content/release-notes/next-generation-scenes.md"
],
"bevy_bsn_ok": false
}
One-evening schedule
| Block | Focus | Exit |
|---|---|---|
| 0:00-0:30 | New crate, Bevy 0.19 dep, first build | Compiles |
| 0:30-1:00 | Camera + player() with Children |
Hierarchy queryable |
| 1:00-1:45 | HUD Node tree via BSN | Visible UI |
| 1:45-2:15 | Patch / scene function cleanup | No Bundle soup left |
| 2:15-2:45 | Read loader caveat aloud; file receipt | bevy_bsn_ok |
Key takeaways
- Bevy 0.19 introduces BSN and Next Generation Scenes as the modern way to declare entity trees in code.
- Use the
bsn!/bsn_list!macros and spawn withspawn_scene,queue_spawn_scene, or.spawn(). - Children and scene functions replace a lot of manual Bundle nesting.
- No first-party
.bsnasset loader ships in 0.19 - code-driven workflow is the honest path. - Optional fields and patches reduce
..Default::default()noise. - Upgraders must read the 0.18→0.19 migration notes for old scene / glTF serialization realities.
- File
bevy_019_bsn_scene_receipt_v1.jsonand latchbevy_bsn_ok. - Keep this distinct from Bevy 0.17 platformer and schedule-debug posts.
FAQ
What is Bevy BSN?
BSN means Bevy Scene Notation - a Rust-like scene syntax used via the bsn! macro in Bevy 0.19, designed to also work in future .bsn asset files. See the Bevy 0.19 release notes.
Can I load .bsn files in Bevy 0.19?
Not with a first-party loader. 0.19 focuses on the code-driven workflow. An official .bsn loader is planned; adventurous teams can implement custom scene asset formats because the spawn system already understands scene asset dependencies.
How do I spawn a BSN scene?
Return impl Scene or impl SceneList from a function and use commands.spawn_scene(...), commands.queue_spawn_scene(...), or .spawn() on the function in a Startup schedule, as shown in the official notes.
When should I use queue_spawn_scene instead of spawn_scene?
When the scene depends on assets that may not be loaded yet. queue_spawn_scene waits; spawn_scene tries immediately and can fail if dependencies are missing.
Is BSN only for UI?
No. It can spawn anything in the ECS. UI is a highlighted win because nested Nodes and widgets get much more readable.
How is this different from Bundles?
Bundles are collections of components. BSN adds optional fields, relationships, patches, scene functions, templates, and asset-path ergonomics - see the Next Generation Scenes section of the release notes.
Should I upgrade from Bevy 0.17 just for BSN?
If you want modern scene authoring, yes - but budget migration work. Use the migration guide and do not assume glTF / old serialization paths are identical.
Where should I go after this evening?
Compose Feathers widgets with BSN using the official feathers examples, then read SceneComponent for prefab guarantees. Keep Bevy resource lists handy for crates and learning paths.
Related reads
- Your First Bevy 0.17 2D Platformer - One Weekend 2026
- Bevy 0.17 ECS Plugin Schedule Order Debug - Fest Demo Menu Hitch
- Unreal Engine 5.8 MCP with Claude Code - First Safe Editor Session 2026
- 25 Free Bevy Rust Game Development Resources 2026
- 15 Free Bevy 0.17 Indie Iteration Resources
- Bevy 0.17 Required Components Panic Fix
- Bevy 0.19 Release Notes (Official)
- Bevy 0.18 to 0.19 Migration Guide (Official)
Conclusion
Bevy 0.19's BSN is the rare engine feature that makes the beginner evening and the senior hierarchy design better at the same time. Spawn a camera, a player() scene with Children, and a small HUD Node tree. Say the .bsn loader caveat out loud so nobody plans a fake asset pipeline. File the receipt. Tomorrow you can chase SceneComponent and Feathers - tonight you just needed the macro to feel inevitable.