Sonnet is a 3D game engine written in C++23 for Windows, Linux, macOS, Android and iOS. It is a set of small modules with one-way dependencies, a Vulkan 1.4 renderer behind a thin render-hardware interface, and an editor for authoring, debugging and playing scenes.
Status: pre-alpha, version 0.20.0, milestone M16 (nested scene instances) landed (docs/roadmap.md), and 1.0.0 has no date and waits for the file formats to stop changing: build, core with a job system, platform, rhi with a bindless set, renderer with a clustered forward pipeline, PBR, cascaded shadows, image-based lighting, post-processing with temporal anti-aliasing, GPU skinning, morph targets, GPU particles and GPU culling into indirect draws with occlusion culling, assets with glTF and image import, KTX2, ASTC and UASTC HDR cooking and hot reload, world on flecs with scenes, prefabs nested to any depth with the changes a scene makes inside them, a fixed timestep, skeletal animation with blending, events and root motion, physics on Jolt with contact and trigger events and compound bodies, Lua scripting with several scripts per entity, editable properties, require and hot reload, audio on miniaudio, gui with the game UI (canvases, layouts, images, signed-distance text and buttons, authored in the editor and shipped in the player), game modules that link a project's own C++ into its player and editor, ui, an editor that authors scenes, materials and scripts (hierarchy, inspector, asset browser, gizmos, picking, undo, play mode, scene tabs, save as prefab and make local, shader hot reload), and a runtime with the generic player, sonnet_cook and export to Windows, Linux, macOS, Android and iOS, so a sample runs from a cooked bundle with no project folder or SDK. This file and docs/ describe what is built and which decisions are taken. docs/roadmap.md gives the order.
- Personal engine, third iteration. Learning and clarity of architecture come before feature count. Most decisions below come from what worked and what hurt in the two previous iterations.
- Modular. Every module has one job, a public header set under
sonnet/<module>/, its own tests, and depends only on modules earlier in the dependency order. No cycles. - Agnostic where it pays off. Platform access (window, input, main loop, file paths) and GPU access sit behind interfaces owned by the engine, each with exactly one implementation today: SDL3 and Vulkan. Everything else is a fixed choice: C++23, CMake, GLM, flecs, Slang, Dear ImGui.
- Modern Vulkan only. One rendering code path on Vulkan 1.4: dynamic rendering, synchronization2, bindless descriptors, push descriptors. No legacy render passes and no second backend to keep in parity.
- Editor first. The editor is an engine feature, not a demo. It drives the design of reflection, serialization, undo/redo and play mode.
- Exportable. A game is a project folder (scenes, assets, scripts) run by a generic player binary, so exporting never needs a compiler on the target.
- Measurable performance. Proposed targets: 10 000 visible draws and 100 dynamic lights at 1080p in 16.6 ms on a 2020-era mid-range desktop GPU, and the same scene in 33 ms on a 2022 flagship phone. First measured in M3 on an RTX 4090 (docs/roadmap.md): about 1.1 ms of GPU time and far more CPU time, which M7 closed by submitting the draws from the GPU (docs/roadmap.md), and M14 measured it on an RTX 2050 laptop (docs/reports/rtx2050-m14.md), a Galaxy S25 Ultra (docs/reports/s25-m14.md) and an iPhone, where the sustained run misses (docs/reports/iphone-m14.md).
- 2D-specific tooling, networking, consoles, other graphics backends (OpenGL, Direct3D, native Metal), managed scripting languages.
- A general-purpose framework. Only what the editor and the sample games need gets built.
| Feature | Milestone |
|---|---|
| Editor shell: docking layout, scene viewport, fly camera, frame statistics overlay | M1 |
| Editor: scene hierarchy, object inspector, gizmos, picking, undo/redo, play/stop | M2 |
| Editor: asset browser, material editing | M3 |
| On-screen performance and resource monitoring, Tracy profiling | M0 (Tracy), M1 (overlay) |
| Physically based rendering, shadows, image-based lighting, post-processing | M3 |
| Physics (Jolt) and Lua scripting | M4 |
| Audio and skeletal animation | M5 |
| Player binary and export to Windows, Linux and macOS | M6 |
| GPU-driven culling and indirect draws | M7 |
| Job system, asynchronous loading and multi-threaded recording | M8 |
| Export to Android | M9 |
| Export to iOS | M10 |
Contact and trigger events, compound bodies, several scripts per entity with editable properties, require |
M11 |
| Animation blending and events, morph targets, particles | M12 |
| Temporal anti-aliasing, occlusion culling, shadows from blended materials, compressed HDR environments | M13 |
| Measured performance targets | M14 |
| Game UI, and native game modules linked into a project's player and editor | M15 |
| Nested scene instances: prefabs of prefabs, with a scene's changes inside an instance saved | M16 |
| Platform | Editor | Player | Vulkan 1.4 comes from |
|---|---|---|---|
| Windows 10/11 x64 | yes | yes | GPU vendor drivers |
| Linux x64 | yes | yes | Mesa (RADV, ANV, Lavapipe) or NVIDIA drivers |
| macOS 12+ (arm64, x64) | yes | yes | MoltenVK 1.4+ over Metal; portability-subset rules apply |
| Android | no | yes | Devices launching with Android 16+, where 1.4 is mandatory, and 1.3 devices that carry the engine's four 1.4 features as extensions (ADR-0019). |
| iOS 15+ | no | yes | MoltenVK 1.4+; built from a macOS host |
Vulkan 1.4 is the minimum, or 1.3 with the four 1.4 features the engine uses as extensions (ADR-0001, amended by ADR-0019). Per-platform consequences are in docs/rendering.md.
| Library | Purpose | Source |
|---|---|---|
| C++23, CMake 3.28+ | Language and build | Toolchain |
| SDL3 | Window, input, main-loop callbacks, audio device, file paths | vcpkg sdl3 |
| Vulkan 1.4 + Vulkan-HPP (RAII) | GPU API | vcpkg vulkan-headers, vulkan-loader; Vulkan SDK on dev machines for validation layers |
| vk-bootstrap | Instance, device and swapchain creation | vcpkg vk-bootstrap |
| Vulkan Memory Allocator (Hpp bindings) | GPU memory allocation, budgets, leak tracking | vcpkg vulkan-memory-allocator-hpp |
| MoltenVK | Vulkan on Metal, linked statically into the player on iOS and macOS (M10) | vcpkg moltenvk |
| Slang | Shading language, compiler, reflection | vcpkg shader-slang |
| GLM | Math | vcpkg glm |
| flecs | Entity component system, hierarchy, prefabs, reflection | vcpkg flecs (ADR-0003) |
| Dear ImGui (docking branch) | Editor and debug UI | vcpkg imgui[docking-experimental,sdl3-binding,vulkan-binding] |
| spdlog | Logging | vcpkg spdlog |
| Tracy | CPU/GPU profiling | vcpkg tracy |
| nlohmann-json | Project and scene files | vcpkg nlohmann-json |
| fastgltf | glTF 2.0 import | vcpkg fastgltf |
| stb | Image decoding for import | vcpkg stb |
| KTX-Software | KTX2 / Basis Universal GPU-compressed textures | vcpkg ktx |
| meshoptimizer | The far shadow cascades' coarser index range (ADR-0025); decoding glTF EXT_meshopt_compression |
vcpkg meshoptimizer |
| Catch2 | Unit tests | vcpkg catch2 |
| Jolt Physics, Lua + sol2, miniaudio | Physics, scripting, audio (M4, M5) | vcpkg joltphysics, lua, sol2, miniaudio |
Dependency policy: vcpkg manifest mode for everything that has a port; CMake FetchContent only for libraries without a port or for pinned forks carrying local patches; never both for the same library (ADR-0004).
A module depends only on modules earlier in the dependency order. Interfaces live with the layer that owns them, next to their default implementation. Upward communication happens through those interfaces, callbacks and events, never through a dependency.
flowchart BT
core
platform --> core
rhi --> platform
renderer --> rhi
assets --> renderer
world --> assets
physics --> world
scripting --> physics
audio --> world
runtime --> audio
runtime --> scripting
ui --> rhi
editor --> ui
editor --> runtime
appEditor["apps/editor"] --> editor
appPlayer["apps/player"] --> runtime
| Module | Responsibility |
|---|---|
core |
Types, typed handles, logging, assertions, UUIDs, hashing, GLM configuration |
platform |
Window, input events, main-loop callbacks, file paths. Interface plus the SDL3 implementation |
rhi |
Render hardware interface plus the Vulkan 1.4 implementation |
renderer |
Render graph, materials, meshes, cameras, lights, passes. Talks only to rhi interfaces |
assets |
Asset database, importers, cooking, hot reload |
world |
ECS world, core components (Transform, hierarchy, Name), scene load and save, skeletal animation |
physics |
Rigid bodies, colliders and raycasts behind IPhysicsWorld, on Jolt |
scripting |
Lua scripts on entities behind IScriptRuntime, reaching components through reflection |
audio |
Sounds on entities behind IAudioDevice, on miniaudio |
runtime |
The world and its subsystems running a project or a cooked bundle, for the player |
ui |
Dear ImGui layer. Editor and debug builds only |
editor |
Panels, selection, undo/redo, gizmos, play mode. Desktop only |
Details, including the entity model, resource handles and the editor/player split, are in docs/architecture.md.
sonnet/
├── CMakeLists.txt, CMakePresets.json, vcpkg.json, vcpkg-configuration.json
├── cmake/ — options, module and test helpers, toolchain glue
├── ports/ — vcpkg overlay ports carrying local patches
├── modules/<name>/ — include/sonnet/<name>/, src/, tests/, shaders/ (renderer only)
├── apps/
│ ├── editor/ — the editor executable (desktop)
│ ├── cook/ — sonnet_cook, which cooks a project into a bundle
│ ├── player/ — the generic runtime that exported projects run on
│ └── samples/ — sample projects used for testing and demos
├── docs/ — this documentation, decisions/ for ADRs
└── .github/workflows/ — CI
Prerequisites: a C++23 compiler, CMake 3.28+, Ninja and vcpkg with VCPKG_ROOT set. Details, presets and options are in docs/build.md.
export VCPKG_ROOT=/path/to/vcpkg
cmake --preset linux-debug # or windows-debug, macos-debug
cmake --build --preset linux-debug
ctest --preset linux-debug| Topic | Document |
|---|---|
| Architecture: modules, dependency rule, entity model, handles, editor/player | docs/architecture.md |
core: handles, logging, assertions, errors, UUIDs |
docs/core.md |
platform: window, events, application lifecycle, paths |
docs/platform.md |
| Build system, toolchains, dependencies, CI | docs/build.md |
| Rendering: Vulkan baseline, platform notes, Slang pipeline, frame structure, render graph | docs/rendering.md |
| Editor: the Dear ImGui layer, panels, viewport camera, frame order | docs/editor.md |
| Assets: identity, database, importers, project and scene files, cooking | docs/assets.md |
| World: components, phases and the fixed timestep, animation, scenes and prefabs | docs/world.md |
| Physics: bodies, colliders, the simulation, queries | docs/physics.md |
| Scripting: script instances, errors and hot reload, the Lua API | docs/scripting.md |
| Audio: sources and listeners, playing, miniaudio | docs/audio.md |
| Player: the runtime module, running a project or a bundle, what an export is | docs/player.md |
| Branding: the icon artwork, regenerating the platform icons | docs/branding.md |
| Roadmap and milestones | docs/roadmap.md |
| Conventions: code style, math, error handling, logging, commits, versioning | docs/conventions.md |
| Decision records | docs/decisions/ |
| ADR | Decision | Status |
|---|---|---|
| 0001 | Vulkan 1.4 is the only graphics backend and a hard minimum | Accepted, amended by 0019 |
| 0002 | SDL3 for windowing, input and the main loop | Accepted |
| 0003 | flecs as the entity component system | Accepted, EnTT recorded as the alternative |
| 0004 | vcpkg first, FetchContent for edge cases | Accepted, amended by 0020 |
| 0005 | Slang as the only shading language | Accepted |
| 0006 | vk-bootstrap creates, Vulkan-HPP RAII owns | Accepted |
| 0007 | Games are data-driven projects run by a generic player | Accepted |
| 0008 | Clustered forward rendering as the main pipeline | Accepted |
| 0009 | Physics and scripting as world subsystems | Accepted |
| 0010 | Audio on miniaudio, animation in world, skinning in compute |
Accepted |
| 0011 | Cooked bundles, the runtime module and what export assembles |
Accepted |
| 0012 | GPU culling into indirect draws, batched per pipeline and mesh | Accepted, amended by 0014, 0015 and 0016 |
| 0013 | One job system in core, with flecs on stage workers of its own |
Accepted |
| 0014 | Indirect draws without drawIndirectCount, for MoltenVK |
Superseded by 0016 |
| 0015 | Bindless vertex buffers instead of a vertex pointer per object | Accepted |
| 0016 | Instanced batches, one indirect command per batch | Accepted |
| 0017 | Depth images in their own bindless array | Accepted |
| 0018 | Mobile export: builds, ASTC, packaging and device checks | Accepted |
| 0019 | Vulkan 1.3 devices that carry the engine's 1.4 features as extensions | Accepted |
| 0020 | Linux runtime libraries beside the editor | Accepted |
| 0021 | Several views in one graph frame | Accepted |
| 0022 | Physics events, script properties and several scripts per entity | Accepted |
| 0023 | Animation blending, morph targets and GPU particles | Accepted |
| 0024 | Temporal anti-aliasing, occlusion culling and compressed HDR environments | Accepted |
| 0025 | A coarser index range for the far shadow cascades | Accepted |
| 0026 | Game UI is scene entities drawn by a gui module |
Accepted |
| 0027 | A game module is a static library the engine build links into a player and an editor | Accepted |
| 0028 | Nested scene instances are prefab instances whose children are addressed by derived identities | Accepted |
| 0029 | Scene files write vectors as arrays | Accepted |
| 0030 | A model prefab's nodes are identified by their name path | Accepted |
| 0031 | Vertex colour is a packed RGBA8 in Vertex | Accepted |
| 0032 | An instance stores the order of its children when it differs from the default | Accepted |
| 0033 | Transmissive materials sample a copy of the opaque scene | Accepted |
No license has been chosen yet. Until one is added, all rights are reserved.