Skip to content
TokterPublic

About

C# UI Library, based on SkiaSharp

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Atelier logo

Atelier

A GPU-accelerated desktop UI framework for .NET 10, written in plain C#
SkiaSharp rendering · Silk.NET windowing · Material Design 3

CI .NET 10 SkiaSharp Silk.NET Material Design 3 MIT License

Atelier Gallery, light theme Atelier Gallery, dark theme


Overview

Atelier is a retained-mode UI framework for desktop applications. You build the interface in C# with a fluent, type-safe markup API instead of XAML, and every control is drawn with SkiaSharp on an OpenGL surface.

  • C# only. No XAML, no CSS, no web view. Views are ordinary C# with IntelliSense, refactoring and hot reload.
  • Material Design 3 out of the box. Light and dark color schemes, the MD3 type scale, default styles sized for desktop use, and 2,100+ Material Symbols with all four variable font axes.
  • A real property system. Bindable properties with value precedence (default, inherited, style, local, animation, coerced), styles, attached properties, typed data binding and change notifications.
  • Built for low overhead. Rendering reuses cached paints, fonts and text blobs, so a steady frame allocates nothing, and windows only redraw when something changed.
  • Reflection-free tooling. Commands ([Command]: name, label, description, icon and default shortcut), keybindings and property-grid metadata come from source generators, as do the MaterialIcons name constants for icons given as text.

Screenshots

All screenshots show the included Gallery application.

F12 developer tools Data grid
F12 DevTools: element tree, element picker, live box model, editable properties and a pixel zoom Data grid: 10,000 virtualized rows, sorting, filter menus, column chooser, cell editing
Open file dialog Color picker, dark theme
File dialogs: open, save and folder dialogs with a path bar, folder tree and file grid Color picker: wheel, RGB/HSL/HSB gradient sliders, alpha and hex
Date and time pickers, dark theme Tabs
Date & time pickers: MD3 docked and modal calendars, clock dial and text input Tabs: MD3 primary and secondary tabs, closeable and reorderable browser tabs
Buttons Text fields, dark theme
Buttons: variants, commands, repeat and toggle buttons, toolbars Text fields: outlined and filled, labels, validation, binding, multi-line
Cards Icons, dark theme
Cards: variants, elevation, shape, media and clipping Icons: Material Symbols with fill, weight, grade and optical size
Typography Layout panels, dark theme
Typography: the MD3 type scale and a live playground Layout: stack, wrap, dock, grid, uniform grid and canvas
Popups and dialogs Property grid
Popups & dialogs: presets, custom content, scoped hosts Property grid: generated metadata, validation, custom editors
Tooltips Theme editor
Tooltips: plain text, or rich content with clickable actions Theme editor: schemes generated from an accent color, every role tunable in light and dark
Keybinding editor Command palette
Keybinding editor: commands by group, with their labels, icons and shortcuts; record new shortcuts, see conflicts Command palette: search and run the commands that work where the focus is (Ctrl+Shift+P)
Node editor, dark theme Timeline ruler and lanes, dark theme
Node editor: Blender-style node graphs with typed sockets, knobs and sliders beside the inputs, live evaluation, and rebindable mouse and keyboard tools
Auto-arranged node graph, dark theme
Node auto-arrange: 44 scrambled nodes in columns along their links, with few crossings, clusters kept together and links led around nodes through reroute points (Shift+L)
Workspaces and areas 3D viewport, dark theme
Workspaces: Blender-style areas that split, join, swap and maximize, each with an editor picked from a registry; workspaces in tabs 3D viewport: OpenGL-rendered meshes with textures, normal maps and translucency, lines and points, a ground grid and Blender-style navigation

Quick start

using Atelier.Controls;
using Atelier.Core.Primitives;
using Atelier.Layout;
using Atelier.Markup;
using Atelier.Platform.Silk;
using Atelier.Theming;
using Atelier.Theming.Material;
using CommunityToolkit.Mvvm.ComponentModel;

