The simulation engine for AI-native MMORPGs

Build entire worlds. As one person.

An engine for living worlds - not a game, but the simulation games run on. Here it is booting for real: seven processes, four tiers, dozens of live modules.

Everything is Entity./Everything is connected./Everything is simulated.

In active development - built in the open. 220 components · 153 updated in the last 30 days · building since Dec 2024.
// Scale by design

Billions of entities. Millions of players. One planet.

ASE simulates individuals, not averages - every leaf, every worm, every bacterium is a first-class entity. Scale isn’t a slider you push; it’s the shape of the architecture.

desert
desert - every climate band, simulated
cloudforest
cloudforest - a sampling of the engine’s biome models
coralreef
coralreef - every climate band, simulated
rainforest
rainforest - a sampling of the engine’s biome models
mountains
mountains - every climate band, simulated
tundra
tundra - a sampling of the engine’s biome models
mangrove
mangrove - every climate band, simulated
ocean
ocean - a sampling of the engine’s biome models
Billions
Entities targeted
Millions
Concurrent players
0
L3 sim modules
0
L4 plugins
0
Named schedules
0
Execution tiers
millions / meadow
A single meadow is already millions
10,000 grass blades × 50 leaves, 1,000 insects, 100 earthworms turning soil, 10,000 bacteria decomposing matter - for ONE meadow. Multiply across a planet and the count reaches billions of independently-simulated entities.
20 Hz → 0.01 Hz
Layered clocks, fast life to slow stone
The world is modeled like a geographic information system, each sphere on its own clock: the Anthroposphere ticks ~20 Hz, the Hydrosphere ~1 Hz, the Atmosphere ~0.1 Hz, the Lithosphere ~0.01 Hz. Bacteria tick fast, tectonics tick slow - each layer owns its rate, LOD and persistence.
EnTT → RAM → MongoDB
HOT / WARM / COLD streaming
Billions of entities don’t fit in RAM, so ASE streams them: the active chunk is HOT in EnTT (every worm digs, every bacterium lives), nearby chunks WARM as aggregated densities, distant chunks COLD in MongoDB - compressed and persisted, waiting for a player to approach.
~6 GB / 1000×1000 world
Chunk math that adds up
~6 KB per 32×32 heightmap chunk, 9 active chunks around a player at ~54 KB, a 1000×1000-chunk world at roughly 6 GB. Planetary scale, with concrete numbers behind it.
20 / 1 / 0.1 per sec
The tick-rate economy
Movement, collision and combat run 20/sec; hunger, thirst and temperature 1/sec; plant growth, weather and decay 0.1/sec. Plants don’t think 20 times a second - not updating slow processes at frame rate is what frees the CPU to carry a planet.
billions + millions
The target, stated plainly
Entire planets with ecosystems, every leaf and bacterium an entity, millions of concurrent players, real physics, weather and fluids - not a render of a world, a simulation of one.
O(n), not O(n²)
Scale is linear by design
Because systems write to shared components instead of wiring to each other, adding entities and adding behaviour both cost linearly. Scale isn’t a wall you optimise against later - it’s the shape of the data model from the first line.
WARM = densities
Aggregation, not deletion
A chunk you walk away from isn’t dropped - it collapses into aggregated densities (how many deer, how much biomass) and keeps evolving cheaply. Walk back and it re-expands into individuals. Nothing is lost, only summarised.
entity-per-item
No arrays, no ceilings
Components hold no arrays and no counts: a molecule with N elements is N entities, a forest is its trees. Structures are unbounded because a query, not a fixed slot, walks them - the data model refuses a hard limit.
Neo4j + MongoDB
Two stores, one world
Relationships, hierarchies and inventory live in one Neo4j graph; chunks, state and snapshots stream to MongoDB. Databases are persistence only - every active entity lives in RAM, so the simulation never waits on a query to tick.
ECS architecture: O(n) where object-oriented engines are O(n²). That is possible vs. impossible - not merely “faster”.
// Everything is connected

New cause-and-effect costs one Component field, not a web of wiring.

ASE’s founding axiom is an architecture, not a slogan: everything is connected, everything is Entity, everything is simulated. Pure ECS is what turns that axiom into something a CPU can actually run.

~10,000
OOP - 100 systems wired to 100 · lines of coupling
collapses to 
~100
ASE - 100 systems on one component bus · lines

The primitives

Entity · Component · System 3
An Entity is just an ID, a Component is pure data with no methods, a System is stateless tick logic - the strict spine that lets the engine treat every leaf and bacterium as a first-class object.
Components are pure data POD
Plain data, no methods, no .cpp - zero-initialised, single responsibility. Behaviour never hides inside data; it lives in stateless systems. That discipline is what keeps a billion entities cheap.
Everything Can, Nothing Must
Any entity CAN carry any component; none MUST. A rock that gains a MetabolismComponent starts metabolising - no class, no inheritance, no factory. Capability is attached, never declared up front.
Tags instead of type flags
No uint8_t type field, no if-else dispatch. A PredatorTag view runs predator logic, a PreyTag view runs prey logic - new behaviour is a new tag plus a new system, not a branch in an old one.
A view is a query, not a loop
No switch, no manual dispatch. A system opens a tag-filtered view and iterates exactly the entities that match - behaviour selected by which components an entity carries, resolved by the query itself.

Coupling

O(n²) → O(n) 10k→100
In OOP, 100 systems wiring to 100 is ~10,000 lines. In ASE, 100 systems each writing to a shared Component is ~100. Add a causal link by writing one field; every reader reacts automatically.
Components are the only channel
Systems never call each other - forbidden. ase-sky can influence ase-metabolism through ase-predator without any of the three knowing each other by name. The shared Hub keys are the entire contract.
The Hub is a star, not a mesh
83 L3 modules write and read through one Communication Hub - a star with zero direct module-to-module coupling. Adding a module adds spokes to the centre, never edges to the others.
Systems own no state
A System holds no member variables and keeps nothing between ticks - it reads components, writes components, done. Statelessness makes systems trivially parallel and endlessly composable.
Parallel because stateless
With no shared mutable state between systems, the scheduler runs independent systems across cores without locks. Concurrency isn’t bolted on - it falls out of the same discipline that removes the wiring.

The data model

New behaviour = new data 0 recompiles
Schema lives in data, not code. Adding a type or behaviour means spawning entities and attaching components. Arrays inside components are forbidden, so structures stay unbounded - zero rebuild.
Entity-per-Item, never arrays
Components hold no arrays and no counts. A molecule with N elements is N entities, each tagged - structures are unbounded and a query, not a loop, walks them. The model refuses fixed slots.
Data-driven, not hardcoded
Formulas read component fields; no magic numbers, no special cases. A new species, climate or economy is new data - never a branch buried in a system.
No inheritance, only composition
There is no class hierarchy. A bat is not a subclass of animal - it is an entity carrying Wings, Echolocation and Metabolism components. New kinds are new combinations, never a new base class.
Deterministic from inputs alone
Feed the same inputs and the world unfolds identically. Because state changes only through components and logged intents, a run is reproducible and replayable - the foundation the whole engine rests on.

Runtime & scale

66 schedules, 21 tiers
The tick isn’t one loop. A custom tiered scheduler orders every system across 66 named schedules in 21 tiers - from once-per-life init to 60 Hz frames. Deliberately not Bevy.
Layered clocks: 20 Hz → 0.01 Hz
Fast life ticks ~20 Hz, the hydrosphere ~1 Hz, the lithosphere ~0.01 Hz. Each system runs at the cadence its phenomenon needs, so a plant and a mountain share one world cheaply.
Billions in RAM, streamed to disk HOT/WARM/COLD
The chunk you stand in is HOT in EnTT, nearby chunks WARM as aggregated densities, distant chunks COLD in MongoDB. Scale is a streaming problem the architecture already solves.
Same ECS on both sides of the wire
EnTT on the C++ server, becsy in the browser, 1:1 parity for SHARED components. A SHARED system recomputes deterministically instead of shipping its result.
There is no graphics without meaning
The sun isn’t a light source - it’s a fusion reactor whose output drives photosynthesis, soil temperature, evaporation and the mood of every creature. Every visual is the surface of a simulation.
One file, one system
Each system is a single stateless file registered to a named schedule. Reading the file tells you exactly when it runs and which components it touches - no hidden registration, no god-object orchestrating the rest.
Reactive by construction
on_construct and on_destroy hooks fire the moment a component is added or removed, so reactions are wired to data changes instead of polled every tick. Attaching a component is itself an event.
// Where we stand

