File size: 19,870 Bytes
7e14ba2
7c611dc
 
 
 
 
 
 
 
 
 
 
 
3a4e505
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7c611dc
 
 
 
 
 
 
 
 
 
 
d27240d
7c611dc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3a4e505
 
 
 
7c611dc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ab26408
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
475860e
ab26408
 
475860e
ab26408
 
 
 
7c611dc
 
 
 
 
 
 
 
 
 
 
 
 
3a4e505
7c611dc
7e14ba2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Segment Lens · every published Herculaneum segment, measured</title>
<meta name="description" content="Traced segments from the Vesuvius Challenge open data as 3D surfaces, with holes, folds and over-stretched grid edges painted on, beside the Segment Atlas numbers.">
<meta name="theme-color" content="#05080b">
<meta name="color-scheme" content="dark">
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' fill='%2305080b'/%3E%3Cpath d='M5 22c5-9 9 3 14-6s6-6 8-4' fill='none' stroke='%23d8e4ea' stroke-width='2'/%3E%3Ccircle cx='12' cy='17' r='2.4' fill='%23ff5c5c'/%3E%3Ccircle cx='22' cy='13' r='2.4' fill='%23ffa733'/%3E%3C/svg%3E">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
<link rel="stylesheet" href="style.css?v=2">
<!-- space-onescroll:start -->
<!-- one page scroll bar: written by python -m kit spaceconnect render; do not edit -->
<style>iframe[srcdoc]{display:block;max-height:none!important}</style>
<script>
(function () {
  if (window.__oneScroll) return;
  window.__oneScroll = true;
  var CSS = 'html,body{height:auto!important;min-height:0!important}html{overflow:hidden!important}';
  function size(f) {
    var d, st = f.__os;
    try { d = f.contentDocument; } catch (e) { return; }
    if (!d || !d.body || st.off) return;
    var de = d.documentElement, r = Math.ceil(de.getBoundingClientRect().height), over = de.scrollHeight;
    var ch = f.clientHeight, t = r;
    if (over > ch + 1) t = Math.max(r, over);
    else if (r >= st.r) t = Math.max(r, ch);
    st.r = r;
    if (Math.abs(t - ch) < 2) return;
    var now = Date.now();
    st.n = now - st.t0 < 4000 ? st.n + 1 : 1;
    if (st.n === 1) st.t0 = now;
    if (st.n > 40) { st.off = true; f.removeAttribute('scrolling'); var g = d.getElementById('space-onescroll'); if (g) g.remove(); return; }
    f.style.setProperty('height', t + 'px', 'important');
  }
  function attach(f) {
    var d, st = f.__os;
    try { d = f.contentDocument; } catch (e) { return; }
    if (!d || !d.documentElement || st.doc === d) return;
    st.doc = d; st.r = Infinity; st.n = 0; st.off = false;
    if (!d.getElementById('space-onescroll')) {
      var s = d.createElement('style'); s.id = 'space-onescroll'; s.textContent = CSS;
      (d.head || d.documentElement).appendChild(s);
    }
    f.setAttribute('scrolling', 'no');
    f.style.setProperty('min-height', '0', 'important');
    f.style.setProperty('max-height', 'none', 'important');
    var w = d.defaultView, go = function () { size(f); };
    if (w && w.ResizeObserver) { var ro = new w.ResizeObserver(go); ro.observe(d.documentElement); if (d.body) ro.observe(d.body); }
    d.addEventListener('load', go, true);
    go();
  }
  function bind(f) {
    if (f.__os || f.getAttribute('data-scroll') === 'inner') return;
    try { if (!f.contentDocument) return; } catch (e) { return; }
    f.__os = {t0: 0, n: 0, r: 0};
    f.addEventListener('load', function () { attach(f); });
    if (f.contentDocument.readyState !== 'loading') attach(f);
    else f.contentDocument.addEventListener('DOMContentLoaded', function () { attach(f); });
  }
  function scan() { var fs = document.getElementsByTagName('iframe'); for (var i = 0; i < fs.length; i++) bind(fs[i]); }
  function start() {
    scan();
    new MutationObserver(scan).observe(document.documentElement, {childList: true, subtree: true});
    window.addEventListener('resize', function () {
      var fs = document.getElementsByTagName('iframe');
      for (var i = 0; i < fs.length; i++) if (fs[i].__os) size(fs[i]);
    });
  }
  if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', start); else start();
})();
</script>
<!-- space-onescroll:end -->
<script type="importmap">
{ "imports": {
  "three": "https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js",
  "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/"
} }
</script>
</head>
<body>
<canvas id="gl" aria-label="3D view of the selected segment"></canvas>

