2
37
Fork
You've already forked knots
1
High performance cross-platform immediate-mode GUI rendering library. https://shahwali.codeberg.page/knots/
  • Zig 94.2%
  • JavaScript 4.1%
  • WGSL 1.7%
2026年07月12日 19:32:52 +02:00
examples Add worker backed WASM dispatch runtime 2026年07月11日 21:13:34 +02:00
lib/js-bridge Add worker backed WASM dispatch runtime 2026年07月11日 21:13:34 +02:00
src Bump wgpu bindings dep 2026年07月12日 19:32:52 +02:00
tests/snapshots Support wasmxx-freestanding as a compilation target ( #15 ) 2026年07月07日 21:58:38 +02:00
.gitignore init 2026年04月16日 13:32:36 +02:00
.oxfmtrc.json Support wasmxx-freestanding as a compilation target ( #15 ) 2026年07月07日 21:58:38 +02:00
.oxlintrc.json Support wasmxx-freestanding as a compilation target ( #15 ) 2026年07月07日 21:58:38 +02:00
build.zig Add worker backed WASM dispatch runtime 2026年07月11日 21:13:34 +02:00
build.zig.zon Bump wgpu bindings dep 2026年07月12日 19:32:52 +02:00
LICENSE.md init 2026年04月16日 13:32:36 +02:00
README.md Add worker backed WASM dispatch runtime 2026年07月11日 21:13:34 +02:00

Knots

Knots is a high performance cross-platform immediate-mode GUI library written in Zig.

Goals

Below goals are listed in order of importance.

  1. Provide a way to build highly performant cross-platform desktop applications.
  2. UI code should get out of the way, letting the developer spend more time on actual problems.
  3. Minimal lean builds, fast compile times.
  4. Highly configurable, with sane defaults.

Known limitations

  • Linux windowing is Wayland-only.
  • Text rendering is UTF-8/codepoint based. HarfBuzz shaping, bidi layout, ligatures, font fallback, and IME composition are not implemented yet.

Requirements

  • Zig compiler, minimum version can be found in build.zig.zon. I try to keep up with the master branch.
  • On Linux, Wayland development packages are required: wayland-client, wayland-cursor, wayland-protocols, wayland-scanner, pkg-config, and xkbcommon.

Supported platforms

Platform Supported GPU APIs
macOS WebGPU and Vulkan (MoltenVK)
Linux WebGPU and Vulkan
Windows WebGPU and Vulkan
WASM (freestanding) WebGPU

Install

zig fetch --save git+https://codeberg.org/shahwali/knots.git

Minimal app

// build.zigconstknots=b.dependency("knots",.{.target=target,.optimize=optimize});exe.root_module.addImport(knots.module("knots"));// ormod.addImport(knots.module("knots"));
conststd=@import("std");constknots=@import("knots");pubfnmain(init:std.process.Init)!void{varapp=tryknots.App.init(init.io,init.gpa,.{.window=.{.width=1280,.height=720,.title="Playground",},});deferapp.deinit();tryapp.start(frameCb);}fnframeCb(app:*knots.App)!void{constsize=app.viewport.window.getSize();returnapp.e(.{knots.component.Rect{.width=.fixed(@floatFromInt(size.width)),.height=.fixed(@floatFromInt(size.height)),.padding=.init(16,16,16,16),.dir=.column,.key=.src(@src()),},});}

Browser WASM

The following is a complete web-only application.

// build.zigconststd=@import("std");constKnots=@import("knots");pubfnbuild(b:*std.Build)void{consttarget=b.standardTargetOptions(.{});constoptimize=b.standardOptimizeOption(.{});constknots=b.dependency("knots",.{.target=target,.optimize=optimize});constexe_mod=b.createModule(.{.root_source_file=b.path("src/main.zig"),.target=target,.optimize=optimize,.imports=&.{.{.name="knots",.module=knots.module("knots")}},});constexe=b.addExecutable(.{.name="app",.root_module=exe_mod});exe.entry=.disabled;Knots.installWeb(b,knots,exe_mod,exe,.{.index_html=b.path("src/index.html"),});}
// src/main.zigconststd=@import("std");constknots=@import("knots");pubconststd_options:std.Options=.{.logFn=knots.web.logFn};fnframe(app:*knots.App)!void{constsize=app.viewport.window.getSize();tryapp.e(.{knots.component.Rect{.width=.fixed(@floatFromInt(size.width)),.height=.fixed(@floatFromInt(size.height)),.padding=.init(16,16,16,16),.key=.src(@src()),},.{knots.component.Text{.content="Hello from Knots",.key=.src(@src()),},},});}exportfnmain()callconv(.{.wasm_mvp=.{}})i32{constallocator=knots.web.allocator;// synchronizes Zig's single-threaded WASM allocator across workers.constio=knots.web.io;// provides worker dispatch, atomic waits, cancellation, clocks, randomness, and non-UI-blocking sleep.constapp=allocator.create(knots.App)catch|err|returnknots.web.fail(err);app.*=knots.App.init(io,allocator,.{.window=.{.width=1280,.height=720,.title="Knots Web App",.canvas_selector="#canvas",},})catch|err|{allocator.destroy(app);returnknots.web.fail(err);};app.start(frame)catch|err|{app.deinit();allocator.destroy(app);returnknots.web.fail(err);};return0;}
<!-- src/index.html -->
<!doctype html>
<html>
 <body>
 <canvas id="canvas"></canvas>
 <script type="module">
 import { startKnots } from "./knots.js";
 startKnots({ wasmUrl: "./app.wasm", canvas: "#canvas" }).catch(console.error);
 </script>
 </body>
</html>
zig build -Dtarget=wasm32-freestanding

wasm64-freestanding also works in browsers with memory64 support. installWeb configures shared memory and installs the WASM and worker files.

Serve the output over HTTP with:

Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp

These headers isolate the page so browsers can safely expose SharedArrayBuffer, which shared WebAssembly memory requires. Cross-origin resources must allow CORS or embedding via Cross-Origin-Resource-Policy.

Distributing Vulkan applications on macOS

Knots checks for a bundled Vulkan loader before falling back to the system loader. A standalone application bundle using the Vulkan backend must include the loader, MoltenVK, and its ICD manifest:

MyApp.app/Contents/Frameworks/libvulkan.1.dylib
MyApp.app/Contents/Frameworks/libMoltenVK.dylib
MyApp.app/Contents/Resources/vulkan/icd.d/MoltenVK_icd.json

The manifest's library_path must resolve to the bundled libMoltenVK.dylib.

Examples

See examples, you can also try the web version of the playground here.