Project Overview
I started this project because I wanted to challenge myself to build a 3D engine from scratch and better understand the architecture behind games like Half-Life 2 and Source-era FPS titles.
Rather than relying on an existing engine like Unity or Unreal, this project explores how to build a custom runtime with explicit systems for rendering, input, timing, simulation, and debug tooling.
The core goals are to keep engine and game code cleanly separated, support fast compile times and iteration, and create a structure that can later grow into editor tooling, level workflows, and reusable runtime systems.
Key Features
- Custom engine architecture with no Unity or Unreal dependency
- Clear separation between engine and game code
- Cross-API rendering via Veldrid
- Immediate-mode debug UI with ImGui
- FPS-style camera and movement foundations
- Fixed-timestep simulation loop
- SDL2 windowing and input handling
- Fast-iteration and editor-friendly project structure
Architecture
The solution is split into clearly defined projects so that systems stay modular and responsibilities remain explicit. This makes the structure easier to reason about, faster to iterate on, and more scalable over time.
- Engine.Core: Math, time, and shared utilities.
- Engine.Platform: Windowing, input, and OS abstraction.
- Engine.Render: Rendering, shaders, and GPU resources.
- Engine.Runtime: Engine host, main loop, and lifecycle management.
- Game: Game-specific code that consumes engine APIs without modifying internals.
One of the main design goals is to avoid engine–game coupling. The game layer should use the engine through clear APIs, rather than reaching into internal systems directly.
Runtime Flow
The runtime is structured around a professional-style main loop with explicit stages for platform events, input updates, per-frame updates, fixed-step simulation, rendering, and debug UI.
- Engine creates the window and graphics device
- Game module is initialised
- OS events are pumped each frame
- Input is updated
- Per-frame update runs
- Fixed-timestep simulation runs
- World rendering runs
- ImGui debug UI is rendered
- Engine shuts down cleanly and disposes resources
This mirrors the kind of runtime flow used in professional engines and keeps each step explicit and easier to debug.
Rendering, Input, and Camera
Rendering is handled through Veldrid, which provides a backend-agnostic graphics layer. The current implementation targets Direct3D11 on Windows and uses explicit command lists and pipelines.
- Rendering: Backend-agnostic via Veldrid, with separated world rendering and ImGui rendering.
- Input: SDL2-based input with relative mouse handling for FPS-style control.
- Camera: Source-inspired movement foundations with camera logic cleanly decoupled from rendering.
- Simulation: Fixed-timestep movement and runtime update flow.
The rendering side is also intended to expand further into depth buffering, multiple render passes, debug overlays, and editor gizmos.
Current Status
The engine is actively being developed and already has several core systems working.
Implemented:
- Engine / game separation
- Windowing and input
- Rendering pipeline
- ImGui integration
- FPS camera and movement foundations
Planned:
- Depth buffer and resize handling
- Basic level geometry
- In-game editor tools
- Scene serialization
- Hot-reloadable content
- Asset pipeline improvements
Motivation
This project exists to deepen my understanding of real engine architecture, avoid black-box workflows, and build reusable systems from a lower level than typical game-engine development.
It is also a strong technical learning project for demonstrating engine-level knowledge, runtime design, and architecture decisions in a portfolio and interview setting.