Brine2D.Engine 0.4.0-alpha

This is a prerelease version of Brine2D.Engine.
There is a newer prerelease version of this package available.
See the version list below for details.
dotnet add package Brine2D.Engine --version 0.4.0-alpha
                    
NuGet\Install-Package Brine2D.Engine -Version 0.4.0-alpha
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Brine2D.Engine" Version="0.4.0-alpha" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Brine2D.Engine" Version="0.4.0-alpha" />
                    
Directory.Packages.props
<PackageReference Include="Brine2D.Engine" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Brine2D.Engine --version 0.4.0-alpha
                    
#r "nuget: Brine2D.Engine, 0.4.0-alpha"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Brine2D.Engine@0.4.0-alpha
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Brine2D.Engine&version=0.4.0-alpha&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=Brine2D.Engine&version=0.4.0-alpha&prerelease
                    
Install as a Cake Tool

Brine2D

The ASP.NET of game engines - A modern .NET 10 game engine built on SDL3 for creating 2D games with C#.

Brine2D brings the familiar patterns and developer experience of ASP.NET to game development. If you've built web apps with ASP.NET, you'll feel right at home building games with Brine2D.

Features

  • Entity Component System (ECS) - ASP.NET-style system pipelines with automatic ordering ✨ NEW in 0.4.0
  • Input System - Keyboard, mouse, gamepad with polling and events
  • Sprite Rendering - Hardware-accelerated with sprite sheets and animations
  • Animation System - Frame-based with multiple clips and events
  • Audio System - Sound effects and music via SDL3_mixer
  • Scene Management - Async loading, transitions, and lifecycle hooks
  • Tilemap Support - Tiled (.tmj) integration with auto-collision
  • Collision Detection - AABB and circle colliders with spatial partitioning
  • Camera System - 2D camera with zoom, rotation, and bounds
  • Particle System - GPU-accelerated particle effects
  • UI Framework - Immediate-mode UI with theming and tooltips
  • Configuration - JSON-based settings with hot reload support
  • Dependency Injection - ASP.NET Core-style DI container
  • Logging - Structured logging with Microsoft.Extensions.Logging
  • Multiple Backends - SDL3 GPU (alpha) and Legacy renderer

Why Brine2D?

ASP.NET Developers Will Feel at Home

// Looks familiar? That's the point!
var builder = GameApplication.CreateBuilder(args);

// Configure services just like ASP.NET
builder.Services.AddSDL3Input();
builder.Services.AddSDL3Audio();

builder.Services.AddSDL3Rendering(options =>
{
    options.WindowTitle = "My Game";
    options.WindowWidth = 1280;
    options.WindowHeight = 720;
});

// Configure ECS systems like middleware (NEW!)
builder.Services.ConfigureSystemPipelines(pipelines =>
{
    pipelines.AddSystem<PlayerControllerSystem>();
    pipelines.AddSystem<AISystem>();
    pipelines.AddSystem<VelocitySystem>();
    pipelines.AddSystem<PhysicsSystem>();
    pipelines.AddSystem<SpriteRenderingSystem>();
});

// Register your scenes like controllers
builder.Services.AddScene<GameScene>();

var game = builder.Build();
await game.RunAsync<GameScene>();

Key Similarities to ASP.NET

ASP.NET Brine2D
WebApplicationBuilder GameApplicationBuilder
Controllers Scenes
Middleware ECS System PipelinesNEW
app.UseAuthentication() pipelines.AddSystem<T>()NEW
appsettings.json gamesettings.json
Dependency Injection Dependency Injection
ILogger<T> ILogger<T>
Configuration binding Configuration binding

Quick Start

Installation

Using NuGet (Recommended)

Create a new .NET 10 console project and add Brine2D:

dotnet new console -n MyGame
cd MyGame
dotnet add package Brine2D.Desktop --version 0.4.0-alpha

That's it! Brine2D.Desktop includes everything you need to start building games.

Package Options

For most users, install the meta-package:

dotnet add package Brine2D.Desktop

Advanced: Install only what you need:

# Core abstractions
dotnet add package Brine2D.Core
dotnet add package Brine2D.Engine
dotnet add package Brine2D.ECS  # NEW!

