Meridian, Flowing Menu Curtain
What it does
A vertical list of large rows where hovering pulls an inverted sheet across the row, carrying the row's own name on an endless marquee with a photographic still between each repetition. The sheet enters from whichever horizontal edge the pointer actually crossed and leaves towards the edge it exits by, measured on both events with a squared-distance test against the top and bottom midpoints. Panel and strip travel in opposite directions — the panel from ∓101%, its content from ±101% — so the marquee holds almost still against the window while the sheet wipes over it, which is what makes it read as a physical sheet rather than a div sliding up. The loop is seamless because exactly one measured copy of the content is animated, and the copy count is derived from that width against the viewport and recomputed on resize.
How it's built
| Category | hover |
|---|---|
| Tech | gsap |
| Complexity | section |
| Performance cost | light |
| Mobile-safe | yes |
Rebuild it with AI
This component's prompt is part of the paid library. Below you can read how it starts; the full prompt, the exact structure, timing and easing an AI agent needs to rebuild the effect, unlocks with any paid plan, yearly or lifetime.
# Flowing Menu Curtain (closest-edge marquee sheet)
## Goal
Build a contents page whose rows answer the hand. Hovering a row pulls an **inverted sheet** across it — ink where the page is paper — carrying that row's own name on an endless marquee with a photographic still between each repetition. The sheet does not simply rise: it **enters from whichever horizontal edge the pointer actually crossed**, and leaves towards the edge it exits by. Come down onto a row and the sheet comes down with you; come up from below and it rises to meet you.
The demo dress is **Meridian**, a printed quarterly cut into five sections.
## Tech
Vanilla HTML/CSS/JS with ES module imports. **`gsap` (npm), no plugins:**
```js
import gsap from "gsap";
```
No ScrollTrigger, no Lenis, no SplitText. Everything runs inside a `DOMContentLoaded` listener.
Write the engine so it takes **every hook as a `data-` attribute selector** rather than hard-coded class names — `[data-flow-item]`, `[data-flow-panel]`, `[data-flow-strip]`, `[data-flow-part]`. It costs four lines and it means the same engine drops into a page with a completely different naming scheme without an edit.
That does mean each hook is written twice in the markup: a **class for painting** and a **`data-` attribute for moving**. That is the deal, and it is worth it — the alternative is an engine that can only ever be used by a page that agreed to its class names.
…
Premium prompt
Unlock this prompt, and every other one
From $99/year, or $139 once for lifetime access. Commercial license included.
See pricing Or start with the free set Already bought? Sign in
New components in your inbox
One email a week, only when new components ship, each with its live demo and prompt.