← Back to docs

v0.24.1

Changelog

All notable changes to ECSpresso are documented here. Format loosely follows Keep a Changelog.

0.24.1

Changed

inspection, contextual recipes, and separate simulation, rendering, and play

evidence. Runnable health/combat examples demonstrate synchronous events and

deferred command visibility.

separate scene presentation from ECS lessons. The gallery groups introductory

lessons, focused features, games, and diagnostics, including new behavior-tree

basics and mutation/change-tracking lessons.

Fixed

Starter bounces clamp overshoot and wall-hit marks remain bounded.

explosions have explicit ownership. Sprite-animation indicators reuse text

objects and release owned assets; React health milestones log crossings once.

0.24.0

Added

.after() declarations. Explicit processing edges precede priority, retain

fixed phases, and validate missing references, duplicate bindings and cycles.

accept primary-system ordering options. Spatial indexes accept phase-specific

rebuild ordering. The turret-defense example now declares its detection and

aiming dependencies directly.

EasingFn type.

completions and type diagnostics from the library declarations, isolated

execution, and recovery from compile errors or stalled code.

Changed

effects. Invalid registrations block processing until repaired; disposal

still cleans up invalid graphs. Updates pin their phase schedules, so runtime

priority/phase changes apply on the next update and removals take effect

immediately, including later fixed steps.

built package. Behavior-tree guidance clarifies that blackboard defaults are

shallow-copied and require fresh nested values for independent mutable state.

Fixed

baseline when the first value becomes available. This repairs silent

$screen and lazy-resource subscriptions without sending an initialization

callback with an undefined previous value.

state per installation. This includes both spatial indexes, input, detection,

audio, diagnostics, coroutines, flocking, particles, UI, and renderer caches

and cleanup hooks. Caller-supplied resources retain their existing ownership.

containers during world disposal. Renderers created by the plugins are

disposed with the world; supplied renderers and ECS-provided GPU assets remain

caller-owned.

clock exists. The audio example uses deployment-relative asset URLs and runs

the world update loop required for playback processing.

isolate Bevy in an iframe, and disable Bevy when its generated files are absent.

0.23.0

Changed

standalone uninstall and retains its failures until teardown observes them.

dependencies, and does not repeat an exit already underway.

components and descendants, then throws an aggregate error after removal.

explicit mutation declarations, dependency timing, and proportional

validation, with focused change-tracking, lifecycle, and testing references.

gates, and are detached when their system is removed.

validate required value types across components, events, resources, assets,

and screens, including the first builder plugin.

plugins with application-specific collision layers or input action unions

can carry those types through their factory generics.

operation. It stops new work, detaches systems, removes entities, runs async

plugin/resource cleanup, and reports failures after cleanup continues.

Callers that previously ignored dispose() may continue doing so, but code

that needs teardown completion should await it.

browser-portable CleanupControl. Call cleanup.requestDisposal() when a

callback must initiate owner teardown without waiting on itself; normal

await world.dispose() calls remain the complete external barrier. Resource

teardown joins active partial/bulk work, preserves dependencies, and reports

initiating cleanup failures after remaining disposal completes.

shape; SystemLifecycleFn<Cfg> remains the initialization callback shape.

disposal without being initialized or registered for processing.

Internal

and automated checks for consumer-skill references, mirrors, and plugin paths.

0.22.0

Fixed

that creates the version commit and tag before publishing.

0.21.0

Breaking

Reusable features must use canonical definePlugin(). Application-owned

system modules should accept SystemRegistrarOf<W> and receive either the

full built world or a scoped registrar.

Added

registration capability with snapshotted phase, priority, and screen defaults.

SystemRegistrarOf types.

Internal

range so the generated documentation pipeline remains reproducible.

0.20.0

Changed

Added

0.19.2

Added

- createCamera3DPlugin({ projection: 'orthographic', minZoom?, maxZoom? }) clamps camera3DState.setZoom, initial zoom, camera sync at init, and built-in wheel zoom (defaults 0.1–10, matching the 2D camera plugin wheel limits).

0.19.1

Added

- Orthographic cameras now use wheel input to update camera3DState.zoom by default.

- createCamera3DPlugin({ wheelMode }) supports 'auto', 'distance', 'zoom', and 'disabled'.

0.19.0

Breaking

- onEnter({ entity, ecs }) instead of onEnter(entity).

- onExit({ entityId, ecs }) instead of onExit(entityId).

Added

- ScreenDefinition.onResume({ config, state, ecs }) runs after popScreen() restores a stacked screen as current.

- screenResume events and game.onScreenResume(screen, handler) expose the same resume point to centralized screen wiring.

0.18.0

Breaking

ScreenDefinition<Config> now defaults State to Config instead of Record<string, never>.

That means code like this may now fail typecheck:

type Screens = {

playing: ScreenDefinition<{ level: number }>;

};

const playing: Screens['playing'] = {

initialState: () => ({}),

};

Before, omitted State meant empty state. Now omitted State means state mirrors config, so initialState must return { level: number }.

Added

- SystemProcessFn<Cfg, Queries, ResourceKeys?, Singletons?> names the .setProcess(...) callback shape.

- SystemLifecycleFn<Cfg> names the .setOnInitialize(...) / .setOnDetach(...) callback shape.

- AssetConfiguratorFn<Assets, AssetGroups?> names the .withAssets(...) callback shape.

- ScreenConfiguratorFn<Screens> names the .withScreens(...) callback shape.

- ComponentsConfig<T>, EventsConfig<T>, ResourcesConfig<T>, AssetsConfig<T>, and ScreensConfig<T> build single-slot configs without spelling empty WorldConfigFrom parameters.

- spritesheetLoader<S>(url) — AssetConfigurator-compatible loader; lazy-loads pixi.js and runtime-shape-checks the resolved value so non-atlas URLs error at load time instead of deep in the play loop.

- clipFromSheet(sheet, name, options?) and animationSetFromSheet(id, sheet, options?) — build clips/sets from a loaded Spritesheet<S>. Animation-name union is inferred when S is declared as an interface ... extends SpritesheetData. Both throw on zero-frame animations.

- clipFromGrid({ source, frameWidth, frameHeight, columns, rows?, count?, indices?, ... }) — slice a grid-arranged image without atlas JSON. Async (lazy-loads pixi) and validates inputs: exactly one of rows/count/indices is required, indices are integer- and bounds-checked when rows is given.

- New exported types: SheetClipOverrides<A>, SheetAnimationKeys<S>.

Internal

0.17.0

No breaking changes from 0.16.3.

Added

Performance

Internal