Spaces:
Running
Running
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">×</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'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("SharpMeow/vesuvius-segment-atlas", "atlas.jsonl", repo_type="dataset") # one file, cached
folder = snapshot_download("SharpMeow/vesuvius-segment-atlas", repo_type="dataset")</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("SharpMeow/vesuvius-segment-atlas", "default", split="train")</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("hf://datasets/SharpMeow/vesuvius-segment-atlas/atlas.jsonl", 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'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 = "https://vesuvius-challenge-open-data.s3.us-east-1.amazonaws.com/PHerc0009B/segments/20250510172639/mesh/20250510172639-on-20250521125136-8.64um.tifxyz"
meta = json.load(urllib.request.urlopen(T + "/meta.json")) # scale, bbox, format
get = lambda c: tifffile.imread(io.BytesIO(urllib.request.urlopen(f"{T}/{c}.tif").read()))
xyz = np.stack([get(c) for c in "xyz"], -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'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 && 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>
|