Skip to content

Commit 3e1cca4

Browse files
committed
body: address CodeRabbit review — heart-as-solid, gzip sniff, LOD retry, a11y
CodeRabbit findings on #64: - Heart no longer classified as vessel material 0: it's a chambered organ, so the slicer-fill was sweeping a PCA-centerline lumen rod through it. Now falls through to solid_tissue (22 concepts artery→solid; fill 715→693 components). Wire + LOD blocks rebaked + reuploaded. - Decompress by the payload, not DecompressionStream support: sniff the gzip magic (1f 8b) so a browser/CDN that already decoded Content-Encoding doesn't get double-inflated, and a browser without DecompressionStream errors clearly instead of feeding gzip bytes to the decoder. - Server-LOD no longer permanently disabled after one failed poll: toggling LOD off clears the failure flag so re-enabling retries. - Search-result rows are now keyboard-focusable <button type="button"> elements instead of mouse-only <div>s. - Plan doc: marked the BF16 (ver 4) section SUPERSEDED by F16 (ver 5) to match the shipped wire.
1 parent 77223f5 commit 3e1cca4

4 files changed

Lines changed: 32 additions & 14 deletions

File tree

claude-notes/plans/2026-06-27-body-v3-server-lod-fill.md

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -106,15 +106,22 @@ centroid (robust to outliers), clamped to an **absolute** `[RMIN, RMAX]`
106106
diameter boundary (`RMAX=0.020` ≈ 34 mm dia, covers the aorta, kills balloons).
107107
662 vessels → +71,872 core verts / +133,152 tris.
108108

109-
### BF16 positions — BSO2 **ver 4** (the "A" brick)
110-
Per-vertex `pos` column is now **BF16** (3× u16 LE = 6 B/vertex), half of ver 3's
109+
### Half-precision positions — the "A" brick
110+
> **SUPERSEDED to F16 (BSO2 ver 5).** BF16 (ver 4) was tried first and **rejected**:
111+
> its 7-bit mantissa gave a ~3 mm step near the head (y≈0.85) → a visible staircase
112+
> (Treppeneffekt) on the eye/brain. Shipped format is **F16 / IEEE half (ver 5)**
113+
> same 6 B/vertex, 10-bit mantissa, ~0.2 mm (measured 0.21 mm max over the wire), no
114+
> staircase. Bake uses ndarray's `F16::from_f32`; renderer widens via a 64K half→f32
115+
> LUT. `BodyV3.tsx` reads ver 3 (f32) / 4 (BF16) / 5 (F16). gz ≈ 63 MB (vs f32's 80).
116+
> The BF16 description below is retained for history.
117+
118+
Per-vertex `pos` column was **BF16** (3× u16 LE = 6 B/vertex), half of ver 3's
111119
12 B f32. Conversion via ndarray's sanctioned RNE batch path
112120
(`f32_to_bf16_batch_rne`) on the native bake host (AVX-512/AMX). The renderer
113121
widens back to f32 client-side (`bits << 16` — BF16 is the top 16 bits of f32, so
114-
the widening is exact). Verified round-trip ≈ 1.4 mm error on a 1.7 m body — below
115-
the visual + cascade (screen-space-error) floor. Wire 176 MB → 150 MB; gz 80 MB →
116-
57.5 MB. `BodyV3.tsx` reads both ver 3 and ver 4. Asset replaced in release
117-
`fma-body-soa-v3-v1` (Dockerfile pulls it same-origin, unchanged).
122+
the widening is exact). Round-trip ≈ 1.4 mm — which turned out to be visible on
123+
small smooth structures, hence the F16 upgrade above. Asset in release
124+
`fma-body-soa-v3-v1` (Dockerfile pulls it same-origin).
118125

119126
### "B": server-side HHTL-O(1) LOD endpoint — WIRED (de-risked)
120127
cockpit-server can't build in-sandbox (quarto-core→runtimelib is a proxy-blocked

