An interactive physics-based text animation where the entire body of text behaves as a continuous physical string. Drag the dangling end to unravel the paragraph letter by letter, watch it fall under gravity, and bounce off the viewport edges.
The full opening of Alice's Adventures in Wonderland is laid out in a zig-zag snake pattern — each line reversing direction so the text forms one unbroken chain. The last few characters hang freely; pull them and the chain propagates back through the paragraph.
Controls:
| Action | Effect |
|---|---|
| Drag the dangling end | Unravels the string, pulling subsequent letters free |
Press F |
Toggles gravity — releases all remaining locked letters at once |
| Multitouch | Supported — grab multiple free letters simultaneously |
- Node.js 18 or later
- npm (bundled with Node.js)
npm install
npm run devThen open http://localhost:5173 in your browser.
npm run build # outputs to dist/
npm run preview # preview the production build locallyThe text is segmented into individual graphemes using Intl.Segmenter and the pretext line-breaking library. Each grapheme is placed in reading order, then the lines are re-ordered into a zig-zag (snake) sequence so the string connects end-to-end across rows without any gaps:
Line 1 → A l i c e w a s b e g i n n i n g …
Line 2 ← … g n i t t i s y b d e r i t y r e v
Line 3 → …
Each letter is a node in a Verlet-integrated particle chain:
- Verlet integration — velocity is implicit in the difference between current and previous position, giving stable simulation without an explicit velocity variable.
- Distance constraints — solved iteratively (12 passes per tick) to keep consecutive letters at their rest length × 1.2.
- Circle-circle collision — non-adjacent unlocked letters repel each other with radius 7 px.
- Boundary reflection — letters bounce off all four viewport edges with a damping coefficient of 0.4.
- Fixed timestep — the simulation runs at 120 Hz regardless of display refresh rate (capped at 4 steps per frame to prevent spiral-of-death on tab resume).
Letters start locked in place. When the chain between a locked letter and its unlocked neighbour is stretched beyond its rest length + 1 px, that letter is released. This creates a cascade that travels back through the whole paragraph as you drag.
├── index.html # Single HTML shell — styles live here
├── main.ts # All simulation logic (layout → physics → render)
├── pretext.js # Bundled pretext text-layout library
├── pretext.d.ts # TypeScript declarations for pretext.js
├── tsconfig.json # TypeScript config (strict, ES2022, bundler resolution)
├── package.json
└── public/
└── drag.png # "Drag me" hint graphic
- TypeScript 5 — strict mode, ES2022 target
- Vite 6 — dev server and bundler (handles
.tsfiles natively) - pretext — Unicode-aware line-breaking and text measurement
- No runtime frameworks or UI libraries
Prashant Koirala