Vesuvius Challenge open data, made usable

A whole scroll, already embedded

The Vesuvius Challenge's dinovol model, run over every voxel of the PHerc0841 scan. Each small cube of the scroll now has a list of numbers that describes what it looks like. Stream them by URL and search, cluster or segment on a laptop, with no GPU.

Made and shared by Chase Hendrick, October 2026. Model and code by the dinovol authors in ScrollPrize/villa.

539 GBof features
19,400CT slices covered
3feature sets
0GPUs needed to use

What these are, in plain words

An X-ray CT scan tells you how dense each tiny point of a scroll is. That is a lot of gray, and it is hard to ask a question of it like "where else does it look like this?". A model can turn the gray into something easier to compare.

The model

dinovol learned what scrolls look like

dinovol is a 3D model from the Vesuvius Challenge team, trained the DINO way: self-supervised, with no labels. Its main features come from learning which parts of a scan look alike, not from being told what papyrus is.

The output

Every small cube gets a list of numbers

For each 8 × 8 × 8 voxel cube (about 75 µm across) the model writes 480 numbers, and for each 4 × 4 × 4 cube it writes 64 more. Those lists are the embeddings, or features. Here they cover the whole scan.

Why it helps

Look-alike cubes get look-alike numbers

Each list has length one, so the dot product of two lists says how alike two cubes look: 1 is the same, 0 is unrelated. Click one point and you can find every place that looks like it, or train a small classifier from a few clicks.

CT slice of PHerc0841 at z 9,600 The same slice, features shown as color
CTfeatures as color

Drag the slider across the scroll

Left is the CT slice at height z 9,600. Right is the same slice with each cube's numbers turned into a color: the three directions in which the numbers vary most become red, green and blue. Cubes with similar colors have similar numbers.

In this slice the colors form bands that follow the rolled layers you can see in the CT. That is how the numbers vary here; it is not a check of the model.

480
tokens_unit: the model's main features, 480 numbers per 8-voxel cube. The best start for search.
64
dense: 64 numbers per 4-voxel cube, finer and smaller.
32
ink: 32 numbers per 4-voxel cube from the model's ink head. Features, not an ink map.

Click anywhere on the scroll

Pick a point and the page lights up every cube in this slice whose numbers are most like it. Drag to move the point. It all runs in your browser, on a small copy of the slice's features that loads when you get here.

CT slice of PHerc0841 at z 9,600; click to search
Loading features…
Click a point inside the scroll.
less alikemost alike

The same search on the full data

This reads the 480 numbers at your point straight from the bucket and compares them with every cube in a box about 10 mm across, centered on it. It runs anywhere Python does, logged out.

Scroll through the whole scan in color

The same coloring as the slider above, for every slice of PHerc0841: each cube's 480 numbers become one color, from the three directions in which they vary most across the whole scan. It is a 3D color volume in OME-Zarr with four zoom levels, so neuroglancer streams it in a web browser and you can move through all 2,448 layers of cubes.

Array 0 is full detail, one color per 8-voxel cube, shape (3, 2448, 963, 963) as channel, z, y, x; arrays 1 to 3 are each half the size of the one before. 0 means outside the scroll. The colors show how the numbers vary; they are not labels.

One layer of the color volume at z 9,680, read from the bucket

Connect your tool

The features and the scan they came from read straight from these URLs, logged out, with no download step. The features are one zarr v2 group in a public Hugging Face bucket; Use it below has a tested Python snippet that opens it.

dinovol embeddings of PHerc0841: the store's index

CC BY-NC 4.0 (derived from Vesuvius Challenge open data) · Model output (scrollprize/dinovol_8um_ps192_102126), not checked by eye. The group sits beside this file: arrays tokens_unit, dense and ink with their _scale arrays; .zattrs has the model, villa commit and tiling.

https://huggingface.co/buckets/SharpMeow/dinovol-embeddings/resolve/PHerc0841/20250821151531-dinovol_8um_ps192_102126.zarr/index.json
Pythontested 2026-10-24
import json, urllib.request

data = json.load(urllib.request.urlopen("https://huggingface.co/buckets/SharpMeow/dinovol-embeddings/resolve/PHerc0841/20250821151531-dinovol_8um_ps192_102126.zarr/index.json"))
curltested 2026-10-24
curl -L -O https://huggingface.co/buckets/SharpMeow/dinovol-embeddings/resolve/PHerc0841/20250821151531-dinovol_8um_ps192_102126.zarr/index.json

Color volume of the features: OME-Zarr metadata

CC BY-NC 4.0 (derived from Vesuvius Challenge open data) · tokens_unit as one color per cube, a multiscale OME-Zarr (zarr v2, uint8, axes c, z, y, x, levels 0 to 3; 0 = outside the scroll). Open the folder this file sits in with zarr.open_group(URL, mode='r', zarr_format=2); the page's Open in neuroglancer button shows it with an RGB shader.

https://huggingface.co/buckets/SharpMeow/dinovol-embeddings/resolve/PHerc0841/20250821151531-dinovol_8um_ps192_102126-rgb.ome.zarr/.zattrs
Pythontested 2026-10-24
import json, urllib.request

