Quirebound
Free

Folio — 3D Book Collection

A book collection that behaves like a table rather than a grid: three hardbacks fanned in real 3D, a torn paper slip that follows the cursor, and a selection that drops the other two out of frame while the chosen one peels open.

Folio — 3D Book Collection

The prompt — 4 sections

Stage Foundation

Build a single-screen book collection called **Folio**. Three hardbacks float in a fan at the bottom of the frame, in real 3D, and the whole page is one viewport — no scroll.
- **Stack:** React + Tailwind + Three.js. One canvas, `position: fixed`, everything else HTML on top of it.
- **Palette:** page a top-lit radial from `#1B2246` through `#141A33` to `#0F142A`, ink `#FDFBF4`, muted `#C9D0EE`, accent `#F591AC` — a chalk pink used for the wordmark, the titles and the rim light, and nowhere else.
- **Type:** one heavy grotesque at 800 for display, a neutral sans for body. No mono, no third face.
The word **Books** sits behind the fan at `min(22.5vw, 45vh)`, pink, tracking `-0.015em`, line-height `0.85`. It is the page's only headline and the books overlap its lower half — that overlap is the whole composition, so do not add clearance.
Camera at `z: 9.9` with a **26° vertical FOV**. A wide lens makes the fan splay and look like a stock 3D mockup; a long lens keeps the boards nearly parallel, which is what reads as photographed.

Building a Book

No GLB, no external model. Each book is four boxes.
- Board `1.42 × 2.14`, spine thickness `0.34`, cover board `0.032` thick, boards overhanging the block by `0.05` on the three open sides.
- **Front board** hinged at the spine: parent the mesh to an empty positioned at the spine edge and offset the mesh back by half its width, so `hinge.rotation.y` peels the cover instead of sliding it.
- **Page block** slightly inset, textured on all four visible edges with a fine vertical striation. The cut block is what separates a book from a decorated cuboid.
- **Spine strip** carrying foil lettering, set to read top-to-bottom.
Every face texture is **painted into a 2D canvas at runtime** and uploaded as a `CanvasTexture` — front artwork, back blurb, spine, page edge. Three reasons, in order: publisher cover CDNs send no `Access-Control-Allow-Origin` so the texture load fails anyway; shipping real jackets in a template ships someone else's artwork; and a painted cover can be recoloured per book from one function.
Add grain to every painted face by walking the `ImageData` and nudging each channel by ±12. Flat vector fill under a key light is the single loudest tell that a 3D book is fake.
Invent the three titles. Give each its own painter — rings, a deco sun over banded water, cut-paper shapes — so no two covers look like the same template with the colour swapped.

Motion & Selection

Every transform is a spring, `k: 110`, `d: 16`, integrated against real delta time. Nothing uses a CSS transition or a fixed-duration tween.
**Hover.** Raycast against the whole book group, not just the front board, so the page edge and the spine are targets too. The hovered book rises `0.12`, comes forward `0.32`, scales `1.035`, and its cover cracks open `0.14rad` — a hint, not a reveal.
**The slip.** While a book is hovered, a torn scrap of paper reading `OPEN` follows the cursor, lagging at `0.18` per frame and tilting into its own velocity. Cut every edge with a `clip-path` deckle and shadow it with `drop-shadow`, not `box-shadow`, so the shadow follows the tear instead of a rectangle. It is never interactive — the click lands on the book underneath.
**Selection.** The chosen book moves left and forward, its cover peels to `0.5rad`, and sixteen loose leaves fade up and drift through the scene. The other two do **not** simply fall: float them up `0.42`, hang for `300ms`, then drop `5.4` below frame, staggered `50ms` apart. A spring aimed straight at the floor accelerates the whole way and reads as a dropped prop rather than a dismissed one.
**Peel.** Dragging left on a selected book opens the cover the rest of the way, `320px` of travel for the full swing. Distinguish it from a click by distance: under 8px is a click, over is a drag.

Sheet & Access

The detail panel is HTML, never geometry. Right at `7vw` on desktop, along the bottom edge on portrait — and on portrait move the book *up* to sit above the sheet rather than letting them overlap.
Title in pink at `clamp(38px, 5.6vw, 92px)`. Blurb in muted at `1.65` line-height, capped at `54ch`. A metadata row of star rating, author and year, then a hairline, then the actions: language, Buy now, Audiobook, and a save button. Stagger the five children in at `60ms` intervals on a `cubic-bezier(0.22, 1, 0.36, 1)`.
Three things this page owes anyone who is not using a mouse:
1. **A keyboard route in.** The books are canvas pixels, so picking cannot be the only way to reach them. Render one real button per book, `sr-only` until focused, then visible in the corner.
2. **Escape closes**, from anywhere, without the close button needing focus.
3. **A reduced-motion fallback that skips the canvas entirely** rather than freezing it — three flat boards in the same fan, laid out in CSS.
Pause the render loop on `IntersectionObserver` and `visibilitychange`. A book collection nobody is looking at should not be costing them battery.