GPU rendered
WebGPU or Vulkan, every frame.
Open source · v0.2.0 preview
Fast, lightweight and written in pure Zig. One codebase for desktop and the web.
zig fetch --save git+https://codeberg.org/shahwali/knots.git
Cross-platform
Your app, written once in Zig.
zig build
aarch64-macosx86_64-windowsx86_64-linuxwasm32Why Knots
WebGPU or Vulkan, every frame.
No C or C++ toolchain. Just Zig.
One language, one build system.
See changes without restarting.
Use the whole thing, or just the UI engine.
Built in the open on Codeberg.
Playground
A real Knots app, compiled to WebAssembly and running in your browser.
WebAssembly · 1.3 MB · Needs a browser with WebGPU
Components
Get started
build.zigEarly preview. Needs a recent Zig; Linux is Wayland-only for now.
const std = @import("std");
const knots = @import("knots");
const ui = @import("ui");
pub fn main(init: std.process.Init) !void {
var app = try knots.App.init(init.io, init.gpa, .{
.window = .{ .width = 1280, .height = 720, .title = "Knots" },
});
defer app.deinit();
try app.start(frame);
}
fn frame(_: *knots.View, frame_context: *ui.Frame) !void {
const size = frame_context.input().logical_extent;
try frame_context.e(ui.component.Rect{
.width = .fixed(@floatFromInt(size.width)),
.height = .fixed(@floatFromInt(size.height)),
.padding = .init(16, 16, 16, 16),
.key = .src(@src()),
});
}
const knots = b.dependency("knots", .{ .target = target, .optimize = optimize });
exe.root_module.addImport("knots", knots.module("knots"));
exe.root_module.addImport("ui", knots.module("ui"));
var context = try ui.Context.init(allocator, .{});
defer context.deinit();
var frame = try context.beginFrame(host_input);
defer frame.deinit();
try buildUi(&frame);
const output = try context.endFrame(&frame);
window.setCursorShape(output.cursor_shape);
const prepared = try painter.prepare(&output.packet, &.{
.width = target_width,
.height = target_height,
.content_scale = host_input.content_scale,
.upload_slot = submission.upload_slot,
.frame_context = submission,
.linear_target = false,
});
try painter.encode(&prepared, host_pass);
const Knots = @import("knots");
const knots = b.dependency("knots", .{
.target = target,
.optimize = optimize,
.web_threads = true,
});
const exe_mod = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
.imports = &.{
.{ .name = "knots", .module = knots.module("knots") },
.{ .name = "ui", .module = knots.module("ui") },
},
});
const exe = b.addExecutable(.{ .name = "app", .root_module = exe_mod });
exe.entry = .disabled;
Knots.installWeb(b, knots, exe_mod, exe, .{});
// zig build -Dtarget=wasm32-freestanding