SharpMeow commited on
Commit
e5067cd
·
verified ·
1 Parent(s): e31bb23

Unroll 1.6.0: Connect your tool panel in the Embed sheet

Browse files
Files changed (7) hide show
  1. CHANGELOG.md +4 -0
  2. CONNECT.md +110 -0
  3. connect.html +86 -0
  4. connect.json +34 -0
  5. index.html +91 -3
  6. llms.txt +1 -0
  7. version.json +3 -3
CHANGELOG.md CHANGED
@@ -5,6 +5,10 @@ Unroll is released as v1.0.0. After it, bump the minor version for a feature pus
5
  with `node tools/stamp_version.mjs minor|patch` before you commit, then add an entry here.
6
  The 0.9.x entries below are the pre-release series that led up to 1.0.0. Version 0.9.0 was reconstructed from the git log.
7
 
 
 
 
 
8
  ## 1.5.0 (2026-10-16)
9
 
10
  - **Labeled segments** in the CT volume: every traced segment that passes through the cube is drawn into a label volume and coloured over the MIP; a list of the segments in the cube, click one to highlight it. `unrollView.ct.volume.labels`, `?ctlabels=1`.
 
5
  with `node tools/stamp_version.mjs minor|patch` before you commit, then add an entry here.
6
  The 0.9.x entries below are the pre-release series that led up to 1.0.0. Version 0.9.0 was reconstructed from the git log.
7
 
8
+ ## 1.6.0 (2026-10-24)
9
+
10
+ - **Connect your tool**, in the Embed sheet (the </> button, also linked from About; and `/CONNECT.md`, `/connect.json`): the open-data URLs behind every layer, a traced winding (tifxyz), a scroll's segment folder and the CT the CT view streams, with ready snippets for Python (zarr, numpy and tifffile), villa's `vesuvius` package, VC3D (File > Attach Remote Zarr), neuroglancer and curl, and links to this page's own API and embed. Each snippet that says "tested" ran against the live public data on 2026-10-24. Made by `python -m kit spaceconnect` in ChaseHendrick/Scrolls, shared by every Space of Chase's.
11
+
12
  ## 1.5.0 (2026-10-16)
13
 
14
  - **Labeled segments** in the CT volume: every traced segment that passes through the cube is drawn into a label volume and coloured over the MIP; a list of the segments in the cube, click one to highlight it. `unrollView.ct.volume.labels`, `?ctlabels=1`.
