facett-demo — the live web demo + the reusable demo harness
facett-demo is the showcase: one eframe binary that exercises every facett component with fake-but-realistic data, switchable across all palettes. It builds two ways from the same panel code — a native desktop window and a wasm32-unknown-unknown bundle served on Codeberg Pages:
- Live demo: https://nordisk.codeberg.page/facett
- Native:
cargo run -p facett-demo
This document also specifies the reusable demo harness (facett-wasm-demo) that nornir, holger, and dwarves copy to stand up their own Pages demo with minimal glue.
Build & deploy
All automation is Rust in xtask/ — there is no YAML CI. From the workspace root:
| command | effect |
cargo xtask demo-wasm |
build the release wasm bundle into dist/ (index.html + facett-demo.js + facett-demo_bg.wasm), a self-contained static site |
cargo xtask deploy-pages |
run demo-wasm, then publish dist/ to the pages branch (force-pushed, single squashed commit) which Codeberg serves at the URL above |
The build path is wasm-bindgen --target web (not trunk / wasm-pack). xtask self-bootstraps the wasm32-unknown-unknown target and a wasm-bindgen CLI whose version matches Cargo.lock (a mismatch is the classic blank-canvas failure). dist/ is git-ignored on main; it lives only on the pages branch.
The wasm build is --no-default-features: it drops the native-only region-clip (osm-katana) and the wgpu paint-callbacks, and runs the glow / WebGL backend with the CPU painters. Verify both hosts before deploying:
cargo build -p facett-demo # native
cargo build --release -p facett-demo --target wasm32-unknown-unknown --no-default-features # wasm
The state hook (verify the shipped bundle without a human)
The wasm bundle republishes its whole state_json — every tab, control, and the runtrace "what RAN" ledger — into a process global each frame, exported to JS as window.__facett_state(). A headless Chromium drive (or the browser console) reads it to confirm what actually rendered and ran in the shipped artifact. index.html lifts the named export onto window because --target web exports are module members, not globals. The document is served no-cache and the JS/wasm URLs carry a per-commit ?v=<sha> so a redeploy never serves a stale bundle.
The reusable harness — facett-wasm-demo
facett-wasm-demo is the "one panel, N hosts" edge, packaged so another repo gets a demo without re-deriving the eframe boot. It mounts a panel — a facett_core::Facet (title / ui / state_json) — onto:
- a native window (
NativeDemo), - a wasm / WebGL canvas (
WebDemo) with a pretty panic hook and a…/#<tab>URL-hash deep-link, and - a per-frame state hook (
publish_state/latest_state) for headless drive.
The panel's fixture is whatever the consumer builds the Facet from; the harness never touches a backend, so it runs with no network and no filesystem (browser-safe). gRPC and direct-Rust calls stay first-class alongside this UI edge — the harness is only the canvas host.
facett-wasm-demo/examples/panel.rs is the copy-paste template. It builds native and wasm from the same source and exports its state hook.
How another repo (nornir / holger / dwarves) reuses it
- Depend on the harness in the repo's
<repo>-democrate:
[dependencies]
facett-wasm-demo = "0.1" # path dep while co-developed; crate version once published
facett-core = "0.1"
egui = "0.34"
serde_json = "1"
[target.'cfg(target_arch = "wasm32")'.dependencies]
wasm-bindgen = "0.2"
-
Copy
examples/panel.rsinto the crate'ssrc/main.rsand swapHelloPanelfor the repo's panel, built from its fixture (aholgerregistry-browser panel, anornirtimeline/dep-graph panel, adwarvesCI/CDfacett-cicdpanel). Rename the__demo_stateexport to__<repo>_state. -
Generate
index.htmlin the repo'sxtaskafterwasm-bindgen, from the one template — no per-repo HTML drift:
facett_wasm_demo::IndexHtml {
stem: "holger-demo", // wasm-bindgen emits <stem>.js + <stem>_bg.wasm
canvas_id: "demo_canvas", // must match WebDemo::new(...)
title: "holger — live web demo",
description: "the holger registry browser, in your browser",
state_export: "__holger_state",
cache_bust: &short_git_sha,
}
.write(&dist_dir)?;
- Deploy to the repo's
pagesbranch (Codeberg serves it athttps://nordisk.codeberg.page/<repo>/).facett'sxtask deploy-pagesis the reference: build wasm →wasm-bindgen --target web→ writeindex.html+.nojekyll+.domains→ force-pushdist/topages.
Where a repo's panel is not yet a wasm component (the WIT panel world in dwarves/.nornir/ui-embedding-and-standalone.md), the demo ships facett's own render of the panel as a labelled interim, and upgrades to the true component artifact when that seam lands. The harness API is unchanged either way — it mounts whatever Facet / eframe::App it is handed.