Wind Scatter

ProShowcase & Mediapowered by @vectorvesper/motion

A deck of cards stacked at the centre that takes flight on hover — each card lifts into 3D, barrel-rolls through the air and settles around the edge of the viewport, leaving the middle clear. Scroll or click the background to call them back.

Wind Scatter

Included with membership

Members install Wind Scatter with one command and get the full source, the usage code and the Framer remix, licensed for client work. One membership covers the whole library and the CLI.

When to use it

An index that should feel like handling a physical deck — a portfolio landing, a case-study picker, a menu that hides until asked for. The centre clears as the cards scatter, so it works well when there is something underneath worth revealing. It wants the whole viewport; it is not a widget to drop in a column.

  • Give it the full viewport. Cards land around the perimeter, so a small container throws them outside their own box.
  • Give every card a stable id — it keys the flight state, and a changing id restarts a card mid-air.
  • Use eight to sixteen cards. Fewer looks sparse around a large perimeter; many more and the edge gets crowded.
  • Use renderCard when you need more than a picture and two lines — it receives whether that card is currently scattered.

Avoid:

  • Do not put anything interactive in the centre expecting it to stay reachable. The stack sits there until the cards scatter.
  • Do not disable both gatherOnBackgroundClick and enableWheelGather — those are the only two ways back, and the deck would stay scattered for good.
  • Do not use full-resolution photographs. Every card is a live 3D-transformed element, and the deck is on screen the whole time.
  • Do not nest it in a scrolling column with enableWheelGather on; the wheel drives the deck instead of the page.

Props

A deck of cards stacked in the middle of the screen that scatters when you approach it. Each card lifts, rolls through the air and lands somewhere around the edge of the viewport, clearing the centre. Scroll or click the empty space to gather them back into the stack.

<WindGustScatter />

The deck, its flight simulation and the perimeter it lands on. Fills its container.

PropTypeDefaultDescription
items*WindCardItem[]—The cards, in order. Required — nothing renders without it.
cardWidthnumber260Card width in pixels while stacked at the centre.
cardHeightnumber350Card height in pixels while stacked at the centre.
flightSpeednumber1.0Multiplier on how quickly a card travels between the stack and the perimeter. Higher is faster, not further.
scatterScalenumberderived from the card countHow much a card shrinks once it reaches the edge. Left unset it scales down as the deck grows, so a large set still fits around the perimeter.
spinDegreesnumber360How far a card rolls during its flight. A full turn reads as a tumble; smaller values read as a glide.
gatherOnBackgroundClickbooleantrueClicking the empty centre recalls every card to the stack.
enableWheelGatherbooleantrueWheel and trackpad scrolling drive the deck between scattered and gathered. Turn it off when the component lives inside a page that needs to scroll.
onCardDisperse(index: number, item: WindCardItem) => void—Fires when an individual card leaves the stack.
onCardGather(index: number, item: WindCardItem) => void—Fires when an individual card returns.
onAllDispersed() => void—Fires once the last card has reached the perimeter — useful for revealing what was underneath.
onAllGathered() => void—Fires once every card is back in the stack.
renderCard(item: WindCardItem, index: number, isDispersed: boolean) => React.ReactNode—Replaces the built-in card face. Receives whether that card is currently scattered, so you can show more once it has landed.
classNamestring""Applied to the wrapper.
styleReact.CSSProperties—Inline styles merged onto the wrapper.
mount"auto" | "eager""auto"When to arrange the cards. The default waits until the page has frame headroom to spare. Set "eager" to scatter them immediately. Note this defaults the opposite way from the components that build a 3D scene: those start eagerly and take "auto" to defer. Both mean the same thing by "auto" — let the runtime pick the moment — the default just matches what each component already did. Neither setting takes it off the shared frame loop or overrides the reduced-motion preference.

<WindCardItem />

type

One card. Every field is optional, but give at least an id and a src — or use renderCard and supply your own content through metadata.

PropTypeDefaultDescription
idstring—Stable key for the card and its flight state.
srcstring—The picture on the card face.
titlestring—Headline on the card.
subtitlestring—Supporting line beneath it.
metadataRecord<string, unknown>—Anything else you need, passed straight through to renderCard.
It reads the visitor's reduced-motion preference and moves each card straight to its destination instead of flying it there. Scattering and gathering still work and the layout still changes — nothing tumbles across the screen to get there.
Every card is a 3D-transformed element updated each frame while the deck is on screen, so cost follows the card count rather than the image size. Keep the pictures near the size they are drawn at; a scattered card is small.
Client component. It measures the viewport to place the perimeter and reads the pointer, so it has to run in the browser.
Back to all components