Node.js & Bun bindings for Zed’s GPUI. Build memory efficient native apps with React or Solid.js
README.md

Downstream branches #

This fork carries the GPUIX changes shared by Slate and Aurelia. Each application pins its own branch:

  • main mirrors remorses/gpuix.
  • shared is upstream plus the changes both applications use. It never references an application.
  • aurelia and slate add one integration commit each on top of shared: the application's crates, native elements and runtime methods. Rebase them when shared moves.

Preparing a checkout #

The Zed submodule stays on upstream's pin. Its GPUI patches live in downstream/zed and are applied to the working tree:

bun vendor/gpuix/downstream/prepare.ts

What shared adds #

GPUI (downstream/zed):

  • Eased mouse-wheel scrolling in lists and scroll containers.
  • Nested scroll containers keep the wheel to themselves.
  • Tail-following lists resume following after a layout change.
  • Even-pixel relative line heights, so single-line text is centred.
  • Shaped text kept across frames, and an unstable scene sort.
  • Windows: callbacks unregistered before a closed window is destroyed.
  • Windows: a window shown on purpose appears even when the launcher asked for a hidden first window, as bun run does.
  • Windows: Oklab gradients convert with the right transfer functions, as upstream's #57543 does, and clamp a channel that rounds below zero, which turned some fully saturated gradients black.
  • Window::paint_glyph_unsnapped places a glyph to a quarter pixel vertically, so text that moves slowly glides instead of stepping.
  • Hover listeners, hover styles and cursors count an element as hovered while the mouse is over one of its descendants, as CSS does. A blocking overlay inside a hovered card no longer un-hovers the card.
  • gpui::grain(light, dark, cell, sparkle) fills a quad with fine noise, as on frosted glass or paper, anchored to the quad so it moves with it.
  • Window::paint_inner_glows paints soft light inside an element: a blurred rounded rect clipped to the element's own shape, for surfaces that seem lit from within.
  • Window::paint_outer_shadows paints drop shadows that stop at the element's edge, as CSS box-shadow does, so they don't show through a translucent element.
  • Content masks can round their corners: a box with rounded corners that hides its overflow clips its content to the curve, as CSS does. A ContentMask carries rounded_bounds and corner_radii beside its bounds; build a plain one with ContentMask::rect(bounds).

GPUIX:

  • hover colors and opacity ease in and out, for custom elements too, and motion animates backgroundColor, borderColor and color.
  • dragOver style while OS files are dragged over an element.
  • <gpuix-cache> regions replayed from the previous frame while unchanged.
  • Per-frame work cut: tree walks only when the tree changes, borrowed style refinements, painted bounds without tracker children, and mimalloc on Windows.
  • Markdown: whole-block and streamed-text fades, images, block layout, code wrap control, inline code font, and a JavaScript highlight provider (onHighlight, answerHighlight).
  • Text asks for its own cursor; <input secure> for secrets; anchored layers centred on their trigger; navigation mouse buttons.
  • Window chrome: clientDecorations and <gpuix-caption action> for native dragging, Snap and caption buttons in an app-drawn title bar; getWindowState() for maximized, active, appearance and display scale.
  • fonts loads font files before the window opens.
  • <img> files and URLs load through a bounded memory (imageMemoryMb, default 256) that drops the least recently drawn images. animated={false} loads only the first frame of an animated file. decodeWidth/decodeHeight shrink a bitmap larger than it is drawn once, as it decodes, and a changed src keeps the old image until the new loads.
  • The native crate is its own Cargo workspace, so it builds inside another repository.