diff --git a/README.md b/README.md index 7d14778..56a9854 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,8 @@ # Refract UI -

- refract-ui demo animation -

- Standalone visualization for the [Refract](https://github.com/refract-org/refract) observation engine. -Load any JSONL file of Refract observation events and explore what changed — timelines, diffs, citation graphs, disputes, and event-type breakdowns. No backend needed. +Load a JSONL file of Refract events to see them as a timeline with word-level diffs, citation and revert charts, talk page activity, and a list of the fields the events carry. Everything runs in the browser; there is no backend. ## Quick start @@ -27,17 +23,17 @@ Then drag `bitcoin-events.jsonl` onto the Refract UI upload zone. ## What you'll see -**Timeline** — Every event in chronological order. Click any event to see the word-level diff of what changed. Filter by event type to narrow the view. +**Timeline** — Every event, in the order the file lists them. Click an event to see the word-level diff of what changed. Filter by event type to narrow the view. -**Citations** — Bar chart showing citation additions, removals, and replacements per revision, plus a sortable table of every citation change. +**Citations** — Bar chart of citation additions, removals, and replacements per revision, plus a table of every citation change. -**Certainty** — Confidence scores over time for model-interpreted events. +**Model confidence** — The confidence score of each event on the `model_interpretation` layer. -**Disputes** — Revert clusters, edit velocity per day, and talk page activity. +**Disputes** — Revert clusters, events per day (with reverts), and talk page activity. -**Language Changes** — Card grid of wording events (claims reworded, strengthened, softened, removed). +**Wording changes** — One card per sentence event (first seen, modified, removed, reintroduced), with the before and after text. -**Schema** — Every JSON key in the loaded data, with types and presence percentage. +**Event schema** — Every top-level field in the loaded events, with its types and the share of events that have it. **Export** — Download filtered data as JSON, JSONL, or CSV. @@ -46,7 +42,7 @@ Then drag `bitcoin-events.jsonl` onto the Refract UI upload zone. - Vite + vanilla TypeScript - No framework dependencies - DOM-based rendering with CSS custom properties -- Works fully offline after first load +- Loads nothing from other origins; an uploaded file is read in the browser and never sent anywhere --- diff --git a/index.html b/index.html index 36108d9..8d3a91e 100644 --- a/index.html +++ b/index.html @@ -3,17 +3,14 @@ - Refract — Observation UI - - - - + Refract event viewer +

Refract

-

Observation Engine — Timeline Viewer

+

Event viewer for Refract JSONL exports

diff --git a/src/citations/CitationChurnChart.ts b/src/citations/CitationChurnChart.ts index ed16b89..b093e25 100644 --- a/src/citations/CitationChurnChart.ts +++ b/src/citations/CitationChurnChart.ts @@ -26,7 +26,7 @@ export class CitationChurnChart { const title = document.createElement("div"); title.className = "panel-title"; - title.textContent = "Citation Churn"; + title.textContent = "Citation churn"; this.container.appendChild(title); const churnData = this.computeChurn(); diff --git a/src/citations/SourceChangeTable.ts b/src/citations/SourceChangeTable.ts index f4b1e88..ee530dd 100644 --- a/src/citations/SourceChangeTable.ts +++ b/src/citations/SourceChangeTable.ts @@ -26,7 +26,7 @@ export class SourceChangeTable { const title = document.createElement("div"); title.className = "panel-title"; - title.textContent = "Source Changes"; + title.textContent = "Source changes"; this.container.appendChild(title); const changes = this.computeChanges(); diff --git a/src/disputes/EditVelocityChart.ts b/src/disputes/EditVelocityChart.ts index a2a773e..1f954bb 100644 --- a/src/disputes/EditVelocityChart.ts +++ b/src/disputes/EditVelocityChart.ts @@ -25,7 +25,7 @@ export class EditVelocityChart { const title = document.createElement("div"); title.className = "panel-title"; - title.textContent = "Edit Velocity"; + title.textContent = "Events per day"; this.container.appendChild(title); const buckets = this.computeBuckets(); diff --git a/src/disputes/RevertClusterDisplay.ts b/src/disputes/RevertClusterDisplay.ts index 09cdcdb..5a1ba64 100644 --- a/src/disputes/RevertClusterDisplay.ts +++ b/src/disputes/RevertClusterDisplay.ts @@ -26,7 +26,7 @@ export class RevertClusterDisplay { const title = document.createElement("div"); title.className = "panel-title"; - title.textContent = "Revert Clusters"; + title.textContent = "Revert clusters"; this.container.appendChild(title); const clusters = this.computeClusters(); diff --git a/src/disputes/TalkPageTimeline.ts b/src/disputes/TalkPageTimeline.ts index 61b08a3..a6c569c 100644 --- a/src/disputes/TalkPageTimeline.ts +++ b/src/disputes/TalkPageTimeline.ts @@ -25,7 +25,7 @@ export class TalkPageTimeline { const title = document.createElement("div"); title.className = "panel-title"; - title.textContent = "Talk Page Activity"; + title.textContent = "Talk page activity"; this.container.appendChild(title); const activities = this.computeActivities(); diff --git a/src/export/SchemaViewer.ts b/src/export/SchemaViewer.ts index bd5811e..4be8847 100644 --- a/src/export/SchemaViewer.ts +++ b/src/export/SchemaViewer.ts @@ -17,7 +17,7 @@ export class SchemaViewer { const title = document.createElement("div"); title.className = "panel-title"; - title.textContent = "Event Schema Inspector"; + title.textContent = "Event schema"; this.container.appendChild(title); if (this.events.length === 0) { diff --git a/src/language/CertaintyTimeline.ts b/src/language/CertaintyTimeline.ts index 75de00b..dfbc9e0 100644 --- a/src/language/CertaintyTimeline.ts +++ b/src/language/CertaintyTimeline.ts @@ -25,7 +25,7 @@ export class CertaintyTimeline { const title = document.createElement("div"); title.className = "panel-title"; - title.textContent = "Certainty Over Time"; + title.textContent = "Model confidence"; this.container.appendChild(title); const points = this.computePoints(); diff --git a/src/language/WordingDiffCard.ts b/src/language/WordingDiffCard.ts index c1159cb..29a5d70 100644 --- a/src/language/WordingDiffCard.ts +++ b/src/language/WordingDiffCard.ts @@ -28,7 +28,7 @@ export class WordingDiffCard { const title = document.createElement("div"); title.className = "panel-title"; - title.textContent = "Wording Changes"; + title.textContent = "Wording changes"; this.container.appendChild(title); const changes = this.computeChanges(); diff --git a/src/styles/main.css b/src/styles/main.css index 9053955..b870686 100644 --- a/src/styles/main.css +++ b/src/styles/main.css @@ -29,9 +29,10 @@ --cyan: #22d3ee; --radius: 10px; --radius-sm: 6px; - --font: "Manrope", system-ui, sans-serif; - --font-heading: "Syne", system-ui, sans-serif; - --mono: "Recursive", monospace; + --font: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; + --font-heading: var(--font); + --mono: + ui-monospace, SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace; } html { @@ -40,7 +41,6 @@ html { body { font-family: var(--font); - font-weight: 350; background: var(--bg-deep); color: var(--text); line-height: 1.5; @@ -48,29 +48,10 @@ body { min-height: 100vh; } -/* ── Ambient Background ── */ -body::before { - content: ""; - position: fixed; - top: 0; - right: 0; - width: 50%; - height: 50%; - background: radial-gradient( - ellipse at top right, - rgba(124, 138, 255, 0.05), - transparent 60% - ); - pointer-events: none; - z-index: 0; -} - #app { max-width: 1440px; margin: 0 auto; padding: 1.25rem 1.5rem; - position: relative; - z-index: 1; } /* ── Header ── */ @@ -85,7 +66,7 @@ body::before { #app-header h1 { font-size: 1.4rem; - font-weight: 650; + font-weight: 600; color: var(--accent); letter-spacing: -0.02em; } @@ -128,46 +109,17 @@ body::before { /* ── Panels ── */ .panel { background: var(--bg-panel); - backdrop-filter: blur(12px); - -webkit-backdrop-filter: blur(12px); border: 1px solid var(--border); border-radius: var(--radius); padding: 1rem 1.25rem; overflow: auto; - transition: - border-color 0.2s ease, - box-shadow 0.2s ease; - animation: panelFadeIn 0.35s ease-out both; + transition: border-color 0.2s ease; } .panel:hover { border-color: var(--border-strong); } -.panel:nth-child(1) { - animation-delay: 0ms; -} -.panel:nth-child(2) { - animation-delay: 60ms; -} -.panel:nth-child(3) { - animation-delay: 120ms; -} -.panel:nth-child(4) { - animation-delay: 180ms; -} - -@keyframes panelFadeIn { - from { - opacity: 0; - transform: translateY(6px); - } - to { - opacity: 1; - transform: translateY(0); - } -} - .panel-title { font-size: 0.7rem; font-weight: 700; @@ -357,7 +309,6 @@ select { color: var(--text-dim); margin-top: 0.15rem; font-family: var(--mono); - font-variation-settings: "MONO" 1; } /* ── Diff Viewer ── */ @@ -384,7 +335,6 @@ select { .diff-lines { font-family: var(--mono); - font-variation-settings: "MONO" 1; font-size: 0.78rem; line-height: 1.6; padding: 0.5rem 0.6rem; @@ -476,14 +426,11 @@ select { background: var(--accent); transform: translate(-50%, -50%); cursor: pointer; - transition: - transform 0.2s ease, - box-shadow 0.2s ease; + transition: transform 0.2s ease; } .certainty-dot:hover { transform: translate(-50%, -50%) scale(1.5); - box-shadow: 0 0 12px rgba(124, 138, 255, 0.4); } .certainty-dot.high { @@ -518,7 +465,6 @@ select { padding: 0.5rem 0.6rem; border-bottom: 1px solid var(--border); font-family: var(--mono); - font-variation-settings: "MONO" 1; font-size: 0.76rem; } @@ -559,7 +505,6 @@ select { .card-diff { font-family: var(--mono); - font-variation-settings: "MONO" 1; font-size: 0.78rem; margin-top: 0.4rem; padding: 0.4rem; @@ -628,7 +573,6 @@ select { /* ── Schema Viewer ── */ .schema-viewer { font-family: var(--mono); - font-variation-settings: "MONO" 1; font-size: 0.76rem; line-height: 1.6; white-space: pre-wrap; diff --git a/src/timeline/DiffView.ts b/src/timeline/DiffView.ts index 4c67a88..63918be 100644 --- a/src/timeline/DiffView.ts +++ b/src/timeline/DiffView.ts @@ -101,7 +101,7 @@ export class DiffView { this.container.innerHTML = ""; const title = document.createElement("div"); title.className = "panel-title"; - title.textContent = "Diff Viewer"; + title.textContent = "Diff"; this.container.appendChild(title); const hint = document.createElement("div"); diff --git a/src/timeline/TimelineView.ts b/src/timeline/TimelineView.ts index 2517ac7..bbbdc82 100644 --- a/src/timeline/TimelineView.ts +++ b/src/timeline/TimelineView.ts @@ -38,7 +38,7 @@ export class TimelineView { const title = document.createElement("div"); title.className = "panel-title"; - title.textContent = "Revision Timeline"; + title.textContent = "Revision timeline"; this.container.appendChild(title); const count = document.createElement("div"); @@ -99,7 +99,8 @@ export class TimelineView { } function formatEventType(type: EventType): string { - return type.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()); + const words = type.replace(/_/g, " "); + return words.charAt(0).toUpperCase() + words.slice(1); } function summarizeEvent(event: EvidenceEvent): string {