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).