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.
npm i @observablehq/plotpnpm add @observablehq/plotyarn add @observablehq/plotQuick Start
Section titled “Quick Start”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 chartsdocument.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>Available Components
Section titled “Available Components”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
WriteTrackDataSchemafromgetData()(no WASM needed). - Analysis Charts — SpeedTimeline, CompositionTimeline, RhythmHeatmap, PauseDistribution, WtOriginBar. Consume a
SessionAnalysisfromgetAnalysis()(requires WASM). - Report Components — IntegrityFooter. Standalone UI elements for session reports.
Component Guide
Section titled “Component Guide”WtBadge
Section titled “WtBadge”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'.
WtOriginBar
Section titled “WtOriginBar”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);DocumentRibbon
Section titled “DocumentRibbon”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);IntegrityFooter
Section titled “IntegrityFooter”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 resultconst analysis = await tracker.getAnalysis();document.querySelector('wt-integrity-footer').setData({ integrity: analysis.integrity, outputSignature: analysis.outputSignature, sessionId: data.metadata.sessionId,});Theming
Section titled “Theming”Charts use CSS custom properties for colors, fonts, and spacing. They automatically adapt to dark/light themes via three mechanisms (in priority order):
themeattribute on the element:<wt-speed-timeline theme="light">data-themeattribute on an ancestor:<body data-theme="light">prefers-color-schememedia query (automatic)
Custom Properties
Section titled “Custom Properties”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 */}| Property | Default (dark) | Default (light) | Used for |
|---|---|---|---|
--wt-color-primary | #fbbf24 | #f59e0b | Lines, fills, bars |
--wt-color-secondary | #22d3ee | #06b6d4 | Paste events, accents |
--wt-color-bg | #111113 | #ffffff | Component background |
--wt-color-surface | #1a1a1d | #f5f5f4 | Panel backgrounds |
--wt-color-text | #fafafa | #1a1a1a | Axis labels, text |
--wt-color-text-muted | #a1a1aa | #6b7280 | Secondary labels |
--wt-color-border | #27272a | #e5e5e5 | Grid lines, rules |
--wt-font-data | JetBrains Mono | JetBrains Mono | Chart labels |
--wt-font-ui | DM Sans | DM Sans | Legends, UI text |
Sizing
Section titled “Sizing”Control chart dimensions with CSS custom properties. These take priority over clientWidth/clientHeight:
| Property | Description |
|---|---|
--wt-chart-width | SVG width in pixels (e.g. 800px) |
--wt-chart-height | SVG height in pixels (e.g. 200px) |
Chart-Specific Properties
Section titled “Chart-Specific Properties”Individual charts expose additional custom properties for fine-grained color control:
wt-edit-beeswarm — keystroke colors:
| Property | Default | Used for |
|---|---|---|
--wt-beeswarm-insert | #22c55e | Typed keystrokes |
--wt-beeswarm-delete | muted | Delete keystrokes |
--wt-beeswarm-paste | secondary | Paste events |
--wt-beeswarm-cut | #f97316 | Cut events |
wt-corrections-bubble — edit type colors:
| Property | Default | Used for |
|---|---|---|
--wt-bubble-insert | #22c55e | Insert runs |
--wt-bubble-delete | #ef4444 | Delete runs |
--wt-bubble-paste | secondary | Paste events |
--wt-bubble-cut | #f97316 | Cut events |
wt-edit-waterfall — cut event color:
| Property | Default | Used for |
|---|---|---|
--wt-color-cut | #f97316 | Cut event dots |
Declarative Usage
Section titled “Declarative Usage”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).
Extract Functions
Section titled “Extract Functions”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.