Skip to content

Visualization

WriteTrack ships chart components as web components powered by Observable Plot. Each chart is a custom element with Shadow DOM encapsulation, responsive sizing, and dark/light theme support.

Terminal window
npm i @observablehq/plot
import { SpeedTimeline, CompositionTimeline } from 'writetrack/viz';
// Register the custom elements (call once)
SpeedTimeline.register();
CompositionTimeline.register();
// After running analysis:
const analysis = await tracker.getAnalysis();
// Pass analysis data to the charts
document.querySelector('wt-speed-timeline').setData(analysis);
document.querySelector('wt-composition-timeline').setData(analysis);
<!-- Add the elements to your page -->
<wt-speed-timeline style="width: 100%; height: 200px;"></wt-speed-timeline>
<wt-composition-timeline
style="width: 100%; height: 80px;"
></wt-composition-timeline>

Charts fall into three groups based on data source and purpose:

  • Summary Statistics — WtBadge, Sparkline. Compact inline components for at-a-glance session stats.
  • Event Charts — DocumentGrowth, DocumentRibbon, EditBeeswarm, EditWaterfall, CorrectionsBubble. Consume raw WriteTrackDataSchema from getData() (no WASM needed).
  • Analysis Charts — SpeedTimeline, CompositionTimeline, RhythmHeatmap, PauseDistribution, WtOriginBar. Consume a SessionAnalysis from getAnalysis() (requires WASM).
  • Report Components — IntegrityFooter. Standalone UI elements for session reports.

A compact metric badge that displays a single stat from a session analysis. Use it inline alongside text or in dashboards.

import { WtBadge } from 'writetrack/viz';
customElements.define('wt-badge', WtBadge);
<wt-badge metric="effort-ratio"></wt-badge>
<wt-badge metric="largest-paste"></wt-badge>
<wt-badge metric="corrections"></wt-badge>
<wt-badge metric="tab-aways"></wt-badge>
const analysis = await tracker.getAnalysis();
document.querySelector('wt-badge').setData(analysis);

The metric attribute controls which stat is shown: 'effort-ratio' | 'largest-paste' | 'corrections' | 'tab-aways'.

A horizontal stacked bar showing the content origin breakdown — how much text was typed vs pasted vs programmatically inserted.

import { WtOriginBar } from 'writetrack/viz';
customElements.define('wt-origin-bar', WtOriginBar);
<wt-origin-bar style="width: 100%; height: 40px;"></wt-origin-bar>
const analysis = await tracker.getAnalysis();
document.querySelector('wt-origin-bar').setData(analysis);

A ribbon showing the document composition timeline — a linear visualization of how the document was built over time.

Unlike analysis charts, DocumentRibbon consumes raw WriteTrackDataSchema from getData() (no WASM needed).

import { DocumentRibbon } from 'writetrack/viz';
customElements.define('wt-document-ribbon', DocumentRibbon);
<wt-document-ribbon style="width: 100%; height: 60px;"></wt-document-ribbon>
const data = tracker.getData();
document.querySelector('wt-document-ribbon').setData(data);

A footer bar displaying hash verification, event count, and session ID. Useful for embedding at the bottom of reports to show data provenance.

import { IntegrityFooter } from 'writetrack/viz';
customElements.define('wt-integrity-footer', IntegrityFooter);
<wt-integrity-footer></wt-integrity-footer>
// Extract integrity data from an analysis result
const analysis = await tracker.getAnalysis();
document.querySelector('wt-integrity-footer').setData({
integrity: analysis.integrity,
outputSignature: analysis.outputSignature,
sessionId: data.metadata.sessionId,
});

Charts use CSS custom properties for colors, fonts, and spacing. They automatically adapt to dark/light themes via three mechanisms (in priority order):

  1. theme attribute on the element: <wt-speed-timeline theme="light">
  2. data-theme attribute on an ancestor: <body data-theme="light">
  3. prefers-color-scheme media query (automatic)

Override these on the host element or a parent container:

wt-speed-timeline {
--wt-color-primary: #3b82f6; /* Chart line/fill color */
--wt-color-secondary: #22d3ee; /* Accent color (paste events) */
--wt-color-text: #fafafa; /* Axis labels */
--wt-color-text-muted: #a1a1aa; /* Secondary text */
--wt-color-border: #27272a; /* Grid lines */
--wt-font-data: 'JetBrains Mono', monospace; /* Data labels */
}
PropertyDefault (dark)Default (light)Used for
--wt-color-primary#fbbf24#f59e0bLines, fills, bars
--wt-color-secondary#22d3ee#06b6d4Paste events, accents
--wt-color-bg#111113#ffffffComponent background
--wt-color-surface#1a1a1d#f5f5f4Panel backgrounds
--wt-color-text#fafafa#1a1a1aAxis labels, text
--wt-color-text-muted#a1a1aa#6b7280Secondary labels
--wt-color-border#27272a#e5e5e5Grid lines, rules
--wt-font-dataJetBrains MonoJetBrains MonoChart labels
--wt-font-uiDM SansDM SansLegends, UI text

Control chart dimensions with CSS custom properties. These take priority over clientWidth/clientHeight:

PropertyDescription
--wt-chart-widthSVG width in pixels (e.g. 800px)
--wt-chart-heightSVG height in pixels (e.g. 200px)

Individual charts expose additional custom properties for fine-grained color control:

wt-edit-beeswarm — keystroke colors:

PropertyDefaultUsed for
--wt-beeswarm-insert#22c55eTyped keystrokes
--wt-beeswarm-deletemutedDelete keystrokes
--wt-beeswarm-pastesecondaryPaste events
--wt-beeswarm-cut#f97316Cut events

wt-corrections-bubble — edit type colors:

PropertyDefaultUsed for
--wt-bubble-insert#22c55eInsert runs
--wt-bubble-delete#ef4444Delete runs
--wt-bubble-pastesecondaryPaste events
--wt-bubble-cut#f97316Cut events

wt-edit-waterfall — cut event color:

PropertyDefaultUsed for
--wt-color-cut#f97316Cut event dots

Charts also accept data via a data attribute (JSON string), useful for server-rendered pages:

<wt-speed-timeline data="..." style="width: 100%; height: 200px;">
</wt-speed-timeline>

The attribute value should be a JSON-serialized SessionAnalysis (for analysis charts) or WriteTrackDataSchema (for event-detail charts).

Each chart exports a standalone data-extraction function so you can use the data without the web components:

import {
extractSeries, // Sparkline: raw capture → [timestamps[], speeds[]]
extractSpeedData, // Speed timeline: analysis → SpeedPoint[]
extractSegments, // Composition: analysis → SegmentDatum[]
extractPasteMarkers, // Composition: analysis → PasteDatum[]
extractRhythmPairs, // Rhythm heatmap: analysis → RhythmPoint[]
extractPauseHistogram, // Pause distribution: analysis → PauseBin[]
extractProcessData, // Document growth: raw capture → ProcessGraphData
extractFocusSegments, // Composition focus mode: analysis → SegmentDatum[]
extractBeeswarmData, // Edit beeswarm: raw capture → BeeswarmDatum[]
extractWaterfallData, // Edit waterfall: raw capture → WaterfallData
extractCorrectionBubbles, // Corrections bubble: raw capture → BubbleDatum[]
} from 'writetrack/viz';

The BaseChart class is also exported for building custom chart components.