GPUI.NET.Core 0.1.0-preview.1

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

GPUI.NET

GPUI.NET is an experimental C# frontend for Rust GPUI. Applications keep their state and view logic in .NET; a native Rust host validates a compact render protocol and materializes GPUI elements, windows, controls, and retained resources.

The API is semantic rather than a direct binding of every GPUI Rust type. This keeps normal C# code platform-neutral and lets the native implementation evolve behind a versioned C ABI.

The current package line is 0.1.0-preview.1. It is a first preview: public APIs, the semantic schema, and the native ABI may change before a stable release.

Requirements

  • .NET SDK 10
  • the stable Rust toolchain and Cargo
  • the platform prerequisites required by GPUI

The repository contains native package targets for win-x64, osx-x64, osx-arm64, and linux-x64. Windows and macOS are the actively exercised desktop environments. macOS builds use GPUI runtime shaders, so the Apple command-line development tools are sufficient for shader compilation.

Build and run

From the repository root:

dotnet build Gpui.slnx
dotnet test Gpui.slnx --no-restore
cargo test --manifest-path crates/gpui-dotnet/Cargo.toml
dotnet run --project samples/Gpui.Sample

The managed build compiles the native host for the current machine and copies it beside the managed output. The sample demonstrates themes, native and managed title bars, menus, multiple windows, retained controls, virtual lists and tables, images, and overlays.

Small application

using Gpui;
using static Gpui.Units;

var application = new GpuiApplication();
application.SetTheme(GpuiTheme.CreateDefault(GpuiThemeAppearance.Dark));
application.OpenWindow(
    new MainView(),
    new GpuiWindowOptions
    {
        Title = "Hello GPUI.NET",
        Width = 900,
        Height = 600,
    }
);
application.Run();

[GpuiView]
internal sealed partial class MainView : View
{
    private int _count;

    protected override Element Render(ref RenderContext ui) =>
        ui.VStack(
                ui.Text($"Count: {_count}"),
                ui.Button("increment", "Increment")
                    .OnClick(this, (view, _) =>
                    {
                        view._count++;
                        view.Invalidate();
                    })
            )
            .Gap(Px(12))
            .Padding(Px(20))
            .Grow()
            .Background(ui.Theme.Colors.Background)
            .TextColor(ui.Theme.Colors.Text);
}

[GpuiView] generates the factory used for framework-owned child views and NativeAOT. Render() describes UI into a native-owned arena and may be retried when that arena grows, so state changes, I/O, and task creation belong in events or lifecycle methods rather than in Render().

On Windows, the application executable must embed a Common Controls v6 manifest because the native host uses Windows common-control APIs. Set ApplicationManifest in the project file and use samples/Gpui.Sample/app.manifest as the reference manifest.

Mental model

C# application and View state
        │ dirty render
        ▼
flat RenderArena: nodes, operations, children, UTF-8
        │ ABI v1 + semantic schema hash
        ▼
Rust validation and retained snapshot
        │
        ├── semantic adapters ──► GPUI elements and deferred layers
        └── retained resources ─► scroll, list/table, input, slider

Clean native repaints do not call managed Render(). High-frequency state such as scrolling, selection, pointer interaction, IME composition, and slider movement stays in Rust. Managed code is called for dirty renders, bound events, and coarse virtual-row batches.

Views and events

Child views are retained by slot. Use a keyed slot when a route or tab may replace the child type:

var content = _page switch
{
    Page.Home => ui.Child<HomeView>("content"),
    Page.Settings => ui.Child<SettingsView>("content"),
    _ => throw new InvalidOperationException(),
};

Use View<TProps> for parent-owned inputs. Props are required on every declaration, while a stable key retains the same child instance and its local state. TProps must implement IEquatable<TProps>; records and record structs do so automatically:

ui.Child<CounterCardView, CounterCardProps>(
    "account",
    new("Account", revision)
);

View and View<TProps> are separate specializations of a shared runtime base, so calling ui.Child<CounterCardView>() for a props view is a compile-time error. The generated factory is used only for reflection-free, NativeAOT-safe child construction.

Events are bound at the element declaration and target a mounted view:

ui.Button("save", "Save").OnClick(this, (view, _) => view.Save());
ui.Input("search"u8).OnChanged(this, (view, e) => view.Search(e));

Task and ValueTask handlers are observed by the session. View lifetime follows UI ownership: a window owns its root and a committed slot owns its child; an ordinary C# reference owns neither. Each View has one lazily allocated, stable Lifetime token, cancelled before terminal OnUnmounted() cleanup. An unmounted instance cannot be reused. See View lifecycle.

Managed render and lifecycle work is confined to GPUI's application thread. Invalidate(), Dispatcher.Post, and controller commands are safe ingress points from worker threads. See Lifecycle and threading.

Themes and application-owned variants

Every render context exposes the active application theme through ui.Theme. A theme can be defined in code or loaded from direct or Zed-style JSON:

application.SetTheme(GpuiTheme.LoadJson("theme.json"));

var card = ui.VStack(content)
    .Background(ui.Theme.Colors.SurfaceBackground)
    .TextColor(ui.Theme.Colors.Text)
    .BorderColor(ui.Theme.Colors.BorderVariant);

Theme changes update managed views, virtual rows, and native control defaults. Theme tokens cover semantic colors and typography. Product-specific names such as Primary, Danger, or Navigation remain application-owned: implement IGpuiElementStyle<TTag> and apply the value with .Style(...). Styles compose ordinary fluent operations, including native Hover* and Active* paint states.

Windows, title bars, and menus

One GpuiApplication owns one native event loop and any number of independent windows. Each window has its own root view tree, retained resources, render snapshots, and failure boundary.

