const app = document.querySelector("#app"); const ROUTES = ["now", "rooms", "records", "route", "proof"]; const ROUTE_ALIASES = { feed: "now", signal: "route" }; const KIND_LABELS = { roomDefinitions: "definition", roomStates: "state", submissions: "submission", artifacts: "artifact", actions: "action", moderation: "moderation", digests: "digest", provenance: "provenance", }; const ROOM_LABELS = { "void/research": "Research", "void/art": "Art", "void/homelab": "Homelab", }; let model = null; let route = parseRoute(); let selectedRoom = "all"; let selectedKind = "all"; let query = ""; function escapeHtml(value) { return String(value ?? "") .replaceAll("&", "&") .replaceAll("<", "<") .replaceAll(">", ">") .replaceAll('"', """) .replaceAll("'", "'"); } function formatDate(value, mode = "short") { if (!value) return "undated"; const date = new Date(value); if (Number.isNaN(date.getTime())) return value; return date.toLocaleString(undefined, { month: "short", day: "2-digit", ...(mode === "long" ? { year: "numeric" } : {}), hour: "2-digit", minute: "2-digit", }); } function parseRoute() { const hash = window.location.hash.replace(/^#\/?/, ""); const [candidate] = hash.split("?"); const normalized = ROUTE_ALIASES[candidate] ?? candidate; return ROUTES.includes(normalized) ? normalized : "now"; } function goto(nextRoute) { route = nextRoute; window.location.hash = nextRoute; render(); } function valueOf(record) { return record?.value ?? {}; } function recordRoom(record) { return valueOf(record).room ?? valueOf(record).scope ?? "network"; } function recordTitle(record) { const value = valueOf(record); return value.title ?? value.action ?? value.status ?? KIND_LABELS[record.kind] ?? "record"; } function recordText(record) { const value = valueOf(record); return ( value.summary ?? value.text ?? value.purpose ?? value.body ?? value.action ?? value.method ?? JSON.stringify(value, null, 2) ); } function truncate(text, max = 260) { const clean = String(text ?? "").trim(); if (clean.length <= max) return clean; return `${clean.slice(0, max).trim()}…`; } function shortUri(uri) { return String(uri ?? "").split("/").at(-1) || uri; } function allRecords(data) { const records = []; for (const room of data.rooms ?? []) records.push(...(room.timeline ?? [])); records.push(...(data.recent ?? [])); const byUri = new Map(); for (const record of records) byUri.set(record.uri, record); return [...byUri.values()].sort((a, b) => new Date(b.createdAt ?? 0) - new Date(a.createdAt ?? 0)); } function filteredRecords(data) { const needle = query.toLowerCase(); return allRecords(data).filter((record) => { const room = recordRoom(record); const haystack = `${room} ${record.kind} ${recordTitle(record)} ${recordText(record)} ${record.uri}`.toLowerCase(); return ( (selectedRoom === "all" || room === selectedRoom) && (selectedKind === "all" || record.kind === selectedKind) && (!needle || haystack.includes(needle)) ); }); } function totalRecords(counts = {}) { return Object.values(counts).reduce((sum, value) => sum + Number(value ?? 0), 0); } function latestState(data) { return (data.rooms ?? []) .map((room) => room.latestState) .filter(Boolean) .sort((a, b) => new Date(b.createdAt ?? 0) - new Date(a.createdAt ?? 0))[0]; } function routeLabel(item) { return { now: "Now", rooms: "Rooms", records: "Records", route: "Signal", proof: "Proof" }[item]; } function shell(content) { return `
${content}
`; } function introPanel(data) { const state = latestState(data); return `

${escapeHtml(data.namespace)}

Void is working in public.

The site answers three questions: what changed, where it belongs, and how a person can route a signal into the system.

Open data browser
`; } function nowView(data) { const records = allRecords(data).slice(0, 7); return shell(`${introPanel(data)}
${(data.rooms ?? []).map(roomSummaryCard).join("")}
latest changes
${records.map(recordCard).join("")}
${openQuestionsPanel(data)}
`); } function roomSummaryCard(room) { const latest = room.latestState?.value ?? {}; const counts = room.counts ?? {}; return `

${escapeHtml(truncate(latest.currentTask ?? latest.summary ?? room.purpose, 150))}

states
${counts.states ?? 0}
actions
${counts.actions ?? 0}
artifacts
${counts.artifacts ?? 0}
`; } function openQuestionsPanel(data) { const blockers = (data.blockers ?? []).slice(0, 5); return ``; } function roomsView(data) { return shell(`

rooms

Three places for work to land.

Each room has a purpose, a latest state, and a trail of canonical records.

${(data.rooms ?? []).map(roomDetailCard).join("")}
`); } function roomDetailCard(room) { const latest = room.latestState?.value ?? {}; const counts = room.counts ?? {}; return `
${escapeHtml(ROOM_LABELS[room.name] ?? room.name)}${escapeHtml(room.name)}

${escapeHtml(room.displayName ?? room.name)}

${escapeHtml(room.purpose)}

${counts.states ?? 0} states${counts.actions ?? 0} actions${counts.submissions ?? 0} submissions${counts.artifacts ?? 0} artifacts
Latest state

${escapeHtml(latest.summary ?? "No state yet.")}

`; } function filtersHtml(data) { const kinds = Object.keys(data.counts ?? {}).filter((kind) => kind !== "provenance"); return `
Room
${(data.rooms ?? []).map((room) => ``).join("")}
Type
${kinds.map((kind) => ``).join("")}
`; } function recordsView(data) { const records = filteredRecords(data); return shell(`

records

Canonical trail.

${totalRecords(data.counts)} records loaded from the public room projection.

${filtersHtml(data)}
${records.length ? records.map(recordCard).join("") : `
No records match this filter.
`}
`); } function recordCard(record) { const room = recordRoom(record); return `
${escapeHtml(KIND_LABELS[record.kind] ?? record.kind)}${escapeHtml(room)}

${escapeHtml(recordTitle(record))}

${escapeHtml(truncate(recordText(record)))}

${escapeHtml(shortUri(record.uri))}
`; } function routeView(data) { return shell(`

signal

Route something into Void.

This page prepares a packet. A human or agent still accepts it before it becomes a canonical ATProto record.

`); } function proofView(data) { const proofHash = "a8935646005b8e51d827a7e44981dc173ccd8a38b7948cc0cfc5e74bfdf4094a"; return shell(`

proof

Saveable state.

The standalone proof bundle embeds the generated room projection. It is an artifact, not the primary reading experience.

Open proof bundle Open data.json
Generated

${escapeHtml(formatDate(data.generatedAt, "long"))}

PDS

${escapeHtml(data.pdsHost)}

Records

${totalRecords(data.counts)}

`); } function render() { if (!model) return; const view = { now: nowView, rooms: roomsView, records: recordsView, route: routeView, proof: proofView }[route] ?? nowView; app.innerHTML = view(model); bindInteractions(); } function bindInteractions() { app.querySelectorAll("[data-route]").forEach((element) => { element.addEventListener("click", (event) => { const next = element.getAttribute("data-route"); if (ROUTES.includes(next)) { event.preventDefault(); goto(next); } }); }); app.querySelectorAll("[data-room]").forEach((button) => { button.addEventListener("click", () => { selectedRoom = button.getAttribute("data-room"); render(); }); }); app.querySelectorAll("[data-kind]").forEach((button) => { button.addEventListener("click", () => { selectedKind = button.getAttribute("data-kind"); render(); }); }); app.querySelector("[data-search]")?.addEventListener("input", (event) => { const cursor = event.target.selectionStart; query = event.target.value; render(); const nextInput = app.querySelector("[data-search]"); nextInput?.focus(); nextInput?.setSelectionRange(cursor, cursor); }); app.querySelectorAll("[data-room-shortcut]").forEach((button) => { button.addEventListener("click", () => { selectedRoom = button.getAttribute("data-room-shortcut"); selectedKind = "all"; query = ""; goto("records"); }); }); app.querySelectorAll("[data-copy]").forEach((button) => { button.addEventListener("click", async () => { await copyText(button.getAttribute("data-copy")); pulse(button, "Copied"); }); }); app.querySelector("[data-action='copy-feed']")?.addEventListener("click", async (event) => { const records = allRecords(model).slice(0, 6); const summary = records.map((record) => `- [${recordRoom(record)} / ${KIND_LABELS[record.kind] ?? record.kind}] ${recordTitle(record)} — ${shortUri(record.uri)}`).join("\n"); await copyText(`Void latest records\n${summary}`); pulse(event.currentTarget, "Copied"); }); app.querySelector("[data-routing-form]")?.addEventListener("submit", async (event) => { event.preventDefault(); const form = new FormData(event.currentTarget); const packet = [ "Void routing packet", `room: ${form.get("room")}`, `kind: ${form.get("kind")}`, `source: website:${location.href}`, "status: proposed", "text:", String(form.get("text") ?? "").trim() || "[empty]", ].join("\n"); await copyText(packet); app.querySelector("[data-route-output]").textContent = "Copied. Paste this into an ingress surface for review/canonicalization."; }); } async function copyText(text) { if (navigator.clipboard?.writeText) return navigator.clipboard.writeText(text); const area = document.createElement("textarea"); area.value = text; document.body.append(area); area.select(); document.execCommand("copy"); area.remove(); } function pulse(button, label) { const original = button.textContent; button.textContent = label; button.disabled = true; setTimeout(() => { button.textContent = original; button.disabled = false; }, 1000); } async function load() { try { const response = await fetch("./rooms/data.json", { cache: "no-store" }); if (!response.ok) throw new Error(`rooms/data.json returned HTTP ${response.status}`); model = await response.json(); route = parseRoute(); render(); } catch (error) { app.innerHTML = `

void.tngl.io

Could not load Void.

${escapeHtml(error.message)}

`; } } window.addEventListener("hashchange", () => { route = parseRoute(); render(); }); load();