Building from Source
Everything you need to build vizcrush locally — Rust crates → WASM → TypeScript packages → tests → benchmarks.
Prerequisites
| Tool | Version | How |
|---|---|---|
| Node.js | 24+ | mise install (recommended; reads the pin in mise.toml) or nvm install 24 |
| pnpm | 12.3+ | mise install (pinned in mise.toml) or corepack enable (uses the packageManager pin) |
| Rust toolchain | 1.98.1, with wasm32-unknown-unknown target | rustup toolchain install 1.98.1 && rustup target add --toolchain 1.98.1 wasm32-unknown-unknown |
wasm-bindgen-cli | 0.2.128, matching wasm-bindgen | cargo install wasm-bindgen-cli --version 0.2.128 --locked |
wasm-opt (optional) | latest | brew install binaryen or download from binaryen releases |
The repo's mise.toml pins the exact Node and pnpm versions. With mise activated in your shell, cd'ing into the repo selects both automatically; run mise install once to fetch them. Volta is unmaintained and its package.json pin has been removed.
First-time setup
git clone git@github.com:debug-diary-1/vizcrush.git
cd vizcrush
pnpm install
pnpm buildpnpm build runs:
pnpm build:wasm—bash scripts/build-wasm.sh, which compiles each Rust crate to WASM and runswasm-bindgento generate the JS loader + TypeScript declarationspnpm turbo build— runstsc(or each package'sbuildscript) in dependency order via Turborepo
After pnpm build, every package's dist/ and wasm/ directories are populated and you can import from them or run any example app.
Common scripts
From the monorepo root:
# Build everything
pnpm build # Rust → WASM → TypeScript
# Build only the Rust → WASM step
pnpm build:wasm # bash scripts/build-wasm.sh
# Lint & format
pnpm lint # oxlint --deny-warnings
pnpm format # oxfmt (apply)
pnpm format:check # oxfmt --check
# Typecheck
pnpm typecheck # tsc --noEmit per package
# Tests
pnpm test # turbo test (vitest + cargo via per-package scripts)
pnpm test:rust # cargo test --workspace
pnpm test:vitest # vitest run
pnpm test:all # Rust + JS together
pnpm test:examples # bash scripts/test-examples.sh
# Benchmarks
pnpm bench # vizcrush-benchmarks run benchBuilding only the Rust workspace
If you're iterating on a single crate, skip the JS build entirely:
cd crates/vizcrush-downsample
cargo test # quick unit tests
cargo build --release --target wasm32-unknown-unknown # build WASMTo match the +simd128 flag the build script passes (note: this enables the target feature but does not prove that an algorithm's hot loop was vectorized; ADR 0002 found byte-identical output for its LTTB build, a differing aggregate binary, and no measured SIMD speedup):
RUSTFLAGS="-C target-feature=+simd128" \
cargo build --release --target wasm32-unknown-unknownThis is exactly what scripts/build-wasm.sh runs under the hood, plus the wasm-bindgen post-step to generate the JS loader.
Building only one TypeScript package
cd packages/downsample
pnpm build # tsc
pnpm typecheck # tsc --noEmitTurbo's caching means subsequent root-level pnpm build calls will skip this package as long as its inputs haven't changed.
Running an example
pnpm install && pnpm build # one-time
cd examples/streaming-dashboard
pnpm dev # starts vite at http://localhost:5173Each example is wired through the pnpm workspace, so vizcrush packages resolve directly to the local sources — no npm link needed.
Running benchmarks
pnpm benchThis runs benchmarks/dist/runner.js which:
- Generates seeded synthetic time-series datasets at 100K / 500K / 1M sizes
- Times the regression set (LTTB, range filtering, stats, and sort) through the shipped JS cores
- Compares against
benchmarks/benchmark-baseline.jsonand exits non-zero if any metric exceeds the configured threshold (25% by default; CI allows 75% for shared-runner noise)
To capture a new baseline (e.g. after a hardware change):
node --experimental-vm-modules benchmarks/dist/runner.js --save-baselineCI uses a separate workflow (.github/workflows/bench-baseline.yml) that uploads the baseline as an artifact for review before committing.
Cleaning
# Nuke node_modules and rebuild
rm -rf node_modules pnpm-lock.yaml
pnpm install
# Nuke Rust target dir
cargo clean
# Nuke generated WASM artifacts
rm -rf packages/*/wasm/
pnpm build:wasmDocs site (this site)
cd docs/site
python3 -m venv .venv
source .venv/bin/activate.fish # or .venv/bin/activate for bash/zsh
pip install -r requirements.txt
mkdocs serve # http://127.0.0.1:8000The site auto-rebuilds on every Markdown change. To produce a static build:
mkdocs build --strict --site-dir _siteCI runs the same mkdocs build --strict and deploys to GitHub Pages on push to main.
Troubleshooting
??? note "cargo build --target wasm32-unknown-unknown fails" Run rustup target add wasm32-unknown-unknown to install the target. The +simd128 target feature also requires Rust 1.78+.
??? note "wasm-bindgen version mismatch" The CLI must match the wasm-bindgen version in Cargo.lock. Install the pinned release from its lockfile: cargo install wasm-bindgen-cli --version 0.2.128 --locked.
??? note "pnpm install warns about engines" engines.node requires Node 24. Install Node 24 (mise install in the repo root, or nvm install 24). The warning is non-fatal but several dependencies assume Node 24+.
??? note "Ignored build scripts: esbuild" pnpm sandboxes postinstall scripts by default, and pnpm 12 fails the install when a dependency ships an unreviewed build script. The repo's pnpm-workspace.yaml lists the reviewed ones under allowBuilds (esbuild is allowed). When a new dependency adds a build script, add it there as true or false; pnpm approve-builds writes that entry for you.
See also
- Architecture — what gets built and why
- Contributing — workflow for submitting changes