BlazorBlaze 1.0.3

dotnet add package BlazorBlaze --version 1.0.3
                    
NuGet\Install-Package BlazorBlaze -Version 1.0.3
                    
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="BlazorBlaze" Version="1.0.3" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="BlazorBlaze" Version="1.0.3" />
                    
Directory.Packages.props
<PackageReference Include="BlazorBlaze" />
                    
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 BlazorBlaze --version 1.0.3
                    
#r "nuget: BlazorBlaze, 1.0.3"
                    
#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 BlazorBlaze@1.0.3
                    
#: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=BlazorBlaze&version=1.0.3
                    
Install as a Cake Addin
#tool nuget:?package=BlazorBlaze&version=1.0.3
                    
Install as a Cake Tool

BlazorBlaze

High-performance rendering library for Blazor WebAssembly with three rendering technologies.

NuGet

Installation


<PackageReference Include="BlazorBlaze" />


<PackageReference Include="BlazorBlaze.Server" />

Rendering Technologies

1. BlazorCanvas + BlazeEngine (Scene Graph)

Interactive scene graph with draggable controls for building visual editors.

@using BlazorBlaze
@using ModelingEvolution.Drawing
@using SkiaSharp

<BlazorCanvas Engine="_engine" Size="Sizes.HD" />

@code {
    private BlazeEngine _engine = new BlazeEngine(Sizes.HD);

    protected override void OnInitialized()
    {
        // Circle with drag support
        var circle = new CircleControl(new SKPoint(100, 100), 50);
        circle.Fill = SKColors.Red;
        circle.EnableDrag();
        circle.OnClick += (s, e) => { /* handle click */ };
        _engine.Scene.AddControl(circle);

        // Rectangle
        var rect = new RectangleControl(new SKRect(200, 50, 350, 150));
        rect.Fill = SKColors.Blue;
        rect.EnableDrag();
        _engine.Scene.AddControl(rect);

        // Polygon
        var points = new Point<float>[] { new(300, 200), new(350, 300), new(250, 300) };
        var polygon = new PolygonControl(new Polygon<float>(points));
        polygon.Fill = SKColors.Green;
        polygon.EnableDrag();
        _engine.Scene.AddControl(polygon);
    }
}

2. Charts (BarChart, TimeSeriesChart)

SkiaSharp-based charts for data visualization.

@using BlazorBlaze.Charts
@using SkiaSharp
@using SkiaSharp.Views.Blazor

<SKCanvasView OnPaintSurface="OnPaintSurface" EnableRenderLoop="true" />

@code {
    private BarChart _chart = new();
    private string[] _labels = { "A", "B", "C" };
    private float[] _values = { 45.2f, 72.8f, 33.1f };

    protected override void OnInitialized()
    {
        _chart.SetData(
            title: "Demo",
            labels: _labels, labelCount: _labels.Length,
            values: _values, valueCount: _values.Length,
            minScale: 0f, maxScale: 100f,
            units: "%", valueFormat: "{0:F1}",
            enableMinMaxTracking: true
        );
    }

    private void OnPaintSurface(SKPaintSurfaceEventArgs e)
    {
        _chart.Location = new SKPoint(0, 0);
        _chart.Size = new SKSize(e.Info.Width, e.Info.Height);
        _chart.Render(e.Surface.Canvas);
    }
}

3. VectorGraphics (WebSocket Streaming)

High-performance binary streaming for real-time graphics over WebSocket.

Protocol v2 Features:

  • Multi-layer rendering with z-ordering (16 layers)
  • Stateful context (stroke, fill, transforms persist across draw calls)
  • Lock-free rendering with layer pooling
  • Delta-encoded points with varint+zigzag compression
  • Save/Restore for hierarchical transforms

Performance (stress test with 20K points @ 60 FPS):

  • Render time: ~2.5ms per frame
  • Transfer rate: ~1.1 MB/s
  • Zero-allocation rendering path
using BlazorBlaze.Server;
using BlazorBlaze.VectorGraphics;

app.UseWebSockets();

app.MapVectorGraphicsEndpointV2("/ws/stream", async (IRemoteCanvasV2 canvas, CancellationToken ct) =>
{
    var points = new SKPoint[] { /* polygon vertices */ };

    while (!ct.IsCancellationRequested)
    {
        canvas.BeginFrame();

        // Layer 0 - Background elements (stateful context)
        var bg = canvas.Layer(0);
        bg.SetStroke(new RgbColor(100, 100, 100));
        bg.SetThickness(1);
        bg.DrawRectangle(0, 0, 800, 600);

        // Layer 1 - Animated content with transforms
        var layer = canvas.Layer(1);
        layer.SetStroke(new RgbColor(255, 100, 100));
        layer.SetThickness(2);
        layer.Save();
        layer.Translate(400, 300);
        layer.Rotate(angle);
        layer.DrawPolygon(points);
        layer.Restore();

        // Layer 2 - Static overlay (Remain = no update)
        canvas.Layer(2).Remain();

        await canvas.FlushAsync(ct);
        await Task.Delay(16, ct); // ~60 FPS
    }
});
Client (Protocol v2)
@using BlazorBlaze.VectorGraphics
@inject ILoggerFactory LoggerFactory