data = json.load(urllib.request.urlopen("https://huggingface.co/buckets/SharpMeow/dinovol-embeddings/resolve/PHerc0841/20250821151531-dinovol_8um_ps192_102126-rgb.ome.zarr/.zattrs"))
curltested 2026-10-24
curl -L -O https://huggingface.co/buckets/SharpMeow/dinovol-embeddings/resolve/PHerc0841/20250821151531-dinovol_8um_ps192_102126-rgb.ome.zarr/.zattrs

X-ray CT the features came from, PHerc0841 9.366 um

CC BY-NC 4.0 (Vesuvius Challenge open data) · Read live from the open-data bucket, never copied here. Feature index i covers scan voxels [i*8, i*8+8) for tokens_unit and [i*4, i*4+4) for dense and ink, at level 0. · browse

https://vesuvius-challenge-open-data.s3.us-east-1.amazonaws.com/PHerc0841/volumes/20250821151531-9.366um-1.2m-113keV-masked.zarr
Python (zarr)tested 2026-10-24
# pip install "zarr>=3" fsspec aiohttp
import zarr

root = zarr.open_group("https://vesuvius-challenge-open-data.s3.us-east-1.amazonaws.com/PHerc0841/volumes/20250821151531-9.366um-1.2m-113keV-masked.zarr", mode="r")  # OME-Zarr, zarr v2
a = root["2"]  # level 0 is full resolution; level L is 2**L times coarser
print(a.shape, a.dtype, a.chunks)
block = a[2400:2464, 1000:1064, 1000:1064]  # (z, y, x); reads only the chunks it touches
villa's vesuvius packagetested 2026-10-24
# pip install "vesuvius[volume-only]"
from vesuvius import Volume

