Master of Puppets is structured as a strict four-layer stack. Every dependency points downward. No layer may reference a layer above it.
┌──────────────────────────────┐
│ Application │ examples/showcase.c
├──────────────────────────────┤
│ Viewport Public API │ include/mop/*.h
├──────────────────────────────┤
│ Viewport Core + Interact │ src/core/ + src/interact/
├──────────────────────────────┤
│ Render Hardware Interface │ src/rhi/
├──────────────────────────────┤
│ Backend Implementations │ src/backend/{cpu,opengl,vulkan}/
└──────────────────────────────┘
Subsections
| Page | Topic |
|---|---|
| Layer Separation | Strict boundary rules between layers |
| Frame Lifecycle | What happens during a single render frame |
| Threading Model | Single-threaded guarantees, future-proofing |
| Memory Ownership | Who allocates, who frees, no implicit transfers |
| Extension Strategy | How to add backends, features, and subsystems |
| Scene Graph | Hierarchical transforms and parent-child meshes |
Layer Responsibilities
Application
The application is any program that links against libmop.a. It sees only the public headers in include/mop/. It creates viewports, adds meshes, sets cameras, calls render, reads back pixels.
Viewport Public API
Defined in include/mop/*.h. Exposes opaque handles (MopViewport *, MopMesh *), value types (MopVec3, MopMat4, MopColor), and free functions. No backend-specific types appear here.
Viewport Core + Interaction
Defined in src/core/ and src/interact/. src/core/ owns the scene graph (flat mesh array), camera state, lighting, overlays, and rendering orchestration. src/interact/ owns the input state machine, gizmo, orbit camera, and undo/redo. Both call the RHI to create buffers, begin frames, issue draw calls, and read back results. Never calls backend APIs directly.
Render Hardware Interface (RHI)
Defined in src/rhi/rhi.h. A function-pointer table (MopRhiBackend) that every backend must populate. The viewport core holds a pointer to this table and calls through it.
Backend Implementations
Each backend lives in src/backend/<name>/ and implements every function in MopRhiBackend.
Dependency Rules
| From | May depend on | Must not depend on |
|---|---|---|
| Application | include/mop/ | src/ (anything internal) |
| Viewport Core | include/mop/, rhi | Backend internals |
| RHI | include/mop/ | Backend internals |
| Backend | include/mop/, rhi | Viewport core, other backends |
| Math | C standard library | Everything else |
Design Rationale
Opaque handles provide ABI stability. The application never sees sizeof(MopViewport), so internal fields can change without recompilation.
Function-pointer table enables runtime backend selection. The application chooses MOP_BACKEND_CPU or MOP_BACKEND_OPENGL at viewport creation — no recompilation needed.
Flat mesh array with active flags avoids allocator complexity. The upper bound MOP_MAX_MESHES (4096) can be raised by recompiling.
Column-major matrices match OpenGL and Vulkan conventions. MopMat4.d[col * 4 + row].