Built in the open. Maturing every day.

Every component carries a status in its VERSION registry - and it isn't claimed, it's auto-derived from the component's commit count. This is exactly where ASE stands today, not a promise.

seed → poc → init → core → feat → refine is computed automatically from each component's commit count; alpha · beta · stable are set by hand. Click any status to see exactly which components sit there - straight from the VERSION registries.

// The live graph

Pull one thread, the whole world moves.

Every module lives in one graph. Click a tile below - the live graph re-wires to that module’s real downstream chain, pulled straight from the engine’s causality docs.

live graph · ase-weather → 8 modules
One module pulses. The whole world answers.
Pull the weather
ase-atmosphere · 5
Pressure, temperature, wind, fog and rain fan out into breathing difficulty, sight, scent propagation, bird behaviour and the sky. Dim one field and five modules answer.
Pull the sun
ase-ephemeris · 5
The sun and moon’s position drives the celestial sky, circadian creatures, the tides through nautical, the render, and even religion’s celestial events.
Pull the land
ase-gis · 8
Geography seeds terrain, local climate, selection, trait expression, habitats, first life, pathing and where the fauna are placed - eight downstream modules from one map.
Pull the metabolism
ase-metabolism · 6
Energy budgets set foraging, survival, scent, movement stamina, healing rate and every hunger-driven decision. The body’s economy is read six ways.
Pull the sky
ase-celestial · 4
Day and night shift AI behaviour, activity windows in the food chain, visual range through perception, and the sky render. The clock overhead moves the ground below.
Pull the scent
ase-signature · 4
A scent trail drives predators that track it, prey-finding in the food chain, extended awareness through perception, and social identity. Smell is causal, not cosmetic.
Pull a fight
ase-combat · 4
A blow reshapes intent through the BDI layer, burns metabolic energy, spills blood that carries scent, and lands as a wound. Violence propagates through four systems.
Pull a life
ase-lifecycle · 3
Birth and death move food-chain populations, carry a soul, and reshape resilience through wounding as an entity ages. A single life ripples three ways.
Pull the genes
ase-genetics · 3
Genes reach back to first life in abiogenesis and forward into the senses through perception and into scent and markings through signature. Inheritance is wired both ways.
Pull the origin
ase-abiogenesis · 4
First chemistry starts entropy’s disorder, evolution’s selection, the earliest genomes, and the beginning of living-and-dying. The origin threads into the whole tree.
Pull the season
ase-calendar · 5
The turn of the calendar re-sets the weather, places the celestial sky, drives the sun track through the ephemeris, tints the render, and advances the clock itself.
Pull the body
ase-bbol · 7
The organism reaches into its genes, ageing, fighting and tiring, taking damage, learning to act, decaying, and driving behaviour - seven modules downstream of one body.
Pull the intent
ase-bdi · 3
A belief-desire-intention commits metabolic energy to a goal, focuses the senses through perception, and shapes the scent trail an actor leaves behind. Mind moves body.
Pull a skill
ase-skill · 5
Learned action ties into inherited aptitude, a lifetime of growing mastery, the body that enacts it, the practice that holds off decay, and the base processes beneath.
// Emergence, step by step

It starts with weather. It ends with a flooded settlement.

No script wrote this. The chain below is what one module's output does to every module downstream - because they share one graph.

Rain falls.
from ase-weather → atmosphere & hydro
Plants grow.
soil moisture rises → ase-plant metabolism
Herbivores bloom.
forage abundance → ase-creature populations
Predators follow.
prey density → ase-foodchain pressure
Rivers erode.
runoff load → ase-erosion & sediment transport
Settlements flood.
channel migration → ase-terrain & the worlds you built on it
All from ONE module.
change a single value upstream - everything downstream re-simulates.
~10 lines, 1 system
A new causality is normally zero new code
To make the moon brighten the night, one SkyMoonSystem writes moon_contribution into SkyBrightnessComponent - ~10 lines, one system. StarSystem, PredatorSystem and PlayerVisibility already read brightness, so they all change behaviour untouched.
stars = danger
Players learn it by playing, not by tutorial
Many visible stars mean a dark, moonless sky where predators ambush; few stars mean bright moonlight that exposes them. Lions hunt most successfully at new moon - ASE simulates reality, not Hollywood, and teaches it through play.
no script
Emergence, not choreography
Nothing in this chain is scripted. Each step is a system reading a component another system wrote. The flood isn’t an event a designer placed - it’s what the water cycle, the terrain and the rainfall add up to.
// The four-tier topology

Four process types, one concern each.

ASE splits its runtime into four planes - Engine, Replica, World and Reasoning - so a simulation crash, a lifecycle command and an LLM call can never block one another. The split isn’t cosmetic; it’s how the engine stays observable and scalable.

Engine
Control plane · :808x
Orchestrates lifecycle, reads project manifests, exposes a typed HTTP API for the ase CLI and CI only. Driven CLI-first, like kubectl or gh: build promotion, project start, smoke test and rollback are all scriptable.
Replica
Data plane · :900x
Owns authoritative state, persists to MongoDB, and is the single public gateway. Browsers talk only to Replica ports. Authentication, sessions, rate limiting and TLS all live here - the Engine and World carry no public auth model at all.
World
Compute plane · :9001+
Runs the simulation schedules and holds no state, no persistence, no client connections. The node that computes state is not the node that owns it - so a World boots, attaches to the state owner, catches up, produces, and tears down like a stateless web worker.
Reasoning
Cognition plane · the 4th type
The non-deterministic, language-based work deterministic simulation structurally cannot produce: skill outputs, NPC dialogue, narrative generation, lore-consistency checks, semantic routing and behavioral anti-cheat. LLM-native, by a dedicated tier - not a plugin.
Reasoning interprets
World simulates
Replica authorizes
Engine orchestrates
Engine :808x Replica :900x (public) World :9001+ + Reasoning browsers reach only :900x

Planes & boundaries

Four process types, one job each
Four distinct binaries, not one monolith: Engine orchestrates, Replica owns state and the public surface, World computes, Reasoning thinks. A crash or scale event in one is invisible to the others - they never share a process.
Three planes, one concern each control/data/compute
Engine orchestrates lifecycle; Replica owns authoritative state and gateways the public; World computes and owns nothing. Each is the smallest process that can restart alone without taking the others down.
Ports carve the trust boundary 808x / 900x / 9001+
The port ranges are the security model. Browsers reach only :900x; the control and compute planes are unreachable from the public internet by construction, not by policy.
Each tier is an observability boundary
A broadcast-latency spike points at the Replica, a tick-duration spike at the World, a lifecycle spike at the Engine. Two tiers in one process means a fault in one takes state, clients or scaling with it.
Reasoning is the fourth tier
Beside control, data and compute sits a fourth plane for language work - skills, dialogue, narrative, semantic routing, behavioural anti-cheat. Horizontally scalable and quota’d on its own terms, not bolted onto the loop.

Transport & wire

