An interactive debugger and profiler for branch-and-bound solvers.
Watch the search tree grow event by event — locally, from a single .vbc trace file.
Branch-and-bound trees routinely reach hundreds of thousands of nodes, yet the standard tools for looking at them are still screenshots and log files. BranchScope turns a solver trace into an explorable object:
- Timeline replay — scrub through every node creation, status change, bound update, and incumbent, at 1–2,000 events per second, or step one event at a time.
- Two layouts — a tidy tree whose vertical gaps adapt to each branch's fan-out (so no edge ever collapses into a horizontal line), and a radial layout with curved edges for wide, skewed trees. Switch with one click.
- Filters — status, depth range, node ID, and full-text search over the solver's own node information. Matches keep their ancestors, so the result is always a tree, never a fragment.
- Inspector — every field the trace recorded about a node, its solutions, bounds, and raw info text.
- Privacy by construction — parsing happens in a local WebAssembly worker; your trace never leaves the machine.
- Portable output — export the current view (or any trace) as a single self-contained HTML file you can email to a co-author or embed in a talk.
npm — one command (requires Node.js ≥ 18):
npm install -g branchscope
branchscope view tree.vbcThe npm package fetches the prebuilt platform binary from the project's GitHub releases on install, so no Rust toolchain is involved.
Or download a prebuilt binary — attached to the latest release for macOS (Apple Silicon and Intel), Linux x86_64, and Windows x86_64; no Node or npm required. Unpack and run (the archive ships with the example trace):
./branchscope view tree.vbcmacOS binaries are unsigned, so clear the quarantine attribute the first time:
xattr -d com.apple.quarantine branchscopeRequirements: Rust, the wasm32-unknown-unknown target, wasm-pack, Node.js ≥ 20.
git clone https://github.com/NJUWallSpider/BranchScope
cd BranchScope
cd web && npm install && npm run build && npm run build:export && cd ..
cargo install --path crates/branchscope-cli
branchscope view examples/tree.vbcThe browser opens with the trace loaded. Alternatively, open the web app with
cd web && npm run dev and drop any .vbc file onto the page.
branchscope view tree.vbc # parse + serve the viewer, open the browser
branchscope inspect tree.vbc # summary statistics on stdout
branchscope export tree.vbc -o tree.html # standalone single-file viewer$ branchscope inspect examples/tree.vbc
File: examples/tree.vbc
Nodes: 413
Events: 4,336
Max depth: 18
Solutions: 275
Time range: 0.01 - 0.12 s
| Key | Action |
|---|---|
Space |
play / pause |
← → |
step one event |
F / R |
fit all / jump to root |
/ |
focus the info-text search |
Esc |
clear selection |
examples/tree.vbc is a SCIP COMPLETE TREE trace of the
MIPLIB instance bell5 (413 nodes, 4,336 events), together with the SCIP
settings that produced it. Any .vbc emitted by SCIP's visualization mode
works — BranchScope is solver-independent at the trace level, and the model
abstraction is ready for other trace formats.
Install SCIP (from scipopt.org or a package manager:
brew install scipoptsuite, apt install scip), then point its visualization
module at a file while solving.
Interactively:
scip
SCIP> read instance.lp
SCIP> set visual vbcfilename tree.vbc
SCIP> set visual dispsols TRUE
SCIP> optimize
SCIP> quit
Or non-interactively with a settings file —
examples/tree.vbc.set is exactly the file used for
the bundled example:
scip -f instance.lp -s examples/tree.vbc.setEither way you get a .vbc trace to open with branchscope view tree.vbc.
Traces recorded with #TYPE: COMPLETE TREE carry the richest replay;
BranchScope also accepts SCIP's other visualization output variants.
.vbc ──▶ Rust core parser ──▶ TraceModel ──▶ Rust/WASM worker ──▶ React + Sigma.js (WebGL)
└────────▶ gzip ──▶ standalone HTML
- Rust core (
crates/branchscope-core) parses.vbcinto a normalized, solver-independentTraceModel— the same crate powers the CLI, the browser (viawasm-bindgen), and the exporter, so behavior is identical everywhere. - Web viewer (
web/) renders the tree with Sigma.js on WebGL; node and edge sizes live in world coordinates and follow the camera, so zooming always stays legible. React manages chrome only — 100k-node graphs never become 100k DOM elements. - Standalone export is one HTML file: the viewer plus the trace, gzipped and base64-embedded. Double-click it anywhere; no assets, no CDN, no network.
cargo fmt --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace
cd web && npm test && npm run build && npm run build:exportRegenerate the README animation with cd web && npm run demo (drives a
headless Chrome through the timeline and encodes a GIF with gifenc).
git tag v0.2.0 && git push origin main --tagsThe tag push builds the four platform binaries and publishes the GitHub
release. The npm package publishes from the same pipeline when the repo has
an NPM_TOKEN secret (an npm Automation token); otherwise run
npm publish in npm/ by hand. Keep these versions in sync when releasing:
Cargo.toml (workspace), npm/package.json, and the tag.
Issues and pull requests are welcome. The interesting open directions include CBC/Gurobi trace formats, richer event plugins, and incremental layout for million-node replays.
Built with Sigma.js and Graphology; trace data generated by SCIP.

