UI lab/React/Tailwind/Motion

UI with a pulse.

A craft-obsessed React library where everything moves like it should — from a button's press to a streaming AI response. Copy the source or install with the shadcn CLI, fully yours to edit.

01Components

Fresh from the lab

The newest components to land — accessible, dependency-light, and built to move.

All components
  • 0 dots · bouncy

    Move across the text.

    The dots keep reacting under solid content. Swipe fast and they get thrown further than the same path taken slowly. Click for a shockwave.

    Stiffness · 90
    Damping · 9
    Cursor drag · 0.9

    Critical damping is 2·√stiffness — about 19 here. Below it the dots overshoot and ring; above it they crawl home. Drop drag to 0 and the field stops caring how fast you move, which is how a lerped grid always behaves.

    Magnetic Dots

    Backgrounds

    A dot grid backdrop driven by a real spring, not a lerp. Dots carry velocity, so they get flung past their rest position and ring back — and the field reads how fast you move, not just where you are: a swipe throws dots further than the same path taken slowly. Click for an expanding shockwave. The canvas is pointer-transparent and listeners bind to the container, so it keeps reacting under headlines and buttons. Fixed 1/120s sub-stepping keeps the spring stable and frame-rate independent; the dirty rect bounds the cost to the influence radius.

    Magnetic Dots
  • Move across the field — or drag, on touch. React never re-renders while it moves.

    Falloff
    Damping · 18
    Slabs · 15

    Damping under ~10 overshoots and wobbles; over ~30 it goes syrupy. The default is 18 — the difference between those numbers is the entire feel of the component.

    Iso Momentum

    Illustrations

    An isometric slab field where every slab's height tracks pointer proximity and springs independently. The pointer flows through a motion value into each slab's path `d` string at 60fps — no React state, no re-renders while it moves. Pointer events, so it works under touch and pen, not just a mouse.

    Iso Momentum
  • motion valuesseamless wrapscroll velocityexponential decayzero re-renders

    Scroll me — fast, slow, and backwards

    01 Flick down and the strip accelerates left and shears with it. Flick up hard enough and it crosses zero and runs the other way. Let go and it coasts back to the base drift instead of stopping dead — that easing is the whole point.

    02 Flick down and the strip accelerates left and shears with it. Flick up hard enough and it crosses zero and runs the other way. Let go and it coasts back to the base drift instead of stopping dead — that easing is the whole point.

    03 Flick down and the strip accelerates left and shears with it. Flick up hard enough and it crosses zero and runs the other way. Let go and it coasts back to the base drift instead of stopping dead — that easing is the whole point.

    04 Flick down and the strip accelerates left and shears with it. Flick up hard enough and it crosses zero and runs the other way. Let go and it coasts back to the base drift instead of stopping dead — that easing is the whole point.

    05 Flick down and the strip accelerates left and shears with it. Flick up hard enough and it crosses zero and runs the other way. Let go and it coasts back to the base drift instead of stopping dead — that easing is the whole point.

    06 Flick down and the strip accelerates left and shears with it. Flick up hard enough and it crosses zero and runs the other way. Let go and it coasts back to the base drift instead of stopping dead — that easing is the whole point.

    07 Flick down and the strip accelerates left and shears with it. Flick up hard enough and it crosses zero and runs the other way. Let go and it coasts back to the base drift instead of stopping dead — that easing is the whole point.

    08 Flick down and the strip accelerates left and shears with it. Flick up hard enough and it crosses zero and runs the other way. Let go and it coasts back to the base drift instead of stopping dead — that easing is the whole point.

    09 Flick down and the strip accelerates left and shears with it. Flick up hard enough and it crosses zero and runs the other way. Let go and it coasts back to the base drift instead of stopping dead — that easing is the whole point.

    10 Flick down and the strip accelerates left and shears with it. Flick up hard enough and it crosses zero and runs the other way. Let go and it coasts back to the base drift instead of stopping dead — that easing is the whole point.

    11 Flick down and the strip accelerates left and shears with it. Flick up hard enough and it crosses zero and runs the other way. Let go and it coasts back to the base drift instead of stopping dead — that easing is the whole point.

    12 Flick down and the strip accelerates left and shears with it. Flick up hard enough and it crosses zero and runs the other way. Let go and it coasts back to the base drift instead of stopping dead — that easing is the whole point.

    13 Flick down and the strip accelerates left and shears with it. Flick up hard enough and it crosses zero and runs the other way. Let go and it coasts back to the base drift instead of stopping dead — that easing is the whole point.

    14 Flick down and the strip accelerates left and shears with it. Flick up hard enough and it crosses zero and runs the other way. Let go and it coasts back to the base drift instead of stopping dead — that easing is the whole point.

    Decay · 0.35s
    Coupling · 1.2
    Skew · 6°
    Playback

    Drop decay to 0.05s and the strip snaps to a halt the instant you stop — that is exactly the broken-feeling version. 0.35s is the default.

    Velocity Marquee

    Marketing

    An infinite strip whose speed and skew couple to scroll velocity — it accelerates as you scroll, reverses when you scroll back, and eases to a base drift when you stop. The wrap is a modulo on a measured content width (seamless in both directions, no CSS-animation restart), and the velocity is smoothed by an exponential moving average so it coasts instead of snapping.

    Velocity Marquee
  • Type that answers the cursor.

    Every glyph measures its own distance from the pointer, springs independently, and resolves to a font-variation-settings string. The boxes are pinned to their resting widths, so nothing reflows and no cached centre ever goes stale — the letters swell in place instead of shoving each other along the line.

    Move across the text — zero React re-renders

    Radius · 120px
    Peak wght · 800
    Stiffness · 280

    Push peak weight to 900 and drag across a word: the line holds its wrapping exactly. Without the pinned boxes, that is the setting where it starts to jitter and re-wrap under the cursor.

    Kinetic Type

    Typography

    Per-glyph variable-font response to pointer proximity — axes swell near the cursor and relax away from it, continuously and reversibly. Glyph boxes are pinned to their resting widths so animating `wght` can't shift neighbours, stale the cached centres, or re-wrap the line; centres are measured once and only re-read on resize or font swap. The accessibility tree reads one clean string.

    Kinetic Type
  • External motion value

    Scrub slowly through the middle — no crossings, no knots.

    Spring · both directions

    Click repeatedly — it reverses cleanly from wherever it is.

    3 subpaths → 2 · the middle line collapses into the X

    Morph Icon

    Icons

    True SVG path interpolation between two icons — not a cross-fade. Ships its own path normalizer with no dependency: a cursor-based parser (correct on packed arc flags, where a number regex silently fails), every command reduced to cubics including the full endpoint→centre arc conversion, equal-arc-length resampling, and a rotation/direction search that minimises total travel so the morph never ties itself in a knot. Multiple subpaths are paired by centroid, and an unmatched one collapses into its nearest counterpart.

    Morph Icon
  • Range
    Easing
    Effect
    native if available
    Panel 1

    Driven by --st-progress, cover · ease-in-out

    Panel 2

    Driven by --st-progress, cover · ease-in-out

    Panel 3

    Driven by --st-progress, cover · ease-in-out

    forced fallback
    Panel 1

    Driven by --st-progress, cover · ease-in-out

    Panel 2

    Driven by --st-progress, cover · ease-in-out

    Panel 3

    Driven by --st-progress, cover · ease-in-out

    effect="none" · your own CSS

    Scroll each panel. The two columns must stay locked together — the left one uses animation-timeline: view() where the browser has it, the right one is forced onto the rAF fallback. Both drive the same custom property, so there is only one thing rendering.

    Scroll Timeline

    Effects

    Continuous scroll-linked animation on the native Scroll-Driven Animations API, with a JS fallback that is numerically identical rather than merely similar. Both paths drive one registered custom property, `--st-progress`, so there is a single renderer and only the source of the number changes — the spec's four view-progress ranges and a real cubic-bézier solver make the fallback match to ~1e-6. Set `forceFallback` on one of two instances to check it yourself.

    Scroll Timeline
  • 0 dotsDPR 1hover to measure
    Spacing · 10px
    Radius · 140px
    Mode
    Direction

    Drop spacing to 8 or below to push past 5,000 dots and watch the fps hold — the per-frame cost is bounded by the influence radius, not the grid size. Scroll the field out of view and the rAF loop is cancelled outright, not left spinning.

    Dot Field

    Backgrounds

    A canvas dot grid that reacts around the cursor, at a density SVG can't reach. The per-frame cost is bounded by the influence radius rather than the dot count: only the dirty rect is cleared and redrawn, and dots are batched into 16 paths by quantised alpha instead of one fill each. DPR-correct on retina, and the rAF loop is genuinely cancelled — offscreen, backgrounded, or simply settled.

    Dot Field
  • Drag, or focus a row and press space

    • Pointer capture
      drag survives leaving the row
    • Cached geometry
      snapshotted once at lift — the whole reason this doesn't oscillate
    • Auto-scroll
      near the container edges
    • Keyboard mode
      space, arrows, space
    • Live announcements
      aria-live on every move
    • Drop animation
      glides into the final slot
    • Ragged heights
      layout is exact, not a uniform pitch
    • Zero re-renders
      transforms written straight to the DOM

    Try to make it oscillate: park the cursor exactly on a boundary and jiggle. The target index is a pure function of the frozen snapshot and the pointer delta, so there is no feedback loop to buzz in.

    Tab to a row, then Space to lift, ↑↓ to move, Space to drop, Esc to cancel — the entire flow without a mouse.

    a → b → c → d → e → f → g → h

    Sortable List

    Data Display

    Drag-to-reorder, hand-written, with a keyboard mode that shares the same code path. The target index is a pure function of geometry frozen at lift and the pointer delta — monotonic in the delta by construction, so there is no feedback loop to oscillate in at any drag speed. Pointer capture, edge auto-scroll, a drop animation into the final slot, and `aria-live` announcements throughout.

    Sortable List
    • Arbitration: scroll the list down, then drag down from inside it — the sheet does not move. Scroll back to the top and the same gesture drags the sheet.
    • Locked for the gesture: start a downward drag mid-list and keep going past the top. The sheet still doesn't grab it — the decision was made on the first move.
    • Rubber band: pull the handle up past the tallest detent.

    Drag Sheet

    Overlays

    A bottom sheet with snap points that feels native rather than like a `<div>` with a transition — three formulas and a state machine. Snapping is velocity-projected, so a flick and a slow drag past the same point resolve differently; bounds use Apple's rubber-band curve; and the drag-vs-scroll decision is made on the first `pointermove` past a 4px threshold and locked for the whole gesture, which is what stops a sheet from stealing a scroll halfway through.

    Drag Sheet
  • Text that develops into focus.

    Each line de-blurs and fades up as it enters the viewport — fires once, and respects reduced-motion.

    Text Reveal

    Motion

    Reveals its children with a soft de-blur + fade as they scroll into view — the 'text develops into focus' effect. Fires once, respects reduced-motion, and is polymorphic via `as` so it can wrap a heading, paragraph, or a single list item.

    Text Reveal
