Getting Started
Scroll Animations
Text Animations
Hover & Cursor
Sliders & Carousels
Galleries & Grids
Menus & Navigation
Preloaders & Intros
Page Transitions
3D & WebGL
import * as React from "react"
import { PhysicsTagDrop } from "@/registry/tween/physics-tag-drop"
export function PhysicsTagDropDemo() {
return (
<div className="h-[600px] w-full overflow-y-auto">
<PhysicsTagDrop style={{ "--ptd-h": "600px" } as React.CSSProperties} />
</div>
)
}
import { PhysicsTagDrop } from "@/components/ui/physics-tag-drop"<PhysicsTagDrop
services={[
{
name: "Tableau",
tags: ["Set Design", "Still Life", "Prop Styling"],
images: ["/sets/plinth.jpg", "/sets/arches.jpg", "/sets/hoops.jpg"],
},
]}
/>Each row sits at a collapsed height with its three images fanned and tucked behind a large display name. On mouseenter the row springs open with an elastic.out ease, the name shifts color, and the images slide up. A beat later, a per-row matter-js engine spawns a rounded "tag" pill for every label; the pills fall under gravity, bounce off the walls, and pile up on an invisible floor while a requestAnimationFrame loop syncs each DOM node's transform to its physics body. On mouseleave the tags fade out, the engine and animation loop are torn down, and the row collapses back.
Every row owns its own engine, rAF loop, and listeners, all cleaned up on unmount. On touch / no-hover devices the row toggles on tap and auto-reveals when scrolled into view. When prefers-reduced-motion: reduce is set, the physics drop and elastic springs are skipped — the row expands instantly and the tags render as a plain static list.
| Prop | Type | Default | Description |
|---|---|---|---|
services | PhysicsTagDropService[] | 3 services | Rows: { name, tags[], images[] }. |
background | string | "#14120f" | Section background and pill backdrop color. |
className | string | — | Extra classes on the outer container. |
style | React.CSSProperties | — | Inline styles; set --ptd-h to cap the height. |