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.