a11oy / static /3d /surfaces /fabric.js
betterwithage's picture
fix(drift-heal): sync static/3d/surfaces/fabric.js to GitHub canonical (compute-pool-hardened endpoint, PR #441)
e3d6432 verified
Raw
History Blame
29.2 kB
// SPDX-License-Identifier: Apache-2.0
// © 2026 Lutar, Stephen P. Jr. — SZL Holdings · Doctrine v11
//
// surfaces/fabric.js — COMPUTE FABRIC surface (Dev2).
//
// Leader/technique modeled (NOT claimed-as): NVIDIA Omniverse DC digital twin +
// MIT-LL TX-Digital Twin (per-node instanced cards, color-graded health) +
// 3d-force-graph (vasturiano) — a 3D force-directed node mesh of the live compute pool.
//
// Primary live endpoint (doctrine v11: WIRE TO LIVE DATA, never fabricate):
// /api/a11oy/v1/compute-pool-hardened (the hardened sub-second, breaker-guarded
// prober that returns the REAL TCP-probed pool JSON; the plain /compute-pool path
// resolves to the SPA shell and the un-suffixed v1 alias 404s)
// counts{nodes_total, nodes_reachable, gpu_nodes_reachable, sovereign_gpu_live}
// nodes[]{name,kind,endpoint,reachable,sovereign,capabilities,models[]}
//
// Every value on screen traces to that JSON. If a node lacks a field (e.g. the
// hardened prober omits capabilities/models), we render the honest absence — we
// never invent a model name or a reachability. If the endpoint 404s / errors /
// {degraded:true}, the badge shows the honest state and the last good mesh is kept
// (or, with no data ever, an honest NO-LIVE-DATA placeholder). 0 runtime CDN.
//
// Honesty posture rendered on the viz:
// * reachable -> REAL TCP probe result (teal glow ON) vs unreachable (dim, red ring)
// * sovereign -> a PROPERTY of owned hardware (gold), passed through, NEVER inferred
// * the node-detail label chip is STRUCTURAL-ONLY: the topology mesh is structure,
// not a measured bandwidth — we do NOT claim measured NVLink bytes/sec. The reach
// counts ARE measured (live probe), labeled accordingly in the HUD.
const ID = "fabric";
const TITLE = "Compute Fabric";
const ENDPOINT = "/api/a11oy/v1/compute-pool-hardened";
// Doctrine palette (matches the shell CSS vars).
const C = {
sovereign: 0xe8c074, // gold — owned sovereign hardware
hosted: 0x6fb1ff, // blue — third-party hosted inference
gpu: 0x39d3c4, // teal — GPU-class node
unreachable: 0xff6b6b,
edge: 0x2a5a6b,
edgeHot: 0x39d3c4,
hub: 0x12202b,
text: "#eef3f6",
para: "#9fb1bf",
};
let _ctx = null, _stage = null, _THREE = null;
let _handle = null, _overlay = null, _panel = null, _detailChip = null;
let _root = null; // group holding the whole mesh (rotates slowly)
let _nodeMeshes = []; // [{ data, group, core, ring, glow, orbit[], labelSprite, basePos }]
let _edges = []; // [{ line, a, b, hot }]
let _hubMesh = null, _healthRing = null, _healthFill = null;
let _raf = null, _frameCb = null;
let _lastJson = null, _lastMeta = null;
let _t = 0;
let _hud = {}; // references to live HUD value spans
let _selected = null;
let _ray = null, _pointer = null, _onClick = null, _onMove = null;
let _domEl = null;
// ----------------------------------------------------------------------------
// Deterministic layout: place nodes on a force-relaxed sphere shell around a
// central fabric hub. We seed positions deterministically from the node name
// (no randomness => stable across polls) and run a light repulsion relax so the
// graph reads like a 3d-force-graph layout without a per-frame CPU sim.
// ----------------------------------------------------------------------------
function _hash(str) {
let h = 2166136261 >>> 0;
for (let i = 0; i < str.length; i++) { h ^= str.charCodeAt(i); h = Math.imul(h, 16777619) >>> 0; }
return h >>> 0;
}
function _seedPos(name, i, n) {
// Fibonacci-sphere seed perturbed by name hash -> deterministic, well-spread.
const h = _hash(name);
const golden = Math.PI * (3 - Math.sqrt(5));
const y = 1 - (i / Math.max(1, n - 1)) * 2;
const r = Math.sqrt(Math.max(0, 1 - y * y));
const theta = golden * i + (h % 360) * Math.PI / 180;
const R = 6.4;
return [Math.cos(theta) * r * R, y * R * 0.78, Math.sin(theta) * r * R];
}
function _relax(positions, iters) {
// tiny O(n^2) repulsion so close seeds spread; n is ~6, cost is trivial.
for (let it = 0; it < iters; it++) {
for (let a = 0; a < positions.length; a++) {
for (let b = a + 1; b < positions.length; b++) {
const dx = positions[a][0] - positions[b][0];
const dy = positions[a][1] - positions[b][1];
const dz = positions[a][2] - positions[b][2];
let d2 = dx * dx + dy * dy + dz * dz;
if (d2 < 0.0001) d2 = 0.0001;
const f = 1.6 / d2;
const d = Math.sqrt(d2);
const ux = dx / d, uy = dy / d, uz = dz / d;
positions[a][0] += ux * f; positions[a][1] += uy * f; positions[a][2] += uz * f;
positions[b][0] -= ux * f; positions[b][1] -= uy * f; positions[b][2] -= uz * f;
}
}
}
return positions;
}
function _isGpu(kind) { return /gpu/i.test(String(kind || "")); }
function _nodeColor(node) {
if (!node.reachable) return C.unreachable;
if (node.sovereign) return C.sovereign;
if (_isGpu(node.kind)) return C.gpu;
return C.hosted;
}
// ----------------------------------------------------------------------------
// HUD overlay (left): title, LIVE badge, fabric-health ring readout, counts,
// honesty legend. Right panel: node-detail (click a node).
// ----------------------------------------------------------------------------
function _styleOverlay(el) {
Object.assign(el.style, {
position: "absolute", left: "14px", top: "14px", zIndex: "5",
display: "flex", flexDirection: "column", gap: "8px",
maxWidth: "min(92%,360px)", pointerEvents: "none",
});
}
function _row(label, valId) {
const r = document.createElement("div");
r.style.cssText = "display:flex;justify-content:space-between;gap:14px;" +
"font:11px ui-monospace,SFMono-Regular,Menlo,monospace;color:" + C.para + ";pointerEvents:none";
const k = document.createElement("span"); k.textContent = label;
const v = document.createElement("span"); v.id = valId;
v.style.cssText = "color:" + C.text + ";font-weight:600;letter-spacing:.3px";
v.textContent = "—";
r.appendChild(k); r.appendChild(v);
_hud[valId] = v;
return r;
}
function _buildOverlay() {
const ov = document.createElement("div");
ov.className = "szl3d-fabric-overlay";
_styleOverlay(ov);
const h = document.createElement("div");
h.style.cssText = "font:600 13px ui-sans-serif,system-ui;color:" + C.text + ";letter-spacing:.4px";
h.textContent = "◇ " + TITLE + " · live node mesh";
ov.appendChild(h);
const badge = _ctx.live.createBadge();
badge.el.style.pointerEvents = "auto";
ov.appendChild(badge.el);
const card = document.createElement("div");
card.style.cssText = "background:#0b121b;border:1px solid #1b2734;border-radius:9px;" +
"padding:9px 11px;display:flex;flexDirection:column;gap:5px;pointerEvents:none";
card.appendChild(_row("fabric health", "v_health"));
card.appendChild(_row("nodes reachable", "v_reach"));
card.appendChild(_row("GPU nodes live", "v_gpu"));
card.appendChild(_row("sovereign GPU live", "v_sov"));
card.appendChild(_row("chaski 2nd-lung", "v_chaski"));
card.appendChild(_row("reach probe", "v_label"));
ov.appendChild(card);
const note = document.createElement("div");
note.style.cssText = "font:9.5px ui-monospace,monospace;color:#6c7a86;line-height:1.5;pointerEvents:none";
note.textContent = "reachable = REAL TCP probe this sweep · sovereign = owned-hardware " +
"property, never inferred · topology is STRUCTURAL-ONLY (no measured NVLink bytes).";
ov.appendChild(note);
const legend = _ctx.label.legend();
legend.style.opacity = "0.85";
legend.style.pointerEvents = "none";
ov.appendChild(legend);
return { ov, badge };
}
function _buildPanel() {
const p = document.createElement("div");
p.className = "szl3d-fabric-panel";
Object.assign(p.style, {
position: "absolute", right: "14px", top: "14px", zIndex: "5",
width: "min(46%,300px)", background: "#0b121b", border: "1px solid #1b2734",
borderRadius: "9px", padding: "11px 13px", display: "none",
font: "11px ui-monospace,SFMono-Regular,Menlo,monospace", color: C.para,
pointerEvents: "auto",
});
return p;
}
function _renderPanel(node) {
if (!_panel) return;
if (!node) { _panel.style.display = "none"; return; }
_panel.style.display = "block";
_panel.innerHTML = "";
const title = document.createElement("div");
title.style.cssText = "font:600 13px ui-sans-serif,system-ui;color:" + C.text +
";display:flex;align-items:center;gap:8px;margin-bottom:7px";
const dot = document.createElement("span");
const hex = "#" + _nodeColor(node).toString(16).padStart(6, "0");
dot.style.cssText = "width:10px;height:10px;border-radius:50%;background:" + hex +
";box-shadow:0 0 8px " + hex;
const nm = document.createElement("span"); nm.textContent = node.name || "(unnamed)";
title.appendChild(dot); title.appendChild(nm);
_panel.appendChild(title);
const close = document.createElement("button");
close.textContent = "×";
close.style.cssText = "position:absolute;right:8px;top:6px;background:none;border:none;" +
"color:" + C.para + ";font-size:16px;cursor:pointer;line-height:1";
close.onclick = () => { _select(null); };
_panel.appendChild(close);
const meta = [
["kind", node.kind || "—"],
["endpoint", node.endpoint || "—"],
["reachable", node.reachable ? "YES (live TCP probe)" : "NO (timeout/refusal)"],
["sovereign", node.sovereign ? "YES (owned hardware)" : "no (hosted/third-party)"],
];
meta.forEach(([k, v]) => {
const r = document.createElement("div");
r.style.cssText = "display:flex;justify-content:space-between;gap:12px;margin:3px 0";
const a = document.createElement("span"); a.textContent = k; a.style.color = C.para;
const b = document.createElement("span"); b.textContent = v;
b.style.cssText = "color:" + C.text + ";text-align:right;max-width:62%;word-break:break-all";
r.appendChild(a); r.appendChild(b); _panel.appendChild(r);
});
// capabilities (honest: only what JSON carries)
const caps = Array.isArray(node.capabilities) ? node.capabilities : [];
const capWrap = document.createElement("div");
capWrap.style.cssText = "margin-top:8px";
const capH = document.createElement("div");
capH.textContent = "capabilities (" + caps.length + ")";
capH.style.cssText = "color:" + C.para + ";margin-bottom:4px";
capWrap.appendChild(capH);
if (caps.length) {
const tagRow = document.createElement("div");
tagRow.style.cssText = "display:flex;flex-wrap:wrap;gap:4px";
caps.forEach((c) => {
const t = document.createElement("span");
t.textContent = String(c);
t.style.cssText = "font-size:9.5px;padding:2px 6px;border-radius:5px;" +
"background:#12202b;border:1px solid #1b2734;color:" + C.text;
tagRow.appendChild(t);
});
capWrap.appendChild(tagRow);
} else {
const none = document.createElement("div");
none.textContent = "— none in feed —";
none.style.cssText = "color:#6c7a86;font-style:italic";
capWrap.appendChild(none);
}
_panel.appendChild(capWrap);
// models (honest: only what JSON carries)
const models = Array.isArray(node.models) ? node.models : [];
const mWrap = document.createElement("div");
mWrap.style.cssText = "margin-top:8px";
const mH = document.createElement("div");
mH.textContent = "models (" + models.length + ")";
mH.style.cssText = "color:" + C.para + ";margin-bottom:4px";
mWrap.appendChild(mH);
if (models.length) {
models.slice(0, 12).forEach((mdl) => {
const li = document.createElement("div");
li.textContent = "• " + (typeof mdl === "string" ? mdl : (mdl && mdl.id) || JSON.stringify(mdl));
li.style.cssText = "color:" + C.text + ";margin:2px 0;word-break:break-all";
mWrap.appendChild(li);
});
if (models.length > 12) {
const more = document.createElement("div");
more.textContent = "… +" + (models.length - 12) + " more";
more.style.color = "#6c7a86";
mWrap.appendChild(more);
}
} else {
const none = document.createElement("div");
none.textContent = "— none in feed (model list not exposed by this node) —";
none.style.cssText = "color:#6c7a86;font-style:italic";
mWrap.appendChild(none);
}
_panel.appendChild(mWrap);
if (node.detail) {
const d = document.createElement("div");
d.textContent = node.detail;
d.style.cssText = "margin-top:8px;color:#6c7a86;line-height:1.5";
_panel.appendChild(d);
}
const chipWrap = document.createElement("div");
chipWrap.style.cssText = "margin-top:9px";
chipWrap.appendChild(_ctx.label.chip("STRUCTURAL-ONLY", { text: "topology" }));
_panel.appendChild(chipWrap);
}
// ----------------------------------------------------------------------------
// 3D mesh construction
// ----------------------------------------------------------------------------
function _clearMesh() {
if (_root && _stage) _stage.scene.remove(_root);
_root = null; _nodeMeshes = []; _edges = [];
_hubMesh = null; _healthRing = null; _healthFill = null;
}
function _makeGlowSprite(THREE, hex) {
const cnv = document.createElement("canvas");
cnv.width = cnv.height = 128;
const g = cnv.getContext("2d");
const col = "#" + hex.toString(16).padStart(6, "0");
const grad = g.createRadialGradient(64, 64, 4, 64, 64, 64);
grad.addColorStop(0, col);
grad.addColorStop(0.25, col);
grad.addColorStop(1, "rgba(0,0,0,0)");
g.globalAlpha = 0.9; g.fillStyle = grad; g.beginPath();
g.arc(64, 64, 64, 0, Math.PI * 2); g.fill();
const tex = new THREE.CanvasTexture(cnv);
if ("colorSpace" in tex && THREE.SRGBColorSpace) tex.colorSpace = THREE.SRGBColorSpace;
const mat = new THREE.SpriteMaterial({ map: tex, transparent: true, blending: THREE.AdditiveBlending, depthWrite: false });
return new THREE.Sprite(mat);
}
function _nameSprite(THREE, text, hex) {
const fs = 40, pad = 14;
const cnv = document.createElement("canvas");
const g = cnv.getContext("2d");
g.font = "600 " + fs + "px ui-monospace,Menlo,monospace";
const w = Math.ceil(g.measureText(text).width) + pad * 2;
const h = fs + pad * 2;
cnv.width = w; cnv.height = h;
g.font = "600 " + fs + "px ui-monospace,Menlo,monospace";
g.fillStyle = "rgba(8,16,26,0.72)";
g.fillRect(0, 0, w, h);
g.fillStyle = "#" + hex.toString(16).padStart(6, "0");
g.textBaseline = "middle"; g.fillText(text, pad, h / 2 + 2);
const tex = new THREE.CanvasTexture(cnv);
if ("colorSpace" in tex && THREE.SRGBColorSpace) tex.colorSpace = THREE.SRGBColorSpace;
const mat = new THREE.SpriteMaterial({ map: tex, transparent: true, depthTest: false });
const sp = new THREE.Sprite(mat);
const sh = 0.5;
sp.scale.set(sh * (w / h), sh, 1);
return sp;
}
function _buildMesh(json) {
const THREE = _THREE;
_clearMesh();
_root = new THREE.Group();
_stage.scene.add(_root);
const nodes = Array.isArray(json.nodes) ? json.nodes : [];
const n = nodes.length;
// central fabric hub
const hubGeo = new THREE.IcosahedronGeometry(1.05, 1);
const hubMat = new THREE.MeshStandardMaterial({
color: C.hub, emissive: C.gpu, emissiveIntensity: 0.25,
metalness: 0.6, roughness: 0.3, wireframe: true, transparent: true, opacity: 0.55,
});
_hubMesh = new THREE.Mesh(hubGeo, hubMat);
_root.add(_hubMesh);
// fabric-health ring (6/6) around the hub — torus whose arc-fill we color by
// reachable/total. Built as two tori: a dim full ring + a bright reachable arc.
const ringBase = new THREE.Mesh(
new THREE.TorusGeometry(2.0, 0.045, 8, 96),
new THREE.MeshBasicMaterial({ color: 0x223240, transparent: true, opacity: 0.8 })
);
ringBase.rotation.x = Math.PI / 2;
_root.add(ringBase);
_healthRing = ringBase;
// positions (deterministic + light relax)
const positions = nodes.map((nd, i) => _seedPos(nd.name || ("node" + i), i, n));
_relax(positions, 18);
// edges hub<->node (the fabric mesh spokes) — bandwidth-style tubes
nodes.forEach((nd, i) => {
const p = positions[i];
const reachable = !!nd.reachable;
const hex = reachable ? C.edgeHot : C.edge;
const pts = [new THREE.Vector3(0, 0, 0), new THREE.Vector3(p[0], p[1], p[2])];
const curve = new THREE.CatmullRomCurve3([
pts[0],
new THREE.Vector3(p[0] * 0.4, p[1] * 0.4 + 0.6, p[2] * 0.4),
pts[1],
]);
const tubeGeo = new THREE.TubeGeometry(curve, 20, reachable ? 0.05 : 0.025, 6, false);
const tubeMat = new THREE.MeshBasicMaterial({
color: hex, transparent: true, opacity: reachable ? 0.55 : 0.2,
blending: THREE.AdditiveBlending, depthWrite: false,
});
const line = new THREE.Mesh(tubeGeo, tubeMat);
_root.add(line);
_edges.push({ line, hot: reachable, idx: i });
});
// node cards (instanced look via per-node box) + glow + reachability ring + model orbit
nodes.forEach((nd, i) => {
const p = positions[i];
const color = _nodeColor(nd);
const grp = new THREE.Group();
grp.position.set(p[0], p[1], p[2]);
// GPU nodes get a chunkier "card"; hosted get a slimmer chip.
const gpu = _isGpu(nd.kind);
const size = gpu ? 0.62 : 0.46;
const coreGeo = gpu
? new THREE.BoxGeometry(size, size * 0.7, size * 0.18)
: new THREE.OctahedronGeometry(size * 0.62, 0);
const coreMat = new THREE.MeshStandardMaterial({
color, emissive: color, emissiveIntensity: nd.reachable ? 0.7 : 0.15,
metalness: 0.5, roughness: 0.35,
});
const core = new THREE.Mesh(coreGeo, coreMat);
core.userData.fabricNodeIdx = i;
grp.add(core);
// reachability glow (additive sprite) — only bright when reachable
const glow = _makeGlowSprite(THREE, color);
glow.scale.set(2.0, 2.0, 1);
glow.material.opacity = nd.reachable ? 0.85 : 0.18;
grp.add(glow);
// unreachable nodes get a red warning ring
let ring = null;
if (!nd.reachable) {
ring = new THREE.Mesh(
new THREE.TorusGeometry(size * 0.95, 0.03, 6, 32),
new THREE.MeshBasicMaterial({ color: C.unreachable, transparent: true, opacity: 0.8 })
);
grp.add(ring);
}
// per-node model-list orbit: one small bead per model, ringing the node.
const models = Array.isArray(nd.models) ? nd.models : [];
const orbit = [];
const orbitGrp = new THREE.Group();
const mCount = Math.min(models.length, 16);
for (let k = 0; k < mCount; k++) {
const a = (k / Math.max(1, mCount)) * Math.PI * 2;
const rr = size + 0.45;
const bead = new THREE.Mesh(
new THREE.SphereGeometry(0.06, 8, 8),
new THREE.MeshBasicMaterial({ color: 0xeef3f6, transparent: true, opacity: 0.85 })
);
bead.position.set(Math.cos(a) * rr, 0, Math.sin(a) * rr);
orbitGrp.add(bead); orbit.push(bead);
}
grp.add(orbitGrp);
// capability-count tag + name
const nameTag = _nameSprite(THREE, nd.name || ("node" + i), color);
nameTag.position.set(0, size + 0.55, 0);
grp.add(nameTag);
_root.add(grp);
_nodeMeshes.push({
data: nd, group: grp, core, glow, ring, orbit, orbitGrp, nameTag,
basePos: [p[0], p[1], p[2]], gpu, color, phase: (_hash(nd.name || "x") % 100) / 100,
});
});
// chaski 2nd-lung indicator: if a node named chaski is present + reachable, draw
// a soft "breathing" secondary ring (the founder-tailnet GPU = the 2nd lung).
const chaski = _nodeMeshes.find((m) => /chaski/i.test(m.data.name || ""));
if (chaski) {
const lung = new THREE.Mesh(
new THREE.TorusGeometry(0.95, 0.02, 6, 40),
new THREE.MeshBasicMaterial({
color: chaski.data.reachable ? C.gpu : 0x55606a,
transparent: true, opacity: 0.7, blending: THREE.AdditiveBlending, depthWrite: false,
})
);
lung.rotation.x = Math.PI / 2;
chaski.group.add(lung);
chaski.lung = lung;
}
}
// ----------------------------------------------------------------------------
// HUD update from live JSON
// ----------------------------------------------------------------------------
function _deriveSovereignGpuLive(json) {
// Prefer the JSON's own count; else derive honestly from nodes[].
const c = json.counts || {};
if (typeof c.sovereign_gpu_live === "number") return c.sovereign_gpu_live;
const nodes = Array.isArray(json.nodes) ? json.nodes : [];
return nodes.filter((nd) => nd.sovereign && _isGpu(nd.kind) && nd.reachable).length;
}
function _updateHud(json, meta) {
const c = (json && json.counts) || {};
const nodes = Array.isArray(json && json.nodes) ? json.nodes : [];
const total = typeof c.nodes_total === "number" ? c.nodes_total : nodes.length;
const reach = typeof c.nodes_reachable === "number"
? c.nodes_reachable : nodes.filter((n) => n.reachable).length;
const gpu = typeof c.gpu_nodes_reachable === "number"
? c.gpu_nodes_reachable : nodes.filter((n) => n.reachable && _isGpu(n.kind)).length;
const sovGpu = _deriveSovereignGpuLive(json);
if (_hud.v_health) _hud.v_health.textContent = reach + "/" + total + " online";
if (_hud.v_reach) _hud.v_reach.textContent = String(reach);
if (_hud.v_gpu) _hud.v_gpu.textContent = String(gpu);
if (_hud.v_sov) {
_hud.v_sov.textContent = String(sovGpu);
_hud.v_sov.style.color = sovGpu > 0 ? "#e8c074" : C.para;
}
const chaski = nodes.find((n) => /chaski/i.test(n.name || ""));
if (_hud.v_chaski) {
_hud.v_chaski.textContent = chaski
? (chaski.reachable ? "BREATHING" : "down") : "absent";
_hud.v_chaski.style.color = chaski && chaski.reachable ? "#39d3c4" : C.para;
}
if (_hud.v_label) {
// reach counts come from a live TCP probe — that IS measured.
_hud.v_label.textContent = "MEASURED (live TCP)";
_hud.v_label.style.color = "#2fd07a";
}
// update health ring fill: scale arc opacity by reachable fraction
if (_healthRing) {
const frac = total > 0 ? reach / total : 0;
_healthRing.material.color.setHex(frac >= 1 ? C.gpu : (frac > 0 ? C.sovereign : C.unreachable));
_healthRing.material.opacity = 0.35 + 0.5 * frac;
}
}
// ----------------------------------------------------------------------------
// Degraded / missing handling
// ----------------------------------------------------------------------------
function _showDegraded(meta) {
// keep last good mesh if we have one; just annotate the HUD honestly
if (_hud.v_health) {
if (meta.state === "missing") _hud.v_health.textContent = "NO-LIVE-DATA";
else if (meta.state === "error") _hud.v_health.textContent = "OFFLINE";
else if (meta.state === "degraded") _hud.v_health.textContent = "DEGRADED";
}
if (!_lastJson && !_nodeMeshes.length) {
// never had data — render an honest placeholder hub so the tab isn't empty.
if (!_root) {
const THREE = _THREE;
_root = new THREE.Group(); _stage.scene.add(_root);
const m = new THREE.Mesh(
new THREE.IcosahedronGeometry(2.2, 1),
new THREE.MeshStandardMaterial({ color: C.hosted, emissive: C.hosted, emissiveIntensity: 0.2, wireframe: true })
);
_root.add(m); _hubMesh = m;
try {
const bb = _ctx.label.billboard(THREE, "STRUCTURAL-ONLY", { text: "compute-pool · awaiting live data", scale: 0.6, position: [0, 3, 0] });
_root.add(bb);
} catch (_) {}
}
}
}
// ----------------------------------------------------------------------------
// Raycast click -> select node -> detail panel
// ----------------------------------------------------------------------------
function _select(idx) {
_selected = idx;
_nodeMeshes.forEach((m, i) => {
const on = i === idx;
if (m.core && m.core.material) {
m.core.material.emissiveIntensity = on ? 1.4 : (m.data.reachable ? 0.7 : 0.15);
}
});
_renderPanel(idx == null ? null : _nodeMeshes[idx] && _nodeMeshes[idx].data);
}
function _setupPicking() {
const THREE = _THREE;
_ray = new THREE.Raycaster();
_pointer = new THREE.Vector2();
_domEl = _stage.renderer && _stage.renderer.domElement;
if (!_domEl) return;
let downX = 0, downY = 0;
_onMove = (e) => { /* reserved for hover; kept light */ };
const _onDown = (e) => { downX = e.clientX; downY = e.clientY; };
_onClick = (e) => {
// ignore drags (orbit controls)
if (Math.abs(e.clientX - downX) > 4 || Math.abs(e.clientY - downY) > 4) return;
const rect = _domEl.getBoundingClientRect();
_pointer.x = ((e.clientX - rect.left) / rect.width) * 2 - 1;
_pointer.y = -((e.clientY - rect.top) / rect.height) * 2 + 1;
_ray.setFromCamera(_pointer, _stage.camera);
const cores = _nodeMeshes.map((m) => m.core).filter(Boolean);
const hits = _ray.intersectObjects(cores, false);
if (hits.length) {
const idx = hits[0].object.userData.fabricNodeIdx;
_select(idx === _selected ? null : idx);
} else {
_select(null);
}
};
_domEl.addEventListener("mousedown", _onDown);
_domEl.addEventListener("click", _onClick);
_domEl._szlFabricDown = _onDown; // for cleanup
}
// ----------------------------------------------------------------------------
// Per-frame animation: slow rotate, GPU-live pulse, model-orbit spin,
// bandwidth-tube shimmer, chaski lung breathing, hub spin.
// ----------------------------------------------------------------------------
function _frame() {
_t += 0.016;
if (_root) _root.rotation.y += 0.0018;
if (_hubMesh) { _hubMesh.rotation.y -= 0.004; _hubMesh.rotation.x += 0.0012; }
_nodeMeshes.forEach((m) => {
// GPU-live pulse: reachable GPU nodes breathe in emissive + glow.
if (m.gpu && m.data.reachable && m.core && m.core.material) {
const pulse = 0.7 + 0.5 * (0.5 + 0.5 * Math.sin(_t * 2.2 + m.phase * 6.28));
if (_selected == null || _nodeMeshes[_selected] !== m) m.core.material.emissiveIntensity = pulse;
if (m.glow) m.glow.material.opacity = 0.6 + 0.35 * (0.5 + 0.5 * Math.sin(_t * 2.2 + m.phase * 6.28));
}
// model orbit spin
if (m.orbitGrp) m.orbitGrp.rotation.y += m.gpu ? 0.012 : 0.006;
// unreachable ring slow pulse
if (m.ring) m.ring.material.opacity = 0.4 + 0.4 * (0.5 + 0.5 * Math.sin(_t * 3));
// chaski lung breathing
if (m.lung) {
const b = 0.85 + 0.25 * (0.5 + 0.5 * Math.sin(_t * 1.3));
m.lung.scale.set(b, b, b);
m.lung.material.opacity = 0.4 + 0.4 * (0.5 + 0.5 * Math.sin(_t * 1.3));
}
});
// bandwidth-tube shimmer: animate opacity of reachable spokes
_edges.forEach((e, i) => {
if (e.hot && e.line && e.line.material) {
e.line.material.opacity = 0.35 + 0.3 * (0.5 + 0.5 * Math.sin(_t * 3 + i));
}
});
}
// ----------------------------------------------------------------------------
// mount / unmount
// ----------------------------------------------------------------------------
function mount(ctx) {
_ctx = ctx; _stage = ctx.stage; _THREE = ctx.THREE;
_t = 0; _selected = null; _lastJson = null; _hud = {};
const built = _buildOverlay();
_overlay = built.ov;
(ctx.container || document.body).appendChild(_overlay);
_panel = _buildPanel();
(ctx.container || document.body).appendChild(_panel);
// enable bloom for the holographic node glow (safe no-op on WebGPU per toolkit).
try { if (_stage.setBloom) _stage.setBloom(true); } catch (_) {}
_frameCb = _frame;
_stage.onFrame(_frameCb);
_setupPicking();
_handle = ctx.live.poll(ENDPOINT, 5000, (json, meta) => {
_lastMeta = meta;
if (meta.state === "live" || meta.state === "degraded") {
_lastJson = json;
_buildMesh(json); // rebuild from the latest real probe
_setupPicking(); // re-bind cores (mesh was rebuilt)
_updateHud(json, meta);
if (meta.state === "degraded") _showDegraded(meta);
// re-render panel if a node is selected and still present
if (_selected != null && _nodeMeshes[_selected]) _renderPanel(_nodeMeshes[_selected].data);
else _select(null);
} else {
_showDegraded(meta);
}
}, { badge: built.badge, onState: (meta) => { if (meta.state !== "live" && meta.state !== "degraded") _showDegraded(meta); } });
return { id: ID, started: true };
}
function unmount() {
try { if (_handle) _handle.stop(); } catch (_) {}
try {
if (_domEl) {
if (_onClick) _domEl.removeEventListener("click", _onClick);
if (_domEl._szlFabricDown) _domEl.removeEventListener("mousedown", _domEl._szlFabricDown);
_domEl._szlFabricDown = null;
}
} catch (_) {}
try { _clearMesh(); } catch (_) {}
try { if (_overlay && _overlay.parentNode) _overlay.parentNode.removeChild(_overlay); } catch (_) {}
try { if (_panel && _panel.parentNode) _panel.parentNode.removeChild(_panel); } catch (_) {}
_handle = null; _overlay = null; _panel = null; _detailChip = null;
_nodeMeshes = []; _edges = []; _root = null; _hubMesh = null;
_healthRing = null; _healthFill = null; _frameCb = null; _ray = null;
_pointer = null; _onClick = null; _onMove = null; _domEl = null;
_ctx = null; _stage = null; _THREE = null; _lastJson = null; _selected = null;
}
export default { id: ID, title: TITLE, endpoints: [ENDPOINT], mount, unmount };