@cirrobio/spatial-viewer
The WebGL spatial and embedding canvases from Spatial Data Studio, plus the checkpoint reader that feeds them, as a library. Spatial Data Studio renders its canvas from this package; a Cirro dashboard tile can import the same components instead of embedding the whole app in an iframe. One source of truth for the canvas.
What's in it
SpatialCanvas/EmbeddingCanvas— the deck.gl canvases, with their layers, legends, minimap, lasso and shape-annotation editing.CanvasHostProvider— the contract a host implements to drive them (see below).DataSourceProvider+openCheckpoint— the read surface the canvases render through, and the.zarr.zipreader that implements it over HTTP Range with zarrita and no backend at all.openCheckpointalso returns the file'sapp_state, its field inventory, and itsfiguresindex (which plots it carries a rendered figure for);DataSource.getPlotFigure(plotId, format)reads one as a blob, so a host can show the saved SVG/PDF/PNG figures without a backend.- The display model (
DisplaySpec,DisplayEncoding,SessionFields,ImageInfo, …) andSPATIAL_ENCODING_DEFAULTS/EMBEDDING_ENCODING_DEFAULTS— the fallbacks the canvases apply for absent encoding fields, so a host authoring a display agrees with what the canvas will actually render.
Using it
import {
CanvasHostProvider, DataSourceProvider, SpatialCanvas, openCheckpoint,
} from '@cirrobio/spatial-viewer';
const { source, appState } = await openCheckpoint(url);
<DataSourceProvider source={source}>
<CanvasHostProvider host={host}>
<SpatialCanvas
display={display}
sessionId={id}
canvasMode={null}
annotationTarget={null}
followDisplayViewport
/>
</CanvasHostProvider>
</DataSourceProvider>CanvasHost is the only seam between the canvases and whoever is hosting them: the field inventory, the data versions, the theme, the edit gate, and onDisplayChange — the host decides what persisting a display edit means. Region drawing, shape annotations and snapshot export are optional groups; omit one and the canvas turns that feature off, affordances included, rather than offering a control that does nothing.
No stylesheet
The package ships no CSS. The in-canvas overlays (legends, hints, minimap, loading cues) carry their own inline styles, which read the host's theme tokens (--color-surface, --color-text, …, as space-separated RGB channels) when they are defined and fall back to a dark palette when they are not.
An in-canvas settings panel is not included — it is host UI. Both canvases take an optional controls slot that receives the canvas-internal state a panel needs (channels, the live camera, the resolved legend); pass nothing for a bare canvas.
Peer dependencies — you must dedupe
@deck.gl/*, @luma.gl/* and @math.gl/* are peers, never dependencies. deck.gl registers layers on a module-level registry and checks instanceof across package boundaries, so a second copy of any of them silently breaks picking and layer updates. Viv (@vivjs/*) pulls its own copies, so a consumer must force a single one — this repo does it with Vite's resolve.dedupe:
resolve: {
dedupe: ['@deck.gl/core', '@luma.gl/core', '@luma.gl/engine', '@luma.gl/webgl', '@math.gl/core'],
}apache-arrow is >=13 on purpose. The package is not "type": "module": apache-arrow 13 has no types export condition, so a CJS-typed package resolves its Arrow.dom.d.ts while an ESM one does not. That is what lets one arrow version serve both this repo (18) and @cirrobio/dashboard (13). Do not add "type": "module".
Releasing
Nothing is published yet, and package.json deliberately declares no license — neither this repo nor frontend/package.json declares one, so picking a license for the extracted package is a decision for a human, not a default to invent. Set it before publishing.
To make this consumable outside the repo, a human has to either:
- Publish to npm —
npm publish -w @cirrobio/spatial-viewerunder the@cirrobioscope (--access publicif the scope is public), after bumpingversion. Consumers then take a normal semver range. - Or reference it from git, the way
Cirro-portalreferencesCirro-components: a dependency ongithub:CirroBio/squidpy-viewer#<ref>with the package underpackages/viewer. That needsdist/to be committed or apreparescript that builds it on install, since git installs run no publish pipeline.
Either way npm run build (Vite library mode + tsc --emitDeclarationOnly) is what produces dist/, and the app is built from the same sources by the repo root's npm run build.