Five transports, each for one property 10 Hz tick
HTTP/REST for CLI and CI; WS-Binary + BIN_MSG for server-to-server (first byte is the type, flat layout memcpy-ed with zero allocations); WebRTC for browsers (reliable snapshots, unreliable input); SSE and WS-JSON non-default. Under a 10 Hz budget, binary zero-parse is correctness.
The Hub is the shared namespace
Modules write and read named Hub keys and the Almanach ships the deltas; no module knows another by name. 83 L3 modules coordinate through one star-topology Hub, so adding a module never rewires the others.
Wire ids live in a registry pre-reserved
Every binary message type has an id reserved in a protocol registry, allocated ahead of implementation. Tiers can be built in any order and never collide on the wire - the contract is written before the code.
Deltas, not snapshots, at steady state
After one snapshot the wire carries only deltas at the tick rate. A SHARED system recomputes client-side instead of receiving results, collapsing ~100 B × 20 Hz to ~4 B × 1 Hz: send the seed, not the picture.

Discipline

Lane discipline is enforced, not advised
Reasoning writes only intents, World consumes and writes state, Replica authorizes, Engine orchestrates. A skill emitting an undeclared intent is rejected at the engine level - the hard constraint that keeps a world replayable.
CLI-first, like kubectl for a world scriptable
The Engine HTTP surface is built for the ase CLI and CI first - build-promote, project-start, smoke-test and rollback are scriptable. The web console is a convenience layer on the very same API.
State at the Replica, compute is fungible
Because state lives at the Replica, any World can attach, catch up on deltas and take over. The plane that computes is never the plane that owns - exactly what makes the seamless, no-loading-screen handoff possible.
// Seamless at scale

Quantum-Travel handoff: the compute swaps mid-region, you never see a loading screen.

Because the browser is attached to the Replica and not the World, ASE can move, split and merge the compute behind a region - a topic-subscription handoff - while the player keeps walking. The seamlessness isn’t a trick; it falls out of the topology.

World Aat capacity / migrating
1 boot 2 subscribe + snapshot 3 catch up on deltas 4 assume compute
World B<100ms · no reconnect
the player keeps walking → observable state never gaps
Invisible handoff, by construction
no loading screen
When a World nears capacity or must migrate, a second instance boots, subscribes to the same Replica topics, receives a snapshot, catches up on deltas and assumes compute. Clients don’t reconnect, don’t re-auth, don’t see a loading screen. A region’s compute identity changes without its observable state changing.
Hot regions split, cold regions merge - live
no restart
The chunk-region partition isn’t fixed. A load-adaptive scheduler subdivides a hot region into two Worlds or collapses two cold regions into one from live telemetry, because reassigning a region is a topic-subscription change, not a state migration. Partition shape follows simulation density, not player count.
No EVE time-dilation, no Elite instancing
Two well-known MMO design trade-offs are explicit non-goals for ASE. It avoids EVE Online’s time dilation - horizontal compute keeps tick rate constant under load - and avoids Elite Dangerous’s player-cap instancing - a crowd never spawns a second disconnected copy of a location. The world stays one world.
Cross-project travel is just an edge
V-3 Verbund
Every project lives in one graph, so a crossing is a relationship between two nodes, not an export or a sync job. A trade caravan moving from project A to B copies no data and sends no inter-server message - and the player sees no handoff, because both projects are the same graph.
100,000+ projects on one substrate
100,000+
A hundred thousand projects share the unified graph and the shared Hub/Almanach namespace; each declares its own Replica groups via manifest. No per-project provisioning of databases or compute - the cost of the thousand-and-first project is similar to the thousandth, because the substrate doesn’t change.
Three independent scaling axes
3 axes
Vertical per process, horizontal per role (Replica per module group, World per chunk region), and the multi-project dimension. Coupling is topic-based: a new World is a new subscriber, a Replica split is a topic-routing change, a new project is a new project_id label. None of it touches another tier’s binary.
State lives at the Replica; the World is fungible
stateless world
The node that computes state is never the node that owns it. A World holds no state, no persistence and no client connections - a stateless compute worker that can be replaced mid-session without the players noticing.
Sub-100ms compute-node replacement
<100ms
Swapping the compute behind a region completes in under 100ms, typically under 10ms. Player reconnects under migration: zero. Loading screens under migration: zero. The handoff window is smaller than a frame.
Browsers reach only the Replica
Replica surface
The World (:9001+) and the Engine (:808x) are browser-unreachable; a browser speaks only to Replica ports. Authentication, sessions, rate-limiting and TLS all live on that single public surface - the compute and control planes carry no public auth model.
Snapshot, then deltas
snapshot + delta
A booting instance subscribes to the region’s Replica topics, receives one full snapshot, catches up on the delta stream, and only then assumes compute. The swap is invisible because observable state never gaps.
Five transports, each for one job
5 transports
HTTP/REST for CLI and CI, WS-Binary for server-to-server, WebRTC DataChannel for browsers (reliable for snapshots, unreliable for input); SSE and WS-JSON stay deliberately non-default. Each transport is picked for one property under a 10 Hz tick.
Binary, zero-parse on the wire
0 alloc
Server-to-server frames put the message type in the first byte and memcpy a flat layout straight into the Hub/Almanach - zero allocations, no JSON parsing on the hot path. At a 10 Hz tick that’s correctness, not micro-optimisation.
One graph, project_id-scoped
1 Neo4j
Every project is a labelled subgraph in one Neo4j instance - no per-project database, no silo. Cross-project relationships are Cypher matches over labels, so a caravan crossing worlds is one edge, not an integration.
Each tier is an observability boundary
isolated planes
A broadcast-latency spike points at the Replica, a tick-duration spike at the World, a lifecycle-latency spike at the Engine - because the planes never share a process. A fault in one can’t take state, clients or scaling down with it.
Partition follows density, not headcount
adaptive mesh
The load-adaptive scheduler reshapes the chunk-region partition from live telemetry: a dense, busy region gets more Worlds, an empty one gets folded away. The mesh tracks where the simulation is heavy, not where the players are counted.
Grows into a mesh at runtime
no restart
A project that starts on a single World becomes a multi-instance mesh during its own runtime. Reassigning a region is a topic-subscription change - no restart, no state migration, no downtime window.
The player never reconnects
session untouched
Through a split, a merge or a full migration the client’s connection to the Replica is never dropped. No reconnect, no re-auth, no loading screen - the compute behind the region changed, but the session and its observable state did not.
Elastic per region, from telemetry
auto-scaled
Capacity follows live telemetry with no operator in the loop: a busy region spins up more Worlds, a quiet one is folded away, continuously. Scaling tracks where the simulation is actually heavy, moment to moment.
Compute follows the crowd, ownership doesn’t
state stays put
Where players gather, more Worlds attach to that region’s Replica topics to share the load. The state’s owner - the Replica - never moves; only the fungible compute does. Density reshapes the mesh, not the source of truth.
// One source, both sides of the wire

Write the simulation once in C++. A transpiler grows its TypeScript twin.

ase-codegen parses the C++ backend and generates the becsy client - components, systems and constants - at 1:1 parity. The same deterministic logic then runs on the server and in your browser, which is exactly what lets the wire ship a seed instead of a picture.

atmo_sim_prs_chg_sys.cpp C++ · EnTT
class AtmoSimPrsChgSystem
    : public ecs::System {
  void tick(Registry& r, float dt) {
    auto v = r.view<AtmoStPrsChgComponent,
                    AtmoStPrsBaseComponent>();
    for (auto [e, chg, base] : v.each()) {
      chg.timer_s += dt;
      if (chg.timer_s >= 60.0f)
        chg.delta = std::min(base.p, MAX_P);
    }
  }
};
AtmoSimPrsChgSystem.ts TS · becsy
@system(s => s.after(AtmoSimPrsAltSystem)
  .inAnyOrderWithWritersOf(AtmoStPrsChgComponent))
