Development

Build from source, work on the shared core alongside, and build the browser bundle.

StatusReference
StabilityThe wasm toolchain pin moves

Repositories

Where the code lives
runebender-gpuiThe editor. Runs in the browser and as a native application from one codebase.
runebender-coreThe shared library: editing model, shaping, measurement, curve analysis. No interface.
runebender-xilemThe same editor on Xilem, the Linebender UI stack. It exists to compare the two GUI stacks on one application.
runebender-druidThe original implementation, kept as project history.

The core crate holds everything that does not need a window, so the same font logic serves any front-end put on top of it.

Build and Run

git clone https://github.com/eliheuer/runebender-gpuicd runebender-gpuicargo run

The repository pins a stable Rust toolchain in rust-toolchain.toml. Cargo applies it on its own.

Working on Core Too

Clone the core crate beside the editor, then add a cargo paths override so the local copy replaces the published one.

git clone https://github.com/eliheuer/runebender-core
# .cargo/config.toml, in the directory that holds both checkouts
paths = ["runebender-core"]

Put that file above the two repositories, not inside either one. The override is a local development setting, and committing it would break the build on every other machine.

Where Things Live

The split is the thing to learn first. Font work lives in runebender-core and has no interface attached. The front-end draws and handles input, and calls core for anything that changes a glyph.

Code Layout is the reference: every module in core by concern, every file in the editor, the conventions, and the checks CI runs.

If an edit changes a glyph, it belongs in core, where it can be tested without a window and reused by the other front-ends.

Adding a Tool

The knife is the shortest complete example. Its geometry is knife_cut_glyph, slice_paths and knife_hit_points in core, and the editor touches it in four places.

  1. Add a variant to the Tool enum in main.rs.
  2. Add an icon to themes/toolbar-icons.json in core, and a tile for it beside the other tools.
  3. Handle the pointer in the canvas, under a check for your variant.
  4. Give it a keyboard shortcut in the key handler.
rg 'Tool::Knife' src/main.rsrg 'knife' ../runebender-core/src

Reading those two searches side by side shows the division. Four call sites in the front-end, and the cutting itself in core with tests around it.

Write the geometry in core first and test it there. A tool whose maths only runs when a window is open is one you cannot check.

The Browser Build

The browser build needs a different toolchain from the native one.

RUSTUP_TOOLCHAIN=nightly-2026-08-01 \
CARGO_UNSTABLE_BUILD_STD="std,panic_abort" \
trunk build --release --public-url /gpui/

Two constraints decide that line. The web backend needs wasm atomics and shared memory, and the prebuilt wasm32-unknown-unknown standard library has neither, so std must be rebuilt. That is -Z build-std, which is nightly only. The nightly must also be newer than the pinned stable, because gpui uses library features that stable already has.

Install rust-src and the wasm target for whichever nightly you use.

To deploy, copy dist/ into this site’s public/gpui/. Keep coi-serviceworker.min.js and its script tag at the top of <head>. GitHub Pages cannot send the COOP and COEP headers that shared memory requires, so the worker sets them in the browser instead.

Dependencies

Every dependency comes from crates.io or a public git repository, so a plain clone builds with no local paths.

GPUI and gpui_platform come from the Zed git repository, which does not publish to crates.io. Both are pinned to a revision, so a fresh resolve lands on the same graph.

gpui_platform needs its font-kit feature. Without it the platform falls back to a small embedded font list and no interface text renders at all, while everything else draws normally. Run runebender-gpui --fonts to see what it can resolve.

The widgets are the editor’s own, under src/widgets: text fields on parley, a slider, resizable panel groups, and an in-window menu bar for platforms without a native one.

License

Apache-2.0 or MIT.