Backgrounds

Floating Card Field

A field of cards drifting at different depths in 3D space: pointer parallax varies by depth, scrolling pulls the whole field back and scatters it, and distant cards blur for depth of field.

This is a WebberUI Pro component

The install command below needs a licence to run; without one it returns 401.

How to install Pro components →See the plans →

Scatter work thumbnails, UI screenshots or any node across different depths as the backdrop for a landing page or portfolio. Each card's position, depth, rotation and size are derived deterministically from a seed and its index, so server and browser render the same layout; near cards are large and sharp, distant ones small and blurred. As the pointer moves, near cards shift more than far ones for parallax; scrolling away pulls the whole field back and scatters it outward from the center. A headline and buttons can sit in the middle — foreground content does not drift.

Bring this into your project

Run this command in your project folder. The CLI adds the source and dependencies; then follow the usage example below.

npx webberui@latest add "https://webberui.com/r/floating-card-field.en.json?t=<install token>"

New project or installation trouble? Start here →

Playground

Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.

12
4
10
40
9
Active edited usageDefault props
<FloatingCardField/>

The complete example includes the preview layout and data. Install the component first, then paste this file into your project.

Installation

npx webberui@latest add "https://webberui.com/r/floating-card-field.en.json?t=<install token>"

Or, once registries are configured in components.json, install it as @webberui/floating-card-field.

Usage

import {
  FloatingCardField,
  type FloatingCard,
} from "@/components/ui/floating-card-field";

const cards: FloatingCard[] = [
  { id: "a", src: "/works/dashboard.png" },
  { id: "b", src: "/works/album.png" },
  { id: "c", node: <div className="h-full w-full bg-gradient-to-br from-sky-400 to-indigo-500" /> },
  // An explicit position and depth override the automatic layout
  { id: "d", src: "/works/player.png", x: 30, y: -20, z: 0.1 },
];

<FloatingCardField cards={cards} height="100vh" depthBlur={4} parallax={40}>
  <h1 className="text-4xl font-semibold">Your work deserves to be seen</h1>
</FloatingCardField>;

Props

PropTypeDefaultDescription
cardsFloatingCard[]—Card list
countnumber—Use only the first count cards; uses all when omitted
seednumber1Layout seed; change it for a different arrangement
depthBlurnumber4Depth-of-field blur (px); a card blurs by depth × depthBlur
parallaxnumber40Maximum pointer parallax offset (px), multiplied by (1 − depth)
driftnumber10Amplitude of each card's slow drift (px)
scatternumber160Maximum outward scatter distance (px) while scrolling away
cardWidthnumber168Base card width (px), multiplied by a 0.8–1.2 size factor; aspect ratio 4:3
heightnumber | string"100vh"Container height; numbers are px
containerRefObject<HTMLElement | null>—Pass when scrolling happens in a nested overflow container; defaults to the window
childrenReactNode—Centered foreground content; does not drift
classNamestring—Forwarded to the outermost container

FloatingCard

FieldTypeDefaultDescription
idstring—React key; falls back to the index
nodeReactNode—Card content; takes precedence over src
srcstring—URL of your own image
altstring""Image alt text; the field is decorative, so usually empty
xnumberhashHorizontal percent from the center (−45 to 45)
ynumberhashVertical percent from the center (−40 to 40)
znumberhashDepth 0–1; 0 nearest, 1 farthest

The FloatingCard and FloatingCardFieldProps types are also exported by name.

How it works

  • Deterministic layout: each card uses mulberry32 seeded by seed and index to produce its position, depth, rotation (−8° to 8°), size (0.8–1.2) and drift rhythm — no Math.random, so server and browser render identically
  • Depth rendering: scale = 1 − depth × 0.5, opacity = 1 − depth × 0.35, blur = depth × depthBlur, and nearer cards stack on top. Depth is simulated with scale rather than translateZ because a filter blur flattens preserve-3d
  • Pointer parallax: the pointer position relative to the container center maps to −1..1, is smoothed by a spring (stiffness 80, damping 20), then multiplied by (1 − depth) × parallax; disabled on touch devices
  • Drift rhythm: each card floats on CSS keyframes with a period of --wb-fcf-drift-period (default 9s) times a 0.67–1.33 factor, staggered with a negative animation-delay. Override the variable to speed up or slow down the whole field
  • Scroll pull-back: scroll progress runs from the container top meeting the viewport top (0) to the container bottom leaving the viewport top (1); the field scales down to 0.7, each card moves scatter px outward from the center, and opacity drops another 30%
  • Pausing: while the container is off-screen, drift animations pause and parallax stops updating

Accessibility

  • The card field is decorative: the whole layer is aria-hidden and ignores pointer events; avoid putting focusable elements inside cards
  • children live in a separate foreground layer that is not hidden, so headlines and buttons remain readable and operable
  • When the user's system has "reduce motion" enabled, there is no drift, no pointer parallax and no scroll pull-back or scatter — cards rest at their initial positions; depth blur and scale are static depth cues and are kept