export class AtmoSimPrsChgSystem extends System {
  private readonly query = this.query(q => q.current
    .with(AtmoStPrsChgComponent).write
    .with(AtmoStPrsBaseComponent).read);
  execute(): void {
    const dt = this.delta;
    for (const e of this.query.current) {
      const chg = e.write(AtmoStPrsChgComponent);
      const base = e.read(AtmoStPrsBaseComponent);
      chg.timer_s += dt;
      if (chg.timer_s >= 60.0)
        chg.delta = Math.min(base.p, MAX_P);
    }
  }
}
registry.view<A,B>()this.query(q => q.with(A).with(B))
view.each()query.current
std::min / std::sinMath.min / Math.sin
float x = 0.0flet x: number = 0.0
float field@field.float32
constexpr PIconst PI · imported (SSOT)
// why we do this - not to save typing

Two hand-written engines drift apart the first time someone fixes a bug on one side only. So ASE never writes two: the logic is authored once in C++ and the TypeScript twin is transpiled from it. One logic on both sides is what lets the browser recompute the world from a seed instead of streaming the picture, predict through a latency spike without stuttering, and stay locked to the server. It still drifts - floating-point and prediction always do - but the authoritative server pulls it back with tiny deltas, the way NTP disciplines a quartz clock against an atomic reference. Same logic is what keeps the drift small and the correction tiny.

SHARED both sides · 1:1

Components and deterministic systems that exist on server and client with identical fields. State that has to render - position, pressure, health. The transpiled systems live here.

SERVER-ONLY never sent

Buffers, requests, broadcast, persistence and Hub access. They stay in C++ and never cross the wire, so the client carries none of the server’s weight.

CLIENT-ONLY auto-generated

NetworkInput, RenderSync and EntityExport systems the codegen writes for you - the plumbing that applies network data to the ECS and syncs it into React.

Why a transpiler, not a second codebase

Identical logic on identical data
Both sides run the same transpiled algorithm over the same SHARED components, so the browser predicts deterministically and stays smooth through a latency spike instead of stuttering.
Send the seed, not the picture
Because the client recomputes rather than receiving results, the wire ships the inputs - collapsing ~100 B × 20 Hz of broadcast to ~4 B × 1 Hz. The client is the quartz clock, the server the atomic clock: the deltas only nudge it back into step, they never re-stream the whole world.
One source of truth, no drift
The C++ is authored; the TypeScript is generated and marked do-not-edit. A hand-maintained client twin can silently drift out of sync - a generated one cannot.
Type-safe across the boundary
Every C++ type maps to a becsy decorator - float to @field.float32, uint32_t to @field.uint32. Change a field in C++ and the client type reshapes on regenerate.
Constants have one home
A constant lives once - in hub/data or a module’s types.hpp. The same name in two modules is a build error, not a silent divergence between server and client.
SHARED can’t cheat
A transpiled system may not touch the Hub, a database or any server-only resource. That restriction is what guarantees it runs the same in the browser as on the server.
ase-codegen --module ase-atmosphere
  1. analyze
  2. clean
  3. structure
  4. types
  5. interfaces
  6. components
  7. transpile
  8. client systems
  9. integrate
  10. index
// Bring your own AI

Develop on your own Claude subscription. Flip one switch to ship.

ASE’s Reasoning-Edge daemon drives the CLI you already pay for - so the heavy iteration cost of building an LLM-driven MMORPG stays a fixed monthly subscription during development, not a metered API bill.

developmentedge_only your CLI subscription · $0 operator cost
flip one switch
one manifest field
productioncloud_only capped, auditable API backends
edge-daemon
$ase edge run
The edge daemon runs on your machine and spawns the installed CLI - claude, codex, gemini-cli, cursor-agent - as a child process, piping stdin/stdout. It proxies no OAuth tokens and manipulates no headers: technically indistinguishable from you starting the CLI in a shell.
Your CLI, as a subprocess
lifecycle.phase
$ase ship --phase production
development defaults to edge_only (your subscription, zero operator cost); production defaults to cloud_only (capped API backends). Flipping the phase ships the same skills with no skill-code change - an incompatible switch is blocked with a skill update list, not a silent break.
One switch to ship
install.sh
$curl edge.ase.dev/install | sh
One native binary under 50 MB for five platforms, each with an SBOM and an ES256 YubiKey-PIV signature for offline verification. It opens only an outbound WSS connection - no inbound port, so it works behind NAT and firewalls - and holds no at-rest state.
One-line install
tos.check
$ase reasoning --tos-check
Reusing a subscription’s OAuth token inside a third-party product is forbidden; invoking the official CLI as a subprocess is sanctioned. Because that clarification is informal, a provider re-closing the model is absorbed by a single manifest switch from edge to cloud-API - zero skill-code changes.
ToS-clean & resilient
backends
$ase edge backends
Four CLI backends plus a custom_backend slot. A skill declares a work_type, never a model name - so switching provider is an engine-config change with no skill-code edit, and dev-vs-prod use different backends for the same skill.
Bring any CLI
manifest.yaml
$ase edge init
The daemon reads ~/.ase-edge/manifest.yaml - which CLI, which project, which connection token. No project code lives on the edge; it only marshals the CLI’s stdout into typed intents the World can consume.
Config, not code
connection
$ase edge status
Outbound WSS to the Replica only, with heartbeat and auto-reconnect. No inbound port means it runs behind NAT, firewalls and café wifi; a dropped link re-attaches without losing the session.
Outbound-only, NAT-safe
vault.lease
$ase vault lease
In production, customer LLM keys live in a dedicated 3-node Vault; Reasoning never reads Vault directly. Each inference fetches a fresh 60-second lease token via the Replica, max 5 renewals - a compromised process can only steal a token that expires in seconds.
60s leases, never hosted
resolve
$ase reasoning --explain-resolve
A deterministic 7-step backend resolver maps a skill’s work_type to a concrete backend and logs resolved_backend_id, backend_pool_version, was_fallback and was_degraded per call - every inference is auditable after the fact.
Deterministic + logged
multi-edge
$ase edge lock
Several edge daemons can attach to one project; a lock mode arbitrates which daemon serves a given skill. A solo dev across two machines - or a small team - shares one project’s reasoning without collisions.
Multi-edge, locked
local.first
$ase reasoning --local
A local_resolution manifest block lets resolution step-0 answer on the edge with no egress before any cloud backend is touched. The cheapest, most private path is tried first by construction - not as an afterthought.
No-egress path first
audit
$ase reasoning audit query --skill <id>
Every inference records resolved_backend_id, was_fallback and was_degraded; the audit query returns the trace for any skill over any date range. “Why did this land on backend X?” has an answer, after the fact.
Every call is traceable
dev.cost
$ase edge cost
During development the iteration cost is a flat CLI subscription - externally, a Claude Max plan is roughly $200/mo versus an estimated $1,000–3,000/mo in equivalent metered API tokens. The expensive phase never meters.
Fixed, not four-figure
auto.tune
$ase reasoning tune
A tuning policy switches a skill’s backend or model-class when live cost-and-quality telemetry crosses a threshold - data-driven, no hardcoded model names. You set a target; the system finds the cheapest backend that still meets it.
Closed-loop cost control
~$200 vs ~$1,000–3,000 / mo
A fixed dev cost, not a four-figure API bill
Because skills run against your own CLI subscription during development, iteration cost is a fixed monthly subscription rather than metered tokens. Externally, a Claude Max plan runs roughly $200/month flat versus an estimated $1,000–3,000/month in equivalent API token cost. Production then flips to capped, transparent cloud billing.
2 layers, never crossed
Two cost layers that never touch
Layer 1 (servers, MongoDB/Neo4j hosting, engine-internal skills) is covered by the flat ASE subscription. Layer 2 - the LLM inference your game generates - goes straight to your own provider bill and never passes through the operator. The operator never subsidizes your LLM cost and never hosts your subscription tokens.
// Skills as ECS entities

A skill is an entity, not a service - compose them like LEGO.

In ASE a skill isn’t a markdown file or a registered microservice. It’s an ECS entity born at runtime from a declarative manifest and picked up by a query - the same Everything-Can-Nothing-Must principle, extended to reasoning.

