Why
The engine is ready for dynamic rules and automata, but it has no shared contract for mechanics that carry state across turns. Gates, switches, and one-step tiles will otherwise add fields that work in play but disappear on Undo, restore, sharing, or solver replay. The solver already has an explicit registry for compact mechanic fields, but the gameplay engine and mod boundary do not provide the corresponding lifecycle.
What Changes
- Define a versioned, declarative mechanic metadata contract for levels and CommonJS packs.
- Add an engine-owned
state.mechanicsenvelope initialized from authored metadata and carried through reset, turns, Undo, restore, andgetState(). - Define named mechanic turn hooks around the existing movement, transform, automata, and contact phases without allowing arbitrary mod code to run.
- Extend settled events with normalized mechanic transitions and diagnostics.
- Preserve mechanic metadata through normalized packs, data-only sharing, and CommonJS export/import.
- Require every dynamic mechanic field to register a deterministic compact solver representation and fail closed when state is unregistered or cannot round-trip through authoritative restore.
This change defines the foundation only. It does not decide gate occupancy, switch edge behavior, FRAIL timing, crumble leftovers, or any other mechanic's gameplay semantics. Those behaviors belong in separate changes with world fixtures and design approval.
Capabilities
New Capabilities
declarative-mechanic-state: validated mechanic metadata, lifecycle state, events, snapshots, sharing, and solver registration.
Modified Capabilities
None.
Impact
The engine state and restore boundary, CommonJS/mod validation, normalized pack and sharing paths, solver codec/transition setup, and focused tests will change. Existing levels without mechanic metadata retain the current state shape and behavior. Designer-owned rendering and world-owned level content remain out of scope.