3D Book
uselayouts/3d-bookFreeComponent
An interactive 3D book component with page flip animations.
Live preview
live · rendered by the registry
Rendered by uselayouts on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://uselayouts.com/r/3d-book.jsonSource
1"use client";23import { useRef, useState } from "react";45export default function InteractiveBook() {6 const bookRef = useRef<HTMLDivElement>(null);7 const [progress, setProgress] = useState(0);8 const [isDragging, setIsDragging] = useState(false);910 // Linear interpolation function11 const lerp = (a: number, b: number, t: number) => a + (b - a) * t;1213 const handlePointerMove = (e: React.PointerEvent<HTMLDivElement>) => {14 if (!bookRef.current) return;1516 const rect = bookRef.current.getBoundingClientRect();17 const cursorX = e.clientX;18 const bookCenterX = rect.left + rect.width / 2;1920 // Calculate how far cursor is from center (-1 to 1)21 const distanceFromCenter = (cursorX - bookCenterX) / (rect.width / 2);2223 // Map cursor position to progress24 // Left side (negative) = open (1), Right side (positive) = closed (0)25 const targetProgress = lerp(1, 0, (distanceFromCenter + 1) / 2);2627 // Clamp between 0 and 128 setProgress(Math.max(0, Math.min(1, targetProgress)));29 };3031 const handlePointerDown = (e: React.PointerEvent<HTMLDivElement>) => {32 setIsDragging(true);33 handlePointerMove(e);34 };3536 const handlePointerUp = () => {37 setIsDragging(false);38 setProgress(0);39 };4041 const handlePointerLeave = () => {42 // Close book when cursor leaves (only if not dragging on mobile)43 if (!isDragging) {44 setProgress(0);45 }46 };4748 // Generate pages - all at same size and position49 const totalPages = 15;50 const pages = [];5152 // All pages same size, different rotation angles53 for (let i = 1; i <= totalPages; i++) {54 const rotationAngle = (i + 1) * 10; // -20, -30, -40... -1605556 pages.push(57 <div58 key={i}59 className="absolute h-48 md:h-72 w-32 md:w-52 rounded-lg md:rounded-2xl border border-border bg-background light"60 style={61 {62 transformStyle: "preserve-3d",63 transformOrigin: "left",64 transform: `rotateY(calc(var(--book-progress) * ${-rotationAngle}deg))`,65 zIndex: 50 + i,66 backfaceVisibility: "visible",67 "--book-progress": progress,68 } as React.CSSProperties69 }70 />71 );72 }7374 return (75 <div className="flex w-full h-full items-center justify-center ">76 <div77 ref={bookRef}78 className="w-32 md:w-52 h-48 md:h-72 will-change-transform translate-x-16 md:translate-x-24 touch-none"79 onPointerMove={handlePointerMove}80// … truncated
What it pulls in
npm packages
Files it writes
More from uselayouts
All 26 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Animated Collectionanimated-collection | uselayouts | Components | Free | 5 deps | |
| Bento Cardbento-card | uselayouts | Components | Free | 5 deps | |
| Bottom Menubottom-menu | uselayouts | Components | Free | 6 deps | |
| Bucketbucket | uselayouts | Components | Free | 5 deps · 2 files | |
| Day Pickerday-picker | uselayouts | Components | Free | 5 deps | |
| Delete Buttondelete-button | uselayouts | Components | Free | 5 deps | |
| Discover Buttondiscover-button | uselayouts | Components | Free | 5 deps | |
| Discrete Tabsdiscrete-tabs | uselayouts | Components | Free | 3 deps |
