Editor built with Blazor Server + Ultralight WebView.
- Overview
- Design Goals
- Current Status
- Architecture
- Features
- Tech Stack
- Supported Platforms
- Build and Run
- Quick Start
- Roadmap
- Contributing
- License
How It Works - ARCHITECTURE.md
A cross-platform 3D game engine written in C# targeting .NET 10. The runtime is built on Vulkan for rendering and SDL3 for windowing and input. An editor is included, powered by an in-process Blazor Server rendered through an embedded Ultralight WebView overlay composited into the Vulkan pipeline.
The engine features a Bevy-inspired staged execution loop with a parallel scheduler, a cache-friendly sparse-set ECS, and an attribute-based behavior system driven by a Roslyn source generator. You can author gameplay logic in two ways:
- Behavior system (attribute-based): mark a struct with
[Behavior], add methods with stage attributes like[OnUpdate], and the generator wires them into the schedule automatically. - Native ECS style: manually add systems to stages and work with
EcsWorldqueries andEcsCommands.
- Ergonomic ECS - Lightweight world + staged schedule; attribute-driven behaviors with run conditions and keyboard toggles to minimize boilerplate.
- Explicit Rendering - Vulkan-first with a structured extract → prepare → queue → graph pipeline; no hidden abstractions.
- Parallel by Default - Resource-access metadata on
SystemDescriptorenables automatic parallel batching within stages; conservative fallback for unannotated systems. - Extensibility - Plugins compose engine services; source generation handles repetitive registration; typed event queues for decoupled communication.
- Cross-Platform - Linux, Windows, and macOS (MoltenVK) targeted with minimal platform-specific code in user land.
- Separation of Concerns - Runtime (game loop, ECS, renderer) cleanly separated from editor tooling (Blazor Server, WebView, hot-reloadable shell scripts).
- Fast Iteration - Hot-reload for editor UI via Roslyn-based
ShellCompiler; inspectable runtime overlays via ImGui; structured logging to file and console.
The engine is in early preview. Core subsystems are functional but APIs are evolving and breaking changes are expected.
What works today:
- SDL3 windowing with Vulkan backend and SDL software-renderer fallback.
- Staged update loop with
Startup, per-frame stages (First→Last), andCleanup. - Parallel scheduler with resource-access batching, run conditions, and
ScheduleDiagnostics. - Sparse-set ECS with generational entity pool, multi-type queries, zero-allocation ref iterators, change tracking, and deferred command buffers.
- Behavior source generator supporting
[With]/[Without]/[Changed]filters,[RunIf]conditions, and[ToggleKey]keyboard shortcuts. - Vulkan graphics device (instance, physical device, logical device, swapchain, pipelines, buffers, images,
descriptors, sync) via Vortice.Vulkan + VMA.
NullGraphicsDevicefor headless runs and unit tests. - Render pipeline with extract → prepare → queue → render-graph execution model, including mesh rendering with
Camera,Mesh,Material, andTransformcomponents, opaque/transparent render phases, pipeline caching, dynamic buffer allocation, and per-object push constants. - Asset pipeline with background threaded loading, path deduplication, typed
Assets<T>storage,Handle<T>handles,AssetEvent<T>lifecycle events, pluggableIAssetLoader<T>/IAssetReadersources, and hot-reload via file watching. - GLSL → SPIR-V shader compilation (both standalone and as asset via
GlslLoader) and SPIR-V cross-reflection. - ImGui runtime overlays (performance HUD, schedule debug HUD, WebView debug HUD).
- Ultralight WebView overlay composited into the Vulkan render pipeline.
- Editor: in-process Blazor Server with hot-reloadable Razor/C# shell scripts, served through the embedded WebView.
- Typed event queues (
Events<T>,EventWriter<T>,EventReader<T>). - Structured multi-provider logging (console + file).
- Unit test suite covering core, ECS, graphics, renderer, and editor subsystems.
See Engine/Program.cs for the runtime entry point and Editor/Program.cs for the editor entry point.
3DEngine.sln
Engine.Application SDL3 window, input backend, ImGui host
│
Engine.Common ─── App, World, Schedule, Config, Logger,
│ Events, Time, Input, Stage
│
Engine.Entities ─ EcsWorld, EcsCommands, BehaviorContext,
│ Attributes, BehaviorsPlugin
│
Engine.Generator Roslyn source generator for [Behavior]
│
Engine.Files ──── AssetServer, Assets<T>, Handle<T>,
│ AssetEvent<T>, IAssetLoader<T>, IAssetReader,
│ FileAssetReader, FileWatcher, hot-reload
│
Engine.Graphics ─ Vulkan device, swapchain, pipelines,
│ buffers, images, SPIR-V compilation,
│ NullGraphicsDevice (headless/test)
│
Engine.Renderer ─ Renderer, RenderGraph, RenderWorld,
│ extract/prepare/queue systems, render phases,
│ Camera/Mesh/Material/Transform components,
│ PipelineCache, DynamicBufferAllocator, ImGui
│
Engine.WebView ── Ultralight integration, WebView overlay
│
Engine ────────── Composition root, DefaultPlugins,
│ sample behaviors (HUD, stress test)
│
Editor ────────── Editor entry point, ShellCompiler host
Editor.Server ─── Blazor Server (in-process), Razor pages
Editor.Shell ──── Shell registry, descriptors, builders
Editor.Compiler ─ Roslyn hot-reload compiler for shells
│
Tests ─────────── xUnit tests (Common, Entities, Graphics,
Renderer, Editor)
- Staged update loop -
Startup(once) →First→PreUpdate→Update→PostUpdate→Render→Last(per frame) →Cleanup(once on exit). - Parallel scheduler - Systems within a stage run in parallel batches based on declared
Read<T>/Write<T>resource-access metadata.ScheduleDiagnosticsprovides per-stage and per-system timing. - Cache-friendly ECS - Sparse-set storage, generational entity pool, per-frame bitset change tracking,
zero-allocation ref iterators, multi-type queries (up to 3),
TransformEach,ParallelTransformEach, and raw span access. - Behavior source generator -
[Behavior]structs with stage attributes ([OnStartup]through[OnCleanup]), component filters ([With],[Without],[Changed]), run conditions ([RunIf]), and keyboard toggles ([ToggleKey]). - Deferred commands -
EcsCommandsqueue spawn/despawn/add/remove operations, flushed automatically atPostUpdate. - Typed event system -
Events<T>queues withEventWriter<T>andEventReader<T>for decoupled, type-safe inter-system communication. - Plugin model -
DefaultPluginsaggregates:AssetPlugin,AppWindowPlugin,AppExitPlugin,ExceptionsPlugin,TimePlugin,InputPlugin,EcsPlugin,BehaviorsPlugin,SdlImGuiPlugin,SdlPlugin,VulkanWebViewPlugin,VulkanImGuiPlugin. Also registersGlslLoaderwith theAssetServer. - Vulkan graphics device - Instance creation, physical device selection, logical device, swapchain management,
pipeline creation, buffer/image allocation (VMA), descriptor sets, and synchronization primitives.
NullGraphicsDeviceprovides a no-op implementation for headless runs and unit tests. - Render pipeline - Extract → BeginFrame → Prepare → Graph execution (Update → auto-barrier → Run per node) →
EndFrame. Built-in extract systems (
CameraExtract,MeshMaterialExtract,ClearColorExtract), prepare systems (MeshPrepare,QueueMeshPhaseItems), and theMainPassNodewith mesh shader pipeline, per-object push constants (MeshPushConstants), camera UBO, andActiveSwapchainPasspattern (pass stays open for overlay nodes). Render components:Camera,Mesh,Material,Transform,RenderMeshInstance,ExtractedView. Render phases:Opaque3dPhase(front-to-back),Transparent3dPhase(back-to-front) withIPhaseItemandIDrawFunction<T>. GPU resource management:PipelineCachefor deduplicating compiled pipelines,DynamicBufferAllocatorfor frame-scoped transient GPU buffers,MeshGpuRegistryfor caching uploaded vertex buffers. - Asset pipeline -
AssetServerwith background threaded loading, path deduplication, typedAssets<T>storage,Handle<T>handles,AssetEvent<T>lifecycle events (Added,Modified,LoadedWithDependencies), pluggableIAssetLoader<T>/IAssetReadersources (FileAssetReader,EmbeddedAssetReader), dependency tracking, and hot-reload viaFileAssetWatcher. Built-in loaders:ByteArrayLoader,StringLoader,GlslLoader(GLSL → SPIR-V as asset). - Shader pipeline - GLSL → SPIR-V compilation via
Vortice.ShaderCompiler; SPIR-V cross-reflection viaVortice.SpirvCross. - ImGui overlays - Performance HUD (FPS, frame time, entity count), schedule debug HUD (batch composition,
conflict notes), and WebView debug HUD. Togglable via
[ToggleKey]. - WebView overlay - Ultralight-based HTML/CSS/JS rendering composited into the Vulkan pipeline with full SDL3 input forwarding.
- Structured logging - Multi-provider logging (console with ANSI colors, file output) with category scoping,
severity levels (
TracethroughCritical), and frame-level trace suppression.
- Blazor Server - In-process ASP.NET Core host serving a Razor component tree over SignalR WebSocket.
- Embedded WebView - Ultralight renders the Blazor UI directly inside the SDL3/Vulkan engine window.
- Hot-reloadable shells -
ShellCompilerwatches.cs/.razor/.cssfiles, recompiles via Roslyn on change, and hot-swaps editor panels without restarting. - Shell registry -
ShellRegistry+ShellDescriptorsystem for dynamically discovered editor panels and inspectors. - Single process - Engine and editor run in one process; Blazor Server on a background thread, SDL3/Vulkan on the main thread.
| Component | Library / Package | Purpose |
|---|---|---|
| Windowing & Input | SDL3-CS (preview) | Cross-platform window, input, audio |
| GPU API | Vortice.Vulkan 3.2.1 | Vulkan bindings |
| Memory Allocator | Vortice.VulkanMemoryAllocator 1.7.0 | GPU memory management (VMA) |
| Shader Compilation | Vortice.ShaderCompiler 1.9.0 | GLSL → SPIR-V |
| Shader Reflection | Vortice.SPIRV 1.0.5 + Vortice.SpirvCross 1.5.4 | SPIR-V cross-reflection |
| Debug UI | Twizzle.ImGui-Bundle.NET 1.91.5.2 | ImGui runtime overlays |
| Asset Import | AssimpNet 5.0.0-beta1 | 3D model import (FBX, glTF, OBJ, …) |
| Scene Interchange | UniversalSceneDescription 6.0.0 | USD scene format |
| WebView | UltralightNet (vendored) | HTML/CSS/JS overlay in Vulkan |
| Editor UI | BlazorBlueprint Components | Blazor component library |
| Hot Reload | Editor.Compiler (Roslyn-based) | Runtime recompilation of shell scripts |
| Serialization | Newtonsoft.Json 13.0.5 | Configuration and data serialization |
| Source Generator | Engine.Generator (Roslyn) | [Behavior] system code generation |
| Platform | Status | Notes |
|---|---|---|
| Linux | Supported | X11 and Wayland via SDL3. Requires recent Vulkan drivers (Mesa / NVIDIA / AMD). |
| Windows | Supported | Vulkan-capable GPU + drivers. |
| macOS | Experimental | Via MoltenVK (Vulkan portability). |
Prerequisites:
- .NET 10 SDK (preview SDK may be required).
- A working Vulkan driver/runtime for your GPU.
Clone and build:
git clone https://github.com/CanTalat-Yakan/3DEngine.git
cd 3DEngine
# Restore and build all projects
dotnet build
# Run the engine runtime
dotnet run --project Engine
# Run the editor
dotnet run --project EditorOpen in an IDE (Rider / Visual Studio / VS Code) using 3DEngine.sln.
Run tests:
dotnet testNotes:
- Native binaries for SDL3, ImGui, and Ultralight are bundled via NuGet. On Linux you still need standard system libraries (X11/Wayland, audio, etc.) and up-to-date GPU drivers.
- If Vulkan initialization fails, verify your driver installation and ensure validation layers are either installed or disabled.
- The editor requires the Blazor Server port (
http://localhost:5000by default) to be available.
[Behavior]
public struct Spinner
{
public float Angle;
[OnStartup]
public static void Spawn(BehaviorContext ctx)
{
var e = ctx.Ecs.Spawn();
ctx.Ecs.Add(e, new Spinner { Angle = 0f });
}
[OnUpdate]
public void Tick(BehaviorContext ctx)
{
Angle += (float)ctx.Time.DeltaSeconds * 90f;
Console.WriteLine($"Entity {ctx.EntityId} angle: {Angle:0.00}°");
}
}- Add the struct to any project that references
Engine.Entities. - Build - the source generator emits systems automatically.
- Run - the behavior executes per entity each frame. No manual registration needed.
var config = Config.GetDefault(
title: "My Game",
width: 1280,
height: 720,
graphics: GraphicsBackend.Vulkan);
new App(config)
.AddPlugin(new DefaultPlugins())
.AddPlugin(new GamePlugin())
.Run();
public sealed class GamePlugin : IPlugin
{
public void Build(App app)
{
app.AddSystem(Stage.Startup, world =>
{
var ecs = world.Resource<EcsWorld>();
var e = ecs.Spawn();
ecs.Add(e, new Spinner { Angle = 0f });
});
app.AddSystem(Stage.Update, new SystemDescriptor(world =>
{
var ecs = world.Resource<EcsWorld>();
var time = world.Resource<Time>();
foreach (var (e, spinner) in ecs.Query<Spinner>())
{
var s = spinner;
s.Angle += (float)time.DeltaSeconds * 45f;
ecs.Update(e, s);
}
}, "GamePlugin.SpinnerUpdate")
.Read<Time>()
.Write<EcsWorld>());
}
}- Platform layer (SDL3 windowing, input, timing)
- Vulkan device initialization, swapchain, VMA allocations
NullGraphicsDevicefor headless runs and unit tests- Render pipeline (extract/prepare/queue/graph model) with mesh rendering
- Render components: Camera, Mesh, Material, Transform
- Render phases (opaque front-to-back, transparent back-to-front)
- GPU resource management: PipelineCache, DynamicBufferAllocator, MeshGpuRegistry
- SPIR-V shader compilation and reflection
- Asset pipeline: AssetServer, background loading, typed storage, handle deduplication, hot-reload
- Built-in asset loaders (ByteArray, String, GlslLoader)
- Sparse-set ECS with generational entity pool and change tracking
- Behavior source generator with filters, run conditions, toggle keys
- Parallel scheduler with resource-access batching
- ImGui runtime overlays
- WebView overlay (Ultralight + Vulkan compositing)
- Editor scaffolding (Blazor Server, hot-reloadable shells)
- Typed event system
- Structured logging (console + file)
- Unit test suite (Common, Entities, Graphics, Renderer, Editor)
- Material system with PBR shading and lighting
- Scene graph and serialization (USD integration)
- Editor tools: dockable panes, inspectors, scene view, property editors
- Asset import loaders (Assimp: FBX, glTF, OBJ), texture loaders, asset packaging and caching
- Compute workloads (culling, particles, post-processing)
- Audio system
- Physics integration
- Networking
- Shader hot-reload
- CI/CD: cross-platform builds, automated formatting, linting
- Comprehensive documentation and samples
Items are aspirational and subject to change as the project evolves.
Early days! If you want to help:
- Try building and running on your platform and open issues for any rough edges.
- Propose small, well-scoped PRs (build scripts, docs, samples, or isolated subsystems).
- Keep changes platform-agnostic when possible.
By participating, you agree to abide by our Code of Conduct.
Code: MPL-2.0 license. See LICENSE for the full text.
Contributions: By submitting a contribution, you agree to license your contribution under the same license as this repository.