Ambit is a .NET 10 library for drawing and editing shapes over images and video in Avalonia. It works well for things like video analytics zones, photo markup, or diagram tools.
Docs & Demo: https://architrixs.github.io/ambit/
dotnet add package Lib.Ambit
dotnet add package Lib.Ambit.AvaloniaNeeds .NET 10 and Avalonia 11.3+. That's it.
Ambit.Core has all the math, points, bounds, hit-testing, and the editing state machine. No Avalonia dependency, so you can test it anywhere.
Ambit.Avalonia does the drawing. It uses Skia directly (ICustomDrawOperation) and gives you two controls:
RegionOverlayControl, just renders, good for 20+ tiles at onceRegionEditorControl, handles mouse input for drawing and editing
All points are stored as 0..1 normalized coordinates. The viewer handles pan, zoom, and letterboxing for you.
using Ambit;
using Ambit.Avalonia.Controls;
var overlay = new RegionOverlayControl
{
ContentSize = new Size(1920, 1080),
};
var style = new RegionStyle { StrokeColorHex = "#EF4444", StrokeThickness = 2.0 }
.With(fillColorHex: "#FCA5A5", fillOpacity: 0.2);
var area = new RectangleRegion(
new NormalizedPoint(0.1, 0.1),
new NormalizedPoint(0.4, 0.4),
style, label: "Detection Zone");
overlay.UpdateRegions(new List<IRegion> { area });
// Updates only redraw when something actually changedusing Ambit;
using Ambit.Avalonia.Controls;
var controller = new RegionEditController();
var editor = new RegionEditorControl(controller)
{
ContentSize = new Size(1920, 1080),
};
controller.SetRegions(new IEditableRegion[] { area });
// Switch tools
controller.ActiveDrawTypeId = RectangleRegion.RectangleTypeId; // draw rectangles
controller.ActiveDrawTypeId = null; // back to select/move
// Pan and zoom are on by default (right-drag + wheel). Turn off:
// editor.IsPanZoomEnabled = false;
// Save when the user finishes a drag
controller.RegionsChanged += (_, _) => Save(controller.Regions);You don't need to change Ambit itself. Just add a class and register it. The sample shows this with CircleRegion.
// 1. Your shape, just implement IEditableRegion
public class TriangleRegion : IEditableRegion { ... }
// 2. Factory for saving/loading + renderer for drawing
public class TriangleFactory : IRegionFactory { ... }
public class TriangleRenderer : IRegionRenderer { ... }
// 3. Register
var registry = new RegionTypeRegistry().RegisterBuiltInTypes();
registry.Register(new TriangleFactory());
var renders = new RegionRenderRegistry().RegisterBuiltInRenderers();
renders.Register(new TriangleRenderer());
var renderer = new RegionOverlayRenderer(renders);
var editor = new RegionEditorControl(controller, renderer);Same idea for decorations like badges or arrows. Check samples/Ambit.Sample/Extensibility/ — it adds CircleRegion + DirectionIndicatorDecoration/CountBadge without touching any library code (edge-midpoint handles intentionally omitted from built-ins; add them via a custom region if needed).
Ambit uses simple DTOs so you can save however you like:
var registry = new RegionTypeRegistry().RegisterBuiltInTypes();
// Save
var dtos = controller.Regions.Select(r => registry.ToDto(r)).ToList();
var json = JsonSerializer.Serialize(dtos);
// Load
var loaded = JsonSerializer.Deserialize<List<RegionDto>>(json)!;
controller.SetRegions(loaded.Select(dto => registry.CreateRegion(dto)));