feat(runtime): add Bevy 0.20 live editor M0 spike
- new bevy_forge_runtime crate with EditorPlugin, EditorState, Selection - native Bevy UI shell + official bevy_ui_widgets 0.20 (no egui in runtime) - live hierarchy, reflection inspector, translate gizmo, editor camera - deterministic 1440x900/1000x640 screenshot mode - demo example, docs and screenshots; v1 crates untouched - interactive computer-use test fixed inspector command-queue panic
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
//! M0 spike demo: a small hardcoded 3D scene plus the Bevy Forge editor plugin.
|
||||
//!
|
||||
//! Run:
|
||||
//! cargo run -p bevy_forge_runtime --example editor_spike
|
||||
//!
|
||||
//! Deterministic screenshot:
|
||||
//! FORGE_SCREENSHOT=$PWD/.swarm/m0/evidence/m0-1440x900.png \
|
||||
//! FORGE_SCREENSHOT_SIZE=1440x900 \
|
||||
//! cargo run -p bevy_forge_runtime --example editor_spike
|
||||
|
||||
use bevy::{prelude::*, render::view::Tonemapping, window::WindowResolution};
|
||||
use bevy_forge_runtime::{EditorPlugin, Selection};
|
||||
|
||||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins.set(WindowPlugin {
|
||||
primary_window: Some(Window {
|
||||
title: "Bevy Forge — M0 Spike".into(),
|
||||
resolution: WindowResolution::new(1440, 900).with_scale_factor_override(1.0),
|
||||
..default()
|
||||
}),
|
||||
..default()
|
||||
}))
|
||||
.add_plugins(EditorPlugin)
|
||||
.add_systems(Startup, demo_scene)
|
||||
.run();
|
||||
}
|
||||
|
||||
fn demo_scene(
|
||||
mut commands: Commands,
|
||||
mut meshes: ResMut<Assets<Mesh>>,
|
||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||
mut selection: ResMut<Selection>,
|
||||
) {
|
||||
commands.insert_resource(GlobalAmbientLight {
|
||||
color: Color::WHITE,
|
||||
brightness: 600.0,
|
||||
..default()
|
||||
});
|
||||
|
||||
let ground = materials.add(StandardMaterial {
|
||||
base_color: Color::srgb(0.16, 0.20, 0.17),
|
||||
perceptual_roughness: 0.95,
|
||||
metallic: 0.0,
|
||||
..default()
|
||||
});
|
||||
commands.spawn((
|
||||
Name::new("Ground"),
|
||||
Mesh3d(meshes.add(Plane3d::default().mesh().size(14.0, 14.0))),
|
||||
MeshMaterial3d(ground),
|
||||
Transform::from_xyz(0.0, -0.02, 0.0),
|
||||
));
|
||||
|
||||
let hero_mat = materials.add(StandardMaterial {
|
||||
base_color: Color::srgb(0.85, 0.55, 0.25),
|
||||
perceptual_roughness: 0.65,
|
||||
metallic: 0.0,
|
||||
..default()
|
||||
});
|
||||
let hat_mat = materials.add(StandardMaterial {
|
||||
base_color: Color::srgb(0.25, 0.45, 0.75),
|
||||
perceptual_roughness: 0.5,
|
||||
metallic: 0.0,
|
||||
..default()
|
||||
});
|
||||
let hero = commands
|
||||
.spawn((
|
||||
Name::new("Hero Cube"),
|
||||
Mesh3d(meshes.add(Cuboid::new(1.0, 1.0, 1.0))),
|
||||
MeshMaterial3d(hero_mat),
|
||||
Transform::from_xyz(0.0, 0.5, 0.0),
|
||||
))
|
||||
.with_children(|parent| {
|
||||
parent.spawn((
|
||||
Name::new("Hat"),
|
||||
Mesh3d(meshes.add(Cuboid::new(0.55, 0.18, 0.55))),
|
||||
MeshMaterial3d(hat_mat),
|
||||
Transform::from_xyz(0.0, 0.62, 0.0),
|
||||
));
|
||||
})
|
||||
.id();
|
||||
|
||||
let red_mat = materials.add(StandardMaterial {
|
||||
base_color: Color::srgb(0.75, 0.18, 0.16),
|
||||
perceptual_roughness: 0.7,
|
||||
..default()
|
||||
});
|
||||
let blue_mat = materials.add(StandardMaterial {
|
||||
base_color: Color::srgb(0.18, 0.35, 0.78),
|
||||
perceptual_roughness: 0.7,
|
||||
..default()
|
||||
});
|
||||
commands.spawn((
|
||||
Name::new("Red Cube"),
|
||||
Mesh3d(meshes.add(Cuboid::new(0.8, 0.8, 0.8))),
|
||||
MeshMaterial3d(red_mat),
|
||||
Transform::from_xyz(-2.6, 0.4, 0.6),
|
||||
));
|
||||
commands.spawn((
|
||||
Name::new("Blue Cube"),
|
||||
Mesh3d(meshes.add(Cuboid::new(0.8, 0.8, 0.8))),
|
||||
MeshMaterial3d(blue_mat),
|
||||
Transform::from_xyz(2.6, 0.4, -0.6),
|
||||
));
|
||||
|
||||
let crate_mat = materials.add(StandardMaterial {
|
||||
base_color: Color::srgb(0.55, 0.38, 0.20),
|
||||
perceptual_roughness: 0.9,
|
||||
..default()
|
||||
});
|
||||
let stack = commands
|
||||
.spawn((
|
||||
Name::new("Crate Stack"),
|
||||
Transform::from_xyz(0.0, 0.0, -2.8),
|
||||
Visibility::default(),
|
||||
))
|
||||
.with_children(|parent| {
|
||||
parent.spawn((
|
||||
Name::new("Crate A"),
|
||||
Mesh3d(meshes.add(Cuboid::new(0.8, 0.8, 0.8))),
|
||||
MeshMaterial3d(crate_mat.clone()),
|
||||
Transform::from_xyz(0.0, 0.4, 0.0),
|
||||
));
|
||||
parent.spawn((
|
||||
Name::new("Crate B"),
|
||||
Mesh3d(meshes.add(Cuboid::new(0.8, 0.8, 0.8))),
|
||||
MeshMaterial3d(crate_mat),
|
||||
Transform::from_xyz(0.0, 1.2, 0.0),
|
||||
));
|
||||
})
|
||||
.id();
|
||||
|
||||
commands.spawn((
|
||||
Name::new("Sun"),
|
||||
DirectionalLight {
|
||||
illuminance: 12_000.0,
|
||||
..default()
|
||||
},
|
||||
Transform::from_xyz(4.0, 8.0, 4.0).looking_at(Vec3::ZERO, Vec3::Y),
|
||||
));
|
||||
|
||||
// Placeholder camera. T04 adopts it for the editor orbit/pan/zoom controls.
|
||||
commands.spawn((
|
||||
Name::new("Editor Camera"),
|
||||
Camera3d::default(),
|
||||
Tonemapping::AcesFitted,
|
||||
Transform::from_xyz(6.0, 5.0, 10.0).looking_at(Vec3::new(0.0, 0.5, 0.0), Vec3::Y),
|
||||
));
|
||||
|
||||
selection.0 = Some(hero);
|
||||
info!(
|
||||
"demo scene ready: hero={hero:?}, stack={stack:?}, selected={:?}",
|
||||
selection.0
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user