CONNECT.md ADDED
@@ -0,0 +1,110 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Connect your tool: Unroll
2
+
3
+ The traced windings, X-ray CT and ink layers in Unroll come from the Vesuvius Challenge open data, and every one of them reads straight from these URLs in your own tool, with no account and no download step.
4
+
5
+ Checked 2026-10-24. Generated from `connect.json` by `kit spaceconnect` in [ChaseHendrick/Scrolls](https://github.com/ChaseHendrick/Scrolls).
6
+
7
+ ## A traced winding (tifxyz), example PHerc0841 w00
8
+
9
+ `https://vesuvius-challenge-open-data.s3.us-east-1.amazonaws.com/PHerc0841/segments/20260220213127-w00/mesh/20260220213127-on-20250821151531-9.366um.tifxyz`
10
+
11
+ License: CC BY-NC 4.0 (Vesuvius Challenge open data). Every winding Unroll shows has a folder like this under SCROLL/segments/ in the open data; Unroll keeps only a decimated copy for the browser.
12
+
13
+ ### Python (numpy, tifffile) (tested 2026-10-24)
14
+
15
+ ```python
16
+ # pip install numpy tifffile
17
+ import io, json, urllib.request
18
+ import numpy as np, tifffile
19
+
20
+ T = "https://vesuvius-challenge-open-data.s3.us-east-1.amazonaws.com/PHerc0841/segments/20260220213127-w00/mesh/20260220213127-on-20250821151531-9.366um.tifxyz"
21
+ meta = json.load(urllib.request.urlopen(T + "/meta.json")) # scale, bbox, format
22
+ get = lambda c: tifffile.imread(io.BytesIO(urllib.request.urlopen(f"{T}/{c}.tif").read()))
23
+ xyz = np.stack([get(c) for c in "xyz"], -1) # xyz[i, j] = (x, y, z) in scan voxels; -1 = no surface
24
+ ```
25
+
26
+ ## Every segment of a scroll, example PHerc0841
27
+
28
+ `s3://vesuvius-challenge-open-data/PHerc0841/segments/`
29
+
30
+ License: CC BY-NC 4.0 (Vesuvius Challenge open data). Each segment folder has mesh/ (tifxyz), surface-volumes/ (OME-Zarr layers) and, where published, ink-detection/.
31
+
32
+ ### Python (list the folder) (tested 2026-10-24)
33
+
34
+ ```python
35
+ import re, urllib.request
36
+
37
+ B = "https://vesuvius-challenge-open-data.s3.us-east-1.amazonaws.com"
38
+ xml = urllib.request.urlopen(B + "/?list-type=2&delimiter=/&prefix=PHerc0841/segments/").read().decode()
39
+ print(re.findall(r"<Prefix>([^<]+)</Prefix>", xml)) # subfolders; <Key> gives files
40
+ ```
41
+
42
+ ## X-ray CT behind the CT view, PHerc0139 9.362 um
43
+
44
+ `https://vesuvius-challenge-open-data.s3.us-east-1.amazonaws.com/PHerc0139/volumes/20250728140407-9.362um-1.2m-113keV-masked.zarr`
45
+
46
+ License: CC BY-NC 4.0 (Vesuvius Challenge open data). Streamed from the open-data bucket, never copied here. Unroll opens any other scan with ?ctzarr=URL&ctum=VOXEL_UM.
47
+
48
+ ### Python (zarr) (tested 2026-10-24)
49
+
50
+ ```python
51
+ # pip install "zarr>=3" fsspec aiohttp
52
+ import zarr
53
+
54
+ root = zarr.open_group("https://vesuvius-challenge-open-data.s3.us-east-1.amazonaws.com/PHerc0139/volumes/20250728140407-9.362um-1.2m-113keV-masked.zarr", mode="r") # OME-Zarr, zarr v2
55
+ a = root["2"] # level 0 is full resolution; level L is 2**L times coarser
56
+ print(a.shape, a.dtype, a.chunks)
57
+ block = a[2622:2686, 828:892, 828:892] # (z, y, x); reads only the chunks it touches
58
+ ```
59
+
60
+ ### villa's vesuvius package (tested 2026-10-24)
61
+
62
+ ```python
63
+ # pip install "vesuvius[volume-only]"
64
+ from vesuvius import Volume
65
+
66
+ v = Volume(type="zarr", path="https://vesuvius-challenge-open-data.s3.us-east-1.amazonaws.com/PHerc0139/volumes/20250728140407-9.362um-1.2m-113keV-masked.zarr/2") # one pyramid level
67
+ block = v[2622:2686, 828:892, 828:892]
68
+ ```
69
+
70
+ ### VC3D (from villa's source)
71
+
72
+ ```text
73
+ In VC3D (villa's volume-cartographer), open or create a project, then
74
+ File > Attach Remote Zarr... and paste:
75
+
76
+ https://vesuvius-challenge-open-data.s3.us-east-1.amazonaws.com/PHerc0139/volumes/20250728140407-9.362um-1.2m-113keV-masked.zarr
77
+
78
+ It accepts http, https and s3 OME-Zarr roots.
79
+ ```
80
+
81
+ ### neuroglancer (tested 2026-10-24)
82
+
83
+ ```text
84
+ 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%2FPHerc0139%2Fvolumes%2F20250728140407-9.362um-1.2m-113keV-masked.zarr%2F%22%2C%22name%22%3A%22X-ray%20CT%20behind%20the%20CT%20view%2C%20PHerc0139%209.362%20um%22%7D%5D%2C%22layout%22%3A%224panel%22%7D
85
+ ```
86
+
87
+ ### curl (tested 2026-10-24)
88
+
89
+ ```bash
90
+ curl -s https://vesuvius-challenge-open-data.s3.us-east-1.amazonaws.com/PHerc0139/volumes/20250728140407-9.362um-1.2m-113keV-masked.zarr/.zattrs # OME multiscales metadata
91
+ curl -s https://vesuvius-challenge-open-data.s3.us-east-1.amazonaws.com/PHerc0139/volumes/20250728140407-9.362um-1.2m-113keV-masked.zarr/2/.zarray # one level: shape, chunks, dtype, codec
92
+ ```
93
+
94
+ ## Unroll's own API, files and embed
95
+
96
+ `https://sharpmeow-unroll.static.hf.space/`
97
+
98
+ License: Page code Apache 2.0; derived data CC BY-NC 4.0. Every button has a data-api name and the same call on window.unroll, so a script or an agent can drive the page.
99
+
100
+ ### Links and embed (tested 2026-10-24)
101
+
102
+ ```text
103
+ API description (window.unroll, postMessage, deep links): https://huggingface.co/spaces/SharpMeow/unroll/resolve/main/api.json
104
+ Guide for agents: https://huggingface.co/spaces/SharpMeow/unroll/resolve/main/llms.txt
105
+ Scroll list and per-scroll manifests: https://huggingface.co/spaces/SharpMeow/unroll/resolve/main/scrolls/index.json
106
+ Ink Bench on the command line: https://huggingface.co/spaces/SharpMeow/unroll/resolve/main/tools/inkbench.py
107
+ Deep link to one winding: https://sharpmeow-unroll.static.hf.space/?scroll=PHerc0139&t=0.6&layer=overlay&focus=w047&compare=0.3
108
+
109
+ <iframe src="https://sharpmeow-unroll.static.hf.space/index.html?embed=1" width="100%" height="600" allow="fullscreen; clipboard-write"></iframe>
110
+ ```
connect.html ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <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}
2
+ .scc h2{font-size:1.15em;margin:.2em 0 .3em}.scc h3{font-size:1em;margin:0 0 .2em}
3
+ .scc p{margin:.3em 0}.scc a{color:var(--a)}
4
+ .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)}
5
+ .scc .scc-meta{font-size:.85em;opacity:.8}
6
+ .scc details{border-top:1px solid color-mix(in srgb,currentColor 12%,transparent);padding:.35em 0}
7
+ .scc summary{cursor:pointer;font-weight:600;list-style-position:inside}
8
+ .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}
9
+ .scc .scc-b.ok{color:#3fb37f}.scc .scc-b.src{color:var(--a)}.scc .scc-b.warn{color:#e0a030}
10
+ .scc .scc-code{position:relative;margin:.4em 0 .2em}
11
+ .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}
12
+ .scc code{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}
13
+ .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}
14
+ .scc button.scc-copy:hover{border-color:var(--a)}
15
+ .scc .scc-url{position:relative}.scc .scc-url pre{padding-right:4.5em;white-space:pre-wrap;word-break:break-all}
16
+ .scc .scc-go{display:inline-block;margin:.3em 0;padding:.25em .8em;border-radius:6px;border:1px solid var(--a);text-decoration:none}
17
+ .scc footer{font-size:.8em;opacity:.75;margin-top:.6em}</style>
18
+ <h2>Connect your tool</h2>
19
+ <p>The traced windings, X-ray CT and ink layers in Unroll come from the Vesuvius Challenge open data, and every one of them reads straight from these URLs in your own tool, with no account and no download step.</p>
20
+ <div class="scc-src" id="connect-segment"><h3>A traced winding (tifxyz), example PHerc0841 w00</h3>
21
+ <p class="scc-meta">CC BY-NC 4.0 (Vesuvius Challenge open data) · Every winding Unroll shows has a folder like this under SCROLL/segments/ in the open data; Unroll keeps only a decimated copy for the browser.</p>
22
+ <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/PHerc0841/segments/20260220213127-w00/mesh/20260220213127-on-20250821151531-9.366um.tifxyz</code></pre></div>
23
+ <details><summary>Python (numpy, tifffile)<span class="scc-b ok">tested 2026-10-24</span></summary>
24
+ <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
25
+ import io, json, urllib.request
26
+ import numpy as np, tifffile
27
+
28
+ T = &quot;https://vesuvius-challenge-open-data.s3.us-east-1.amazonaws.com/PHerc0841/segments/20260220213127-w00/mesh/20260220213127-on-20250821151531-9.366um.tifxyz&quot;
29
+ meta = json.load(urllib.request.urlopen(T + &quot;/meta.json&quot;)) # scale, bbox, format
30
+ get = lambda c: tifffile.imread(io.BytesIO(urllib.request.urlopen(f&quot;{T}/{c}.tif&quot;).read()))
31
+ 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>
32
+ </div>
33
+ <div class="scc-src" id="connect-segments"><h3>Every segment of a scroll, example PHerc0841</h3>
34
+ <p class="scc-meta">CC BY-NC 4.0 (Vesuvius Challenge open data) · Each segment folder has mesh/ (tifxyz), surface-volumes/ (OME-Zarr layers) and, where published, ink-detection/. · <a href="https://scrollprize.org/data_browser/PHerc0841" target="_blank" rel="noopener">browse</a></p>
35
+ <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>s3://vesuvius-challenge-open-data/PHerc0841/segments/</code></pre></div>
36
+ <details><summary>Python (list the folder)<span class="scc-b ok">tested 2026-10-24</span></summary>
37
+ <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>import re, urllib.request
38
+
39
+ B = &quot;https://vesuvius-challenge-open-data.s3.us-east-1.amazonaws.com&quot;
40
+ xml = urllib.request.urlopen(B + &quot;/?list-type=2&amp;delimiter=/&amp;prefix=PHerc0841/segments/&quot;).read().decode()
41
+ print(re.findall(r&quot;&lt;Prefix&gt;([^&lt;]+)&lt;/Prefix&gt;&quot;, xml)) # subfolders; &lt;Key&gt; gives files</code></pre></div></details>
42
+ </div>
43
+ <div class="scc-src" id="connect-ct"><h3>X-ray CT behind the CT view, PHerc0139 9.362 um</h3>
44
+ <p class="scc-meta">CC BY-NC 4.0 (Vesuvius Challenge open data) · Streamed from the open-data bucket, never copied here. Unroll opens any other scan with ?ctzarr=URL&amp;ctum=VOXEL_UM. · <a href="https://scrollprize.org/data_browser/PHerc0139" target="_blank" rel="noopener">browse</a></p>
45
+ <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/PHerc0139/volumes/20250728140407-9.362um-1.2m-113keV-masked.zarr</code></pre></div>
46
+ <details><summary>Python (zarr)<span class="scc-b ok">tested 2026-10-24</span></summary>
47
+ <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 &quot;zarr&gt;=3&quot; fsspec aiohttp
48
+ import zarr
49
+
50
+ root = zarr.open_group(&quot;https://vesuvius-challenge-open-data.s3.us-east-1.amazonaws.com/PHerc0139/volumes/20250728140407-9.362um-1.2m-113keV-masked.zarr&quot;, mode=&quot;r&quot;) # OME-Zarr, zarr v2
51
+ a = root[&quot;2&quot;] # level 0 is full resolution; level L is 2**L times coarser
52
+ print(a.shape, a.dtype, a.chunks)
53
+ block = a[2622:2686, 828:892, 828:892] # (z, y, x); reads only the chunks it touches</code></pre></div></details>
54
+ <details><summary>villa&#x27;s vesuvius package<span class="scc-b ok">tested 2026-10-24</span></summary>
55
+ <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 &quot;vesuvius[volume-only]&quot;
56
+ from vesuvius import Volume
57
+
58
+ v = Volume(type=&quot;zarr&quot;, path=&quot;https://vesuvius-challenge-open-data.s3.us-east-1.amazonaws.com/PHerc0139/volumes/20250728140407-9.362um-1.2m-113keV-masked.zarr/2&quot;) # one pyramid level
59
+ block = v[2622:2686, 828:892, 828:892]</code></pre></div></details>
60
+ <details><summary>VC3D<span class="scc-b src">from villa&#x27;s source</span></summary>
61
+ <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>In VC3D (villa&#x27;s volume-cartographer), open or create a project, then
62
+ File &gt; Attach Remote Zarr... and paste:
63
+
64
+ https://vesuvius-challenge-open-data.s3.us-east-1.amazonaws.com/PHerc0139/volumes/20250728140407-9.362um-1.2m-113keV-masked.zarr
65
+
66
+ It accepts http, https and s3 OME-Zarr roots.</code></pre></div></details>
67
+ <details><summary>neuroglancer<span class="scc-b ok">tested 2026-10-24</span></summary>
68
+ <a class="scc-go" href="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%2FPHerc0139%2Fvolumes%2F20250728140407-9.362um-1.2m-113keV-masked.zarr%2F%22%2C%22name%22%3A%22X-ray%20CT%20behind%20the%20CT%20view%2C%20PHerc0139%209.362%20um%22%7D%5D%2C%22layout%22%3A%224panel%22%7D" target="_blank" rel="noopener">Open in neuroglancer</a>
69
+ <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>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%2FPHerc0139%2Fvolumes%2F20250728140407-9.362um-1.2m-113keV-masked.zarr%2F%22%2C%22name%22%3A%22X-ray%20CT%20behind%20the%20CT%20view%2C%20PHerc0139%209.362%20um%22%7D%5D%2C%22layout%22%3A%224panel%22%7D</code></pre></div></details>
70
+ <details><summary>curl<span class="scc-b ok">tested 2026-10-24</span></summary>
71
+ <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 -s https://vesuvius-challenge-open-data.s3.us-east-1.amazonaws.com/PHerc0139/volumes/20250728140407-9.362um-1.2m-113keV-masked.zarr/.zattrs # OME multiscales metadata
72
+ curl -s https://vesuvius-challenge-open-data.s3.us-east-1.amazonaws.com/PHerc0139/volumes/20250728140407-9.362um-1.2m-113keV-masked.zarr/2/.zarray # one level: shape, chunks, dtype, codec</code></pre></div></details>
73
+ </div>
74
+ <div class="scc-src" id="connect-page"><h3>Unroll&#x27;s own API, files and embed</h3>
75
+ <p class="scc-meta">Page code Apache 2.0; derived data CC BY-NC 4.0 · Every button has a data-api name and the same call on window.unroll, so a script or an agent can drive the page.</p>
76
+ <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-unroll.static.hf.space/</code></pre></div>
77
+ <details><summary>Links and embed<span class="scc-b ok">tested 2026-10-24</span></summary>
78
+ <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>API description (window.unroll, postMessage, deep links): https://huggingface.co/spaces/SharpMeow/unroll/resolve/main/api.json
79
+ Guide for agents: https://huggingface.co/spaces/SharpMeow/unroll/resolve/main/llms.txt
80
+ Scroll list and per-scroll manifests: https://huggingface.co/spaces/SharpMeow/unroll/resolve/main/scrolls/index.json
81
+ Ink Bench on the command line: https://huggingface.co/spaces/SharpMeow/unroll/resolve/main/tools/inkbench.py
82
+ Deep link to one winding: https://sharpmeow-unroll.static.hf.space/?scroll=PHerc0139&amp;t=0.6&amp;layer=overlay&amp;focus=w047&amp;compare=0.3
83
+
84
+ &lt;iframe src=&quot;https://sharpmeow-unroll.static.hf.space/index.html?embed=1&quot; width=&quot;100%&quot; height=&quot;600&quot; allow=&quot;fullscreen; clipboard-write&quot;&gt;&lt;/iframe&gt;</code></pre></div></details>
85
+ </div>
86
+ <footer>Machine-readable: <a href="https://huggingface.co/spaces/SharpMeow/unroll/blob/main/connect.json" target="_blank" rel="noopener">connect.json</a> and <a href="https://huggingface.co/spaces/SharpMeow/unroll/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>
connect.json ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "schema": "space-connect/1",
3
+ "space": "SharpMeow/unroll",
4
+ "title": "Unroll",
5
+ "checked": "2026-10-24",
6
+ "intro": "The traced windings, X-ray CT and ink layers in Unroll come from the Vesuvius Challenge open data, and every one of them reads straight from these URLs in your own tool, with no account and no download step.",
7
+ "sources": [
8
+ {"id": "segment", "title": "A traced winding (tifxyz), example PHerc0841 w00", "kind": "tifxyz",
9
+ "url": "https://vesuvius-challenge-open-data.s3.us-east-1.amazonaws.com/PHerc0841/segments/20260220213127-w00/mesh/20260220213127-on-20250821151531-9.366um.tifxyz",
10
+ "license": "CC BY-NC 4.0 (Vesuvius Challenge open data)",
11
+ "note": "Every winding Unroll shows has a folder like this under SCROLL/segments/ in the open data; Unroll keeps only a decimated copy for the browser."},
12
+ {"id": "segments", "title": "Every segment of a scroll, example PHerc0841", "kind": "s3-prefix",
13
+ "url": "https://vesuvius-challenge-open-data.s3.us-east-1.amazonaws.com", "prefix": "PHerc0841/segments/",
14
+ "license": "CC BY-NC 4.0 (Vesuvius Challenge open data)",
15
+ "note": "Each segment folder has mesh/ (tifxyz), surface-volumes/ (OME-Zarr layers) and, where published, ink-detection/.",
16
+ "browse": "https://scrollprize.org/data_browser/PHerc0841"},
17
+ {"id": "ct", "title": "X-ray CT behind the CT view, PHerc0139 9.362 um", "kind": "ome-zarr",
18
+ "url": "https://vesuvius-challenge-open-data.s3.us-east-1.amazonaws.com/PHerc0139/volumes/20250728140407-9.362um-1.2m-113keV-masked.zarr",
19
+ "zarr_format": 2, "example": {"level": "2", "start": [2622, 828, 828]},
20
+ "license": "CC BY-NC 4.0 (Vesuvius Challenge open data)",
21
+ "note": "Streamed from the open-data bucket, never copied here. Unroll opens any other scan with ?ctzarr=URL&ctum=VOXEL_UM.",
22
+ "browse": "https://scrollprize.org/data_browser/PHerc0139"},
23
+ {"id": "page", "title": "Unroll's own API, files and embed", "kind": "page-api",
24
+ "url": "https://sharpmeow-unroll.static.hf.space/",
25
+ "links": [{"label": "API description (window.unroll, postMessage, deep links)", "url": "https://huggingface.co/spaces/SharpMeow/unroll/resolve/main/api.json"},
26
+ {"label": "Guide for agents", "url": "https://huggingface.co/spaces/SharpMeow/unroll/resolve/main/llms.txt"},
27
+ {"label": "Scroll list and per-scroll manifests", "url": "https://huggingface.co/spaces/SharpMeow/unroll/resolve/main/scrolls/index.json"},
28
+ {"label": "Ink Bench on the command line", "url": "https://huggingface.co/spaces/SharpMeow/unroll/resolve/main/tools/inkbench.py"},
29
+ {"label": "Deep link to one winding", "url": "https://sharpmeow-unroll.static.hf.space/?scroll=PHerc0139&t=0.6&layer=overlay&focus=w047&compare=0.3"}],
30
+ "embed": "https://sharpmeow-unroll.static.hf.space/index.html?embed=1",
31
+ "license": "Page code Apache 2.0; derived data CC BY-NC 4.0",
32
+ "note": "Every button has a data-api name and the same call on window.unroll, so a script or an agent can drive the page."}
33
+ ]
34
+ }
index.html CHANGED
@@ -139,7 +139,7 @@ if (!/(^|[#&])s=/.test(location.hash)) ['scrolls/index.json', 'scrolls/PHerc0139
139
  <button class="icon" id="btnOpen" data-testid="open-own" data-api="panel('open')" title="Open your own scroll: files stay in your browser, nothing is uploaded" aria-label="Open your own scroll">+</button>
140
  <button class="icon" id="btnBench" data-testid="bench" data-api="bench.open()" title="Ink Bench: score your own ink prediction against the published ink. Runs in your browser, nothing is uploaded" aria-label="Ink Bench"><svg viewBox="0 0 24 24" width="15" height="15"><path d="M4 19V9M10 19V5M16 19v-7M21 19H3" fill="none" stroke="currentColor" stroke-width="1.6"/></svg></button>
141
  <button class="icon" id="btnInfo" data-testid="about" data-api="panel('about')" title="About this page" aria-label="About">i</button>
142
- <button class="icon" id="btnEmbed" data-testid="embed" data-api="panel('embed')" title="Embed this viewer on your site" aria-label="Embed this viewer">&lt;/&gt;</button>
143
  <button class="icon" id="btnFull" data-testid="fullscreen" data-api="fullscreen()" title="Fullscreen" aria-label="Fullscreen" aria-pressed="false">
144
  <svg viewBox="0 0 24 24" width="15" height="15"><path d="M4 9V4h5M15 4h5v5M20 15v5h-5M9 20H4v-5" fill="none" stroke="currentColor" stroke-width="1.5"/></svg>
145
  </button>
@@ -232,12 +232,12 @@ if (!/(^|[#&])s=/.test(location.hash)) ['scrolls/index.json', 'scrolls/PHerc0139
232
  <p class="mono dim small">Sources: open data bucket <code>PHerc0139/segments/*/mesh/*9.362um.tifxyz</code>, <code>surface-volumes/9.362um…zarr</code> and <code>ink-detection/downsampled</code>. Data: Giorgio Angelotti, Stephen Parsons, Sean Johnson, Elian Rafael Dal Prà, Johannes Rudolph, Paul Tafforeau, Alessandro Mirone, Paul Henderson, Hendrik Schilling, Forrest McDonald, David Josey, Youssef Nader, C. Seth Parker, W. Brent Seales. <i>Vesuvius Challenge - CT Scans of Herculaneum Papyri.</i> Vesuvius Challenge. Licensed <a href="https://creativecommons.org/licenses/by-nc/4.0/" target="_blank" rel="noopener">CC BY‑NC 4.0</a>. The page's code (HTML, CSS, JS and <code>tools/</code>) is Apache 2.0; see the Space's README.</p>
233
  <p class="mono dim small made-by">Made by Chase Hendrick.</p>
234
  </div>
235
- <div class="sheet-foot mono dim small about-foot"><span>For agents: <a href="llms.txt" target="_blank" rel="noopener">llms.txt</a> · <a href="AGENTS.md" target="_blank" rel="noopener">AGENTS.md</a> · <a href="api.json" target="_blank" rel="noopener">api.json</a></span> <span id="aVersion" class="version" data-testid="version" title="Version and build (CHANGELOG.md)"></span></div>
236
  </section>
237
 
238
  <section id="embedSheet" class="sheet about" role="dialog" aria-modal="false" aria-labelledby="eTitle" hidden data-testid="embed-panel">
239
  <div class="sheet-head">
240
- <div><div class="mono dim">EMBED</div><h2 id="eTitle">Put this viewer on your site</h2></div>
241
  <button class="icon" id="eClose" data-testid="embed-close" data-api="panel('embed', false)" aria-label="Close">✕</button>
242
  </div>
243
  <div class="about-body">
@@ -248,6 +248,94 @@ if (!/(^|[#&])s=/.test(location.hash)) ['scrolls/index.json', 'scrolls/PHerc0139
248
  <textarea id="embedCode" class="embed-code mono" rows="5" readonly aria-label="Embed code" data-testid="embed-code" data-api="embed.snippet()"></textarea>
249
  <p><button class="chip" id="embedCopy" data-testid="embed-copy" data-api="embed.snippet()">Copy</button> <a id="embedPreviewURL" href="./" target="_blank" rel="noopener" data-testid="embed-preview" data-api="embed.snippet()">Preview the embed</a></p>
250
  <p class="mono dim small">oEmbed: <a href="oembed.json" target="_blank" rel="noopener">/oembed.json</a>. Host pages can drive the viewer with postMessage; see <a href="docs/EMBED.md" target="_blank" rel="noopener">EMBED.md</a>.</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
251
  </div>
252
  </section>
253
 
 
139
  <button class="icon" id="btnOpen" data-testid="open-own" data-api="panel('open')" title="Open your own scroll: files stay in your browser, nothing is uploaded" aria-label="Open your own scroll">+</button>
140
  <button class="icon" id="btnBench" data-testid="bench" data-api="bench.open()" title="Ink Bench: score your own ink prediction against the published ink. Runs in your browser, nothing is uploaded" aria-label="Ink Bench"><svg viewBox="0 0 24 24" width="15" height="15"><path d="M4 19V9M10 19V5M16 19v-7M21 19H3" fill="none" stroke="currentColor" stroke-width="1.6"/></svg></button>
141
  <button class="icon" id="btnInfo" data-testid="about" data-api="panel('about')" title="About this page" aria-label="About">i</button>
142
+ <button class="icon" id="btnEmbed" data-testid="embed" data-api="panel('embed')" title="Embed this viewer on your site, or connect your tool to its data" aria-label="Embed this viewer or connect your tool">&lt;/&gt;</button>
143
  <button class="icon" id="btnFull" data-testid="fullscreen" data-api="fullscreen()" title="Fullscreen" aria-label="Fullscreen" aria-pressed="false">
144
  <svg viewBox="0 0 24 24" width="15" height="15"><path d="M4 9V4h5M15 4h5v5M20 15v5h-5M9 20H4v-5" fill="none" stroke="currentColor" stroke-width="1.5"/></svg>
145
  </button>
 
232
  <p class="mono dim small">Sources: open data bucket <code>PHerc0139/segments/*/mesh/*9.362um.tifxyz</code>, <code>surface-volumes/9.362um…zarr</code> and <code>ink-detection/downsampled</code>. Data: Giorgio Angelotti, Stephen Parsons, Sean Johnson, Elian Rafael Dal Prà, Johannes Rudolph, Paul Tafforeau, Alessandro Mirone, Paul Henderson, Hendrik Schilling, Forrest McDonald, David Josey, Youssef Nader, C. Seth Parker, W. Brent Seales. <i>Vesuvius Challenge - CT Scans of Herculaneum Papyri.</i> Vesuvius Challenge. Licensed <a href="https://creativecommons.org/licenses/by-nc/4.0/" target="_blank" rel="noopener">CC BY‑NC 4.0</a>. The page's code (HTML, CSS, JS and <code>tools/</code>) is Apache 2.0; see the Space's README.</p>
233
  <p class="mono dim small made-by">Made by Chase Hendrick.</p>
234
  </div>
235
+ <div class="sheet-foot mono dim small about-foot"><span><a href="#connect" onclick="document.getElementById('btnEmbed').click();setTimeout(()=>document.getElementById('connect').scrollIntoView({behavior:'smooth'}),50);return false">Connect your tool</a> · For agents: <a href="llms.txt" target="_blank" rel="noopener">llms.txt</a> · <a href="AGENTS.md" target="_blank" rel="noopener">AGENTS.md</a> · <a href="api.json" target="_blank" rel="noopener">api.json</a></span> <span id="aVersion" class="version" data-testid="version" title="Version and build (CHANGELOG.md)"></span></div>
236
  </section>
237
 
238
  <section id="embedSheet" class="sheet about" role="dialog" aria-modal="false" aria-labelledby="eTitle" hidden data-testid="embed-panel">
239
  <div class="sheet-head">
240
+ <div><div class="mono dim">EMBED</div><h2 id="eTitle">Put this viewer on your site, or its data in your tool</h2></div>
241
  <button class="icon" id="eClose" data-testid="embed-close" data-api="panel('embed', false)" aria-label="Close">✕</button>
242
  </div>
243
  <div class="about-body">
 
248
  <textarea id="embedCode" class="embed-code mono" rows="5" readonly aria-label="Embed code" data-testid="embed-code" data-api="embed.snippet()"></textarea>
249
  <p><button class="chip" id="embedCopy" data-testid="embed-copy" data-api="embed.snippet()">Copy</button> <a id="embedPreviewURL" href="./" target="_blank" rel="noopener" data-testid="embed-preview" data-api="embed.snippet()">Preview the embed</a></p>
250
  <p class="mono dim small">oEmbed: <a href="oembed.json" target="_blank" rel="noopener">/oembed.json</a>. Host pages can drive the viewer with postMessage; see <a href="docs/EMBED.md" target="_blank" rel="noopener">EMBED.md</a>.</p>
251
+ <!-- space-connect:start -->
252
+ <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}
253
+ .scc h2{font-size:1.15em;margin:.2em 0 .3em}.scc h3{font-size:1em;margin:0 0 .2em}
254
+ .scc p{margin:.3em 0}.scc a{color:var(--a)}
255
+ .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)}
256
+ .scc .scc-meta{font-size:.85em;opacity:.8}
257
+ .scc details{border-top:1px solid color-mix(in srgb,currentColor 12%,transparent);padding:.35em 0}
258
+ .scc summary{cursor:pointer;font-weight:600;list-style-position:inside}
259
+ .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}
260
+ .scc .scc-b.ok{color:#3fb37f}.scc .scc-b.src{color:var(--a)}.scc .scc-b.warn{color:#e0a030}
261
+ .scc .scc-code{position:relative;margin:.4em 0 .2em}
262
+ .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}
263
+ .scc code{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}
264
+ .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}
265
+ .scc button.scc-copy:hover{border-color:var(--a)}
266
+ .scc .scc-url{position:relative}.scc .scc-url pre{padding-right:4.5em;white-space:pre-wrap;word-break:break-all}
267
+ .scc .scc-go{display:inline-block;margin:.3em 0;padding:.25em .8em;border-radius:6px;border:1px solid var(--a);text-decoration:none}
268
+ .scc footer{font-size:.8em;opacity:.75;margin-top:.6em}</style>
269
+ <h2>Connect your tool</h2>
270
+ <p>The traced windings, X-ray CT and ink layers in Unroll come from the Vesuvius Challenge open data, and every one of them reads straight from these URLs in your own tool, with no account and no download step.</p>
271
+ <div class="scc-src" id="connect-segment"><h3>A traced winding (tifxyz), example PHerc0841 w00</h3>
272
+ <p class="scc-meta">CC BY-NC 4.0 (Vesuvius Challenge open data) · Every winding Unroll shows has a folder like this under SCROLL/segments/ in the open data; Unroll keeps only a decimated copy for the browser.</p>
273
+ <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/PHerc0841/segments/20260220213127-w00/mesh/20260220213127-on-20250821151531-9.366um.tifxyz</code></pre></div>
274
+ <details><summary>Python (numpy, tifffile)<span class="scc-b ok">tested 2026-10-24</span></summary>
275
+ <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
276
+ import io, json, urllib.request
277
+ import numpy as np, tifffile
278
+
279
+ T = &quot;https://vesuvius-challenge-open-data.s3.us-east-1.amazonaws.com/PHerc0841/segments/20260220213127-w00/mesh/20260220213127-on-20250821151531-9.366um.tifxyz&quot;
280
+ meta = json.load(urllib.request.urlopen(T + &quot;/meta.json&quot;)) # scale, bbox, format
281
+ get = lambda c: tifffile.imread(io.BytesIO(urllib.request.urlopen(f&quot;{T}/{c}.tif&quot;).read()))
282
+ 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>
283
+ </div>
284
+ <div class="scc-src" id="connect-segments"><h3>Every segment of a scroll, example PHerc0841</h3>
285
+ <p class="scc-meta">CC BY-NC 4.0 (Vesuvius Challenge open data) · Each segment folder has mesh/ (tifxyz), surface-volumes/ (OME-Zarr layers) and, where published, ink-detection/. · <a href="https://scrollprize.org/data_browser/PHerc0841" target="_blank" rel="noopener">browse</a></p>
286
+ <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>s3://vesuvius-challenge-open-data/PHerc0841/segments/</code></pre></div>
287
+ <details><summary>Python (list the folder)<span class="scc-b ok">tested 2026-10-24</span></summary>
288
+ <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>import re, urllib.request
289
+
290
+ B = &quot;https://vesuvius-challenge-open-data.s3.us-east-1.amazonaws.com&quot;
291
+ xml = urllib.request.urlopen(B + &quot;/?list-type=2&amp;delimiter=/&amp;prefix=PHerc0841/segments/&quot;).read().decode()
292
+ print(re.findall(r&quot;&lt;Prefix&gt;([^&lt;]+)&lt;/Prefix&gt;&quot;, xml)) # subfolders; &lt;Key&gt; gives files</code></pre></div></details>
293
+ </div>
294
+ <div class="scc-src" id="connect-ct"><h3>X-ray CT behind the CT view, PHerc0139 9.362 um</h3>
295
+ <p class="scc-meta">CC BY-NC 4.0 (Vesuvius Challenge open data) · Streamed from the open-data bucket, never copied here. Unroll opens any other scan with ?ctzarr=URL&amp;ctum=VOXEL_UM. · <a href="https://scrollprize.org/data_browser/PHerc0139" target="_blank" rel="noopener">browse</a></p>
296
+ <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/PHerc0139/volumes/20250728140407-9.362um-1.2m-113keV-masked.zarr</code></pre></div>
297
+ <details><summary>Python (zarr)<span class="scc-b ok">tested 2026-10-24</span></summary>
298
+ <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 &quot;zarr&gt;=3&quot; fsspec aiohttp
299
+ import zarr
300
+
301
+ root = zarr.open_group(&quot;https://vesuvius-challenge-open-data.s3.us-east-1.amazonaws.com/PHerc0139/volumes/20250728140407-9.362um-1.2m-113keV-masked.zarr&quot;, mode=&quot;r&quot;) # OME-Zarr, zarr v2
302
+ a = root[&quot;2&quot;] # level 0 is full resolution; level L is 2**L times coarser
303
+ print(a.shape, a.dtype, a.chunks)
304
+ block = a[2622:2686, 828:892, 828:892] # (z, y, x); reads only the chunks it touches</code></pre></div></details>
305
+ <details><summary>villa&#x27;s vesuvius package<span class="scc-b ok">tested 2026-10-24</span></summary>
306
+ <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 &quot;vesuvius[volume-only]&quot;
307
+ from vesuvius import Volume
308
+
309
+ v = Volume(type=&quot;zarr&quot;, path=&quot;https://vesuvius-challenge-open-data.s3.us-east-1.amazonaws.com/PHerc0139/volumes/20250728140407-9.362um-1.2m-113keV-masked.zarr/2&quot;) # one pyramid level
310
+ block = v[2622:2686, 828:892, 828:892]</code></pre></div></details>
311
+ <details><summary>VC3D<span class="scc-b src">from villa&#x27;s source</span></summary>
312
+ <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>In VC3D (villa&#x27;s volume-cartographer), open or create a project, then
313
+ File &gt; Attach Remote Zarr... and paste:
314
+
315
+ https://vesuvius-challenge-open-data.s3.us-east-1.amazonaws.com/PHerc0139/volumes/20250728140407-9.362um-1.2m-113keV-masked.zarr
316
+
317
+ It accepts http, https and s3 OME-Zarr roots.</code></pre></div></details>
318
+ <details><summary>neuroglancer<span class="scc-b ok">tested 2026-10-24</span></summary>
319
+ <a class="scc-go" href="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%2FPHerc0139%2Fvolumes%2F20250728140407-9.362um-1.2m-113keV-masked.zarr%2F%22%2C%22name%22%3A%22X-ray%20CT%20behind%20the%20CT%20view%2C%20PHerc0139%209.362%20um%22%7D%5D%2C%22layout%22%3A%224panel%22%7D" target="_blank" rel="noopener">Open in neuroglancer</a>
320
+ <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>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%2FPHerc0139%2Fvolumes%2F20250728140407-9.362um-1.2m-113keV-masked.zarr%2F%22%2C%22name%22%3A%22X-ray%20CT%20behind%20the%20CT%20view%2C%20PHerc0139%209.362%20um%22%7D%5D%2C%22layout%22%3A%224panel%22%7D</code></pre></div></details>
321
+ <details><summary>curl<span class="scc-b ok">tested 2026-10-24</span></summary>
322
+ <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 -s https://vesuvius-challenge-open-data.s3.us-east-1.amazonaws.com/PHerc0139/volumes/20250728140407-9.362um-1.2m-113keV-masked.zarr/.zattrs # OME multiscales metadata
323
+ curl -s https://vesuvius-challenge-open-data.s3.us-east-1.amazonaws.com/PHerc0139/volumes/20250728140407-9.362um-1.2m-113keV-masked.zarr/2/.zarray # one level: shape, chunks, dtype, codec</code></pre></div></details>
324
+ </div>
325
+ <div class="scc-src" id="connect-page"><h3>Unroll&#x27;s own API, files and embed</h3>
326
+ <p class="scc-meta">Page code Apache 2.0; derived data CC BY-NC 4.0 · Every button has a data-api name and the same call on window.unroll, so a script or an agent can drive the page.</p>
327
+ <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-unroll.static.hf.space/</code></pre></div>
328
+ <details><summary>Links and embed<span class="scc-b ok">tested 2026-10-24</span></summary>
329
+ <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>API description (window.unroll, postMessage, deep links): https://huggingface.co/spaces/SharpMeow/unroll/resolve/main/api.json
330
+ Guide for agents: https://huggingface.co/spaces/SharpMeow/unroll/resolve/main/llms.txt
331
+ Scroll list and per-scroll manifests: https://huggingface.co/spaces/SharpMeow/unroll/resolve/main/scrolls/index.json
332
+ Ink Bench on the command line: https://huggingface.co/spaces/SharpMeow/unroll/resolve/main/tools/inkbench.py
333
+ Deep link to one winding: https://sharpmeow-unroll.static.hf.space/?scroll=PHerc0139&amp;t=0.6&amp;layer=overlay&amp;focus=w047&amp;compare=0.3
334
+
335
+ &lt;iframe src=&quot;https://sharpmeow-unroll.static.hf.space/index.html?embed=1&quot; width=&quot;100%&quot; height=&quot;600&quot; allow=&quot;fullscreen; clipboard-write&quot;&gt;&lt;/iframe&gt;</code></pre></div></details>
336
+ </div>
337
+ <footer>Machine-readable: <a href="https://huggingface.co/spaces/SharpMeow/unroll/blob/main/connect.json" target="_blank" rel="noopener">connect.json</a> and <a href="https://huggingface.co/spaces/SharpMeow/unroll/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>
338
+ <!-- space-connect:end -->
339
  </div>
340
  </section>
341
 
llms.txt CHANGED
@@ -11,6 +11,7 @@
11
  - [Adding a scroll](/docs/ADDING_A_SCROLL.md): the manifest format and the precompute pipeline
12
  - [EMBED.md](/docs/EMBED.md): embedding in an iframe and the postMessage API
13
  - [oembed.json](/oembed.json): oEmbed
 
14
  - [CHANGELOG.md](/CHANGELOG.md): versions; the current one is in /version.json
15
 
16
  ## Quick start
 
11
  - [Adding a scroll](/docs/ADDING_A_SCROLL.md): the manifest format and the precompute pipeline
12
  - [EMBED.md](/docs/EMBED.md): embedding in an iframe and the postMessage API
13
  - [oembed.json](/oembed.json): oEmbed
14
+ - [CONNECT.md](/CONNECT.md): read the data behind the page from your own tool (Python, villa, VC3D, neuroglancer, curl); machine-readable in [connect.json](/connect.json)
15
  - [CHANGELOG.md](/CHANGELOG.md): versions; the current one is in /version.json
16
 
17
  ## Quick start
version.json CHANGED
@@ -1,8 +1,8 @@
1
  {
2
  "name": "unroll",
3
- "version": "1.5.0",
4
- "date": "2026-10-16",
5
- "sha": "bf9ab42",
6
  "license": "Apache-2.0",
7
  "data_license": "CC-BY-NC-4.0",
8
  "shaNote": "Short SHA of the commit this build was stamped on (its parent, since a commit cannot contain its own hash). Run node tools/stamp_version.mjs patch before each push.",
 
1
  {
2
  "name": "unroll",
3
+ "version": "1.6.0",
4
+ "date": "2026-10-24",
5
+ "sha": "e31bb23",
6
  "license": "Apache-2.0",
7
  "data_license": "CC-BY-NC-4.0",
8
  "shaNote": "Short SHA of the commit this build was stamped on (its parent, since a commit cannot contain its own hash). Run node tools/stamp_version.mjs patch before each push.",