SkillManifest · a skill is data, not a service
id: lore-consistency-checker
subscriptions: [ DialogueIntent, LoreState ]
reads:  [ CharacterMemory, WorldFacts ]
writes: [ AnomalyIntent ]        # nothing outside this is allowed
work_type: reasoning_heavy      # a need, not a model name
cost_layer: game
communication_pattern: standard
memory: [ episodic, semantic, procedural ]
quota: { usd, rate, concurrency, … }  # 10 axes, checked before spend
Attach a component → the skill is live.
Two skills on overlapping components → emergent reasoning, no orchestration.
11 manifest field-groups  ·  9 work_types  ·  0 registry services
Attach a component, the skill is live
0 registry services
A project attaches SkillManifest components to the right entities; the Reasoning Tier picks them up through registry.view<SkillManifest, SkillSubscriptions>. No skill-registry service, no loading pattern, no per-project setup endpoint - the composition logic lives in the query, not an orchestration layer.
One skill entity, every matching project
1 entity · N projects
A single centrally-authored skill - say a lore-consistency checker - lives once as an entity and traverses the shared V-3-Verbund graph across project boundaries, with no per-project install. Two projects with overlapping subscriptions get overlapping emergent reasoning without knowing about each other.
A skill physically can’t write outside its lane
11 manifest field-groups
The manifest is the only authority over a skill’s behavior. If a skill - through a bug, prompt injection or LLM drift - emits an intent type it didn’t declare, the write is rejected and logged as a lane-violation. The reads list is just as strict - an undeclared component can’t even enter the prompt, a default-privacy line under GDPR/LGPD.
Declare what you need, not which model
9 work_types · 7-step resolution
A skill declares a work_type like reasoning_heavy, not a model name. Switching provider is an engine-config change with no skill-code edit, resolved deterministically in seven steps and fully logged - resolved_backend_id, was_fallback, was_degraded and a full trace recorded per inference.
Reasoning never writes state directly
source:skill vs source:player
Skill outputs are logged as *Intent components tagged source:skill; player inputs as *Intent tagged source:player; World consumes both identically. That single lane rule is what keeps an ASE world reproducible from inputs alone - a replay can reuse logged intents or re-roll fresh reasoning.
Memory modeled on human cognition
9 collections
Skill memory is nine MongoDB collections along the Tulving/Squire classification - episodic, semantic, procedural, relational - with vector indices on the three semantic ones. The Replica owns all nine; Reasoning never touches MongoDB. Player memory sits in a GDPR/LGPD delete cascade driven by a single ase player forget.
Everything-Can-Nothing-Must, for reasoning
compose by attachment
The principle that governs world entities governs skills too: a skill CAN subscribe to anything it declares and MUST do nothing implicitly. Behaviour is composed by attaching a component, never wired by a coordinator - reasoning is just more ECS.
Two skills, emergent reasoning
emergent
Two skills subscribed to overlapping components produce combined behaviour neither declares alone. That’s the LEGO promise: no orchestration code, no integration - the composition is emergent, exactly like the simulation beneath it.
Quota gates every call, before the spend
10 axes · pre-spend
Ten orthogonal quota axes are checked before an inference runs. At a hard limit the call is never issued - a QuotaExceededIntent is written instead - so a prompt-injected or runaway skill cannot accumulate cost, because the spend never begins.
communication_pattern picks the lane
4 lanes
A skill’s communication_pattern - standard, anti_cheat_lane, reasoning_pipeline or engine_internal_bus - routes it onto the right lane with its own caps and escalation depth. Declared once in the manifest, enforced by the engine.
Anti-cheat is just another skill
anti-cheat lane
Behavioural anomaly detection ships as skills on a dedicated anti-cheat lane with deeper escalation caps and an inverted player quota - the more anomalous the behaviour, the more analysis it gets. Same entity model, flipped economics.
Credentials the skill never sees
60s lease
Customer LLM keys never reach a skill. Reasoning fetches a fresh 60-second lease token via the Replica for each inference (max 5 renewals); a skill is handed a capability, not a secret - and a compromised process can only steal something that expires in seconds.
Born at runtime, gone when detached
lifecycle = entity
A skill’s lifecycle is an entity’s lifecycle: it comes alive the moment its manifest component is attached and stops the moment it’s removed. No deploy step, no registration, no teardown script - spawning and despawning is the whole install story.
Reasoning is a tier, not a chatbot
4th process plane
The Reasoning Tier is its own horizontally-scalable process plane beside Engine, Replica and World - not an API call bolted onto a render loop. Language-based work lives where it can be scaled, quota’d and audited on its own terms.
Two cost layers, per skill
cost_layer
A cost_layer field decides who pays: engine-internal skills ride the flat ASE subscription; skills that call your own model bill straight to your provider. The operator never subsidises your inference and never fronts your tokens.
The World can’t tell skill from player
both are *Intent
Skill outputs and player inputs both arrive as *Intent components; the World applies them by the same rules and never branches on their origin. That symmetry is exactly what lets a non-deterministic tier sit on top of a deterministic simulation.
Vector search on three of nine
semantic memory
Of the nine memory collections, the three semantic ones carry vector indices for similarity recall; episodic and procedural memory stay exact-match. Reasoning holds only ECS reference pointers into them - the Replica owns the store.
One command erases a player
ase player forget
Data-subject erasure is a single operator command: ase player forget cascades a GDPR/LGPD delete across all nine memory collections at once. Privacy is a built-in operation, not a manual sweep across stores.
Every inference leaves a trace
fully auditable
resolved_backend_id, backend_pool_version, was_fallback, was_degraded and a full resolution trace are logged per call. Which model answered, whether it fell back and whether it degraded is reconstructable after the fact for any inference.
Idle skills cost nothing
subscribe, don’t poll
Skills react to component changes through subscriptions, not a polling loop. A skill with nothing to react to issues no inference and spends nothing - attention, and cost, follow where the simulation actually changes.
Ask why a skill chose a backend
audit query
ase reasoning audit query --skill <id> returns the resolution traces for any skill over any date range. “Why did this skill land on backend X?” has a concrete, after-the-fact answer, not a shrug.
Three flow patterns, that’s all
3 patterns
Every Reasoning Tier interaction reduces to three named flow patterns. Reasoning-domain modules and LLM plugins implement them; phase plans reference the pattern by name instead of re-choreographing it. The cognition layer has a grammar.
Skills that auto-tune
closed loop
A tuning policy can switch a skill’s model-class or backend, or pin a different manifest version, when live cost-and-quality telemetry crosses a threshold - data-driven, with no hardcoded model names and no per-skill special cases. The system tunes itself.
Answer locally first
local_resolution
A local_resolution manifest block makes resolution step-0 ask “can this be answered on the edge, with no egress?” before any cloud call is considered. Cheap, private, local cognition is tried first - the economic keystone of planet-scale reasoning.
The engine-internal bus is sealed
lane-enforced
A skill with cost_layer engine carries a lane marker that routes its output only to other engine-cost skills, never to customer skills - enforced at the wire level in the Replica’s decode. Internal cognition can’t leak onto a customer lane.
// Predictable cost

At a hard limit, the inference never starts - so cost can’t drift.

The Reasoning Tier gates every LLM call behind ten orthogonal quota axes. A prompt-injected or runaway skill can’t rack up a bill, because the spend never begins. Indie-friendly caps are a property of the architecture, not a promise.