<header class="hud tl">
  <div class="kicker mono dim"><span class="k-src">VESUVIUS CHALLENGE<span class="sep">/</span>OPEN DATA<span class="sep">/</span></span><span id="k-count">…</span> MESHES</div>
  <h1>Segment <em>Lens</em></h1>
  <p class="lede">Traced segments as surfaces, with the grid's problems painted on: <span class="c-hole">holes</span>, <span class="c-fold">folds</span> and <span class="c-str">over-stretched</span> edges. Numbers from the <a href="https://huggingface.co/datasets/SharpMeow/vesuvius-segment-atlas" target="_blank" rel="noopener">Segment Atlas</a>.</p>
</header>

<nav class="hud tr" aria-label="View">
  <div class="seg" role="tablist">
    <button class="chip on" data-mode="lens" role="tab">3D</button>
    <button class="chip" data-mode="table" role="tab">Table</button>
  </div>
  <button class="tbtn" id="b-about">Guide</button>
</nav>

<aside class="hud bl panel" id="picker" aria-label="Pick a segment">
  <label class="mono small dim" for="sel-scroll">SCROLL</label>
  <select id="sel-scroll"></select>
  <label class="row mono small"><input type="checkbox" id="only-top" checked> top-level meshes only</label>
  <input id="filter" class="mono small" type="search" placeholder="filter segments" aria-label="Filter segments">
  <ol id="list" class="list mono small"></ol>
</aside>

<aside class="hud br panel" id="card" aria-live="polite">
  <div class="mono small dim" id="c-kicker">SELECT A SEGMENT</div>
  <h2 id="c-title">…</h2>
  <details id="c-more" class="more" open>
    <summary class="mono dim">NUMBERS</summary>
    <dl id="c-nums" class="nums mono small"></dl>
  </details>
  <div class="legend mono small">
    <label><input type="checkbox" id="t-hole" checked> <span class="sw hole"></span>holes</label>
    <label><input type="checkbox" id="t-fold" checked> <span class="sw fold"></span>folds</label>
    <label><input type="checkbox" id="t-str" checked> <span class="sw str"></span>stretched</label>
    <label><input type="checkbox" id="t-wire"> grid</label>
  </div>
  <div class="actions mono small">
    <button id="b-copy" class="lk">copy kit command</button>
    <a id="a-bucket" class="lk" target="_blank" rel="noopener">mesh folder</a>
  </div>
  <p class="mono tiny dim" id="c-note"></p>
</aside>

<section id="table-view" class="sheet" hidden>
  <div class="sheet-head">
    <h2>Every mesh in the atlas</h2>
    <p class="mono small dim" id="t-meta"></p>
    <input id="t-filter" class="mono small" type="search" placeholder="filter by scroll or segment" aria-label="Filter the table">
  </div>
  <div class="tablewrap">
    <table class="mono small" id="tbl">
      <thead><tr>
        <th data-k="scroll">scroll</th><th data-k="segment">segment</th><th data-k="voxel_um" class="n">voxel µm</th>
        <th data-k="area_cm2" class="n">area cm²</th><th data-k="filled_share" class="n">filled</th>
        <th data-k="within_10pct" class="n">edges ±10%</th><th data-k="holes_mm2" class="n">holes mm²</th>
        <th data-k="folds_mm2" class="n">folds mm²</th><th data-k="stretched_mm2" class="n">stretched mm²</th>
        <th data-k="lens">3D</th>
      </tr></thead>
      <tbody></tbody>
    </table>
  </div>
</section>

