evy
a unified-memory, multi-engine, neural-first game engine. selectively forks 16 bevy crates (in evy/forks/); adopts ~20 bevy crates intact from crates.io; replaces 8 with cyber-native primitives. [patch.crates-io] redirects transitive deps on forked crates to our versions. powers cyb and any future cyber-stack game
primary target: Apple Silicon (M-series). portable targets: any UMA platform with NPU + matrix coprocessor (AMD Strix Halo, Qualcomm X Elite, future ARM SoCs). discrete-GPU PC is a degraded-mode target, not a first-class one
0. abstract
evy inverts a decades-old game engine architecture. traditional engines treat the GPU as a remote device behind a copy boundary; evy treats memory as the single shared substrate and compute engines (CPU, AMX, GPU, ANE) as plural peers that operate on it concurrently. presentation is one formally specified protocol (prysm) across 2D and 3D. content is content-addressed particles reached over radio. trust-critical state lives in bbg's polynomial commit. on Apple Silicon, aruminium is the renderer — raster + compute, zero copy, native MTLSharedEvent sync; wgpu is the portable fallback on platforms where Metal is unavailable. intelligence (glia per neuron) is a frame-time-affordable resource
what evy buys from bevy: ~100K LOC of rendering machinery (PBR, post-process, anti-alias, animation, gizmos) that would take a multi-engineer year to reproduce. what evy replaces in bevy: every assumption below the visual stack — storage, scheduler, presentation, scenes, assets, networking, audio. the result is a new engine that uses bevy as its rendering substrate
1. axioms
three axioms generate the engine. change any axiom and the entire system reconfigures
| axiom | symbol | statement |
|---|---|---|
| memory | $\mathcal{M}$ | one physical pool. all engines see the same pages. zero-copy is the default, not an optimization |
| engines | $\mathcal{E}$ | $\{\text{Cpu}, \text{Amx}, \text{Gpu}, \text{Ane}\}$. plural, peer, concurrent. Gpu is one engine, one driver per platform: aruminium on Apple Silicon, wgpu on portable targets |
| presentation | $\mathcal{P}$ | one protocol (prysm) for 2D and 3D. layout is renderer-independent. mir is prysm's 3D-mode renderer |
derived: the engine is a multi-engine dispatch graph $\mathcal{D}$ over a single memory pool, with prysm as the universal presentation layer above it
2. invariants
testable constraints. an implementation is not evy until all pass
| # | invariant | formal statement |
|---|---|---|
| M1 | zero-copy default | shader-visible component data is read by Gpu/Ane without intermediate copy |
| M2 | shared address stability | a shader-visible cell in the unimem backend has stable address for its lifetime; despawn returns to free list with generation bump |
| M3 | unified pool | every buffer used by ≥2 engines lives in a single unimem IOSurface page set |
| E1 | engine concurrency | engines $e_1, e_2$ with disjoint write sets run in parallel within a frame |
| E2 | cross-engine sync | every data dependency across engines is encoded as a DAG edge with explicit sync primitive |
| E3 | no engine monopoly | render graph nodes declare their engine kind; no kind is privileged |
| P1 | prysm conformance | UI passes all 10 invariants of prysm/layout §3.3 (I1–I10) |
| P2 | 2D/3D parity | every prysm atom has identical semantics in 2D and 3D modes |
| C1 | particle identity | every content unit is a particle (hemera hash of content); entity identity is the particle |
| C2 | signal provability | every state transition on a bbg-backed component produces a zheng proof or is rejected |
| N1 | content addressing | asset references use radio://<particle> scheme; file paths are an authoring-only convenience |
| N2 | offline tolerance | every networked operation degrades to local cache; UI never blocks on network |
| R1 | budget honesty | per-frame compute budget is allocated explicitly across engines; overrun is logged, not silent |
3. hardware target
evy supports mobile, desktop, console, and XR out of the box. capability varies by platform; the runtime detects what each device offers and the dispatch scheduler routes work to available engines, degrading features that require absent silicon. four target tiers
3.1 first-class (full stack)
every honeycrisp engine available; every feature enabled
| platform | UMA | bandwidth | NPU | matrix | notes |
|---|---|---|---|---|---|
| Apple M1 Pro/Max desktop/laptop | yes | 200/400 GB/s | ANE 11 TOPS | AMX | reference platform |
| Apple M2/M3/M4 desktop/laptop | yes | 100–800 GB/s | ANE 16–38 TOPS | AMX / SME on M4 | first-class |
macOS distribution is direct (DMG, Homebrew, .app) — no App Store dependency. Apple mobile (iOS/iPadOS) and Vision Pro are not targets (§3.6)
3.2 portable (degraded, supported)
partial engine availability; features that require missing silicon disable
| platform | available engines | unavailable | degradation |
|---|---|---|---|
| AMD Strix Halo (Windows/Linux) | Cpu (+AVX-512), Gpu/wgpu(Vulkan), Ane (via XDNA driver, TBD) | AMX, aruminium path | matrix work routes to Cpu/AVX-512; Gpu only via wgpu |
| Qualcomm X Elite (Windows ARM) | Cpu (+SME), Gpu/wgpu(D3D12), Ane (via Hexagon NN, TBD) | AMX, aruminium | similar to Strix Halo, ARM CPU |
| Snapdragon 8 Gen 2+ Android | Cpu (+NEON), Gpu/wgpu(Vulkan), Ane (NNAPI/Hexagon NN) | AMX, aruminium, IOSurface | shared memory via AHardwareBuffer; ANE via NNAPI |
| mid-tier Android (no flagship NPU) | Cpu (+NEON), Gpu/wgpu(Vulkan) | AMX, aruminium, Ane, IOSurface | neural materials disabled or fall back to GPU; per-NPC inference reduced count |
| PS5 / Steam Deck APU | Cpu, Gpu/wgpu | Ane, AMX | neural features disabled |
| discrete-GPU PC (Intel/AMD CPU + NVIDIA/AMD GPU) | Cpu, Gpu/wgpu | Ane, AMX, IOSurface | non-UMA: pays staging-buffer cost; neural features disabled |
degraded platforms still run the same game content. the engine reports PlatformCapabilities at startup; systems that require absent engines skip, fall back, or fail loudly per FallbackPolicy declared by the system author. content authors target the capability set, not specific platforms
3.3 capability matrix
quick reference for what each platform tier offers
| capability | macOS M-series | Android flagship | Android mid | Windows ARM | Windows x86 desktop | console APU | discrete PC |
|---|---|---|---|---|---|---|---|
| unimem zero-copy | ✓ | partial (AHardwareBuffer) | — | — | — | — | — |
| AMX matrix coprocessor | ✓ | — | — | — | — | — | — |
| ANE neural engine | ✓ | NNAPI | — | NNAPI | NNAPI (NPU SKUs) | — | — |
| Gpu driver | aruminium (raster + compute, hand MSL) | wgpu (Vulkan) | wgpu (Vulkan) | wgpu (D3D12) | wgpu (D3D12) | wgpu | wgpu |
| radio P2P | ✓ | ✓ | ✓ | ✓ | ✓ | restricted | ✓ |
| neural materials | ✓ | ✓ (slower) | fallback to baked | — | — | — | — |
| generative cache | ✓ | ✓ (slower) | disabled | — | — | — | — |
| per-NPC inference at scale | thousands | dozens | tens (CPU) | dozens | dozens | — | — |
3.4 runtime capability detection
at startup, evy probes the platform and constructs a PlatformCapabilities resource:
systems and dispatch nodes register fallback policy:
a neural material with FallbackPolicy::DegradeTo(Cpu) runs on CPU with reduced batch size when ANE is absent. one with FallbackPolicy::Skip simply doesn't render its neural component, falling through to a baked texture. one with FallbackPolicy::Required refuses to load on platforms without ANE — useful for AI-driven game logic that has no acceptable degradation
3.5 thermal and power policy
mobile targets and laptops on battery have thermal/power limits. evy respects these via:
tick_rate_hzfromPlatformCapabilities— gameplay state cadence (BBG commits) drops on battery- φ*-budget allocator scales per-particle inference budget by current thermal headroom
- ANE/NPU prefers idle-time burst over sustained dispatch (NPU power efficiency wins when intermittent)
- Android Activity lifecycle: engine checkpoints state on
onPause, restores ononResume. checkpoint format = BBG root + ephemeral ShardStore snapshot. background-killed processes restore from checkpoint on next launch
3.6 non-targets
- Apple mobile (iOS / iPadOS) — distribution requires App Store; deployment policy and review process are unacceptable. macOS desktop direct-distribution path is the Apple-side target
- Apple Vision Pro — same App Store constraint as iOS; deferred indefinitely
- WebGPU browser deployment — possible but unimem doesn't survive translation; deferred
- single-threaded environments — the engine assumes parallel engine dispatch
- discrete-GPU desktop as a first-class target — supported (degraded mode per §3.2) but architectural choices favor UMA platforms
4. memory model (axiom $\mathcal{M}$)
4.1 the pool
all buffers shared between ≥2 engines are allocated via unimem primitives:
| primitive | role | source |
|---|---|---|
unimem::Block |
IOSurface-backed pinned page. stable address for lifetime | honeycrisp/unimem/src/block.rs |
unimem::Grid |
slot-pool of typed cells. stable address per cell | honeycrisp/unimem/src/grid.rs |
unimem::Tape |
bump allocator, ~1ns take, frame-reset | honeycrisp/unimem/src/tape.rs |
cells in a Grid<T> are simultaneously:
- a
&Tin Rust - a slot in an
MTLBufferfor aruminium raster + compute (Apple Silicon) - an input surface for rane ANE inference
- a tile source for acpu AMX/NEON ops
no copy, no upload, no extract. one IOSurface, many views
4.2 the storage interface
evy adopts bbg's ShardStore trait verbatim (bbg/specs/storage.md). there is no separate "ECS storage." components live in shards. the same trait serves authenticated cybergraph state, ephemeral render buffers, and everything between
quoting bbg's spec: "the polynomial commitment provides authentication. the local data structure provides access. they are INDEPENDENT — the store doesn't know about polynomials, the polynomial doesn't know about storage." this separation is the keystone. evy inherits it
4.3 backends
five backend implementations of ShardStore, selected per-shard by hardware capability + access pattern + tier policy:
| backend | implementation | optimal for | latency |
|---|---|---|---|
| memory | HashMap + bitvec |
small shards (≤64 GB) | 50 ns read |
| unimem | unimem IOSurface-pinned Blocks | Apple Silicon hot path; zero-copy CPU/AMX/GPU/ANE | ~1 ns alloc |
| ssd | fjall LSM-tree |
shards exceeding RAM | 20 μs read |
| hdd | redb B-tree MVCC |
full history, cold | sequential 200 MB/s |
| network | NetworkStore trait (injected by radio) |
content not held locally; DAS sampling | seconds |
backend selection is per-shard, not per-component-class. on Apple Silicon, a component touched by GPU defaults to unimem; on non-Apple-Silicon, the same component defaults to memory with explicit upload at access. the component definition does not change. there are no storage classes — only backends and dimensions
4.4 the canonical state schema
evy state partitions into 13 namespaces: 10 public dimensions of BBG_poly + 2 private polynomial commitments + 1 ephemeral domain. components register into one
| namespace | source | committed | role |
|---|---|---|---|
| particles | BBG_poly dim 0 | yes | content nodes, energy, φ* |
| axons_out | BBG_poly dim 1 | yes | outgoing edge index |
| axons_in | BBG_poly dim 2 | yes | incoming edge index |
| neurons | BBG_poly dim 3 | yes | agent state: focus, karma, stake |
| locations | BBG_poly dim 4 | yes | spatial proofs |
| coins | BBG_poly dim 5 | yes | fungible token denominations |
| cards | BBG_poly dim 6 | yes | non-fungible knowledge assets, names |
| files | BBG_poly dim 7 | yes | content availability commitments |
| time | BBG_poly dim 8 | yes | temporal index |
| signals | BBG_poly dim 9 | yes | finalization log |
| A(x) | commitment polynomial | yes (private) | individual cyberlinks (record-level) |
| N(x) | nullifier polynomial | yes (private) | spent-record markers |
| ephemeral | none | no | local-only state: Transform, animation, render scratch, VFX |
component registration declares one namespace. ephemeral is the default for engine-internal components. authenticated namespaces (everything except ephemeral) participate in BBG_root and emit zheng proofs at tick boundaries (§6.2)
4.5 component → namespace mapping
| component | namespace | backend on M-series |
|---|---|---|
| Transform | ephemeral | unimem (GPU reads it) |
| AnimationPhase | ephemeral | memory (CPU only) |
| Currency balance | coins | unimem (AMX Poseidon2) |
| OwnedItem | cards | unimem |
| HistoricalLink | time | hdd (cold replay) |
| OpenAsset | files | network (radio fetch) |
| NeuronProfile | neurons | unimem (GPU render) |
| IndividualCyberlink | A(x) | unimem (private record) |
| SpentNullifier | N(x) | unimem (double-spend check) |
| VFXLifetime | ephemeral | memory |
| RenderScratch | ephemeral | unimem (Gpu/Aruminium kernel target) |
plain english: pick the namespace your data semantically belongs to (or ephemeral); the backend is resolved from hardware + tier policy. no class hierarchy, no storage taxonomy beyond what bbg already defines
4.6 stable addresses come from the backend
bevy_ecs's Table storage uses swap_remove on archetype change (storage/table/mod.rs:214), which moves component bytes. this is incompatible with GPU buffer descriptors holding addresses
resolution: backend choice. the unimem backend implements ShardStore over slot-pooled IOSurface cells where addresses do not move. the memory backend implements ShardStore over BlobVec with swap-remove semantics. components do not pick a class — they pick a backend (or accept auto-selection), and the backend's allocator determines address stability
cells in the unimem backend carry a generation tag (index: u32, gen: u16). cell reuse bumps the generation. GPU buffers holding stale (index, gen) pairs fail validation on read. this prevents the swap-remove hazard without sacrificing GPU access stability
cost: 6 bytes per shader-visible cell. one extra indirection per query (L1 cache hit, single-digit ns)
4.7 IOSurface lifetimes
per unimem design: IOSurface is locked at creation, unlocked at drop. cells within an IOSurface-backed shard are addressable for the shard's lifetime. cross-process IOSurface sharing works (zero-copy IPC) but is out of v1 scope. cross-engine sharing within process is the load-bearing case
4.8 tier routing
cyb/soma-equivalent policy layer (deferred to v2) sets routing: which shards stay hot (unimem/memory), which demote to ssd, which archive to hdd. evy executes the mechanism; focus (φ*) IS the cache priority. high focus = stay hot; low focus = migrate cold. for v1, default policy: ephemeral + recently-touched authenticated = hot; rest = ssd
5. engine model (axiom $\mathcal{E}$)
5.1 the four engines
an engine is a distinct dispatch context the scheduler must track, not distinct silicon. NEON is part of Cpu because any thread issues NEON instructions in the same stream as scalar, sharing the SIMD register file (v0–v31). AMX is its own engine because per-thread AmxCtx must be initialized before AMX instructions can issue. ANE is its own engine because dispatch goes through rane's MIL bytecode queue, not through the issuing thread. Gpu is one engine with one driver per platform: aruminium (raster + compute, hand-written MSL, zero copy) on Apple Silicon; wgpu (cross-vendor Vulkan/D3D12) on portable targets
| engine | hardware | dispatch | workloads |
|---|---|---|---|
| Cpu | P-cores + E-cores. scalar + NEON SIMD share register file | direct call; any thread | ECS systems, layout, input, audio DSP (NEON via acpu::vector), blake3 hashing for BAO, FFT, vector math, crypto SHA/AES/PMULL (via acpu::crypto), small inference below ANE dispatch threshold |
| Amx | Apple AMX coprocessor (per-cluster). M4 introduces SME as future replacement | inline asm via acpu; per-thread AmxCtx required |
transform propagation, skinning palettes, eigensolvers (LOBPCG), Poseidon2 hashing, SGEMM ≥32×32, batched matrix math |
| Gpu | Apple GPU (on macOS) or vendor GPU (elsewhere) | aruminium on Apple Silicon — its own MTLDevice + MTLCommandQueue, raster + compute, zero copy via unimem. wgpu elsewhere — Vulkan/D3D12 fallback |
raster, post, custom MSL compute kernels, mir tier passes, neural material vertex transforms |
| Ane | Apple Neural Engine | rane MIL bytecode dispatch queue | batched neural inference (≥1M params), neural material per-pixel feature maps, NeRF eval, diffusion, per-NPC behavior models |
each engine has its own dispatch primitive and (where applicable) its own worker context. engines share memory but not state
5.2 one renderer per platform
within engine Gpu, exactly one driver is active per platform — they do not coexist:
| platform | driver | what |
|---|---|---|
| Apple Silicon (macOS) | aruminium | hand-written MSL, raster + compute, zero copy via unimem, native MTLSharedEvent cross-engine sync |
| portable (Android, Windows, Linux, console) | wgpu | cross-vendor Vulkan/D3D12; no zero-copy guarantee |
aruminium is the renderer on Apple Silicon because the wgpu abstraction taxes ~9–13 ms of frame budget for the same Metal hardware (per-draw-call CPU overhead 5–8 µs vs 1–2 µs; mesh upload BW 25 GB/s vs 70–100 GB/s direct IOSurface; lost MTLSharedEvent cross-engine sync; WGSL→MSL translation cost). on a 16.6 ms frame, that's the difference between 60 FPS and 30. on Apple Silicon evy is Apple-first; portability overhead is paid only where Metal isn't available
wgpu does not coexist with aruminium on Apple Silicon. an earlier draft of this spec proposed sharing MTLDevice between the two drivers; that was reverted (commit 48f1bc8 in honeycrisp/aruminium). on every platform evy ships, exactly one Gpu driver is active
5.3 engine routing rules
a workload routes to an engine by these defaults:
| workload | engine | reason |
|---|---|---|
| batched matrix multiply (≥32×32) | Amx | tile-shaped, no GPU dispatch overhead |
| small dense vector ops (length < 1024) | Cpu/NEON | dispatch overhead dominates |
| dense vector ops (≥ 1024) | Amx or Gpu compute | depending on shape |
| raster pass | Gpu (aruminium on Apple, wgpu elsewhere) | what GPUs do |
| compute over shared memory | Gpu (aruminium on Apple, wgpu compute on others) | zero translation on Apple Silicon |
| neural inference (≥ 1M params) | Ane | 50× more efficient per watt than Gpu |
| neural inference (tiny, < 100K params) | Cpu or Gpu | dispatch overhead matters |
| graph eigensolve (LOBPCG) | Amx | repeated mat-vec, AMX shape |
| Poseidon2 hashing | Amx (via acpu field jets) | matrix-shaped permutation |
| BAO content verification | Cpu (blake3 via acpu) | I/O bound |
routing is per-node in the dispatch graph, not per-system. one logical Bevy system can spawn work on multiple engines
6. dispatch model (the unified DAG)
6.1 one DAG, two execution semantics
evy's dispatch DAG and bbg's signal DAG are the same DAG. they share infrastructure (ShardStore reads/writes, scheduler, topology). they differ in execution semantics: each node declares a commit policy. some nodes' writes trigger BBG commitment (polynomial recommit + zheng proof + radio gossip). others stay ephemeral and never touch the commit path
bevy_render's existing RenderGraphNodes map to DispatchNode with engine() == Engine::Gpu(Wgpu) and commit_policy() == None. mir's tier passes implement Engine::Gpu(Aruminium) with None. glia per-particle inferences implement Engine::Ane. AMX-batched transform propagation implements Engine::Amx. a gameplay signal handler (currency transfer, cyberlink creation, ownership change) implements CommitPolicy::BbgDimension(d) or BbgPrivate
the render graph is the subset of the dispatch DAG where commit_policy() == None. it is not a separate construct
6.2 the scheduler
per frame, the scheduler:
- collects all enabled
DispatchNodes (render + gameplay) - topo-sorts by
ShardRefread/write dependencies - batches by engine: Wgpu nodes record into one command buffer; Aruminium nodes dispatch to its queue; Ane nodes submit to rane queue; Amx nodes dispatch on pinned threads
- inserts cross-engine sync primitives at DAG edges that cross engine kinds (§6.3)
- submits per-engine work in parallel
- at tick boundary (subset of frames; e.g. every 6th frame at 60Hz → 10Hz tick): collects writes from nodes with
CommitPolicy::BbgDimension/BbgPrivate, callsShardStore::commit()on affected shards, recomputes BBG_root, generates zheng proof, gossips via radio - awaits cross-engine sync barriers before next frame
frame ≠ tick. frame is render swap cadence (60–120Hz). tick is gameplay state cadence (10–30Hz). render nodes run per frame; BBG-committing nodes run per tick. one scheduler, two cadences
6.3 cross-engine synchronization
Apple Silicon has no universal barrier. each engine pair has its own sync primitive
| from → to | mechanism |
|---|---|
| Cpu → Gpu | MTLCommandBuffer enqueue, fence |
| Gpu → Cpu | MTLCommandBuffer completed handler or waitUntilCompleted |
| Ane → Cpu | IOSurface lock/unlock semantics |
| Cpu → Ane | rane program input ready |
| Amx → any | thread-local fence (AMX context is per-thread) |
| Gpu → Ane | uncommon; routes via Cpu fence today |
scheduler encodes all seven pairs. nodes whose engine pair has no direct sync route through Cpu
6.4 ExtractSchedule collapses
bevy's ExtractSchedule copies MainWorld components into RenderWorld each frame. for unimem-backed shards, the bytes are already shared between worlds via IOSurface. extract becomes a no-op for these shards. for memory-backed shards used across worlds, the original extract path remains valid. result: extract cost scales with the number of shader-visible-but-not-unimem-backed shards, which v1 expects to be near zero
6.5 frame budget
a 60Hz frame is 16.6ms. allocation across engines, default policy:
| engine | typical share | notes |
|---|---|---|
| Cpu | 4 ms | ECS, layout, input, scripting, NEON DSP |
| Amx | 3 ms | transform, skinning, physics matrices, Poseidon2 at tick |
| Gpu | 8 ms | raster + post + compute kernels |
| Ane | full 16.6 ms | inference is async to other engines; rate-limited by ANE bandwidth |
engines run concurrently. the 31.6ms theoretical sum compresses to 16.6ms wall time because they execute on independent silicon. Ane runs without contending with Gpu — that is the structural advantage evy extracts from Apple Silicon
at tick boundary (every Nth frame), an additional commit cost: ~50μs for BBG polynomial recommit + proof generation. amortized across frames it is invisible; if a single tick batches many signals it can spike. tick rate is tunable per game (10–30Hz typical)
7. presentation model (axiom $\mathcal{P}$)
7.1 prysm is the UI engine
prysm is a formal layout protocol with 14 theorems formalized in Lean 4. evy adopts prysm directly. bevy_ui is replaced
prysm provides:
- layout algorithm: pure function (element tree × viewport → coordinates). O(n), single-pass, deterministic, ≤2ms for 10K organelles
- atoms: glass, text, ion, saber, images
- molecules: 22 composed widgets (button, hud, input, content, neuron-card, ...)
- cells: 3 regional compositions (oracle-cell, sphere-cell, ...)
- aips: 10 full-screen applications
- emotion: computed color signal layer, 4 evaluation rules, formal thresholds, fallback policy
- responsive: fold protocol with optimal conformation selection (theorem T6)
- motion: one duration, one curve, single-pass
- semantic: accessibility layer with formal
Semanticrole tagging
every prysm spec includes a Bevy-shaped ECS section (Components, Systems). implementation is mechanical transcription of those sections into Rust
7.2 2D and 3D as modes
prysm spans 2D and 3D in one protocol (prysm/layout §11). atoms have identical semantics in both modes; what differs is the renderer
| mode | renderer | use |
|---|---|---|
| 2D | bevy-mesh quad batcher + cosmic-text + sprite atlas | HUD, menus, content surfaces, traditional UI |
| 3D | mir (Bevy mesh + aruminium tier compute) | spatial cybergraph navigation, T0–T∞ tiers, neural radiance |
mir is not a separate UI system. mir is prysm's 3D-mode renderer. the same glass atom in 2D draws a translucent quad; in 3D, the same atom occupies depth $s_d$ and z-position $p_z$ driven by gravity. one protocol, two drawers
7.3 prysm crate layout
| crate | role | LOC estimate |
|---|---|---|
evy_prysm_core |
Π protocol, Φ sizing, K containers, layout function | ~2K |
evy_prysm_atoms |
5 atom implementations (glass, text, ion, saber, images) | ~1.5K |
evy_prysm_molecules |
22 molecule bundles | ~3K |
evy_prysm_cells |
3 cells + 10 aip scaffolds | ~2K |
evy_prysm_emotion |
emotion function with 4 evaluation rules | ~500 |
evy_prysm_motion |
motion system | ~300 |
evy_prysm_2d |
2D draw backend (quads, text, images via bevy mesh) | ~1K |
evy_prysm_3d |
3D draw backend (mir tier integration) | ~1K |
total: ~11K LOC. implementation work is bounded by the spec, not by design
8. content model
8.1 particle = entity
entity identity IS its particle. spawning a new entity for content that is already a particle returns the existing entity (idempotent). entities without explicit content get an anonymous local particle (hemera hash of session UUID + spawn counter)
implications:
- save/load by particle is structural:
World::checkpoint() → root_particle,World::restore(root_particle) - cross-machine entity reference works without an entity mapper
- duplicate spawn detection is automatic
- entity ID stability across sessions and machines
8.2 component = cyberlink
a component instance is conceptually a cyberlink ask(ν, p, q, τ, a, v, t):
- ν: neuron — who set this component
- p: from-particle — the entity
- q: to-particle — the component value
- τ: type — dialect for this component
- a: stake — 0 for ephemeral components
- v: valence — +1 default
- t: time — tick
Bbg-backed components store the full cyberlink record. Grid and Table components store only the value; the cyberlink metadata is implicit
8.3 .cyb particles as scene format
bevy_scene is deleted. scenes are .cyb particles containing a section of cyberlinks. loading a scene = fetching the particle and replaying its cyberlinks as ECS commands. .cyb format is fixed (TOML frontmatter + ~~~name separators) and supports binary asset sections in-line
8.4 assets are particles
bevy_asset is replaced. asset references use radio://<particle> URIs. the radio adapter (see §9) resolves the particle → bytes via local cache, peers, or fallback relay. .cyb is the universal container; loaders inspect frontmatter and dispatch to type-specific sub-loaders (image, mesh, model, glTF as a section type)
| asset kind | source | loader |
|---|---|---|
| texture | radio://particle | evy_particle_loader::image |
| mesh | radio://particle | evy_particle_loader::mesh |
| neural model | radio://particle | evy_particle_loader::model (yields glia::Model) |
| audio clip | radio://particle | evy_particle_loader::audio |
| scene | radio://particle | evy_particle_loader::scene (replays cyberlinks) |
| font | radio://particle | evy_particle_loader::font |
hot-reload happens when a reference resolves to a new particle: gossip notifies subscribers, asset server invalidates handles
9. networking model
9.1 radio as content + replication
radio (built on iroh: QUIC + BAO + gossip + Willow) provides content addressing, streaming verification, P2P discovery, and CRDT-style replication. evy consumes radio as an out-of-engine service
architecture:
[ Bevy app, single thread, deterministic ]
│
│ channel handles
▼
[ evy_radio adapter, owned tokio runtime ]
│
│ iroh API
▼
[ iroh endpoint: blobs, gossip, docs, willow ]
│
│ QUIC
▼
[ peer mesh ]
evy_radio runs its own tokio runtime in a dedicated thread. Bevy holds Res<RadioClient> which is a channel handle. async iroh operations are submitted as messages; completions arrive on a return channel polled at frame start. this isolates iroh's select!-heavy async code from Bevy's executor (compliance with established select! cancel-safety lessons)
9.2 what radio handles
| concern | radio primitive |
|---|---|
| asset fetch | iroh-blobs by particle, with BAO incremental verify |
| asset hot-reload | gossip notification on particle-reference change |
| state replication | iroh-gossip for signals; iroh-docs for derived CRDT state |
| peer discovery | iroh-relay + DERP |
| late-join state sync | fetch state root + missing particles |
| chat / events with anti-spam | signals with stake (cost = stake) |
9.3 multiplayer model
no client/server distinction. every player is an iroh node. world canonicality is determined by foculus (collective focus theorem) — the φ* distribution over signals converges to a stable attractor that defines consensus. signals from any neuron propagate via gossip; each node validates and applies independently
cheating is structurally detectable: invalid signals fail verification on receipt; deviating state diverges from the consensus root. recovery is local — out-of-consensus nodes resync from the canonical root
9.4 offline tolerance
every networked operation has a local-cache fallback. fetch returns from cache if available; gossip subscriptions buffer offline and replay on reconnect; signals queue and submit on reconnect. UI never blocks waiting for network. this is invariant N2
10. rendering model
10.1 hybrid raster + inference
a frame composes raster, compute, and neural paths into the same framebuffer. on Apple Silicon all three share one Metal device (aruminium); on portable targets, raster + compute go through wgpu and neural is unavailable
| path | Apple Silicon | portable |
|---|---|---|
| raster | aruminium (hand MSL, native MTLBuffer + MTLTexture from unimem) | wgpu (WGSL/naga, copy-staged) |
| compute | aruminium (custom MSL kernels, same queue as raster) | wgpu compute (degraded; no zero copy) |
| neural | ANE via rane (zero-copy IOSurface inputs) | NNAPI on Android, otherwise none |
on Apple Silicon, all three paths share buffers via unimem. raster reads positions from a Grid; compute writes positions into the same Grid; neural reads features from a Grid that mir's compute populated. one memory, three pipelines, one device — no cross-driver sync. on portable targets the model degrades per §3.2: same pipelines, no zero copy, fewer engines
10.2 neural materials
a NeuralMaterial is a bevy Material trait impl that, instead of a shader-only pipeline, takes:
- standard inputs (UV, view, normal, light)
- a
Modelhandle (glia model loaded from a .model particle) - graph context inputs (nearby cyberlinks, cyberank, current path)
and produces radiance via a glia forward pass on ANE. mesh raster (wgpu) handles vertex transform; per-pixel evaluation routes to a precomputed feature map produced by an ANE pass earlier in the frame DAG
constraint: ANE inferences batch per draw call, not per pixel. one inference produces a feature map that the raster shader samples. the feature map is a Grid texture. ~100μs ANE dispatch overhead is amortized across millions of pixels
10.3 φ*-driven render budget
tru produces φ*, the focus distribution over particles. evy consumes φ* as a render budget allocator:
- particles in top focus quantile: full neural material + tier-3 detail + per-frame inference
- mid quantile: cached neural material (inference every N frames) + tier-2 detail
- low quantile: impostor billboard + tier-1 detail
- edge-of-frustum: label-only atom
implementation: a PhiBudget resource holds per-particle render policy. systems consult it before scheduling work. evy_phi_budget crate
10.4 generative cache
an asset that resolves to "particle exists but has no bytes" triggers generation:
| missing asset | generator | engine |
|---|---|---|
| texture | diffusion model on Ane + Gpu | Ane primary, Gpu sampling steps |
| mesh | shape generator (TBD) | Gpu |
| audio | sound model | Ane |
| 3D environment | neural radiance from cyberlink context | Ane + Gpu |
generated assets are published back to radio as new particles. peers exploring the same context retrieve the cached generation. evy_generative_cache crate
10.5 speculative graph inference
unexplored regions of the cybergraph get LLM-speculated cyberlinks, signed with low stake. two players exploring the same region see identical speculations (deterministic from context). canonical content from neurons overrides speculations. unresolved game-design question: what does a player who explored a speculation later see when canonical content arrives (open question OQ-6)
11. what bevy provides — adopted intact
these crates are used unmodified from crates.io. ~52K LOC of substrate
| crate | role |
|---|---|
| bevy_app | App, Plugin, SubApp, schedules |
| bevy_winit | macOS event loop, window event integration |
| bevy_window | window component model |
| bevy_input | OS input event translation |
| bevy_gilrs | gamepad |
| bevy_state | states, transitions |
| bevy_time | time, timer, fixed timestep |
| bevy_log | tracing-based logging |
| bevy_math | NEON wrapper added below; primitives intact |
| bevy_color | color spaces |
| bevy_reflect | type reflection (extended via wrapper for dialects) |
| bevy_utils, bevy_macro_utils, bevy_derive, bevy_ptr, bevy_platform | substrate utilities |
| bevy_picking | ray picking |
| bevy_camera | camera component model |
| bevy_light | light component model |
| bevy_text | cosmic-text glyph layout (used by prysm as font shaper) |
| bevy_input_focus | OS focus integration (prysm uses its own NavigationOrder above this) |
12. what bevy provides — adopted with modification
these crates are forked. upstream tracking is loose
| crate | LOC | level | what changes |
|---|---|---|---|
| bevy_ecs | 104K | EXTEND (+~1.5K LOC) | adds StorageType::Grid backed by unimem; scheduler gains Engine routing metadata |
| bevy_render | 26K | REPLACE-internal | RenderGraph generalized to multi-engine; ExtractSchedule collapses for Grid components; shared MTLDevice between wgpu and aruminium |
| bevy_pbr | 36K | REWRITE | neural material support; MSL shader path alongside WGSL; clustered-light compute via aruminium |
| bevy_core_pipeline | 7K | REWRITE | post-process compute via aruminium; shared-memory textures |
| bevy_anti_alias | 3K | REWRITE | MSL TAA/SMAA/FXAA over shared textures |
| bevy_post_process | 4K | REWRITE | DOF/chromatic/motion blur via aruminium compute |
| bevy_animation | 4.5K | EXTEND | AMX skinning palette mul; NEON curve eval |
| bevy_transform | 2.5K | EXTEND | AMX batched propagation |
| bevy_mesh | 9K | REWRITE | MeshAllocator backed by Grid |
| bevy_image | 6K | REWRITE | image data on IOSurface; decoders write into IOSurface pages |
| bevy_tasks | 3.7K | EXTEND | AmxTaskPool (pinned threads with AmxCtx); AneTaskPool |
| bevy_diagnostic | 1.3K | EXTEND | PMU-backed diagnostic via acpu probe |
| bevy_gizmos, bevy_gizmos_render | 7.7K | REWRITE | MSL shaders, shared-memory vertex buffer |
| bevy_sprite, bevy_sprite_render | 7.2K | REWRITE | shared-memory atlas |
13. what bevy provides — replaced or deleted
| crate | LOC | action | replacement |
|---|---|---|---|
| bevy_ui | 12K | DELETE | prysm |
| bevy_ui_widgets | 2.4K | DELETE | prysm molecules |
| bevy_feathers | 3.3K | DELETE | prysm emotion |
| bevy_ui_render | 5.5K | REPURPOSE | becomes prysm 2D quad/text/image batcher |
| bevy_scene | 4.3K | DELETE | .cyb particles via radio |
| bevy_asset | 21K | REPLACE | evy_radio_asset (radio:// scheme) |
| bevy_gltf | 4.7K | REPLACE | evy_particle_loader (glTF as a .cyb section type) |
| bevy_audio | 1.9K | REPLACE | evy_audio (acpu NEON DSP + Ane spatial HRTF) |
14. new crates — no bevy equivalent
these crates do not exist in bevy. they are the substance of evy
| crate | role | est | status |
|---|---|---|---|
| evy_engine_core | assembly, Engine::builder() wires every subsystem |
~1K | ✓ landed (340 LOC, 9 tests + end-to-end smoke) |
| evy_platform_caps | runtime probe (engines, NPU, thermal class) + FallbackPolicy | ~400 | ✓ landed (280 LOC, 6 tests) |
| evy_ecs_storage | typed component adapter over bbg::ShardStore |
~1.5K | ✓ landed (600 LOC, 25 tests) |
| evy_engine_tasks | AmxTaskPool + AneTaskPool (Apple Silicon; stub elsewhere) | — | ✓ landed (280 LOC, 7 tests) — spec deviation: was bevy_tasks EXTEND in §12, became separate crate |
| evy_engine_dispatch | DispatchNode trait + scheduler + commit-policy + engine pool routing | ~2.5K | ✓ session 1+2 landed (520 LOC, 18 tests). sessions 3-4 (parallel layer + cross-engine sync) blocked on aruminium step 3 |
| evy_prysm_core | Π + Φ + K + fold + motion + emotion (core protocol, no atoms) | ~2K | ✓ landed (1500 LOC, 47 tests) |
| evy_radio | channel bridge to iroh daemon | ~2K | ✓ session 1 landed (330 LOC, 6 tests) with stub daemon. session 2 = real iroh; session 3 = radio:// AssetSource |
| evy_diagnostic | wall + PMU measurement + Diagnostic accumulator | — | ✓ landed (370 LOC, 11 tests) — extends spec; was implicit |
| evy_dialect | dialects + registry | ~800 | ✓ landed (300 LOC, 14 tests) |
| evy_nnapi_runtime | Android NPU dispatch parallel to rane; glia .model → NNAPI translation | ~2K | pending Android bring-up |
| evy_render_compute | aruminium compute passes as DispatchNodes | ~1K | blocked on aruminium step 3 |
| evy_neural_material | model-driven Material trait + glia bridge | ~1.5K | blocked on steps 3+4 |
| evy_phi_budget | φ*-driven per-particle render allocator | ~500 | blocked on step 8 (glia) |
| evy_generative_cache | diffusion-on-miss for textures/meshes | ~2K | blocked on step 8 |
| evy_glia_runtime | per-particle Ane inference dispatcher | ~1.5K | blocked on steps 3+4 |
| evy_mir_nodes | mir tier passes as DispatchNodes | ~3K (mir core lives in mir repo) | blocked on step 3 |
| evy_particle_loader | .cyb particle loaders (image, mesh, model, scene, audio, font) | ~2K | needs step 11.2 |
| evy_radio_asset | ShardStore network-backend impl serving the radio:// scheme | ~500 | needs step 11.2 |
| evy_audio | acpu NEON DSP + Ane spatial audio | ~2K | replaces bevy_audio |
| evy_prysm_* (atoms, molecules, cells, aips) | prysm implementation above core (§7.3) | ~11K | atoms blocked on render path (step 5+); molecules/cells/aips depend on atoms |
total landed: 9 crates, ~4.5K LOC, 143 tests. total planned new: ~33K LOC.
15. crate inventory roll-up
| category | crates | LOC |
|---|---|---|
| bevy adopted intact | 19 | ~52K |
| bevy forked (EXTEND or REWRITE) | 14 | ~221K |
| bevy deleted | 4 | ~22K |
| bevy replaced | 4 | ~32K |
| new (evy) | 24 planned | ~33K |
| total bevy code involved | 52 | ~327K |
| total evy new code | 24 planned, 9 landed | ~33K planned, 4.5K landed |
ratio: ~10× more bevy code is involved than evy new code. the engine is mostly bevy with surgical replacements at load-bearing seams. that is what makes the project feasible
landed crates have 143 tests passing across 9 crates as of 2026-05-21; end-to-end smoke test in evy_engine_core exercises every subsystem
16. dependencies on soft3 components
| component | maturity | engine role |
|---|---|---|
| unimem | working | memory foundation (axiom $\mathcal{M}$) |
| acpu | working | Amx + NEON dispatch |
| aruminium | working | Gpu compute path |
| rane | working | Ane dispatch |
| hemera | working | particle hashing (entity identity is its particle) |
| bbg | working | ShardStore trait + 12 namespaces — the storage substrate for ALL components |
| cybergraph | working | signal chain + VDF |
| nox | working | provable scripting compile target |
| mir | partial | 3D-mode prysm renderer |
| glia | partial | neural material + per-NPC inference |
| prysm | spec done, implementation partial | UI engine |
| radio | working | networking |
| tru | partial | φ* generation |
| trident | working | .tri → .nox compile |
| zheng | working | proof gen/verify |
| mudra | stub | crypto (defer to v2) |
| foculus | spec | consensus (defer to v2) |
v1 ships with: working soft3 components + spec-done prysm. partial components (mir, glia, tru) ship in their current form; defer foculus + mudra to v2
17. open questions
honest gaps that need resolution before or during implementation
| # | question | impact |
|---|---|---|
| OQ-1 | unimem backend allocation policy: static per-shard cap vs growable via chained IOSurfaces; rebind GPU descriptors on growth | affects bundle insertion failure mode |
| OQ-2 | cross-world ShardStore sharing: how do RenderApp + MainApp reference the same shard without violating bevy's world isolation; lifetime + Arc semantics |
architectural, blocks step 3 of attack order |
| OQ-3 | per-frame inference batching: glia API needs to support batched per-particle eval, not arbitrary .model | blocks neural material payoff |
| OQ-4 | bbg verification cost vs framerate: 10–50μs per particle is too slow at 120Hz; cache+invalidate strategy needed; ties to tick boundary policy (OQ-11) | affects bbg storage UX |
| OQ-5 | deterministic neural eval across M1/M2/M3/M4 ANE: float differences break consensus when inference drives state | gameplay-impacting inference outputs need quantization rule |
| OQ-6 | speculation horizon: when canonical content arrives after a player saw speculation, what does the player see | game-design problem, not just engineering |
| OQ-7 | radio bootstrap on cold start: needs peer seed list or HTTP fallback | UX cliff for first launch |
| OQ-8 | glia .model format vs commercial models: safetensors → .model converter is a prerequisite | blocks third-party model use |
| OQ-9 | zheng proof generation latency: seconds-per-program today, not realtime; gameplay enforcement deferred to v2 | constrains v1 trust model |
| OQ-10 | ShardStore backend auto-selection policy: priority order (unimem → memory → ssd) and fallback semantics when preferred backend unavailable |
runtime hardware probe + per-shard hint resolution |
| OQ-11 | tick rate vs frame rate: at what cadence do BBG commits run; mid-tick read of write-pending state needs explicit consistency rule (snapshot at tick start, or read-your-writes) | scheduler-level decision, affects all gameplay code |
| OQ-12 | engine boundary for inference: glia inference results are non-deterministic across hardware. when do those results become BBG signals (with quantization) vs stay ephemeral (visual only) | the determinism/expressiveness tradeoff |
| OQ-13 | A(x) / N(x) component semantics in ECS: an individual cyberlink IS a private record; the ECS shape for an "owned cyberlink as component" needs design | private-state ergonomics |
| OQ-14 | Android shared-memory model: AHardwareBuffer is the closest IOSurface analogue but has different lifetime + import semantics. is the unimem backend ported (with AHardwareBuffer impl) or does Android fall back to memory backend with explicit GPU upload? |
platform-shim scope decision |
| OQ-15 | thermal throttling policy: when NPU/Gpu hit thermal limits, who decides to throttle? lower tick rate, reduce φ*-budget, drop NPC count, or all of the above? policy needs to be per-game-configurable | UX-critical on mobile, deferred to v1.1 acceptable |
| OQ-16 | NNAPI as ANE substitute on Android: rane's MIL bytecode doesn't translate to NNAPI; need a separate evy_nnapi_runtime crate parallel to rane, with model-import path from glia's .model |
unblocks Android neural materials |
| OQ-17 | Android Activity lifecycle: checkpoint format on onPause and restore on onResume (or cold start after kill). BBG root + ephemeral ShardStore snapshot — ephemeral data (Transforms, animation phases) doesn't survive process death gracefully; needs deterministic restoration policy |
Android correctness issue |
18. non-goals
what evy explicitly is not
- a cross-platform game engine with feature parity on every platform — capability tiers (§3.3) make platform differences explicit, not hidden
- a drop-in replacement for bevy that bevy games can port to
- compatible with the bevy plugin ecosystem
- optimal for AAA discrete-GPU PC rasterization workloads
- a research project on every layer simultaneously — adopts soft3 components as-is, forks bevy at chosen seams
- a WebGPU browser engine — unimem doesn't survive WebGPU translation
- self-contained — depends on unimem/acpu/aruminium/rane from honeycrisp and ~15 soft3 components
19. order of attack
implementation sequence. earlier steps unblock later ones
- ✓ evy_platform_caps + evy_ecs_storage: probe + FallbackPolicy +
bbg::ShardStoreadapter. memory + unimem backends. ~3 sessions, landed - ✓ bevy_tasks extension: AmxTaskPool + AneTaskPool. ~1 session, landed as separate crate
evy_engine_tasks(spec deviation; bevy_tasks moves from FORK to INTACT) - ⏳ aruminium gains raster support —
RenderPipelineState+RenderPassDescriptor+RenderEncoder+ render-targetTexture, so aruminium is a complete renderer (not just compute) on Apple Silicon. ~3–4 sessions. proposal drafted at~/cyber/honeycrisp/aruminium/.claude/plans/raster-support.md. The earlier device-sharing constructors (commit26ba16b) were reverted (48f1bc8) because the wgpu+aruminium coexistence model they enabled costs 9–13 ms/frame on Apple Silicon - ◐ evy_engine_dispatch:
DispatchNodetrait, scheduler, commit-policy, capability-aware fallback. ~4 sessions, sessions 1-2 landed (trait + scheduler skeleton + engine pool routing); sessions 3-4 (parallel layer + real cross-engine sync) blocked on step 3 - ⛔ bevy_mesh + bevy_image on unimem
ShardStore; meshes/textures stop uploading. ~3 sessions, blocked on step 3 - ⛔ bevy_transform with AMX propagation. first visible perf win. ~2 sessions, blocked on step 4 complete
- ◐ prysm core + atoms implementation. ~5 sessions, core protocol landed (Π + Φ + K + fold + motion + emotion in
evy_prysm_core, 47 tests). atoms blocked on render path - ⛔ evy_glia_runtime + evy_neural_material — the wow demo. ~6 sessions, blocked on steps 3+4
- ⛔ mir tier passes as DispatchNodes. ~4 sessions, blocked on step 3
- ⛔ BBG signal handlers as DispatchNodes; tick-boundary commit scheduling; cybergraph + nox integration. ~5 sessions, blocked on step 4 complete
- ◐ evy_radio adapter + ShardStore network-backend impl serving radio://. ~3 sessions, session 1 landed (channel bridge + stub daemon, 6 tests); session 2 = real iroh; session 3 = AssetSource wiring
- ⛔ prysm molecules + cells + aips. ~10 sessions, blocked on step 7 atoms
- ⛔ evy_phi_budget + evy_generative_cache. ~4 sessions, blocked on step 8
- ⛔ bevy_pbr + post-process REWRITE. ~6 sessions, blocked on steps 3+4+5
- ⛔ Android bring-up. ~5 sessions, blocked on step 4 complete
- ⛔ evy_nnapi_runtime. ~5 sessions, blocked on step 4 + Android
- ✓ PMU-backed
evy_diagnostic+ thermal/power telemetry. ~3 sessions, landed (370 LOC, 11 tests, PMU upgrade path with Wall fallback)
plus landed extras: evy_dialect (300 LOC, 14 tests; particle-identified component schemas), evy_engine_core (340 LOC, 9 tests; assembly + end-to-end smoke test)
progress: 11 of 17 steps complete or substantially started. step 3 reframed: aruminium gains raster (proposal drafted) — the earlier device-sharing path was abandoned after numbers showed wgpu+aruminium coexistence taxes 9–13 ms/frame on Apple Silicon. ~25 sessions of downstream work (steps 4.3-4.4, 5, 6, 8, 9, 10, 14) unblock once aruminium raster lands.
estimated total: ~69 sessions (~180–210 pomodoros, 35–42 days of focused work). this is the substantial-but-tractable scope of v1 including Android-out-of-the-box
20. license
cyber license: don't trust. don't fear. don't beg