Bevy Coven
Some parts of a game only grow as fast as people can author them: levels, set dressing, dialogue, the lives of villagers, interfaces, weather. Bevy Coven is a family of Bevy crates built so that those parts grow with agents too.
⚠️ Vibe Coded. Written by AI agents working from a human’s direction, covered by tests rather than a line-by-line human review. Read the code before you rely on it for something you care about.
The coven, the grimoire, the cauldron and the familiar
- The coven is the family of crates. Each one is a Bevy plugin with its own settings, and works on its own: a sky, a forest, a crowd, a dialog box.
- The grimoire is the book of spells, and it is what a game loads: its kits, the grammar learned from your example, and the maps built from that grammar (bevy_grimoire).
- The Cauldron is the editor where the grimoire is written: you and the familiar place pieces, and the learned grammar brews more.
- The familiar is the helper at your side: the agent that reads and writes the grimoire, through the Cauldron’s MCP server.
Two more helpers belong to the same story: bevy_fairy, which lets an agent read and drive a running game, and golem, which drives Blender to make meshes.
How the crates relate
- Every crate stands alone: add it with
cargo addand its plugin withapp.add_plugins(...). See Using a crate on its own. - The Cauldron hosts each crate as an optional cargo feature and edits that crate’s own settings live, in your game’s project. See Using a crate in the Cauldron.
- Some crates use each other.
bevy_societyspeaks throughbevy_speech_bubbles, steers its walkers withbevy_orcaand leaves marks withbevy_stigmergy.
The map of the coven shows every crate, grouped by what it gives a game.
The map of the coven
Every crate in the family, grouped by what it gives a game. Each picture plays from the crate’s own repository.
The grimoire and the Cauldron
bevy_grimoire
The grimoire is what a game loads: a library of pieces and a map. The Cauldron is the editor that writes it: it learns a world’s grammar from your example and builds more, with the Familiar beside you.
World
bevy_elements
Sky, weather, wind, clouds, terrain and water, simulated in compute shaders.
bevy_flora
Procedural stylized trees and shrubs that grow over time.
isomesh
isomesh and bevy_isomesh: signed distance fields in, meshes out, with caves and carving.
bevy_lights
Flickering fires and a budgeted pool of real lights over thousands of virtual ones.
bevy_light_grid
An illuminance grid that creature AI can read and follow.
Life
bevy_society
Villagers with needs, moods, memories, relationships, rumours and factions.
bevy_stigmergy
Fading marks on a grid that crowds coordinate through, like ant trails.
bevy_orca
Walkers that steer around each other without colliding.
bevy_speech_bubbles
Speech balloons, barks, conversation graphs and a dialog box.
Interface
bevy_gooey
Menus, HUD meters, dialogs and tooltips with keyboard and gamepad navigation.
Spectacle
bevy_carnage
Wounds that bleed and bodies that break, deterministic to the bit.
Agents and tooling
bevy_fairy
Lets a coding agent read and drive a running Bevy game.
Using a crate on its own
Every crate in the coven is a Bevy plugin plus its settings, and none of them needs the Cauldron.
-
Add it:
cargo add bevy_elementsA crate that is not on crates.io yet (
bevy_light_grid) is a git dependency:bevy_light_grid = { git = "https://github.com/bevy-coven/bevy_light_grid" } -
Add its plugin to your app:
use bevy::prelude::*; fn main() { App::new() .add_plugins((DefaultPlugins, bevy_elements::ElementsPlugins)) .run(); }Each crate’s page in this book, and its README, gives its own plugin name and a quick start that compiles.
-
Tune it. A crate’s settings are plain Rust types that implement
serde’sSerializeandDeserialize, so you can build them in code, or load them from a RON or JSON file in your project.
Each crate’s README has a cargo run --example line that opens the scene in its hero GIF; that is the fastest way to see what it does before you add it.
Using a crate in the Cauldron
The Cauldron is the coven’s editor, where the grimoire a game loads is written. It runs as its own program on your game’s project, so the editor never becomes part of your game’s build:
cargo run -p bevy_cauldron -- <game-root> <map> --kit <kit>
With --live, every change is written through to disk as you make it, for a game that watches its own project.
Each crate is an optional feature of the editor
The Cauldron takes each crate in the family as an optional cargo feature, pinned to a git revision on that crate’s main. Turning a feature on gives the editor that crate’s panels: a sky and weather panel for bevy_elements, a forest panel for bevy_flora, villagers for bevy_society, and so on.
Configure, don’t fork
The editor never defines a second schema for a crate’s settings. A crate’s own serde types are the data: the Cauldron saves them in your game’s project, and edits them live. So the file the editor writes is the same file your game loads with the crate on its own, and a game can drop the editor at any time.
The two-way street
When the editor needs something from a crate, the change is made in that crate’s repository, with its own tests, and requested there as an issue labelled consumer and consumer:bevy_grimoire. The editor takes it by moving its pin once the issue is closed as fixed. A game asks the editor for what it needs the same way, with consumer and consumer:<game> on the editor’s repository.
The Familiar
The Cauldron’s MCP server (bevy_cauldron_mcp) lets an agent, the Familiar, read the editor’s state with grimoire_state and change a map with grimoire_apply_operation. Each crate’s page says what its panel lets you, or the Familiar, change.
Grimoire and the Cauldron (bevy_grimoire)
The grimoire is the book of spells a game loads (bevy_grimoire and bevy_grimoire_core). The Cauldron is the coven’s editor, where you write it: a world editor for Bevy games where you build levels with an AI agent, the Familiar, working beside you. The Familiar changes a map only through the same named operations you use, its changes join your one undo history, and you show it what you mean by snipping a rectangle of the editor with a note.
The demo
64 seconds on a walled map: the agent frames two wall pieces, turns wall_02_2 to 90 degrees and removes wall_02_3; the person’s Cmd+Z reports put back wall_02_3. It ends with a snip: the person drags a box over the walled cluster, writes a note, and the receipt names the PNG it saved.
Add it
The editor is a program you run from a clone, on your game’s project:
git clone https://github.com/bevy-coven/bevy_grimoire
cd bevy_grimoire
cargo run -p bevy_cauldron -- /path/to/your/game
Your game links only the libraries: cargo add bevy_grimoire_core bevy_grimoire. bevy_grimoire_core is engine-free and holds the grammar and the solvers; bevy_grimoire puts a library and a map into a Bevy world (GrimoirePlugin), and GrimoireLivePlugin reloads them while the game runs, so an edit shows up about a second later. A project from before the rename keeps its data in assets/emerge; the editor moves it to assets/grimoire the first time it opens the project.
What it gives you
- Maps built from kits: place, fill, turn, remove and undo (building maps).
- Layouts learned from a corner you laid out and continued with wave function collapse, drawn before you keep them.
- Kits and labels, with a vision model’s proposals marked unchecked until you confirm them (kits and labels).
- The MCP server,
bevy_cauldron_mcp, whose tools (grimoire_state,grimoire_apply_operation, captures, snips) let the Familiar read and drive the open editor (MCP tools). - Panels for the rest of the coven, each editing that crate’s own settings (using a crate in the Cauldron).
Use it in the Cauldron
This is the Cauldron. Every other crate’s page says what the Cauldron does with it.
Links
bevy_elements
Living environments for Bevy 0.20: a sun and moon on real ephemerides, the bright-star sky, a seeded climate that schedules hourly weather, a GPU wind field, volumetric clouds, rain and snow, lightning and thunder, fog, heightfield terrain with erosion and flooding, ground cover, rocks, dust, paths and trails — all in compute shaders. Everything runs behind one Environment system parameter, so gameplay asks the simulation what the ground, the water, the light and the weather are doing instead of guessing at it.
Add it
cargo add bevy_elements
use bevy::prelude::*;
use bevy_elements::*;
fn main() {
App::new()
.add_plugins((DefaultPlugins, ElementsPlugins))
.insert_resource(WorldClock::new(CivilDate::new(2026, 6, 21)).at_hour(7.0))
.insert_resource(Climate::temperate())
.add_systems(Startup, setup)
.run();
}
fn setup(mut commands: Commands) {
// The environment follows and renders for the `ElementsCamera`.
commands.spawn((
Camera3d::default(),
ElementsCamera::default(),
Transform::from_xyz(0.0, 160.0, 0.0).looking_at(Vec3::new(100.0, 100.0, 0.0), Vec3::Y),
));
// 2 km of rolling hills, centred on the origin.
commands.spawn(Terrain::procedural(ProceduralTerrain::hills(42)));
}
Or run it first: cargo run --release --example quickstart.
What it gives you
- A living sky over any scene — sun, moon and 8 404 stars from real ephemerides, with exposure that keeps night dark: sky, weather and light.
- A seeded climate that schedules the weather —
ClearthroughBlizzard, hourly, with seasons and a snow season a game sets by date: climate, seasons and weather. - Rain, snow, fog and lightning that read from every camera — including orthographic and isometric views, through
PrecipitationLook::readable(): precipitation. - A terrain you generate, sculpt and save — procedural presets, a height map or flat ground, brushes on the live heightfield, snapshots to save and restore: terrain.
- Ground that wears — drifting snow and melt, wetness and puddles, blown sand, trodden paths, pressed footprints: ground cover.
- Water that answers — shallow-water hydrology with erosion, lakes and rivers, wakes from anything moving through: rivers, lakes and waves.
- A simulation gameplay can query — ground height and normal, water depth and velocity, snow depth, cloud shadow, the lumens a night lamp needs: gameplay queries.
Use it in the Cauldron
The Cauldron takes bevy_elements as the optional cargo feature bevy_elements (the volume snow feature builds on it as volume_snow), and its map environment panel edits this crate’s own serde types, written to <project>/family/bevy_elements.ron so the editor’s preview and the game read the same values:
WorldClock,GeoLocationandClimate— the date, the clock, where the observer stands and the climate the scheduler draws from.WeatherPresetasforced_weather—Some(Rain)forces one preset andNonereleases the weather back to the climate’s own schedule, so a map can be authored under a storm and played under whatever the season brings.SnowSettings,WetnessSettings,RockSettingsandDustSettings— how the snow settles, drifts and melts; how the ground wets and puddles; how many rocks lie on the ground; how the sand moves.SurfaceCoverasvolume_cover— a fixed snow and wetness a carvedbevy_isomeshvolume wears whatever the weather is, which is what a preview of a snow-capped cliff needs.
The editor also builds a map’s heightfield from ProceduralTerrain‘s presets (hills, mountains, dunes, plains) and puts bevy_elements’ SnowyField over a carved volume. Nothing outside those types is reachable from the editor yet: EnvironmentSetup and SurfaceSetup — the whole sky-and-ground setup as one saved, validated value that applies live — are the natural next panel, and the terrain’s TerrainSetup, SculptTerrain and RestoreTerrain would give it sculpting and undo.
Links
bevy_flora
bevy_flora is the coven’s trees: parametric, stylized procedural trees for Bevy 0.20 that grow over time. A tree is a TreeParams value with a seed in it — one of 20 presets or every field tuned by hand — and the same value makes the same tree on every run, at every age. Twenty thousand of them draw from a pool of a few seed variants in under 4 ms a frame, and they can be notched, felled, bucked, burnt, shaken and picked like game objects rather than looked at like scenery.
Add it
cargo add bevy_flora
Add the plugin and spawn a tree. Growing advances its age every frame until it is mature; leave it off and set TreeAge yourself.
use bevy::prelude::*;
use bevy_flora::{FloraPlugin, Growing, ProceduralTree, TreeAge, TreePreset};
fn main() {
App::new()
.add_plugins((DefaultPlugins, FloraPlugin))
.add_systems(Startup, setup)
.run();
}
fn setup(mut commands: Commands) {
let mut params = TreePreset::Maple.params();
params.seed = 7;
commands.spawn((ProceduralTree(params), TreeAge(0.0), Growing::default()));
commands.spawn((DirectionalLight::default(), Transform::from_xyz(10.0, 20.0, 10.0).looking_at(Vec3::ZERO, Vec3::Y)));
commands.spawn((Camera3d::default(), Transform::from_xyz(0.0, 5.0, 20.0).looking_at(Vec3::new(0.0, 4.0, 0.0), Vec3::Y)));
}
cargo run --release --example showcase is the same thing with the controls wired up; the README’s quick start and its doctests are the version CI compiles.
What it gives you
- A tree over any age.
TreeAgeandGrowingon the CPU, orGpuGrowthfor two hundred oaks at 0.81 ms a frame — growing. - A forest.
TreePoolandPooledTreewith three levels of detail and baked impostors,BackgroundPoolsto build them off the frame,PoolColorsfor more than one look,Scatterfor where the trees stand,FloraGroundfor the terrain,FloraUnitsfor a world that is not in metres — forests. - A look. Bundled CC0 bark scans and real leaf outlines, veins grown by space colonisation,
Natural,PainterlyandToonstyles, and low-polyCrownStyle::Hullconifers — bark, leaves and looks. - A year.
FloraSeasonfor autumn colour, leaf fall, snow and blossom, fruit through summer, andFloraWetnessfor rain — seasons. - Things that happen to trees.
TreeShakes,DropLeaves,TreeFruit,TreeNotchandFellTree,BuckTree,FloraFireandFoliagePusher— interaction. - Answers for the game.
TreeShapefor colliders,FloraIndex(nearest tree, trees within a radius, the trunk a ray meets),TreeConditionfor sick and dying trees, and what a save holds — gameplay. - Cameras.
SeeThroughTreesto keep the player visible, and orthographic cameras whose levels of detail follow the zoom — cameras.
Use it in the Cauldron
The Cauldron takes this crate as the optional cargo feature bevy_flora (pinned to a git revision of main, with the crate’s ron feature on). With the feature off, the two operations are still registered and refuse, naming the feature, so the editor’s surface does not change with the build.
Two operations, both writing files the game loads with the crate on its own:
tree_editwrites<grimoire_dir>/trees/<name>.tree.ron, which isTreeParamsin the formatTreeParamsLoaderreads.presetstarts the file from one of the 20 presets (by name, throughTreePreset::from_name);setchanges fields by dotted path intoTreeParams—trunk.radius,branches.density,foliage.scan,crown,trunk_style,style,wind,bark— and a path the crate does not know is refused with the crate’s own message, so a typo is never written. The settings are the crate’s serde types; the editor defines no second schema for them. A tree that shares the file regrows after an edit with nothing to recompile, which isProceduralTreeAssetand thefile_watcher.forest_scatterwrites<grimoire_dir>/forest/<map>.ron: oneTreeper trunk — an id, a species (a preset name or a.tree.ronpath), its(x, z), its ground height, its scale, its seed and its pool variant — masked to the stroke the author drew. The editor plants it with the crate’s ownScatter(its Poisson-disc spacing, groves and species weights, its seed) and stands each trunk on the map’s terrain withFloraGround.
In the viewport the trees are always the crate’s: a scattered trunk is a PooledTree of its species’ TreePool, built with BackgroundPools; a tree placed by hand is a ProceduralTree at its own TreeAge and seed, so the same seed grows the same tree in the editor and in the game. The preview’s FloraSeason follows bevy_elements’ WorldClock, so the month set in the environment panel turns the forest from blossom to leaf to autumn to snow.
Not yet a panel: FloraFire, TreeCondition and SeeThroughTrees have no editor surface — a fire’s grid (FloraFire::cells) and a tree’s condition would each be a file beside the forest’s, restored with FloraFire::with_cells and restore and with insert(TreeCondition::Sick).
Links
isomesh
Signed distance field in, triangles out. An SDF (signed distance field) is a function that returns how far a point is from a surface, negative inside; isomesh turns one into a mesh with any of seven extractors, so a voxel world can have caves, arches and overhangs that a heightfield cannot store, and a CAD tool can have f64 precision from the same crate. Three crates live in the repository: isomesh (the engine-free core, no_std, one dependency), bevy_isomesh (the Bevy plugin and every example) and isomesh-gpu.
Add it
cargo add isomesh # the core, no engine
cargo add bevy_isomesh # the Bevy plugin
The README has a quick start compiled on every cargo test. Eleven of the demos run in a browser at bevy-coven.github.io/isomesh.
What it gives you
- Seven extractors: Marching Cubes (with MC33’s tunnels), Surface Nets, Dual Contouring, Manifold Dual Contouring, Marching Tetrahedra, greedy quads, and subgrid Marching Tetrahedra, which sees features thinner than a voxel (algorithms).
- Chunks that tile with no cracks at their seams, streaming, LOD with Transvoxel seams, and meshing off the main thread under a frame budget (what it can do).
- Validity and accuracy checks as public API: Euler characteristic, manifoldness, orientation, self-intersections, determinism, Hausdorff distance (what gets checked).
- GPU extraction in
isomesh-gpu, 37 times faster than the CPU at 129³ when the field is evaluated in the shader.
Use it in the Cauldron
The Cauldron takes isomesh for carved volumes (issue #101): a volume’s edit list is the data, and the editor samples it over the ground one chunk at a time, each chunk sharing its boundary plane with its neighbour so the mesh has no cracks, and meshes it with isomesh. That is how caves, overhangs and tunnels a heightfield cannot hold get onto a map, and how bevy_elements’ terrain gets them too.
Links
bevy_lights
Practical lights for Bevy 0.20: the fires a scene’s props actually carry. A world can hold thousands of torches and afford a dozen real lights, so this crate ranks the candidates by the light they put on you, hands the budget out without a pop, modulates each light the way a fire’s light moves, and draws the flame that motivates it — with sparks, smoke, tongues for a wide fire and a bed of coals that goes on glowing after the fire is put out.
Add it
cargo add bevy_lights
use bevy::prelude::*;
use bevy_lights::*;
#[derive(Component)]
struct MyFocus;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins((FlickerPlugin, LightPoolPlugin::<MyFocus>::default(), FlamePlugin, FirePlugin))
.add_systems(Startup, |mut commands: Commands| {
let fire = Fire::lit(FireKind::Campfire, 250.0, 0.35);
commands.spawn((fire, Transform::from_xyz(4.0, 0.0, 2.0)));
commands.spawn((MyFocus, Transform::default()));
})
.run();
}
Fire::lit(kind, lux, over) is a whole fire in one component: the kind’s flame, the light the pool hands
it, its sparks, smoke, tongues and bed of coals. Or run it first: cargo run --release --example courtyard.
What it gives you
- Fires that flicker, flare and go out (fires):
Flickerdips a light below its base at the rate its fuel bed sets,Kindleflares it up over 0.6 s,Snuffputs it out over 1.2 s with the linked flame. - A budget of real lights for a town of thousands (the light pool): ranked by the light each candidate puts on you, held with hysteresis, cross-faded on a hand-off, with a shadow budget of its own and one template that reaches every light live.
- The flame drawn where the fire is (shader flames): one additive billboard per fire, breathing on its light’s clock, in a hue of its own, shedding sparks, smoking, leaning in a wind and streaming behind a torch you carry — and going out when a wall hides its source.
- Coals that outlive the flame (the fuel bed): a temperature field that breathes with the flicker, warms as the fire catches and cools over a minute once it is put out.
- A cinematographer’s numbers (the lighting look):
fire_lumens,fill_for,blackbody_colourandwhite_balancedturn “1000 lx at 4 m” and “1900 K” into a sized, coloured light. - Every curve outside the engine (engine-free maths): the same maths as plain
f32functions with nobevyin them, for a host that drives its own lights. - What a host touches, and what it saves (host API): the components and resources a game spawns, marks and reads, and the
serdefeature that makes a placed fire one line of a scene file.
Use it in the Cauldron
The Cauldron, the Coven’s level editor, takes bevy_lights as an optional cargo feature (bevy_lights) and a
project lists it in its family.ron. Two things it does with the crate today:
- A placement’s fire is the crate’s own settings type.
family_setwrites a field of the fire’sFlicker—base,phase,depth,diameter— in<project>/family/bevy_lights.ron, and the placed prop reads back as the crate’sFlicker, so the editor has no schema of its own for it.placement_set_familyputs that value on one placement, or takes it off. - Two read-only operations answer “which of my torches are real, and how lit is this tile?” —
light_poolruns the crate’s ownLightPoolPluginover the map’s fixtures and reads itsPoolBudgetfor where the viewer stands, andlight_mapbakes abevy_light_gridilluminance field from the same fixtures.
There is no panel for the fire kinds yet. One would edit Fire { kind, lumens, phase, color, embers, smoke, tongues, bed } — the whole fire as one serde value — and read Fire::problems() beside the fields, which
is what every settings type in the crate returns: a list of Problem { field, kind } naming what cannot
work, before the value reaches a light.
Links
bevy_light_grid
An illuminance grid that creature AI can read. It answers “how bright is it here, and which way is brighter” per cell, on the CPU, so a creature can flee into shadow or climb toward a lamp. Your GPU lighting already knows how bright each pixel is, but that answer lives in a framebuffer gameplay cannot read; this crate computes it in a form gameplay can sample and differentiate.
Add it
Not on crates.io yet:
[dependencies]
bevy_light_grid = { git = "https://github.com/bevy-coven/bevy_light_grid" }
The README has a quick start that is compiled on every cargo test. The crate takes bevy_math and bevy_ecs and nothing that draws.
What it gives you
LightGridwithbake(static lamps, rerun when one changes) andcompose(movingFlashlightCones on the cached bake, every tick), both shadowed by your own line-of-sight closure (the field).sample_cellandgradient_cell, andlight_push_atfor a steering push up or down the gradient.Photophobic,PhotophilicandPhototropicmarkers, andphototropic_scalefor growth toward light.
Use it in the Cauldron
The Cauldron takes this crate behind its bevy_light_grid feature for the light map (issue #103), a read-only operation and overlay. Every placement that carries a bevy_lights Flicker is a fixture, a placement whose descriptor is a wall blocks line of sight, and the values drawn over the map are the crate’s own LightGrid::sample_cell, so what the author reads is what a light-shy creature in the game reads.
Links
bevy_society
Living societies for Bevy: villagers who remember, gossip, take sides, fall out and make up. Big Five personalities, moods on a pleasure/arousal/dominance axis, an OCC emotion set, needs that decay and memories that fade; utility-AI daily lives over tagged places and other people; directed ties with a Dunbar-style cap; opinions, rumors, reputation and factions; Rhai scripts, dialogue through bevy_speech_bubbles; and a save that restores the society the reload would have produced.
cargo run --release --example capture -- --scene village: one afternoon in a village of twenty-four people. The plate reads Day 4 · 14:01 Friendships 30 · Rivalries 1 on the first frame and Day 4 · 20:01 Friendships 27 · Rivalries 1 with “Bram stole bread” — known by 2/24 on the last.
Add it
cargo add bevy_society
#![allow(unused)]
fn main() {
use bevy::prelude::*;
use bevy_society::{
Autonomous, Home, Person, Place, PlaceTags, SocietyClock, SocietyDefs, SocietyPlugins,
SocietySettings,
};
let defs = SocietyDefs::starter().expect("the starter pack is valid");
// A headless app has no frame clock, so `Time<Fixed>` never advances on its own. Without this the
// society takes zero ticks however many updates you run.
let step = std::time::Duration::from_secs_f64(1.0 / 64.0);
let mut app = App::new();
app.add_plugins((MinimalPlugins, TransformPlugin))
.insert_resource(bevy::time::TimeUpdateStrategy::ManualDuration(step))
.insert_resource(SocietySettings::default())
.insert_resource(defs);
// `DialoguePlugin` needs a speech-bubbles plugin over a camera, which this snippet has not.
let plugins = SocietyPlugins.build();
#[cfg(feature = "dialogue")]
let plugins = plugins.disable::<bevy_society::DialoguePlugin>();
app.add_plugins(plugins);
let well = app
.world_mut()
.spawn((Name::new("well"), Place { capacity: 6 }, PlaceTags(vec!["gathering".into()]), Transform::default()))
.id();
for name in ["Bram", "Alys", "Corin"] {
app.world_mut()
.spawn((Person, Autonomous, Name::new(name), Home(well), Transform::default()));
}
for _ in 0..600 {
app.update();
}
// The society advanced: this line is what proves the fixed step was pinned.
assert!(app.world().resource::<SocietyClock>().tick > 0);
}
With the default dialogue feature, DialoguePlugin panics in finish without bevy_speech_bubbles::SpeechBubblesPlugin::<YourCamera> over a camera; add that first, or .disable::<DialoguePlugin>() as above.
What it gives you
- People with a mind. Big Five personalities, PAD mood, OCC emotions, decaying needs, fading memories, and a
Chronotypeso a lark and an owl keep their own hours in one village. features - A day they choose. Utility-AI scoring over tagged places and other people, with travel, arrival, durations, per-tier ranks and an urgency that wins the tier while a need is low. features
- Relationships. Directed ties with affinity, trust, respect and familiarity, a Dunbar-style cap, friend and rival labels with hysteresis, and rebuff memory so someone turned down stops asking. features
- Opinions, rumors, reputation and factions. Bounded-confidence influence, Daley–Kendall gossip, witnesses who judge deeds and hold grudges, in-group affinity and conferred standing. features
- Scripts. Rhai triggers over a per-tick snapshot, bound to an area, a faction or named people, with a
ctxreader and anfxwriter that cannot see its own writes. scripting - An economy and a save file. Goods as quantities with a per-head price, sharing and swapping between people, and
capture/restoreof the whole society. features · persistence - An editor’s handles.
fast_forward,preview_forward(run a day, report what moved, put it back),test_trigger,check_script,place_dependentsandpersons_in_rect. editor
Use it in the Cauldron
The Cauldron takes bevy_society as an optional cargo feature, named bevy_society in Cargo.toml and in a project’s family.ron. When the project lists it, the editor:
- writes the crate’s own settings through
family_set, which rewrites one dot-pathed field of the RON file the crate’s serde types parse — the editor holds no schema for them, so it keeps the rest of the file as the author left it; - refuses a definitions file the crate would reject: a saved society definition goes through
bevy_society::SocietyDefs::from_ronfirst, so a file the loader would not compile is never written; - authors people on a map through
person_set(<emerge_dir>/people/<map>.ron), with a name, a position, a faction the project’s definitions declare, a home, a workplace and starting ties; - runs a map’s people forward through
people_run, which spawns them inbevy_society’s own headless app and reports where each went and which ties moved — the crate’s systems decide, the editor adds no behaviour.
A settings panel for this crate would edit SocietySettings (seed, tick_secs, seconds_per_day, start_hour, start_weekday, the clock source, locomotion, the society plane and the perception, contact and interaction radii), the tie capacities (max_ties, close_ties), the memory and knowledge capacities, and the rates on Tuning — every one of which is Serialize through the crate’s settings types. SocietyDefs itself is authored as a DefsFile in RON, and DefsFile::to_ron exists so an editor can save what it edited.
Links
bevy_stigmergy
Fading marks on a grid that a crowd coordinates through, like ant trails. Agents deposit into shared channels that evaporate and diffuse between floor cells, never through a wall, and read them back by value or by gradient, so a crowd converges on a trail, scatters from a threat or rallies toward a moving target without any agent planning a route. The field is computed once per tick and shared by every agent.
Add it
cargo add bevy_stigmergy
The README has a quick start that is compiled on every cargo test. The crate depends only on bevy_math; it owns no resources, registers no systems and has no schedule, so it ticks wherever your game’s loop says.
What it gives you
StigGrid<N>:Nscalar channels withdeposit,evaporate_diffuse,sample_cell,gradient_cellandhotspot_cell(the field).RallyGrid: a vector per cell, for recruiting toward a target that moves.CellFrame: an optional world-to-cell mapping for an axis-aligned grid.evaporate_diffuse_with: the same tick split into chunks for your own thread pool, bit-identical to the inline one (ticking).serdeandreflectfeatures on the settings types.
Use it in the Cauldron
The Cauldron takes this crate behind its bevy_stigmergy feature, for the crowd preview (issue #107): it walks N people from one area of a map to another with bevy_orca’s avoidance, and each lays a trail and a congestion mark into a StigGrid laid over the map with a CellFrame. The result is a measurement, not an edit: the two fields drawn as an overlay, how many walkers arrived, and where congestion peaks, so you can see where a gap between buildings jams before a game ships it. The settings it uses are the crate’s own ChannelDefs, which are Serialize/Deserialize behind the serde feature.
Links
- Repository · docs.rs · crates.io · CHANGELOG
bevy_orca
Walkers that steer around each other without colliding. ORCA (optimal reciprocal collision avoidance) gives each agent the velocity closest to the one it wanted that no neighbour can object to, assuming every neighbour reasons the same way and each takes half the dodge. It is a plain library on bevy_math’s Vec2, with no ECS, plugin or schedule: you call a function and get a velocity back.
Add it
cargo add bevy_orca
The README has a single-agent quick start that is compiled on every cargo test.
What it gives you
new_velocityfor one agent, with a documented, finite answer for every unusable input and never a velocity overmax_speed(one agent).Crowdfor many: a neighbour grid, a deterministic tie-break, a sidewaysnudge, and no allocation once warm (a whole crowd).- Right of way through
priority, andCrowd::begin/CrowdStep::solve_rangeto split a step over your own thread pool with bit-identical results. ObstaclesBuilderfor buildings, walls, polygons and tile maps, as RVO2’s obstacle lines (static obstacles).serdeandreflectfeatures onAgent,CrowdMemberandCrowdParams.
Use it in the Cauldron
The Cauldron takes this crate behind its bevy_orca feature for the crowd preview (issue #107): it walks N people from one area of a map to another, each stepping with bevy_orca’s Crowd against its neighbours and against the cells the map’s pieces make solid, and lays their trails and congestion into a bevy_stigmergy field. The editor draws the result over the map with how many arrived and where congestion peaks, and saves nothing to the map. The settings it passes are the crate’s own CrowdParams, which are Serialize/Deserialize behind the serde feature.
Links
- Repository · docs.rs · crates.io · CHANGELOG
bevy_speech_bubbles
A dialog kit for Bevy: world-space speech and thought balloons that float over their speakers, a conversation graph with a runtime, paced barks, and a skinnable screen dialog box. Balloons are quads in the scene rather than a UI layer, so they hold a world position, can be hidden behind a wall, and turn to face the camera.
Add it
cargo add bevy_speech_bubbles
The README has a quick start that is compiled on every cargo test. Your game names the camera balloons face with a marker component, and loads its own font.
What it gives you
- Balloons (
build_bubble,track_bubbles,BalloonSkin,BalloonScale), including pixel-perfect ones (balloons). - A
DialogueScriptofLineandChoicenodes, loaded from RON or any serde format, strict about unknown keys, and checked byvalidate_script(conversations). - A runtime driven by
StartConversation,ChoicePickedandConversationEnded, withDialogueNodeEnteredfor effects, and two presenters: balloons or the dialog box. Barks withBarkSettingspacing, and a 9-slicedDialogSkinwith portrait, name tag and typewriter.
Use it in the Cauldron
The Cauldron takes this crate behind its bevy_speech_bubbles feature and keeps a project’s dialogue as the crate’s own DialogueScript in family/bevy_speech_bubbles.ron, with barks as Vec<Bark>. family_set writes them and runs validate_script before anything is saved, so a dangling next or a missing start node is refused with nothing written. dialogue_preview walks one path through a conversation, taking the options you name at each choice, and answers with the lines said, where the walk stopped and which nodes no path reaches, without changing a file. People placed with bevy_society speak these lines.
Links
- Repository · docs.rs · crates.io · CHANGELOG
bevy_gooey
Game interfaces made easy for Bevy 0.20: a skin, ready-made game widgets and keyboard and gamepad
navigation, built on Bevy’s own headless widgets (bevy_ui_widgets) and input focus
(bevy_input_focus). A menu is a few nested calls, every widget looks like one family, and a pad or a
keyboard reaches everything a mouse does — with the WCAG 2.2 contrast and target-size checks the crate
runs on your own skin.
Add it
cargo add bevy_gooey
use bevy::prelude::*;
use bevy_gooey::*;
fn main() {
App::new()
.add_plugins((DefaultPlugins, GooeyPlugins))
.add_systems(Startup, setup)
.run();
}
fn setup(mut commands: Commands) {
commands.spawn(Camera2d);
commands.spawn((
screen(),
children![(
panel(),
children![
heading("Paused"),
(
menu(),
children![
(button("Resume"), observe(|_: On<Activate>| info!("resume"))),
button("Quit"),
]
),
]
)],
));
}
Or run the gallery first: cargo run --example gallery.
What it gives you
- A skin as data (skins):
GooeySkinholds every colour and size, with thedarkandparchmentpresets andproblems(), which checks WCAG 2.2 contrast and target size. Change it and everything restyles that frame. Fonts live inGooeyFonts, never in the skin. - Every widget a game screen needs (the widget set):
screen,panel,menu,heading,label,button,meter(a HUD bar),toggle,choice,slider,list,toast,toast_alert,Tooltipand the modaldialog— each a free function returning a bundle, so they compose inchildren![]and withobserve. - Settings controls that are the widget (controls):
a
toggle,choiceandslidereach root on Bevy’s ownCheckbox,ButtonandSlider, so the entity you spawn carries the value, takesobserveand says each change once inValueChange. - A list that scrolls and follows focus (lists):
list(4.5, children![..])shows four rows and a half, cuts the fifth so the player sees there is more, and keeps the next row in sight as the arrows walk down it. - Navigation with no mode to enter (focus): arrows and the D-pad move focus to the nearest widget, Enter, Space and South activate, Tab cycles, an open dialog holds focus, and the focus ring appears the moment a key is pressed.
- Toasts that read at the player’s pace (toasts):
commands.spawn(toast("Game saved"))and it stacks, times itself to its own length and ages on real time, so a paused game’s menu still lets it go. - One interface at every resolution (scale):
GooeyScalePluginkeeps the skin’s sizes the same share of the screen, and every border is a whole number of device pixels at any scale. - A pointer that passes through a HUD (over a game world):
the empty part of a
screenisPickable::IGNORE, so a click on the world under a HUD still reaches the world.
Use it in the Cauldron
The Cauldron, the Coven’s level editor, takes bevy_gooey as an optional cargo feature (bevy_gooey) and
a project lists it in its family.ron. It adds the crate’s GooeyStylePlugin (not GooeyNavPlugin:
the editor owns the arrow keys) and reads a project’s skin from <project>/family/bevy_gooey.ron, which
is the crate’s own GooeySkin type written as RON — the same file a game ships:
(accent: Srgba((red: 0.2, green: 0.6, blue: 0.9, alpha: 1.0)), text_scale: 1.25)
GooeySkin is #[serde(default)], so a partial file is the default skin with only that field changed.
Editing the file live swaps the running GooeySkin resource and the crate’s own apply_skin restyles
every widget that frame; a file that is not a skin is a problem on the status line and the last good
skin stays; a skin that breaks the crate’s own rules is applied and each broken rule
(GooeySkin::problems()) is a problem. Removing the file puts the default skin back.
There is no panel for the skin yet. One would edit GooeySkin’s fields — the colours (background,
surface, surface_raised, text, text_muted, accent, accent_text, danger, focus_ring,
outline, scrim), the sizes (text_size, heading_size, gap, padding, radius, border,
meter_height, min_target) and the player’s text_scale — with problems() listed beside them, and
it would read UiScaleSettings { reference_short_side, scale } and ToastSettings { anchor, max_visible, base_seconds, chars_per_second, duration_scale, fade_seconds } the same way: each is
serde data, so each is one line of the project’s family/ folder.
Links
bevy_carnage
Runtime gore for Bevy characters, deterministic to the bit. Add a plugin, dress a loaded character with one component, and send a GoreHit per injury: a wound peels through skin, fat and muscle to bone, bleeds along the pose of an animated body, pools on the floor and dries, and a body that takes enough comes apart into watertight-capped chunks. A violence setting the player controls is honoured, and every canvas is owned by the CPU, so a whole fight can be hashed and replayed.
Add it
cargo add bevy_carnage
The README has an 18-line quick start that is compiled on every cargo test; the full quick start covers the flesh material, skinned characters, cost, the violence tiers and baking a fracture by hand. Putting it on a real glTF character has a checklist.
What it gives you
- The preset:
GorePlugin,GoreandGoreSceneto dress surfaces,GoreHitfor impacts, blows, burns and slashes, andGorePolicyfor the player’s violence setting. - The fracture: bake once with
FractureSubject, then query a hierarchy and a bond graph per blow, with two meshes per fragment and convex colliders (the API). - Seven kernels as modules:
bloodstain,wetmap,viscera,cross_section,flaymap,lacerationandfracture_modes(the family). - A recorded gallery of every demo.
Use it in the Cauldron
The Cauldron takes this crate behind its bevy_carnage feature for destructible props (issue #108). destructible_set marks a piece destructible and fractures it once with the crate’s own fracture_mesh over its mesh and a box proxy of its bounds, caching the chunks in the project (destructible/<piece>.bake.ron, keyed by the mesh’s bytes and the cut settings, so it never bakes twice). destructible_hit previews a hit on the cached chunks and reports which break loose and whether each is a closed solid, by the crate’s own audit. The violence dials are the crate’s own GorePolicy, saved as family/bevy_carnage.ron through family_set; the editor itself ships no gore.
Links
- Repository · docs.rs · crates.io · CHANGELOG
bevy_fairy
bevy_fairy lets a coding agent look inside a running Bevy 0.20 game, drive it, and ask the person playing it for help — without touching the desktop. It is one crate with two halves: a Bevy plugin the game links, which registers bevy_fairy/* methods on the Bevy Remote Protocol (BRP, Bevy’s own JSON-RPC interface on port 15702), and an MCP server, bevy-fairy, that gives an agent tools to read the game’s state, run the game’s own commands, capture a PNG from the game’s own pixels and inject input into Bevy’s own messages. Nothing here captures the screen or synthesises an OS event: a capture from the window focused had 7,188 distinct colours on the game this was built for, and one flat colour with another app in front.
Add it
cargo add bevy_fairy --no-default-features --features plugin
use bevy::prelude::*;
use bevy::remote::http::RemoteHttpPlugin;
use bevy_fairy::DebuggerPlugin;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
// Owns the BRP RemotePlugin. Never add a second one next to it.
.add_plugins(DebuggerPlugin::default())
.add_plugins(RemoteHttpPlugin::default())
.run();
}
Then cargo install bevy_fairy --no-default-features --features server and register bevy-fairy --stdio with the agent. The README’s Quick Start is the same two steps with the checks between them.
What it gives you
- Read state, change it, undo it.
brpcalls any BRP method the game serves;observeanswers a phrase query with component values and diffs it against the last read;experimentspawns, modifies and deletes entities and steps back through its own history — the tools, changing the game. - Watch one value over time.
watchreports which fields moved and which stopped, each sample stamped with the game frame;burstreturns a run of frames as one labelled contact sheet;bevy_fairy/ringrecords frames inside the game and freezes on a trigger — the tools. - Run the game’s own actions, and replay them.
commandslists what the game registered with typed params and a worked example;runcalls one;scene savewrites the run to a fileBEVY_FAIRY_SCENEreplays at startup — commands, scenes. - See the screen.
screenshotcaptures from an offscreen render target or from the window, with a crop and a zoom, and says which frame it was asked on and which it was delivered on — capture. - Press keys, type, click and drag.
bevy_fairy/inputwrites into Bevy’s own input messages, soButtonInput, text fields andbevy_uipicking all see it; a press, a cursor move and a release elsewhere is a drag — input. - Ask a person.
guideposts a script the game draws one step at a time, and each step moves on when a checkpoint the game registered passes — the guide overlay. - Six worked sessions. A value that stops changing, an entity in the wrong place, a capture with state beside it, a player’s keystroke, a regression test that is a command, a reproduction walked through a person — workflows.
Use it in the Cauldron
The Cauldron takes this crate as an optional dependency, bevy_debugger_bevy (the package is bevy_fairy), pinned to a git revision of main with default-features = false, features = ["plugin", "plugin-guide", "plugin-screenshot"]: the guide overlay, capture, and the injected cursor, and none of the server. With the feature off, cargo tree -i bevy_debugger_bevy finds no package and neither does bevy_remote.
There is no settings panel for it, because there is nothing to author: the plugin has no file format of its own and no serde configuration. What it does in the editor is drive the editor.
DebuggerPlugin::default()is added inharness.rs, so the editor’s own window answersbevy_fairy/status,commands,input,screenshot,capture,guideandquitat 127.0.0.1:15702. That is how an agent looks at the Cauldron the way it looks at a game; it is on by default because the editor is not a build that ships to a player.DebugCaptureTargetis inserted insurface.rswith the image the editor’s camera renders to, so ascreenshotof the Cauldron is the editor’s own interface — panes, tabs and all — captured offscreen, with the window behind another app or on another Space.DebugCommandsAppExt::add_debug_commandinops_brp.rsregisters the editor’s own verbs, so an agent finds them withcommandsand runs them withrunwith typed params and an example, rather than driving the UI blind.CheckpointsandGuideinguided.rsandchooser.rsare what a guided run uses: each step names a condition the editor itself evaluates, so a script the agent posts advances when the author actually got there.GuidePlacementisinsert_resourced attop: 58.0so the card sits below the title line rather than over the tab bar it describes.cursor_position(&window, &DebugCursor)inview.rsis the one line an editor that reads the pointer itself has to write: the plugin injects a cursor instead of moving the real mouse, so a host reads through the plugin’s function rather thanWindow::cursor_position.
A setting that would fit a panel, and does not exist yet: a GuidePlacement and a “debugger on/off” toggle in the editor’s own settings file, so the port and the card’s position survive a restart.
Links
Contributing
How issues, pull requests and docs work across the coven is in the org’s CONTRIBUTING.md, and every README and docs page follows the one documentation guide, DOCUMENTATION.md. A change that a user can see updates its crate’s README, its docs/ folder and its page in this book in the same pull request.