Case study · 03 / Sweep

What actually happens if I act right now?

A live crypto market terminal built around the question existing terminals refuse to answer directly: what actually happens if I act right now? Point a size at the order book and it states your average fill, slippage and worst price before you commit. And when the feed dies, the terminal says so instead of impersonating a quiet market.

Point a size at the book

SWEEP · BTC-USD · KRAKEN

RECORDED FRAME · $5 BUCKETS

77,835.500.6651
77,830.508.4433
77,825.5010.7087
77,820.502.6801
77,815.5015.0671
77,810.508.7801
77,805.500.1226
77,800.508.5202
77,795.507.6296
77,790.500.7201
77,785.503.5873
77,780.5014.3013
SPREAD 0.10MID 77,780.45
77,780.400.0023
77,775.400.0163
77,770.400.0010
77,765.400.0001
77,760.400.1734
77,755.401.4802
77,750.401.8183
77,745.401.6510
77,740.404.3458
77,735.400.3625
77,730.400.1528
77,725.407.3294
BTC
AVG FILL
77,780.50
SLIPPAGE · BPS
+0.0
LEVELS
1
WORST
77,780.50

PAPER ONLY · LEVELS FROM THE RECORDED SESSION THE LIVE TERMINAL REPLAYS · DISPLAYED DEPTH IS OPTIMISTIC

A working slice of the sweep readout, running on levels from the real recorded Kraken session the live terminal replays. Choose a size and a side; the levels your order would consume tint amber and the readout states average fill, slippage in basis points, levels cleared and worst price touched. The book is asymmetric in this frame, so the same size costs differently in each direction. That asymmetry is the product.

Open the live product, opens in a new tab

The slice above is coded into this page. The full build is at sweep-trade.vercel.app.

Year
2026
Role
Product Design, Front-end Build, Data Engineering
Venue
BTC-USD on Kraken; Binance in code as proof the engine is venue-agnostic
Type
Personal build; design, engine and interface
Stack
Next.js, TypeScript, lightweight-charts, zero other runtime deps
Honesty
Observation and simulation only. No keys, no auth, no real orders
Outcome
last trade → your fill, the number no retail terminal shows: your average price across the levels your size would actually consume

The short version

A market interface should show executable truth, and should degrade visibly when it stops being true.

  • Terminals answer “what is the price?” Sweep answers the question with money on it: what actually happens if I act right now?
  • Point a size at the book and it states average fill, slippage and worst price before you commit. The levels you would consume tint amber.
  • A dead feed stops impersonating a quiet market: past 250ms the figures themselves fade until you cannot confidently act on them.
  • The deploy replays a real recorded session through the same engine as the live socket; GO LIVE sits behind it.
  • 797,210 messages in a one-hour live soak, every checksum clean, zero crossed books, zero gaps swallowed.

What was wrong

What the old experience made people do

01

The price on screen is not a price you can get

Every terminal leads with the last trade, or the top of a book you will not fully get. The number that matters to someone with size is the average fill across the levels their order would consume, and no retail terminal puts it in front of them. People guess, act, and meet the real number in their fill history.

Fixed by making the book an instrument you point a size at: consumed levels tint amber, and a readout states average fill, slippage in basis points, levels cleared and worst price touched, before you act.

02

A dead feed looks exactly like a quiet market

Terminals render a three-minute-old price identically to a live one. A dropped socket and a calm market are indistinguishable on screen, which makes staleness the most expensive lie in the category. It is a design failure, not an engineering one.

Fixed by putting staleness on the figures themselves, never in chrome: past 250ms of silence the numbers desaturate, then fade, then an explicit counter appears reading LAST MESSAGE 14.8s AGO, DO NOT ACT ON THIS. A number you can barely read is one you cannot confidently act on.

03

Activity rendering that punishes attention

Flash-on-change is the category default, and at real feed rates it is a strobe. A level changing five times in half a second flashes five times, which trains people to stop looking at exactly the thing the interface exists to show.

Fixed by replacing flash with accumulating heat: +0.18 alpha per change, a 500ms half-life, clamped at 0.35. Sustained activity reads as sustained warmth. The rejected strobe survives as the losing half of a side-by-side A/B on the deploy.

The problem

Two questions, zero answers

A person with money on the line is not asking what the price is. They are asking what happens if they act, and whether they can trust what they are looking at.

Trading terminals are dense, and the density is a costume. Under the panels and the indicators, the retail category answers one question: what was the last price somebody paid? That number is already history, and for any meaningful size it is not even a good prediction, because your order will walk through the book consuming levels, each one worse than the last.