ThemeManager.Current = MaterialTheme.CreateLight();

var vm = new GreetingViewModel();
var window = new SilkWindow(title: "Hello Atelier", width: 640, height: 400);

// A factory lambda enables hot reload: the view is rebuilt from the same view model.
window.SetContent(() =>
    new StackPanel()
        .Spacing(16)
        .Margin(32)
        .Children(
            new TextBlock("Welcome to Atelier").HeadlineMedium(),
            new TextBox()
                .Label("Your name")
                .LeadingIconKind(MaterialIconKind.Person)
                .MaxWidth(320)
                .HorizontalAlignment(HorizontalAlignment.Left)
                .BindText(vm, v => v.Name, (v, name) => v.Name = name),
            new TextBlock().BodyLarge().BindText(vm, v => $"Hello, {v.Name}!"),
            new Button("Say hello")
                .HorizontalAlignment(HorizontalAlignment.Left)
                .OnClick(() => vm.Name = "World")));

window.Run();

public partial class GreetingViewModel : ObservableObject
{
    [ObservableProperty]
    private string _name = "Atelier";
}

Reference Atelier.Markup and Atelier.Platform.Silk; they bring in the rest of the framework.

The markup API

Every property has a fluent method with the same name that returns the element, so calls chain and keep their type:

new Button("Save").Variant(ButtonVariant.Tonal).Command(vm.SaveCommand).IsEnabled(false);
new Grid().Columns("Auto,*").Spacing(12, 8).Children(label.Cell(0, 0), field.Cell(0, 1));
  • Bind{Property}(source, s => s.Value) binds to an object; Bind{Property}((MyViewModel vm) => vm.Value) binds to the DataContext. An optional setter makes the binding two-way.
  • On{Event}(...) attaches handlers; events without data also accept an Action.
  • Controls get their size, shape and colors from the theme, so views only set what they change.

Features

Controls