cockpit/src/BodyV3.tsx

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,7 @@ function mount(container: HTMLDivElement, d: Decoded, st: RenderState, onStats:
301301
if (renderer.getPixelRatio() !== pr) renderer.setPixelRatio(pr);
302302
uniforms.uEnabled.value = st.enabled; // shared by both materials
303303
uniforms.uGlobalAlpha.value = st.alpha;
304+
if (!st.lodOn) lodFail = false; // toggling LOD off clears a transient failure → re-enabling retries
304305
uniforms.uLodOn.value = st.lodOn && !lodFail && lodReady ? 1 : 0; // only cull after a real response
305306
if (st.focus) { // search-pick zoom: glide to the organ
306307
tmp.set(st.focus.t[0], st.focus.t[1], st.focus.t[2]);
@@ -360,10 +361,18 @@ export function BodyV3() {
360361

361362
useEffect(() => {
362363
let cancelled = false;
363-
const inflate = async (r: Response) =>
364-
r.body && typeof DecompressionStream !== 'undefined'
365-
? new Response(r.body.pipeThrough(new DecompressionStream('gzip'))).arrayBuffer()
366-
: r.arrayBuffer();
364+
// Decide by the *payload*, not by DecompressionStream support: if the browser (or a
365+
// CDN) already decoded Content-Encoding: gzip, the bytes are plain; if served raw,
366+
// they start with the gzip magic 1f 8b. Only inflate when actually gzipped.
367+
const inflate = async (r: Response): Promise<ArrayBuffer> => {
368+
const buf = await r.arrayBuffer();
369+
const u8 = new Uint8Array(buf);
370+
const gz = u8.length > 1 && u8[0] === 0x1f && u8[1] === 0x8b;
371+
if (!gz) return buf;
372+
if (typeof DecompressionStream === 'undefined')
373+
throw new Error('body.soa.gz is gzip but this browser lacks DecompressionStream');
374+
return new Response(new Blob([buf]).stream().pipeThrough(new DecompressionStream('gzip'))).arrayBuffer();
375+
};
367376
(async () => {
368377
const local = await fetch('/body.soa.gz').catch(() => null);
369378
if (local && local.ok) return decodeBso2(await inflate(local));
@@ -428,10 +437,10 @@ export function BodyV3() {
428437
{matches.length > 0 && (
429438
<div style={{ marginTop: 4, background: '#0e1219', border: '1px solid #1c2530', borderRadius: 6, overflow: 'hidden', maxHeight: 320, overflowY: 'auto' }}>
430439
{matches.map((c) => (
431-
<div key={c.row} onClick={() => { pick(c); setQuery(''); }} style={{ padding: '6px 9px', cursor: 'pointer', display: 'flex', justifyContent: 'space-between', gap: 8, borderBottom: '1px solid #141b24', color: '#cdd9e5' }}>
440+
<button type="button" key={c.row} onClick={() => { pick(c); setQuery(''); }} style={{ width: '100%', textAlign: 'left', padding: '6px 9px', cursor: 'pointer', display: 'flex', justifyContent: 'space-between', gap: 8, border: 'none', borderBottom: '1px solid #141b24', background: 'transparent', color: '#cdd9e5', font: '13px ui-monospace, monospace' }}>
432441
<span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{c.name}</span>
433442
<span style={{ opacity: 0.5, flexShrink: 0 }}>{LAYERS[(c.layer - 1) % 8]?.name}</span>
434-
</div>
443+
</button>
435444
))}
436445
</div>
437446
)}
0 Bytes
Binary file not shown.

crates/osint-bake/tools/bake_body_soa.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,10 @@
4848
{"id": 5, "name": "neural", "doppler": "none", "rgb": [226, 205, 88]},
4949
]
5050
TISSUE_MATERIAL = {
51-
"artery": 0, "heart": 0, "vein": 3, "vessel": 3, "nerve": 5,
52-
# everything solid (bone/cartilage/muscle/organs/skin/flesh) → solid_tissue
51+
"artery": 0, "vein": 3, "vessel": 3, "nerve": 5,
52+
# heart is a chambered ORGAN, not a tube — mapping it to artery(0) made the slicer-
53+
# fill sweep a PCA-centerline lumen rod through it. Fall through to solid_tissue
54+
# (like every other solid: bone/cartilage/muscle/organs/skin/flesh).
5355
}
5456

5557

0 commit comments

Comments
 (0)