The second question is quieter and more expensive. Every figure on a trading screen carries an implicit claim of nowness, and nothing in the category tests that claim in front of the user. The connection drops, the screen holds its last state, and the interface goes on looking confident. Sweep was built as a two-part answer: state what a size actually gets, and make trust in the screen something the screen itself has to earn.

A market interface should show executable truth, and should degrade visibly when it stops being true.

What I built

One screen, one venue, one instrument

BTC-USD on Kraken, depth over breadth. The order book stops being a passive table and becomes an instrument you point a size at.

The levels your order would consume tint amber. A readout states average fill, slippage in basis points, levels cleared and worst price touched. A cost curve draws size against average price, and the shape is the liquidity story: steep means thin, flat means deep. The FILL button records a paper position at the sweep’s computed average, exactly the figure the readout promised, and marks it against the live mid from then on. A 15 BTC paper buy showing a loss the instant it fills is not a bug; it is the slippage lesson transferred into your own position.

Under the screen sits a venue-agnostic engine kept deliberately outside React. It ingests the feed at whatever rate arrives, coalesces changes into immutable snapshots, and the interface subscribes at a fixed 10Hz, because reading a figure costs about 200ms and rendering faster than comprehension is noise, not freshness. The tape runs its own 30Hz budget: motion is tracked pre-attentively, digits are not. The cadence is enforced in architecture rather than left to discipline.

The engine is proven against two venues with different wire protocols, Kraken and Binance, and fed either by a live socket or by deterministic replay of raw recorded frames. It cannot tell which. Replay is the deploy default and GO LIVE sits behind it, which means the deployed piece will still play a real session in three years, after every venue API has changed.

The engineering

Recordings are raw wire frames, and the clock is the master

The recorder writes every raw message with its arrival time, not parsed events, so a recording outlives every parser improvement.

The same stateful session classes drive live and replay, which is what makes the claim that the engine cannot tell true rather than aspirational. A one-hour live soak of 797,210 messages passed every Kraken checksum with zero crossed books, and replays deterministically with identical numbers. The browser plays a spliced clip whose synthetic head snapshot is re-verified by the venue’s own CRC32 across the splice: 49,189 of 49,189 clean.

The first replay shipped as a setTimeout chain, one timer per message, and died the same day: browsers throttle chained timers in hidden tabs to one per second, which crawled a 150-message-per-second feed to one. The rewrite inverted control. The store owns a replay clock; every publish tick pumps the player synchronously up to it. A clock cannot be throttled, only the pump can, and a starved pump just emits a bigger batch on the next tick, with the clock walking back to the feed rather than skipping past it. In a throttled tab, replay time lags wall time, which is the honest direction to fail.

Every real fork in the build is logged in decisions.md from the day it was hit, and each entry names what the choice costs and who pays it. The setTimeout rewrite is in there as the fork it was.

Decision 01

The UI hears about the book at 10Hz, and flash became heat

Reading a figure costs about 200ms, so rendering faster than 10Hz is noise. The cost is named: a scalper watching for sub-100ms book flicker loses information here. That user is not who this is for, and would need a different mode, not a different constant.

Decision 02

Staleness lands on the figures, never in chrome

A banner is chrome and gets ignored; a number you can barely read is one you cannot confidently act on. The rule has no exceptions: when the recorded session ends, the clock keeps walking and the terminal degrades exactly as it would on a dead socket. A hole in the feed is never silently resumed. It is stated, 42s MISSING, until a human dismisses it.

Decision 03

Replay is the deploy default

On an ordinary bad network the live path fails, and the design’s job is to make that failure visible rather than rare. Raw frames cost about the storage of parsed events, and the meta line of every clip says what the splice snapshot is. This is a scene to design against, not a dataset.

Decision 04

Paper fills record the number the readout promised

Entry is booked at the sweep’s computed average, and the blotter marks it against live mid from then on. A blotter that recorded a kinder price would be the interface calling its own headline number a lie. No fees, no latency model; the panel says PAPER and means it.

Decision 05

One decided layout

Every terminal ships draggable panels to avoid making a layout decision; making the decision is the work. Chart left, book and tape right, sweep and positions below. No panel invents its own rhythm: 32px headers, 24px column heads, 20px rows.

The landscape

Where the category stands

Not a feature matrix, because Sweep would lose one on purpose: it has no watchlist, no indicators and no drawing tools, and refuses them in writing. The comparison that matters is behavioural. When the same six moments happen, what does the screen do?

The headline number

Retail crypto terminals ·The last trade, or top of book. A price that is already history, and one your size would not get.

Sweep ·Your average fill across the levels your size would consume, stated before you act.

The feed quietly dies