# Choose your implementations
dotnet add package Brine2D.Rendering.SDL
dotnet add package Brine2D.Input.SDL
dotnet add package Brine2D.Audio.SDL

# ECS bridges (optional)
dotnet add package Brine2D.Rendering.ECS  # NEW!
dotnet add package Brine2D.Input.ECS      # NEW!
dotnet add package Brine2D.Audio.ECS      # NEW!

Your First Game

Create Program.cs:

using Brine2D.Core;
using Brine2D.Hosting;
using Brine2D.Input;
using Brine2D.Input.SDL;
using Brine2D.Rendering;
using Brine2D.Rendering.SDL;
using Microsoft.Extensions.Logging;

// Create the game application builder
var builder = GameApplication.CreateBuilder(args);

// Configure SDL3 rendering
builder.Services.AddSDL3Rendering(options =>
{
    options.WindowTitle = "My First Brine2D Game";
    options.WindowWidth = 1280;
    options.WindowHeight = 720;
    options.VSync = true;
});

// Add SDL3 input
builder.Services.AddSDL3Input();

// Register your scene
builder.Services.AddScene<GameScene>();

// Build and run
var game = builder.Build();
await game.RunAsync<GameScene>();

// Define your game scene
public class GameScene : Scene
{
    private readonly IRenderer _renderer;
    private readonly IInputService _input;
    private readonly IGameContext _gameContext;

    public GameScene(
        IRenderer renderer,
        IInputService input,
        IGameContext gameContext,
        ILogger<GameScene> logger) : base(logger)
    {
        _renderer = renderer;
        _input = input;
        _gameContext = gameContext;
    }

    protected override void OnRender(GameTime gameTime)
    {
        _renderer.Clear(Color.CornflowerBlue);
        _renderer.BeginFrame();
        
        _renderer.DrawText("Hello, Brine2D!", 100, 100, Color.White);
        
        _renderer.EndFrame();
    }

    protected override void OnUpdate(GameTime gameTime)
    {
        if (_input.IsKeyPressed(Keys.Escape))
        {
            _gameContext.RequestExit();
        }
    }
}

Run your game:

dotnet run

Alpha Release Notice

⚠️ This is an alpha release (0.4.0-alpha)

What works:

  • Entity Component System (ECS)NEW!
  • System pipelines with automatic orderingNEW!
  • Prefabs and serializationNEW!
  • Transform hierarchy (parent/child)NEW!
  • Utility components (Timer, Lifetime, Tween)NEW!
  • ✅ Legacy rendering (sprites, primitives, text)
  • ✅ Input system (keyboard, mouse, gamepad)
  • ✅ Audio system
  • ✅ Animation system
  • ✅ Collision detection
  • ✅ Tilemap support
  • ✅ UI framework
  • ✅ Camera system
  • ✅ Particle system

What doesn't work yet:

  • ❌ GPU renderer (use Backend = "LegacyRenderer" in config)
  • ⚠️ Scene graph (partially implemented via ECS hierarchy)

Expect breaking changes before 1.0!


🆕 Entity Component System (ECS)

Brine2D 0.4.0 introduces a powerful ECS framework with ASP.NET-style system pipelines.

Creating Entities

using Brine2D.ECS;
using Brine2D.ECS.Components;
using System.Numerics;

// Create an entity
var player = _world.CreateEntity("Player");
player.Tags.Add("Player");

// Add components
var transform = player.AddComponent<TransformComponent>();
transform.Position = new Vector2(400, 300);

var velocity = player.AddComponent<VelocityComponent>();
velocity.MaxSpeed = 200f;

var sprite = player.AddComponent<SpriteComponent>();
sprite.TexturePath = "assets/player.png";

Using Prefabs (Reusable Templates)

using Brine2D.ECS;

// Create a prefab
var enemyPrefab = new EntityPrefab("Enemy");
enemyPrefab.Tags.Add("Enemy");

enemyPrefab.AddComponent<TransformComponent>();
enemyPrefab.AddComponent<SpriteComponent>(s => 
{
    s.TexturePath = "assets/enemy.png";
    s.Tint = new Color(255, 100, 100);
});
enemyPrefab.AddComponent<VelocityComponent>(v => v.MaxSpeed = 150f);
enemyPrefab.AddComponent<AIControllerComponent>(ai => 
{
    ai.Behavior = AIBehavior.Chase;
    ai.TargetTag = "Player";
});

