Page Sections

Drifting Logos Hero

A centred headline over a field of partner marks drifting slowly at different speeds and directions, with a subtle parallax that follows the pointer.

Behind a centred headline, subtitle and CTAs sits a layer of fictional partner marks (circle + letter, triangle, wave or a plain wordmark). Each mark derives its position, drift amplitude (12–40px), period (18–36s) and rotation (±6°) from an index hash and drifts back and forth along a small ellipse; when the pointer moves inside the section the whole layer shifts up to ±12px, scaled by each mark's depth. The drift is pure CSS transform, and no mark is placed inside the centre 40% width reserved for the headline.

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 drifting-logos-hero.en

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
1
600
Active edited usageDefault props
<DriftingLogosHero/>

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/drifting-logos-hero.en.json

Or, once registries are configured in components.json, install it as @webberui/drifting-logos-hero.

Usage

import { DriftingLogosHero } from "@/components/ui/drifting-logos-hero";

<DriftingLogosHero
  eyebrow="已有 120+ 個團隊導入"
  title="把出貨流程交給一張看板"
  subtitle="訂單、倉儲、配送狀態集中在同一個畫面。"
  primaryAction={{ label: "免費試用", href: "/signup" }}
  secondaryAction={{ label: "看客戶案例", href: "/customers" }}
  marks={[
    { label: "北辰物流" },
    { label: "Orbis", shape: "circle" },
    { label: "Peakline", shape: "triangle" },
    { label: "潮聲音樂", shape: "wave" },
  ]}
  density={16}
/>

Props

PropTypeDefaultDescription
titleReactNode—Main headline (required)
eyebrowReactNode—Small label above the title, shown in the accent colour
subtitleReactNode—Subtitle below the headline
primaryActionDriftingLogosHeroAction—Primary CTA with an accent background
secondaryActionDriftingLogosHeroAction—Secondary, outlined CTA
as"h1" | "h2""h1"Heading level; use "h2" when the page already has an h1
minHeightnumber560Minimum section height (px)
marksDriftingLogo[]12 fictional marksPartner marks drifting in the background; reused cyclically when fewer than density
densitynumber12Number of background marks, capped at 24
parallaxbooleantrueShift the marks layer up to ±12px with the pointer, scaled by depth
speednumber—Drift speed multiplier written to --wb-drifting-logos-hero-speed; higher is faster, falls back to the CSS variable (default 1)
durationnumber—Entrance duration (ms) written to --wb-drifting-logos-hero-duration; falls back to the CSS variable (default 600)
announceMarksbooleanfalseAnnounce partner names to screen readers via an sr-only list
marksLabelstring"合作夥伴" (Partners)Accessible name of the sr-only list
classNamestring—Merged into the root section
FieldTypeDefaultDescription
labelstring—Mark text, also the name read out by the sr-only list
shape"circle" | "triangle" | "wave" | "text""text"Mark shape; circle puts the first character of the label inside a ring

DriftingLogosHeroAction

FieldTypeDefaultDescription
labelstring—Button label
hrefstring—Renders an <a> when set, otherwise a <button type="button">
onClick(event: React.MouseEvent<HTMLElement>) => void—Click handler

How it works

  • Deterministic layout: an 8 × 5 grid minus the headline zone, picked in index-hash order and jittered ±30% within each cell, so SSR and client render the exact same composition with no hydration mismatch.
  • The drift is an inline CSS @keyframes along an ellipse with alternate; negative delays start each mark at a different point on its path, and the period is divided by --wb-drifting-logos-hero-speed.
  • Parallax uses useMotionValue + useSpring (stiffness 120, damping 20) and only responds to mouse and pen, so touch drags do not make the marks jump.
  • Hovering a single mark raises it to full opacity and switches it to the accent colour (200ms).
  • Overridable CSS variables: --wb-drifting-logos-hero-accent (default #0d9488, #2dd4bf in dark mode), --wb-drifting-logos-hero-speed, --wb-drifting-logos-hero-duration.
  • Entrance order: eyebrow, title, subtitle, CTAs rise 16px and fade in, 80ms apart, easing cubic-bezier(0.22,1,0.36,1).

Accessibility

  • The root is a <section aria-labelledby> pointing at the title's useId.
  • The marks layer is aria-hidden and purely decorative; turn on announceMarks to expose partner names through an sr-only list.
  • CTAs are <a> elements or type="button" buttons with a focus-visible ring.
  • With reduce motion enabled, all drifting stops and parallax is disabled for a static composition; the entrance becomes a 150ms fade with no stagger.