Paper deformation
Grab a card corner and fold it like real paper. CSS clip-path morphing with spring physics — 6 approaches tried, pure CSS won.
Cards on this site are styled to look like paper on a desk. This experiment takes that metaphor further: grab any corner and the card folds like a real sheet of paper.
The final approach uses pure CSS — no WebGL, no texture capture. The card’s entire shape is a clip-path: path() with a quadratic bezier that morphs from a rounded corner into a straight diagonal fold line. A sibling flap element shows the paper’s back side. Spring physics drive the animation.
Controls
How it works
- LIFT — drag a corner and it straightens from a rounded arc to a straight diagonal (Q bezier morph)
- FOLD — a small fold-over triangle appears on the crease, growing from a sliver to fill the diagonal
- PULL — the fold-over and crease grow together as you drag further
- Release — damped spring snaps everything back to the default state
The fold line is always a 45° diagonal. The flap’s hypotenuse is geometrically locked to the clip’s diagonal — no gap. Pre-folded cards start at different stages to show the range.
The journey: 6 approaches tried
Getting here wasn’t straightforward. We tried 6 different approaches — from CSS clip-path to Three.js mesh deformation and back. Each mini-demo below shows what the approach looked like (hover to interact, or click where noted):
Empty Overlay Divs
Applied clip-path to empty <div> overlays inside the card. But clip-path on an empty transparent div is invisible — the card looks completely unchanged. Nothing happens.
Child Flap (Clip Inheritance)
Applied clip-path to the card itself and placed a paper-colored flap as a child element. But CSS clip-path clips ALL descendants — the child flap gets clipped along with the content. It can never escape the parent's clip boundary.
Sibling Flap (Flat Fold)
Placed the flap as a sibling element outside the card's DOM — no clip inheritance. The fold-over triangle is visible. But it's a rigid flat triangle — the text doesn't bend with the fold.
Three.js Mesh Deformation
Captured the card as a Canvas texture and mapped it onto a subdivided Three.js plane. Vertex deformation created a beautiful cylindrical curl — but the texture never matched the DOM. foreignObject produced black textures. Canvas 2D manual drawing had wrong fonts and colors.
R3F + html2canvas
Switched to React Three Fiber with html2canvas for better texture fidelity. Colors were closer but still slightly grey. A 150ms cross-fade hid the mismatch somewhat, but the transition was still noticeable.
Pure CSS Fold (Current)
No WebGL, no texture capture. The card's shape is entirely clip-path: path() with a Q bezier that morphs from rounded corner → straight diagonal. A sibling flap shows the paper-back color. Three phases: LIFT (corner straightens), FOLD (flap grows on crease), PULL (both grow). The DOM is always real DOM — zero fidelity loss.