From cargo new to a main menu
Seven steps. The first two already give you a window, a main menu, settings that save and Esc to pause.
- 01
Add the crate
Depend on the engine with its defaults off and pick features: physics (avian3d) and fps (the first-person controller). Name bevy yourself with no features, so its derive macros resolve; the engine picks every feature. Your dev feature turns the debug tools on.
Placeholder Not on crates.io yet: a path dependency for now.
[dependencies.engine] path = "../engine" default-features = false features = ["physics", "fps"] [dependencies] bevy = { version = "=0.19.1", default-features = false } [features] # cargo run / cargo test keep every debug tool default = ["dev"] dev = ["engine/devtools", "engine/trace"] - 02
Write main.rs
One call builds the window or headless app, CLI flags, data and asset folders, settings, the main menu and the pause menu. Add your game as a plugin and put its flow under AppState::InGame.
use engine::prelude::*; fn main() { engine::app( GameInfo::new("orbs", "Orbs").tagline("Collect them all."), ) .add_plugins(MyGamePlugin) .run(); } - 03
Add your settings
Your section is a serde struct. It is saved next to the core settings in settings.json, 0.6 s after the last change and on exit. A corrupt file is moved aside and defaults load.
#[derive(Resource, Serialize, Deserialize, Default, Clone, PartialEq)] #[serde(default)] struct MySettings { difficulty: usize, assist: bool } fn main() { engine::app(GameInfo::new("id", "Title")) .add_plugins((engine::settings::SettingsPlugin::<MySettings>::default(), MyPlugin)) .run(); } - 04
Put them on screen
Each FieldDef is a row on the generated settings screen: Toggle, Slider, Choice, Cards or Swatches, on the tab you name. Reset tab restores the defaults.
app.register_setting(FieldDef { key: "assist", tab: "Gameplay", label: "Steering assist", hint: "More grip and calmer steering at speed. Off: the bike slides and drifts.", kind: FieldKind::Toggle, get: |w| b(s(w).assist), set: |w, v| s_mut(w).assist = v > 0.5, }) - 06
Run it, test it
Dev builds take engine flags such as
--playand--headless. The control port lets a test or an agent press keys, read state and save screenshots from a hidden window.cargo run --example minimal --features fps # the smallest game: ground, cube, camera cargo run -- --play # skip the main menu (dev builds) cargo run -- --headless # no window, for tests - 07
Ship without the tools
Build with
--no-default-features. The debug tools live in the ashlar crates (control port, MCP, trace); the packaging script fails if any of them is still in the tree or the binary, and copies only the binary and assets.scripts/package.sh --manifest Cargo.toml --package mygame --bin mygame \ --features "physics fps" --assets assets cargo tree -p <pkg> --no-default-features --features "<ship features>" -e normal | grep ashlar # prints nothing