// strata's page: the layers picture (one DOM lane per app), the reader line, and "look inside an app"
// (duckdb-wasm over the app's public parquet files). served by the worker at ui.js; talks to api/* relatively.
const fmt = new Intl.NumberFormat("en-US");
const compact = new Intl.NumberFormat("en-US", { notation: "compact", maximumFractionDigits: 1 });
const dayFmt = new Intl.DateTimeFormat("en-CA", { timeZone: "UTC", year: "numeric", month: "2-digit", day: "2-digit" });
const timeFmt = new Intl.DateTimeFormat("en-GB", { timeZone: "UTC", hour: "2-digit", minute: "2-digit" });
const STEPS = [1, 2, 5, 10, 25, 50, 100];
const FLOOR = 0.14;
const OTHER = "other";
const OTHER_LABEL = "everything else";
// the whole-network bootstrap ran 2026-07-28 → 2026-08-03 ~07:00 utc (stream /status: "backfill took 6d 2h")
const BOOTSTRAP_END_US = 1785740400000000;
const ERA_LABEL = { bootstrap: "history, replayed", live: "as it happened" };
function byId(id, ctor) {
const node = document.getElementById(id);
if (!(node instanceof ctor)) throw new Error(`missing #${id} (${ctor.name})`);
return node;
}
const el = {
layers: byId("layers", HTMLDivElement),
cursor: document.createElement("div"),
reader: byId("reader", HTMLDivElement),
lede: byId("lede", HTMLParagraphElement),
find: byId("find", HTMLInputElement),
nsList: byId("ns-list", HTMLDataListElement),
more: byId("more", HTMLButtonElement),
tableToggle: byId("table-toggle", HTMLButtonElement),
table: byId("table", HTMLDivElement),
live: byId("live", HTMLSpanElement),
updated: byId("updated", HTMLSpanElement),
legendBar: byId("legend-bar", HTMLSpanElement),
askNs: byId("ask-ns", HTMLSelectElement),
askSize: byId("ask-size", HTMLSpanElement),
askRun: byId("ask-run", HTMLButtonElement),
askEdit: byId("ask-edit", HTMLButtonElement),
askSql: byId("ask-sql", HTMLTextAreaElement),
askFine: byId("ask-fine", HTMLParagraphElement),
askOut: byId("ask-out", HTMLDivElement),
askTable: byId("ask-table", HTMLDivElement),
prompts: byId("prompts", HTMLDivElement),
};
const esc = (s) => String(s).replace(/[&<>"]/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """ }[c]));
const displayName = (key) => (key === OTHER ? OTHER_LABEL : key);
const shortName = (nsid) => nsid.slice(nsid.indexOf(".", nsid.indexOf(".") + 1) + 1);
// one hue, dark → light, with a floor so a cell with anything in it never fades into the empty tone
function shade(t) {
const u = FLOOR + (1 - FLOOR) * Math.max(0, Math.min(1, t));
return `oklch(${(0.27 + 0.66 * u).toFixed(3)} ${(0.045 + 0.08 * u * (1 - u)).toFixed(3)} 222)`;
}
const rowHeight = (count, maxCount) => Math.round(12 + 34 * (Math.log10(Math.max(1, count)) / Math.log10(Math.max(10, maxCount))));
async function api(path) {
const r = await fetch(path);
return r.json();
}
const view = { top: 10, expanded: new Map(), pinned: [], namespaces: [], step: 10 };
let picture = null; // { rows, buckets, step }
let hover = null; // { ri, bi }
async function loadProgress() {
const p = await api("api/progress");
el.lede.innerHTML = `strata — what's in the archive. every app on the network writes its own kinds of records; this is how much of each there is, and when it arrived. so far: ${compact.format(p.events)} records from ${fmt.format(p.namespaces)} apps, in ${fmt.format(p.collections)} record types.`;
if (p.updatedAt) {
const d = new Date(p.updatedAt);
const partial = p.archiveSegments && p.archiveSegments > p.segments;
el.live.innerHTML = partial
? `· showing the first ${fmt.format(p.segments)} of ${fmt.format(p.archiveSegments)} chunks — still reading`
: `· ${fmt.format(p.segments)} chunks read`;
el.updated.textContent = `updated ${dayFmt.format(d)} ${timeFmt.format(d)} utc`;
}
view.step = STEPS.find((s) => Math.ceil(p.segments / s) <= 120) ?? STEPS[STEPS.length - 1];
if (!view.namespaces.length) {
const { namespaces } = await api("api/namespaces");
view.namespaces = namespaces;
el.nsList.innerHTML = namespaces.map((n) => ``).join("");
el.askNs.innerHTML = `` + namespaces.filter((n) => n.ns !== "app.bsky").map((n) => ``).join("");
}
}
function seriesFor(cells, key, bucketIndex, n) {
const a = new Float64Array(n);
for (const c of cells) {
if (c.key !== key) continue;
const i = bucketIndex.get(c.bucket);
if (i !== undefined) a[i] += c.count;
}
return a;
}
async function load() {
await loadProgress();
const step = view.step;
const heat = await api(`api/heat?step=${step}&top=${view.top}`);
if (heat.error) {
el.reader.innerHTML = `${esc(heat.error)}`;
return;
}
const buckets = heat.buckets;
const bucketIndex = new Map(buckets.map((b, i) => [b.bucket, i]));
const keys = new Map(heat.keys.map((k) => [k.key, k]));
const order = heat.keys.map((k) => k.key);
const extra = view.pinned.filter((p) => !keys.has(p.ns));
const extraHeat = await Promise.all(extra.map((p) => api(`api/heat?step=${step}&ns=${p.ns}`)));
extra.forEach((p, i) => {
keys.set(p.ns, { key: p.ns, count: p.count, members: p.members, cells: extraHeat[i].cells });
order.push(p.ns);
});
if (heat.cells.some((c) => c.key === OTHER)) {
order.push(OTHER);
keys.set(OTHER, { key: OTHER, count: 0, members: 0 });
}
const rows = [];
for (const key of order) {
const k = keys.get(key);
const values = k.cells ? seriesFor(k.cells, key, bucketIndex, buckets.length) : seriesFor(heat.cells, key, bucketIndex, buckets.length);
const total = key === OTHER ? values.reduce((a, b) => a + b, 0) : k.count;
rows.push({ key, depth: 0, total, members: k.members, values, expandable: key !== OTHER && k.members > 1 });
const sub = view.expanded.get(key);
if (sub && sub.step === step) rows.push(...sub.rows);
}
picture = { rows, buckets, step };
for (const [key, sub] of view.expanded) if (sub.step !== step) expand(key);
render();
}
async function expand(key) {
const step = view.step;
const sub = await api(`api/heat?step=${step}&ns=${key}`);
const bucketIndex = new Map(sub.buckets.map((b, i) => [b.bucket, i]));
const rows = sub.keys.map((k) => ({ key: k.key, depth: 1, total: k.count, members: 1, values: seriesFor(sub.cells, k.key, bucketIndex, sub.buckets.length), expandable: false }));
view.expanded.set(key, { step, rows });
if (picture && picture.step === step) {
dropChildren(key);
const at = picture.rows.findIndex((r) => r.key === key && r.depth === 0);
if (at >= 0) picture.rows.splice(at + 1, 0, ...rows);
}
render();
}
function dropChildren(key) {
const at = picture.rows.findIndex((r) => r.key === key && r.depth === 0);
if (at < 0) return;
let end = at + 1;
while (end < picture.rows.length && picture.rows[end].depth === 1) end++;
picture.rows.splice(at + 1, end - at - 1);
}
function collapse(key) {
view.expanded.delete(key);
if (picture) dropChildren(key);
render();
}
const eraOf = (b) => (b.min_witnessed_at < BOOTSTRAP_END_US ? "bootstrap" : "live");
function render() {
if (!picture) return;
const { rows, buckets } = picture;
const n = buckets.length;
const maxTotal = Math.max(...rows.filter((r) => r.depth === 0).map((r) => r.total));
const maxPerRow = rows.map((r) => Math.max(0, ...r.values));
const lanes = rows.map((r, ri) => {
const h = Math.max(r.depth ? 11 : 12, rowHeight(r.total, maxTotal) - (r.depth ? 8 : 0));
const rects = [];
for (let bi = 0; bi < n; bi++) {
const v = r.values[bi];
if (v <= 0) continue;
rects.push(``);
}
const glyph = r.expandable ? (view.expanded.has(r.key) ? "▾" : "▸") : r.depth ? "·" : "";
const label = r.depth ? shortName(r.key) : displayName(r.key);
const expandAttr = r.expandable ? ` aria-expanded="${view.expanded.has(r.key)}"` : "";
return `
` +
`` +
`` +
`${compact.format(r.total)}
`;
});
const eras = [];
let start = 0;
for (let bi = 1; bi <= n; bi++) {
if (bi === n || eraOf(buckets[bi]) !== eraOf(buckets[start])) {
const era = eraOf(buckets[start]);
eras.push(``);
start = bi;
}
}
// ticks: the first day of each era, then days spaced at least a tenth of the strip apart; the
// boundary between eras is always labelled even when the later era is a single column
const ticks = [];
let lastAt = -Infinity;
const eraAts = [];
for (let bi = 0; bi < n; bi++) if (bi === 0 || eraOf(buckets[bi]) !== eraOf(buckets[bi - 1])) eraAts.push(bi / n);
const place = (bi, text, cls) => {
const at = bi / n;
// an era label near the right edge is anchored to its right and reaches ~a quarter of the strip leftward
const shadowed = eraAts.some((e) => (e > 0.8 ? at > e - 0.27 && at < e + 0.05 : at > e - 0.05 && at < e + 0.22));
if (!cls && (at - lastAt < 0.1 || shadowed)) return;
ticks.push(`${text}`);
lastAt = at;
};
let lastDay = "";
for (let bi = 0; bi < n; bi++) {
const day = dayFmt.format(new Date(buckets[bi].min_witnessed_at / 1000));
const eraStart = bi === 0 || eraOf(buckets[bi]) !== eraOf(buckets[bi - 1]);
if (eraStart) place(bi, `${ERA_LABEL[eraOf(buckets[bi])]} · ${day}`, "era-tick");
else if (day !== lastDay) place(bi, day);
lastDay = day;
}
const axis = `
${eras.join("")}${ticks.join("")}
`;
el.layers.innerHTML = `${lanes.join("")}${axis}`;
el.cursor = byId("cursor", HTMLDivElement);
el.legendBar.style.background = `linear-gradient(90deg, ${[0, 0.25, 0.5, 0.75, 1].map(shade).join(",")})`;
el.more.textContent = view.top >= 60 ? "all shown" : `show more (${fmt.format(view.namespaces.length - rows.filter((r) => r.depth === 0 && r.key !== OTHER).length)} more apps)`;
renderTable();
}
function cellFromPointer(ev) {
if (!picture) return null;
const lane = ev.target instanceof Element ? ev.target.closest(".lane[data-ri]") : null;
if (!lane) return null;
const strip = lane.querySelector(".strip");
if (!(strip instanceof HTMLElement)) return null;
const rect = strip.getBoundingClientRect();
const ri = Number(lane.dataset.ri);
const x = (ev.clientX - rect.left) / rect.width;
const bi = x < 0 || x >= 1 ? -1 : Math.floor(x * picture.buckets.length);
return { ri, bi, rect };
}
function readCell(c) {
const r = picture.rows[c.ri];
const what = r.depth ? "record type" : r.key === OTHER ? "the apps not shown" : "app";
if (c.bi < 0) {
el.reader.innerHTML = `${esc(displayName(r.key))} · ${what} · ${fmt.format(r.total)} records in the archive${r.expandable ? ` across ${r.members} record types · click the name to open` : ""}`;
return;
}
const b = picture.buckets[c.bi];
const v = r.values[c.bi];
const from0 = dayFmt.format(new Date(b.min_witnessed_at / 1000));
if (v <= 0) {
el.reader.innerHTML = `nothing from ${esc(displayName(r.key))} in this slice (received ${from0} utc)`;
return;
}
const share = b.event_count ? (100 * v) / b.event_count : 0;
const from = dayFmt.format(new Date(b.min_witnessed_at / 1000));
const to = dayFmt.format(new Date(b.max_witnessed_at / 1000));
const chunk = b.last_idx !== b.first_idx ? `chunks #${b.first_idx}–${b.last_idx}` : `chunk #${b.first_idx}`;
el.reader.innerHTML =
`${esc(displayName(r.key))} wrote ${fmt.format(v)} records in this slice — ${share < 0.01 && v ? "under 0.01" : share.toFixed(2)}% of the ${compact.format(b.event_count)} in it ` +
`archive ${chunk} · received ${from}${to !== from ? ` → ${to}` : ""} utc · record numbers ${fmt.format(b.min_seq)} – ${fmt.format(b.max_seq)}`;
}
function showCursor(c) {
if (c.bi < 0) {
el.cursor.style.display = "none";
return;
}
const host = el.layers.getBoundingClientRect();
const w = c.rect.width / picture.buckets.length;
el.cursor.style.display = "block";
el.cursor.style.left = `${c.rect.left - host.left + c.bi * w}px`;
el.cursor.style.width = `${Math.max(w, 1)}px`;
}
function clearHover() {
hover = null;
el.cursor.style.display = "none";
el.reader.innerHTML = 'move over the picture to read a cell · open an app to see its record types';
}
el.layers.addEventListener("pointermove", (ev) => {
const c = cellFromPointer(ev);
if (!c) {
clearHover();
return;
}
hover = { ri: c.ri, bi: c.bi };
showCursor(c);
readCell(c);
});
el.layers.addEventListener("pointerleave", clearHover);
el.layers.addEventListener("click", (ev) => {
const button = ev.target instanceof Element ? ev.target.closest("button.name[aria-expanded]") : null;
if (!(button instanceof HTMLButtonElement)) return;
const key = button.dataset.key ?? "";
if (view.expanded.has(key)) collapse(key);
else expand(key);
});
function renderTable() {
if (!picture || el.table.hidden) return;
const { rows, buckets } = picture;
el.table.innerHTML =
`
app / record type
records
${buckets.map((b) => `
#${b.first_idx}
`).join("")}
` +
rows.map((r) => `
${r.depth ? " · " : ""}${esc(displayName(r.key))}
${fmt.format(r.total)}
${Array.from(r.values, (v) => `
${v ? fmt.format(v) : ""}
`).join("")}
`).join("") +
`
`;
}
el.tableToggle.addEventListener("click", () => {
el.table.hidden = !el.table.hidden;
el.tableToggle.setAttribute("aria-pressed", String(!el.table.hidden));
el.tableToggle.textContent = el.table.hidden ? "show the numbers as a table" : "hide the table";
renderTable();
});
el.more.addEventListener("click", () => {
view.top = Math.min(60, view.top + 12);
el.more.disabled = view.top >= 60;
load();
});
el.find.addEventListener("change", () => {
const ns = el.find.value.trim().toLowerCase();
const hit = view.namespaces.find((n) => n.ns === ns);
if (!hit) {
el.reader.innerHTML = `no app called ${esc(ns)} has written to the archive yet`;
return;
}
if (!view.pinned.some((p) => p.ns === ns)) view.pinned.push(hit);
el.find.value = "";
load();
});
window.addEventListener("resize", () => {
if (hover) el.cursor.style.display = "none";
});
// ---- look inside an app ----
const PROMPTS = [
["what it writes", "select collection as record_type, op as action, count(*) as records, count(distinct did) as accounts\nfrom rows group by all order by records desc"],
["people per day", "select strftime(make_timestamp(time_us), '%Y-%m-%d') as day, count(distinct did) as accounts, count(*) as records\nfrom rows where kind = 'commit' group by 1 order by 1"],
["when each type first appeared", "select collection as record_type, strftime(make_timestamp(min(time_us)), '%Y-%m-%d %H:%M') as first_seen, count(*) as records\nfrom rows where kind = 'commit' group by 1 order by min(time_us)"],
["most active accounts", "select did as account, count(*) as records, count(distinct collection) as record_types\nfrom rows where kind = 'commit' group by 1 order by 2 desc limit 20"],
["creates vs deletes", "select op as action, count(*) as records from rows where kind = 'commit' group by 1 order by 2 desc"],
];
PROMPTS.forEach(([label, sql], i) => {
if (i > 0) el.prompts.append(" · ");
const b = document.createElement("button");
b.type = "button";
b.className = "linkish";
b.textContent = label;
b.addEventListener("click", () => {
el.askSql.value = sql;
if (el.askNs.value) runAsk();
});
el.prompts.append(b);
});
{
el.prompts.append(" · ");
const edit = el.askEdit;
edit.className = "linkish";
el.prompts.append(edit);
}
el.askSql.value = PROMPTS[0][1];
el.askEdit.addEventListener("click", () => {
el.askSql.hidden = !el.askSql.hidden;
el.askFine.hidden = el.askSql.hidden;
el.askEdit.setAttribute("aria-pressed", String(!el.askSql.hidden));
if (!el.askSql.hidden) el.askSql.focus();
});
let duck = null;
let partition = null;
async function duckdb() {
if (duck) return duck;
el.askOut.innerHTML = "loading the query engine…";
const mod = await import("https://cdn.jsdelivr.net/npm/@duckdb/duckdb-wasm@1.29.0/+esm");
const bundle = await mod.selectBundle(mod.getJsDelivrBundles());
const worker = new Worker(URL.createObjectURL(new Blob([`importScripts("${bundle.mainWorker}");`], { type: "text/javascript" })));
const db = new mod.AsyncDuckDB(new mod.ConsoleLogger(mod.LogLevel.WARNING), worker);
await db.instantiate(bundle.mainModule, bundle.pthreadWorker);
duck = await db.connect();
return duck;
}
el.askNs.addEventListener("change", async () => {
partition = null;
el.askRun.disabled = true;
el.askTable.innerHTML = "";
el.askOut.innerHTML = "";
if (!el.askNs.value) {
el.askSize.textContent = "";
return;
}
el.askSize.textContent = "checking…";
const p = await api(`api/partitions?ns=${el.askNs.value}`);
if (p.error) {
el.askSize.textContent = p.error;
return;
}
partition = p;
const size = p.bytes < 1 << 20 ? `${Math.round(p.bytes / 1024)} KB` : `${(p.bytes / (1 << 20)).toFixed(1)} MB`;
el.askSize.textContent = p.files.length ? `${size} to read from ${p.files.length} chunk${p.files.length === 1 ? "" : "s"}` : "not copied out of the archive yet";
el.askRun.disabled = !p.files.length;
});
function formatCell(value, numeric) {
if (value === null || value === undefined) return "";
return numeric ? fmt.format(value) : esc(value);
}
async function runAsk() {
if (!partition || !partition.files.length) return;
el.askRun.disabled = true;
try {
const conn = await duckdb();
await conn.query(`create or replace view rows as select * from read_parquet([${partition.files.map((f) => `'${f}'`).join(", ")}])`);
const t = performance.now();
const res = await conn.query(el.askSql.value);
const fields = res.schema.fields.map((f) => ({ name: f.name, numeric: /Int|Float|Decimal/.test(String(f.type)) }));
const out = res.toArray().map((r) => r.toJSON());
el.askOut.innerHTML = `${fmt.format(out.length)} row${out.length === 1 ? "" : "s"} in ${(performance.now() - t).toFixed(0)} ms`;
el.askTable.innerHTML =
`