Retail crypto terminals ·The screen holds its last state and goes on looking confident. A dropped socket is indistinguishable from a calm market.

Sweep ·Figures desaturate, fade toward 40% opacity, then a counter states LAST MESSAGE 14.8s AGO, DO NOT ACT ON THIS.

A hole in the data

Retail crypto terminals ·Reconnect and resume as though nothing happened.

Sweep ·Stated in amber, 42s MISSING, until a human dismisses it.

A busy level

Retail crypto terminals ·Flashes on every change. At real feed rates, a strobe.

Sweep ·Accumulates heat with a 500ms half-life, so sustained activity reads as sustained warmth.

The layout

Retail crypto terminals ·Draggable panels, so the product never has to make a decision.

Sweep ·One decided layout. Making the decision is the work.

Paper trading

Retail crypto terminals ·Fills at the price on screen, which is kinder than reality.

Sweep ·Fills at the computed sweep average, slippage included. The readout is accountable to its own number.

The professional tier is a different conversation: Bloomberg and the exchange-native pro tools do estimate depth-weighted fills, at desk prices, for people who already know to ask. The claim here is narrower and checkable: in the terminals retail crypto actually trades on, these six moments default the other way.

The design system

The tokens every screen is built from

The system exists to serve two sentences: show executable truth, and degrade visibly when it stops being true. Green and red are spent entirely on direction, amber is reserved for the single state where a human must decide, and the highest contrast on screen belongs not to a brand mark but to the digits that are currently changing.

01

Executable truth

The book answers a size, not a level. Average fill, slippage, levels cleared, worst touched.

02

Liveness you can feel

Staleness lives in the figures, never in chrome. Silence is the good state.

03

Hue is never the only channel

Direction is carried three ways at once: fixed position, a luminance gap, and a sign glyph. Verified under deuteranopia simulation.

04

The terminal remembers

Look away for forty seconds and it tells you what you missed, once, then gets out of the way.

Sweep DS v1Nine colour tokens, a 2px spatial scale, and two typefaces with a treaty between them. Small on purpose: every token that exists is one a screen this dense has to defend.

Two tiers. The ramps are raw values that no component is allowed to reference; the tokens beneath name a role and point at one. Select a token to see which step it resolves to.

ink The greys, darkest to lightest. Canvas is never #000: saturated green halates on OLED.

canvas

surface

raised

hairline

stable

dim

text

volatile

signal The only hues on screen, and each is allowed to mean exactly one thing.

bid

ask

attention

Direction

Figures

Structure

More screens

The same 15 BTC sweep pointed at the sell side: bid levels flooded amber, the readout stating average fill 77,792.25, slippage +7.6 basis points across 55 levels, and the cost curve falling away steeply.
The same 15 BTC, other side. Buying this frame costs +0.5 bps into an ask wall; selling costs +7.6 bps across 55 levels, and the cost curve says so before the trade does. Steep means thin.
The terminal 33 seconds into a dead feed: the book desaturated and faded, a NO DATA badge on the panel, and an amber counter reading LAST MESSAGE 33.5s AGO, DO NOT ACT ON THIS.
The staleness ladder, 33.5s into a dead feed. No banner: the figures themselves have faded until they are hard to act on, which is the correct amount of hard.
The terminal after the feed reconnects, with an amber chip in the toolbar reading 42s MISSING and the book live again behind it.
After reconnect the book is live again, and the hole is not forgiven silently: 42s MISSING stays in the toolbar until a human dismisses it.
Two order books side by side on the same replay: the left flashing per change, the right accumulating heat, with the caption Same replay, same changes.
The A/B that settled the motion argument: the same replay through flash-on-change and through heat. The rejected half ships with the product, as evidence.

Still open

What I would do in the next pass

  1. Displayed depth is not executable depth

    A meaningful share of resting size is cancelled before you reach it, so the sweep readout is optimistic and does not yet say so. Measuring cancellation rates near the touch and drawing a confidence band on the fill estimate is the strongest v2 idea, and the honest answer to spoofing.

  2. Mobile is a different hierarchy, not a smaller one

    The density argument assumes a desktop viewport. Shrinking this layout would be a lie; a phone terminal would lead with the readout and hide the book behind a gesture.

  3. Live means we heard from them recently

    Message arrival is measured; venue-side latency is not. Liveness overstates itself by exactly the width of the network, and the next pass should say so on screen.

  4. The dark convention deserves a real challenge

    Dark terminals come from low-light desks, and a lot of crypto is traded in daylight on a phone. v1 declined to ship a half-committed light mode, which is not the same as the question being settled.

A number you cannot trust should be a number you can barely read.


Esc