// Register and instantiate
_prefabLibrary.Register(enemyPrefab);
var enemy = enemyPrefab.Instantiate(_world, new Vector2(500, 300));

Configuring System Pipelines (ASP.NET-style!)

using Brine2D.ECS.Systems;
using Brine2D.Rendering.ECS;
using Brine2D.Input.ECS;
using Brine2D.Audio.ECS;

// Configure like ASP.NET middleware!
builder.Services.ConfigureSystemPipelines(pipelines =>
{
    // Update systems (run every frame)
    pipelines.AddSystem<PlayerControllerSystem>();  // Order: 10 (input)
    pipelines.AddSystem<AISystem>();                // Order: 50 (AI)
    pipelines.AddSystem<VelocitySystem>();          // Order: 100 (movement)
    pipelines.AddSystem<PhysicsSystem>();           // Order: 200 (collision)
    pipelines.AddSystem<AudioSystem>();             // Order: 300 (audio)
    pipelines.AddSystem<CameraSystem>();            // Order: 400 (camera)
    
    // Render systems (run during render phase)
    pipelines.AddSystem<SpriteRenderingSystem>();   // Order: 0 (sprites)
    pipelines.AddSystem<ParticleSystem>();          // Update + Render
    pipelines.AddSystem<DebugRenderer>();           // Order: 1000 (debug overlay)
});

Using System Pipelines in Scenes

public class GameScene : Scene
{
    private readonly UpdatePipeline _updatePipeline;
    private readonly RenderPipeline _renderPipeline;
    private readonly IEntityWorld _world;

    public GameScene(
        UpdatePipeline updatePipeline,
        RenderPipeline renderPipeline,
        IEntityWorld world,
        ILogger<GameScene> logger) : base(logger)
    {
        _updatePipeline = updatePipeline;
        _renderPipeline = renderPipeline;
        _world = world;
    }

    protected override void OnUpdate(GameTime gameTime)
    {
        // Execute all update systems in order (ASP.NET-style!)
        _updatePipeline.Execute(gameTime);
        
        // Update entity lifecycle
        _world.Update(gameTime);
    }

    protected override void OnRender(GameTime gameTime)
    {
        _renderer.BeginFrame();
        
        // Execute all render systems in order
        _renderPipeline.Execute(_renderer);
        
        _renderer.EndFrame();
    }
}

Save/Load System

using Brine2D.ECS.Serialization;

// Save game state
await _serializer.SaveWorldAsync(_world, "saves/game.json");

// Load game state
await _serializer.LoadAndRestoreWorldAsync(_world, "saves/game.json");

Utility Components

// Timer - Countdown with events
var timer = entity.AddComponent<TimerComponent>();
timer.Duration = 3f;
timer.OnComplete += () => Logger.LogInfo("Timer finished!");

// Lifetime - Auto-destroy after time
var lifetime = projectile.AddComponent<LifetimeComponent>();
lifetime.Lifetime = 5f;

// Tween - Simple animations
var tween = entity.AddComponent<TweenComponent>();
tween.Type = TweenType.Position;
tween.StartPosition = new Vector2(0, 0);
tween.EndPosition = new Vector2(100, 100);
tween.Duration = 1f;
tween.Easing = EasingType.EaseInOutQuad;

Transform Hierarchy (Parent/Child)

// Create weapon as child of player
var weapon = _world.CreateEntity("Sword");
weapon.AddComponent<TransformComponent>();
weapon.AddComponent<SpriteComponent>();

// Attach weapon to player (transforms follow parent)
weapon.SetParent(player);

// When player moves/rotates, weapon follows automatically!

Examples

ECS Quick Start Example

See samples/BasicGame/ECSQuickStartScene.cs for a complete minimal example showing:

  • Entity creation
  • Prefabs
  • System pipelines
  • Save/load
  • Events

Loading and Drawing Sprites

using Brine2D.Core;
using Brine2D.Rendering;

