Skip to content

No.213 · Authentication

QR Handoff Sign-in

Sign in by pointing your phone at the screen: the code's frame carries the instructions and time left as a ticker round its edge, a scan sends a ripple out through the code, and approving turns it over to a check.

The prompt

The design brief behind this component — reuse it to regenerate, remix, or explain it.

Build a 'Sign in with your phone' card around a 248px square frame: a 26px band with 30px corners, and inside it the code on light paper (phones need contrast in either theme). The band carries a ticker: an SVG rounded-rect loop through the middle of the band, with mono capitals ('SCAN WITH VITRINE · EXPIRES IN 1:58 · MUSCAT · ENCRYPTED ·') repeated to one lap, spread with textLength, in two textPaths one lap apart whose startOffset advances in requestAnimationFrame at 26px/s, easing to 4px/s while the pointer is over the frame. Its words change with the state, and it takes the accent colour after a scan and green after approval. States: waiting → scanned → approved, or expired after the TTL (120s, counted down in the ticker). Accept a 'code' prop for your real QR SVG; without one, draw a stand-in with QR anatomy (three finders with separators, timing lines, seeded data — not readable) as one rect per module. Each module has --d, its distance from the centre. A new code fades its modules in from the middle (22ms per module of distance). A scan runs a ripple outward (34ms per unit): each module shrinks to 35% in the accent colour and springs back, then the code dims while a ring breathes from the centre, 'Approve on Hamza's iPhone'. Approval flips the card (rotateY 180°, slight overshoot) to a green back face whose circle and check draw in. Expiry blurs the code to 12% and shows a 'Get a new code' button. Under the frame: a role=status line explaining the current step, optional demo buttons, an 'or' divider and 'Sign in with email instead'. Night and Paper.

Notes

Interaction
Hover the frame to slow the ticker. In the demo, press Simulate scan, then Simulate approve, or Expire now and Get a new code.
Motion
Ticker 26px/s easing to 4px/s; fade-in 420ms, 22ms per module; ripple 760ms, 34ms per module; flip 900ms; check draws after.
Accessibility
The code is a role="img" with a label; the ticker is aria-hidden and every fact in it is repeated in the role=status line, which also announces each step. The email fallback is always present. Reduced motion stops the ticker and makes every change instant.
Responsive
The card is up to 24rem and the frame is a fixed 248px, which fits a 320px screen.
On touch
The ticker keeps its normal speed; everything else is the same.

Featured

301 components