> Cinder 0.1.0 documentation: Cinder architecture
> Canonical page: https://cinder.ash10.dev/docs/architecture/ · Source: `docs/ARCHITECTURE.md` in the engine repository (engine commit 47c9352, imported 2026-11-09)
> Index of every page for agents: https://cinder.ash10.dev/llms.txt

# Cinder architecture

## Module map

Dependencies point downward only. A module may import from the layers below it, never from the same
layer except where noted, and never from above.

```
sample/                 third-person sample game (Mojo), a `Game` run by cinder/app
  └── cinder/app        App runtime: owns every subsystem, fixed-step loop, headless mode, CLI
        └── cinder/tools      ImGui debug overlay (inspector, asset browser, render graph, log)
        └── cinder/{render,physics,anim,audio,input,assets,scene}
              └── cinder/ecs            archetype ECS, queries, command buffers, hierarchy, scheduler
              └── cinder/gfx            safe typed wgpu layer, shader manager, hot reload, debug draw
              └── cinder/platform       SDL3 window/input/gamepad, surfaces, ImGui event forwarding
                    └── cinder/core     log, assert, arena, handles, ring, math, jobs, time, fs, profile, boxed
                          └── cinder/ffi    generated bindings + layout tests (never hand-edited)
                                └── native/   libcinder_native (C11 shim) + vendored C/C++ libs
```

| Module | Language | Responsibility |
|---|---|---|
| `native/` | C11 (shim), C/C++ (deps) | Single shared library `libcinder_native`. Wraps wgpu-native, SDL3, joltc, miniaudio, cgltf, stb_image, KTX, meshoptimizer, MikkTSpace, dcimgui + backends, Tracy, flecs (benchmark only). Owns **every** callback and the lock-free event queues. `libcinder_alloccount` is a separate LD_PRELOAD library for the allocation test. |
| `cinder/ffi` | Mojo (generated) | Raw bindings for each native header. Generated by `tools/bindgen` (ADR-0005), committed, verified by the layout test. |
| `cinder/core` | Mojo | Logging, assertions, arenas, generational handles, rings, SIMD math (`core/math`), work-stealing job system, time, filesystem, Tracy zones (`profile`), heap cells with stable addresses (`boxed`). No GPU or window I/O. |
| `cinder/platform` | Mojo | SDL3: window, events, input, gamepad, surface creation per OS, forwarding events to ImGui. The only module with per-OS branches. |
| `cinder/gfx` | Mojo | Typed handles over wgpu (`Resources`), ownership and leak accounting, WGSL shader manager with hot reload, validation surfacing, swapchain, debug draw. |
| `cinder/ecs` | Mojo | Archetype storage, typed queries and cached `QuerySpec`s, change ticks, command buffers, hierarchy and transform propagation, access-declared system scheduling on the job system. |
| `cinder/render` | Mojo + WGSL | Frame graph, clustered forward+, cascaded and atlas shadows, IBL, GTAO, bloom, tone mapping, FXAA, MSAA, culling, LODs, skinning, morph targets, debug views. Allocation-free in steady state. |
| `cinder/assets` | Mojo | glTF import, cooked formats, incremental cooker, KTX2 textures, `AssetServer` (async loads, refcounts, hot reload). |
| `cinder/scene` | Mojo | Text and binary scene formats with migrations, component registry, ECS to render-scene bridge (`RenderBridge`), glTF spawning into the ECS. |
| `cinder/physics` | Mojo | Safe layer over joltc: world, shapes, bodies, events, casts, `CharacterController`, ECS sync with interpolation (`PhysicsSync`). |
| `cinder/anim` | Mojo | Skeletons, clip sampling, blend trees, crossfades, root motion, events; one job per animator. |
| `cinder/audio` | Mojo | Buses, one-shots, streams, spatialisation over miniaudio; ECS sources and listener. |
| `cinder/input` | Mojo | Action/axis mapping over keyboard, mouse and gamepad; runtime rebinding; text save/load. |
| `cinder/app` | Mojo | `App` runtime and the `Game` trait: subsystem ownership, fixed-step loop, windowed or `--headless`, allocation accounting, CLI parsing. |
| `cinder/tools` | Mojo | ImGui debug overlay: frame graph, entity inspector, asset browser, render graph view, log console. |
| `sample/` | Mojo | The sample game: components, levels, settings, gameplay (ADR-0014). |
| `tools/` | Mojo, Python, shell | Cooker CLI, bindings generator, lint, test drivers, asset fetchers, benchmark checker. |
| `bench/` | Mojo | Benchmarks writing JSON (`stress`, `sample_bench`, `ecs_bench`) and their baselines; see `docs/BENCHMARKS.md`. |
| `tests/` | Mojo, C (CTest) | Unit, golden-image, replay, fuzz, playthrough and allocation tests. |

## The C boundary

- One shim, one shared library, flat C ABI (`cinder_native.h`, C11).
- **Pull model.** C callbacks (wgpu async requests, device lost, uncaptured errors, Jolt contacts,
  miniaudio data, SDL log) write fixed-size events into fixed-capacity SPSC/MPSC lock-free rings inside the
  shim. Mojo drains them once per frame on the main thread. Mojo code never executes on a C thread unless
  spike 4 proves it safe and an ADR records that (ADR-0003).
- Generated raw bindings live in `cinder/ffi` and are never edited by hand. A C program emits
  `sizeof`/`alignof`/`offsetof` for every bound struct and every enum value; a generated Mojo test asserts
  identical values. Mismatch fails CI.
- Safe wrappers: one distinct handle struct per resource type, ownership through `__deinit__`, explicit
  lifetimes for borrowed C strings and views, each shared library loaded exactly once, every `unsafe_` call
  annotated with `# SAFETY:`.

## Threading model

- Main thread: SDL event pump, window, presentation (`wgpuSurfacePresent`), ImGui.
- Job system (`cinder/core/jobs`): one worker per physical core minus one, work-stealing deques, a
  per-frame dependency graph. Everything else (culling, animation, ECS systems, asset decode, physics
  step through Jolt's own job system adapter) runs there.
- Shared state crosses threads only through jobs, atomics or documented locks named in
  `docs/THREADING.md`.
- Audio: miniaudio's device thread runs in C only; it reads a lock-free command ring and never calls Mojo.

## Frame loop

Fixed 60 Hz simulation with accumulator (`App.run_frame`: poll events, fixed steps with physics and
`Game.fixed_update`, `Game.update`, animation jobs, transform propagation, audio sync, render-scene
bridge, render, ImGui, present or offscreen readback). Per-frame memory lives in persistent scratch
fields that are cleared, never freed, between frames; steady state performs zero heap allocations from
Mojo code (asserted by `tests/perf/test_zero_alloc.mojo`, ADR-0014).

## Conventions (fixed)

Right-handed, Y up, −Z forward, metres, column-major matrices, reverse-Z with infinite far plane, linear
lighting, sRGB render targets, RGBA16F intermediates. Recoverable failures raise typed errors; broken
invariants abort with a message.
