Developing devpage

How to work on devpage itself: build it, run its tests and the three gates, run the documentation while you edit it, and know what needs a rebuild. The code map and the tests go one level deeper. It is a task article under Engineering; how a change travels from idea to main is the SDLC.

You need the toolchain from Installing devpage. Every command runs from the repository root.

Build and run

cargo build                 # debug build, target/debug/devpage
cargo run -- docs           # build if needed, then serve these docs

Building devpage builds no WebAssembly: the design engine's module for the browser is vendored in assets/vendor/, and the binary embeds it.

Run it from the repository root: the folder devpage starts from is the served folder, so the whole repository is served and the docs' links to ../LICENSE work. cargo run -- <args> passes everything after -- to devpage, so cargo run -- check docs and cargo run -- pdf docs/talks/devpage work the way an installed devpage would. It prints the address — http://localhost:3030, or the next free port up if another devpage already holds 3030.

The vendored design engine

assets/vendor/design-engine.wasm and assets/vendor/design-engine.js are the engine built for the browser and its bindings, committed like the pele bundle. Rebuild them after changing anything they are built from:

cargo run -p devpage-design-module

It builds devpage-design-wasm for wasm32-unknown-unknown in the size-optimised wasm profile, into target/design-module/, runs wasm-bindgen on it as a library, and writes the two files and assets/vendor/design-engine.fingerprint (Dependencies). The target is the one rust-toolchain.toml names, so rustup adds it in a checkout; nothing else needs it. The fingerprint is a SHA-256 of everything the module is built from: every file in design/src/, design/fonts/, design/proto/, design/wasm/src/ and design/module/src/, the three crates' Cargo.toml and design/build.rs, the wasm profile, and the locked version of every package in the module's and wasm-bindgen's dependency trees. The toolchain is recorded beside it but not hashed, so the same sources give the same fingerprint on every machine. cargo test fails while the recorded fingerprint differs from the sources', and says to run the command.

The edit–save–refresh loop

What you edit decides what you have to do to see it:

You change What it takes
A Markdown page under docs/ Save. Pages are read on every request and the open page updates itself.
A page's Topics list Save. The sidebar is rebuilt on every request, on every open page.
docs/devpage.yml, or any document file Save. Document files are read on every request and the index of them is kept current by the watcher.
Rust code in src/ Stop devpage (Ctrl-C) and cargo run again, then reload the browser tab. A page reconnects to its event stream by itself, but doesn't fetch itself again on reconnecting.
assets/style.css, assets/devpage.js, assets/design.js, assets/vendor/pele.js Rebuild and restart — they are compiled into the binary with include_str! — then do a full reload of the tab. Live updates and in-place links swap only the page content and its navigation, never the stylesheet or the scripts.
A .design file, or an image a design uses Save. The design store resolves again the designs made from that file and the open canvases redraw in place (Designs).
The engine in design/src/, the module in design/wasm/src/, or design/proto/design.proto Run cargo run -p devpage-design-module to rebuild the vendored module, then rebuild and restart devpage, and do a full reload of the tab — the binary embeds the module. After changing what the engine draws, run DEVPAGE_UPDATE_REFERENCES=1 cargo test -p devpage-design to rewrite the reference PNGs in design/testdata/, and look at them before committing.

Tests

$ cargo test                  # all four crates; needs no network and no Chrome
$ cargo test -- --ignored     # the tests that drive Chrome

Run the Chrome tests after changing the page script, the design script, the module, the stylesheet, a widget, print mode, devpage pdf, a slide's PNG, or devpage video and its recorder (assets/video.js). They drive chrome-headless-shell — devpage video's, Chrome for Testing — never a Chrome installed on the machine. What each module's tests pin, the watcher tests that need file-system events, and what has no test, is on Tests.

The gates

Green before any pull request opens (from AGENTS.md):

cargo fmt --check
cargo clippy --all-targets -- -D warnings
cargo test

Formatting must match rustfmt's defaults, clippy's warnings — on tests too — are errors, and the suite passes. There is no CI yet, so nothing runs these for you: run them by hand before you push. See CI.

The code

devpage is one binary — main.rs and its modules — with its built-in assets and the system widgets, and the design engine in three workspace crates beside it. Which module does what, and how main wires them together, is on the Code map; what each crate does is in Dependencies.

Working on the docs

These docs are a devpage site: docs/devpage.yml, rooted at docs/README.md. Keep cargo run -- docs open, from the repository root, while you write, and run cargo run -- check docs before you push — cargo test checks the same internal links. How to write and organize pages is in the viewer's task articles; the reading hierarchy this repository follows is the documentation skill, .claude/skills/documentation/SKILL.md. Check every diagram you add with the Node command in Diagrams.

Topics