axis 01USD cost
axis 02Rate-limit slots
axis 03Memory storage
axis 04Concurrency
axis 05Player-spam
axis 06Escalation depth
axis 07Cross-project reads
axis 08Edge subscription
axis 09Blast radius / skill
axis 10Blast radius / project
an inference request all 10 axes checked before any spend pass · the call runs fail · never issued → QuotaExceededIntent
Hard limit = inference not startedspend never begins
At a hard limit the call isn’t throttled, it’s never issued - a QuotaExceededIntent is written instead. A prompt-injected or runaway skill cannot accumulate cost, because the inference doesn’t begin in the first place.
Full token and USD transparency, per inferenceper-skill dashboard
Every call records resolved_backend_id, backend_pool_version, was_fallback, was_degraded and a full resolution trace. The customer dashboard aggregates cost-per-skill broken down by backend, fallback rate and degradation rate - you read the bill line by line.
Two cost layers, never crossed2 layers
Operator infrastructure cost and your LLM inference cost are separated structurally. The operator never subsidizes customer LLM spend and never hosts customer subscription tokens - so the two bills can’t contaminate each other.
Ten orthogonal quota axes10 axes
USD cost, rate-limit slots, memory storage, concurrency, player-spam, escalation depth, cross-project reads, edge subscription and two blast-radius axes - all ten must be satisfied before a single inference runs.
Capped per skill, player, project, backendcapped four ways
Every axis is enforced per skill, per player, per project and per backend, so no single dimension can run away. Predictable caps are a property of the architecture, not a promise printed on a pricing page.
Forecast within ±5%±5%
With a correctly declared skill manifest, cost forecasts land within about five percent - because the caps are declarative, the bill is predictable before you ship, not reconciled in shock afterward.
Develop on a subscription, ship on capsedge → cloud
Development runs edge_only on your own flat CLI subscription; production flips to capped, auditable cloud billing. The expensive iteration phase never touches metered tokens - cost discipline is enforced before money is spent.
Query the bill by skillaudit query
ase reasoning audit query --skill <id> returns the resolution traces behind a skill’s spend over any date range. The bill isn’t a black box - you can ask which backend answered, how often it fell back, and what it cost.
cost_layer decides who paysengine / game
A skill’s cost_layer is either engine (ridden on the flat ASE subscription) or game (billed to your own provider). The billing axis is declared in the manifest, so who pays for an inference is never a surprise discovered on an invoice.
Cheapest path first: local resolutionno egress
Resolution step-0 asks whether a call can be answered locally on the edge with no egress at all, before any paid cloud backend is considered. The zero-cost path is tried first by construction - the economic keystone of scaling cognition.
Quota persists without a bridgefire-and-forget
The Reasoning tier ships quota increments fire-and-forget to the Replica, which persists them to a dedicated quota state - no extra bridge service, no synchronous write in the hot path. Accounting never slows an inference down.
The system tunes toward a targetmin quality @ max cost
An auto-tune policy expresses a target - minimum acceptable quality at a maximum cost - and switches a skill’s backend or model-class when live telemetry crosses the threshold. Cost/quality is a dial you set, not a bill you audit later.
Flat marginal cost per project1001 ≈ 1000
Projects share one substrate - one graph, one Hub/Almanach namespace - so the cost of the thousand-and-first project is about the cost of the thousandth. There’s no per-project database or compute to provision, and no per-project cost cliff.
Bring your own AI during developmentedge_only
Iterate against your own CLI subscription while you build; production flips to capped cloud billing with one manifest switch. The phase where you burn the most inference - development - never touches metered tokens at all.
Cost is a manifest field, not a mysterydeclared
Quota, cost_layer and model-class are declared per skill in the manifest. Spend is designed up front - you can read a skill’s cost profile before it ever runs, rather than discovering it on next month’s invoice.
Escalation and blast-radius are cappedbounded reach
Two of the ten quota axes bound how far a single skill may escalate and how wide its effect can reach. A runaway or prompt-injected skill can’t chain itself into an unbounded spend - the reach is capped, not just the per-call cost.
Indie-friendly pricing with predictable caps. Bring your own AI during development.
Predictable caps - no metered runaway, no surprise invoices
Develop on your own AI subscription, ship on capped cloud billing
Cost discipline enforced before money is spent, not reconciled after
// Anti-cheat as first-class reasoning

Reasoning detects, World quarantines, Engine sanctions - a human signs the ban.

Anti-cheat is a built-in reasoning use-case with a three-tier authority hierarchy that escalates in irreversibility - and stops short of ever letting an LLM ban a player on its own.

// why from hour one, not after launch

Every MMO fights the same rot: bot farming, exploits, griefing, duped items, runaway inflation. EVE Online, World of Warcraft, Star Citizen: every long-running world has fought them in the open, and the lesson repeats. Enforcement bolted on after launch arrives too late; the economy is already poisoned, the wipe follows, and the players leave. ASE is built against that history from hour one, with three decades of MMO experience folded into the architecture: detection, quarantine and human-signed sanctions are engine primitives, not a post-launch patch.

reversibleAnomalyIntentReasoning detects
reversibleQuarantineStateWorld quarantines
irreversiblePlayerSanctionStateEngine sanctions · a human signs
Three authority tiers, escalating irreversibility
3 tiers
Reasoning writes a reversible AnomalyIntent (score + category + evidence pointer). World deterministically accumulates them into a reversible QuarantineState. Only the Engine writes the irreversible PlayerSanctionState - which requires a human_reviewer_id and an audit trail. A skill’s recommended_action can be monitor, quarantine or review, but never ban.
A detector suite you opt into per project
4 detectors
The design includes engine-cost detectors any project can enable: BehaviorWatcher (behavioral anomalies), CoordinationDetector (multi-account patterns), EconomyAuditor (economic exploits) and MovementValidator (speed-hack/teleport, reasoning-augmented atop World’s deterministic fast-check).
Suspicious players get watched more, not less
inverted quota
Anti-cheat skills carry an inverted player quota - the more anomalous the behaviour, the more analysis it gets - and run on a dedicated communication lane with deeper escalation caps. The economics are flipped on purpose.
Determinism survives a non-deterministic tier
replayable
Because reasoning only ever writes intents, never simulative state, an ASE world stays reproducible from inputs alone. A replay can reuse logged skill-intents for a perfect reproduction or issue fresh reasoning calls for non-deterministic re-generation - your choice, only possible because of the lane rule.
Your API keys: stored, never seen
60s leases · max 5 renewals
Customer LLM credentials live in a dedicated 3-node Vault cluster (Raft, auto-unseal), separated from engine credentials at the storage level. The operator identity has no read policy on customer paths, and Reasoning has no direct Vault access - every inference fetches a fresh 60-second lease token, max 5 renewals, mediated through the Replica. A compromised reasoning process can only steal short-lived tokens that quickly go worthless.
A human signs every ban
human-in-loop
The irreversible sanction can only be written by the Engine and requires a human_reviewer_id plus an audit trail. An LLM can recommend monitor, quarantine or review - it can never ban a player on its own. Automation escalates; a person decides.
Deterministic fast-check, semantic slow-check
<1s / <30s
MovementValidator runs a deterministic speed/teleport check on the World in under a second; reasoning-augmented pattern detection then adds semantic context in under thirty. Two speeds, one verdict - cheap certainty first, expensive nuance second.
Quarantine is reversible, sanction is not
reversible → final
QuarantineState accumulates deterministically from AnomalyIntents and can be lifted; only the final sanction is permanent. Escalation always runs from reversible toward irreversible, never the other way - a false positive costs a lifted quarantine, not a wrongful ban.
Collusion across accounts
multi-account
CoordinationDetector looks for patterns a single deterministic check can’t see - synchronized timing, economy flows and movement correlation across accounts - as an LLM pattern-recognition skill. Context is exactly what deterministic anti-cheat lacks.
Economy auditing, built in
economy
EconomyAuditor watches for dupe loops, market manipulation and impossible wealth curves as an engine-cost skill any project switches on - not a service you integrate. The economy is simulated, so its exploits are legible.
Evidence pointer, not a raw dump
auditable
An AnomalyIntent carries a score, a category and an evidence pointer - reasoning references ECS state, it doesn’t copy it. The audit trail stays lean, the World stays authoritative, and every decision is reproducible from the same inputs.
No kernel driver, no client scanning
server-side only
Detection is behavioural and lives on the server - ASE ships no anti-cheat kernel driver and scans no player’s memory. Cheating is caught by what a player does in the simulation, not by surveilling their machine.
Server-authoritative by construction
World owns state
The World holds authoritative state; client input arrives on the unreliable channel and is validated server-side. A hacked client can request, but it cannot assert - it never gets to write state the simulation didn’t compute.
Behavioural anomaly, not a rule list
novel exploits
BehaviorWatcher flags statistical anomalies through LLM pattern recognition, so it catches novel exploits a fixed rule list has never seen. The detector reasons about behaviour instead of matching a signature that attackers already know.
Escalation depth is a capped axis
quota-bounded
How far an anti-cheat skill may escalate is one of the ten quota axes - with a deliberately higher cap on the anti-cheat lane. Even the watchers run inside the same bounded, auditable cost model as everything else.
Scrutiny scales horizontally
more compute, not a bottleneck
Anti-cheat runs as reasoning skills on their own horizontally-scalable tier, so watching a suspicious player harder is more compute - never a stall in the game loop. Enforcement can grow without the simulation paying for it.
An immutable audit trail
append-only
Every sanction records the human_reviewer_id, the evidence pointer and a timestamp in an append-only trail. An appeal replays the exact record that led to the decision - not a summary written after the fact.
The intent is score, category, evidence
reports, doesn’t decide
An AnomalyIntent carries only a numeric score, a category and a pointer to the ECS state that triggered it. It reports; the World decides what to accumulate and the Engine decides whether a human ever sees it.
Watching runs on metered quota
bounded scrutiny
Anti-cheat inference is quota’d like any other skill - score, rate and escalation depth are all capped. Scrutiny has a bounded, auditable cost, so the enforcement side can no more run away than the game side.
Detection improves without a patch
manifest, not release
Because BehaviorWatcher reasons about behaviour instead of matching a fixed rule list, teaching it a new exploit pattern is a manifest and prompt change - not an engine release. The watchers learn faster than a patch cycle.
A false positive is cheap
reversible by design
Because everything below the final sanction is reversible, a wrong flag costs a lifted quarantine, not a wrongful ban. The escalation is built so that the expensive mistake - a bad permanent sanction - is the one a human has to sign for.
// Worlds you can build