<dialog id="about" class="sheet-dialog">
  <form method="dialog"><button class="x" aria-label="Close">&times;</button></form>
  <h2>Guide</h2>
  <p>A <b>segment</b> is a piece of the rolled papyrus surface that someone (or a program) traced through the X-ray CT of a scroll. It is stored as a <b>tifxyz</b> mesh: three images, x.tif, y.tif and z.tif, that together hold a grid of 3D points in the scan's voxels. The open data maps each segment onto several scan volumes, so one segment can have several meshes.</p>
  <p>The colors mark what <code>kit tifxyz check</code> flags on the full grid:</p>
  <ul>
    <li><span class="c-hole">Holes</span>: missing grid nodes inside the sheet (not joined to its border). The preview draws the rim around them.</li>
    <li><span class="c-fold">Folds</span>: neighboring cells whose surface normals turn by more than 90 degrees, where the surface doubles back.</li>
    <li><span class="c-str">Stretched</span>: grid edges more than 1.5 times longer or shorter than the spacing the mesh's meta.json promises.</li>
  </ul>
  <p>"Edges ±10%" is the share of grid edges within 10 percent of that spacing: how close the grid is to isometric, which matters for flattened renders. A clean mesh can still jump from one wrap of papyrus to the next; nothing here looks at the CT or judges ink, and none of it is an official villa or prize check.</p>
  <p>3D previews are shown only for scans on none of the prize lists (Grand Prize, First Letters, and the title prize's PHerc. Paris 4, from kit's dated snapshot); scrolls on a list appear in the table with numbers only. Previews keep every k-th node, at most 256 per side, with each flag pooled over the block it stands for.</p>
  <!-- space-connect:start -->
