Add plugin skeleton with versioned skill directories, TODO SKILL.md scaffolds with goals for skill-creator, and copy over bevy-skill-research reports from spacecraft into docs/workpad/research/.
4.5 KiB
Bevy Skill Research: ECS Core
Bevy version: 0.18, with 0.19 notes
Date: 2026-07-07
Components
Derive: #[derive(Component)] on structs/enums. Requires Send + Sync + 'static.
Storage:
- Table (default) — fast iteration
#[component(storage = "SparseSet")]— fast insert/remove
Immutable components (0.18+): #[component(immutable)] — restricts to &T only, no &mut T.
Required components: #[require(B, C)] — auto-inserts B and C when this component is added. Supports constructors: B(value), C { field: val }, function calls, = expr.
Hooks: on_add, on_insert, on_replace, on_remove, on_despawn — set via #[component(on_add = fn_name)] or self-referential #[component(on_add)].
Clone behavior: #[component(clone_behavior = Ignore)] to skip during entity clone.
Bundles removed (0.16+): Use #[require(...)] or spawn with tuples instead of #[derive(Bundle)].
Resources
| Type | Purpose |
|---|---|
Res<T> |
Shared read access |
ResMut<T> |
Exclusive write access |
Option<Res<T>> / Option<ResMut<T>> |
Resources that may not exist |
Local<'a, T> |
Per-system private state, persists across calls, default-initialized |
NonSend<T> / NonSendMut<T> |
For !Send resources |
World methods: init_resource::<R>() (uses Default), insert_resource(value), remove_resource::<R>().
0.19 change: Resources implement Component and live on abstract entities. Query<Entity> now matches resource entities — filter with Without<IsResource>. Cannot derive both Component and Resource on one type.
Systems
Standard: any fn(params...) { } where each param implements SystemParam.
Fallible (0.18+): fn system(params...) -> Result — bare Result (alias for Result<(), BevyError>). Errors are logged, system continues on next tick. ? operator works with any error convertible to BevyError.
Exclusive: fn system(world: &mut World) { } — full world access, blocks parallelism.
Registration: app.add_systems(Update, (sys_a, sys_b)) or app.add_systems(Startup, setup).
Valid SystemParam Types
Query, Res, ResMut, Commands, Local, MessageReader, MessageWriter, ParamSet, Single, Populated, SystemName, SystemChangeTick, RemovedComponents<T>, DeferredWorld, &World, (), Option<T>, Result<T, SystemParamValidationError>, PhantomData<T>.
Queries
Signature: Query<D, F> where D: QueryData, F: QueryFilter (default ()).
Data Parameters
&T— read&mut T— writeEntity— entity IDHas<T>— returns bool- Tuples of the above
Filters
| Filter | Fires when |
|---|---|
With<T> |
Entity has component T |
Without<T> |
Entity lacks component T |
Added<T> |
First tick after component added |
Changed<T> |
First tick after add or mut deref |
Spawned |
First tick after entity spawn (new) |
Or<(A, B)> |
Either filter matches |
Key Methods
.iter()/.iter_mut()— iterate all matching.get(entity)/.get_mut(entity)— single entity lookup.single()— panics if not exactly one match.par_iter()/.par_iter_mut()— parallel iteration
Specialized System Params
Single<D, F>— system param alternative toquery.single(), panics if not exactly onePopulated<D, F>— system skips execution if query is empty
Custom Derives
#[derive(QueryData)]— for complex query data#[derive(QueryFilter)]— for reusable filter combinations
Commands
| Method | Purpose |
|---|---|
commands.spawn((CompA, CompB)) |
Spawn entity with tuple, returns EntityCommands |
commands.spawn_empty() |
Empty entity, chain .insert(bundle) |
commands.spawn_batch(iter) |
Batch spawn from iterator |
commands.entity(e).insert(comp) |
Add component to existing entity |
commands.entity(e).insert_if_new(comp) |
Add only if absent |
commands.entity(e).remove::<T>() |
Remove component |
commands.entity(e).despawn() |
Destroy entity (auto-recursive with children) |
commands.queue(custom_command) |
Push custom Command impl |
System Ordering
(a, b).chain()—aruns beforeb.before(system_or_set)/.after(system_or_set)— explicit ordering#[derive(SystemSet)]— define named sets for groupingapp.configure_sets(Update, SetA.before(SetB))— order setsAmbiguousSystemConflictsWarningwarns about unordered systems with overlapping access