Aetheria: 9,000 procedural planets that collapse into one shared world.

These aren’t features of ASE - they’re worlds built WITH it. Aetheria is the proof taking shape, the way Fortnite proves Unreal. Mythic on the surface, mechanical underneath.

9,0001
Reincarnation collapses the multiverse - a soul binds to flesh, every untaken path ceases to exist, and one irreversible, shared world remains.
9,000 planets · 6 phases
9,000 planets, not 9,000 shards
Aetheria generates 9,000 procedural planets that are birthplaces, not parallel servers. Each imprints a character across six phases - genetics, physique, vocation, theology, psyche, transcendence - so procedural variety becomes the cultural, genetic and spiritual diversity of one shared world.
9,000 → 1
Reincarnation collapses the multiverse
A soul moves as a superposition through unchosen futures; every decision spawns a branch, every discarded genome collapses for good. The instant it binds to flesh, all 9,000 planets and every untaken path cease to exist - one irreversible, shared reality, persisted to MongoDB and Neo4j.
5% / 10% / 15% / >15%
A world with an immune system
Antarien is not a body but an organism - Mater Dormiens, the sleeping mother. A data-driven wound index keyed to mining escalates: under 5% it sleeps; 5–10% furrows heal and tools corrode; 10–15% brings quakes, gravity anomalies and toxic gas; over 15% the nerve-paths beneath the ocean floor pulse and glow as it wakes.
1 universe
One organism, two games, no shards
The Convergence hands a character from the prequel Aetheria into the persistent world Antares Open World through a server-side handoff - one global universe, every player, no instances. The full dataset (seed, biome, genetics, theology, psyche) becomes permanent and irreversible.
5 characters
Five souls, one player
Each player runs five resonance chambers - five characters, five claims, five start zones, all alive at once. You steer one; the other four run AI-driven, with a soul-jump to switch between them. A firefly swarm-intelligence bridge ferries between your own characters along the Cruor network.
the pyramid paradox
Prequel knowledge becomes a compass
At reincarnation conscious memory is lost but the body keeps everything - genetics, vocation as muscle memory, soul-color predispositions. The player knows what the character cannot: the “holy stones” are clotted blood, the “earthquakes” are a creature turning over, the shrines are the thinnest spots in breathing skin.
built in the open
The reference world, in numbers
153 components · 86 systems (zero violations), 13 web submodules - the showcase that says you can build a real game with this, maturing daily.
6 phases
A person, not a spawn
Genetics, physique, vocation, theology, psyche, transcendence - each phase stamps the character, turning a procedural planet into a person with a body, a culture, a faith and a fate. Diversity is imprinted, not decorated.
ship = comet
The generation ship is a comet
The vessel that carries souls between worlds reads, from the outside, as a comet - the same object is both the myth in the night sky and the mechanism of the Convergence. Nothing in the world is only decoration.
72 / 1,789 / 1,794
Lore engineered, not improvised
The world is modelled as a Neo4j design graph - 72 modules, 1,789 use cases, 1,794 actors - before a line of it is played. The story has an architecture, the same way the engine does.
46,730 stars
A real night sky
The star map is 46,730 actual bodies from the HYG database - the sky above Aetheria is the real catalogue, navigable and consistent, not a painted backdrop behind the action.
soul-jump
Five lives, no logout
You steer one of five characters; the other four keep living AI-driven. A soul-jump moves your attention between them along the Cruor network - five claims, five start zones, one continuous presence in the world.
the Cruor network
A firefly bridge between souls
A firefly swarm-intelligence bridge ferries between your own characters along the Cruor network. Moving between your five lives isn’t a menu toggle - it is a journey through a living system that connects them.
prequel → persistent
Aetheria forges, Antares keeps
Aetheria is the prequel where a soul is forged across the six phases; Antares Open World is the persistent world where it then lives. Two games, one continuous universe - the Convergence is the seam between them.
MongoDB + Neo4j
Bound reality, written down
The instant a soul binds to flesh, the full dataset - seed, biome, genetics, theology, psyche - persists to MongoDB and Neo4j as permanent, irreversible fact. The lore isn’t narrated; it is stored.
// The module wall

Eighty-three L3 simulation modules, wired through one Hub.

The engine isn’t a monolith - it’s a star of independent L3 modules that write outputs and read each other through a Communication Hub, with zero direct coupling. Every L3 module in the tree below - each its own marker, with its real maturity.

// Architecture in layers

Six layers. Dependencies only ever point downward.

ASE is built in strict layers, L0 to L5 - and the line between engine and game runs right through them. Engine developers own L0–L3; you build your game in L4 and L5, and see nothing but the ase-sdk header.