var window = application.OpenWindow(
    new DocumentView(),
    new GpuiWindowOptions
    {
        Title = "Document",
        TitleBarStyle = WindowTitleBarStyle.System,
    }
);

window.SetTitle("Renamed document");
window.Resize(1000, 720);
window.Activate();

WindowTitleBarStyle supports System, Custom, and Hidden. Custom title bars use semantic WindowControlArea regions for native drag, minimize, maximize, and close behavior.

Declare application commands once with GpuiMenu[]. macOS installs them in the global native menu bar. GpuiTitleBar.RenderWindow uses the same definitions for a minimal managed menu/title bar on Windows and Linux; macOS keeps its system title bar unless forceManagedMenuOnMac is requested. The helper is optional—applications may compose PopoverMenu, buttons, and control regions manually.

Retained controls and data

The following components keep interaction state in Rust across managed renders:

  • Scroll: offset, wheel/trackpad motion, and overlay scrollbar
  • List: viewport, measurements, keyboard navigation, and batched row cache
  • Table: the list row engine plus declarative native column/header layout
  • Input: value, selection, focus, clipboard, IME, caret, and horizontal reveal
  • Slider: value/range, pointer drag, keyboard interaction, and release events

Controllers provide imperative operations without moving ownership back to C#. For example, ScrollController.ScrollToTop, ListController.ScrollToItem, InputController.Focus, and SliderController.SetValue enqueue native resource commands.

Virtual rows are generated in aligned batches:

[GpuiListItem]
private Element Row(int index, ref RenderContext ui) =>
    ui.Button("row", $"Row {index:N0}")
        .OnClick(this, (view, e) => view.OpenRow(e), checked((ulong)index));

protected override Element Render(ref RenderContext ui) =>
    ui.List(
            ref _list,
            new ListDataSource(_items.Count, _contentRevision),
            Rows.Row
        )
        .Grow();

Increment contentRevision whenever cached row output can change. Rows are element-only snapshots, not mounted child views, and cannot contain nested retained resources or deferred layers.

Images, vector drawings, and overlays

ui.Image sends a filesystem path and presentation options to GPUI's native decoder/cache. Supported fits are Fill, Contain, Cover, ScaleDown, and None.

ui.Drawing layers native vector paths inside normal GPUI layout. A ViewBox maps stable drawing coordinates into the final element bounds, while stroke widths remain device-independent pixels:

var area = ui.Path()
    .MoveTo(0, 100)
    .LineTo(50, 35)
    .LineTo(100, 60)
    .LineTo(100, 100)
    .Close()
    .Fill(ui.Theme.Colors.Accent.WithAlpha(40));

var line = ui.Path()
    .MoveTo(0, 100)
    .LineTo(50, 35)
    .LineTo(100, 60)
    .Stroke(ui.Theme.Colors.Accent, Px(2));

return ui.Drawing(area, line).ViewBox(0, 0, 100, 100).Height(Px(240));

Paths support lines, quadratic and cubic Bézier curves, elliptical arcs, fill rules, strokes, and dash patterns. Rect, Ellipse, Circle, and Line are convenience path factories. Circle keeps a uniform rendered radius when a ViewBox scales its axes independently; Ellipse follows the independent axis scales.

For app-defined animation, ui.Dynamic(active, child) transparently requests one managed render per display frame while active remains true. Compute progress from a monotonic clock and rebuild the target subtree normally; invalidations are synchronized to GPUI frames and deduplicated per owning View:

var progress = Math.Clamp(Stopwatch.GetElapsedTime(_started).TotalSeconds / 0.4, 0, 1);
return ui.Dynamic(progress < 1, RenderChart(ref ui, (float)progress));

Window-relative composition includes:

  • Overlay for generic modal or non-modal layers
  • Dialog and Sheet as overlay compositions
  • Tooltip for delayed, trigger-relative content
  • ContextMenu for pointer-anchored right-click content
  • PopoverMenu for trigger-attached left-click menus

Rust owns placement, viewport clamping, focus restoration, stacking, and dismissal. Layer content and actions remain normal managed elements and callbacks.

Repository layout

bindings/                 semantic component and operation schema
crates/gpui-dotnet/       Rust native host
src/Gpui/                 managed public API and runtime sources
src/Gpui.Core/            platform-neutral package project
src/Gpui.Native/          RID-specific native package projects
src/Gpui.Generators/      Roslyn generators for views and list rows
samples/Gpui.Sample/      interactive component gallery
tests/Gpui.Tests/         managed contract and generator tests
tools/                    semantic binding generator and UI driver
eng/                      native build, staging, and packaging scripts
docs/                     design and contributor documentation

Development checks

Run these before submitting changes:

dotnet run --project tools/Gpui.Bindings.Generator -- verify
cargo fmt --manifest-path crates/gpui-dotnet/Cargo.toml -- --check
cargo test --manifest-path crates/gpui-dotnet/Cargo.toml
dotnet test Gpui.slnx --no-restore
dotnet build samples/Gpui.Sample/Gpui.Sample.csproj --no-restore

When bindings/schema.json changes, regenerate both managed and Rust bindings:

dotnet run --project tools/Gpui.Bindings.Generator -- generate
dotnet run --project tools/Gpui.Bindings.Generator -- verify

Do not edit Semantic.g.cs or semantic.g.rs by hand.

Documentation

GPUI Component and Zed are implementation references, but GPUI.NET keeps its own semantic ABI and pinned GPUI dependency. See NOTICE for attribution.

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 GPUI.NET.Core:

Package Downloads
GPUI.NET

GPUI bindings for .NET.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.1.0-preview.1 35 9/1/2026