<section class="scc" id="connect" aria-label="Connect your tool"><style>.scc{--a:var(--scc-accent,#4ea8de);color:inherit;font:inherit;line-height:1.5;max-width:60rem}
.scc h2{font-size:1.15em;margin:.2em 0 .3em}.scc h3{font-size:1em;margin:0 0 .2em}
.scc p{margin:.3em 0}.scc a{color:var(--a)}
.scc .scc-src{border:1px solid color-mix(in srgb,currentColor 18%,transparent);border-radius:10px;padding:.7em .9em;margin:.7em 0;background:color-mix(in srgb,currentColor 4%,transparent)}
.scc .scc-meta{font-size:.85em;opacity:.8}
.scc details{border-top:1px solid color-mix(in srgb,currentColor 12%,transparent);padding:.35em 0}
.scc summary{cursor:pointer;font-weight:600;list-style-position:inside}
.scc .scc-b{font-weight:400;font-size:.75em;padding:.05em .5em;border-radius:99px;margin-left:.5em;border:1px solid currentColor;opacity:.75;white-space:nowrap}
.scc .scc-b.ok{color:#3fb37f}.scc .scc-b.src{color:var(--a)}.scc .scc-b.warn{color:#e0a030}
.scc .scc-code{position:relative;margin:.4em 0 .2em}
.scc pre{margin:0;padding:.7em .8em;border-radius:8px;overflow:auto;font-size:.82em;background:color-mix(in srgb,currentColor 9%,transparent);white-space:pre}
.scc code{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}
.scc button.scc-copy{all:unset;box-sizing:border-box;position:absolute;top:.35em;right:.35em;font-size:.75em;line-height:1.4;padding:.1em .6em;border-radius:6px;border:1px solid color-mix(in srgb,currentColor 30%,transparent);background:color-mix(in srgb,currentColor 8%,transparent);color:inherit;cursor:pointer}
.scc button.scc-copy:hover{border-color:var(--a)}
.scc .scc-url{position:relative}.scc .scc-url pre{padding-right:4.5em;white-space:pre-wrap;word-break:break-all}
.scc .scc-go{display:inline-block;margin:.3em 0;padding:.25em .8em;border-radius:6px;border:1px solid var(--a);text-decoration:none}
.scc footer{font-size:.8em;opacity:.75;margin-top:.6em}</style>
<h2>Connect your tool</h2>
<p>Every number and preview on this page comes from the Segment Atlas dataset, and every mesh it measures is a tifxyz folder on the open-data bucket. Both read straight from these URLs, with no account.</p>
<div class="scc-src" id="connect-atlas"><h3>Segment Atlas (one row per published mesh)</h3>
<p class="scc-meta">CC BY-NC 4.0 (derived from Vesuvius Challenge open data) · Each row has the mesh&#x27;s open-data url, its grid size, area, filled share, edge statistics and the holes, folds and stretched area that kit tifxyz check reports. lens/ holds the decimated 3D previews.</p>
<div class="scc-url"><button type="button" class="scc-copy" data-testid="connect-copy" onclick="navigator.clipboard&&navigator.clipboard.writeText(this.parentNode.querySelector('code').innerText).then(()=>{this.textContent='Copied';setTimeout(()=>this.textContent='Copy',1200)})">Copy</button><pre><code>https://huggingface.co/datasets/SharpMeow/vesuvius-segment-atlas</code></pre></div>
<details><summary>Python (huggingface_hub)<span class="scc-b ok">tested 2026-10-24</span></summary>
<div class="scc-code"><button type="button" class="scc-copy" data-testid="connect-copy" onclick="navigator.clipboard&&navigator.clipboard.writeText(this.parentNode.querySelector('code').innerText).then(()=>{this.textContent='Copied';setTimeout(()=>this.textContent='Copy',1200)})">Copy</button><pre><code># pip install huggingface_hub
from huggingface_hub import hf_hub_download, snapshot_download

path = hf_hub_download(&quot;SharpMeow/vesuvius-segment-atlas&quot;, &quot;atlas.jsonl&quot;, repo_type=&quot;dataset&quot;)  # one file, cached
folder = snapshot_download(&quot;SharpMeow/vesuvius-segment-atlas&quot;, repo_type=&quot;dataset&quot;)</code></pre></div></details>
<details><summary>Python (datasets)<span class="scc-b ok">tested 2026-10-24</span></summary>
<div class="scc-code"><button type="button" class="scc-copy" data-testid="connect-copy" onclick="navigator.clipboard&&navigator.clipboard.writeText(this.parentNode.querySelector('code').innerText).then(()=>{this.textContent='Copied';setTimeout(()=>this.textContent='Copy',1200)})">Copy</button><pre><code># pip install datasets
from datasets import load_dataset

default = load_dataset(&quot;SharpMeow/vesuvius-segment-atlas&quot;, &quot;default&quot;, split=&quot;train&quot;)</code></pre></div></details>
<details><summary>pandas<span class="scc-b ok">tested 2026-10-24</span></summary>
<div class="scc-code"><button type="button" class="scc-copy" data-testid="connect-copy" onclick="navigator.clipboard&&navigator.clipboard.writeText(this.parentNode.querySelector('code').innerText).then(()=>{this.textContent='Copied';setTimeout(()=>this.textContent='Copy',1200)})">Copy</button><pre><code># pip install pandas huggingface_hub
import pandas as pd

df = pd.read_json(&quot;hf://datasets/SharpMeow/vesuvius-segment-atlas/atlas.jsonl&quot;, lines=True)</code></pre></div></details>
<details><summary>Command line (hf)<span class="scc-b ok">tested 2026-10-24</span></summary>
<div class="scc-code"><button type="button" class="scc-copy" data-testid="connect-copy" onclick="navigator.clipboard&&navigator.clipboard.writeText(this.parentNode.querySelector('code').innerText).then(()=>{this.textContent='Copied';setTimeout(()=>this.textContent='Copy',1200)})">Copy</button><pre><code>pip install -U huggingface_hub
hf download SharpMeow/vesuvius-segment-atlas atlas.jsonl --repo-type dataset --local-dir vesuvius-segment-atlas</code></pre></div></details>
<details><summary>curl<span class="scc-b ok">tested 2026-10-24</span></summary>
<div class="scc-code"><button type="button" class="scc-copy" data-testid="connect-copy" onclick="navigator.clipboard&&navigator.clipboard.writeText(this.parentNode.querySelector('code').innerText).then(()=>{this.textContent='Copied';setTimeout(()=>this.textContent='Copy',1200)})">Copy</button><pre><code>curl -L -O https://huggingface.co/datasets/SharpMeow/vesuvius-segment-atlas/resolve/main/atlas.jsonl</code></pre></div></details>
</div>
<div class="scc-src" id="connect-mesh"><h3>A measured mesh (tifxyz), example PHerc0009B 20250510172639</h3>
<p class="scc-meta">CC BY-NC 4.0 (Vesuvius Challenge open data) · Every row of the atlas names its mesh folder in url; the table&#x27;s mesh folder link opens it. Read live from the open-data bucket, never copied here.</p>
<div class="scc-url"><button type="button" class="scc-copy" data-testid="connect-copy" onclick="navigator.clipboard&&navigator.clipboard.writeText(this.parentNode.querySelector('code').innerText).then(()=>{this.textContent='Copied';setTimeout(()=>this.textContent='Copy',1200)})">Copy</button><pre><code>https://vesuvius-challenge-open-data.s3.us-east-1.amazonaws.com/PHerc0009B/segments/20250510172639/mesh/20250510172639-on-20250521125136-8.64um.tifxyz</code></pre></div>
<details><summary>Python (numpy, tifffile)<span class="scc-b ok">tested 2026-10-24</span></summary>
<div class="scc-code"><button type="button" class="scc-copy" data-testid="connect-copy" onclick="navigator.clipboard&&navigator.clipboard.writeText(this.parentNode.querySelector('code').innerText).then(()=>{this.textContent='Copied';setTimeout(()=>this.textContent='Copy',1200)})">Copy</button><pre><code># pip install numpy tifffile
import io, json, urllib.request
import numpy as np, tifffile

T = &quot;https://vesuvius-challenge-open-data.s3.us-east-1.amazonaws.com/PHerc0009B/segments/20250510172639/mesh/20250510172639-on-20250521125136-8.64um.tifxyz&quot;
meta = json.load(urllib.request.urlopen(T + &quot;/meta.json&quot;))  # scale, bbox, format
get = lambda c: tifffile.imread(io.BytesIO(urllib.request.urlopen(f&quot;{T}/{c}.tif&quot;).read()))
xyz = np.stack([get(c) for c in &quot;xyz&quot;], -1)  # xyz[i, j] = (x, y, z) in scan voxels; -1 = no surface</code></pre></div></details>
</div>
<div class="scc-src" id="connect-page"><h3>This page&#x27;s code and data</h3>
<p class="scc-meta">Page code Apache 2.0; data as above · python -m kit atlas show SCROLL and python -m kit tifxyz check MESH_URL reproduce the numbers from a clone of ChaseHendrick/Scrolls.</p>
<div class="scc-url"><button type="button" class="scc-copy" data-testid="connect-copy" onclick="navigator.clipboard&&navigator.clipboard.writeText(this.parentNode.querySelector('code').innerText).then(()=>{this.textContent='Copied';setTimeout(()=>this.textContent='Copy',1200)})">Copy</button><pre><code>https://sharpmeow-segment-lens.hf.space/</code></pre></div>
<details><summary>Links and embed<span class="scc-b ok">tested 2026-10-24</span></summary>
<div class="scc-code"><button type="button" class="scc-copy" data-testid="connect-copy" onclick="navigator.clipboard&&navigator.clipboard.writeText(this.parentNode.querySelector('code').innerText).then(()=>{this.textContent='Copied';setTimeout(()=>this.textContent='Copy',1200)})">Copy</button><pre><code>The whole atlas as one CSV: https://huggingface.co/datasets/SharpMeow/vesuvius-segment-atlas/resolve/main/atlas.csv
API and MCP for agents (list_scrolls, list_segments, get_segment, segment_picture): https://sharpmeow-segment-lens.hf.space/agents/
Page source: https://github.com/ChaseHendrick/Scrolls/tree/main/spaces/segment-lens</code></pre></div></details>
</div>
<footer>Machine-readable: <a href="https://huggingface.co/spaces/SharpMeow/segment-lens/blob/main/connect.json" target="_blank" rel="noopener">connect.json</a> and <a href="https://huggingface.co/spaces/SharpMeow/segment-lens/blob/main/CONNECT.md" target="_blank" rel="noopener">CONNECT.md</a>. 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).</footer></section>
<!-- space-connect:end -->
  <h3>On your own machine</h3>
  <pre class="mono small">git clone https://github.com/ChaseHendrick/Scrolls &amp;&amp; cd Scrolls
python -m pip install numpy tifffile imagecodecs
python -m kit atlas show PHerc0139 --top 10
python -m kit tifxyz check MESH_URL --png check.png</pre>
  <h3>Credits</h3>
  <ul class="small">
    <li>Meshes: Vesuvius Challenge open data, CC BY-NC 4.0. The atlas numbers and previews carry the same license.</li>
    <li>This page: Apache 2.0, by Chase Hendrick (<a href="https://github.com/ChaseHendrick/Scrolls/tree/main/spaces/segment-lens" target="_blank" rel="noopener">source</a>). three.js is MIT.</li>
  </ul>
</dialog>

<div id="toast" class="toast mono small" role="status" hidden></div>
<script type="module" src="app.js?v=2"></script>
</body>
</html>