v = Volume(type="zarr", path="https://vesuvius-challenge-open-data.s3.us-east-1.amazonaws.com/PHerc0841/volumes/20250821151531-9.366um-1.2m-113keV-masked.zarr/2")  # one pyramid level
block = v[2400:2464, 1000:1064, 1000:1064]
VC3Dfrom villa's source
In VC3D (villa's volume-cartographer), open or create a project, then
File > Attach Remote Zarr... and paste:

https://vesuvius-challenge-open-data.s3.us-east-1.amazonaws.com/PHerc0841/volumes/20250821151531-9.366um-1.2m-113keV-masked.zarr

It accepts http, https and s3 OME-Zarr roots.
neuroglancertested 2026-10-24 Open in neuroglancer
https://neuroglancer-demo.appspot.com/#!%7B%22layers%22%3A%5B%7B%22type%22%3A%22image%22%2C%22source%22%3A%22zarr%3A%2F%2Fhttps%3A%2F%2Fvesuvius-challenge-open-data.s3.us-east-1.amazonaws.com%2FPHerc0841%2Fvolumes%2F20250821151531-9.366um-1.2m-113keV-masked.zarr%2F%22%2C%22name%22%3A%22X-ray%20CT%20the%20features%20came%20from%2C%20PHerc0841%209.366%20um%22%7D%5D%2C%22layout%22%3A%224panel%22%7D
curltested 2026-10-24
curl -s https://vesuvius-challenge-open-data.s3.us-east-1.amazonaws.com/PHerc0841/volumes/20250821151531-9.366um-1.2m-113keV-masked.zarr/.zattrs            # OME multiscales metadata
curl -s https://vesuvius-challenge-open-data.s3.us-east-1.amazonaws.com/PHerc0841/volumes/20250821151531-9.366um-1.2m-113keV-masked.zarr/2/.zarray     # one level: shape, chunks, dtype, codec

This page's own files

Page code Apache 2.0; data as above · The page's numbers (slice, box, accuracy of its 32-number search) are the JSON in its data script tag.

https://sharpmeow-dinovol-embeddings.static.hf.space/
Links and embedtested 2026-10-24
The bucket, with its README: https://huggingface.co/buckets/SharpMeow/dinovol-embeddings
The page's slice of features for search (32 numbers per cell, int8): https://huggingface.co/spaces/SharpMeow/dinovol-embeddings/resolve/main/assets/search.i8
Page source and build script: https://github.com/ChaseHendrick/Scrolls/tree/main/spaces/dinovol-embeddings
Machine-readable: connect.json and CONNECT.md. Checked 2026-10-24. "Tested" means the snippet ran against this public data on that date. Scan data keeps its own license (the Vesuvius Challenge open data is CC BY-NC 4.0).

Who it is for, and how to use it

Running dinovol over this scan took about 48 hours of GPU time. Now it is done once, and everyone can start from the result.

Concept search

Find everything like this

Pick a point, take its vector, and compute dot products over a region or the whole scan. High values mark cubes the model sees as alike.

Few-click segmentation

Train on frozen features

Label a handful of points as "this" and "not this", fit a logistic regression or a small MLP on their vectors, and apply it everywhere. No backbone to train.

Exploring

Cluster and map

Cluster a region, reduce it with PCA or UMAP, or compare scans of other scrolls you embed yourself with the same model and settings.

From nothing to your first numbers

Install three packages.
pip install "zarr>=3" fsspec aiohttp numpy
Open the store by URL. Nothing downloads until you slice an array, and then only the chunks you touch.

It worked when it prints (2448, 963, 963, 480) (4896, 1926, 1926, 64).

Turn stored numbers into vectors. Each vector is kept as int8 with one float16 scale: multiply them. Cubes outside the scroll are all zero.
v = g["tokens_unit"][i, j, k].astype("float32") * g["tokens_unit_scale"][i, j, k]
# i, j, k = z // 8, y // 8, x // 8 for tokens_unit; // 4 for dense and ink
Compare. A dot product of two vectors is their cosine similarity. The search box in Try it writes a complete example for the point you click.

Download it

Everything streams, so most people never need a copy. When you want files on disk, the free hf command copies any folder of the store, logged out. A downloaded copy opens with the same zarr code, with the folder's path in place of the URL.

539 GBeverything, about 940,000 files
179 GBtokens_unit with its scales
238 GBdense with its scales
122 GBink with its scales
1.6 GBthe color volume, all levels
A region

Only the chunks you need

Chunk folders follow the scan: ARRAY/Z/Y/X with Z = z ÷ 192 and Y, X = y, x ÷ 96, in scan voxels, for every array. This strip at z 9,600 is 40 MB and took 7 s logged out.

One feature set

tokens_unit, 179 GB

Swap in dense or ink for the others. The vectors and their scales are separate arrays; take both.

Everything

All 539 GB

Log in first with a free Hugging Face account: listing the whole store logged out gets rate limited.

Needs pip install -U huggingface_hub, which provides the hf command. Then read it locally: zarr.open_group("pherc0841-dinovol.zarr", mode="r", zarr_format=2).

How it was made

Every step ran from scripts on Hugging Face Jobs, with a record for each part. Nothing was edited by hand.

The organizers' model, pinned

Weights scrollprize/dinovol_8um_ps192_102126, teacher_step_640000.pt (sha256 2354c493…), run with villa's dinovol/dinovol_2/eval/embed_volume.py at commit 4ea26d9c on the dinovol-refactor branch.

One normalization for the whole scan

The input is the masked level-0 scan, 9.366 µm voxels. Its intensity statistics were measured once over 1,216 sampled chunks and used for every slab, so a vector means the same thing everywhere.

102 slabs on L4 GPUs

The scan was cut into slabs of 192 slices. Each ran on its own, 192-voxel tiles on a 96-voxel grid, each tile reading 32 voxels past the slab's edges. 22 Jobs on NVIDIA L4 GPUs took about 48 GPU hours. Tiles with no scroll in them were skipped.

One store, no rewriting

Each slab's chunk files were renamed into one scan-wide zarr (slab k is z chunk k), so the stored bytes are exactly what the model wrote, stored as int8 with a scale per vector.

Checked by URL, logged out

One 24 × 48 × 48 block from each of the 102 slabs was read back over HTTPS with no account: 5.6 million cells. No vector was off unit length by more than 1 percent, and the cells with features matched the cells with scan data exactly. This check could have failed; it shows the files are complete and line up with the scan. It says nothing about how good the features are.

Format

One zarr v2 group. Index i covers scan voxels [i × step, (i + 1) × step) on every axis, from voxel 0.

ArrayShape (z, y, x, numbers)One vector perStored as
tokens_unit2448 × 963 × 963 × 4808 × 8 × 8 voxelsint8, chunks 24 × 12 × 12 × 480, zstd
dense4896 × 1926 × 1926 × 644 × 4 × 4 voxelsint8, chunks 48 × 24 × 24 × 64, zstd
ink4896 × 1926 × 1926 × 324 × 4 × 4 voxelsint8, zstd
*_scalefloat16, one per vector: vector = int8 values × scale; after that each vector has length one
.zattrsThe model, its sha256, villa's commit, the tiling, the normalization statistics and the slabs present
index.jsonChunk file counts (156,480 per array) and the z range
Limits. These are raw model output, and nobody has checked them by eye. They are features, not a reading of any text, and the ink head's numbers are not an ink map. Each 192-slice slab was embedded on its own, so values can step slightly at multiples of z 192. Only PHerc0841 is here; for another scan, run villa's embed_volume.py with the same model.

Credit and terms

The scan is Vesuvius Challenge open data under CC BY-NC 4.0, and these features are shared under the same terms. The model is scrollprize/dinovol_8um_ps192_102126 and the code is dinovol in ScrollPrize/villa (MIT); credit to their authors. The features were computed and shared by Chase Hendrick.

Cite

Chase Hendrick (2026). dinovol embeddings of the PHerc0841 scan.
Hugging Face. https://huggingface.co/buckets/SharpMeow/dinovol-embeddings
Computed with ScrollPrize/villa dinovol (4ea26d9c) and scrollprize/dinovol_8um_ps192_102126
(teacher_step_640000.pt) on Vesuvius Challenge open data (CC BY-NC 4.0).
Copied