Browser-based explorer for hosted spatial-omics and image data. The app loads
10x Xenium and Atera output folders, standard Visium (55 µm spots) and Visium
HD Space Ranger output folders, direct AnnData .h5ad files (including Visium
AnnData with uns/spatial), SpatialData Zarr stores, and image-only
OME-TIFF/TIFF/QPTIFF/OME-Zarr URLs from object storage.
It renders spatial cells, spots, bins, image pyramids, morphology channels, expression
overlays, transcript density/exact overlays, annotations, ROI queries,
shareable view state, and dataset diagnostics without a server-side data
service.
The implementation is a Vite + React application. It uses deck.gl for spatial rendering, DuckDB WASM and Hyparquet for browser-side Parquet queries, GeoTIFF, OME-Zarr, and JPEG2000 decoding for image tiles, and Zarr/HDF5 readers for cell-feature matrices, Feature Slice H5, H5AD, and native transcript LOD access.
npm ci
npm run devUseful development commands:
npm run typecheck
npm run lint
npm run test
npm run build
npm run previewEnd-to-end tests use the built app through Vite preview:
npm run build
npm run test:e2eOne smoke test runs the axe accessibility rules (WCAG 2.2 A and AA) on the
layer sections, the info drawer, the dataset menu, Help, Settings and the
Embedding panel, empty and with a fixture loaded. Known violations are
listed in tests/e2e/axe-baseline.json, and any other violation fails the
test. When you fix one, the test fails until you remove it from the list; to
rewrite the list, run:
UPDATE_AXE_BASELINE=1 npx playwright test --grep "axe baseline"The Vite dev and preview servers are configured with cross-origin isolation headers needed by the browser-side WASM and decoding paths.
To cut a release, open Releases > Draft a new release, create a new vX.Y.Z
tag on main, generate the release notes, and publish. The
Release workflow then type-checks the tag,
runs the unit and E2E smoke tests, builds the app, and attaches it to the
release as explorer-<tag>.zip. Pre-releases get a zip too. To retry, or to
attach a zip to an older release, run the workflow manually with the tag.
The zip holds one explorer-<tag>/ folder with index.html, assets/, and a
version.json that records the tag and commit. Asset paths are relative, so
the folder works when served from a domain root or any subpath. It has to be
served over HTTP; opening index.html from disk does not work. See
Deploy to S3 for hosting it.
src/App.tsxcoordinates dataset loading, controls, diagnostics, URL hash state, ROI workflows, and the viewer shell.src/components/contains the spatial viewer, morphology canvas, error boundary, and viewer model helpers.src/data/contains browser data access for Parquet, Zarr, HDF5, analysis outputs, annotations, ROI queries, diagnostics, range checks, telemetry, and shareable state.src/datasets/defines the spatial dataset interface and platform implementations for Xenium, Atera, standard Visium, Visium HD, H5AD, SpatialData, and image-only sources.src/features/contains domain UI and workflow modules for the app shell, genes, transcripts, annotations, ROI, morphology, cells, diagnostics, and platform-specific behavior.src/rendering/contains deck.gl layer creation, styling, aggregation, viewport logic, opacity handling, and morphology canvas helpers.src/tiff/,src/codecs/,src/zarr/, andsrc/workers/handle tiled OME-TIFF and OME-Zarr loading, JPEG2000 decoding, byte-range chunk access, tile caching, and worker-backed decode concurrency.tests/e2e/contains Playwright coverage; colocated*.test.tsand*.test.tsxfiles cover the data, rendering, component, and store modules.
Enter a source in the Dataset or image URL field:
- Xenium: output folder with
experiment.xenium,cells.parquet, and a readablecell_feature_matrix.zarr.ziporcell_feature_matrix.h5. - Atera: Atera Onboard Analysis output folder with
experiment.spatial,cell_feature_matrix.zarr.zip,csc_cell_feature_matrix.zarr.zip, andcells.zarr.zip, plus themorphology_2d/OME-TIFFs for the image. - Standard Visium (v1/v2, 55 µm spots): Space Ranger
outs/folder withspatial/tissue_positions.csv(or the 1.xtissue_positions_list.csv),spatial/scalefactors_json.json, andfiltered_feature_bc_matrix.h5, plus the hires or lowres tissue PNG; or a.h5adwith the scanpy/CELLxGENEuns/spatial/<library>layout. A dataset manifest loads GEO samples, whose files are renamed and gzipped, in place. - Visium HD: Space Ranger
outs/folder with at least onebinned_outputs/square_*umtier containing positions, scalefactors, and a filtered feature-barcode matrix, plus rootfeature_slice.h5for gene overlays. - H5AD: direct
.h5adfile URL withobs,var,/X, and a supported 2Dobsmcoordinate matrix. Files over 300 MiB need a.h5ad.jsonreference or.h5ad.icechunkrepository next to them. - SpatialData: Zarr store root (v2 or v3) with consolidated metadata, an AnnData table annotating a shapes or labels element, and optionally image elements.
- Image-only: direct OME-TIFF, TIFF, QPTIFF, OME-Zarr, or validated NDPI URL.
- Icechunk: a
.icechunkrepository URL holding AnnData, SpatialData (images, labels, and tables), or an OME-Zarr image.
Files do not have to keep these names. A dataset manifest, explorer.json in
the dataset folder (or any .json URL entered directly), can name the
platform, point to renamed or moved files, and set the genes, layers, and image
channels shown on first load. See Dataset manifest.
Because data is read directly by the browser, hosted datasets must support CORS
and HTTP byte-range requests for large binary assets. The in-app
Diagnose Dataset action checks the detected platform and the key assets for
the active source.
examples/ lists public datasets from data repositories
(BioImage Archive, CELLxGENE, IDR, and others) with links that open them in
the hosted viewer. Each is a dataset manifest pointing at the repository's own
files; add one with npm run examples to refresh the list. The viewer's start
screen reads the same list from main at runtime, so a new example appears
there without a release.
The full index is in docs/README.md.
- User guide: loading supported sources, navigation, layers, genes, transcript overlays, annotations, ROI tools, embeddings, diagnostics, and shareable URLs.
- UI reference: every panel, control, default, viewer interaction, and shareable URL parameter, with platform availability.
- Architecture: detection order, load pipeline, platform gating, coordinates, caching, workers, and error handling.
- Modality read paths: Xenium, Atera, standard Visium, Visium HD, H5AD, SpatialData, and image sources. Each lists the files read, the libraries used, the source modules involved, and known limitations.
- Deploy the React app to S3-compatible object storage: download a release zip or build the Vite app, upload it to AWS S3 or Ceph RGW-style storage, configure edge headers, and validate production.
- Host your own data: required and optional files for Xenium, Atera, standard Visium, Visium HD, H5AD, SpatialData, and image-only sources, plus HTTP requirements and quick validation commands.
- Dataset manifest: the optional
explorer.jsonthat maps renamed files and sets first-load display defaults, with a JSON Schema inpublic/schemas/. - Image-only and GeoJSON annotations: direct image URL support, platform gating, and GeoJSON shape import/export rules.
- S3/CORS hosting playbook: exact CORS headers, object serving rules, byte-range validation, and CDN considerations.
- Cell-feature matrix compatibility: the key decision to prefer native CSC Zarr for fast ROI gene statistics and fall back to HDF5 for older Xenium output, instead of generating custom cell-major sidecars.
- Visium HD 2 µm strategy: why 2 µm first
paint uses filtered matrix barcodes and a derived affine grid instead of the
full
tissue_positions.parquet. - Unified plan: the build plan, phase records, architecture decisions, refactor history, and open items.