about things notes.zzstoatzz.io
notes
notes systems interactive-data-interfaces.md
7.2 kB
Markdown
at main

interactive data interfaces #

A live data interface has two jobs: represent the data faithfully and preserve the viewer's ability to act while it changes. Visual polish includes the second job. A correct total in a layout that loses focus or hides its controls is not a complete result.

budget space around the primary loop #

Identify the smallest useful loop: inspect the graph, move time, compare the result. Keep those controls usable together at normal zoom. Height and width are coupled budgets; reducing height by crowding out the plot merely moves the problem.

On narrow screens, move secondary representations below the primary controls instead of shrinking every element equally. A packing algorithm proves that items fit; screenshots and actual interaction establish whether the result is readable. Different quantities need different visual encodings. Rank above an image and a total below it should not look like two interchangeable numbers.

expose entry points, disclose editing #

Progressive disclosure should hide infrequent work, not the reason someone visits. An account lookup can remain visible while the long selection roster is collapsed. Name the state and action concretely: “on the chart” and “choose posters” explain more than a metaphor and “manage.”

Give a default state one entry and one intelligible return path. A reset action that silently does nothing in the default state communicates poorly. Distinguish navigation from selection and removal with separate semantic controls; do not make an entire identity card destructive while adding an apparently separate remove icon.

separate viewing intent from data arrival #

Ingestion, live-edge following, playback and an active drag are different states. Scrubbing can suspend advancement without changing the user's playing/paused intent. A release should restore that intent; it should not always start or stop. Transient hover ends when the pointer leaves its target, even if it remains inside a larger chart. Keyboard focus and touch navigation need explicit behavior too.

Use stable keys when reconciling live rows and portraits. Recreating controls on each update can lose focus, interrupt interaction and cause image flicker even when the underlying data is correct. Test identity retention as well as rendered values.

animate causality, bound the work #

A live celebration is a claim that a new event happened. Trigger it from accepted, fresh changes rather than initial state, replay or duplicate delivery. Where the interface draws a connection between two objects, travel should follow that entire connection before the destination reacts. Draw the connector layer behind the complete destination layer, not behind only its own destination.

Keep motion ephemeral. Coalesce repeated arrivals per entity rather than queueing an animation for every event; data can update immediately while a celebration is already playing. Provide a reduced-motion signal without requiring travel or bounce. A bounded animation count is useful, but is not a measurement of frame time.

keep serving work proportional to the view #

Send incremental changes instead of repeatedly broadcasting the whole dataset. Measure initial-load traffic separately from steady-state traffic before adding fanout infrastructure. Fetch small pages and enrich only requested identities; bound caches and cancel obsolete work. Filtering a loaded page must not masquerade as searching the whole collection.

Freshness labels must identify their clock: event observation, historical view, or wall time. Historical reconstruction cannot claim stronger continuity than its retained event history supports. See watermark semantics and change timestamps.

verify the states, qualify the result #

Check the default, empty, singular, full, replaying and recovering states. Test transitions as well as screenshots: a profile click must not select, a removal must affect one item, and a drag must preserve playback intent. Automated checks, browser inspection and device testing answer different questions. State which ones were performed; passing unit tests is not a screen-reader or capacity audit.

draw a small DAG as a DAG, and turn it with the screen #

a lineage graph of tens to a few hundred typed nodes reads best as a layered flow, not a force layout (a different picture every load) and not an embedding map (no edges). rank by longest path from the sources, order rows by the barycenter of neighbours in a few alternating sweeps, keep a group's nodes contiguous within a rank, and the layout is deterministic and cheap enough to run on the client on every load.

on a phone the flow runs top to bottom so the narrow axis holds the widest rank. two things follow: a rank with fewer nodes than the widest one spreads them over the widest rank's slots instead of the row grid, or its wider pills collide; and a pill's width comes from the measured label at the current zoom, capped by its slot, not from world units, because fonts clamp in pixels while world units scale. what the viewer may not see still gets drawn as a ghost node when something visible derives from it: the edge into the boundary is the information.

everything else is the atlas playbook: unified pointer events with a pinch pair, zoom anchored under the pointer, a demand-driven frame, a devicePixelRatio backing store, a touch-widened hit radius, and labels that are culled at the viewport edge rather than shifted off their node.

sampled sound and activity indicators #

For turning a stream into sound, see firehose as sound.

When sound represents a sample of a data stream, distinguish the sample from the underlying traffic. Show separately what arrived, which events qualify for sound, and how the sound is thinned. A quiet chart can expose this information without turning every event into a flash or an audible note.

A comparative baseline needs a source, window, unit, and scope. For example, Chimes receives JSON stream messages while Stream’s hourly baseline comes from relay sequence rates in relay-eval. Those related counts can differ. Label the reference and link its methodology; do not present it as an exact health score. Use a stable, disclosed chart scale and clear paused measurements so stale values do not look live.

sources #

  • race38, docs/ui-rigor.md, web/main.ts, web/dom.ts, web/style.css, src/portraits.ts, src/pulses.ts, src/live.ts and associated tests; design review and implementation with Nate, September 4–5, 2026.
  • race38, ARCHITECTURE.md and STREAM-TYPEAHEAD-RESEARCH.md, September 5, 2026; measured repeated snapshot delivery and the bounded-serving comparison.
  • pub-search site/atlas.js and bot web/src/lib/components/AtlasOverlay.svelte (the atlas playbook), and a canvas lineage graph of a dbt/dagster asset DAG checked at 393 px and 1280 px, 2026-09-18
  • Chimes src/activity.ts and src/firehose.ts, 2026-09-19; Stream baseline and relay-eval rate profile.