- Role: Solo. Design and front-end development.
- When: 2026, ahead of the event on August 9 in Shanghai
- Stack: TypeScript, Vite (multi-page), Three.js, custom GLSL, Locomotive Scroll, GSAP
- Live: miracool.org
The idea
Miracool is an annual gathering of motion-graphics artists in China. The 2026 edition took place on August 9 at the NEO VERSE theater in Shanghai, with 38 exhibitors and showcasers.
The audience makes the brief unusual: they animate things for a living. A static event page would look wrong to them. So the site needed to feel like their medium, while still doing a landing page’s job: what the event is, when and where, how to submit work, how to get in, who is showing, and what came before.
I laid it out as an editorial sequence of chapters and a numbered rail down the side, like a magazine spread.
Scrolling in chapters
On desktop, one scroll gesture moves exactly one chapter. Getting that right took more work than the shader did.
The trackpad was the hard case. A single flick fires dozens of wheel events, and a naive version skips three chapters at once. The fix: add up the wheel deltas, trigger once the total crosses a small threshold, then ignore everything until the gesture has been quiet for 180 ms. Each jump is a 0.66 second eased scroll through Locomotive Scroll, locked so it can’t be interrupted halfway. Keyboard shortcuts are ignored while you are typing in a field.
Inside each chapter, layers move at different speeds: the back layer travels further than the headline, decorations drift sideways in alternating directions, and a chapter fades as you leave it.
Below 781px wide, or when the visitor has asked for reduced motion, all of this switches off and the page scrolls normally. Snapping on a phone fights the thumb.
A cursor from After Effects
Hovering over headlines, images, schedule rows or cards draws a selection box around them, with corner handles and a live width and height readout. It is the selection box every motion designer stares at all day in After Effects. It only appears on devices with a real mouse, and it follows the element while the page scrolls.
An exhibitor page from a spreadsheet
After the event, the site gained a second page: every exhibitor and their work. The organizers already kept all of it in a spreadsheet: names, self-introductions, work titles, links, notes.
Instead of retyping it into HTML, the page reads the spreadsheet itself. The sheet is exported to CSV, Vite imports the raw file, and a small parser (quoted fields, commas and line breaks inside cells) turns each row into a card with avatar, cover images, work titles, links and role tags, such as staff or collaboration. And together they form a Masonry Layout. Long notes fold into an expandable block, and a numbered index at the top links to each card. Updating the list means re-exporting the sheet.

Building it
It is a plain TypeScript and Vite multi-page build with no framework: the main page and the exhibitor page are separate entries, and Three.js and GSAP are split into their own chunks. The campaign film is embedded from Bilibili.