public class SpriteScene : Scene
{
    private readonly IRenderer _renderer;
    private readonly ITextureLoader _textureLoader;

    private ITexture? _playerTexture;

    protected override async Task OnLoadAsync(CancellationToken cancellationToken)
    {
        // Load with nearest neighbor filtering for pixel art
        _playerTexture = await _textureLoader.LoadTextureAsync
        (
            "assets/player.png",
            TextureScaleMode.Nearest,
            cancellationToken
        );
    }

    protected override void OnRender(GameTime gameTime)
    {
        _renderer.Clear(Color.Black);
        _renderer.BeginFrame();

        if (_playerTexture != null)
        {
            _renderer.DrawTexture(_playerTexture, 100, 100);
        }

        _renderer.EndFrame();
    }
}

Sprite Animation

using Brine2D.Core;
using Brine2D.Core.Animation;
using Brine2D.Rendering;

public class AnimatedScene : Scene
{
    private SpriteAnimator? _animator;
    private ITexture? _spriteSheet;

    protected override async Task OnLoadAsync(CancellationToken cancellationToken)
    {
        _spriteSheet = await _textureLoader.LoadTextureAsync
        (
            "assets/character.png",
            TextureScaleMode.Nearest,
            cancellationToken
        );

        _animator = new SpriteAnimator();

        // Create walk animation from sprite sheet
        var walkAnim = AnimationClip.FromSpriteSheet
        (
            "walk",
            32,
            32,
            8,
            8
        );

        _animator.AddAnimation(walkAnim);
        _animator.Play("walk");
    }

    protected override void OnRender(GameTime gameTime)
    {
        _renderer.Clear(Color.Black);
        _renderer.BeginFrame();

        if (_spriteSheet != null && _animator?.CurrentFrame != null)
        {
            var frame = _animator.CurrentFrame;
            var rect = frame.SourceRect;

            _renderer.DrawTexture
            (
                _spriteSheet,
                rect.X, rect.Y, rect.Width, rect.Height,
                100, 100, 64, 64
            );
        }

        _renderer.EndFrame();
    }

    protected override void OnUpdate(GameTime gameTime)
    {
        _animator?.Update((float)gameTime.DeltaTime);
    }
}

Playing Audio

using Brine2D.Audio;
using Brine2D.Core;
using Brine2D.Input;

public class AudioScene : Scene
{
    private readonly IAudioService _audio;

    private IMusic? _bgMusic;
    private ISoundEffect? _jumpSound;

    protected override async Task OnLoadAsync(CancellationToken cancellationToken)
    {
        _jumpSound = await _audio.LoadSoundAsync("assets/jump.wav", cancellationToken);
        _bgMusic = await _audio.LoadMusicAsync("assets/music.mp3", cancellationToken);

        _audio.PlayMusic(_bgMusic);
    }

    protected override void OnUpdate(GameTime gameTime)
    {
        if (_input.IsKeyPressed(Keys.Space) && _jumpSound != null)
        {
            _audio.PlaySound(_jumpSound);
        }
    }
}

Input Handling

using Brine2D.Core;
using Brine2D.Input;

protected override void OnUpdate(GameTime gameTime)
{
    // Keyboard
    if (_input.IsKeyDown(Keys.W))
    {
        /* Move up */
    }

    if (_input.IsKeyPressed(Keys.Space))
    {
        /* Jump */
    }

    // Mouse
    var mousePos = _input.MousePosition;

    if (_input.IsMouseButtonPressed(MouseButton.Left))
    {
        /* Click */
    }

    // Gamepad
    if (_input.IsGamepadConnected())
    {
        var leftStick = _input.GetGamepadLeftStick();

        if (_input.IsGamepadButtonPressed(GamepadButton.A))
        {
            /* Jump */
        }
    }
}

Configuration

Create a gamesettings.json file in your project:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Brine2D": "Debug"
    }
  },
  "Rendering": {
    "WindowTitle": "My Game",
    "WindowWidth": 1280,
    "WindowHeight": 720,
    "VSync": true,
    "Fullscreen": false,
    "Backend": "LegacyRenderer"
  }
}

Architecture

Brine2D follows a modular architecture with clear separation of concerns:

Core Packages

  • Brine2D.Core - Core abstractions, animation, collision, tilemap
  • Brine2D.Engine - Game loop and scene management
  • Brine2D.Hosting - ASP.NET-style application hosting
  • Brine2D.ECS - Entity Component System ✨ NEW!

Abstraction Layers

  • Brine2D.Rendering - Rendering abstractions (IRenderer, ITexture, ICamera)
  • Brine2D.Input - Input abstractions (IInputService, keyboard, mouse, gamepad)
  • Brine2D.Audio - Audio abstractions (IAudioService, music, sound effects)

SDL3 Implementations

  • Brine2D.Rendering.SDL - SDL3 GPU + Legacy renderer implementation
  • Brine2D.Input.SDL - SDL3 input implementation
  • Brine2D.Audio.SDL - SDL3_mixer audio implementation

ECS Bridges ✨ NEW!

  • Brine2D.Rendering.ECS - Sprite rendering, particles, camera systems
  • Brine2D.Input.ECS - Player controller system
  • Brine2D.Audio.ECS - Audio playback system

Extensions

  • Brine2D.UI - UI framework (buttons, inputs, dialogs, tabs)

Meta-Package

  • Brine2D.Desktop - All-in-one package (recommended for most users)

Requirements

  • .NET 10 SDK
  • SDL3 (included via SDL3-CS NuGet package)
  • SDL3_image (for texture loading)
  • SDL3_mixer (for audio playback)

Platform Support

Platform Status Notes
Windows ✅ Supported Tested on Windows 10/11
Linux ⚠️ Untested Should work via SDL3
macOS ⚠️ Untested Should work via SDL3

SDL3 provides cross-platform support, but we've only tested on Windows so far. Community testing on other platforms is welcome!

Building from Source

If you want to build from source or contribute:

git clone https://github.com/CrazyPickleStudios/Brine2D.git
cd Brine2D
dotnet build

Then reference the projects directly in your game:

<ItemGroup>
  <ProjectReference Include="..\Brine2D\src\Brine2D.Desktop\Brine2D.Desktop.csproj" />
</ItemGroup>

Samples

Check out the samples/ directory for complete working examples:

  • BasicGame - ECS demo with entities, prefabs, systems ✨ NEW!
  • ECSQuickStartScene - Minimal ECS example ✨ NEW!
  • PlatformerGame - Coming soon
  • AdvancedGame - Coming soon

Community & Support

Roadmap

0.4.0-alphaCURRENT

  • ✅ Entity Component System (ECS)
  • ✅ ASP.NET-style system pipelines
  • ✅ Prefabs and serialization
  • ✅ Transform hierarchy
  • ✅ Utility components
  • ✅ Working ECS samples

0.5.0-beta (Upcoming)

  • Advanced ECS queries and filters
  • Complete GPU renderer
  • More polished samples
  • Performance optimizations

1.0.0 (Future)

  • Stable API
  • Complete documentation
  • Production-ready
  • Full platform testing

See the full roadmap.

Contributing

We welcome contributions! Please see CONTRIBUTING.md for guidelines.

License

MIT License - see LICENSE file for details

Credits

Built with:

  • SDL3 - Simple DirectMedia Layer
  • SDL3-CS - C# bindings for SDL3

Made with ❤️ by CrazyPickle Studios

Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on Brine2D.Engine:

Package Downloads
Brine2D.Hosting

ASP.NET-style application hosting for Brine2D. Provides GameApplicationBuilder pattern with dependency injection and configuration support.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.8.0-beta 57 1/18/2026
0.7.0-beta 62 1/14/2026
0.6.0-beta 55 1/9/2026
0.5.0-beta 55 1/7/2026
0.4.0-alpha 54 1/5/2026
0.3.8-alpha 58 1/3/2026
0.3.7-alpha 59 1/3/2026
0.3.6-alpha 49 1/3/2026
0.3.5-alpha 53 1/3/2026
0.3.4-alpha 56 1/2/2026
0.3.3-alpha 54 1/2/2026
0.3.2-alpha 50 1/2/2026
0.3.1-alpha 60 1/2/2026
0.3.0-alpha 62 1/2/2026