Control Highlights
Button, RepeatButton, ToggleButton Filled, tonal, elevated, outlined and text variants; commands with CanExecute; a registered command's icon, label and tooltip (description and shortcut) when no content is set; click modes; repeat delay and interval; two- and three-state toggles
CheckBox, RadioButton, Switch Three states, rich content, named and unnamed radio groups, thumb icons, value-matching radio binding
TextBox Outlined and filled variants, floating label, placeholder, leading icon, supporting text, INotifyDataErrorInfo validation, max length, password mode, undo/redo, clipboard and word navigation; multi-line text areas (AcceptsReturn, TextWrapping, MinLines/MaxLines, scrolling)
ComboBox Items or bound collections, typed item templates, text search, keyboard navigation, max drop-down height, compact mode
Slider, Knob, ProgressBar Ranges, small and large steps, tick snapping, formatted value bubble; a rotary knob (Atelier.Audio) turned by dragging (Shift for fine steps), the wheel or the keys, reset by double-clicking; determinate and indeterminate progress
ListBox, ItemsControl UI virtualization (only the items in view get containers), incremental updates from observable collections, typed templates, type-to-search, keyboard navigation
TreeView Data-bound or item-built trees, children selector, typed templates, configurable expander icons; the shown nodes form one virtualized list
DataGrid Virtualized rows; text, template and check box columns; multi-column sorting; Pixel, Auto and Star widths; resizing, reordering and a column chooser with saved layouts; a filter row and spreadsheet-style filter menus; single, check box and extended selection of rows or cells; F2 editing with custom editors and validation; Ctrl+C as tab-separated text; row context menus and empty placeholders
OpenFileDialog, SaveFileDialog, FolderBrowserDialog The same dialog on every platform, with WPF's properties (Filter, Multiselect, CheckFileExists, OverwritePrompt, InitialDirectory, ...): path bar with clickable folders, folder tree, file grid with optional attribute columns, new folder and rename; any file system through IFileSystemProvider
Menu, MenuItem, ContextMenu Menu bars (also in the title bar), submenus and context menus; icons, check and radio items, separators; header, icon and shortcut text from the command's [Command] declaration; CanExecute disables or hides items; access keys; menus built from data with a children selector and item templates
TabControl MD3 primary and secondary tabs with a sliding indicator; browser-style tabs that close, add and reorder by dragging; header and content templates
DatePicker, TimePicker MD3 docked and modal calendars and date input; clock dial and text input with 12- and 24-hour clocks; typed dates and times, ranges and validation; compact mode
ColorPicker Hue/saturation wheel, RGB, HSL and HSB sliders that show their gradients, alpha, hex and channel inputs
Badge MD3 small dot and large count or text badges on any element
Card, Border Outlined, elevated and filled cards; elevation shadows; per-corner radii; clipping
Popup, Dialog, DialogHost Smart placement with flipping (or at the pointer), light dismiss, dialog presets and custom buttons, async results, scoped hosts
ToolTip, RichToolTip .ToolTip("text") on any element; rich tooltips hold any element and stay open for their buttons and links; placement, delays, disabled elements, optional keyboard-focus tooltips
ScrollViewer Per-axis scroll bar modes, wheel and keyboard scrolling, scroll events
TransitioningContentControl Fade, slide, zoom, slide-and-fade and composite transitions with configurable duration and easing
PropertyGrid Categories (alphabetical, or in a given order with CategoryOrder), sorting, filtering, validation, custom editors per type or predicate, a resizable label column; metadata generated at compile time
GridSplitter Resizes grid columns or rows by dragging or with the arrow keys; keeps star proportions; min/max limits, snapping, preview mode, Escape to cancel, double-click to restore
Icon, Image, TextBlock Material Symbols with variable axes, SVG path data or whole SVG documents (Source: an icon name or SVG); stretch modes; wrapping, trimming, max lines and line height
TitleBar, Toolbar, KeybindingHandler Custom window chrome, action bars, scoped shortcuts with chords, and pointer gestures bound like keys ("RightClick", "Ctrl+WheelUp", "MiddleDrag" running an IDragCommand); a handler can run further groups for a fixed target; users can change a command's label, icon and shortcut (KeybindingManager.SetCustomization, saved and restored as JSON)
KeybindingEditor, ShortcutRecorder, ShortcutView Lets users change every command's label, icon and shortcut, listed by group (or all, or the changed ones), with search, conflicts and reset; records shortcuts and chords from key presses, and clicks, drags and wheel turns; shows shortcuts as key caps
CommandPalette Searches the commands whose shortcuts work where the focus is (KeybindingHandler.GetActiveCommands: the handlers from the focus up to the window), ranks label prefixes, word starts and initials first, and runs the chosen one on its target
NodeEditor Blender-style node graphs (Atelier.NodeEditor): typed sockets with opt-in conversions, links as curves, value controls beside unconnected inputs; Blender-style editing (select, box select, move with snapping, drag to connect or move links, delete, duplicate, collapse, mute, a searchable add menu and a context menu; drop a node on a link to insert it, Alt+drag to detach it, drop a link on empty space to search for a node to connect, Ctrl+right drag to cut links, Shift+right drag to add reroute points); auto-arrange (Shift+L: a layered layout in columns along the links, with few crossings, clusters of closely linked nodes kept together, links led around nodes through reroute points and unlinked parts packed compactly, as one undo step); reusable node groups (Ctrl+G to make one, Tab to edit it, with its inputs and outputs in a panel); saving as JSON and copy and paste with every action a rebindable command; grid and dot backgrounds, undo, and optional dataflow evaluation
TimelineRuler, TimelineLane A DAW-style beat and time ruler and track lanes (Atelier.Audio) connected through a shared TimelineContext (zoom, scroll, tempo map, sample rate), so zooming or scrolling one moves all; ticks and labels adapt to the zoom in bars and beats (5, 5.2, 5.2.3, following tempo and time signature changes), time (01:05, milliseconds only when zoomed in) or samples, with an optional second row in another unit; Bitwig-style zooming by dragging the ruler, wheel zoom and scroll, and a menu to choose the units, all rebindable commands; lanes draw the matching grid lines behind their content. Colored marker flags above the ruler (shared by the song and drawn across every lane, or a lane's own), a loop bar below it, a play start marker and a playhead, with positions pinned to seconds or to beats; click to set the play start, drag flags and loop edges (snapping to the grid in view, Shift inverts it), double-click to add or rename markers or toggle the loop, right-click to recolor or delete
TimelinePanel, WaveformView Clips on a track (Atelier.Audio): the panel places each child at an attached start and length in seconds or beats, following zoom, scroll and tempo changes and skipping clips out of view; the lightweight waveform draws part of a sound from a shared WaveformData (an exact min/max peak pyramid and running sums for RMS, so drawing costs the same at any length) like a DAW: a filled peak envelope with the RMS inside when zoomed out (smoothed over 25 ms, so low notes don't turn into moiré), the waveform's own shape closer in, and a line through the samples with a dot per sample at the deepest zoom; one lane per channel or combined
AudioWaveformEditor Non-destructive editing of one sound on the timeline (Atelier.Audio), like a DAW clip: drag the edges to trim (the trimmed parts stay dimmed), square handles to fade in and out (linear or equal-power), and a dB chip to change the gain; drag to select, trim to the selection, and a menu; everything snaps to the grid and is a bindable property, and GetGain() gives the same fade and gain curve (WaveformGain) for playback; the waveform is drawn at the level they give it
WorkspaceView, AreaLayout, Area Blender-style areas and workspaces: register editor types (id, title, icon, category, content and header factories) in an AreaEditorRegistry, and every area gets a button in its top-left corner to switch its editor (switching back finds the editor as it was). Drag from an area's corner into it to split it, into a neighbor to join that neighbor, or with Ctrl onto another area to swap them; drag borders to resize; right-click a border for the Area Options (split, join, swap) or a header for split, Maximize Area (Ctrl+Space) and Close Area. Workspaces are browser-style tabs that switch arrangements (Ctrl+Page Up/Down), added from templates, renamed by double-click, duplicated (Layout.001), deleted and reordered from their menu; AreaDefinition describes layouts in code and saves them as JSON
Viewport3D GPU-rendered 3D (Atelier.Graphics3D): a Scene3D of MeshInstance3Ds (a Mesh3D of triangles, lines or points with normals, texture coordinates and vertex colors, a transform and a Material3D: base color and sRGB texture, tangent-free normal map, roughness, metalness, translucency for backlit fabric, unlit, double-sided, drawn on top) rendered with OpenGL 3.3 on the window's context into a 4× multisampled floating-point buffer, lit by a sun (GGX highlights) and a sky and ground ambient, tone-mapped (Khronos PBR Neutral) over a background gradient; an infinite ground grid, an axis gizmo and shaded, wireframe or shaded-wireframe drawing; Mesh3D.UpdatePositions animates every frame; redraws only on changes. Blender-style navigation with an OrbitCamera: middle-drag orbit, Shift+middle-drag pan, wheel zoom towards the pointer, Alt+drag without a middle button, Home to frame, numpad views and orthographic, all rebindable commands; a placeholder without a GPU
XYChart 2D line and scatter charts for engineering data (Atelier.Charts): XYSeries with solid, dashed or dotted lines and circle, square, diamond or triangle markers; axes with titles, nice ticks (1, 2, 5 × 10ⁿ, as many decimals as the step needs, in the current culture), grid and zero lines; labeled points (ChartAnnotation) in rounded labels that place themselves around the point clear of other labels, the legend and the curves; a legend in the emptiest corner; a readout of the nearest point under the pointer. The view fits the data (and follows new points) until you zoom or pan: the wheel zooms at the pointer (Ctrl only horizontally, Shift only vertically), dragging pans, right-dragging zooms into a box, + and − zoom, Home or a double click fits again, all rebindable commands; lines skip what is out of view, so thousands of points stay fast

Layout

StackPanel, WrapPanel, DockPanel, Grid (Auto, pixel and star sizes, spans), UniformGrid, Canvas and VirtualizingStackPanel (realizes only the items in view and reuses their containers; fixed or measured heights), plus margin, padding, alignment, min/max sizes, visibility, clipping, opacity, layout transforms and render transforms. Any element can set the mouse cursor (.Cursor(CursorType.Hand)); text boxes show the I-beam and splitters the resize arrows.

Theming and styling

  • MaterialTheme.CreateLight() / CreateDark(): MD3 color schemes, switchable at runtime in every open window.
  • MaterialColorScheme.FromSeed(accent, isDark, variant) generates a complete light or dark scheme from one accent color (tonal spot, vibrant, fidelity, neutral or monochrome), with every "on" color at 4.5:1 contrast or more.
  • Theme default styles follow the MD3 specs with a desktop density (32 px buttons, 48 px text fields); MaterialSizing.Touch gives the standard MD3 sizes.
  • Styles apply by type or by key (.StyleKey(...), typography shortcuts such as .TitleLarge()), with the precedence theme style < app style < local value.
  • Focus rings appear for keyboard navigation only.

F12 developer tools

In Debug builds, press F12 in any window to open the DevTools beside the window's content (behind a GridSplitter); press it again to put the window back as it was. Release builds contain none of it. F12 and Ctrl+Shift+C are ordinary commands of the "DevTools" window group (KeybindingManager.WindowGroups: shortcuts that work anywhere in a window), so they appear in menus, the command palette and the keybinding editor, and can be rebound.

  • Element tree of the window and its open popups, with search; hovering a node highlights its element.
  • Select Element (Ctrl+Shift+C): the element under the pointer is highlighted live, a click selects it; Escape stops.
  • Properties: every bindable property of the selected element, attached ones included, edited in a PropertyGrid (thicknesses and corner radii as text: 8, 8,4 or 1,2,3,4).
  • Values: all values with their source (local, style, inherited, default, animation), filterable.
  • Layout: the box model (margin, border, padding, content, spacing) drawn over the window and as a diagram, plus position, desired size, alignment, min/max sizes and layout state.
  • Zoom: the selected element magnified pixel by pixel (up to 32×), with a pixel grid, box-model outlines and the color of the pixel under the pointer.
  • Outline every element's bounds, show the frame rate, select the parent or the focused element.

Platform

  • Borderless windows with native resizing, snapping and shadows on Windows; multiple windows with per-window focus.
  • Render-on-demand: idle windows don't draw.
  • Game controllers: Gamepads.First / Gamepads.GetState(i) give sticks (+Y up), triggers (0–1) and buttons in the Xbox layout, from GLFW's gamepad support (Xbox and most other controllers); Gamepads.ApplyDeadzone for dead zones.
  • SilkWindow.Closing intercepts every close request (close button, Alt+F4, taskbar, Close()): cancel it, or pass an async decision such as a "Save changes?" dialog to e.Defer(...); Close(force: true) skips it.
  • Hot reload through .NET Hot Reload, or manually with F5 or Ctrl+R when the app doesn't handle those keys itself.
  • System clipboard, key repeat, and an optional frame-rate overlay (SilkWindow.ShowFpsOverlay).

Project structure

Project Contents
Atelier.Core Visual tree, bindable properties and bindings, styles, routed input, focus, animation, dispatcher, keybindings
Atelier.Rendering SkiaSharp drawing context, paint, font and text caches, text measurement
Atelier.Layout Layout panels and Border
Atelier.Controls The control library
Atelier.Theming Theme infrastructure and renderer registry, theme extensions for other libraries' controls
Atelier.Theming.Material Material Design 3 renderers, color schemes, typography, sizing and default styles
Atelier.Markup The fluent markup API
Atelier.Generators Source generators for commands, keybindings and property-grid metadata
Atelier.NodeEditor Node graph view models, undo, dataflow evaluation and the NodeEditor control (namespace Atelier.Nodes)
Atelier.Audio Controls for audio tools: the Knob, and the timeline model shared by connected timeline controls (TimelineContext for zoom and scroll, TempoMap with tempo and meter changes, TimelinePosition in seconds or beats, and the adaptive beat, time and sample TimelineGrid), the TimelineRuler and TimelineLane, clips on a TimelinePanel, WaveformView with shared WaveformData, and the AudioWaveformEditor for trims, fades, gain and selections
Atelier.Charts The XYChart with its series, annotations and axes (XYSeries, ChartAnnotation, ChartAxis), nice tick math (ChartTicks), zoom and pan commands, renderer and theme styles
Atelier.Graphics3D The 3D scene model (Scene3D, Mesh3D, Material3D, Texture3D, OrbitCamera) and the OpenGL Viewport3D, which renders on the window's GPU context (IHostWindow.GraphicsDevice) and composites into the 2D frame
Atelier.Platform.Silk Windows, OpenGL context, input and clipboard via Silk.NET
Atelier.DevTools The F12 developer tools (Debug builds only)
Atelier.Gallery Showcase application for every control
Atelier.Tests Unit, layout, binding and rendering tests (1,530+)
tools/MakeIcon.cs Makes the gallery's .exe icon (Assets/Icons/Atelier.ico) from the logo; run dotnet run tools/MakeIcon.cs after changing it

Running the Gallery

dotnet run --project samples/Atelier.Gallery

The gallery has a page for every control group. Each page demonstrates the control's properties, events, bindings and states, with the code that builds it. Useful shortcuts:

Shortcut Action
Ctrl+F Search the pages
Ctrl+T Switch between the light and dark theme
Ctrl+Shift+F Show the frame-rate overlay
Ctrl+Shift+P Open the command palette: search and run the commands that work where the focus is
Ctrl+K, Ctrl+S Customize the commands: labels, icons and shortcuts (saved in %APPDATA%\Atelier\Gallery)
F5 / Ctrl+R Rebuild the window content (hot reload; F5 resets the demos on the Keybindings page)
F12 Open or close the developer tools (Debug builds)
Ctrl+Shift+C Select an element with the pointer in the developer tools

To render pages to PNG files without opening a window, as for the screenshots above, set ATELIER_GALLERY_SNAPSHOT=<output folder>. Optionally also set ATELIER_GALLERY_PAGES=0,3,7, ATELIER_GALLERY_THEME=dark, ATELIER_GALLERY_SIZE=1280x800 and ATELIER_GALLERY_SEED=#006A6A[:Vibrant] (a theme generated from that accent color). ATELIER_GALLERY_TOOLTIP=<n> opens the page's n-th tooltip, and ATELIER_GALLERY_FILE_DIALOG=open|save|folder shows a file dialog limited to the repository (run it from the repository folder), and in Debug builds ATELIER_GALLERY_DEVTOOLS=<text>[:tab] opens the developer tools with the first element whose description contains the text selected. ATELIER_GALLERY_COMMAND_EDITOR=<Group>/<Name> opens the command editor with that command selected, and ATELIER_GALLERY_COMMAND_PALETTE=<search> (* for none) the command palette. ATELIER_GALLERY_ARRANGE=1 auto-arranges the page's last node editor and scrolls to it.


Running the tests

dotnet test

License

This project is licensed under the MIT License. Copyright (c) 2026 Markus Luedin.

About

C# UI Library, based on SkiaSharp

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages