MIT License NuGet

Home / Why SeasonEngine

Why SeasonEngine

A C# renderer with a modern feature set, one API across six platforms, and a source tree small enough that you can read the part you are debugging. MIT licensed, no editor, no asset pipeline, no runtime fee.

It exists because one specific option does not exist elsewhere: a maintained, pure-C#, editor-free engine with a current-generation renderer. Below that line are the bindings — excellent ones — where you get a device and a command list and write the other forty thousand lines yourself. Above it are the engines with editors, where a 3D window costs you a project format, an import pipeline and a large install. SeasonEngine is the layer in between: the renderer is done, the application shell is done, and the code is yours to read.

One API, four backends, six platforms

You write against Season.Controls and Season.Rendering. The backend is chosen by the target framework, not by your code.

PlatformBackendTarget framework
WindowsDirect3D 12net10.0-windows10.0.19041.0
LinuxVulkannet10.0
AndroidVulkannet10.0-android
iOSMetalnet10.0-ios
macOSMetalnet10.0-maccatalyst
BrowserWebGPUnet10.0-browser

The same is true of windowing, input, storage and fonts — each has one interface and a per-platform implementation under Season/Platforms. Your application project does not reference a platform namespace at all. See Cross-platform isolation for how that boundary is enforced, and where it currently leaks.

The renderer is modern, not minimal

"Small engine" usually means forward rendering, a single shadow map and a Lambert term. This one ships the techniques you would otherwise spend a year on.

  • Metallic-roughness PBR with image-based lighting
  • Cascaded sun shadows with soft filtering
  • Ground-truth ambient occlusion, on compute
  • Dynamic diffuse global illumination with SDF tracing
  • Physical sky, aerial perspective and volumetric clouds
  • Temporal anti-aliasing with a sharpening resolve
  • HDR scene colour, bloom and tone mapping
  • Skinned animation, GPU instancing, ray-based picking

Every one of those is a compute or raster pass you can inspect, disable or replace through the public RenderQuality and FrameSchedule API. The feature tour lists what is shipped, what is partial and what is missing, with the same badges throughout.

The integration is the product

None of these techniques is a secret, and the graphics API bindings underneath are somebody else's excellent work. What is scarce is the assembly: PBR, glTF skinning, cascaded shadows, DDGI, GTAO, TAA, a dynamic sky, MSDF text and 2D sprites all working together, on four graphics APIs, behind one coherent API surface. That is the part that takes years and the part that is being offered.

Many objects, declared rather than drawn

There are no Draw calls to write. You declare a control and the engine owns the batching, the culling and the ordering. An InstancedModel is one control holding a list of transforms, so a field of animated units is a list you add to.

var crowd = new InstancedModel { ModelName = "Assets/robot.glb" };

for (int i = 0; i < count; i++)
    crowd.Instances.Add(new MeshInstanceTransform
    {
        PosX = x, PosY = 0f, PosZ = z,
        AnimationClip = walk,   // clip index
        AnimationTimeOffset = Random.Shared.NextSingle() * 2f
    });

AddControl(crowd);

The comparison worth making here is with the alternative in editor-based engines. Unity can certainly reach high entity counts — through DOTS, a second paradigm with its own memory model that you largely restructure your project around. This gives you a useful share of that from ordinary C#, with no second paradigm to adopt.

This claim has no published benchmark yet

"Useful share" is the honest word until there are numbers next to it. A measured units-versus-frame-time figure is on the list and is not on this site, so treat the paragraph above as an architectural argument rather than a measurement. The mechanism is real and documented in Instancing; the quantity is not yet published.

One implementation per domain

Most engines accrete options. This one refuses them, and the refusal is the design.

DomainThe one implementationWhat is deliberately absent
Models and animationglTFFBX, OBJ, a proprietary mesh format
TextMSDF atlasesBitmap fonts, a second rasteriser path
Graphics APIOne per platformOpenGL and WebGL fallbacks
Platform divergenceDeviceServices#if forests in engine code

The benefit is that there is one code path to understand, one to optimise and one that can be wrong. The cost is that if your assets are FBX, you convert them; if your target device has no Vulkan, there is no fallback to drop to. Both of those are real, and both are on How it compares.

A scene is a C# class

There is no scene file, no prefab, no .meta sidecar and no GUID registry. A panel constructs its controls, and a control is an object with properties.

internal class Island : Panel
{
    internal Island()
    {
        AddControl(new Model
        {
            Name = "Assets/island.glb",
            PosX = 0f, PosY = 0f, PosZ = 0f,
            Width = 40f
        });
    }
}

This is a smaller claim than it sounds and a larger benefit than it sounds. It means your scene diffs in a pull request. It means a merge conflict is a merge conflict in C#, not in a binary asset. It means the same loop, condition or helper method you would write in any other C# code works here, because there is no separate authoring language to cross into.

The cost of that, stated plainly

No editor means no drag-to-place, no visual material graph and no live inspector. Positioning is typing numbers, building, looking. The reference application answers this with an in-app object picker that prints the transform of whatever you click, so the loop is at least short — but it is still a loop. If your work is mostly visual arrangement, an editor-based engine will beat this, and How it compares says so.

Small enough to read

The engine is 232 C# files, roughly 119,000 lines, MIT licensed. Shaders are embedded strings in the effect classes that own them, so there is no shader build step, no offline compiler in your build and nothing to keep in sync between a .hlsl file and the code that dispatches it.

That size is the actual feature. When ambient occlusion looks wrong you open Season/Rendering/Effects/Gtao.cs, read the kernel, and change it. You do not file an issue and wait for a release. The classes carry long explanatory comments — the reasoning behind a magic number is next to the number — which is also where most of this documentation came from.

Dependencies are few and deliberate: Silk.NET for the D3D12 and Vulkan bindings, SharpGLTF for glTF parsing, GtkSharp for Linux windowing, and an MSDF font atlas package. There is no plugin marketplace to be locked into and no telemetry to turn off.

Extensible at the interesting layer

The built-in effects use the same public API you would. TAA, bloom, GTAO and DDGI are all ComputeEffect subclasses registered through FrameSchedule.RegisterCompute. There is no privileged internal path, so an effect you write has exactly the capabilities the shipped ones have — including reading scene colour, depth and velocity, and publishing a named texture that the rest of the frame consumes.

Practically, that also makes debugging cheap: every intermediate texture has a name, and a Sprite2D draws a texture by name. See Compute effects.

And local AI, because it is the same problem

Shipping an ONNX or GGML model inside a desktop application runs into the same class of problem as shipping a renderer: version drift, native dependencies, and a CUDA stack that is difficult to package. The AI layer exists to make that a solved build configuration rather than a research project, with the same rule as the renderer — if the hardware cannot do it, the feature declines cleanly instead of crashing.

The local AI layer explains what is available today, and is honest about the parts that live outside this repository.

Version 0.2.0, and what that means

The engine is pre-1.0 and the version number is not modesty. APIs move between releases, some features are Windows-first, and a few of the platform targets are better tested than others. The documentation on this site marks state explicitly rather than describing intentions as capabilities.

Shipped Partial Not yet

If a page here does not carry one of those, it is because everything on it is shipped.

Where to start