// SPDX-License-Identifier: CC-BY-SA-4.0 // Copyright (c) Jonathan D.A. Jewell j.d.a.jewell@open.ac.uk // SPDX-FileCopyrightText: 2024-2026 Jonathan D.A. Jewell (hyperpolymath) = Enaction Engine :toc: :toc-placement: preamble
image:https://img.shields.io/badge/Code-AGPL–3.0–or–later-blue.svg[Code licence: AGPL-3.0-or-later,link=“https://www.gnu.org/licenses/agpl-3.0”] image:https://img.shields.io/badge/Docs-CC–BY–SA–4.0-blue.svg?logo=creativecommons[Docs licence: CC-BY-SA-4.0,link=“https://creativecommons.org/licenses/by-sa/4.0/”] image:https://img.shields.io/badge/RSR-Rhodium_Standard-9C27B0[Rhodium Standard Repository,link=“https://github.com/hyperpolymath/rhodium-standard-repositories”]
Enaction Engine is a deterministic, type-safe game engine for worlds shaped through perception, affect, intention, action and consequence.
The name describes the intended whole: agents and worlds continuously constitute and alter one another through situated action. The current code is deliberately smaller than that destination. It is an early deterministic timing and interpolation substrate, implemented in Rust and tested as one crate. // ── Compliance ───────────────────────────────────────────────────────────── image:https://img.shields.io/badge/SOC_3-Compliant-brightgreen[SOC 3 Compliant,link=https://github.com/organizations/metadatastician/settings/compliance] image:https://img.shields.io/badge/ISO_27001-Compliant-blue[ISO 27001 Compliant,link=https://github.com/organizations/metadatastician/settings/compliance] image:https://img.shields.io/badge/CIAQ-Compliant-9f55ff[CIAQ Compliant,link=https://github.com/organizations/metadatastician/settings/compliance] nimage:https://www.bestpractices.dev/projects/8509/badge[OpenSSF Best Practices,link=“https://www.bestpractices.dev/projects/8509”]
== The invariant everything follows from
The simulation advances only in whole, equal steps, and render interpolation never feeds simulation state.
Variable frame time must not become simulation input.
enaction-time therefore turns elapsed wall time into a
count of whole fixed steps and a render-only fraction. A host simulates
the whole steps, then may use that fraction to draw continuous values
between two completed states. Discrete values are read from the current
state, never blended.
== Implemented now
What exists is a timing crate plus one deliberately small typed event
seam: The repository currently provides enaction-time:
[cols=“1,3,2”] |=== |Artifact |Implemented behaviour |Evidence and provenance
|FixedStep |Fixed-timestep accumulation, whole-step
counts, a render fraction, hostile input handling, and a configurable
spiral-of-death guard. |Unit and doctests in this repository. New engine
code; it has not yet run in a released game.
|DoubleBuffer<T, N> |Two inline fixed-size state
buffers, commit/prime/snap operations, exact endpoints, and render-only
interpolation of continuous values. |Tests inherited or derived from
IDApTIK experience. The interpolation design has served in IDApTIK; this
extracted crate has not yet replaced that game code.
|Blend and lerp |Clamped, endpoint-exact
interpolation, including measured floating-point edge cases. |Unit
tests, doctests, and size checks. No heap allocation appears in these
operations or in the fixed-size buffer representation. |===
Discontinuities such as teleports, restarts, loads, or
resynchronisation use commit followed by snap:
the new state first enters the buffer, then stale history is
discarded.
== Intended engine direction
Enaction Engine is intended to grow into a complete game engine. Its destination includes deterministic simulation; world and event models; agency and embodiment; physics and interaction; rendering and presentation; sound and music; input; networking and multiplayer; persistence and replay; assets and content; host contracts; tools; and Universal Modding Studio integration.
That direction is not a claim that those systems exist today. There is currently no renderer, ECS, audio system, input layer, asset pipeline, networking stack, general AI framework, physical simulation, or complete cognitive, affective, or conative implementation here. New modules must arrive with a real use, implementation, and tests; empty subsystem crates are explicitly disallowed.
=== Cognition, affect, and conation
These are sibling dimensions of agency, not competing names for the engine:
- cognition covers perception, attention, memory, belief, inference, and planning;
- affect covers appraisal, mood, atmosphere, trust, fear, attachment, and significance;
- conation covers needs, motives, goals, commitment, inhibition, and action selection.
They operate over host-defined entities, events, worlds, ecologies, and institutions. Games retain their domain ontology and game-specific rules.
== Proving grounds
link:https://github.com/metadatastician/IDApTIK[IDApTIK] is the first
proving ground. Its deterministic, event-sourced Rust core supplied the
operational experience behind DoubleBuffer, discontinuity
handling, continuous-versus- discrete rendering, replay, and snapshot
concerns. FixedStep itself is new engine code and is not
yet integrated into IDApTIK.
Chronicles of Slavia is the planned second abstraction test. A facility should not be called general merely because one game can use it: the second game must exercise the boundary without importing IDApTIK-specific ontology into the engine.
== Universal Modding Studio
Universal Modding Studio (UMS) will author, generate, validate, preview, and package content through versioned game profiles and contracts. Enaction Engine is runtime infrastructure; it must not depend on the UMS application. Released games consume validated, compiled packages rather than the editor UI. See link:docs/architecture/UMS-INTEGRATION.adoc[UMS integration].
== Using the current crate
[source,rust]
use enaction_time::{DoubleBuffer, FixedStep};
let mut clock = FixedStep::from_hz(60.0); let mut buffer: DoubleBuffer<f64, 1> = DoubleBuffer::new(); buffer.prime(&[world.x()]);
for _ in 0..clock.advance(real_dt) { world.step(); // whole steps only buffer.commit(&[world.x()]); } draw(buffer.sample(0, clock.alpha())); // render-only —-
== Repository map
== Current integration evidence
crates/enaction-time/tests/idaptik_parity.rs covers
healthy fixed-step accounting, hostile elapsed time, interpolation,
discrete versus continuous state, discontinuities and snapshot/restart
interaction. It proves the extracted interpolation boundary; it does not
prove that IDApTIK uses FixedStep. IDApTIK still uses
Bevy’s accumulator, and this pass deliberately does not replace it.
Enaction is a runtime dependency candidate below games. It does not
depend on UMS. An optional UMS preview adapter may be added later, but
released games must not depend on the UMS UI. The current IDApTIK
appraisal example is game-local; the general enaction-trace
seam is new and remains unadopted.
== Language
The intended long-term implementation language is AffineScript. This is Rust, deliberately and for now: AffineScript is a real working compiler, but it ships no release artefact and its typed-wasm bridge is still gated. The port is gated on both of those, and would pin to a compiler commit rather than a version. See link:docs/decisions/0004-rust-now-affinescript-later.adoc[ADR-0004]. [source,text] —- crates/enaction-time/ current Rust timing and interpolation crate docs/architecture/ target architecture and integration boundaries docs/decisions/ accepted architecture decisions docs/status/ROADMAP.adoc evidence-gated staged direction .machine_readable/ RSR metadata, policies, and contracts build/just/ recipes imported by the root Justfile scripts/ repository and verification gates —-
== Build and verification
[source,sh]
cargo fmt –all – –check cargo test –workspace cargo clippy –workspace –all-targets – -D warnings just test just verify —-
The exact RSR gates behind just verify are defined in
Justfile and build/just/.
EXPLAINME.adoc maps the major claims above to
implementation artifacts and checks.
== Language direction
Rust is the implementation language now. AffineScript is a future direction only when it has a genuine release artefact and the required typed-Wasm path is ready. Any later port must preserve behaviour and tests, pin its toolchain, and earn adoption through working integration; no AffineScript build is claimed today. See link:docs/decisions/0004-rust-now-affinescript-later.adoc[ADR-0004].
== Current limitations
- The crate supplies timing and interpolation utilities, not a frame loop or a complete engine runtime.
- Determinism of a whole game still depends on the host using deterministic state, ordering, arithmetic, inputs, and side-effect boundaries.
FixedStepdrops excess accumulated time when its step cap is reached; hosts should observetook_shortcut()and decide how to surface degraded timing.- The no-allocation evidence covers the current fixed-size value representation and its operations, not an instrumented whole-process allocator trace.
- Current extracted code has not yet been validated as a reusable contract by two games.
== Licence
Code, configuration, and scripts are link:LICENSE[GNU Affero General
Public License v3.0 or later] (AGPL-3.0-or-later). Prose
documentation is CC-BY-SA-4.0. Full texts are in
LICENSES/; per-file SPDX headers remain authoritative.
Long-term attribution uses Quantum-Safe Provenance as described in
link:docs/legal/EXHIBIT-B-QUANTUM-SAFE.txt[the provenance exhibit].