A DICOM viewer that runs in your browser.

Drop in a folder of .dcm files and read the study — windowing, slice scrolling, real Hounsfield units. Everything is decoded on your own machine. Nothing is ever uploaded.

No account. No upload. Works offline once loaded.

Lung · W 1500 · L −600
Axial chest CT from the demo study, displayed in a lung window
The same slice at three window presets — genuine output, rendered from the demo study's pixel data in true Hounsfield units.

What it does

Engineering notes

The parts that were actually hard, and what the numbers were.

  1. Decoding

    16-bit JPEG Lossless is not the easy path

    The reference study was entirely JPEG Lossless SV1 (1.2.840.10008.1.2.4.70) at 16 bits — not the 8-bit baseline JPEG a browser can decode natively. Getting it rendering meant fixing three separate integration failures: CommonJS codec interop, a transitive dependency extending Node's EventEmitter in the browser, and a metadata path that silently dropped pixel data for encapsulated local files.

  2. Correctness

    Windowing has to happen in Hounsfield units

    CT pixels are stored rescaled — the reference study used a slope of 1 and an intercept of −1024. Apply the window before the modality LUT and a lung preset produces a white rectangle. Applied in the right order, air reads at −1000 HU and the presets mean what radiologists expect.

  3. Ordering

    Filename order is not slice order

    Series are sorted by projecting each image's patient position onto the slice normal, derived from the orientation cosines. Verified across twenty series: spacing came out perfectly uniform every time — 0.61mm, 0.40mm, 0.50mm, 1.0mm, 5.0mm — with no gaps or duplicates.

  4. Performance

    Indexing got 73× faster by measuring first

    Indexing 311 files took 8148ms. Rather than guess, the header extent was measured across all 2486 files in the reference study: the longest was 11KB, against the 256KB being read per file. Reading 64KB instead brought the same work down to 112ms.

  5. Delivery

    Threaded WASM needs cross-origin isolation

    One bundled codec is thread-enabled and needs SharedArrayBuffer, which browsers only expose under COOP/COEP. Those headers are set in production and mirrored in local preview, so the constraint is caught before a deploy rather than after.

  6. Architecture

    This page carries none of the viewer

    The viewer is roughly 9MB once the WASM codecs are counted. It lives on its own entry point, so reading this page never downloads any of it.

Your images stay on your machine

DOCOC has no backend and no analytics. Studies you open are read directly from disk by the browser and decoded in memory. There is no upload step to opt out of, because there is nowhere for the data to go. A Hide patient info toggle blanks identifiers in the overlay for screen sharing.

Open the viewer