elidedb-qbe / python /elidedb /desk_ui.html
SudharshanR
ElideDB query by example: no text, no model at query time
a1dd5ba
Raw
History Blame Contribute Delete
101 kB
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>ElideDB</title>
<style>
/* ElideDB console: a precision instrument, not a demo.
Monospace-forward identity, paper and graphite surfaces, one
working accent. Chart hues are the validated categorical set. */
:root {
--ground:#f3f2ee; --panel:#fcfbf9; --panel-2:#eceae4; --rail:#eae8e2;
--ink:#191d21; --muted:#565e66; --faint:#8a9098;
--line:#d8d5cd; --hairline:#e5e2da; --grid:#e9e6df;
--accent:#0f6f63; --accent-ink:#0b5c52; --accent-soft:rgba(15,111,99,.12);
--signal:#b4500f; --code-bg:#efede7;
--shadow:0 14px 40px rgba(24,28,32,.14);
}
@media (prefers-color-scheme: dark) { :root {
--ground:#131518; --panel:#1a1d21; --panel-2:#22262b; --rail:#0e1013;
--ink:#e7e9ea; --muted:#9aa3ab; --faint:#697077;
--line:#2c3238; --hairline:#24292e; --grid:#22272c;
--accent:#3fb9a5; --accent-ink:#5accb9; --accent-soft:rgba(63,185,165,.14);
--signal:#e8763d; --code-bg:#101317;
--shadow:0 18px 48px rgba(0,0,0,.55);
}}
* { box-sizing:border-box; }
html,body { margin:0; height:100%; }
body {
display:flex; background:var(--ground); color:var(--ink);
font:13px/1.55 ui-monospace, "SF Mono", Menlo, Consolas, monospace;
overflow:hidden;
-webkit-font-smoothing:antialiased;
}
.tnum { font-variant-numeric:tabular-nums; }
::selection { background:var(--accent-soft); }
/* micro label: the one recurring signature */
.lbl { font-size:9.5px; letter-spacing:.16em; text-transform:uppercase;
color:var(--faint); font-weight:600; }
/* left rail */
aside {
width:252px; flex:none; background:var(--rail);
border-right:1px solid var(--line);
display:flex; flex-direction:column;
}
.brand { padding:18px 16px 14px; border-bottom:1px solid var(--line); }
.brand b { letter-spacing:.22em; font-size:13px; font-weight:700; }
.brand b i { font-style:normal; color:var(--accent); }
.brand .sub { color:var(--faint); font-size:10px; margin-top:3px;
letter-spacing:.05em; }
.rail-h { padding:14px 16px 6px; }
.stores { flex:1; overflow-y:auto; padding:4px 10px 10px; }
.store-card {
padding:10px 12px; border-radius:6px; cursor:pointer;
border:1px solid transparent; margin-bottom:5px;
}
.store-card:hover { background:var(--panel); }
.store-card.on { background:var(--panel); border-color:var(--line);
box-shadow:inset 3px 0 0 var(--accent); }
.store-card .n { font-weight:700; font-size:12.5px; letter-spacing:.02em; }
.store-card .m { color:var(--faint); font-size:10.5px; margin-top:3px; }
.railfoot { padding:12px 16px; color:var(--faint); font-size:10px;
border-top:1px solid var(--line); line-height:1.7; }
/* main column */
.main { flex:1; display:flex; flex-direction:column; min-width:0; }
.topbar {
display:flex; align-items:center; gap:18px; padding:0 22px;
border-bottom:1px solid var(--line); background:var(--ground);
min-height:52px; flex-wrap:wrap;
}
.topbar h1 { font-size:14px; margin:0; font-weight:700;
letter-spacing:.03em; }
nav#views { display:flex; gap:2px; align-self:stretch; }
nav#views button {
border:0; background:transparent; color:var(--muted); cursor:pointer;
font:600 10.5px/1 ui-monospace, Menlo, monospace;
letter-spacing:.14em; padding:0 13px; border-bottom:2px solid transparent;
text-transform:uppercase;
}
nav#views button:hover { color:var(--ink); }
nav#views button.on { color:var(--ink); border-bottom-color:var(--accent); }
nav#views button:focus-visible { outline:2px solid var(--accent); }
.topstat { margin-left:auto; color:var(--faint); font-size:11px; }
.content { flex:1; overflow-y:auto; padding:22px 24px 40px; }
.view { display:none; } .view.on { display:block; }
/* stat tiles */
.tiles { display:grid; grid-template-columns:repeat(auto-fit,minmax(150px,1fr));
gap:10px; margin-bottom:18px; }
.tile { background:var(--panel); border:1px solid var(--line);
border-radius:6px; padding:12px 14px 10px; }
.tile .k { font-size:9.5px; letter-spacing:.16em; text-transform:uppercase;
color:var(--faint); font-weight:600; margin-bottom:6px; }
.tile .v { font-size:21px; font-weight:700; letter-spacing:-.01em; }
.tile .v small { font-size:11px; color:var(--muted); font-weight:500; }
.tile .d { font-size:10.5px; color:var(--muted); margin-top:3px; }
.tile.hero { border-color:var(--accent); }
.tile.hero .v { color:var(--accent-ink); }
/* panels: engineering sheet header, hairline body */
.panel { background:var(--panel); border:1px solid var(--line);
border-radius:6px; padding:0; margin-bottom:16px; overflow:hidden; }
.panel > .hd { display:flex; align-items:baseline; gap:12px;
padding:11px 16px 9px; border-bottom:1px solid var(--hairline); }
.panel > .hd h2 { margin:0; font-size:11px; letter-spacing:.16em;
text-transform:uppercase; font-weight:700; }
.panel > .hd .note { color:var(--faint); font-size:10.5px; }
.panel > .bd { padding:14px 16px 16px; }
table { border-collapse:collapse; width:100%; font-size:12px; }
th { text-align:left; font-size:9.5px; letter-spacing:.14em;
text-transform:uppercase; color:var(--faint); font-weight:600;
padding:5px 14px 5px 0; border-bottom:1px solid var(--line); }
td { padding:5.5px 14px 5.5px 0; border-bottom:1px solid var(--grid);
color:var(--muted); }
td:first-child { color:var(--ink); }
td.r,th.r { text-align:right; }
tr:last-child td { border-bottom:0; }
.tablewrap { overflow-x:auto; }
.badge { display:inline-block; font-size:9px; padding:1px 7px;
border-radius:3px; border:1px solid var(--line);
color:var(--muted); letter-spacing:.08em; text-transform:uppercase; }
.pill { font-size:9.5px; padding:1.5px 8px; border-radius:3px;
border:1px solid var(--line); color:var(--muted); }
.pill.ok { color:var(--accent-ink); border-color:var(--accent); }
.pill.warn { color:var(--signal); border-color:var(--signal); }
/* charts */
.chart-tip { position:fixed; z-index:60; pointer-events:none; display:none;
background:var(--panel); border:1px solid var(--line); border-radius:4px;
box-shadow:var(--shadow); padding:6px 9px; font-size:10.5px;
color:var(--muted); max-width:280px; }
.chart-tip b { color:var(--ink); display:block; font-size:11px; }
.bar-row { display:grid; grid-template-columns:170px 1fr 92px; gap:12px;
align-items:center; padding:3px 0; }
.bar-row .id { font-size:11.5px; overflow:hidden; text-overflow:ellipsis;
white-space:nowrap; }
.bar-track { height:14px; background:var(--panel-2); border-radius:3px;
position:relative; }
.bar-fill { position:absolute; top:2px; bottom:2px; left:0;
background:var(--accent); border-radius:2px; min-width:2px; }
.bar-fill.dim { opacity:.35; }
.bar-val { font-size:10.5px; color:var(--faint); text-align:right; }
.heat-row { display:grid; grid-template-columns:170px 1fr 92px; gap:12px;
align-items:center; padding:2.5px 0; }
.heat-strip { display:flex; height:13px; border-radius:3px; overflow:hidden;
background:var(--panel-2); }
.heat-cell { flex:1; }
.axis { display:flex; justify-content:space-between; color:var(--faint);
font-size:9.5px; margin-top:6px; }
.axis.indent { padding-left:182px; padding-right:104px; }
/* timeline */
.tl-bar { position:absolute; top:2px; bottom:2px; border-radius:2px;
min-width:3px; }
/* forms */
.seg { display:inline-flex; gap:2px; background:var(--panel-2);
padding:3px; border-radius:5px; flex-wrap:wrap; }
.seg button { border:0; background:transparent; color:var(--muted);
cursor:pointer; font:600 10.5px/1 ui-monospace, Menlo, monospace;
letter-spacing:.08em; padding:6px 12px; border-radius:3px; }
.seg button.on { background:var(--panel); color:var(--ink);
box-shadow:0 1px 2px rgba(0,0,0,.14); }
textarea,input[type=text] {
width:100%; background:var(--code-bg); color:var(--ink);
border:1px solid var(--line); border-radius:5px; padding:10px 12px;
font:12.5px/1.5 ui-monospace, Menlo, monospace; resize:vertical;
}
textarea:focus,input:focus,select:focus { outline:2px solid var(--accent);
border-color:transparent; }
select,input[type=number] { background:var(--code-bg); color:var(--ink);
border:1px solid var(--line); border-radius:4px; padding:6px 8px;
font:11.5px ui-monospace, Menlo, monospace; }
.hint { color:var(--faint); font-size:10.5px; margin:7px 2px 0;
line-height:1.6; }
.ctrl { display:flex; flex-wrap:wrap; gap:14px; margin-top:12px;
align-items:center; }
.ctrl label { display:flex; align-items:center; gap:6px; font-size:10.5px;
color:var(--muted); font-weight:600; letter-spacing:.04em;
text-transform:uppercase; }
.ctrl input[type=number] { width:70px; }
.runrow { display:flex; gap:12px; align-items:center; margin-top:14px; }
button.run { background:var(--accent); color:#fff; border:0;
border-radius:5px; font:700 11px/1 ui-monospace, Menlo, monospace;
letter-spacing:.14em; text-transform:uppercase; padding:10px 22px;
cursor:pointer; }
button.run:hover { filter:brightness(1.07); }
.btn { background:var(--panel-2); border:1px solid var(--line);
color:var(--ink); border-radius:4px; padding:6px 13px; cursor:pointer;
font:600 11px ui-monospace, Menlo, monospace; }
.btn:hover { border-color:var(--accent); }
.btn.danger { color:var(--signal); }
.btn.danger:hover { border-color:var(--signal); }
.btn:disabled { opacity:.5; cursor:default; }
.qstat { color:var(--faint); font-size:11px; }
.err { color:var(--signal); font-size:11.5px; margin-top:10px;
white-space:pre-wrap; }
.empty { color:var(--faint); padding:36px; text-align:center;
font-size:11.5px; }
/* result grid */
.hitgrid { display:grid; grid-template-columns:repeat(auto-fill,minmax(200px,1fr));
gap:12px; margin-top:14px; }
.hit { background:var(--panel-2); border-radius:5px; overflow:hidden;
border:1px solid var(--line); cursor:pointer; position:relative; }
.hit img { width:100%; aspect-ratio:4/3; object-fit:cover; display:block;
background:var(--grid); }
.hit .m { padding:7px 10px; font-size:10.5px; color:var(--muted); }
.hit .m b { color:var(--ink); }
.hit .play { position:absolute; inset:0; display:flex; align-items:center;
justify-content:center; aspect-ratio:4/3; opacity:0; transition:opacity .12s;
pointer-events:none; }
.hit:hover .play { opacity:1; }
.hit .play span { width:42px; height:42px; border-radius:50%;
background:rgba(12,16,20,.68); display:flex; align-items:center;
justify-content:center; }
.hit .play svg { width:15px; height:15px; margin-left:2px; fill:#fff; }
/* index and maintenance rows */
.ixrow { display:flex; align-items:center; gap:12px; padding:8px 0;
border-bottom:1px solid var(--grid); font-size:12px; }
.ixrow:last-child { border-bottom:0; }
.ixrow .grow { flex:1; }
/* map */
.mapgrid { display:grid; grid-template-columns:1fr 230px; gap:16px; }
.canvasbox { position:relative; }
canvas.viz { width:100%; display:block; border-radius:5px;
background:var(--panel-2); cursor:crosshair; }
.legend { font-size:11.5px; }
.legend h3 { font-size:9.5px; letter-spacing:.16em; text-transform:uppercase;
color:var(--faint); margin:0 0 6px; font-weight:600; }
.legend .li { display:flex; align-items:center; gap:7px; padding:2px 0;
color:var(--muted); }
.legend .li i { width:9px; height:9px; border-radius:50%; flex:none; }
.legend .li.noise i { background:transparent;
border:1.5px solid var(--faint); }
.legend .cnt { margin-left:auto; color:var(--faint); }
.hovercard { position:absolute; z-index:20; pointer-events:none; width:190px;
background:var(--panel); border:1px solid var(--line); border-radius:6px;
box-shadow:var(--shadow); overflow:hidden; display:none; }
.hovercard .ph { width:190px; height:120px; background:var(--panel-2);
display:flex; align-items:center; justify-content:center;
color:var(--faint); font-size:10.5px; }
.hovercard img { width:100%; display:block; }
.hovercard .m { padding:7px 10px; font-size:10.5px; color:var(--muted); }
.hovercard .m b { color:var(--ink); display:block; font-size:11px; }
/* player */
.player-back { position:fixed; inset:0; background:rgba(8,10,13,.72);
z-index:100; display:none; align-items:center; justify-content:center;
backdrop-filter:blur(3px); }
.player-back.on { display:flex; }
.player { width:min(760px, 92vw); background:var(--panel);
border:1px solid var(--line); border-radius:8px; box-shadow:var(--shadow);
overflow:hidden; }
.player video { width:100%; display:block; background:#000;
min-height:280px; }
.player .loading { height:340px; display:flex; flex-direction:column;
align-items:center; justify-content:center; color:var(--faint);
font-size:12px; gap:10px; }
.spin { width:16px; height:16px; border:2px solid var(--line);
border-top-color:var(--accent); border-radius:50%;
animation:spin .8s linear infinite; }
@keyframes spin { to { transform:rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .spin { animation:none; } }
.player .bar { display:flex; align-items:center; gap:12px;
padding:10px 14px; }
.player .bar b { font-size:12px; }
.player .bar .t { color:var(--faint); font-size:11px; }
.player .bar button { margin-left:auto; background:var(--panel-2);
border:1px solid var(--line); color:var(--muted); border-radius:4px;
padding:6px 12px; cursor:pointer; font-size:11px; }
.player .bar button + button { margin-left:0; }
.player .bar button:hover { color:var(--ink); }
</style>
</head>
<body>
<aside>
<div class="brand"><b>ELIDE<i>DB</i></b>
<div class="sub">timestamp-native multimodal store</div></div>
<div class="rail-h lbl">Stores</div>
<div class="stores" id="stores"></div>
<div class="railfoot">Parquet tables under a transaction log.<br>
Reads are byte-range and counted.</div>
</aside>
<div class="main">
<div class="topbar">
<h1 id="store-title"></h1>
<nav id="views" role="tablist">
<button data-v="overview" class="on">Overview</button>
<button data-v="analytics">Analytics</button>
<button data-v="search">Search</button>
<button data-v="data">Data &amp; Storage</button>
<button data-v="arch">Architecture</button>
<button data-v="map">Map</button>
<button data-v="geo" id="geo-btn" style="display:none">Geo</button>
<button data-v="ops">Ops</button>
</nav>
<span class="topstat tnum" id="store-sub"></span>
</div>
<div class="content">
<div class="view on" id="v-overview"></div>
<div class="view" id="v-analytics"></div>
<div class="view" id="v-search">
<div class="panel">
<div class="hd"><h2>Search</h2>
<span class="note">every result is a playable clip</span></div>
<div class="bd">
<div class="seg" id="qmodes">
<button data-q="set" class="on">Event</button>
<button data-q="predicate">Predicate</button>
<button data-q="sql">SQL</button>
<button data-q="window">Window</button>
</div>
<div id="q-set" style="margin-top:12px">
<input type="text" id="set-input" placeholder="Describe an event">
<div class="hint">
Returns up to K clips and only clips the index is confident in;
a query the corpus cannot answer returns nothing. Scores fuse
every channel this store carries.
</div>
<div class="ctrl">
<label>Max results
<input type="number" id="set-k" value="10" min="1" max="24"></label>
<label title="Verify each candidate with the geometry tracker: the named objects must be present, move, and satisfy the stated relation. Slower.">
<input type="checkbox" id="set-audit"> Geometry audit</label>
<label>Stream <select id="set-stream"><option value="">any</option></select></label>
<label>From s <input type="number" id="set-t0"></label>
<label>To s <input type="number" id="set-t1"></label>
</div>
</div>
<div id="q-predicate" style="display:none; margin-top:12px">
<div class="ctrl" style="margin-top:0">
<label>Table <select id="pred-table"></select></label>
<label>Column <select id="pred-col"></select></label>
<label>Op <select id="pred-op">
<option value=">=">&ge;</option><option value="<=">&le;</option>
<option value="==">=</option><option value="between">between</option>
</select></label>
<label>Value <input type="number" step="any" id="pred-val" style="width:110px"></label>
<label id="pred-val2-wrap" style="display:none">and
<input type="number" step="any" id="pred-val2" style="width:110px"></label>
</div>
<div class="hint">Filter rows by a numeric column. The result
reports how many files and bytes the scan touched versus
skipped.</div>
</div>
<div id="q-sql" style="display:none; margin-top:12px">
<textarea id="sql-input" rows="4"></textarea>
<div class="hint">Read-only SQL over every table in this store.</div>
</div>
<div id="q-window" style="display:none; margin-top:12px">
<input type="text" id="win-input"
placeholder="start,end in seconds from capture start">
<div class="hint">Retrieve one aligned time window across every
table: frames as playable streams, sensors as rows.</div>
</div>
<div class="runrow">
<button class="run" id="run">Run</button>
<span class="qstat" id="q-stat"></span>
</div>
<div id="q-out"></div>
</div>
</div>
</div>
<div class="view" id="v-data"></div>
<div class="view" id="v-storage">
<div class="panel">
<div class="hd"><h2>Storage</h2>
<span class="note">transaction log and physical file layout,
read from the Parquet footers</span></div>
<div class="bd">
<div class="seg" id="storage-tables"></div>
<div id="storage-out"></div>
</div>
</div>
</div>
<div class="view" id="v-arch">
<div class="seg" id="arch-seg">
<button data-p="db" class="on">Database engine</button>
<button data-p="model">Retrieval model</button>
</div>
<div id="arch-pane-db"></div>
<div id="arch-pane-model" style="display:none">
<div id="arch-wrap">
<svg id="arch-svg"><g id="arch-cam"></g></svg>
<div id="arch-title"></div>
<div id="arch-detail"></div>
<div id="arch-hint">drag to pan · wheel to zoom · click a block
for its schema · double click resets</div>
</div>
</div>
</div>
<div class="view" id="v-map">
<div class="panel">
<div class="hd"><h2>Embedding map</h2>
<span class="note">2D layout for browsing only; retrieval ranks
in the full vector space<span id="map-src"></span></span></div>
<div class="bd">
<div class="mapgrid">
<div class="canvasbox">
<canvas id="scatter" class="viz" height="470"></canvas>
<div class="hovercard" id="card">
<div class="ph">decoding</div><div class="m"></div></div>
</div>
<div class="legend" id="legend"></div>
</div>
</div>
</div>
</div>
<div class="view" id="v-geo">
<div class="panel">
<div class="hd"><h2>Geo trace</h2>
<span class="note" id="geo-note"></span></div>
<div class="bd">
<canvas id="route" class="viz" height="420" style="cursor:default"></canvas>
</div>
</div>
</div>
<div class="view" id="v-ops"></div>
</div>
</div>
<div class="chart-tip" id="chart-tip"></div>
<div class="player-back" id="player-back">
<div class="player">
<div id="player-media"><div class="loading"><div class="spin"></div>
decoding and muxing the clip</div></div>
<div class="bar"><b id="player-title"></b>
<span class="t" id="player-time"></span>
<button id="player-pin">open as window</button>
<button id="player-close">close</button></div>
</div>
</div>
<script>
"use strict";
/* validated categorical palette (fixed order, never cycled) */
const CAT = {
light:["#2a78d6","#eb6834","#1baf7a","#eda100","#e87ba4","#008300","#4a3aa7","#e34948"],
dark: ["#3987e5","#d95926","#199e70","#c98500","#d55181","#008300","#9085e9","#e66767"],
otherLight:"#9aa5b0", otherDark:"#5c6873",
};
const $ = id => document.getElementById(id);
const cssVar = n => getComputedStyle(document.documentElement).getPropertyValue(n).trim();
const mode = () => matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
const fmtB = b => b >= 1e9 ? (b/1e9).toFixed(2)+" GB" : b >= 1e6 ? (b/1e6).toFixed(1)+" MB" : (b/1e3).toFixed(0)+" KB";
const fmtN = n => n >= 1e6 ? (n/1e6).toFixed(2)+" M" : n >= 1e3 ? (n/1e3).toFixed(1)+" k" : ""+n;
const esc = s => String(s).replace(/[&<>"]/g, c => ({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;"}[c]));
const PLAY = `<span><svg viewBox="0 0 14 14"><path d="M2 1l11 6-11 6z"/></svg></span>`;
let STORES = [], CUR = null, MAP = null, GEO = null, PIN = null;
const rel = ns => ((ns - CUR.min_ts) / 1e9);
async function j(url, opts) {
const r = await fetch(url, opts);
const d = await r.json().catch(() => ({error: r.statusText}));
if (!r.ok) throw new Error(d.error || r.statusText);
return d;
}
/* shared chart tooltip */
const tip = $("chart-tip");
function tipShow(e, html) {
tip.innerHTML = html; tip.style.display = "block";
const x = Math.min(e.clientX + 14, innerWidth - 300);
tip.style.left = x + "px";
tip.style.top = Math.min(e.clientY + 14, innerHeight - 90) + "px";
}
function tipHide() { tip.style.display = "none"; }
function wireTips(root) {
root.querySelectorAll("[data-tip]").forEach(el => {
el.addEventListener("pointermove", e => tipShow(e, el.dataset.tip));
el.addEventListener("pointerleave", tipHide);
});
}
/* stores rail */
async function loadStores() {
STORES = await j("/api/stores");
$("stores").innerHTML = STORES.map(s => `
<div class="store-card" data-k="${s.key}">
<div class="n">${esc(s.name)}</div>
<div class="m tnum">${s.tables.length} tables · ${fmtN(s.rows)} rows · ${fmtB(s.db_bytes)}</div>
</div>`).join("") || `<div class="empty">no stores found</div>`;
document.querySelectorAll(".store-card").forEach(el =>
el.addEventListener("click", () => selectStore(el.dataset.k)));
if (STORES.length) selectStore(STORES[0].key);
}
async function selectStore(key, refresh) {
if (refresh) STORES = await j("/api/stores");
CUR = STORES.find(s => s.key === key);
MAP = GEO = PIN = IXDATA = ANA = null; ARCH = null;
document.querySelectorAll(".store-card").forEach(el =>
el.classList.toggle("on", el.dataset.k === key));
$("store-title").textContent = CUR.name;
$("store-sub").textContent =
`${fmtB(CUR.db_bytes)} · ${Math.round((CUR.max_ts - CUR.min_ts)/1e9)} s span`;
$("set-stream").innerHTML = `<option value="">any</option>`;
renderOverview(); renderStorageTabs();
$("geo-btn").style.display = "none";
j(`/api/geo?store=${key}`).then(g => {
GEO = g;
if (g.points.length) $("geo-btn").style.display = "";
}).catch(() => {});
j(`/api/map?store=${key}`).then(mp => {
const names = [...new Set((mp.points || []).map(p => p.s))].sort();
$("set-stream").innerHTML = `<option value="">any</option>` +
names.map(n => `<option>${esc(n)}</option>`).join("");
}).catch(() => {});
const cur = document.querySelector("#views button.on").dataset.v;
routeView(cur);
}
/* overview: identity, coverage timeline, tables */
function fmtDur(sec) {
if (sec == null) return "";
if (sec >= 5400) return (sec / 3600).toFixed(1) + " h";
if (sec >= 90) return Math.round(sec / 60) + " min";
return Math.round(sec) + " s";
}
function renderOverview() {
const s = CUR;
const extentS = Math.round((s.max_ts - s.min_ts) / 1e9);
const covS = s.covered_s != null ? Math.round(s.covered_s) : null;
const ratio = s.raw_bytes > 0 && s.db_bytes > 0
? s.raw_bytes / s.db_bytes : null;
const tiles = [];
if (s.raw_bytes > 0)
tiles.push({k:"source data", v: fmtB(s.raw_bytes),
d:`${s.raw_files} original file${s.raw_files === 1 ? "" : "s"} as ingested`});
tiles.push({k:"database", v: fmtB(s.db_bytes), hero:true,
d: s.standalone ? "serves without the source"
: "depends on linked media"});
if (ratio != null && ratio > 1.05)
tiles.push({k:"compression", v: ratio.toFixed(1) + "x",
d:"source bytes per database byte", hero:true});
tiles.push({k:"media", v: fmtB(s.media_bytes + s.linked_bytes),
d: s.linked_bytes > 0 ? "linked from another store"
: "managed, byte-range decoded"});
tiles.push({k:"tables", v: fmtB(s.bytes),
d:`${s.tables.length} Parquet tables · ${fmtN(s.rows)} rows`});
tiles.push({k:"coverage",
v: covS != null ? fmtDur(covS) : fmtDur(extentS),
d: covS != null && extentS > covS * 1.2
? `recorded content over a ${fmtDur(extentS)} extent`
: "recorded content"});
tiles.push({k:"vectors", v: fmtN(s.vec_rows),
d:`${s.vec_tables} vector table${s.vec_tables === 1 ? "" : "s"}`});
let h = `<div class="tiles">` + tiles.map(t =>
`<div class="tile${t.hero?" hero":""}"><div class="k">${t.k}</div>
<div class="v tnum">${t.v}</div>${t.d?`<div class="d">${t.d}</div>`:""}</div>`).join("") + `</div>`;
if (s.raw_missing > 0)
h += `<div class="panel"><div class="bd">
<span class="pill">source removed</span>
<span class="qstat">${s.raw_missing} original source
file${s.raw_missing === 1 ? "" : "s"} no longer exist on disk.
${s.standalone ? "The store serves anyway; that is the point." :
"This store still depends on linked media."}</span></div></div>`;
if (s.linked_bytes > 0)
h += `<div class="panel" style="border-color:var(--signal)"><div class="bd">
<span class="pill warn">linked media</span>
<span class="qstat">${fmtB(s.linked_bytes)} of media is symlinked
from another store. Remove the target and this store stops
serving frames. Copy the media in to make it standalone.</span></div></div>`;
if (s.external_bytes > 0)
h += `<div class="panel" style="border-color:var(--signal)"><div class="bd">
<span class="pill warn">external media</span>
<span class="qstat">${fmtB(s.external_bytes)} of media is referenced
outside the store. Run <b>elidedb adopt ${esc(s.key)}</b> to make the
database standalone.</span></div></div>`;
const lo = s.min_ts, hi = s.max_ts || lo + 1;
h += `<div class="panel"><div class="hd"><h2>Coverage</h2>
<span class="note">each table on the store timeline; a query window
outside a bar never opens that table's files</span></div><div class="bd">`;
const kindColor = {frame_index:"var(--accent)", timeseries:"#7d8fa3",
embeddings:"#8a7fe0", centroids:"#8a7fe0"};
for (const t of s.tables) {
if (!t.rows || t.table === "centroids") continue;
const l = ((t.min_ts - lo) / (hi - lo)) * 100;
const w = Math.max(((t.max_ts - t.min_ts) / (hi - lo)) * 100, 0.35);
h += `<div class="bar-row"><div class="id">${esc(t.table)}</div>
<div class="bar-track"><div class="tl-bar"
style="left:${l.toFixed(2)}%;width:${w.toFixed(2)}%;background:${kindColor[t.kind]||"var(--accent)"}"
data-tip="<b>${esc(t.table)}</b>${fmtN(t.rows)} rows · ${fmtB(t.bytes)}"></div></div>
<div class="bar-val tnum">${fmtN(t.rows)} · ${fmtB(t.bytes)}</div></div>`;
}
h += `<div class="axis indent tnum"><span>0 s</span>
<span>${Math.round((hi-lo)/2e9)} s</span>
<span>${Math.round((hi-lo)/1e9)} s</span></div></div></div>`;
h += `<div class="panel"><div class="hd"><h2>Tables</h2>
<span class="note">version counts commits; older versions stay readable</span></div>
<div class="bd"><div class="tablewrap"><table><thead><tr>
<th>table</th><th>kind</th><th class="r">rows</th><th class="r">size</th>
<th class="r">files</th><th class="r">version</th><th>window</th></tr></thead><tbody>`;
for (const t of s.tables) {
h += `<tr><td>${esc(t.table)}</td>
<td><span class="badge">${t.kind}</span></td>
<td class="r tnum">${t.rows.toLocaleString()}</td>
<td class="r tnum">${fmtB(t.bytes)}</td>
<td class="r tnum">${t.files}</td><td class="r tnum">v${t.version}</td>
<td class="tnum">${t.table === "centroids" ? "" :
`+${rel(t.min_ts).toFixed(1)} to +${rel(t.max_ts).toFixed(1)} s`}</td></tr>`;
}
h += `</tbody></table></div></div></div>`;
$("v-overview").innerHTML = h;
wireTips($("v-overview"));
}
/* analytics: general to any datastore */
let ANA = null;
async function loadAnalytics() {
const el = $("v-analytics");
if (!ANA) {
el.innerHTML = `<div class="empty">reading logs and footers</div>`;
try { ANA = await j(`/api/analytics?store=${CUR.key}`); }
catch (e) { el.innerHTML = `<div class="err">${esc(e.message)}</div>`; return; }
}
const a = ANA, spanS = (a.span.hi - a.span.lo) / 1e9;
const totB = a.tables.reduce((x, t) => x + t.bytes, 0);
const totR = a.tables.reduce((x, t) => x + t.rows, 0);
let h = `<div class="tiles">
<div class="tile hero"><div class="k">bytes on disk</div>
<div class="v tnum">${fmtB(totB)}</div>
<div class="d">${a.tables.length} tables</div></div>
<div class="tile"><div class="k">rows</div>
<div class="v tnum">${fmtN(totR)}</div></div>
<div class="tile"><div class="k">commits</div>
<div class="v tnum">${a.commit_total}</div>
<div class="d">across all logs</div></div>
<div class="tile"><div class="k">vector tables</div>
<div class="v tnum">${a.vectors.length}</div>
<div class="d">${a.base_rows ? fmtN(a.base_rows) + " base units" : ""}</div></div>
<div class="tile"><div class="k">indexes</div>
<div class="v tnum">${a.indexes.bptree.length + a.indexes.ann.length}</div>
<div class="d">${a.indexes.bptree.length} btree · ${a.indexes.ann.length} ann</div></div>
<div class="tile"><div class="k">span</div>
<div class="v tnum">${Math.round(spanS)}<small> s</small></div></div>
</div>`;
/* storage by table: one measure, one hue */
const byBytes = [...a.tables].filter(t => t.rows).sort((x, y) => y.bytes - x.bytes);
const maxB = Math.max(...byBytes.map(t => t.bytes), 1);
h += `<div class="panel"><div class="hd"><h2>Storage by table</h2>
<span class="note">compressed bytes on disk</span></div><div class="bd">`;
for (const t of byBytes) {
h += `<div class="bar-row"><div class="id">${esc(t.table)}</div>
<div class="bar-track"><div class="bar-fill"
style="width:${(100 * t.bytes / maxB).toFixed(2)}%"
data-tip="<b>${esc(t.table)}</b>${fmtB(t.bytes)} · ${t.rows.toLocaleString()} rows · ${t.files} files · ${t.bpr ?? "?"} bytes per row"></div></div>
<div class="bar-val tnum">${fmtB(t.bytes)}</div></div>`;
}
h += `</div></div>`;
/* temporal density: rows per bucket per table, footer stats only */
const dTables = Object.keys(a.density);
if (dTables.length) {
h += `<div class="panel"><div class="hd"><h2>Row density over time</h2>
<span class="note">rows per time bucket from row group statistics;
this is the elision map a range query prunes against</span></div><div class="bd">`;
for (const name of dTables) {
const cells = a.density[name], mx = Math.max(...cells, 1);
const strip = cells.map((v, i) => {
const t0 = (spanS * i / a.buckets).toFixed(0);
const t1 = (spanS * (i + 1) / a.buckets).toFixed(0);
return `<div class="heat-cell"
style="background:${v ? `color-mix(in srgb, var(--accent) ${Math.round(12 + 88 * v / mx)}%, var(--panel-2))` : "transparent"}"
data-tip="<b>${esc(name)}</b>~${v.toLocaleString()} rows · +${t0} to +${t1} s"></div>`;
}).join("");
h += `<div class="heat-row"><div class="id">${esc(name)}</div>
<div class="heat-strip">${strip}</div>
<div class="bar-val tnum">${fmtN(cells.reduce((x, y) => x + y, 0))}</div></div>`;
}
h += `<div class="axis indent tnum"><span>0 s</span>
<span>${Math.round(spanS / 2)} s</span><span>${Math.round(spanS)} s</span></div>
</div></div>`;
}
/* vector inventory */
if (a.vectors.length) {
h += `<div class="panel"><div class="hd"><h2>Vector inventory</h2>
<span class="note">every embedding table, with coverage against the
store's base units</span></div><div class="bd">
<div class="tablewrap"><table><thead><tr>
<th>table</th><th>encoder</th><th class="r">dim</th>
<th class="r">rows</th><th>coverage</th><th class="r">size</th>
</tr></thead><tbody>`;
for (const v of a.vectors) {
const cov = v.per_base == null ? "" :
`<div class="bar-track" style="width:110px;display:inline-block;vertical-align:middle">
<div class="bar-fill${v.per_base < 1 ? " dim" : ""}"
style="width:${Math.min(100, 100 * Math.min(v.per_base, 1)).toFixed(0)}%"
data-tip="<b>${esc(v.table)}</b>${v.per_base} vectors per base unit"></div>
</div> <span class="tnum" style="font-size:10.5px">${v.per_base}x</span>`;
h += `<tr><td>${esc(v.table)}</td>
<td style="font-size:10.5px">${esc(v.model)}</td>
<td class="r tnum">${v.dim ?? ""}</td>
<td class="r tnum">${v.rows.toLocaleString()}</td>
<td>${cov}</td>
<td class="r tnum">${fmtB(v.bytes)}</td></tr>`;
}
h += `</tbody></table></div></div></div>`;
}
/* fitted retrieval profile */
if (a.fitted && a.fitted.set_weights) {
const f = a.fitted;
const rowOf = (w, title, alpha, q, r) => {
const entries = Object.entries(w).sort((x, y) => y[1] - x[1]);
const mx = Math.max(...entries.map(e => e[1]), 1);
let g = `<div style="flex:1;min-width:280px">
<div class="lbl" style="margin-bottom:8px">${title}</div>`;
for (const [c, v] of entries) {
g += `<div class="bar-row" style="grid-template-columns:56px 1fr 40px">
<div class="id">${esc(c)}</div>
<div class="bar-track"><div class="bar-fill${v ? "" : " dim"}"
style="width:${(100 * v / mx).toFixed(1)}%"
data-tip="<b>${esc(c)}</b>ordering weight ${v}"></div></div>
<div class="bar-val tnum">${v}</div></div>`;
}
g += `<div style="margin-top:8px;display:flex;gap:6px;flex-wrap:wrap">
<span class="pill">cut ${alpha}</span>
<span class="pill">filter q ${Number(q).toFixed(2)}</span>
<span class="pill">dedup r ${r}</span></div></div>`;
return g;
};
h += `<div class="panel"><div class="hd"><h2>Retrieval profile</h2>
<span class="note">per-store fitted roles: which channels order,
filter, and where the returned set ends · holdout objective
${f.loqo_mean ?? ""}</span></div>
<div class="bd"><div style="display:flex;gap:32px;flex-wrap:wrap">` +
rowOf(f.set_weights_dir || {}, "directional queries",
f.cut_alpha_dir ?? 0, f.filter_quantile_dir ?? 0, f.nms_r_dir ?? 0) +
rowOf(f.set_weights || {}, "descriptive queries",
f.cut_alpha ?? 0, f.filter_quantile ?? 0, f.nms_r ?? 0) +
`</div></div></div>`;
}
/* write history */
if (a.commits.length) {
h += `<div class="panel"><div class="hd"><h2>Write history</h2>
<span class="note">latest ${a.commits.length} of ${a.commit_total}
commits, straight from the transaction logs</span></div><div class="bd">
<div class="tablewrap"><table><thead><tr>
<th>table</th><th>op</th><th class="r">version</th>
<th class="r">rows added</th><th>utc</th></tr></thead><tbody>` +
[...a.commits].reverse().map(c => `<tr>
<td>${esc(c.table)}</td>
<td><span class="badge">${esc(c.op)}</span></td>
<td class="r tnum">v${c.version}</td>
<td class="r tnum">${(c.rows || 0).toLocaleString()}</td>
<td class="tnum" style="font-size:10.5px">${esc(c.ts_utc)}</td></tr>`).join("") +
`</tbody></table></div></div></div>`;
}
el.innerHTML = h;
wireTips(el);
}
/* storage */
function renderStorageTabs() {
const tabs = CUR.tables.filter(t => t.rows);
$("storage-tables").innerHTML = tabs.map((t, i) =>
`<button data-t="${esc(t.table)}"${i === 0 ? ' class="on"' : ''}>${esc(t.table)}</button>`).join("");
$("storage-out").innerHTML = "";
document.querySelectorAll("#storage-tables button").forEach(b =>
b.addEventListener("click", () => {
document.querySelectorAll("#storage-tables button").forEach(x =>
x.classList.toggle("on", x === b));
loadStorage(b.dataset.t);
}));
}
async function drawBytes() {
const host = $("bytes-panel"); if (!host) return;
if (!BYTES) {
host.innerHTML = `<div class="panel"><div class="bd">
<div class="empty">measuring bytes</div></div></div>`;
try { BYTES = await j(`/api/bytes?store=${CUR.key}`); }
catch (e) { host.innerHTML = ""; return; }
}
const B = BYTES, tot = B.total || 1;
const seg = (label, v, cls, note) => v <= 0 ? "" : `
<div class="byrow"><div class="bylab ${cls}">${label}</div>
<div class="bybar"><i class="${cls}" style="width:${
Math.max(0.4, 100 * v / tot)}%"></i></div>
<div class="byval">${fmtB(v)} <span>${(100 * v / tot).toFixed(1)}%</span></div>
<div class="bynote">${note}</div></div>`;
host.innerHTML = `<div class="panel"><div class="hd">
<h2>Bytes on disk</h2><span class="note">a directory size adds
together four different things; only the first is the database</span>
</div><div class="bd">
${seg("live", B.live, "b-live",
"parquet the LOG points at — this IS the database")}
${seg("orphaned", B.orphaned, "b-orph",
"superseded by a replace/compact commit; still on disk until vacuum")}
${seg("media", B.media, "b-media",
"managed video renditions, byte-range decoded, never copied raw")}
${seg("cache", B.cache, "b-cache",
"_cache/ — ITM cross-encoder vision tokens. DISPOSABLE: deleting it "
+ "costs recompute time, never correctness")}
<div class="bynote" style="margin-top:9px">
models are <b>not</b> in the store — they live in models/ at the repo
root (iv2_stage2_1b alone is 2.8 GB), which is why “store size” and
“what this system needs on disk” are different numbers.
</div>
<div class="dbsec" style="margin-top:14px">COMPRESSION</div>
<div class="bynote">${fmtB(B.compressed)} stored for
${fmtB(B.uncompressed)} of column data — <b>${B.ratio}×</b> overall.
The ratio is low because <b>vectors dominate and vectors do not
compress</b>: they are already fp16-packed high-entropy floats, and
that halving happened at write time so it never shows here.
Structural tables do compress — see the ratio column.</div>
<table class="dbt"><tr><th>table</th><th class="n">rows</th>
<th class="n">stored</th><th class="n">raw cols</th>
<th class="n">ratio</th><th>codec · encodings</th></tr>` +
B.tables.map(r => `<tr><td>${esc(r.table)}</td>
<td class="n">${fmtN(r.rows)}</td>
<td class="n">${fmtB(r.compressed)}</td>
<td class="n">${fmtB(r.uncompressed)}</td>
<td class="n"${r.ratio >= 2 ? ' style="color:#5accb9"' : ''}>${r.ratio}×</td>
<td style="color:var(--dim)">${esc((r.codec[0] || "") + " · " +
r.encodings.join(" ").replace(/RLE_DICTIONARY/g, "RLE_DICT"))}</td>
</tr>`).join("") + `</table></div></div>`;
}
async function loadStorage(table) {
table = table || document.querySelector("#storage-tables button.on")?.dataset.t;
if (!table) return;
$("storage-out").innerHTML = `<div class="empty">reading Parquet footers</div>`;
try {
const d = await j(`/api/storage?store=${CUR.key}&table=${encodeURIComponent(table)}`);
const H3 = t => `<div class="lbl" style="margin:18px 0 8px">${t}</div>`;
let h = H3(`transaction log · ${d.history.length} commit${d.history.length > 1 ? "s" : ""} · v${d.version}`);
h += `<div class="tablewrap"><table><thead><tr><th>v</th><th>op</th>
<th class="r">rows added</th><th>utc</th><th>meta</th></tr></thead><tbody>` +
d.history.map(c => `<tr><td class="tnum">v${c.version}</td>
<td><span class="badge">${esc(c.op)}</span></td>
<td class="r tnum">${c.added_rows.toLocaleString()}</td>
<td class="tnum" style="font-size:10.5px">${esc(c.ts_utc)}</td>
<td style="font-size:10.5px;max-width:340px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">${esc(JSON.stringify(c.meta))}</td></tr>`).join("") +
`</tbody></table></div>`;
h += H3(`active files · ${d.files.length} · row groups are the pruning unit`);
const maxB = Math.max(...d.files.map(f => f.bytes), 1);
for (const f of d.files) {
const segs = f.row_groups.map(g => {
const t0 = g.min_ts != null ? `+${rel(g.min_ts).toFixed(1)}s` : "?";
const t1 = g.max_ts != null ? `+${rel(g.max_ts).toFixed(1)}s` : "?";
return `<div data-tip="<b>row group</b>${g.rows.toLocaleString()} rows · ${fmtB(g.bytes)} · ${t0} to ${t1}"
style="flex:${Math.max(g.bytes, 1)};background:var(--accent);opacity:.85;border-right:2px solid var(--panel);min-width:3px"></div>`;
}).join("");
h += `<div style="margin:12px 0">
<div style="display:flex;justify-content:space-between;gap:12px;font-size:11px">
<span style="overflow:hidden;text-overflow:ellipsis">${esc(f.name)}</span>
<span class="tnum" style="color:var(--faint);flex:none">${f.rows.toLocaleString()} rows · ${f.row_groups.length} groups · ${fmtB(f.bytes)} · footer ${fmtB(f.footer_bytes)}</span></div>
<div style="display:flex;height:20px;border-radius:3px;overflow:hidden;background:var(--panel-2);width:${Math.max(100 * f.bytes / maxB, 10)}%;margin-top:4px">${segs}</div></div>`;
}
if (d.files[0])
h += `<div class="hint" style="margin-top:14px">columns: ${esc(d.files[0].columns.join(" · "))}</div>`;
$("storage-out").innerHTML = h;
wireTips($("storage-out"));
} catch (e) {
$("storage-out").innerHTML = `<div class="err">${esc(e.message)}</div>`;
}
}
/* embedding map */
async function loadMap() {
if (!MAP) {
$("legend").innerHTML = `<h3>clusters</h3><div class="li">computing layout</div>`;
try { MAP = await j(`/api/map?store=${CUR.key}`); }
catch (e) { $("legend").innerHTML = `<div class="err">${esc(e.message)}</div>`; return; }
}
// say WHERE the colours come from: a store with no cluster column
// gets k-means over the 2D layout, and that must never be mistaken
// for retrieval structure
const ms = $("map-src");
if (ms && MAP && MAP.cluster_source)
ms.innerHTML = ` · colours: ${esc(MAP.cluster_source)}`;
drawScatter();
}
function drawScatter() {
const canvas = $("scatter"), pts = MAP ? MAP.points : [];
const pal = CAT[mode()], other = mode() === "dark" ? CAT.otherDark : CAT.otherLight;
const dpr = devicePixelRatio || 1, W = canvas.clientWidth, H = 470;
canvas.width = W * dpr; canvas.height = H * dpr;
const ctx = canvas.getContext("2d"); ctx.scale(dpr, dpr);
ctx.clearRect(0, 0, W, H);
if (!pts.length) {
ctx.fillStyle = cssVar("--faint"); ctx.font = "12px ui-monospace, Menlo";
ctx.fillText("no embeddings table in this store", 24, 40);
$("legend").innerHTML = ""; return;
}
const counts = {};
for (const p of pts) if (p.c >= 0) counts[p.c] = (counts[p.c] || 0) + 1;
const ranked = Object.entries(counts).sort((a, b) => b[1] - a[1]);
const slot = new Map(ranked.map(([c], i) => [+c, i < 8 ? i : -2]));
const xs = pts.map(p => p.x), ys = pts.map(p => p.y);
const x0 = Math.min(...xs), x1 = Math.max(...xs), y0 = Math.min(...ys), y1 = Math.max(...ys);
const pad = 24;
for (const p of pts) {
p.X = pad + ((p.x - x0) / (x1 - x0 || 1)) * (W - 2 * pad);
p.Y = H - pad - ((p.y - y0) / (y1 - y0 || 1)) * (H - 2 * pad);
}
ctx.strokeStyle = cssVar("--grid");
for (let g = 1; g < 4; g++) {
ctx.beginPath(); ctx.moveTo(W*g/4, 8); ctx.lineTo(W*g/4, H-8); ctx.stroke();
ctx.beginPath(); ctx.moveTo(8, H*g/4); ctx.lineTo(W-8, H*g/4); ctx.stroke();
}
const r = pts.length > 400 ? 3.4 : 5;
for (const p of pts) {
ctx.beginPath(); ctx.arc(p.X, p.Y, r, 0, 7);
if (p.c < 0) { ctx.strokeStyle = cssVar("--faint"); ctx.lineWidth = 1.4; ctx.stroke(); }
else {
const s = slot.get(p.c);
ctx.fillStyle = s === -2 ? other : pal[s]; ctx.fill();
ctx.strokeStyle = cssVar("--panel-2"); ctx.lineWidth = 1; ctx.stroke();
}
}
let lh = `<h3>clusters</h3>`;
ranked.slice(0, 8).forEach(([c, n], i) =>
lh += `<div class="li"><i style="background:${pal[i]}"></i>cluster ${c}<span class="cnt tnum">${n}</span></div>`);
const otherN = ranked.slice(8).reduce((a, [, n]) => a + n, 0);
if (otherN) lh += `<div class="li"><i style="background:${other}"></i>${ranked.length - 8} more<span class="cnt tnum">${otherN}</span></div>`;
const noise = pts.filter(p => p.c < 0).length;
if (noise) lh += `<div class="li noise"><i></i>noise<span class="cnt tnum">${noise}</span></div>`;
lh += `<h3 style="margin-top:14px">windows</h3>
<div class="li">plotted<span class="cnt tnum">${pts.length}</span></div>` +
(MAP.sampled_of > pts.length ?
`<div class="li">of<span class="cnt tnum">${MAP.sampled_of.toLocaleString()}</span></div>` : "") +
`<div class="li">previews<span class="cnt">decoded live</span></div>
<div class="li">click<span class="cnt">plays the clip</span></div>`;
$("legend").innerHTML = lh;
}
let hoverP = null, thumbTimer = null;
$("scatter").addEventListener("pointermove", e => {
if (!MAP) return;
const rect = $("scatter").getBoundingClientRect();
const mx = e.clientX - rect.left, my = e.clientY - rect.top;
let best = null, bd = 400;
for (const p of MAP.points) {
const d = (p.X - mx) ** 2 + (p.Y - my) ** 2;
if (d < bd) { bd = d; best = p; }
}
const card = $("card");
if (!best) { card.style.display = "none"; hoverP = null; return; }
if (best !== hoverP) {
hoverP = best;
card.querySelector(".m").innerHTML =
`<b>${esc(best.s)}</b>+${rel(best.t0).toFixed(1)} to +${rel(best.t1).toFixed(1)} s · cluster ${best.c}`;
let ph = card.querySelector(".ph"), img = card.querySelector("img");
if (img) img.remove();
if (!ph) { ph = document.createElement("div"); ph.className = "ph";
ph.textContent = "decoding"; card.prepend(ph); }
clearTimeout(thumbTimer);
thumbTimer = setTimeout(() => {
const im = new Image();
im.onload = () => { if (hoverP === best) {
card.querySelector(".ph")?.remove(); card.prepend(im); } };
im.src = `/api/thumb?store=${CUR.key}&stream=${encodeURIComponent(best.s)}&t=${best.t0}&w=380`;
}, 120);
}
card.style.left = Math.min(Math.max(best.X + 14, 0), $("scatter").clientWidth - 200) + "px";
card.style.top = Math.max(best.Y - 175, 4) + "px";
card.style.display = "block";
});
$("scatter").addEventListener("pointerleave", () => {
$("card").style.display = "none"; hoverP = null; });
$("scatter").addEventListener("click", () => {
if (hoverP) openPlayer(hoverP.s, hoverP.t0, hoverP.t1);
});
/* geo */
function drawGeo() {
if (!GEO || !GEO.points.length) return;
const canvas = $("route"), R = GEO.points;
$("geo-note").textContent =
`table ${GEO.table} · ${R.length} fixes, downsampled · the accent span is covered by frame-indexed video`;
const dpr = devicePixelRatio || 1, W = canvas.clientWidth, H = 420;
canvas.width = W * dpr; canvas.height = H * dpr;
const ctx = canvas.getContext("2d"); ctx.scale(dpr, dpr); ctx.clearRect(0, 0, W, H);
const las = R.map(p => p.la), los = R.map(p => p.lo);
const la0 = Math.min(...las), la1 = Math.max(...las), lo0 = Math.min(...los), lo1 = Math.max(...los);
const sc = Math.cos(((la0 + la1) / 2) * Math.PI / 180);
const k = Math.min((W - 48) / ((lo1 - lo0) * sc || 1), (H - 48) / ((la1 - la0) || 1));
const px = p => (W - (lo1 - lo0) * sc * k) / 2 + (p.lo - lo0) * sc * k;
const py = p => H - (H - (la1 - la0) * k) / 2 - (p.la - la0) * k;
const vids = CUR.tables.filter(t => t.kind === "frame_index");
const vlo = Math.min(...vids.map(t => t.min_ts), Infinity);
const vhi = Math.max(...vids.map(t => t.max_ts), -Infinity);
ctx.strokeStyle = "#7d8fa3"; ctx.lineWidth = 2; ctx.lineJoin = "round";
ctx.beginPath(); R.forEach((p, i) => i ? ctx.lineTo(px(p), py(p)) : ctx.moveTo(px(p), py(p))); ctx.stroke();
ctx.strokeStyle = cssVar("--accent"); ctx.lineWidth = 6; ctx.lineCap = "round";
ctx.beginPath(); let st = false;
for (const p of R) if (p.t >= vlo && p.t <= vhi) {
st ? ctx.lineTo(px(p), py(p)) : ctx.moveTo(px(p), py(p)); st = true; }
ctx.stroke();
ctx.fillStyle = cssVar("--muted"); ctx.font = "11px ui-monospace, Menlo";
const s0 = R[0], s1 = R[R.length - 1];
ctx.beginPath(); ctx.arc(px(s0), py(s0), 4, 0, 7); ctx.fill();
ctx.fillText("start", px(s0) + 8, py(s0) + 4);
ctx.beginPath(); ctx.arc(px(s1), py(s1), 4, 0, 7); ctx.fill();
ctx.fillText("end", px(s1) + 8, py(s1) + 4);
}
/* clip player */
function openPlayer(stream, t0, t1) {
PIN = {s: stream, t0, t1};
$("player-back").classList.add("on");
$("player-title").textContent = stream;
const durS = (t1 - t0) / 1e9;
$("player-time").textContent =
`+${rel(t0).toFixed(2)} to +${rel(t1).toFixed(2)} s · ${durS.toFixed(1)} s` +
(durS > 30 ? " · first 30 s previewed" : "");
$("player-media").innerHTML =
`<div class="loading"><div class="spin"></div>decoding and muxing the clip</div>`;
const url = `/api/clip?store=${CUR.key}&stream=${encodeURIComponent(stream)}&t0=${t0}&t1=${t1}&w=720`;
fetch(url).then(async r => {
if (!r.ok) {
let d = {};
try { d = await r.json(); } catch (_) {}
const why = d.error || `server returned ${r.status}`;
$("player-media").innerHTML =
`<div class="loading"><b>${esc(why)}</b>` +
(d.detail ? `<div style="margin-top:6px">${esc(d.detail)}</div>` : "") +
`</div>`;
return;
}
const v = document.createElement("video");
v.controls = true; v.autoplay = true; v.loop = true; v.playsInline = true;
v.src = URL.createObjectURL(await r.blob());
v.addEventListener("loadeddata", () => {
$("player-media").innerHTML = ""; $("player-media").appendChild(v);
});
v.addEventListener("error", () => {
$("player-media").innerHTML =
`<div class="loading">the clip built but this browser refused to play it</div>`;
});
}).catch(e => {
$("player-media").innerHTML =
`<div class="loading">could not reach the server: ${esc(String(e))}</div>`;
});
}
function closePlayer() {
$("player-back").classList.remove("on");
$("player-media").querySelector("video")?.pause();
$("player-media").innerHTML = "";
}
$("player-close").addEventListener("click", closePlayer);
$("player-back").addEventListener("click", e => {
if (e.target === $("player-back")) closePlayer(); });
addEventListener("keydown", e => { if (e.key === "Escape") closePlayer(); });
$("player-pin").addEventListener("click", () => {
if (!PIN) return;
closePlayer();
setQMode("window");
$("win-input").value = `${rel(PIN.t0).toFixed(2)},${rel(PIN.t1).toFixed(2)}`;
document.querySelector('#views button[data-v="search"]').click();
});
/* search console */
function setQMode(m) {
document.querySelectorAll("#qmodes button").forEach(b =>
b.classList.toggle("on", b.dataset.q === m));
$("q-set").style.display = m === "set" ? "" : "none";
$("q-predicate").style.display = m === "predicate" ? "" : "none";
$("q-sql").style.display = m === "sql" ? "" : "none";
$("q-window").style.display = m === "window" ? "" : "none";
if (m === "predicate") fillPredicate();
if (m === "sql" && !$("sql-input").value)
$("sql-input").value = "SELECT count(*) AS rows, min(ts), max(ts) FROM " +
(CUR.tables.find(t => t.kind === "timeseries")?.table || CUR.tables[0].table);
}
document.querySelectorAll("#qmodes button").forEach(b =>
b.addEventListener("click", () => setQMode(b.dataset.q)));
let IXDATA = null;
async function fillPredicate() {
IXDATA = IXDATA || await j(`/api/indexes?store=${CUR.key}`).catch(() => ({indexable:{}}));
const tsel = $("pred-table");
tsel.innerHTML = Object.keys(IXDATA.indexable).map(t => `<option>${esc(t)}</option>`).join("");
tsel.onchange = () => {
$("pred-col").innerHTML = (IXDATA.indexable[tsel.value] || [])
.map(c => `<option>${esc(c)}</option>`).join("");
};
tsel.onchange();
}
$("pred-op").addEventListener("change", () =>
$("pred-val2-wrap").style.display = $("pred-op").value === "between" ? "" : "none");
$("run").addEventListener("click", runQuery);
$("set-input").addEventListener("keydown", e => { if (e.key === "Enter") runQuery(); });
$("win-input").addEventListener("keydown", e => { if (e.key === "Enter") runQuery(); });
async function runQuery() {
const m = document.querySelector("#qmodes button.on").dataset.q;
const out = $("q-out"), stat = $("q-stat");
out.innerHTML = ""; stat.textContent = "running";
try {
let body = {store: CUR.key};
if (m === "set") {
body.type = "context"; body.text = $("set-input").value;
body.k = +$("set-k").value || 10;
const cs = $("set-stream").value; if (cs) body.streams = [cs];
if ($("set-audit").checked) body.rerank = true;
const ca = $("set-t0").value, cb = $("set-t1").value;
if (ca !== "") body.t0 = Math.round(CUR.min_ts + +ca * 1e9);
if (cb !== "") body.t1 = Math.round(CUR.min_ts + +cb * 1e9);
}
if (m === "predicate") {
body.type = "predicate"; body.table = $("pred-table").value;
body.column = $("pred-col").value; body.op = $("pred-op").value;
body.value = $("pred-val").value;
if (body.op === "between") body.value2 = $("pred-val2").value;
}
if (m === "sql") Object.assign(body, {type: "sql", sql: $("sql-input").value});
if (m === "window") {
const [a, b] = $("win-input").value.split(",").map(Number);
Object.assign(body, {type: "window",
t0: Math.round(CUR.min_ts + a * 1e9), t1: Math.round(CUR.min_ts + b * 1e9)});
}
const r = await j("/api/query", {method: "POST",
headers: {"Content-Type": "application/json"}, body: JSON.stringify(body)});
if (m === "sql" || m === "predicate") {
const st = r.stats;
stat.textContent = (m === "predicate"
? `${r.count.toLocaleString()} rows · ${st.files} files · ${st.elided_pct}% elided · `
: `${r.rows.length} rows · `) + `${r.ms} ms`;
out.innerHTML = `<div class="tablewrap" style="margin-top:14px"><table><thead><tr>` +
r.columns.map(c => `<th>${esc(c)}</th>`).join("") + `</tr></thead><tbody>` +
r.rows.map(row => `<tr>` + row.map(v =>
`<td class="tnum">${esc(typeof v === "number" && !Number.isInteger(v) ? v.toFixed(4) : (v ?? ""))}</td>`).join("") + `</tr>`).join("") +
`</tbody></table></div>`;
} else if (m === "set") {
const S = r.stats;
if (S.no_match && !r.hits.length) {
stat.textContent = `${r.ms} ms`;
out.innerHTML = `<div class="empty">This corpus does not contain
that action. The index abstained rather than returning
look-alikes.</div>`;
return;
}
const chans = S.channels && S.channels.length ?
`channels ${S.channels.join(" · ")} · ` : "";
stat.textContent = `${r.hits.length} clips · ${chans}${r.ms} ms`;
out.innerHTML = `<div class="hitgrid">` + r.hits.map(h => {
const dur = (h.t1 - h.t0) / 1e9;
const mid = Math.round((+h.t0 + +h.t1) / 2);
return `
<div class="hit" data-s="${esc(h.stream)}" data-t0="${h.t0}" data-t1="${h.t1}">
<img src="/api/thumb?store=${CUR.key}&stream=${encodeURIComponent(h.stream)}&t=${mid}&w=420" alt="">
<div class="play">${PLAY}</div>
<div class="m"><b class="tnum">${h.score.toFixed(3)}</b> · ${esc(h.stream)}<br>
<span class="tnum">+${rel(h.t0).toFixed(1)} to +${rel(h.t1).toFixed(1)} s · ${dur.toFixed(1)} s</span></div>
</div>`;
}).join("") + `</div>`;
out.querySelectorAll(".hit").forEach(el => el.addEventListener("click", () =>
openPlayer(el.dataset.s, +el.dataset.t0, +el.dataset.t1)));
} else if (m === "window") {
const s = r.stats;
stat.textContent = `${s.files} files · ${fmtB(s.bytes_touched)} of ${fmtB(s.corpus_bytes)} read · ${s.elided_pct}% elided · ${r.ms} ms`;
let h = "";
for (const [name, t] of Object.entries(r.tables)) {
if (t.kind === "frames") {
const [wa, wb] = $("win-input").value.split(",").map(Number);
const wt0 = Math.round(CUR.min_ts + wa * 1e9), wt1 = Math.round(CUR.min_ts + wb * 1e9);
h += `<div style="margin-top:14px"><b>${esc(name)}</b>
<span class="qstat"> ${t.count} frames · ${t.streams.length} streams</span>
<div class="hitgrid" style="margin-top:8px">` + t.streams.map(sname => `
<div class="hit" data-s="${esc(sname)}" data-t0="${wt0}" data-t1="${wt1}">
<img src="/api/thumb?store=${CUR.key}&stream=${encodeURIComponent(sname)}&t=${wt0}&w=420">
<div class="play">${PLAY}</div>
<div class="m"><b>${esc(sname)}</b></div></div>`).join("") + `</div></div>`;
} else if (t.count) {
h += `<div style="margin-top:14px"><b>${esc(name)}</b>
<span class="qstat"> ${t.count.toLocaleString()} rows</span>
<div class="tablewrap"><table><thead><tr>` +
t.columns.slice(0, 8).map(c => `<th>${esc(c)}</th>`).join("") +
`</tr></thead><tbody>` + t.head.map(row =>
`<tr>` + row.slice(0, 8).map(v => `<td class="tnum">${esc(typeof v === "number" && !Number.isInteger(v) ? v.toFixed(3) : v)}</td>`).join("") + `</tr>`).join("") +
`</tbody></table></div></div>`;
}
}
out.innerHTML = h || `<div class="empty">the window is empty</div>`;
out.querySelectorAll(".hit").forEach(el => el.addEventListener("click", () =>
openPlayer(el.dataset.s, +el.dataset.t0, +el.dataset.t1)));
}
} catch (e) {
stat.textContent = "";
out.innerHTML = `<div class="err">${esc(e.message)}</div>`;
}
}
/* data: schema and sample rows */
let BYTES = null;
async function loadData(table) {
const el = $("v-data");
if (!table) {
el.innerHTML = `<div id="bytes-panel"></div>
<div class="panel"><div class="hd"><h2>Tables</h2>
<span class="note">columns, types, real rows — and what each one
costs on disk</span></div>
<div class="bd"><div class="empty">reading schema</div></div></div>`;
drawBytes();
const all = await j(`/api/schema?store=${CUR.key}`).catch(e => ({error: e.message}));
if (all.error) {
el.querySelector(".bd").innerHTML = `<div class="err">${esc(all.error)}</div>`;
return;
}
el.querySelector(".bd").innerHTML =
`<div class="seg" id="data-tabs"></div><div id="data-detail"></div>`;
$("data-tabs").innerHTML = all.map((t, i) =>
`<button data-t="${esc(t.table)}"${i === 0 ? ' class="on"' : ''}>${esc(t.table)}</button>`).join("");
document.querySelectorAll("#data-tabs button").forEach(b => b.onclick = () => {
document.querySelectorAll("#data-tabs button").forEach(x =>
x.classList.toggle("on", x === b));
loadData(b.dataset.t);
});
if (all.length) loadData(all[0].table);
return;
}
const d = (await j(`/api/schema?store=${CUR.key}&table=${encodeURIComponent(table)}`))[0];
if (!d) return;
const span = d.rows ? `+${rel(d.min_ts).toFixed(1)} to +${rel(d.max_ts).toFixed(1)} s` : "";
let h = `<div class="ctrl" style="margin:14px 0 10px">
<span class="badge">${esc(d.kind)}</span>
<span class="qstat tnum">${d.rows.toLocaleString()} rows · ${fmtB(d.bytes)} · v${d.version} · ${span}</span></div>`;
h += `<div class="tablewrap"><table><thead><tr><th>column</th><th>type</th></tr></thead><tbody>` +
d.columns.map(c => `<tr><td>${esc(c.name)}</td>
<td style="color:var(--faint)">${esc(c.type)}</td></tr>`).join("") +
`</tbody></table></div>`;
if (d.sample && d.sample.length) {
const cols = Object.keys(d.sample[0]).slice(0, 9);
h += `<div class="lbl" style="margin:20px 0 8px">first rows</div>
<div class="tablewrap"><table><thead><tr>` +
cols.map(c => `<th>${esc(c)}</th>`).join("") + `</tr></thead><tbody>` +
d.sample.map(r => `<tr>` + cols.map(c => {
let v = r[c];
if (c === "ts" && typeof v === "number")
v = v === 0 ? "" : `+${rel(v).toFixed(3)} s`;
return `<td class="tnum">${esc(v ?? "")}</td>`;
}).join("") + `</tr>`).join("") + `</tbody></table></div>`;
}
$("data-detail").innerHTML = h;
}
/* ops: indexes + maintenance */
async function loadOps() {
const el = $("v-ops");
el.innerHTML = `<div class="empty">reading index state</div>`;
const d = await j(`/api/indexes?store=${CUR.key}`).catch(e => ({error: e.message}));
IXDATA = d;
if (d.error) { el.innerHTML = `<div class="err">${esc(d.error)}</div>`; return; }
let h = `<div class="panel"><div class="hd"><h2>Secondary indexes</h2>
<span class="note">zone maps prune the time axis for free; a btree on
any other numeric column prunes its predicates too</span></div><div class="bd">`;
for (const [tbl, cols] of Object.entries(d.indexable)) {
for (const c of cols) {
const ex = d.bptree.find(x => x.table === tbl && x.column === c);
h += `<div class="ixrow"><span>${esc(tbl)}.${esc(c)}</span>
<span class="grow"></span>
${ex ? `<span class="pill ok">v${ex.version} · ${fmtB(ex.bytes)}</span>` : ""}
<button class="btn" data-ix-t="${esc(tbl)}" data-ix-c="${esc(c)}">${ex ? "rebuild" : "build"}</button></div>`;
}
}
if (!Object.keys(d.indexable).length)
h += `<div class="empty">no numeric columns to index</div>`;
h += `</div></div>`;
if (d.has_embeddings) {
h += `<div class="panel"><div class="hd"><h2>Vector indexes</h2>
<span class="note">approximate tiers over the embeddings table;
exact scan needs no build and stays available</span></div><div class="bd">`;
for (const kind of ["hnsw", "ivfpq"]) {
const ex = d.ann.find(x => x.kind === kind);
h += `<div class="ixrow"><span>${kind.toUpperCase()}</span><span class="grow"></span>
${ex ? `<span class="pill ${ex.stale ? "warn" : "ok"}">v${ex.version}${ex.stale ? " stale" : ""} · ${fmtB(ex.bytes)}</span>` : ""}
<button class="btn" data-ann="${kind}">${ex ? "rebuild" : "build"}</button></div>`;
}
h += `</div></div>`;
}
h += `<div class="panel"><div class="hd"><h2>Maintenance</h2>
<span class="note">each operation is one atomic commit; earlier
versions stay readable until vacuumed</span></div><div class="bd">
<div class="ixrow"><span>Compact</span>
<span class="qstat">rewrite a table into few large sorted files</span>
<span class="grow"></span>
<select id="mt-compact-tbl"></select>
<button class="btn" id="mt-compact">Compact</button>
<span class="qstat" id="mt-compact-out"></span></div>
<div class="ixrow"><span>Vacuum</span>
<span class="qstat">drop files unreachable from the last</span>
<input type="number" id="mt-retain" value="3" min="1" style="width:52px">
<span class="qstat">versions</span>
<span class="grow"></span>
<button class="btn" id="mt-vacuum-dry">Dry run</button>
<button class="btn danger" id="mt-vacuum">Vacuum</button>
<span class="qstat" id="mt-vacuum-out"></span></div>
<div class="ixrow"><span>Delete range</span>
<select id="mt-del-tbl"></select>
<span class="qstat">from s</span>
<input type="number" id="mt-del-t0" style="width:80px">
<span class="qstat">to s</span>
<input type="number" id="mt-del-t1" style="width:80px">
<span class="grow"></span>
<button class="btn danger" id="mt-del">Delete</button>
<span class="qstat" id="mt-del-out"></span></div>
</div></div>`;
el.innerHTML = h;
el.querySelectorAll("[data-ix-t]").forEach(btn => btn.onclick = () =>
buildIx(btn, {table: btn.dataset.ixT, column: btn.dataset.ixC}));
el.querySelectorAll("[data-ann]").forEach(btn => btn.onclick = () =>
buildIx(btn, {ann: btn.dataset.ann}));
const tbls = CUR.tables.filter(t => t.rows && t.table !== "centroids")
.map(t => `<option>${esc(t.table)}</option>`).join("");
$("mt-compact-tbl").innerHTML = tbls; $("mt-del-tbl").innerHTML = tbls;
const post = (o) => j("/api/maintenance", {method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({store: CUR.key, ...o})});
$("mt-compact").onclick = async () => {
$("mt-compact-out").textContent = "working";
try { const r = await post({op: "compact", table: $("mt-compact-tbl").value});
$("mt-compact-out").textContent =
`${r.files_before} to ${r.files_after} files · ${r.ratio}x · ${r.ms} ms`;
selectStore(CUR.key, true);
} catch (e) { $("mt-compact-out").innerHTML = `<span class="err">${esc(e.message)}</span>`; }
};
const vac = (dry) => async () => {
const out2 = $("mt-vacuum-out"); out2.textContent = "working";
try { const r = await post({op: "vacuum", retain: +$("mt-retain").value, dry_run: dry});
out2.textContent = `${dry ? "would free" : "freed"} ${fmtB(r.bytes_freed)} · ${r.files_removed} files · ${r.ms} ms`;
if (!dry) selectStore(CUR.key, true);
} catch (e) { out2.innerHTML = `<span class="err">${esc(e.message)}</span>`; }
};
$("mt-vacuum-dry").onclick = vac(true); $("mt-vacuum").onclick = vac(false);
$("mt-del").onclick = async () => {
if (!confirm("Delete rows in this time range? Earlier versions keep the data until vacuum.")) return;
const out2 = $("mt-del-out"); out2.textContent = "working";
try { const r = await post({op: "delete_range", table: $("mt-del-tbl").value,
t0: Math.round(CUR.min_ts + +$("mt-del-t0").value * 1e9),
t1: Math.round(CUR.min_ts + +$("mt-del-t1").value * 1e9)});
out2.textContent = `deleted ${r.rows_deleted.toLocaleString()} rows · ${r.files_rewritten} rewritten · ${r.ms} ms`;
selectStore(CUR.key, true);
} catch (e) { out2.innerHTML = `<span class="err">${esc(e.message)}</span>`; }
};
}
async function buildIx(btn, spec) {
btn.disabled = true; const old = btn.textContent; btn.textContent = "building";
try {
const r = await j("/api/build_index", {method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({store: CUR.key, ...spec})});
btn.textContent = `done · ${r.ms} ms`;
setTimeout(loadOps, 700);
} catch (e) { btn.textContent = "failed"; btn.title = e.message;
btn.disabled = false; setTimeout(() => btn.textContent = old, 1500); }
}
/* view routing */
function routeView(v) {
if (v === "map") loadMap();
if (v === "arch") loadArch();
if (v === "geo") drawGeo();
if (v === "data") loadData();
if (v === "ops") loadOps();
if (v === "analytics") loadAnalytics();
if (v === "overview") renderOverview();
}
document.querySelectorAll("#views button").forEach(b =>
b.addEventListener("click", () => {
document.querySelectorAll("#views button").forEach(x =>
x.classList.toggle("on", x === b));
document.querySelectorAll(".view").forEach(v => v.classList.remove("on"));
$("v-" + b.dataset.v).classList.add("on");
routeView(b.dataset.v);
}));
matchMedia("(prefers-color-scheme: dark)").addEventListener("change", () => {
drawScatter(); drawGeo(); });
addEventListener("resize", () => { clearTimeout(window._rz);
window._rz = setTimeout(() => { if (MAP) drawScatter(); drawGeo(); }, 150); });
/* read-only deployments have no operations surface at all */
j("/api/version").then(v => {
if (v.readonly)
document.querySelector('#views button[data-v="ops"]').style.display = "none";
}).catch(() => {});
loadStores();
</script>
<style>
/* architecture schematic */
#v-arch { position:relative; padding:0;
height:calc(100vh - 118px); min-height:480px; }
#arch-seg { position:absolute; top:8px; left:12px; z-index:6; }
#arch-pane-db { position:absolute; inset:44px 0 0 0; overflow:auto;
padding:0 14px 24px; background:#11151c; }
/* never shrink below legibility: scroll the pane instead of scaling the
diagram down until the labels are unreadable */
#db-svg { display:block; width:1400px; min-width:1400px; }
#db-info { position:sticky; bottom:0; margin-top:10px;
background:rgba(13,17,23,.96); border:1px solid var(--line);
border-radius:4px; padding:9px 12px; font:12px/1.65 var(--mono);
color:#dce8f2; max-width:110ch; }
#db-info b { color:var(--accent); letter-spacing:.06em; }
text.db-lane { fill:#9fb4c8; font:600 10px var(--mono);
letter-spacing:.11em; }
text.db-t { fill:#ffffff; font:600 12px var(--mono); }
text.db-s { fill:#cfe0ee; font:11px var(--mono); }
.db-node rect { transition:filter .12s; }
.db-node:hover rect { filter:brightness(1.55); }
rect.db-b { stroke-width:1; }
rect.db-l0 { fill:#10161f; stroke:#3a4756; } /* lake */
rect.db-l1 { fill:#131b26; stroke:#4a6076; } /* store */
rect.db-l2 { fill:#16212c; stroke:#7fb0ff; } /* table */
rect.db-l3 { fill:#152430; stroke:#5accb9; } /* file */
rect.db-l4 { fill:#13282a; stroke:#5accb9; } /* rowgrp*/
rect.db-l5 { fill:#1b2320; stroke:#7f9a6b; } /* chunk */
rect.db-l6 { fill:#222417; stroke:#b0a85f; } /* page */
rect.db-l7 { fill:#2a2418; stroke:#c99a5b; } /* value */
rect.db-commitband { fill:#241f2e; stroke:#a07fd4; }
rect.db-footerband { fill:#1a2733; stroke:#7fb0ff; stroke-dasharray:3 2; }
rect.db-prune { fill:#2a2418; stroke:#c99a5b; }
.an-train { fill:#1d2a24; stroke:#5accb9; stroke-width:1; }
#db-head { padding:4px 0 8px; }
#db-info .mk { color:#a07fd4; }
path.db-link { fill:none; stroke:#4a6076; stroke-width:1; opacity:.5; }
#arch-pane-model { position:absolute; inset:44px 0 0 0; }
/* database pane: dense, monospaced, built to be read out loud */
.dbsec { margin:16px 0 6px; font:600 11px/1.5 var(--mono);
letter-spacing:.09em; text-transform:uppercase; color:var(--accent); }
.dbnote { font:11px/1.6 var(--mono); color:var(--dim); max-width:96ch;
margin:0 0 8px; }
table.dbt { border-collapse:collapse; font:11px/1.5 var(--mono);
width:100%; margin:4px 0 10px; }
table.dbt th { text-align:left; color:var(--dim); font-weight:500;
border-bottom:1px solid var(--line); padding:3px 8px 3px 0;
white-space:nowrap; }
table.dbt td { padding:2px 8px 2px 0; border-bottom:1px solid
rgba(120,150,170,.07); white-space:nowrap; }
table.dbt td.n, table.dbt th.n { text-align:right;
font-variant-numeric:tabular-nums; }
.dbbar { display:inline-block; height:8px; background:var(--accent);
vertical-align:middle; border-radius:1px; }
.dbbar.cold { background:#3a4756; }
.dbkpi { display:flex; gap:26px; flex-wrap:wrap; margin:6px 0 12px; }
.dbkpi div { font:11px/1.4 var(--mono); color:var(--dim); }
.dbkpi b { display:block; font:600 19px/1.3 var(--mono); color:var(--ink);
font-variant-numeric:tabular-nums; }
.byrow { display:grid; grid-template-columns:78px 1fr 132px 2fr;
gap:10px; align-items:center; margin:5px 0;
font:11px/1.5 var(--mono); }
.bylab { font-weight:600; text-transform:uppercase; letter-spacing:.07em; }
.bybar { height:12px; background:rgba(120,150,170,.10); border-radius:2px;
overflow:hidden; }
.bybar i { display:block; height:100%; }
.byval { text-align:right; color:var(--ink);
font-variant-numeric:tabular-nums; }
.byval span { color:var(--dim); }
.bynote { color:var(--dim); font:10.5px/1.55 var(--mono); }
.b-live { color:#5accb9; background:#5accb9; }
.b-orph { color:#c99a5b; background:#c99a5b; }
.b-media { color:#7fb0ff; background:#7fb0ff; }
.b-cache { color:#a07fd4; background:#a07fd4; }
.bylab.b-live, .bylab.b-orph, .bylab.b-media, .bylab.b-cache
{ background:transparent; }
.dbpath { color:var(--ink); background:rgba(120,150,170,.10);
padding:1px 5px; border-radius:2px; }
button.mini { border:1px solid var(--line); background:transparent;
color:var(--muted); font:11px/1.4 var(--mono); padding:2px 7px;
border-radius:3px; cursor:pointer; margin:0 2px 3px 0; }
button.mini:hover { color:var(--ink); }
button.mini.on { background:var(--accent); color:#0d1117;
border-color:var(--accent); }
#arch-wrap { position:absolute; inset:0; overflow:hidden; background:#11151c; }
#arch-wrap::before { content:""; position:absolute; inset:0;
background-image:
linear-gradient(rgba(120,150,170,.06) 1px, transparent 1px),
linear-gradient(90deg, rgba(120,150,170,.06) 1px, transparent 1px),
linear-gradient(rgba(120,150,170,.03) 1px, transparent 1px),
linear-gradient(90deg, rgba(120,150,170,.03) 1px, transparent 1px);
background-size:120px 120px, 120px 120px, 24px 24px, 24px 24px;
pointer-events:none; }
#arch-svg { width:100%; height:100%; cursor:grab; display:block; }
#arch-svg:active { cursor:grabbing; }
#arch-svg text { font-family:ui-monospace, "SF Mono", Menlo, monospace; }
.an-card { fill:#171c25; stroke:#39424f; stroke-width:1.2; rx:3; }
.an-card.sel { stroke:#5accb9; stroke-width:2; }
.an-head { fill:#1e242f; }
.an-title { fill:#e3e8ee; font-size:12.5px; font-weight:700;
letter-spacing:.04em; }
.an-kind { font-size:8.5px; letter-spacing:.14em; }
.an-stat { fill:#8b96a4; font-size:9.5px; }
.an-field-n { fill:#b4bec9; font-size:9.5px; }
.an-field-t { fill:#68727e; font-size:9.5px; }
.an-badge { fill:#12261f; stroke:#265c4c; }
.an-badge-t { fill:#5accb9; font-size:8px; letter-spacing:.08em; }
.an-lane { fill:#535e6b; font-size:10px; letter-spacing:.35em; opacity:.85; }
.an-lane-rule { stroke:#2a323d; stroke-dasharray:2 6; }
.an-trace { stroke:#46525f; stroke-width:1.3; fill:none; }
.an-flow { stroke:#3fb9a5; stroke-width:1.3; fill:none;
stroke-dasharray:3 9; animation:an-dash 1.6s linear infinite; opacity:.7; }
@keyframes an-dash { to { stroke-dashoffset:-12; } }
@media (prefers-reduced-motion: reduce) { .an-flow { animation:none; } }
.an-elabel { fill:#68727e; font-size:8.5px; }
.an-chan { fill:#171c25; stroke:#39424f; }
.an-chan-t { fill:#9fded1; font-size:10px; font-weight:600; }
.an-chan-n { fill:#68727e; font-size:8.5px; }
.an-stage { fill:#171c25; stroke:#3fb9a5; }
/* the panel now carries the elements, the models and the training
loop, so it needs to scroll and to keep clear of the pan hint */
#arch-title { position:absolute; right:18px; bottom:36px; top:14px;
width:430px; overflow:auto; pointer-events:auto;
border:1px solid #39424f; background:rgba(17,21,28,.96);
font-family:ui-monospace, Menlo, monospace; color:#b8c4d2;
font-size:11px; line-height:1.6; padding:9px 13px; }
#arch-title b { color:#e3e8ee; font-size:11.5px; letter-spacing:.12em; }
#arch-title .rule { border-top:1px solid #2a323d; margin:5px -12px; }
#arch-hint { position:absolute; left:18px; bottom:16px; color:#535e6b;
font:10px ui-monospace, Menlo, monospace; pointer-events:none; }
#arch-detail { position:absolute; top:14px; right:14px; width:340px;
max-height:calc(100% - 90px); overflow:auto; display:none;
border:1px solid #39424f; background:rgba(17,21,28,.97);
font-family:ui-monospace, Menlo, monospace; font-size:11px;
color:#b4bec9; padding:12px 14px; }
#arch-detail.on { display:block; }
#arch-detail h4 { margin:0 0 4px; color:#5accb9; font-size:13px; }
#arch-detail table { width:100%; border-collapse:collapse; margin:6px 0; }
#arch-detail td { padding:1.5px 4px 1.5px 0;
border-bottom:1px solid #232a34; vertical-align:top; }
#arch-detail td:last-child { color:#68727e; text-align:right; }
#arch-detail pre { background:#10141a; border:1px solid #232a34;
padding:6px; overflow:auto; font-size:10px; color:#8b96a4; }
#arch-detail .x { position:sticky; float:right; top:0; cursor:pointer;
color:#68727e; }
</style>
<script>
let ARCH = null, DBI = null, DBI_TABLE = null;
/* one explanation surface for the model pane, mirroring db-info:
click a channel or a stage and read what it is and why it is there */
function archNote(title, id, note) {
const d = $("arch-detail");
d.className = "on";
d.innerHTML = `<h4>${esc(title)}</h4>` +
`<div style="color:#8fa3b8;font:10px var(--mono);margin-bottom:6px">` +
`id ${esc(id || "")}</div>` +
`<div style="line-height:1.65">${esc(note || "")}</div>`;
}
async function loadArch() {
if (!ARCH) ARCH = await j(`/api/architecture?store=${CUR.key}`);
drawArch();
await loadDb();
document.querySelectorAll("#arch-seg button").forEach(b => b.onclick = () => {
document.querySelectorAll("#arch-seg button").forEach(x =>
x.classList.toggle("on", x === b));
const db = b.dataset.p === "db";
$("arch-pane-db").style.display = db ? "" : "none";
$("arch-pane-model").style.display = db ? "none" : "";
if (!db) {
// the pane was display:none on first draw, so getBBox() returned
// zeros and the fit was skipped - fit once, now that it is visible
const sv = $("arch-svg");
if (!sv._fitted) { sv._view = null; sv._fitted = true; }
drawArch();
}
});
}
async function loadDb(table) {
const q = table ? `&table=${encodeURIComponent(table)}` : "";
DBI = await j(`/api/dbinternals?store=${CUR.key}${q}`);
DBI_TABLE = DBI.table;
drawDb();
}
/* DATABASE ENGINE, DRAWN. Five lanes left to right, every box sized and
populated from THIS store right now: store -> meta files -> tables ->
(log commits + parquet files) -> pages -> column chunks. Hover any box
for what it is and why it exists. */
const DB_DOC = {
store: ["STORE", "A directory. No server, no daemon, no custom byte "
+ "format outside the media itself. Everything is Parquet under a "
+ "transaction log, so another engine can read it directly."],
meta: ["META FILE", "Sidecar state next to the tables. Authoritative "
+ "(_store.json), fitted artifact (_set_weights.json), cache "
+ "(_vocab.json, grown lazily per new word) or disposable (_cache/, "
+ "deleting it costs recompute time, never correctness)."],
tables: ["TABLES", "One directory per table, each with its OWN commit "
+ "log. Every table must carry ts (int64 ns) sorted within a file - "
+ "the single schema law, and what makes time the primary axis."],
table: ["TABLE", "State is the fold of its log, not the files in the "
+ "directory. Height here is proportional to bytes on disk."],
log: ["COMMIT LOG", "Append-only JSON commits. Version N is immutable "
+ "forever (snapshot isolation + time travel), a multi-file load "
+ "lands as ONE entry (atomicity), and the lock is O_EXCL on the "
+ "next filename - single writer, many readers, no coordinator."],
commit: ["COMMIT", "One manifest entry: op, schema, and the file list "
+ "with zone maps. op=replace removes the old file set in the same "
+ "commit that adds the new one - it exists because appending a "
+ "rebuild once doubled the events table to 16,526 rows silently."],
file: ["PARQUET FILE", "Immutable, never edited in place. Its "
+ "min_ts/max_ts live in the COMMIT ENTRY, so a time-window query "
+ "drops the whole file before opening a single footer. That is "
+ "prune layer 1, and it costs zero I/O against the data."],
page: ["ROW GROUP (page)", "A page carries its own ts statistics, so "
+ "groups outside the window are never decompressed - prune layer "
+ "2. Sized by BYTES (8 MB target) not by row count, or a 1152-d "
+ "vector table emits groups nobody can skip inside. This is the "
+ "random-access vs compression tension the Lance paper is about."],
chunk: ["COLUMN CHUNK", "Each column is stored separately inside the "
+ "page, so a projection touches only the columns it asked for. "
+ "Width here is the compressed size."],
prune: ["PUSHDOWN, EXECUTED", "A real scan run just now. bytes_touched "
+ "is charged as footer + overlapping row groups + projected column "
+ "chunks - the same arithmetic the reader performs, not an "
+ "estimate. Every read goes through the counter, which is what "
+ "makes the elision number honest."],
media: ["MEDIA", "Store-managed renditions. Raw sources are NEVER "
+ "copied in: a frames row whose source starts with @ is managed, "
+ "anything else is an external reference-in-place. The store is an "
+ "index over your video, not a second copy of it."],
frames: ["FRAME INDEX", "Not frames - (ts, byte_offset, packet_size, "
+ "keyframe, codec, source, stream), one row per frame pointing INTO "
+ "a media file. Pixels are produced last, from byte ranges, only "
+ "for rows that survived every prune. Late materialization."],
};
function dbInfo(kind, extra) {
const d = DB_DOC[kind]; if (!d) return;
$("db-info").innerHTML = `<b>${d[0]}</b>${extra ? " · " + extra : ""}
<div class="rule"></div>${d[1]}`;
}
function drawDb() {
const d = DBI, P = d.prune || {}, L = d.ladder || [];
const by = {}; L.forEach(x => by[x.id] = x);
const NS = "http://www.w3.org/2000/svg";
$("arch-pane-db").innerHTML =
`<div id="db-head"></div><svg id="db-svg"><g id="db-cam"></g></svg>
<div id="db-info"></div>`;
const cam = $("db-cam");
const el = (t, a, parent) => { const e = document.createElementNS(NS, t);
for (const k in a) e.setAttribute(k, a[k]);
(parent || cam).appendChild(e); return e; };
const txt = (x, y, s, cls, parent, anchor) => {
const e = el("text", { x, y, class: cls }, parent);
if (anchor) e.setAttribute("text-anchor", anchor);
e.textContent = s; return e; };
/* table picker */
$("db-head").innerHTML = d.tables.map(t =>
`<button class="mini${t === d.table ? " on" : ""}"
onclick="loadDb('${t}')">${esc(t)}</button>`).join(" ");
/* CONTAINMENT. Each rung physically encloses the next, because that
is the actual relationship: a value lives in a page, which lives in
a column chunk, which lives in a row group, which lives in a file,
which a commit lists, which a table folds, which a store holds. */
const W = 1400, PAD = 21, HEAD = 30;
const levels = ["lake", "store", "table", "file", "rowgroup",
"chunk", "page", "value"];
const hover = (r, id) => {
r.addEventListener("mouseenter", () => {
const x = by[id]; if (!x) return;
$("db-info").innerHTML =
`<b>${esc(x.label)}</b> &nbsp;<span style="color:var(--ink)">
${esc(x.n)}</span> &nbsp;<span>${esc(x.sub)}</span>
<div class="rule"></div>
<div><span class="mk">metadata:</span> ${esc(x.meta)}</div>
<div style="margin-top:5px">${esc(x.why)}</div>`;
});
};
const N = levels.length;
// bottoms stagger by BSTEP so each nested box visibly ends inside its
// parent - without it the TABLE and the FILE ended within 6px of each
// other and their two bands (commit, footer) drew on top of one another
const BSTEP = 26, BASE = 14 + N * (HEAD + 6) + 150;
const H = BASE + 14;
let bandY = [];
levels.forEach((id, i) => {
const x = PAD + i * PAD, w = W - 2 * (PAD + i * PAD);
const y = 14 + i * (HEAD + 6);
const h = (BASE - i * BSTEP) - y;
const g = el("g", { class: "db-node" });
const r = el("rect", { x, y, width: w, height: h, rx: 4,
class: "db-b db-l" + i }, g);
hover(r, id);
const it = by[id] || {};
txt(x + 11, y + 19, it.label || id.toUpperCase(), "db-t", g);
// right-hand stats are anchored to the right edge, so an over-long
// string grows leftward and collides with the label - cap it
const stat = `${it.n || ""} ${it.sub || ""}`;
txt(x + w - 11, y + 19, stat.length > 62 ? stat.slice(0, 61) + "…" : stat,
"db-s", g, "end");
bandY.push({ x, y, w, h });
});
/* the two things that hang OFF the ladder rather than inside it:
the commit log (sibling of the files, inside the table) and the
footer (inside the file, after the row groups) */
const tb = bandY[2], fb = bandY[3];
const cg = el("g", { class: "db-node" });
const cr = el("rect", { x: tb.x + 12, y: tb.y + tb.h - 34,
width: tb.w - 24, height: 26, rx: 3, class: "db-b db-commitband" }, cg);
hover(cr, "commit");
const lc = by["commit"] || {}, ll = by["log"] || {};
txt(tb.x + 22, tb.y + tb.h - 16,
`${lc.label || "COMMIT"}${lc.n || ""} · ${ll.sub || ""}`,
"db-s", cg);
txt(tb.x + tb.w - 22, tb.y + tb.h - 16,
`${lc.sub || ""}`, "db-s", cg, "end");
const fg = el("g", { class: "db-node" });
const fr = el("rect", { x: fb.x + 12, y: fb.y + fb.h - 34,
width: fb.w - 24, height: 26, rx: 3, class: "db-b db-footerband" }, fg);
hover(fr, "footer");
const ft = by["footer"] || {};
txt(fb.x + 22, fb.y + fb.h - 16,
`${ft.label || "FOOTER"}${ft.n || ""} · ${ft.meta || ""}`,
"db-s", fg);
/* pushdown badge, measured, sitting under the ladder */
if (P && !P.error) {
const y = H + 6;
const g = el("g", { class: "db-node" });
const r = el("rect", { x: PAD, y, width: W - 2 * PAD, height: 42,
rx: 4, class: "db-b db-prune" }, g);
hover(r, "prune");
txt(PAD + 12, y + 18, "PREDICATE PUSHDOWN · executed now", "db-t", g);
txt(PAD + 12, y + 33,
`layer 1 (commit zone maps): ${P.files_touched}/${P.files_total} ` +
`files kept · layer 2 (row-group stats + projection): ` +
`${fmtB(P.bytes_touched)} read of ${fmtB(P.corpus_bytes)} · ` +
`${fmtN(P.rows_returned)} rows · ${P.elided_pct}% elided` +
(d.n_row_groups <= 1 ? " (one row group — nothing to prune)" : ""),
"db-s", g);
}
const TOT = H + 60;
const svg = $("db-svg");
svg.setAttribute("viewBox", `0 0 ${W} ${TOT}`);
svg.style.height = TOT + "px";
$("db-info").innerHTML =
`<b>Hover any layer.</b> The ladder reads bottom-up: a VALUE lives
in a PAGE, pages make a COLUMN CHUNK, chunks make a ROW GROUP,
groups make a FILE, a COMMIT lists files, the TABLE is the fold of
its commits, the STORE holds tables, the LAKE holds stores.`;
}
function archLane(n) {
if (n.kind === "media") return 0;
if (n.kind === "model") return 3;
if (["centroids"].includes(n.id)) return 3;
if (n.kind === "embeddings") return 2;
return 1;
}
const AN_LANES = ["MEDIA", "RAW TABLES", "VECTOR TABLES", "ARTIFACTS"];
const AN_KINDC = { media:"#c99a5b", timeseries:"#7fb0ff",
embeddings:"#5accb9", model:"#d98fd4",
frame_index:"#7fb0ff" };
function fmtTs(ns) { return ns == null ? "" :
new Date(ns / 1e6).toISOString().slice(0, 19).replace("T", " "); }
function drawArch() {
const svg = $("arch-svg"), cam = $("arch-cam");
cam.innerHTML = "";
const NS = "http://www.w3.org/2000/svg";
const el = (t, a, parent) => { const e = document.createElementNS(NS, t);
for (const k in a) e.setAttribute(k, a[k]);
(parent || cam).appendChild(e); return e; };
const txt = (x, y, s, cls, parent, anchor) => {
const e = el("text", { x, y, class: cls }, parent);
if (anchor) e.setAttribute("text-anchor", anchor);
e.textContent = s; return e; };
const LANE_X = [40, 330, 660, 990], LANE_W = 250, PIPE_X = 1330;
const laneY = [70, 70, 70, 70];
const pos = {};
const byLane = [[], [], [], []];
ARCH.nodes.forEach(n => byLane[archLane(n)].push(n));
byLane.forEach(l => l.sort((a, b) => (b.bytes || 0) - (a.bytes || 0)));
const g_edges = el("g", {}), g_nodes = el("g", {});
byLane.forEach((lane, li) => {
txt(LANE_X[li], 40, AN_LANES[li], "an-lane");
el("line", { x1: LANE_X[li] - 20, y1: 50, x2: LANE_X[li] - 20,
y2: 1400, class: "an-lane-rule" });
lane.forEach(n => {
const fields = (n.fields || []).slice(0, 7);
const h = 46 + fields.length * 13 +
((n.sidecars || []).length || n.meta_json ? 18 : 6);
const g = el("g", { class: "an-node", "data-id": n.id,
transform: `translate(${LANE_X[li]},${laneY[li]})` },
g_nodes);
pos[n.id] = { x: LANE_X[li], y: laneY[li], w: LANE_W, h };
laneY[li] += h + 26;
el("rect", { width: LANE_W, height: h, class: "an-card" }, g);
el("rect", { width: LANE_W, height: 22, class: "an-head" }, g);
el("rect", { width: 3, height: h,
fill: AN_KINDC[n.kind] || "#7fb0ff" }, g);
txt(10, 15, n.id.replace("model:", ""), "an-title", g);
const kt = txt(LANE_W - 8, 14, n.kind.toUpperCase(), "an-kind", g,
"end");
kt.setAttribute("fill", AN_KINDC[n.kind] || "#7fb0ff");
txt(10, 36, (n.rows != null ? fmtN(n.rows) + " rows · " : "") +
fmtB(n.bytes || 0) +
(n.files != null ? ` · ${n.files}f` : "") +
(n.version ? ` · v${n.version}` : ""), "an-stat", g);
fields.forEach((f, i) => {
txt(12, 52 + i * 13, f.name, "an-field-n", g);
txt(LANE_W - 10, 52 + i * 13, f.type.length > 18 ?
f.type.slice(0, 17) + ".." : f.type, "an-field-t", g, "end");
});
let bx = 10;
const by = 46 + fields.length * 13 + 2;
const badge = (s) => {
const w = s.length * 5.4 + 10;
el("rect", { x: bx, y: by - 9, width: w, height: 12, rx: 6,
class: "an-badge" }, g);
txt(bx + w / 2, by, s, "an-badge-t", g, "middle");
bx += w + 6; };
if ((n.sidecars || []).length) badge("MMAP x" + n.sidecars.length);
if (n.meta_json) badge("META");
g.style.cursor = "pointer";
});
});
ARCH.edges.forEach(e => {
const a = pos[e.from], b = pos[e.to];
if (!a || !b) return;
const x1 = a.x + a.w, y1 = a.y + 22, x2 = b.x, y2 = b.y + 22;
const mx = (x1 + x2) / 2;
const d = `M${x1},${y1} C${mx},${y1} ${mx},${y2} ${x2},${y2}`;
el("path", { d, class: "an-trace" }, g_edges);
el("path", { d, class: "an-flow" }, g_edges);
txt(mx, (y1 + y2) / 2 - 5, e.label || "", "an-elabel", g_edges,
"middle");
});
/* query pipeline: channels feed the fitted selection chain */
txt(PIPE_X, 40, "QUERY PIPELINE", "an-lane");
el("line", { x1: PIPE_X - 20, y1: 50, x2: PIPE_X - 20, y2: 1400,
class: "an-lane-rule" });
let cy = 70;
const CH_W = 190, ST_X = PIPE_X + CH_W + 90;
ARCH.channels.forEach(c => {
const g = el("g", { transform: `translate(${PIPE_X},${cy})` });
const cr = el("rect", { width: CH_W, height: 34, rx: 3,
class: "an-chan" }, g);
txt(10, 14, c.label, "an-chan-t", g);
txt(10, 26, (c.note || "").slice(0, 46), "an-chan-n", g);
txt(CH_W - 8, 14, c.id, "an-kind", g, "end");
// click any block for the full explanation, same as the DB pane
cr.style.cursor = "pointer";
cr.onclick = () => archNote("CHANNEL · " + c.label, c.id, c.note);
const y = cy + 17;
const d = `M${PIPE_X + CH_W},${y} C${PIPE_X + CH_W + 45},${y} ` +
`${PIPE_X + CH_W + 45},${92} ${ST_X},${92}`;
el("path", { d, class: "an-trace" }, g_edges);
el("path", { d, class: "an-flow" }, g_edges);
cy += 46;
});
let sy = 70;
const F = ARCH.fitted || {};
const stageNote = {
fuse: F.set_weights ? "per-store weights, holdout " + (F.loqo_mean ?? "") : null,
cut: F.cut_alpha != null ? `alpha ${F.cut_alpha_dir ?? 0} dir · ${F.cut_alpha} other` : null,
nms: F.nms_r_dir != null ? `radius ${F.nms_r_dir} dir · ${F.nms_r ?? 0} other` : null,
};
let prev = null;
ARCH.pipeline.forEach(p => {
const g = el("g", { transform: `translate(${ST_X},${sy})` });
const sr = el("rect", { width: 150, height: 44, rx: 3,
class: "an-stage" }, g);
txt(10, 18, p.label, "an-chan-t", g);
txt(10, 32, (stageNote[p.id] || p.note || "").slice(0, 26),
"an-chan-n", g);
sr.style.cursor = "pointer";
sr.onclick = () => archNote("STAGE · " + p.label, p.id,
stageNote[p.id] || p.note);
if (prev != null) {
const x = ST_X + 75;
const d = `M${x},${prev + 44} L${x},${sy}`;
el("path", { d, class: "an-trace" }, g_edges);
el("path", { d, class: "an-flow" }, g_edges);
}
prev = sy;
sy += 66;
});
/* the five elements: what a clip is decomposed into. Rendered only
when this store actually carries them, so an un-elemented store
shows nothing rather than a promise. */
const els = ARCH.elements || [];
const elemHtml = els.length ? (
`<div class="rule"></div><b>FIVE ELEMENTS</b><br>` +
els.map(e => `${esc(e.label)}&nbsp;<span style="opacity:.6">` +
`${fmtN(e.n)}</span><br><span style="opacity:.55;font-size:10px">` +
`${esc(e.note)}</span>`).join("<br>")) : "";
const mods = ARCH.models || [];
const modHtml = mods.length ? (
`<div class="rule"></div><b>MODELS</b><br>` +
mods.map(m => {
const head = m.kind === "teacher"
? `${esc(m.id)} · yield ${m.yield} / prec ${m.prec}`
: `${esc(m.id)} · ${m.params_M}M · ${m.read_ms}ms read · ` +
`${m.write_s_per_demo}s/demo write`;
const env = m.env && Object.keys(m.env).length
? `<br><span style="opacity:.55;font-size:10px">env ` +
Object.entries(m.env).map(([k, v]) => `${esc(k)}=${esc(String(v))}`)
.join(" ") + `</span>` : "";
return `${head}${env}<br><span style="opacity:.55;font-size:10px">` +
`${esc(m.note)}</span>`;
}).join("<br>")) : "";
/* TRAINING / RETRAINING LOOP — drawn as a cycle, because it is one:
serving produces no labels, but more DATA widens the corpus
statistics the whole system is built on, and re-running teacher →
distill is the retrain. Click a step for what it does. */
const TR = ARCH.training || [];
if (TR.length) {
// BELOW WHATEVER THE LANES ACTUALLY REACH. A fixed y collided with
// the RAW TABLES lane, whose height depends on how many tables the
// store has - the one thing that varies per store.
const TY = Math.max(...laneY, cy, sy) + 78, TW = 230, TG = 26;
txt(LANE_X[0], TY - 22, "TRAINING / RETRAINING LOOP", "an-lane");
TR.forEach((t, i) => {
const x = LANE_X[0] + i * (TW + TG);
const g = el("g", { transform: `translate(${x},${TY})` });
const r = el("rect", { width: TW, height: 46, rx: 3,
class: "an-train" }, g);
r.style.cursor = "pointer";
r.onclick = () => archNote(t.label, t.id, t.note);
txt(10, 18, t.label, "an-chan-t", g);
txt(10, 33, (t.note || "").slice(0, 34) + "…", "an-chan-n", g);
if (i) {
const d0 = `M${x - TG},${TY + 23} L${x},${TY + 23}`;
el("path", { d: d0, class: "an-trace" }, g_edges);
el("path", { d: d0, class: "an-flow" }, g_edges);
}
});
// the loop closes: step 6 feeds step 3 again
const x0 = LANE_X[0] + (TR.length - 1) * (TW + TG) + TW / 2;
const x1 = LANE_X[0] + 2 * (TW + TG) + TW / 2;
el("path", { class: "an-trace",
d: `M${x0},${TY + 46} C${x0},${TY + 96} ${x1},${TY + 96} ${x1},${TY + 46}` },
g_edges);
txt((x0 + x1) / 2, TY + 92, "more data → relabel → retrain",
"an-chan-n", g_edges, "middle");
}
const TRH = (ARCH.training || []).length ? (
`<div class="rule"></div><b>TRAINING / RETRAINING LOOP</b><br>` +
ARCH.training.map(t =>
`<span style="color:#5accb9">${esc(t.label)}</span><br>` +
`<span style="opacity:.62;font-size:10px">${esc(t.note)}</span>`)
.join("<br>") +
`<br><span style="color:#5accb9">↻ step 6 feeds step 3</span>` +
`<span style="opacity:.62;font-size:10px"> — nothing here needs ` +
`human annotation</span>`) : "";
$("arch-title").innerHTML =
`<b>ELIDEDB · STORE SCHEMATIC</b><div class="rule"></div>` +
`store&nbsp;&nbsp;&nbsp;${esc(ARCH.store)}<br>` +
`tables&nbsp;&nbsp;${ARCH.totals.tables} · ` +
`${fmtN(ARCH.totals.rows)} rows · ${fmtB(ARCH.totals.bytes)}<br>` +
`channels ${ARCH.channels.map(c => c.id).join(" · ")}` +
elemHtml + modHtml + TRH +
`<div class="rule"></div>drawn from live state · ` +
new Date().toISOString().slice(0, 16).replace("T", " ");
// FIT THE WHOLE SCHEMATIC ON FIRST DRAW. The fixed 0.82 zoom left the
// training loop (drawn below the lanes) off screen entirely, so the
// one part that explains how the models are PRODUCED was invisible
// unless you knew to pan for it.
let view = svg._view;
if (!view) {
view = { x: 0, y: 0, k: 0.82 };
try {
const bb = cam.getBBox(), r = svg.getBoundingClientRect();
if (bb.width && bb.height && r.width && r.height) {
view.k = Math.max(0.45, Math.min(r.width / (bb.width + 60),
r.height / (bb.height + 60), 1));
view.x = 24 - bb.x * view.k;
view.y = 16 - bb.y * view.k;
}
} catch (e) { /* keep the default */ }
}
svg._view = view;
const apply = () => cam.setAttribute("transform",
`translate(${view.x},${view.y}) scale(${view.k})`);
apply();
svg.onwheel = (ev) => { ev.preventDefault();
const r = svg.getBoundingClientRect();
const px = ev.clientX - r.left, py = ev.clientY - r.top;
const k2 = Math.min(3, Math.max(.15,
view.k * (ev.deltaY < 0 ? 1.12 : 0.89)));
view.x = px - (px - view.x) * k2 / view.k;
view.y = py - (py - view.y) * k2 / view.k;
view.k = k2; apply(); };
let drag = null;
svg.onpointerdown = (ev) => {
const nodeG = ev.target.closest(".an-node");
drag = { px: ev.clientX, py: ev.clientY, node: nodeG,
vx: view.x, vy: view.y };
if (nodeG) { const p = pos[nodeG.dataset.id];
drag.nx = p.x; drag.ny = p.y; }
svg.setPointerCapture(ev.pointerId); };
svg.onpointermove = (ev) => { if (!drag) return;
const dx = ev.clientX - drag.px, dy = ev.clientY - drag.py;
if (drag.node) {
const p = pos[drag.node.dataset.id];
p.x = drag.nx + dx / view.k; p.y = drag.ny + dy / view.k;
drag.node.setAttribute("transform", `translate(${p.x},${p.y})`);
drag.moved = (Math.abs(dx) + Math.abs(dy)) > 3;
if (drag.moved) redrawEdges();
} else { view.x = drag.vx + dx; view.y = drag.vy + dy; apply(); } };
function redrawEdges() {
g_edges.querySelectorAll(".an-trace, .an-flow, .an-elabel")
.forEach(e => e.remove());
ARCH.edges.forEach(e => {
const a = pos[e.from], b = pos[e.to];
if (!a || !b) return;
const x1 = a.x + a.w, y1 = a.y + 22, x2 = b.x, y2 = b.y + 22;
const mx = (x1 + x2) / 2;
const d = `M${x1},${y1} C${mx},${y1} ${mx},${y2} ${x2},${y2}`;
el("path", { d, class: "an-trace" }, g_edges);
el("path", { d, class: "an-flow" }, g_edges);
txt(mx, (y1 + y2) / 2 - 5, e.label || "", "an-elabel", g_edges,
"middle");
}); }
svg.onpointerup = (ev) => {
if (drag && drag.node && !drag.moved) archSelect(drag.node.dataset.id);
drag = null; };
svg.ondblclick = () => { view.x = 0; view.y = 0; view.k = 0.82; apply(); };
}
function archSelect(id) {
const n = ARCH.nodes.find(x => x.id === id);
if (!n) return;
document.querySelectorAll(".an-card").forEach(c =>
c.classList.remove("sel"));
const g = document.querySelector(`.an-node[data-id="${CSS.escape(id)}"]`);
if (g) g.querySelector(".an-card").classList.add("sel");
let h = `<span class="x" onclick="$('arch-detail').classList.remove('on')">x</span>` +
`<h4>${esc(n.id)}</h4>` +
`<div>${n.kind} · ${n.rows != null ? fmtN(n.rows) + " rows · " : ""}` +
`${fmtB(n.bytes || 0)}${n.files != null ? " · " + n.files + " files" : ""}` +
`${n.version ? " · " + n.version + " commits" : ""}</div>` +
`<div style="color:#68727e">${fmtTs(n.min_ts)} to ${fmtTs(n.max_ts)}</div>`;
if ((n.fields || []).length) {
h += `<table>` + n.fields.map(f =>
`<tr><td>${esc(f.name)}</td><td>${esc(f.type)}</td></tr>`).join("") +
`</table>`;
}
if ((n.sidecars || []).length)
h += `<div>mmap sidecars:</div><pre>${esc(n.sidecars.join("\n"))}</pre>`;
if (n.meta && Object.keys(n.meta).length)
h += `<div>table meta:</div><pre>${esc(JSON.stringify(n.meta, null, 1))}</pre>`;
$("arch-detail").innerHTML = h;
$("arch-detail").classList.add("on");
}
</script>
</body>
</html>