Skip to content

BSN: scene.spawn() system ergonomics#23868

Merged
alice-i-cecile merged 1 commit intobevyengine:mainfrom
cart:scene_spawn_ergo
Apr 19, 2026
Merged

BSN: scene.spawn() system ergonomics#23868
alice-i-cecile merged 1 commit intobevyengine:mainfrom
cart:scene_spawn_ergo

Conversation

@cart
Copy link
Copy Markdown
Member

@cart cart commented Apr 18, 2026

Objective

Spawning a scene on startup is a common pattern. Lets make it easier to do so!

Solution

  • Add SpawnSystem and SpawnListSystem traits that are implemented for functions that return scenes / scene lists, and return a system that spawns the scene / handles errors.

Before

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_systems(Startup, setup)
        .run();
}

fn setup(world: &mut World) -> Result {
    world.spawn_scene_list(bsn_list![Camera2d, ui()])?;
    Ok(())
}

After

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_systems(Startup, scene.spawn())
        .run();
}

fn scene() -> impl SceneList {
    bsn_list![Camera2d, ui()]
}

This cuts out some boilerplate. It also further encourages people to define standalone "scene functions" rather than embedding them in code, which is generally a good pattern.

@cart cart added C-Usability A targeted quality-of-life change that makes Bevy easier to use A-Scenes Composing and serializing ECS objects labels Apr 18, 2026
@cart cart added this to the 0.19 milestone Apr 18, 2026
@alice-i-cecile alice-i-cecile added X-Contentious There are nontrivial implications that should be thought through S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Apr 18, 2026
@alice-i-cecile
Copy link
Copy Markdown
Member

Why not use a .pipe(spawn) approach? That would be much simpler, both internally and in terms of teaching.

Copy link
Copy Markdown
Contributor

@Diddykonga Diddykonga left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When first seeing this, I thought and posted in discord that perhaps we could just use piping with a generic function provided by the ECS. app.add_systems(Startup, scene.pipe(scene_spawner))
Although I quickly realized that would just end up with a scene_spawner per scene, which is equivalent to this, but this is on a trait impled on the scene function, so its even better. 👍

Edit: ninja'd by alice

@alice-i-cecile
Copy link
Copy Markdown
Member

Another proposed alternative: make a system generating function that works like our run conditions, then pass in your functions that return scenes to that :)

@cart
Copy link
Copy Markdown
Member Author

cart commented Apr 18, 2026

Why not use a .pipe(spawn) approach? That would be much simpler, both internally and in terms of teaching.

This is an interesting thought. However I don't think we're ready to start training people to think of "scene functions" as "systems":

  1. Treating "scene functions" as systems isn't fully possible yet: fn scene() -> impl Scene is pipeable to fn spawn(scene: In<impl Scene>, commands: Commands), but fn scene(counter: Res<Counter>) -> impl Scene is not.
  2. Treating "scene functions" as systems isn't correct in the context of BSN: "scene functions" in BSN are not run as systems, nor should the be (as this requires world access, and Scenes are "stateless" / standalone descriptions). For example afn scene(counter: Res<Counter>) is not directly spawnable in BSN / it would require passing in a Res<Counter> from the root.

With reactivity, we might be able to start thinking about scenes this way, but the mechanism there is still very TBD. I think training people to think of "scene functions" as systems themselves would be a mistake at this stage, and we might never want to do this.

Another proposed alternative: make a system generating function that works like our run conditions, then pass in your functions that return scenes to that :)

Do you mean something like app.add_systems(Startup, spawn_system(my_scene))? If so, I still largely prefer my_scene.spawn() from a legibility / ergo perspective.

@alice-i-cecile
Copy link
Copy Markdown
Member

Okay, agreed that we should rule out the first. For the second, call it spawn. Then it's short and reads even more naturally.

I think that that's a simpler pattern and something that users can comfortably learn from and modify.

@alice-i-cecile alice-i-cecile added S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Apr 18, 2026
@cart
Copy link
Copy Markdown
Member Author

cart commented Apr 18, 2026

Okay, agreed that we should rule out the first. For the second, call it spawn. Then it's short and reads even more naturally.

One downside of this is that we need two different functions for this: spawn() and spawn_list(), whereas we can have scene.spawn() and scene_list.spawn() with the current impl.

The method-style approach also means we don't need to have spawn and spawn_list floating around in the global autocomplete context.

@alice-i-cecile
Copy link
Copy Markdown
Member

One downside of this is that we need two different functions for this: spawn() and spawn_list(), whereas we can have scene.spawn() and scene_list.spawn() with the current impl.

Should be easy enough to solve with a trait Spawnable, which can be implemented for Scene, SceneList and Bundle :)

I think I've made my case though; I'll defer to your judgement here!

@alice-i-cecile alice-i-cecile added S-Needs-Review Needs reviewer attention (from anyone!) to move forward and removed S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged labels Apr 19, 2026
@cart
Copy link
Copy Markdown
Member Author

cart commented Apr 19, 2026

Should be easy enough to solve with a trait Spawnable, which can be implemented for Scene, SceneList and Bundle :)

I'd argue that this is what my current SpawnSystem trait is :)
My vote is still to roll with the current impl

@alice-i-cecile alice-i-cecile added S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Apr 19, 2026
@alice-i-cecile alice-i-cecile added this pull request to the merge queue Apr 19, 2026
Merged via the queue into bevyengine:main with commit aa5322e Apr 19, 2026
53 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Scenes Composing and serializing ECS objects C-Usability A targeted quality-of-life change that makes Bevy easier to use S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it X-Contentious There are nontrivial implications that should be thought through

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants