npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@orbidicom/core

v0.11.7

Published

Framework-agnostic engine for a modern, mobile-responsive DICOM viewer: Cornerstone3D setup, pluggable PACS/local DataSources, tools and W/L presets.

Downloads

4,425

Readme

@orbidicom/core

Framework-agnostic engine for OrbiDICOM — a modern, mobile-responsive DICOM viewer. Owns Cornerstone3D setup, the pluggable DataSource interface (PACS / DICOMweb / local files), auth strategies, and the tool/window-level preset registry.

No Vue, no DOM-framework code, no hardcoded endpoints.

Note: OrbiDICOM's source repository is currently private, so the github.com/docorbitapp/orbidicom links in this README are not yet publicly accessible.

What's inside

  • Data sourcesDicomWebDataSource (QIDO/WADO-RS), LocalDataSource (.dcm files), NiftiDataSource, all implementing the pluggable DataSource interface.
  • Auth strategiesnone / basic / bearer / cookie / custom.
  • RegistriesregisterTool / registerWindowPreset and a modality-aware windowPresetsFor preset engine.
  • Keyboard shortcuts — a framework-agnostic keymap (DEFAULT_KEYMAP, resolveHotkey, resolveEditCommand for undo/redo).
  • Cornerstone3D setupinitCornerstone, createStack, plus DICOM metadata + SR parsing.
  • Annotations & reports — measurement export (JSON/CSV) + DICOM-SR (buildMeasurementSr) with Part-10 encoding (dicomJsonToPart10) for STOW-RS upload, plus create/delete undo/redo (annotationHistory) and key-image export (keyImagesToJson).
  • DICOM-SEG — parse + decode a SEG into per-image labelmaps (getSegmentation, buildSegLabelmaps) and render it over a stack (StackHandle.showSegmentation); read-only.

Install

npm install @orbidicom/core

Just want to look at images? You don't need to write any code. The orbidicom CLI serves the full viewer in one command — npx orbidicom for local files, or npx orbidicom --pacs <url> against a DICOMweb PACS. Reach for @orbidicom/core when you're embedding the engine in your own app or wiring a custom backend.

Usage

Use a built-in data source:

import { DicomWebDataSource } from "@orbidicom/core";

const source = new DicomWebDataSource({ root: "/dicom-web" });
const series = await source.getSeries(["1.2.840…"]);
const imageIds = await source.getImageIds(series[0]);

Authentication

Every DicomWebDataSource takes an optional auth strategy (the discriminator is kind). none (default) and cookie add no Authorization header — cookie rides on withCredentials for a cross-origin session — while basic, bearer, and custom inject headers:

new DicomWebDataSource({ root: "/dicom-web" }); // same-origin, no header
new DicomWebDataSource({ root: "https://pacs/dicom-web", auth: { kind: "cookie" } });
new DicomWebDataSource({
  root: "https://pacs/dicom-web",
  auth: { kind: "basic", username: "user", password: "pass" },
});
new DicomWebDataSource({
  root: "https://pacs/dicom-web",
  // A bearer token can be a string, or a (possibly async) function for refresh:
  auth: { kind: "bearer", token: () => getFreshAccessToken() },
});

Other built-in sources

import { LocalDataSource, NiftiDataSource, DicomJsonDataSource } from "@orbidicom/core";

// Offline: parse dropped .dcm files (a study folder or zip), no server.
const local = new LocalDataSource();
await local.addFiles(fileList); // File[] from an <input> / drag-drop

// A single .nii / .nii.gz volume.
const nifti = new NiftiDataSource();
await nifti.addFile(niiFile);

// In-memory DICOM-JSON metadata (e.g. a QIDO/WADO-RS response you already hold).
const json = new DicomJsonDataSource({ metadata, root: "/dicom-web" });

…or add your own backend by implementing the DataSource contract — getSeries, getImageIds, optional getMetadata / downloadArchive, plus capabilities. The UI never branches on backend type, so a new backend is a new adapter, not a UI change:

import type { DataSource, SeriesSummary } from "@orbidicom/core";

class MyPacs implements DataSource {
  capabilities = { multiStudy: true };
  async getSeries(studyUids: string[]): Promise<SeriesSummary[]> {
    /* … */ return [];
  }
  async getImageIds(series: SeriesSummary): Promise<string[]> {
    /* … */ return [];
  }
}

Register window presets for any modality (CT ships five standard windows):

import { registerWindowPreset, windowPresetsFor } from "@orbidicom/core";

registerWindowPreset({ modality: "MR", name: "Brain T2", windowWidth: 2200, windowCenter: 1100 });
windowPresetsFor("MR"); // → [{ modality: "MR", name: "Brain T2", … }]

Search a worklist (QIDO-RS)

DICOMweb sources advertise capabilities.studySearch and implement searchStudies — a StudyQuery in, StudySummary[] out:

const studies = await source.searchStudies({
  patientId: "12345",
  modality: "CT",
  studyDate: "20240101-20241231", // DICOM date range
  limit: 50,
});
// → [{ studyInstanceUID, patientName, studyDate, modalitiesInStudy, … }]

Export measurements (JSON / CSV / DICOM-SR)

Collect the on-screen annotations, then serialize them. The same measurements feed a Comprehensive DICOM-SR document:

import {
  collectMeasurements,
  measurementsToCsv,
  measurementsToJson,
  buildMeasurementSr,
} from "@orbidicom/core";

const measurements = collectMeasurements(); // Length / Angle / ROI / Probe
const csv = measurementsToCsv(measurements);
const json = measurementsToJson(measurements);
const srDocument = buildMeasurementSr(measurements); // DICOM-JSON SR (TID-1500-flavored)

Encode that SR to Part-10 and upload it to a store-capable PACS (STOW-RS):

import { dicomJsonToPart10 } from "@orbidicom/core";

const part10 = dicomJsonToPart10(srDocument); // Explicit-VR-LE Part-10 bytes
await source.storeInstances?.([part10], { studyUid: "1.2.840…" }); // multipart/related STOW

Keyboard shortcuts (framework-agnostic)

resolveHotkey maps a key event to a command against DEFAULT_KEYMAP (or your own map), so the keymap is reusable outside Vue:

import { DEFAULT_KEYMAP, resolveHotkey } from "@orbidicom/core";

window.addEventListener("keydown", (e) => {
  const cmd = resolveHotkey(e, DEFAULT_KEYMAP);
  if (cmd?.kind === "tool") setPrimaryTool(cmd.tool);
  // other commands: invert, rotate, flipH, reset, cine, scroll, preset
});

Read DICOM metadata

import { readImageMetadata, readMetadataGroups } from "@orbidicom/core";

const meta = await readImageMetadata(imageId); // { patientName, modality, pixelSpacing, … }
const groups = await readMetadataGroups(imageId); // grouped rows for a tag-reader panel

MPR + 3D volume rendering

Build a volume from a stack and drive four linked panes (axial / coronal / sagittal / 3D-VR) with selectable transfer-function presets:

import { createMprView, isVolumeCapable, VR_PRESETS } from "@orbidicom/core";

if (isVolumeCapable(series, imageIds.length)) {
  const mpr = createMprView({ axial, coronal, sagittal, volume3d }); // four HTMLDivElements
  await mpr.setVolume(imageIds, { modality: "CT" });
  mpr.setPreset("CT-Bone"); // VR_PRESETS: CT-Bone, CT-Lung, CT-MIP, MR-Default, …
}

Plugins & data sources

Bundle tools, window presets, and backend factories into a plugin and register them in one call — they fan out to the registries the UI reads from:

import { registerPlugin, createDataSource } from "@orbidicom/core";

registerPlugin({
  name: "acme-extras",
  windowPresets: [{ modality: "CT", name: "Stroke", windowWidth: 40, windowCenter: 40 }],
  // tools: [...], dataSources: [{ id: "acme", label: "Acme PACS", create: (cfg) => new AcmeSource(cfg) }],
});

// The built-in adapters are pre-registered, so you can build one by id:
const source = createDataSource("dicomweb", { root: "/dicom-web" });

Roadmap

See the project ROADMAP.md. Shipped here: MPR + 3D volume rendering (createMprView, VR presets), measurement export (JSON/CSV) + DICOM-SR with Part-10/STOW upload, annotation undo/redo, key-image flagging, and read-only DICOM-SEG labelmap rendering (2D stack, pending browser QA). Next up: DICOM-SEG MPR/volume rendering and brush/threshold editing.

License

MIT © OrbiDICOM contributors.

"OrbiDICOM" and its logo are trademarks of DocOrbit — the MIT license covers the source code, not the name or logo. Trademark, licensing, security, or commercial inquiries: [email protected].