Handset
Live 3D device mockup: a studio-lit beveled phone whose screen renders your real React children as DOM. Springs between present, landscape, exploded-stack and back poses (or scroll-scrubs via progress), drag to spin, rises in with a soft contact shadow. Offscreen-paused, reduced-motion-safe, CSS-frame fallback.
r3fpro
Pro
The preview is live. The source is Pro.
One purchase, lifetime access: every pro component's source, CLI install with your own registry token, and all future drops.
Installation
CLI
npx shadcn@latest add @crucible/handsetManual — install dependencies, then copy the source
npm install three @react-three/fiber @react-three/dreiProps
| Prop | Type | Default | Description |
|---|---|---|---|
| children | React.ReactNode | Live React content rendered ON the screen as real DOM (focusable, clickable), laid out in a screenWidth-px-wide portrait viewport. Note: it mounts in a separate React root, so app-level context providers do not reach it — pass data in as props. | |
| screenSrc | string | Image URL shown on the screen when no children are given (cover-fit). | |
| pose | HandsetPose | "present". Overridden by progress when set | Preset pose. |
| progress | number | Scroll-scrub control, 0–1. Overrides pose: 0 → present, .33 → landscape, .66 → explode, 1 → back, interpolated in between. | |
| finish | HandsetFinish | "metal" (brushed titanium-silver) | Body material. |
| interactive | boolean | true | Drag (or focus + Left/Right arrows) to spin; springs back to the current pose. |
| paused | boolean | Freeze all motion: no intro, no idle drift, pose changes are instant and drag is disabled. Reduced motion behaves the same (drag stays, damped). | |
| screenWidth | number | 300 | CSS width (px) of the screen's layout viewport. |
| label | string | "Device mockup" | Accessible name for the device region. |
| className | string | relative aspect-[4/5] w-full | Extra classes for the wrapper. |
| ref | React.Ref<HandsetHandle> | Imperative handle: setPose(), replay(). |
Honors prefers-reduced-motion with a designed static fallback, pauses offscreen and on hidden tabs, and passes className through.