<SKCanvasView @ref="_canvasView" OnPaintSurface="OnPaintSurface" EnableRenderLoop="true" />

@code {
    private RenderingStreamV2? _stream;
    private SKCanvasView? _canvasView;

    protected override void OnInitialized()
    {
        _stream = new RenderingStreamV2(1200, 800, LoggerFactory);
    }

    private async Task Connect()
    {
        var uri = new Uri("ws://localhost:5100/ws/stream");
        await _stream!.ConnectAsync(uri);
    }

    private void OnPaintSurface(SKPaintSurfaceEventArgs e)
    {
        var canvas = e.Surface.Canvas;
        canvas.Clear(SKColors.Black);
        _stream?.Render(canvas);  // Lock-free, composites all layers
    }

    // Pool statistics available for monitoring
    // _stream.PoolInUse, _stream.PoolCached, _stream.PoolTotalCreated
}
Server (Protocol v1 - Simple)
app.MapVectorGraphicsEndpoint("/ws/simple", async (IRemoteCanvas canvas, CancellationToken ct) =>
{
    canvas.Begin();
    canvas.DrawPolygon(points, new DrawContext
    {
        Stroke = new RgbColor(255, 100, 100),
        Thickness = 2,
        Offset = new SKPoint(100, 100),
        Rotation = 45f,
        Scale = new SKPoint(1.5f, 1.5f)
    });
    await canvas.FlushAsync(ct);
});

Running the Sample App

Quick Start

cd samples/SampleApp
./run.sh

Opens at http://localhost:5100

Demo pages:

  • /canvas - BlazorCanvas with draggable shapes
  • /barchart - Bar chart demo
  • /timeseries - Time series chart with live updates
  • /stress - WebSocket streaming 20K points @ 60 FPS (Protocol v2)

Manual Build

# Clean build
cd samples/SampleApp
dotnet clean
rm -rf bin obj publish
rm -rf ../SampleApp.Client/bin ../SampleApp.Client/obj
./run.sh

Architecture

VectorGraphics Protocol v2 Internals

Server Side:
┌─────────────────┐    ┌──────────────────┐    ┌─────────────┐
│ IRemoteCanvasV2 │───>│ VectorEncoderV2  │───>│  WebSocket  │
│   ILayerCanvas  │    │ (binary protocol)│    │   (send)    │
└─────────────────┘    └──────────────────┘    └─────────────┘

Client Side:
┌─────────────┐    ┌───────────────────┐    ┌────────────────┐    ┌───────────┐
│  WebSocket  │───>│ VectorStreamDecoder│───>│ RenderingStage │───>│ LayerPool │
│  (receive)  │    │ (parse + decode)   │    │ (frame mgmt)   │    │ (recycle) │
└─────────────┘    └───────────────────┘    └────────────────┘    └───────────┘
                                                     │
                                                     v
                                            ┌────────────────┐
                                            │ RenderingStreamV2│
                                            │ (lock-free render)│
                                            └────────────────┘

Key Components:

  • LayerPool - Thread-safe pool of LayerCanvas instances using ConcurrentBag
  • RenderingStage - Manages frame lifecycle with lock-free consumer access
  • Ref<T> / RefArray<T> - Reference-counted smart pointers for safe frame sharing
  • Lease<T> - Pool return wrapper, returns layer to pool on dispose

Project Structure

src/
  BlazorBlaze/                        # Main library (WASM-compatible)
    Charts/                           # BarChart, TimeSeriesChart
    VectorGraphics/                   # Streaming, Decoder, RenderingStream
      Protocol/                       # IStage, LayerPool, LayerCanvas
    ValueTypes/                       # Ref<T>, RefArray<T>, Lease<T>
  BlazorBlaze.Server/                 # Server extensions (ASP.NET Core)
    IRemoteCanvasV2                   # Multi-layer canvas interface
    VectorEncoderV2                   # Binary protocol encoder
samples/
  SampleApp/                          # Server + WebSocket endpoints
  SampleApp.Client/                   # Blazor WASM client
tests/
  BlazorBlaze.Tests/                  # Unit tests (177 tests)
benchmarks/
  BlazorBlaze.Benchmarks/             # Performance benchmarks

Dependencies

  • .NET 10.0
  • SkiaSharp
  • SkiaSharp.Views.Blazor
  • ModelingEvolution.Drawing

License

MIT

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

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
1.0.3 0 12/13/2025
1.0.2 0 12/13/2025
1.0.1 258 12/11/2025