Why the finest-scanned Herculaneum scroll still reads as noise — and what actually blocks it
I ran the Vesuvius Challenge ink model on PHerc1203 — the finest-scanned scroll still sealed shut — and it gave me speckle. No Greek, no letters, no prize. So I traced why the read failed, corrected a mistake I’d made along the way, and turned the correction into a cheap test that tells you — before you spend a GPU-hour — whether a surface can produce readable ink at all.
The short version: the scroll is readable. My rendered surface wasn’t. Two different problems, and for most of a day I chased the wrong one.
PHerc1203 in cross-section — a carbonized scroll, never unrolled, imaged at 2.4 µm. The writing is on those coiled sheets. Reading it means virtually following one sheet through the spiral, flattening it, and detecting ink that is barely denser than the papyrus it sits on. Every step downstream depends on the first one being clean.
The pipeline is geometry first, inference second
Reading a sealed scroll is three steps: segment the coiled surface out of the CT volume, render it flat, then run ink detection over the rendered surface. The public documentation is blunt about where it breaks — segmentation fails where adjacent sheets are packed or torn, and ink detection is hard because carbon ink and papyrus sit at almost the same X-ray density, so the model infers subtle texture rather than reading black pixels.
That ordering matters. The ink model isn’t magic; it expects a specific input. The canonical model reads a 62-layer depth window sampled along the surface normal — a thin stack centered, ideally, on one sheet of papyrus. Feed it a stack that cuts obliquely through several sheets, and it sees mixed structure instead of a single writing surface. Garbage geometry in, speckle out.
For PHerc1203 I rendered and scored the 22 public auto_grown surfaces. The output was pure noise —
nowhere close to the borderline-legible smudges you’d squint at and argue over. Which points the
question away from “is the model good enough” and toward “was the surface I fed it ever going to work.”
The wrong answer: “it’s wound too tight”
My first hypothesis was physical. The 62-layer window is about 149 µm deep on this scan. If the scroll’s winding pitch — the sheet-to-sheet spacing — were smaller than that, then even a perfect, perfectly-perpendicular surface would drag in neighbouring wraps. The scroll would be unreadable by this whole class of rendered-surface inference, and the fix would be a new representation entirely.
I measured the pitch by counting bright repeated bands in the depth columns. They came out tight — tighter than the window. Case closed: too dense to read.
Except I was counting the wrong thing.
The self-correction: fibers are not sheets
Papyrus is fibrous. A single sheet is not a smooth slab — it has bright internal strands running through it. When I counted bright bands as separate sheets, I was counting fibers inside one sheet as if they were the walls between wraps. That inflates the band count and collapses the apparent pitch. My “too tight to read” was an artifact of my own metric.
The correction came from outside my own numbers. The Vesuvius community maintains a rigorously measured winding-pitch atlas, and it puts PHerc1203’s true pitch at roughly 211 µm. When I re-measured at the sheet scale instead of the fiber scale, I agreed with it.
The scale that broke my first conclusion. The sheets (blue caliper, ~211 µm apart) are built from much finer bright fibers — and it was the fibers I’d mistakenly counted as sheets. At the true sheet spacing, the winding pitch (~211 µm) is comfortably larger than the 149 µm ink window: one wrap fits inside the window with room to spare.
That flips the conclusion. 211 µm of pitch is bigger than the 149 µm window, so a properly on-sheet surface does fit inside a single wrap. PHerc1203 is readable in principle under the existing pipeline. The blocker is the quality of the public surfaces, which are bad inputs.
I dwell on this because the tempting story — “the scroll is too tight” — would have sent me building the wrong thing. The measured story — “my surface is wrong” — points at segmentation quality and, usefully, at a cheap way to reject bad surfaces before inference.
The gate: measure the render before you pay for it
So I built the check I wished I’d had before the first GPU run. It asks one question:
Does this rendered window isolate a single papyrus sheet?
It doesn’t look for ink. No labels, no neural network, no GPU. For each depth column in the 62-layer stack, it measures occupancy — the fraction of the window filled with bright, papyrus-like material.
The whole metric in one picture. A surface sitting cleanly on one sheet (left) puts papyrus in a narrow band with dark inter-sheet gaps around it — low occupancy, and the model has a single surface to read. A surface that slices obliquely through the laminae, or sits in packed gap-less material (right), stays bright through the entire window — high occupancy, and the model gets a smear.
Run it on real surfaces and the separation is stark. A genuinely readable control sheet from
PHerc1667 — a scroll that has been read — measures around 0.35. The PHerc1203 auto_grown
surfaces measure around 0.97: saturated almost all the way through. Nearly 3× apart, and the gap
held across every brightness threshold I tried.
The number that decides whether a render deserves the GPU. 0.35 leaves dark gaps for the model to find a single sheet in; 0.97 is a saturated depth window — an oblique or packed surface. The gate flags the second before you pay to discover it produces speckle.
The same verdict spatially. Green is single-sheet-isolable, red is saturated. The readable control (left) is green almost everywhere; the PHerc1203 surface (right) is red almost everywhere. This is a render-acceptance test, not an ink detector.
What the control proved — and what it didn’t
I did not want to ship a metric that merely detects “which scan is this.” So I built a same-scroll control: take the same readable PHerc1667 patch, hold scan and coverage fixed, and vary only the geometry by warping the sampling surface. Occupancy rose when the surface got worse — the right direction.
But that same control stopped me from overclaiming. Even a pervasive steep warp of a readable sheet raised the saturated tail without dragging the median past ~0.47 — nowhere near the real negatives’ 0.97. So this is not a pure “obliqueness detector.” Orientation alone doesn’t reproduce the failure; the underlying material — packed, gap-less laminae — contributes too. The honest claim is narrow: high depth-occupancy flags render windows where single-sheet isolation has likely failed, whether from obliqueness, packed material, or both.
One limitation I state plainly: the positive and negative examples come from different scans (1667 and 1203). The same-scroll warp control rules out “it’s only warp-sensitive,” but a cross-volume intensity difference isn’t fully excluded. It’s an empirical engineering gate, not a physical law.
Why this is the useful result
Ink inference is expensive; a CPU occupancy check is nearly free. If a candidate surface reads 0.97, I shouldn’t expect a model trained on clean single-sheet examples to recover letters from it — and I shouldn’t confuse its output with a real read attempt. Gate the render first. Then spend the GPU.
That’s the systems lesson I’m carrying into the next attempt, and it lines up with the challenge’s own framing that better diagnostics matter more than better models. The bottleneck on PHerc1203 isn’t a scroll wound too tight. It’s getting a clean on-sheet surface — and having a cheap, honest way to tell which candidate surfaces are worth the compute.
I still haven’t read the scroll. What I have now is a number where there used to be a guess, and a reason to believe the letters are still in there to be found.
The gate is open-source and CPU-only: github.com/robertlangdonn/vesuvius-readability-gate. Built on public Vesuvius Challenge data. The winding-pitch atlas that corrected my measurement is the community’s; I’m grateful for it.