Guide
Compile & distribute #
Knots uses the Zig build system. A native build installs one executable. A browser build installs a directory of static files that any web server can host.
Native apps #
Build a release for the target that you ship:
zig build -Doptimize=ReleaseSafe
zig build -Doptimize=ReleaseSafe -Dtarget=x86_64-windows
zig build -Doptimize=ReleaseSafe -Dtarget=aarch64-macos
The executable is in zig-out/bin. Also ship the files that your app reads.
| Target | The user must have |
|---|---|
| Linux |
A Wayland session, libwayland-client,
libwayland-cursor, libxkbcommon, and a Vulkan 1.3
driver for the Vulkan backend.
|
| Windows | A Vulkan 1.3 driver for the Vulkan backend, or Direct3D 12 for WebGPU. |
| macOS |
Nothing for the WebGPU backend. For Vulkan, put MoltenVK and
libvulkan.1.dylib in the Frameworks directory of the
app bundle.
|
Knots does not need a C++ runtime. Cross-compilation works for the Vulkan backend on all targets. Linux targets link to system Wayland libraries, so they need those libraries for the target. Read GPU backends for the backend choice.
Browser builds #
A browser build needs three changes to a native project:
- Disable the entry point of the executable and call
Knots.installWeb. - Export a start function from Zig instead of
main. - Add an HTML page that loads
knots.js.
The tutorial shows all three. The build part is:
const Knots = @import("knots");
if (target.result.cpu.arch.isWasm() and target.result.os.tag == .freestanding) {
exe.entry = .disabled;
Knots.installWeb(b, knots, exe.root_module, exe, .{
.index_html = b.path("web/index.html"),
});
} else {
b.installArtifact(exe);
}
zig build -Dtarget=wasm32-freestanding -Doptimize=ReleaseSmall
installWeb options #
| Option | Default | Description |
|---|---|---|
dir |
"web" |
The directory in zig-out for the files. |
start_symbol |
"main" |
The exported Zig function that the page calls to start. |
index_html |
null |
An HTML file to install as index_name. |
extra_export_symbol_names |
&.{} |
More Zig functions that the page can call. |
host_js_name, bridge_js_name, wasm_name
|
knots.js, js-bridge.js, app.wasm
|
The names of the installed files. |
Knots.addWebInstall does the same as installWeb, but returns
the step and does not add it to the install step.
The page #
startKnots in knots.js loads the WASM file and starts the app.
It returns the WebAssembly instance, so the page can call functions that you export
with extra_export_symbol_names:
import { startKnots } from "./knots.js";
const { instance } = await startKnots({ wasmUrl: "./app.wasm", canvas: "#canvas" });
instance.exports.app_set_dark(matchMedia("(prefers-color-scheme: dark)").matches ? 1 : 0);
The Zig side of the browser API is knots.web. It contains
allocator, io, fail, and
logFn. Set std_options.logFn = knots.web.logFn to send
std.log output to the browser console.
Threads in the browser #
By default, browser builds use worker threads for App.dispatch. Threads
need shared memory, and browsers allow shared memory only on a cross-origin isolated
page. Serve every page that loads the app with these headers:
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
If your host cannot send these headers, or if the app is in an
iframe on a page that you do not control, disable threads:
const knots = b.dependency("knots", .{
.target = target,
.optimize = optimize,
.web_threads = false,
});
Without threads, the build uses normal memory and installs no worker scripts.
App.dispatch then returns error.ConcurrencyUnavailable.
With threads, the install directory also has knots-worker-pool.js and
knots-worker.js. Deploy them with the other files.
Release checklist #
- Build the exact target and optimization mode that you publish.
- Test on each target OS, GPU driver, and display server.
- For the web, deploy all files in the install directory.
- For threaded web builds, check the COOP and COEP headers before you test.
- Serve
.wasmfiles with the typeapplication/wasm. - Install your own assets and configuration files with your build.