A JBrowse 2 plugin that adds a GraphGenomeView for pangenome graphs (GFA / rGFA), plus a right-click launcher to open the local subgraph around a region from a linear genome view.
The HLA class II locus of the HPRC human pangenome, the same subgraph in two layouts:
| Anchored (rGFA, reference-aligned) | Force-directed (Bandage) |
|---|---|
![]() |
![]() |
Left: rank-0 backbone drawn at its GRCh38 offsets with each rank on its own row, under the bubble and segment feature tracks it was launched from. Right: the same subgraph laid out by the Bandage force engine, the shape people recognize.
It ships three layouts:
- Anchored (rGFA only): x is reference bp, one row per stable rank, read from the file so it renders instantly and aligns under a linear view.
- Sample rows (rGFA only): x is reference bp, one row per contributing assembly.
- Force-directed: the graph's shape, computed by the OGDF FMMM engine from Bandage.
This plugin is GPL-3.0-or-later. The force-directed layout is computed by a WebAssembly build of Bandage's FMMM layout from OGDF, and both Bandage and OGDF are GPL-licensed, so this plugin takes the same license rather than linking around it.
JBrowse itself is unaffected and stays Apache-2.0: this is a separate plugin, loaded at runtime only by configs that ask for it. The anchored and sample-row layouts are pure TypeScript and need no external engine.
Requires pnpm.
This plugin depends on @jbrowse/render-core, which is not yet published to npm,
so it is consumed via a link: to a sibling jbrowse-components checkout. Clone
both side by side:
~/src/jbrowse-components/ # provides @jbrowse/render-core
~/src/jbrowse-plugin-graphgenomeviewer/
Then:
pnpm install
pnpm start # esbuild watch, serves dist/out.js on :9000 with CORSIn another terminal, serve a JBrowse Web that points at config.json (its
plugins entry already targets http://localhost:9000/dist/out.js).
pnpm build # native ESM bundle via esbuild (code-split)
pnpm typecheck # tsc, separately — esbuild strips types without checking themThis writes the plugin to dist/, and the whole directory must be served
together — the entry loads its sibling chunks relative to its own url:
jbrowse-plugin-graphgenomeviewer.esm.js— the plugin entrychunks/bandage-layout-<hash>.js— the Bandage layout engine (~425kb), imported on demand and named by content hash so a redeployed engine is never served from cachechunks/*.js— other lazily-loaded code split out of the entry
Load the plugin from any JBrowse 2 config with an esmUrl:
{
"plugins": [
{
"name": "GraphGenomeView",
"esmUrl": "https://your-host/jbrowse-plugin-graphgenomeviewer.esm.js"
}
]
}Note: ESM plugins are loaded via a dynamic import(), which cannot carry a
subresource-integrity hash the way a UMD <script integrity> can. For a
deployment that needs pinned, tamper-evident bytes, serve the plugin from an
immutable, version-pinned url on a host you control.
Generate the digest with
openssl dgst -sha384 -binary FILE | openssl base64 -A. The engine chunk is
already immutable by content hash, so it needs no separate pin.
The engine is a lazy chunk: it is only fetched the first time someone selects the
force-directed layout, so sessions that use the anchored or sample-row layouts
never download it. Its URL is derived from the plugin's own URL above, which is
why the two files need to sit together — the layout RPC runs in a web worker and
resolves the location from the plugin definition JBrowse passes in. A layoutUrl
option on the view overrides that if you need to host the engine elsewhere.
src/bandage/bandage-layout.js is a committed build artifact, so a normal
pnpm build never needs Emscripten. Regenerate it only when the C++ layout
sources change:
pnpm build:wasm # needs emsdk + a BandageNG checkout (BANDAGE_DIR)It compiles with -sSINGLE_FILE=1, embedding the wasm as base64 so the result is
one self-contained ES module that esbuild can copy rather than bundle.
pnpm test # vitest unit tests
pnpm test:watch
pnpm test:wasm # runs the committed Bandage engine, no deps needed
pnpm test:e2e # puppeteer, opt-in — see test/README.md
pnpm lint
pnpm typecheckpnpm test:e2e drives the force layout through a real JBrowse in a headless
browser. It is gated behind RUN_E2E=1 until the graph_viz jbrowse-components
branch ships; test/README.md explains why and how to run it.

