3DEngine 4.0.1
dotnet add package 3DEngine --version 4.0.1
NuGet\Install-Package 3DEngine -Version 4.0.1
<PackageReference Include="3DEngine" Version="4.0.1" />
<PackageVersion Include="3DEngine" Version="4.0.1" />
<PackageReference Include="3DEngine" />
paket add 3DEngine --version 4.0.1
#r "nuget: 3DEngine, 4.0.1"
#:package 3DEngine@4.0.1
#addin nuget:?package=3DEngine&version=4.0.1
#tool nuget:?package=3DEngine&version=4.0.1
<p align="center" style="text-align:center"> <img src="Images/3DEngineIcon.png" alt="3D Engine Icon" width="256"/> </p>
<h1 align="center" style="text-align:center">3D Engine</h1> <h4 align="center" style="text-align:center">C# 3D Game Engine (Vulkan + SDL3).</h4> <p align="center" style="text-align:center">Editor planned with Avalonia UI.</p>
<p align="center" style="text-align:center"> <img alt=".NET" src="https://img.shields.io/badge/.NET-10.0-512BD4"> <img alt="Graphics API" src="https://img.shields.io/badge/Graphics-Vulkan-AC162C"> <img alt="Windowing" src="https://img.shields.io/badge/Windowing-SDL3-0B7BB2"> </p>
<p align="center" style="text-align:center"> <img alt="Status" src="https://img.shields.io/badge/Status-Early%20Preview-yellow"> <img alt="Platforms" src="https://img.shields.io/badge/Platforms-Linux%20%7C%20Windows%20%7C%20macOS-lightgrey"> </p>
- Overview
- Design Goals
- Current Status
- Features
- Tech Stack
- Supported Platforms
- Build and Run
- Quick Start
- How It Works
- Roadmap (high-level)
- Contributing
- License
Overview
This repository is the restart of a cross‑platform 3D engine written in C#. The runtime is being built on Vulkan for rendering and SDL3 for windowing/input. An editor built with Avalonia UI is planned but not implemented yet.
The runtime already includes a minimal ECS and a behavior system powered 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. - Native ECS style: manually add systems to stages and work with
ECSWorldqueries andECSCommands.
Design Goals
- Ergonomic ECS: Lightweight world + staged schedule inspired by Bevy; attribute-driven behaviors to reduce boilerplate.
- Explicit Rendering: Vulkan-first with a modern resource and synchronization model; avoid hidden abstractions.
- Extensibility: Plugins compose engine services; source generation handles repetitive registration tasks.
- Cross‑Platform: Linux, Windows, macOS (MoltenVK) targeted with minimal platform-specific code in user land.
- Separation of Concerns: Runtime (game loop, ECS, renderer) separate from future editor (Avalonia UI) tooling layer.
- Fast Iteration: Hot‑reload ambitions for shaders/assets; clear, inspectable runtime overlay via ImGui.
Current Status
- SDL3 bootstrap that creates a window and drives a staged update loop.
- Vulkan and related native dependencies are wired via NuGet (Vortice.* and SDL3‑CS bundles).
- ECS core (entities/components, simple queries) and a behavior source generator that auto-registers systems.
- ImGui runtime overlay is available for diagnostics.
- APIs are evolving; breaking changes are expected.
See Engine/Program.cs for usage examples.
Features
Implemented (early preview):
- Staged update loop (Startup → First → PreUpdate → Update → PostUpdate → Render → Last)
- Cache-friendly ECS (sparse-set storage, per-frame bitset change tracking, zero-allocation ref iterators)
- Attribute-based behavior system with Roslyn source generator
- Basic plugin model (
DefaultPlugins) for window/time/input/ECS/ImGui - ImGui runtime overlay integration
- Vulkan device + window initialization scaffolding (rendering pipeline WIP)
In Progress / Planned (see roadmap for detail):
- Renderer: swapchain, command buffers, descriptor sets, shader reflection
- Asset pipeline: import, packaging, caching
- Scene graph & serialization (USD integration)
- Editor (Avalonia) with dockable tools & inspectors
- Job system & parallelism
Tech Stack
- SDL3 + SDL3‑CS: cross‑platform windowing, input, and basic rendering bootstrap.
- Vulkan via Vortice.Vulkan and VMA: modern, explicit GPU API and memory allocator.
- SPIR‑V toolchain (Vortice.SPIRV, SpirvCross): shader compilation and reflection.
- ImGui bundle: debug and tooling UI (runtime overlay; editor planned separately).
- AssimpNet: asset import for common 3D formats (planned integration).
- USD.NET / UniversalSceneDescription: scene and asset interchange (planned integration).
- Newtonsoft.Json: configuration and serialization utilities.
Supported Platforms
- Linux: X11 and Wayland supported via SDL3. Ensure recent Vulkan drivers (Mesa/NVIDIA/AMD).
- Windows: Vulkan-capable GPU + drivers. No WinUI/WinAppSDK dependency; editor will use Avalonia.
- macOS: via Vulkan portability (MoltenVK) as available through dependencies. Status: experimental.
Build and Run
Prerequisites:
- .NET SDK matching
TargetFramework(seeEngine/Engine.csproj, currentlynet10.0). Preview SDK may be required. - A working Vulkan driver/runtime for your GPU.
Clone + build:
# Clone
git clone https://github.com/CanTalat-Yakan/3DEngine.git
cd 3DEngine
# Restore & build all projects
dotnet build
# Run the engine sample (runtime entry point)
dotnet run --project Engine
Open in an IDE (Rider/VS/VSCode) using 3DEngine.sln if you prefer.
Notes:
- Native binaries for SDL3 and related libraries are bundled via NuGet. On Linux you still need standard system libs ( 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.
Quick Start
An automatic minimal behavior + system example:
[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; // 90 deg/s
Console.WriteLine($"Entity {ctx.EntityID} angle now {Angle:0.00}");
}
}
- Add the struct in any runtime project.
- Build: the source generator emits systems automatically.
- Run: the console prints per-frame updates from the behavior.
To add a manual system instead:
public sealed class Program
{
[STAThread]
private static void Main()
{
new App(Config.GetDefault())
.AddPlugin(new DefaultPlugins())
.AddPlugin(new SamplePlugin())
.Run();
}
}
public sealed class SamplePlugin : 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, (world) =>
{
var ecs = world.Resource<EcsWorld>();
foreach (var (e, spinner) in ecs.Query<Spinner>())
{
var newSpinner = spinner;
newSpinner.Angle += (float)world.Resource<Time>().DeltaSeconds * 45f;
ecs.Update(e, newSpinner);
}
});
}
}
How It Works
Stages and the Schedule
The engine drives a Bevy-like staged loop (Source/App/Stage.cs):
Startup(once), then per frame:First→PreUpdate→Update→PostUpdate→Render→Last.- Systems are
SystemFn(World world)delegates added to stages viaApp.AddSystem(stage, system)and executed bySchedule.
Plugins
Plugins configure the app and register systems. DefaultPlugins wires everything you typically need:
- Window, time, input, events
- ECS world/commands and a post-update command application pass
- Auto-registration of generated behavior systems (see below)
- Kernel/ImGui setup and a clear-color system
Resources
World is a simple resource container (Bevy-style). Insert and fetch singletons by type:
app.InsertResource(new MyService())orworld.InsertResource(value)world.Resource<T>()to retrieve; throws if missingBehaviorContext.Res<T>()is a shortcut forworld.Resource<T>()
Common resources used by systems/behaviors:
EcsWorld– entity/component storage and queriesEcsCommands– queued mutations applied afterUpdate(atPostUpdate)AppWindow,Time,GUIRenderer, etc.
ECS: Entities, Components, and Commands
- Entities are
intIDs only (no public handle type). Create withvar id = ecs.Spawn();and remove withecs.Despawn(id);. - Component APIs (ID-only):
Add<T>(id, comp),Update<T>(id, comp),TryGet<T>(id, out comp),Has<T>(id),Remove<T>(id). - Queries:
ecs.Query<T>(),ecs.Query<T1,T2>(),ecs.Query<T1,T2,T3>()iterate matching entities. Joins walk the smallest set for speed. - Mutations can be immediate or queued via
EcsCommands(ID-only):Spawn,Add<T>,Despawn. Commands are applied inPostUpdate. - Disposal: On
Despawn, components that implementIDisposableare disposed.
Beyond Query, the ECS exposes zero-allocation iteration and transforms for hot loops:
- In-place ref iteration:
foreach (var rc in ecs.IterateRef<T>()) { rc.Component ... }(marks changed automatically). - Transform helpers:
TransformEach<T>((id, c) => { /* mutate */ return c; })ParallelTransformEach<T>((id, c) => { /* mutate */ return c; })
- Span access:
var span = ecs.GetSpan<T>();returns entities/components spans for tight loops (manual marking recommended).
See also: ECS Iteration Modes, Change Tracking, and Entity Generations.
ECS Iteration Modes: Query vs IterateRef vs GetSpan
- Query<T>/Query<T1,T2[,T3]>:
- Returns value tuples; component structs are copied when iterating.
- Easy and LINQ-friendly; good for read-only scans or when you call
Updateafter changing a local copy. - Does not mark components as changed.
- IterateRef<T>/IterateRef<T1,T2>:
- Zero-allocation ref enumerators; returns refs to live component storage for in-place mutation.
- Marks components as changed while iterating (suitable for systems that mutate frequently).
- Ref structs can’t be stored/escaped; use immediately inside the loop.
- GetSpan<T>:
- Returns
(ReadOnlySpan<int> Entities, Span<T> Components)for manual indexed loops. - Doesn’t mark changed by itself; combine with
TransformEach<T>(no-op transform) to mark, or callUpdate.
- Returns
Examples:
// Read-only query
foreach (var (e, comp) in ecs.Query<Position>())
{
// inspect comp
}
// In-place mutation with IterateRef (marks changed)
foreach (var rc in ecs.IterateRef<Velocity>())
{
rc.Component.dx += 1;
}
// Transform helper (marks changed)
ecs.TransformEach<Position>((e, p) => { p.x += 1; return p; });
// Parallel transform (marks changed)
ecs.ParallelTransformEach<Position>((e, p) => { p.x += 1; return p; });
// Spans (manual marking)
var span = ecs.GetSpan<Mass>();
for (int i = 0; i < span.Entities.Length; i++)
{
span.Components[i].value *= 2;
}
// mark all as changed without altering values
ecs.TransformEach<Mass>((e, m) => m);
Change Tracking
- Each component store maintains a per-entity “changed this frame” bitset.
- The bit is set when you
Update, when aTransformEachwrites, or as you iterate viaIterateRef. Changed<T>(id)reads the bit; bits are cleared atBeginFrame()(stageFirst).
Entity Generations
- The world tracks a generation counter per entity ID internally to guard against stale IDs.
- On
Despawn(id), the generation for that ID is incremented and the ID is added to a free list for reuse. - Public API remains ID-only. For diagnostics or tooling, you can inspect the current generation via
ecs.GetGeneration(id).
ECS Internals and File Layout
- Storage: Sparse-set layout (sparse index + dense arrays for entities and components) — cache-friendly, O(1) lookups.
- Changed flags: Compact bitset aligned to dense storage; cleared per frame.
- Type lookup: One store per component type with direct casting (no interfaces in hot loops).
- File split (partial class):
EcsWorld.cs– entity lifecycle (spawn/despawn), frame management, counts, and entity listsEcsWorld.Components.cs– component storage, CRUD, spans, and single-type queryEcsWorld.Queries.cs– multi-type queries and predicatesEcsWorld.RefIterators.cs– ref iterators, transforms, and parallel transforms
Behavior System (Attribute-based ECS)
Author gameplay in a script-like way:
- Mark a struct with
[Behavior]. - Add methods and mark when they should run using attributes:
[OnStartup],[OnFirst],[OnPreUpdate],[OnUpdate],[OnPostUpdate],[OnRender],[OnLast].
- Optionally add filters on instance methods:
[With(typeof(Position), typeof(Velocity))][Without(typeof(Disabled))][Changed(typeof(Transform))]
- Note: The current generator supports
Withjoins of up to two component types. If more are specified, it falls back to querying only the behavior component and appliesWithout/Changedchecks inside the loop.
Static vs Instance methods:
- Static methods run once per stage invocation and receive
BehaviorContext. - Instance methods run per entity that has this behavior component. They can use fields/properties on
this. The generator:- Iterates
ecs.Query<YourBehavior>() - Sets
ctx.EntityID - Calls your method
- Writes back the component with
ecs.Update
- Iterates
Creating entities for instance behaviors:
- Instance methods only run if at least one entity has that behavior. A common pattern is a static
[OnStartup]to spawn and add the behavior component.
Access to engine services:
- Use
ctx.Res<T>()for other resources (e.g.,Time,Input, etc.). ctx.Ecsandctx.Cmdprovide ECS access.
Reference types inside behavior structs:
- Safe and supported. Storing a class reference in your behavior struct allows complex per-entity state without copying
large data. Initialize lazily or in
[OnStartup]as needed.
Examples:
using ImGuiNET;
[Behavior]
public struct HUDOverlay
{
[OnUpdate]
public static void Draw(BehaviorContext ctx)
{
ImGui.Begin("HUD");
ImGui.Text($"FPS: {(1.0 / ctx.Time.DeltaSeconds):0}");
ImGui.End();
}
}
[Behavior]
public struct Spawner
{
public float a;
private float b { get; set; }
[OnStartup]
public static void Init(BehaviorContext ctx)
{
var e = ctx.Ecs.Spawn();
ctx.Ecs.Add(e, new Spawner { a = 1.0f });
}
[OnUpdate]
public void Tick(BehaviorContext ctx)
{
b += (float)ctx.Time.DeltaSeconds;
Console.WriteLine($"Spawner running. a={a}, b={b}");
}
}
public class SomeDisposable : IDisposable
{
private float _num = 2;
public string Log() => _num.ToString();
public void Dispose()
{
// Cleanup resources
}
}
[Behavior]
public struct HeavyBehavior : IDisposable
{
private SomeDisposable _handle;
[OnStartup]
public static void Init(BehaviorContext ctx)
{
var e = ctx.Ecs.Spawn();
ctx.Ecs.Add(e, new HeavyBehavior { _handle = new SomeDisposable() });
}
[OnUpdate]
public void Tick(BehaviorContext ctx)
{
Console.WriteLine(_handle.Log());
}
public void Dispose()
{
_handle?.Dispose();
_handle = null;
}
}
Native ECS Style (Manual Systems)
Prefer writing systems directly? Use App.AddSystem and operate on EcsWorld:
app.AddSystem(Stage.Update, (World w) =>
{
var ecs = w.Resource<EcsWorld>();
foreach (var (e, comp) in ecs.Query<MyComponent>())
{
// mutate comp and write back
ecs.Update(e, comp);
}
});
You can mix and match: the behavior generator emits systems under the hood; you can still register hand-written systems alongside them.
Source Generator
Engine.SourceGen scans for [Behavior] structs and methods with stage attributes, then emits:
- Per-behavior static classes with stage entry points that call your methods (static or per-entity loops for instance methods).
- A
BehaviorsPluginthat registers those systems into the app.
DefaultPlugins includes BehaviorsPlugin, so behaviors are picked up automatically at build time—no manual
registration required.
FAQ
- Static vs Instance: Static methods run once per stage and are great for global logic/UI; instance methods run per entity and can use fields/properties on the component. structs.
- Struct lifetimes and disposal: Structs are value types; they aren't “destroyed” with a finalizer. If your struct holds
class references with unmanaged resources, implement
IDisposableon the struct and dispose those references inDispose(). The ECS will invokeDispose()for components onDespawn.
Roadmap (high-level)
- Core
- Robust platform layer (windowing, input, timing) on SDL3
- Vulkan renderer: swapchain, command submission, synchronization, VMA allocations
- Shader pipeline: SPIR‑V compilation, reflection, hot‑reload
- Asset pipeline: import (Assimp), packaging, and caching
- Scene graph and serialization (USD integration)
- ECS and job system
- Tooling
- Editor built with Avalonia UI (dockable panes, inspectors, scene view)
- ImGui runtime overlay for debugging
- Live reload for assets and scripts
- Systems
- Material system and PBR
- Compute workloads (culling, particles, post‑processing)
- Audio, physics, and networking (research and vendor selection TBD)
- CI/DevX
- Cross‑platform builds (Linux/Windows/macOS)
- Automated formatting, linting, and basic tests
Items are aspirational and subject to change as the project evolves.
Contributing
Early days! If you want to help:
- Try building/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.
A formal guideline will be added once the editor and initial subsystems land.
License
Code: MIT 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.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- 3DEngine.App (>= 1.0.1)
- 3DEngine.Core (>= 1.0.1)
- 3DEngine.Debug (>= 1.0.1)
- 3DEngine.ECS (>= 1.0.0)
- 3DEngine.Renderer (>= 1.0.2)
- 3DEngine.Window (>= 1.0.0)
- Newtonsoft.Json (>= 13.0.4)
- SDL3-CS (>= 3.3.2.1)
- SDL3-CS.Native (>= 3.3.2)
- SDL3-CS.Native.Image (>= 3.2.4)
- SDL3-CS.Native.Mixer (>= 2.8.1.1)
- SDL3-CS.Native.TTF (>= 3.2.2)
- Twizzle.ImGui-Bundle.NET (>= 1.91.5.2)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 4.0.1 | 272 | 11/16/2025 |
| 4.0.0 | 266 | 11/16/2025 |
| 3.1.0 | 360 | 10/30/2024 |
| 3.0.99 | 244 | 10/30/2024 |
| 3.0.98 | 248 | 10/30/2024 |
| 3.0.97 | 287 | 10/29/2024 |
| 3.0.96 | 286 | 10/29/2024 |
| 3.0.95 | 238 | 10/29/2024 |
| 3.0.94 | 239 | 10/29/2024 |
| 3.0.93 | 269 | 10/29/2024 |
| 3.0.92 | 248 | 10/29/2024 |
| 3.0.91 | 242 | 10/29/2024 |
| 3.0.90 | 249 | 10/29/2024 |
| 3.0.89 | 285 | 10/29/2024 |
| 3.0.88 | 252 | 10/29/2024 |
| 3.0.87 | 284 | 10/29/2024 |
| 3.0.86 | 250 | 10/29/2024 |
| 3.0.85 | 266 | 10/29/2024 |
| 3.0.84 | 233 | 10/29/2024 |
| 3.0.83 | 263 | 10/29/2024 |
| 3.0.82 | 242 | 10/27/2024 |
| 3.0.81 | 236 | 10/26/2024 |
| 3.0.80 | 272 | 10/26/2024 |
| 3.0.79 | 254 | 10/25/2024 |
| 3.0.78 | 260 | 10/24/2024 |
| 3.0.77 | 222 | 10/24/2024 |
| 3.0.76 | 251 | 10/24/2024 |
| 3.0.75 | 280 | 10/24/2024 |
| 3.0.74 | 283 | 10/23/2024 |
| 3.0.73 | 283 | 10/23/2024 |
| 3.0.72 | 278 | 10/23/2024 |
| 3.0.71 | 234 | 10/23/2024 |
| 3.0.70 | 231 | 10/21/2024 |
| 3.0.69 | 252 | 10/21/2024 |
| 3.0.68 | 262 | 10/21/2024 |
| 3.0.67 | 263 | 10/21/2024 |
| 3.0.66 | 220 | 10/21/2024 |
| 3.0.65 | 271 | 10/21/2024 |
| 3.0.64 | 234 | 10/21/2024 |
| 3.0.63 | 251 | 10/21/2024 |
| 3.0.62 | 267 | 10/21/2024 |
| 3.0.61 | 258 | 10/21/2024 |
| 3.0.60 | 239 | 10/21/2024 |
| 3.0.59 | 241 | 10/21/2024 |
| 3.0.58 | 216 | 10/21/2024 |
| 3.0.57 | 235 | 10/21/2024 |
| 3.0.56 | 247 | 10/21/2024 |
| 3.0.55 | 255 | 10/21/2024 |
| 3.0.54 | 278 | 10/19/2024 |
| 3.0.53 | 249 | 10/19/2024 |
| 3.0.52 | 313 | 10/19/2024 |
| 3.0.51 | 284 | 10/19/2024 |
| 3.0.50 | 324 | 10/18/2024 |
| 3.0.49 | 238 | 10/18/2024 |
| 3.0.48 | 255 | 10/17/2024 |
| 3.0.47 | 241 | 10/17/2024 |
| 3.0.46 | 211 | 10/17/2024 |
| 3.0.45 | 259 | 10/17/2024 |
| 3.0.44 | 251 | 10/17/2024 |
| 3.0.43 | 255 | 10/17/2024 |
| 3.0.42 | 251 | 10/17/2024 |
| 3.0.41 | 275 | 10/17/2024 |
| 3.0.40 | 270 | 10/17/2024 |
| 3.0.39 | 249 | 10/9/2024 |
| 3.0.38 | 253 | 10/9/2024 |
| 3.0.37 | 211 | 10/7/2024 |
| 3.0.36 | 221 | 10/7/2024 |
| 3.0.35 | 240 | 10/7/2024 |
| 3.0.34 | 230 | 10/3/2024 |
| 3.0.33 | 243 | 10/1/2024 |
| 3.0.32 | 269 | 10/1/2024 |
| 3.0.31 | 258 | 9/30/2024 |
| 3.0.30 | 236 | 9/30/2024 |
| 3.0.29 | 227 | 9/30/2024 |
| 3.0.28 | 234 | 9/28/2024 |
| 3.0.27 | 246 | 9/27/2024 |
| 3.0.26 | 284 | 9/26/2024 |
| 3.0.25 | 276 | 9/25/2024 |
| 3.0.24 | 226 | 9/25/2024 |
| 3.0.23 | 234 | 9/22/2024 |
| 3.0.21 | 243 | 9/19/2024 |
| 3.0.19 | 278 | 9/19/2024 |
| 3.0.18 | 241 | 9/18/2024 |
| 3.0.17 | 244 | 9/18/2024 |
| 3.0.16 | 277 | 9/18/2024 |
| 3.0.15 | 328 | 9/17/2024 |
| 3.0.14 | 241 | 9/17/2024 |
| 3.0.13 | 244 | 9/17/2024 |
| 3.0.12 | 292 | 9/15/2024 |
| 3.0.11 | 293 | 9/15/2024 |
| 3.0.10 | 249 | 9/15/2024 |
| 3.0.9 | 263 | 9/15/2024 |
| 3.0.8 | 256 | 9/15/2024 |
| 3.0.7 | 246 | 9/15/2024 |
| 3.0.6 | 245 | 9/15/2024 |
| 3.0.5 | 254 | 9/15/2024 |
| 3.0.4 | 267 | 9/15/2024 |
| 3.0.3 | 257 | 9/15/2024 |
| 3.0.2 | 264 | 9/11/2024 |
| 3.0.1 | 289 | 9/11/2024 |
| 3.0.0 | 267 | 9/8/2024 |
| 2.2.2 | 257 | 8/11/2024 |
| 2.0.2 | 434 | 3/7/2024 |
| 2.0.1 | 382 | 2/25/2024 |
| 2.0.0 | 432 | 2/25/2024 |
| 1.0.7 | 859 | 10/20/2023 |
| 1.0.6 | 320 | 10/20/2023 |
| 1.0.5 | 412 | 10/19/2023 |
| 1.0.4 | 369 | 10/18/2023 |
| 1.0.3 | 421 | 10/18/2023 |
| 1.0.2 | 395 | 10/18/2023 |
| 1.0.1 | 460 | 10/18/2023 |
| 1.0.0 | 411 | 10/13/2023 |