02Blocks

Whole sections, ready to drop in

Install one and its component dependencies come with it.

All blocks
  • Process Isometric

    Features
    Process Isometric
  • Hero Agent

    Heroes
    Hero Agent
  • Pain Points

    Features
    Pain Points
  • Outcome Features

    Features
    Outcome Features
  • Setup Steps

    Features
    Setup Steps
  • Stats CTA

    CTA
    Stats CTA
  • Footer Agent

    Navigation
    Footer Agent
  • Scroll Story

    Marketing
    Scroll Story
  • Compare Split

    Marketing
    Compare Split
03Templates

Full pages, assembled

Production-ready pages built from the blocks — install everything at once.

All templates
  • Agentic Landing

    A complete landing page for an AI/agent product, assembled from the agentic blocks: navbar → hero → problem → autonomous system → outcomes → setup → closing CTA → footer. `brand` + `label` props thread the amber accent and wordmark through every section; light-mode, motion-rich, self-contained theme. Install it and every block + component comes with it.

    8 blocks
    Agentic Landing
  • SaaS Landing Page

    A complete, production-ready SaaS landing page — navbar, hero, logos, features, bento, stats, testimonials, pricing, FAQ, CTA, and footer — assembled from the blocks. Install it and every block and component comes with it.

    11 blocks
    SaaS Landing Page
04How it works

No lock-in. The code becomes yours.

No theme to set up. Add any component, block, or template — by CLI or copy-paste — and it brings its own styling.

Install with the CLI

One command drops the component and its dependencies into your project via the shadcn registry.

Or just copy-paste

Every component page shows the full, dependency-light source with a one-click copy button.

Terminal
# add anything — components, blocks, or a whole template
npx shadcn@latest add https://ui.saumyarex.xyz/r/spotlight-card.json

# no theme step, no config: each item ships its own light + dark colors
npx shadcn@latest add https://ui.saumyarex.xyz/r/hero-agent.json