L0Foundation
L1Core
L2Kernel
L3Modules
L4Plugins
L5Servers & Clients
Every layer depends only downward. No exceptions.
L0
Foundation
ase-math · ase-types · ase-utils · ase-containers · ase-json
Zero-dependency vector, matrix, noise and interpolation. Deliberately pure - no ECS - so nothing can leak downward. Every simulation system above it computes on this bedrock.
L1
Core
ase-ecs · ase-log · ase-neo4j · ase-mongodb
The EnTT-wrapping ECS, logging, and the Neo4j and MongoDB clients. Neo4j holds relationships and hierarchies; MongoDB holds chunks, state and snapshots.
L2
Kernel
ase-kernel
The heartbeat: game loop, dlopen module loader, and the custom tiered scheduler - 66 schedules across 21 tiers, deliberately not Bevy, from once-per-life init to 60 Hz frames.
L3
Modules · 83 of them
ase-hub · ase-weather · ase-replication · ase-foodchain · ase-perception …
The engine itself - the simulation modules, wired through ase-hub’s star topology with no direct module-to-module coupling. This is where billions of entities get their behaviour.
L4
Plugins · 27 of them
ase-pl-erosion · ase-pl-sky · ase-pl-water · ase-pl-flora …
Hot-loadable shared libraries the kernel discovers, API-version-checks and dlopen-loads. Missing plugins degrade gracefully - the server runs fine without the weather plugin - so games compose exactly the systems they need.
L5
Servers & Clients
ase-server-world · ase-server-replica · ase-client-web
The four-tier servers and the browser client. The World server is the compute process where physics, ecology and weather actually tick; the web client runs becsy with strict 1:1 parity to the C++ backend.
The engine / game boundary2 layers, 1 header
Engine developers own Foundation through Modules; game developers build only L4 plugins and L5 servers/clients, behind the single ase-sdk header. That encapsulation is how one person builds an MMORPG with the engine instead of an engine.
Same ECS, both sides of the wire1:1 parity
EnTT on the C++ server, becsy in the browser - view<A,B>() maps to query, on_construct to added - so SHARED components keep strict 1:1 parity. A SHARED system recomputes deterministically, collapsing ~100 B × 20 Hz of broadcast down to ~4 B × 1 Hz: send the seed, not the result.
Dependencies point only downwardL0 ← L5, one direction
L5 to L0, strictly: a higher layer may reach down, never up or sideways. L0 Foundation (math, types, utils) has zero ECS dependency, so nothing can leak upward into the bedrock the whole simulation computes on.
L2 Kernel: the heartbeat66 schedules · 21 tiers
The kernel runs the game loop, the dlopen module loader and a custom tiered scheduler - 66 named schedules across 21 tiers, from once-per-life init to 60 Hz frames. Deliberately not Bevy; everything above ticks because of it.
L1 Core: ECS plus the DB clientsNeo4j + MongoDB
The EnTT-wrapping ECS, logging, and the Neo4j (relationships, hierarchies) and MongoDB (chunks, state, snapshots) clients - the hot real-time layer plus the data plane’s persistence, kept one level below the modules.
L4 plugins hot-load and degradehot-loadable
Plugins are dlopen-loaded shared libraries with API-version checks; a missing plugin degrades gracefully - the server runs fine without the weather plugin - so a game composes exactly the systems it needs, no more.
L3 is the engine itself83 modules
Eighty-three simulation modules wired through ase-hub’s star topology with no direct module-to-module coupling - this is the layer where billions of entities get their behaviour, and where new causality costs one component field.
L0 Foundation has no ECSpure bedrock
Math, types and utils sit at the bottom and depend on nothing above them - not even the ECS. The bedrock the whole simulation computes on stays free of engine coupling, so nothing can leak downward into it.
The integration layer is main.cppone exception
Systems never call each other - the single sanctioned exception is the HTTP handlers in the server’s main, the integration layer. Everywhere else, logic talks only through components, which is what keeps the whole thing composable.
L5: the servers and clients you shipR3F + becsy
At the top, ase-server-game runs the world and ase-client-web renders it in the browser with React-Three-Fiber over a becsy ECS. Both are L5, built on everything below - the only layers most game devs ever touch.
// Who it’s for

The engine for AI-native MMORPGs. For everything else, there’s still Unreal.

ASE is sharply targeted, and it’s worth being honest about who should build on it today - and who shouldn’t. Complementary by design, not competitive.

For the solo builder of a living world
2 layers, 1 header
If you want to build an LLM-driven MMORPG as one person - design it at a workbench and stand outside it as creator - ASE is built for exactly that. Game devs touch two layers and one header; attach the components you want and the full simulation cascade comes for free wherever you attached something.
For planet-scale simulation beyond games
7+ domains
Because ASE simulates real causal systems rather than rendering scenery, the same substrate targets climate research (CO² and temperature cycles), ecology (invasive species, extinction), urban planning, geology over millions of years, evolution and population dynamics, education and generative art.
For teams who want LLM-native, not bolted-on
A dedicated Reasoning Tier, skills as ECS entities, BYO-AI economics and anti-cheat as a first-class use-case - reasoning is a process plane in the architecture, not a chatbot stapled to the side of a render loop.
Not for your next photoreal FPS
ASE optimizes for simulated meaning and planetary scale, not the highest-fidelity render of a small hand-authored level. That’s a deliberate boundary: for AI-native MMORPGs, build with ASE; for everything else, there’s still Unreal.
Honest about where it stands
closed beta coming
ASE is built in the open and maturing daily. The architecture and vision are thought through, the implementation is underway, and a closed beta is coming. No claims of “finished” - the live build-status ladder above shows every module’s real maturity, from seed to refine.
For the AI-builder crowd
AI-native
If you think in agentic AI, tool-use and skills-as-first-class, ASE applies that philosophy to worlds: skills are ECS entities, reasoning is a federated tier with an edge daemon. Cross-pollination between AI and game-dev, not a genre pivot.
For climate & Earth-system research
climate
CO² and temperature cycles, hydrology, erosion over deep time - the same GIS-layered simulation that runs a game world runs a planet you can study. The output is data, not just scenery.
For ecology & evolution
ecology
Invasive species, extinction cascades, natural selection and population dynamics emerge from entity-per-organism simulation - a lab where the mechanisms are legible because every organism is a first-class entity, not a spawn table.
Not for a hobby platformer
power, not hand-holding
If you want a build-your-first-game-in-30-minutes tutorial, Unity or Godot fit better. ASE trades hand-holding for power - it’s for the people the friendly tools usually hold back, not for the friendly path itself.
Not for a single-player story game
complementary
For a hand-authored single-player narrative, Unreal is the better home. ASE is for living, LLM-driven, persistent worlds - a different problem, solved differently, and deliberately not everyone’s engine.
For urban planning & logistics
cities
Traffic, supply chains, population flow and infrastructure stress model naturally as agents on a GIS-layered world. The same substrate that runs a city in a game runs a city you want to study - every vehicle and resident a first-class entity.
For geology over deep time
deep time
Erosion, sedimentation and tectonic change over millions of simulated years fall out of the same layered-clock architecture that ticks a plant at 0.1 Hz and stone at 0.01 Hz. Time-scale is a schedule tier, not a special mode.
For generative art & installations
a living canvas
A world that runs on real cause-and-effect is a generative instrument: seed it, let the simulation breathe, and the output is emergent rather than authored. The simulation is the content - a canvas that keeps painting itself.
For AI & multi-agent researchers
emergence at scale
Millions of concurrent agents with real perception, memory and reasoning make ASE a testbed for emergent multi-agent dynamics - not a toy grid-world. Behaviour composes from components, so new experiments are new data, not new engines.
For the systems-first metagamer
depth over polish
If you love deeply interlocking systems - the EVE, Dwarf Fortress, Rimworld lineage - ASE is built for that instinct: everything is simulated, everything is connected, and the depth is the point, not a difficulty setting.
For education, as an instrument
teach the mechanism
A simulation whose every effect has a legible cause is a teaching tool: watch a wound index wake a planet, a food chain collapse, a climate band shift - the mechanism is visible because it’s real, not scripted for the lesson.
Not for a weekend game jam
rewards depth
ASE rewards building a world, not shipping a scene by Sunday night. If you want a jam-sized prototype in 48 hours, a lighter engine fits better - ASE is for the long build that a deep, living world actually needs.
What you build · starter kits scaffold a genre - then you build
space-sim
space-sim - a starter kit the engine ships
rpg-quest
rpg-quest - scaffold a genre, then you build
survival-3d
survival-3d - a starter kit the engine ships
evolution-sim
evolution-sim - scaffold a genre, then you build
multiplayer-arena
multiplayer-arena - a starter kit the engine ships
Closed beta · in waves

Request closed-beta access.

We onboard solo developers and small studios in waves - leave your address and we'll send one signal when your wave opens. No spam, no card, no commitment.

A place in line - that's all. This form is a mockup; your address stays in your browser.