KQ-659 · BRIDGE/HOP

Bridge Hop

Two chain cards over a hop whose rail carries one node per stage, and a single token puck that crosses it: each completed stage slides the puck to the next node on glide, and the rail itself never fills, so the only thing travelling is the token. The rail's width is measured with a ResizeObserver and the puck moves by x in pixels off that measurement, so it can never overhang at any width; in flight it breathes on drift between two keyframes and stops for a hidden tab. Arrival lands on recoil while the destination balance rolls up on snap, and the stage nodes are real buttons with a roving tabindex whose focus writes the same read-out as hovering.

KQ-659 · BRIDGE/HOP
Basin to Coldbrook1/4
BasinBSN420.00
ColdbrookCBK
LockedAttestedRelayedMinted

Attested · Signed by 9 of 12 guards · 0xb7e3…05aa

Bridge locked · 1/4

Install

One command — the source lands in your repo. Or copy it from the Code tab.

$ pnpm dlx shadcn@latest add @kinetiq/bridge-hop

Props

stages
BridgeStage[]
default locked / attested / relayed / minted
The hop's nodes source to destination: id, label, and an optional detail and hash for the read-out.
stage
number
default 0
How many stages have completed; stages.length means arrived.
from / to
BridgeChain
default
The two chain cards: a name and a short ticker each.
amount
number
default
The sum crossing, printed as a debit on the source card.
destinationBalance
number
default
The destination's balance; its digits roll when the transfer lands.
format
(value: number) => string
default Intl.NumberFormat("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })
Formats the amount and the destination balance. The default pins an explicit locale so server and client agree.
asset
string
default "BSN"
Ticker for the amounts; its first letter is the mark on the token.
failed
boolean
default false
Stops the token on the stage in flight and marks it danger. Nothing bounces on a failure.
onStageFocus
(id: string) => void
default
Fires from the hover or focus that changed the read-out under the rail.
onArrive
() => void
default
Fires once, from the effect that observes the last stage completing.
label
React.ReactNode
default
Visible caption; omit it and pass aria-label.