Spindle

Don't take our word. Spin the file.

Fig. 1 — Spindle, live captureOpen the live demo ↗12 s loop · recorded frame by frame on GPU

Field notes

A testimonials page that is a rotary card file. Sixteen reviews hang on an axle as ruled index cards: they fall one by one, riffle when you flick the file or turn the knob, and the reading card pulls out to face you with the rest of the quote.

  • 3D
  • Pointer interaction
  • Light theme

Spindle is the kind-words page of Fair Copy, a fictional bookkeeping app. A black card file sits on a putty desk: two side plates, a chrome axle, a ribbed knob. Sixteen ivory index cards hang on it, each with a lettered tab, a name, a role and a quote on blue rules. Step through them and each card falls forward under gravity, bounces once and joins the pile, showing its back: the company and one result. Flick the file and it keeps spinning, slowing to a stop on a card. Jump to a letter and it riffles the shorter way round. Click the reading card and it comes out to face you with the second half of the quote.

There is no canvas: the file is HTML under CSS 3D transforms, so every review is real text in the accessibility tree and there is nothing to fall back from. The whole pose comes from two numbers, and a 12-second tour goes exactly once round the ring before handing over mid-motion at the first touch. Everything works from the keyboard and reduced motion cuts instead of falling. The reviews, the names and every string live in one file, copy.ts.

How it's built

  • A ring with no reset: each card's angle is a function of its distance from the reading spot. Cards waiting lean back, read cards lie on a pile, and the two ranges meet at 180 degrees under the axle, out of sight. So the position can run forever in either direction.
  • Gravity without physics: one card moves linearly in position, and the angle function does the falling: t squared for the first 80 %, then one small bounce. A riffle is the same function with the position eased.
  • A flick that keeps the hand's speed: a cubic ease-out over 3 × distance ÷ speed seconds starts at exactly the release speed, so there is no jerk between dragging and coasting, and it always stops on a whole card.
  • No canvas: the file is DOM under preserve-3d. Each card's two faces are flat sheets, so text and marks cannot z-fight with the paper, and backface-visibility hides a whole face at once. All sixteen reviews stay in the accessibility tree.
  • One frame from one clock: the state keeps when a move started, never how far along it is. The tour is the same actions fed a fixed list of inputs; it passes all sixteen cards, so second 12 equals second 0, and the first touch adopts it mid-motion.

Inside the prompt

Every file below is written out in full, so your agent creates the project exactly — no guessing, no missing pieces.

spindle-testimonials/
├─ .gitignore
├─ check.ts
├─ index.html
├─ package.json
├─ tsconfig.json
├─ vite.config.ts
└─ src/
   ├─ App.tsx
   ├─ index.css
   ├─ main.tsx
   ├─ vite-env.d.ts
   ├─ components/
   │  ├─ Copy.tsx
   │  └─ File.tsx
   └─ lib/
      ├─ copy.ts
      ├─ live.ts
      ├─ loop.ts
      ├─ pose.ts
      ├─ time.ts
      └─ timeline.ts

Recut it

  • Replace the reviews, the product name and every stringsrc/lib/copy.ts + index.html → REVIEWS / PRODUCT / COPY / <title>
  • Change how many cards there aresrc/lib/copy.ts + src/lib/timeline.ts → REVIEWS / TOUR
  • Retime a fall, a riffle, a pull or a flicksrc/lib/timeline.ts → STEP, PER_CARD, LIFT, FLICK_REACH
  • Reshape the fall or the fan of cardssrc/lib/pose.ts → angle() / READ, FALLEN, LAND
  • Change the toursrc/lib/timeline.ts → TOUR
  • Recolour the desk, the cards and the frame, or change the fontssrc/index.css + index.html → @theme
  • Change the camera angle or the drag gearingsrc/components/File.tsx → VIEW, DRAG, KNOB
  • Add a mark to the cardssrc/lib/copy.ts + src/components/File.tsx + src/index.css → Mark / Card / .stamp

Also in the vault