Repository navigation
Creating a Game Module
Stable-v1 boundary: Stable-v1 is blocked and uncertified. Its intended product shape is Windows 11 x64 with MSVC v143, D3D11 (or Windows NullRHI), C++ game modules, and one first-party single-player
SparkGameFPSvertical slice. There is no certified versioned SDK or module ABI release. Other hosts, backends, scripting, templates, addons, and multiplayer remain experimental or unsupported.
SparkEngine uses a dynamic module system. Game logic is compiled as a shared library (a DLL on the declared Windows profile; source build paths also exist elsewhere). The current manager permits one ModuleKind::Game module per process; ModuleKind::Addon modules (library/extension-style modules) may coexist when their own metadata permits it. Development reload and compatibility checks do not establish a stable public ABI or hot-reload support guarantee.
Source: SparkSDK/Include/Spark/SparkSDK.h, cmake/SparkGameModule.cmake
Templates/EmptyProject is a standalone installed-SDK package, not an in-tree GameModules/ directory. Copy or materialize it outside the engine checkout, install a configured engine build, and configure it against the installed CMake package:
cmake --install <engine-build> --prefix <sdk> --config Release
cmake -S <MyGame> -B <MyGame>/build -DSparkEngine_DIR="<sdk>/lib/cmake/SparkEngine"
cmake --build <MyGame>/build --config ReleaseThe template package layout is:
MyGame/
├── CMakeLists.txt # Build configuration
├── Source/
│ ├── GameModule.h # Module class (IModule implementation)
│ └── GameModule.cpp # Module factory exports
├── <ProjectName>.sparkproject # Project/editor metadata
└── spark.modules.json # Module manifest
When materializing a template under a new name, update the literal package name consistently across its directory, CMake target, source, metadata, and scene files. Do not copy the stock package directly below GameModules/; use the in-tree setup below for that route.
Every game module implements Spark::IModule from <Spark/SparkSDK.h>. This is the contract between the engine and your game code.
class IModule
{
public:
virtual ~IModule() = default;
// Return metadata about your module
virtual ModuleInfo GetModuleInfo() const = 0;
// Called once when the DLL is loaded
virtual bool OnLoad(IEngineContext* context) = 0;
// Called before the DLL is unloaded
virtual void OnUnload() = 0;
// Called every frame
virtual void OnUpdate(float deltaTime) = 0;
// Called every frame after OnUpdate (optional)
virtual void OnRender() {}
// Called when the window is resized (optional)
virtual void OnResize(int width, int height) {}
};The ModuleInfo struct provides metadata about your module:
| Field | Type | Description |
|---|---|---|
name |
const char* |
Human-readable module name |
version |
const char* |
Semantic version string (e.g. "1.0.0") |
sdkVersion |
uint32_t |
SDK version this module was built against (SPARK_SDK_VERSION) |
loadOrder |
int |
Initialization priority (lower = earlier, default 1000) |
SPARK_SDK_VERSION is 4 (SparkSDK/include/Spark/Version.h) after IEngineContext gained
GetInvalidStateDetector() and GetComponentSerializers(). IsSDKCompatible is exact equality, so
a v3 module is refused by a v4 host and a v4 module by a v3 host — there is no forward or backward
window. Spark/IEngineContext.h pins EngineContextVirtualCount = 90 with a static_assert tying
it to the version constant: adding or removing a virtual means updating both together, or an old
host will accept a module that calls off the end of its vtable.
| Method | Required | When Called | Description |
|---|---|---|---|
GetModuleInfo() |
Yes | After DLL load | Return module name, version, SDK version, load order |
OnLoad() |
Yes | After CreateModule()
|
Initialize the module; return false to abort loading |
OnUnload() |
Yes | Before DestroyModule()
|
Clean up resources, unsubscribe events |
OnUpdate() |
Yes | Every frame | Main game logic tick |
OnRender() |
No | Every frame after update | Custom rendering (HUD, debug overlays) |
OnResize() |
No | Window resize | Handle viewport changes |
#include <Spark/SparkSDK.h>
class MyGameModule : public Spark::IModule
{
public:
Spark::ModuleInfo GetModuleInfo() const override
{
Spark::ModuleInfo info{};
info.name = "MyGame";
info.version = "0.1.0";
info.sdkVersion = SPARK_SDK_VERSION;
info.loadOrder = 1000; // lower values load first
return info;
}
bool OnLoad(Spark::IEngineContext* context) override
{
m_context = context;
// Access engine systems through the context
m_graphics = context->GetGraphics();
m_input = context->GetInput();
m_timer = context->GetTimer();
m_events = context->GetEventBus();
// Subscribe to engine events
m_collisionSub = m_events->Subscribe<Spark::CollisionEvent>(
[this](const Spark::CollisionEvent& e) {
HandleCollision(e);
});
m_sceneSub = m_events->Subscribe<Spark::SceneLoadedEvent>(
[this](const Spark::SceneLoadedEvent& e) {
OnSceneLoaded(e.sceneName);
});
return true; // return false to abort loading
}
void OnUnload() override
{
// Clean up event subscriptions
m_events->Unsubscribe<Spark::CollisionEvent>(m_collisionSub);
m_events->Unsubscribe<Spark::SceneLoadedEvent>(m_sceneSub);
m_context = nullptr;
}
void OnUpdate(float deltaTime) override
{
// Game logic here
UpdatePlayer(deltaTime);
UpdateEnemies(deltaTime);
}
void OnRender() override
{
// Custom rendering (HUD, debug overlays)
DrawHUD();
}
void OnResize(int width, int height) override
{
m_viewportWidth = width;
m_viewportHeight = height;
}
private:
void HandleCollision(const Spark::CollisionEvent& e) { /* ... */ }
void OnSceneLoaded(const std::string& name) { /* ... */ }
void UpdatePlayer(float dt) { /* ... */ }
void UpdateEnemies(float dt) { /* ... */ }
void DrawHUD() { /* ... */ }
Spark::IEngineContext* m_context = nullptr;
GraphicsEngine* m_graphics = nullptr;
InputManager* m_input = nullptr;
Timer* m_timer = nullptr;
Spark::EventBus* m_events = nullptr;
Spark::SubscriptionID m_collisionSub = 0;
Spark::SubscriptionID m_sceneSub = 0;
int m_viewportWidth = 1280;
int m_viewportHeight = 720;
};In exactly one .cpp file, use the SPARK_IMPLEMENT_MODULE macro to generate the required DLL exports:
// GameModule.cpp
#include "GameModule.h"
#include <Spark/ModuleDllMain.h> // Emits the canonical Windows DllMain
SPARK_IMPLEMENT_MODULE(MyGameModule)This generates the following exported functions:
extern "C" SPARK_MODULE_API Spark::IModule* CreateModule();
extern "C" SPARK_MODULE_API void DestroyModule(Spark::IModule*);The engine calls CreateModule() to instantiate your module and DestroyModule() to clean it up. You should never call these functions directly.
SPARK_IMPLEMENT_MODULE expands to:
extern "C" __declspec(dllexport) Spark::IModule* CreateModule()
{
return new MyGameModule();
}
extern "C" __declspec(dllexport) void DestroyModule(Spark::IModule* mod)
{
delete mod;
}On Linux, __declspec(dllexport) is replaced with __attribute__((visibility("default"))).
If your game module lives inside the SparkEngine source tree, put its CMake file under GameModules/<name>/. The root CMakeLists.txt already includes cmake/SparkGameModule.cmake and auto-discovers those directories, so the child file should use the helper directly:
file(GLOB_RECURSE GAME_SOURCES CONFIGURE_DEPENDS "Source/*.cpp" "Source/*.h")
spark_add_game_module(MyGame ${GAME_SOURCES})
target_include_directories(MyGame PRIVATE "Source")Configure and launch an in-tree module from the repository root. With a multi-config generator, keep the configuration segment in both paths:
cmake -S . -B build -G "Visual Studio 17 2022" -A x64
cmake --build build --config Release --target SparkEngine MyGame
.\build\bin\Release\SparkEngine.exe -game .\build\bin\Release\MyGame.dllThe spark_add_game_module(TARGET_NAME ...) function performs the following:
| Step | Action |
|---|---|
| 1 | Creates a SHARED library target from the provided sources |
| 2 | Defines SPARK_MODULE_DLL and SPARK_GAME_DLL compile definitions |
| 3 | Links against Spark::SparkEngineLib
|
| 4 | Sets up SDK include directories (SPARK_ENGINE_INCLUDE_DIR) |
| 5 | Enforces C++23 standard (cxx_std_23) |
| 6 | On MSVC, sets the runtime library to MultiThreadedDLL / MultiThreadedDebugDLL
|
For standalone projects outside the engine tree, use the installed CMake package:
cmake_minimum_required(VERSION 3.25)
project(MyGame LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 23)
find_package(SparkEngine CONFIG REQUIRED)
file(GLOB_RECURSE GAME_SOURCES CONFIGURE_DEPENDS "Source/*.cpp" "Source/*.h")
spark_add_game_module(MyGame ${GAME_SOURCES})
target_include_directories(MyGame PRIVATE "Source")SparkEngineConfig.cmake imports the package targets and the installed SparkGameModule.cmake helper. SparkEnginePreflight.cmake is a source-tree utility, not an installed-SDK dependency; do not add a relative source-tree module path to a standalone package.
Use -DSparkEngine_DIR="<sdk>/lib/cmake/SparkEngine" (or an equivalent package-discovery setting) after cmake --install <engine-build> --prefix <sdk> --config Release. A raw engine build directory is not the standalone SDK contract.
Tests/PackageSmoke/FPSProgression compiles the production FPS progression, local-profile, asset-path, and weapon-configuration sources using only the canonical installed Spark/ headers and module headers, without linking an engine target. Its isolated SDK header directory is recreated from the selected installation on every configure, so an obsolete staged header cannot hide an incomplete current package. SparkSDKHeaderRefresh verifies this with a successful real consumer build followed by removal of an installed header, reconfiguration of the same build tree, and an expected compilation failure. Its asset tests run copied consumers in isolated layouts to verify executable-directory and parent priority on Windows/Linux, working-directory discovery, missing-root fallback, UTF-8 paths, and cached root stability. Weapon tests preserve the 18 balance configurations, 25 display names, fallback rules, numeric enum values, and calculation/validation behavior. Spark/WeaponTypes.h is the single weapon enum definition shared by the SDK and legacy engine/module headers, preserving its SparkEditor namespace and underlying int; no SDK ABI version changes. The diagnostic-bearing modification and string-parsing operations retain their engine logging in a separate translation unit and are not covered by the SDK-only consumer. The class ability consumer also compiles the production ClassAbilityState.cpp used by ClassSystem and Player, covering energy gating, repeated activation, duration expiry, cooldown progress and clamping, explicit deactivation, and reset without private engine headers. The extraction preserves existing timing: the full frame delta is applied to cooldown in the same update that expires the active duration. The full FPS module still depends on private rendering, input, and world interfaces; these consumers establish a bounded migration step, not complete SDK independence.
The FPS inventory and quest mutation overloads also compile in the isolated consumer without private engine headers. Existing calls that supply an EventBus* are implemented by Game/FPSGameplayEvents.cpp; they apply the same mutation once and retain pickup/completion publication, including repeatable quests and null-bus behavior. Tests/FPSGameplayEvents compiles that production adapter with the real engine EventBus as a separate CTest integration target. It intentionally uses private engine headers and does not count as SDK-only or full-module linkage evidence.
Current template packages use a project/editor metadata file. It does not replace explicit runtime module selection:
{
"projectFileVersion": 1,
"name": "MyGame",
"version": "0.1.0",
"engineVersion": "1.0.0",
"description": "My first SparkEngine game",
"modules": ["MyGame"],
"defaultScene": "Scenes/Default.sparkscene",
"scenes": ["Scenes/Default.sparkscene"]
}| Field | Required | Description |
|---|---|---|
name |
Yes | Project display name |
version |
Yes | Semantic version of your game |
engineVersion |
Yes | Minimum compatible engine version |
description |
No | Human-readable project description |
modules |
Yes | Project metadata naming this package's module target |
defaultScene |
No | Scene to load on startup |
Module manifest whose loader consumes each non-empty path entry:
{
"modules": [
{
"path": "MyGame.dll"
}
]
}| Field | Type | Description |
|---|---|---|
path |
string |
Non-empty relative or absolute path to the DLL/SO; a relative path is resolved against the manifest directory |
name / loadOrder
|
metadata | Not consumed by the current manifest parser; use ModuleInfo for module metadata |
For the engine-directory fallback, place spark.modules.json next to the executable: build/bin/<Config>/ for a multi-config root build and build/bin/ for a single-config root build. An explicit -manifest <path> may name a regular manifest file elsewhere.
The loader rejects a second ModuleKind::Game module because two games would own the same simulation. A manifest can include the selected Game module plus compatible ModuleKind::Addon modules (library/extension-style modules); their kinds and lifecycle dependencies come from their ModuleInfo, not manifest loadOrder metadata:
{
"modules": [
{ "path": "MyGame.dll" },
{ "path": "MyGameplayAddon.dll" }
]
}The engine resolves a selected game module using this priority:
-
Command-line game path:
SparkEngine.exe -game path/to/MyGame.dll -
Explicit manifest:
SparkEngine.exe -manifest path/to/spark.modules.json -
Engine-directory manifest:
spark.modules.jsonnext to the executable -
Bare launch (platform-specific):
- Windows: discover candidates without bulk-loading them; one candidate loads directly, while several require the windowed selector or headless pick-one guidance
-
Current non-Windows path: scan the executable directory through
LoadModulesFromDirectory; the manager still refuses a second Game-kind module, so prefer-gameor-manifest
Module Discovery Flow
│
├── Check command line: -game <path>
│ └── Found? → Load specified DLL
│
├── Check command line: -manifest <path>
│ └── Found? → Load each manifest path (one Game module maximum)
│
├── Check for spark.modules.json next to the executable
│ └── Found? → Load each manifest path (one Game module maximum)
│
└── Bare launch (platform-specific)
├── Windows: one candidate loads; multiple candidates require an explicit choice
└── Non-Windows: directory scan attempts matches; one-Game policy still applies
Engine Startup
│
├── Load DLL/SO (platform LoadLibrary / dlopen)
├── Resolve CreateModule() symbol
├── Call CreateModule() ← allocate module instance
├── Call GetModuleInfo() ← metadata, SDK version check
├── Validate SDK version
│ └── Mismatch? → Log warning, skip module
├── Call OnLoad(context) ← initialization
│ └── Returns false? → Call DestroyModule(), skip
│
├── Main Loop ──────────────────┐
│ ├── OnUpdate(deltaTime) │ ← every frame
│ └── OnRender() │ ← every frame (if overridden)
│ └────────────────────────────┘
│
├── Call OnUnload() ← cleanup
├── Call DestroyModule() ← deallocate module instance
└── Unload DLL/SO (FreeLibrary / dlclose)
The process hosts one Game module. Compatible ModuleKind::Addon modules (library/extension-style modules), when present, follow their own ModuleInfo lifecycle rules; manifest loadOrder is not a runtime control.
Once you have the IEngineContext*, access services exposed by the active build. Availability varies by configuration; do not infer that every listed subsystem is part of stable-v1.
Since the 2026-09 sweep the gameplay lifecycle populates GetLocalization, GetAI, GetAnimation,
GetWeapons, GetMusic, GetDestruction, GetAbilities, GetConditions, GetInstances,
GetTween, GetVFS, and GetAreaStreaming with the host's instances. Two accessors are new:
GetInvalidStateDetector() and GetComponentSerializers() -- modules must use these host instances
rather than GetInstance(), which returns a DLL-local copy inside the module. GetSceneManager() is
nullptr unless a host registers one, and the engine loads no language file on its own.
class IEngineContext
{
public:
virtual GraphicsEngine* GetGraphics() = 0;
virtual InputManager* GetInput() = 0;
virtual Timer* GetTimer() = 0;
virtual Spark::EventBus* GetEventBus() = 0;
virtual AudioEngine* GetAudio() = 0;
virtual PhysicsSystem* GetPhysics() = 0;
virtual Spark::Animation::AnimationSystem* GetAnimation() = 0;
virtual Spark::AI::AISystem* GetAI() = 0;
virtual Spark::NetworkManager* GetNetwork() = 0;
virtual SceneManager* GetSceneManager() = 0;
virtual AngelScriptEngine* GetScriptEngine() = 0;
virtual Spark::SaveSystem* GetSaveSystem() = 0;
virtual Spark::CoroutineScheduler* GetCoroutineScheduler()= 0;
virtual uint32_t GetEngineVersion() const = 0;
virtual uint32_t GetSDKVersion() const = 0;
virtual bool IsHeadless() const = 0;
};| Getter | Returns | Description |
|---|---|---|
GetGraphics() |
GraphicsEngine* |
Rendering implementation compiled into the active build; stable-v1 is D3D11/Windows NullRHI only |
GetInput() |
InputManager* |
Keyboard, mouse, gamepad input |
GetTimer() |
Timer* |
Frame timing and delta time |
GetEventBus() |
EventBus* |
Publish/subscribe event system |
GetAudio() |
AudioEngine* |
Concrete engine audio service; the host's separate IAudioBackend factory is not exposed through this getter |
GetPhysics() |
PhysicsSystem* |
Jolt Physics simulation |
GetAnimation() |
AnimationSystem* |
Skeletal animation pipeline |
GetAI() |
AISystem* |
Behavior trees and NavMesh |
GetNetwork() |
NetworkManager* |
UDP multiplayer (requires ENABLE_NETWORKING) |
GetSceneManager() |
SceneManager* |
Scene hierarchy and serialization |
GetScriptEngine() |
AngelScriptEngine* |
Experimental AngelScript surface outside stable-v1 |
GetSaveSystem() |
SaveSystem* |
Game state serialization |
GetCoroutineScheduler() |
CoroutineScheduler* |
Coroutine-based async tasks |
IsHeadless() |
bool |
True if running without graphics (dedicated server) |
The public Spark::IEngineContext passed to a module does not expose the
concrete host's RegisterSystem<T>() or GetSystem<T>() registry APIs. Keep
game-specific managers in module-owned state, communicate through the public
event bus or named getters, or define an explicit addon interface. Do not
downcast IEngineContext to the private engine implementation.
Game modules typically subscribe to events during OnLoad() and unsubscribe during OnUnload():
bool OnLoad(Spark::IEngineContext* context) override
{
auto* bus = context->GetEventBus();
m_damageSub = bus->Subscribe<Spark::EntityDamagedEvent>(
[this](const Spark::EntityDamagedEvent& e) {
OnEntityDamaged(e);
});
m_killSub = bus->Subscribe<Spark::EntityKilledEvent>(
[this](const Spark::EntityKilledEvent& e) {
OnEntityKilled(e);
});
m_frameSub = bus->Subscribe<Spark::FrameBeginEvent>(
[this](const Spark::FrameBeginEvent& e) {
OnFrameBegin(e.deltaTime);
});
return true;
}
void OnUnload() override
{
auto* bus = m_context->GetEventBus();
bus->Unsubscribe<Spark::EntityDamagedEvent>(m_damageSub);
bus->Unsubscribe<Spark::EntityKilledEvent>(m_killSub);
bus->Unsubscribe<Spark::FrameBeginEvent>(m_frameSub);
}See Event System for the full list of built-in event types.
Game modules can create entities and attach components using the World:
bool OnLoad(Spark::IEngineContext* context) override
{
// Get the ECS world from the scene manager
auto* sceneMgr = context->GetSceneManager();
// Create a player entity
EntityID player = world.CreateEntity("Player");
auto& tf = world.AddComponent<Transform>(player);
tf.position = {0.0f, 1.0f, 0.0f};
auto& hp = world.AddComponent<HealthComponent>(player);
hp.maxHealth = 100.0f;
hp.health = 100.0f;
auto& mesh = world.AddComponent<MeshRenderer>(player);
mesh.meshIndex = 0;
mesh.materialIndex = 0;
mesh.visible = true;
return true;
}See Entity Component System for the full component and system reference.
Common causes of module load failures:
| Symptom | Cause | Fix |
|---|---|---|
| DLL not found | Wrong path in manifest | Check spark.modules.json path |
CreateModule symbol not found |
Missing SPARK_IMPLEMENT_MODULE macro |
Add macro to exactly one .cpp file |
| SDK version mismatch | Module built with different SDK version | Rebuild module against current SDK |
OnLoad() returns false |
Initialization error in module code | Check module logs for details |
| Missing DLL dependency | Module links against absent library | Use dumpbin /dependents (Windows) or ldd (Linux) |
The engine provides console commands for module inspection:
module_list # List all loaded modules with version and load order
module_info <name> # Show detailed info for a specific module
module_reload <name># Hot-reload a module (development only)
-
Store the context pointer -- Save
IEngineContext*inOnLoad()and use it throughout your module's lifetime. The pointer remains valid untilOnUnload(). -
Clean up subscriptions -- Always unsubscribe from events in
OnUnload(). Dangling subscriptions cause crashes after the module DLL is unloaded. -
Check for null subsystems -- Some subsystems may be null in headless or minimal configurations. Always check before using:
if (auto* audio = context->GetAudio()) audio->PlaySound("startup");
-
Keep module metadata coherent --
ModuleInfoowns a module's kind and lifecycle metadata. Do not rely on manifestloadOrder; a second Game-kind module is refused. -
Avoid global state -- Keep all state inside your module class. Global variables in a DLL can cause issues with hot-reload and multiple module instances.
-
Match SDK versions -- Always build your module against the same SDK version as the engine. The engine logs a warning on version mismatch.
- Entity Component System -- Work with entities and components
- Scripting with AngelScript -- Add scripted gameplay logic
- Scene Management -- Load and manage scenes
- Event System -- Subscribe to engine events
- Input System -- Handle player input
- Architecture Overview -- Engine architecture and module system
- Entity Component System -- Work with entities and components
- Scripting with AngelScript -- Add scripted gameplay logic
- Scene Management -- Load and manage scenes
- Event System -- Subscribe to engine events
- Input System -- Handle player input
- Build System and CMake Modules -- Build configuration
Published from 2b03dc797148. Edit the canonical source in wiki/.
- Documentation
- Docs route
- Wiki index
- Guides
- Tutorials
- Samples
- Examples
- API Reference
- API route
- Reference
- Build Guide
- Dependencies
- FAQ
- Changelog
- Roadmap
- Contributing
- Code of Conduct
- Home
- FAQ
- Getting Started
- Quick-Start Tutorial
- Making Your First Game
- Making Your First Multiplayer Game
- Artist Workflow Guide
- Editor Walkthrough
- Migration Guide
- How SparkEngine Works
- Architecture Overview
- Engine Architecture Flowchart
- Creating a Game Module
- Game Modules (catalog)
- Entity Component System
- Rendering and Graphics
- Physics
- Cloth Simulation
- Audio
- Input System
- Camera System
- Scripting with AngelScript
- Visual Scripting
- AI and Navigation
- Animation
- 2D Systems
- Networking
- Dedicated Server
- Multiplayer Quick Start
- Area Server Architecture
- Scene Management
- Large World Support
- Collaborative Editing
- Coroutine System
- Event System
- Event Response System
- Job System
- UI System
- UI Layout Extensions
- Localization
- Dialogue System
- Destruction System
- Replay System
- Achievement System
- Loading System
- Mod System
- Content Delivery
- Tween System
- Memory Integrity
- Gameplay Systems
- Terrain and Procedural Generation
- Save System
- Persistence System
- Day Night Cycle and Weather
- Cinematic Sequencer
- Runtime Prefabs
- SparkEditor
- Editor Tutorials
- SparkConsole
- SparkDaemon
- Shader Pipeline
- Asset Pipeline
- Asset Validation
- Asset Migration
- Game Packaging
- Online Services
- DataTable System
- Loot and Crafting System
- CSG System
- Font System
- Timer Manager
- Movie Render Pipeline
- HLOD and World Partition
- Remote Debug System
- Selection Manager
- Asset Dependency Graph
- Editor Automation
- File Watcher
- Project Templates
- System Requirements
- VR Support
- Mobile Platform
- Accessibility
- Platform Input
- Platform Certification
- Cross-Compilation: Wine Testing
- RHI Abstraction Layer
- D3D11 Backend
- D3D12 Backend
- Vulkan Backend
- OpenGL Backend
- Metal Backend
- DXR Raytracing
- Hybrid Ray Tracing
- Upscaling (DLSS/FSR)
- Render Graph
- Shader Graph
- GPU Particles
- GPU-Driven Rendering
- Volumetric Fog
- Volumetric Clouds
- Global Illumination
- Virtual Texturing
- Water Rendering
- Clustered Lighting
- Material System
- Post-Processing
- Shadow System
- Particle System
- Decal System
- Sky and Atmosphere
- Foliage System
- Mesh Shaders
- Neural Rendering
- Configuration Reference
- Performance Tips
- Benchmark Framework
- Threading Model
- Fuzz Policy and Parser Security
- Memory Safety
- Memory Management Patterns
- Build System and CMake Modules
- Profiler and Debugging
- Performance Profiling Guide
- Telemetry System
- Crash Reporting
- Golden Image Testing
- Utilities
- Testing
- Fuzz Policy and Parser Security
- Codebase Statistics
- Codebase Health
- Error Handling Patterns
- Hot Reload Overview
- Troubleshooting
- Contributing
- Workflow Patterns
- Build Optimizations
- CI Reproducible Builds
- GitHub API and PR Checks
- Git Rebase Conflicts
- Clang-Format
- Code Quality Violations
- AI Bloat Pattern
- MinGW + Wine Cross-Compilation
- Live Editor Testing
- Engine & Renderer Landscape
- DuetOS Portability Catalog
- Five-Engine Analysis
- Eleven-Engine Analysis
- ThorVG / Unity Graphics Analysis
- Advanced Techniques Catalog
- Third-Party Library Evaluation
- Engine Viability Evaluation
- Engine Feature Recommendations
- Project Recommendations
- Mac Compatibility Analysis
- Codebase Observations
- Codebase Bloat Audit
- Test Suite Audit
- Documentation Coverage Audit
- ThirdParty Dependencies Audit
- Load Test Baseline
- Gameplay Systems Status
- SparkGame Module Status
- Stub and Abandoned Features
- Memory Integrity System
- Memory Safety Evaluation
- Hardware Acceleration Systems
- Jolt Physics Integration
- GPU/CPU Separation Plan
- Daemon Services Architecture
- Reflection & Polymorphism Refactoring Plan
- SparkBuild In-Tree
- Wine No-JobSystem Breakthrough
- Wine Role and Fallback Tiers