Files
Bevy_Forge/compat/bsn-smoke

bsn-smoke — Bevy 0.20 generated-code compile check

bsn-smoke is Bevy Forge's proof that exported scenes are real Bevy 0.20 code, not just plausible-looking text. It is the only crate in this repository that depends on Bevy; it is excluded from the workspace (Cargo.toml → exclude = ["compat/bsn-smoke"]) so the editor, core and CLI crates stay Bevy-free and build in seconds.

compat/bsn-smoke/
├── Cargo.toml          standalone package (empty [workspace]), pinned Bevy 0.20.0
├── Cargo.lock          lockfile for the verification dependency graph
├── src/lib.rs          hand-written scenes mirroring every codegen shape + support types
├── src/generated.rs    BSN export of the 3D garden demo (written by the gate script)
├── src/generated_2d.rs BSN export of the 2D platformer demo (written by the gate script)
└── src/rust_export.rs  imperative `Commands::spawn` export shape, also compiled

What is verified

Compile-checked against bevy 0.20.0 (default-features = false):

  • Roots: single root bsn! / -> impl Scene; multiple roots bsn_list! / -> impl SceneList with -- separators.
  • Hierarchy: nested Children [ ... -- ... ], including a Visibility patch on a grandchild and components before/after Children.
  • Names and transforms: Name("..."), full three-field Transform with Quat::from_euler(EulerRot::XYZ, x.to_radians(), ...).
  • Sprites: image path handles, Color::srgba, flip_x/flip_y, and braced custom_size: { Some(Vec2::new(w, h)) } (the brace form is mandatory in BSN patches).
  • Text: Text2d, TextFont { font_size: FontSize::Px(..) }, TextColor.
  • Cameras: bare Camera2d, Camera3d::default().
  • Lights: PointLight (color/intensity/range/shadows) and DirectionalLight (color/illuminance/shadows).
  • Custom components: struct-with-fields patches (Health { current: 10.0, max: 10.0 }, forge_demo::Orbit { radius: 2.4, speed: 0.45 }) and bare unit-component patches (Marker).
  • 3D meshes: all five primitive shapes (Cuboid, Sphere, Plane3d, Cylinder, Capsule3d) with braced method-call handles (Mesh3d({ meshes.add(..) })) and inline materials (MeshMaterial3d::<StandardMaterial>({ materials.add(StandardMaterial { ..default() }) })), plus an asset mesh path (Mesh3d("models/...#Mesh0/Primitive0")) with an inline material.
  • Generated signatures: mesh scenes take &mut Assets<Mesh> and &mut Assets<StandardMaterial> only when needed.
  • Imperative Rust export shape (src/rust_export.rs): commands.spawn, with_children, Name::new, Transform::from_xyz(..).with_rotation(..).with_scale(..), Sprite { ..default() }, Mesh3d/MeshMaterial3d, Text2d::new, TextFont, TextColor, Camera3d::default(), lights and Visibility.

The committed src/generated*.rs files are the CLI exports produced by the last successful gate run (plus the shim described below), so the crate compiles on a fresh checkout even before the script runs. scripts/check-generated-code.sh regenerates them from the demo project and recompiles, verifying the generator + demo scenes end to end. The exports are deterministic, so re-running the gate leaves the files unchanged.

Compatibility shim for custom type paths

Generated BSN references custom components by their project type path, e.g. forge_demo::Orbit. In a real Bevy project the generated function is pasted where that path is already in scope. Here the generated file is a module, so the gate script prepends four lines (#![allow(unused_imports)], two comments, and use crate::*;) to expose the crate-root support types; the generated code itself is appended unchanged. lib.rs provides forge_demo::Orbit with the same fields as examples/demo-project/src/main.rs. If a demo scene introduces another custom type, add its support type to lib.rs.

Bevy version and feature set

Pinned to Bevy 0.20.0 through Cargo.lock. Feature set (chosen by .swarm/recon/R02.md to keep compile time and APIs aligned with the verified BSN forms):

bevy = { version = "0.20", default-features = false, features = [
  "std", "bevy_scene", "bevy_sprite", "bevy_asset", "bevy_color", "bevy_text",
  "bevy_pbr", "bevy_mesh", "bevy_camera", "bevy_light", "bevy_image",
] }

No windowing or audio backends are compiled in and no GPU device is initialized: this is a compile check that needs no display, asset files or App.

Running

Directly (the load-bearing check):

cd compat/bsn-smoke
CARGO_NET_OFFLINE=true cargo check

End to end (generator → CLI → Bevy compile):

bash scripts/check-generated-code.sh

The script exports examples/demo-project/scenes/garden.forge.ron and .../platformer.forge.ron with cargo run -q -p bevy_forge_cli -- export ... --format bsn, writes the results into this crate, and runs the check. It fails loudly on any error; if the CLI or demo project does not exist yet it fails with a clear message instead of silently passing. FORGE_SKIP_GENERATED=1 skips with an explicit message (bootstrap only); FORGE_SKIP_SECOND_SCENE=1 skips the 2D export; FORGE_GARDEN_SCENE / FORGE_PLATFORMER_SCENE override the scene paths; CARGO_TARGET_DIR is passed through.

Expected cost

Measured on this Linux machine (Rust 1.99.1, 2026-10):

Build Wall time target/ size
First cargo check, cold target dir 2 min 15 s ~803 MB
Subsequent cargo check, warm target dir < 1 s —
Reusing an existing Bevy 0.20 target/ (e.g. recon) ~1 s —

compat/bsn-smoke/target/ is ignored by .gitignore; never commit it. If you already have a warm Bevy 0.20 target directory, point CARGO_TARGET_DIR at it to avoid the cold build (the dependency feature set must match exactly).

Runtime caveats (compile ≠ loaded assets)

  • Asset paths (Sprite { image: "textures/x.png" }, Mesh3d("models/...gltf#...")) compile, but Bevy turns them into HandleTemplate::Path values that are resolved by the AssetServer at spawn time. If the project has no loader/asset for the path, the handle stays loading/failed and nothing renders — it is not a compile error (see R02 §9).
  • Bevy Forge never emits material asset paths (MeshMaterial3d::<StandardMaterial>("...")), because those need a project-registered material loader; materials are always inline materials.add(StandardMaterial { ..default() }) handles.
  • The check is compile-only: it does not spawn the scenes or validate asset existence. Asset references are validated separately by forge validate / the editor.