-
Notifications
You must be signed in to change notification settings - Fork 0
cockpit/torso: land anisotropic + /torso-map + helix codec into main (stacked merges stayed in intermediate branches) #55
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,42 +1,23 @@ | ||
| { | ||
| "source": "BodyParts3D 4.0 (DBCLS) part-of OBJ, decimated 99%", | ||
| "license": "CC-BY 4.0", | ||
| "attribution": "BodyParts3D, (c) The Database Center for Life Science licensed under CC Attribution 4.0 International", | ||
| "source": "BodyParts3D 4.0 (DBCLS) part-of OBJ, decimated 99%, with vn normals", | ||
| "license": "CC-BY 4.0 (site) / CC-BY-SA 2.1 JP (2013 files)", | ||
| "attribution": "BodyParts3D, (c) The Database Center for Life Science. Current site licence: CC-BY 4.0; 2013 mesh files embed CC-BY-SA 2.1 Japan.", | ||
| "format": "SPL2 (anisotropic + node-row tags); node SoA in torso.nodes.json", | ||
| "root_fma": "FMA7181", | ||
| "root_name": "trunk", | ||
| "concepts": 102, | ||
| "concepts": 178, | ||
| "meshes": 577, | ||
| "vertices_total": 693959, | ||
| "gaussians": 231320, | ||
| "radius": 0.0045, | ||
| "gaussians": 231515, | ||
| "radius": 0.0035, | ||
| "bbox_min": [ | ||
| -0.5499420475739409, | ||
| -0.2690260109315338, | ||
| -0.5499102767007714, | ||
| -0.269514341019139, | ||
| -0.9999999999999999 | ||
| ], | ||
| "bbox_max": [ | ||
| 0.5499420475739409, | ||
| 0.2690260109315338, | ||
| 0.5499102767007714, | ||
| 0.269514341019139, | ||
| 1.0000000000000002 | ||
| ], | ||
| "regions": [ | ||
| { | ||
| "fma": "FMA259209", | ||
| "name": "thoracic segment of trunk" | ||
| }, | ||
| { | ||
| "fma": "FMA259211", | ||
| "name": "abdominal segment of trunk" | ||
| }, | ||
| { | ||
| "fma": "FMA10427", | ||
| "name": "body wall" | ||
| }, | ||
| { | ||
| "fma": "FMA9579", | ||
| "name": "perineum" | ||
| } | ||
| ], | ||
| "generated_by": "crates/osint-bake/tools/bake_torso_splat.py", | ||
| "format": "SPL1: hdr[magic4|count u32|radius f32|bbox_min 3f|bbox_max 3f]; body count*[pos 3f|rgb 3u8|opacity u8]; little-endian" | ||
| "owners": 91 | ||
| } |
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,272 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // FMA torso · map view — the splat AS the GUID substrate. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Renders the same torso.splat (SPL2: real BodyParts3D geometry, per-vertex | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // normal, per-gaussian node-row tag) but treats it as the value-tenant SoA it | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // is: click a gaussian -> its node row -> O(1) into torso.nodes.json (the node | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // SoA) -> the FMA structure's identity (concept id, name, partonomy path, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // gaussian range). Click a structure in the list -> its gaussians highlight. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Geometry, graph, and splat are three tenants of one identity, switch-selected. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Geometry: BodyParts3D, (c) The Database Center for Life Science (CC-BY 4.0 / | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // CC-BY-SA 2.1 JP). Attribution shown in-view. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useEffect, useMemo, useRef, useState } from 'react'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import * as THREE from 'three'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| interface NodeRow { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| row: number; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fma: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| depth: number; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| parent: number | null; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| tiers: number[]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| rgb: [number, number, number]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| g_start: number; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| g_count: number; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| centroid: [number, number, number] | null; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| interface NodesDoc { attribution: string; root: string; nodes: NodeRow[] } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| interface Spl2 { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| count: number; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| positions: Float32Array; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| colors: Float32Array; // 0..1 rgb | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| rows: Float32Array; // node_row per gaussian | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function decodeSpl2(buf: ArrayBuffer): Spl2 { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const dv = new DataView(buf); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const magic = String.fromCharCode(dv.getUint8(0), dv.getUint8(1), dv.getUint8(2), dv.getUint8(3)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (magic !== 'SPL2') throw new Error(`bad magic "${magic}" (expected SPL2)`); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const count = dv.getUint32(4, true); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const off = 40; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const positions = new Float32Array(count * 3); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const colors = new Float32Array(count * 3); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const rows = new Float32Array(count); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (let i = 0; i < count; i++) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const b = off + i * 21; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+37
to
+47
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win Validate SPL2 size before trusting
Proposed guard function decodeSpl2(buf: ArrayBuffer): Spl2 {
+ if (buf.byteLength < 40) {
+ throw new Error(`SPL2 file too short: ${buf.byteLength} bytes`);
+ }
const dv = new DataView(buf);
const magic = String.fromCharCode(dv.getUint8(0), dv.getUint8(1), dv.getUint8(2), dv.getUint8(3));
if (magic !== 'SPL2') throw new Error(`bad magic "${magic}" (expected SPL2)`);
const count = dv.getUint32(4, true);
+ const expectedBytes = 40 + count * 21;
+ if (buf.byteLength < expectedBytes) {
+ throw new Error(`SPL2 file truncated: ${buf.byteLength} bytes, expected at least ${expectedBytes}`);
+ }
const off = 40;📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // upright: (x,y,z) -> (x,z,-y) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| positions[i * 3] = dv.getFloat32(b, true); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| positions[i * 3 + 1] = dv.getFloat32(b + 8, true); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| positions[i * 3 + 2] = -dv.getFloat32(b + 4, true); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| colors[i * 3] = dv.getUint8(b + 15) / 255; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| colors[i * 3 + 1] = dv.getUint8(b + 16) / 255; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| colors[i * 3 + 2] = dv.getUint8(b + 17) / 255; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| rows[i] = dv.getUint16(b + 19, true); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { count, positions, colors, rows }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const VERT = ` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| attribute vec3 aColor; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| attribute float aRow; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| uniform float uSelected; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| uniform float uSize; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| varying vec3 vColor; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| varying float vDim; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| void main() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| vColor = aColor; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| vDim = (uSelected < 0.0 || abs(aRow - uSelected) < 0.5) ? 1.0 : 0.16; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| vec4 mv = modelViewMatrix * vec4(position, 1.0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| gl_Position = projectionMatrix * mv; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| gl_PointSize = uSize * (1.0 / -mv.z); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const FRAG = ` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| precision mediump float; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| varying vec3 vColor; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| varying float vDim; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| void main() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| vec2 c = gl_PointCoord - 0.5; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (dot(c, c) > 0.25) discard; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| float a = smoothstep(0.25, 0.05, dot(c, c)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| gl_FragColor = vec4(vColor * vDim, a); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+78
to
+82
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major 🧩 Analysis chain🌐 Web query:
💡 Result: In GLSL ES, smoothstep(edge0, edge1, x) has undefined results when edge0 is greater than or equal to edge1; i.e., the specification states results are undefined if edge0 >= edge1. Therefore behavior in that case (including your stated “edge0 >= edge1”) is not guaranteed and may vary by compiler/GPU. [1][2] What is defined (for reference): it returns 0.0 when x <= edge0 and 1.0 when x >= edge1, and only performs the smooth Hermite interpolation when edge0 < x < edge1. [1][2] Practical fix: ensure edge0 < edge1 (swap them or reorder your inputs), or implement your own definition that handles edge0 >= edge1 deterministically rather than relying on smoothstep’s undefined behavior. The community discussion and the spec quote both recommend not relying on edge0 >= edge1. [2][3] Citations:
🏁 Script executed: #!/bin/bash
set -euo pipefail
# Inspect the relevant file and surrounding lines.
sed -n '1,140p' cockpit/src/TorsoMap.tsx | cat -n
# Find the exact smoothstep usage(s) in the repository.
rg -n "smoothstep\\(" cockpit/src/TorsoMap.tsx cockpit/src || trueRepository: AdaWorldAPI/q2 Length of output: 6474 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Inspect the relevant file and surrounding lines.
sed -n '1,140p' cockpit/src/TorsoMap.tsx | cat -n
# Find the exact smoothstep usage(s) in the repository.
rg -n "smoothstep\\(" cockpit/src/TorsoMap.tsx cockpit/src || trueRepository: AdaWorldAPI/q2 Length of output: 6474 Use ordered Proposed shader fix- float a = smoothstep(0.25, 0.05, dot(c, c));
+ float a = 1.0 - smoothstep(0.05, 0.25, dot(c, c));📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }`; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function mount( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| container: HTMLDivElement, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| splat: Spl2, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onPick: (row: number) => void, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| apiRef: { current: { select: (row: number) => void } | null }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ): () => void { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let w = container.clientWidth || window.innerWidth; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let h = container.clientHeight || window.innerHeight; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const scene = new THREE.Scene(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| scene.background = new THREE.Color(0x0a0e17); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const camera = new THREE.PerspectiveCamera(45, w / h, 0.01, 100); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| camera.position.set(0, 0.05, 3.0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const renderer = new THREE.WebGLRenderer({ antialias: true }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| renderer.setSize(w, h); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| container.appendChild(renderer.domElement); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const geom = new THREE.BufferGeometry(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| geom.setAttribute('position', new THREE.BufferAttribute(splat.positions, 3)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| geom.setAttribute('aColor', new THREE.BufferAttribute(splat.colors, 3)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| geom.setAttribute('aRow', new THREE.BufferAttribute(splat.rows, 1)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const mat = new THREE.ShaderMaterial({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| vertexShader: VERT, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fragmentShader: FRAG, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| uniforms: { uSelected: { value: -1 }, uSize: { value: 4.2 } }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| transparent: true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| depthWrite: true, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const points = new THREE.Points(geom, mat); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| scene.add(points); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const controls = new OrbitControls(camera, renderer.domElement); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| controls.enableDamping = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| controls.dampingFactor = 0.08; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| controls.target.set(0, 0, 0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| controls.minDistance = 0.6; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| controls.maxDistance = 12; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const ray = new THREE.Raycaster(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ray.params.Points = { threshold: 0.02 }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const ndc = new THREE.Vector2(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let downAt = { x: 0, y: 0 }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| renderer.domElement.addEventListener('pointerdown', (e) => { downAt = { x: e.clientX, y: e.clientY }; }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| renderer.domElement.addEventListener('pointerup', (e) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (Math.hypot(e.clientX - downAt.x, e.clientY - downAt.y) > 5) return; // drag, not click | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const r = renderer.domElement.getBoundingClientRect(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ndc.x = ((e.clientX - r.left) / r.width) * 2 - 1; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ndc.y = -((e.clientY - r.top) / r.height) * 2 + 1; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ray.setFromCamera(ndc, camera); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const hit = ray.intersectObject(points, false); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (hit.length && hit[0].index != null) onPick(splat.rows[hit[0].index]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| apiRef.current = { select: (row: number) => { mat.uniforms.uSelected.value = row; } }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let raf = 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const tick = () => { raf = requestAnimationFrame(tick); controls.update(); renderer.render(scene, camera); }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| tick(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const onResize = () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| w = container.clientWidth || window.innerWidth; h = container.clientHeight || window.innerHeight; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| camera.aspect = w / h; camera.updateProjectionMatrix(); renderer.setSize(w, h); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const ro = new ResizeObserver(onResize); ro.observe(container); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cancelAnimationFrame(raf); ro.disconnect(); controls.dispose(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| geom.dispose(); mat.dispose(); renderer.dispose(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (renderer.domElement.parentNode === container) container.removeChild(renderer.domElement); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export function TorsoMap() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const ref = useRef<HTMLDivElement>(null); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const apiRef = useRef<{ select: (row: number) => void } | null>(null); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [splat, setSplat] = useState<Spl2 | null>(null); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [doc, setDoc] = useState<NodesDoc | null>(null); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [sel, setSel] = useState<number | null>(null); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [error, setError] = useState<string | null>(null); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let cancelled = false; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fetch('/torso.splat') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .then((r) => { if (!r.ok) throw new Error(`HTTP ${r.status} torso.splat`); return r.arrayBuffer(); }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .then((b) => !cancelled && setSplat(decodeSpl2(b))) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .catch((e) => !cancelled && setError(String(e))); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| fetch('/torso.nodes.json') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .then((r) => (r.ok ? r.json() : null)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .then((d) => !cancelled && d && setDoc(d as NodesDoc)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .catch(() => {}); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+169
to
+172
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win Surface A missing or stale nodes document currently fails silently, leaving Proposed error handling fetch('/torso.nodes.json')
- .then((r) => (r.ok ? r.json() : null))
- .then((d) => !cancelled && d && setDoc(d as NodesDoc))
- .catch(() => {});
+ .then((r) => {
+ if (!r.ok) throw new Error(`HTTP ${r.status} torso.nodes.json`);
+ return r.json();
+ })
+ .then((d) => !cancelled && setDoc(d as NodesDoc))
+ .catch((e) => !cancelled && setError(String(e)));📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return () => { cancelled = true; }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, []); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const c = ref.current; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!c || !splat) return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return mount(c, splat, (row) => setSel(row), apiRef); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, [splat]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| useEffect(() => { apiRef.current?.select(sel ?? -1); }, [sel]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+176
to
+182
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win Replay the current selection after the WebGL mount is created. If Proposed sync fix useEffect(() => {
const c = ref.current;
if (!c || !splat) return;
- return mount(c, splat, (row) => setSel(row), apiRef);
+ const dispose = mount(c, splat, (row) => setSel(row), apiRef);
+ apiRef.current?.select(sel ?? -1);
+ return dispose;
}, [splat]);📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // the "switch": row -> node, built once (O(1) lookup) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const byRow = useMemo(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const m = new Map<number, NodeRow>(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| doc?.nodes.forEach((n) => m.set(n.row, n)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return m; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, [doc]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // partonomy breadcrumb (walk parent links) for the selected node | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const path = useMemo(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (sel == null) return []; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const out: NodeRow[] = []; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let cur: number | null = sel; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for (let i = 0; i < 24 && cur != null; i++) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const n = byRow.get(cur); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!n) break; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| out.push(n); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| cur = n.parent; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return out.reverse(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, [sel, byRow]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const owners = useMemo( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| () => (doc?.nodes ?? []).filter((n) => n.g_count > 0).sort((a, b) => b.g_count - a.g_count), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [doc], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const selNode = sel != null ? byRow.get(sel) : undefined; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const css = (rgb: [number, number, number]) => `rgb(${rgb[0]},${rgb[1]},${rgb[2]})`; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div style={{ position: 'fixed', inset: 0, background: '#0a0e17', overflow: 'hidden', color: '#cdd9e5', font: '12px ui-monospace, monospace' }}> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div ref={ref} style={{ position: 'absolute', inset: 0 }} /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div style={{ position: 'absolute', top: 12, left: 16, pointerEvents: 'none' }}> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div style={{ fontSize: 15, color: '#fff' }}>FMA torso · map</div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div style={{ opacity: 0.7 }}> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| click a structure — splat ↔ FMA, one node at one address | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {doc ? ` · ${owners.length} structures` : ''} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {error && ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div style={{ position: 'absolute', top: '46%', width: '100%', textAlign: 'center', color: '#ff8095' }}>{error}</div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {/* selected structure + partonomy path */} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {selNode && ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div style={{ position: 'absolute', top: 12, right: 16, width: 290, background: '#0e1422cc', border: '1px solid #20304a', borderRadius: 6, padding: '10px 12px' }}> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <span style={{ width: 11, height: 11, borderRadius: 3, background: css(selNode.rgb) }} /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <span style={{ color: '#fff', fontSize: 14 }}>{selNode.name}</span> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div style={{ opacity: 0.7, marginTop: 4 }}> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {selNode.fma} · {selNode.g_count.toLocaleString()} gaussians · depth {selNode.depth} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div style={{ opacity: 0.55, marginTop: 6, fontSize: 11 }}>HHTL tiers [{selNode.tiers.join(', ')}]</div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div style={{ marginTop: 8, borderTop: '1px solid #1b2740', paddingTop: 6, opacity: 0.85 }}> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {path.map((n, i) => ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div key={n.row} style={{ paddingLeft: i * 8, color: n.row === sel ? '#fff' : '#8aa0bb', cursor: 'pointer' }} onClick={() => setSel(n.row)}> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {i > 0 ? '└ ' : ''}{n.name} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+241
to
+243
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win Make selectable rows keyboard-operable. The breadcrumb and structure rows are clickable Also applies to: 253-256 🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ))} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| )} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {/* structure list (graph -> splat) */} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div style={{ position: 'absolute', bottom: 30, left: 16, maxHeight: '42%', width: 250, overflowY: 'auto', background: '#0e1422aa', border: '1px solid #1b2740', borderRadius: 6, padding: 6 }}> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {owners.map((n) => ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| key={n.row} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| onClick={() => setSel(n.row)} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| style={{ display: 'flex', alignItems: 'center', gap: 7, padding: '2px 4px', borderRadius: 3, cursor: 'pointer', background: n.row === sel ? '#1d2b40' : 'transparent', color: n.row === sel ? '#fff' : '#9fb2c9' }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| > | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <span style={{ width: 9, height: 9, borderRadius: 2, background: css(n.rgb), flex: '0 0 auto' }} /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{n.name}</span> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ))} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div style={{ position: 'absolute', top: 14, right: 320, font: '12px ui-monospace, monospace' }}> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <a href="/torso-live" style={{ color: '#7fa6c4', textDecoration: 'none' }}>live orbit →</a> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div style={{ position: 'absolute', bottom: 8, left: 16, color: '#5a6b7e', fontSize: 10, pointerEvents: 'none' }}> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {doc?.attribution ?? 'BodyParts3D, (c) The Database Center for Life Science (CC-BY 4.0 / CC-BY-SA 2.1 JP)'} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Keep spelling variant consistent in the document
Use one variant consistently (e.g., “Realizes” vs “Realises”) to avoid mixed-style docs.
🧰 Tools
🪛 LanguageTool
[uncategorized] ~83-~83: Do not mix variants of the same word (‘realise’ and ‘realize’) within a single text.
Context: ...h -> splat) highlights gaussians. Realises the osint-cad-splat thesis: graph and s...
(EN_WORD_COHERENCY)
🤖 Prompt for AI Agents
Source: Linters/SAST tools