Skip to content

3D & effects

Two layers of depth. CSS 3D effects ship in @pelagic-ui/react and cost no JavaScript beyond the component. WebGL scenes live in @pelagic-ui/three: they follow the theme, pause off-screen, render a single still frame under reduced motion and fall back gracefully without WebGL. Three.js is only downloaded when a 3D scene scrolls into view.

15 components on this page. Every demo is live — change the theme in the header or flip a demo to right-to-left with its RTL button. These components are React-only for now; Vue, Svelte and Angular versions are coming.

TiltCard Link to TiltCard

A card that tilts toward the pointer with an optional glare highlight.

Live demo
Free

Starter

$0 / month

Popular

Pro

$29 / month

Best value

Team

$99 / month

Props

PropTypeDescription
maxTilt number Maximum tilt in degrees. Default 10.
glare boolean Light glare that follows the pointer.
padded boolean Inner padding.

Accessibility

Purely visual: content stays readable and focusable; the tilt is disabled under prefers-reduced-motion.

Code

ReactComing to Vue, Svelte and Angular.

TiltCard · React
<TiltCard maxTilt={12}>
  <h3>Pro plan</h3>
  <p>$29 / month</p>
</TiltCard>

FlipCard Link to FlipCard

A two-sided card flipped by a real toggle button.

Live demo

Question

What does WCAG stand for?

Showing: front

Props

PropTypeDescription
front / back ReactNode Faces.
flipLabel ReactNode Button text. Default “Show back”.
flipped / onFlippedChange boolean Controlled state.
height string Card height.

Accessibility

FlipCard keyboard support
KeyAction
Enter / Space Flip (on the flip button)

The button reports aria-pressed; the hidden face is aria-hidden and inert. Crossfades instead of rotating under reduced motion.

Code

ReactComing to Vue, Svelte and Angular.

FlipCard · React
<FlipCard height="14rem" front={<p>What is WCAG?</p>} back={<p>Web Content Accessibility Guidelines.</p>} />

CubeCarousel Link to CubeCarousel

Slides on the faces of a rotating cube. Drag or swipe to turn it.

Live demo

📊 Charts

15 accessible chart types with data tables.

Slide: 1 of 4

Props

PropTypeDescription
label string Accessible name (required).
slides { title?, content }[] Slides.
index / onIndexChange number Controlled slide.
autoplay number Interval (ms); pauses on hover and focus.

Accessibility

CubeCarousel keyboard support
KeyAction
Arrow Left / Arrow Right Previous / next slide (mirrored in RTL)
Home / End First / last slide

aria-roledescription="carousel"; inactive faces are hidden from assistive tech and the new slide is announced. With reduced motion (OS or data-a11y-motion="off") it is a flat slider.

Code

ReactComing to Vue, Svelte and Angular.

CubeCarousel · React
<CubeCarousel label="Release highlights" slides={[
  { title: 'Charts', content: <p>15 accessible chart types</p> },
  { title: '3D', content: <p>WebGL with fallbacks</p> },
]} />

Carousel3D Link to Carousel3D

A perspective carousel in three modes — coverflow, ring and stack — with drag and swipe, dots and autoplay.

Live demo

Charts

15 accessible chart types, each with a data table.

Slide: 1 of 5: Charts

Props

PropTypeDescription
label string Accessible name (required).
slides { title?, content }[] Slides.
mode 'coverflow' | 'ring' | 'stack' Layout in depth. Default coverflow.
index / onIndexChange number Controlled slide.
autoplay number Interval (ms, min 2000). Adds a pause button; pauses on hover and focus.
loop / showDots boolean Wrap around; slide picker dots.
slideWidth / height string Slide size (CSS lengths; use vw or rem for ring mode).

Accessibility

Carousel3D keyboard support
KeyAction
Arrow Left / Arrow Right Previous / next slide (mirrored in RTL)
Home / End First / last slide

APG carousel: the rotation control comes first, slides are labelled groups ("2 of 5: Themes"), neighbours are visible but aria-hidden and inert, and the slide region is polite only when not rotating. Reduced motion turns it into a plain slider and never autoplays.

Code

ReactComing to Vue, Svelte and Angular.

Carousel3D · React
<Carousel3D label="Product gallery" mode="coverflow" autoplay={5000} slides={[
  { title: 'Charts', content: <ChartsCard /> },
  { title: 'Themes', content: <ThemesCard /> },
  { title: 'RTL', content: <RtlCard /> },
]} />

ParallaxLayers Link to ParallaxLayers

Layers that move at different depths with the pointer or on scroll.

Live demo

Explore Wadi Rum

Move your pointer over the scene.

Props

PropTypeDescription
layers { content, depth, decorative? }[] Depth: 0 (static) to ~1 (moves most).
trigger 'pointer' | 'scroll' What drives the motion.

Accessibility

Decorative layers are aria-hidden; motion stops under prefers-reduced-motion.

Code

ReactComing to Vue, Svelte and Angular.

ParallaxLayers · React
<ParallaxLayers layers={[
  { content: <Sky />, depth: 0.2, decorative: true },
  { content: <Hills />, depth: 0.5, decorative: true },
  { content: <h2>Explore</h2>, depth: 0.9 },
]} />

Text3D Link to Text3D

Extruded headline text built from layered shadows (alias: ExtrudedText).

Live demo

Pelagic UI

بيلاجيك

Props

PropTypeDescription
as ElementType Element. Default h2.
depth number (1–16) Extrusion depth.
tone 'primary' | 'surface' Colour.

Accessibility

Real text, so it is selectable, translatable and read normally.

Code

ReactComing to Vue, Svelte and Angular.

Text3D · React
<Text3D as="h2" depth={8}>Pelagic UI</Text3D>

Floating3DIcon Link to Floating3DIcon

A decorative floating tile for icons in heroes and empty states.

Live demo

Decorative tiles — pair them with real headings.

Props

PropTypeDescription
icon ReactNode Glyph or SVG.
size string CSS size.

Accessibility

Decorative (aria-hidden). Pair it with real text.

Code

ReactComing to Vue, Svelte and Angular.

Floating3DIcon · React
<Floating3DIcon icon="🚀" size="5rem" />

OrbitBadge Link to OrbitBadge

A decorative badge with satellites orbiting on a tilted ring.

Live demo
WCAG 2.2 AA

The badge itself is decorative; this text carries the meaning.

Props

PropTypeDescription
children ReactNode Centre content.
size string CSS size.

Accessibility

Decorative (aria-hidden); orbit stops under reduced motion.

Code

ReactComing to Vue, Svelte and Angular.

OrbitBadge · React
<OrbitBadge size="8rem">AA</OrbitBadge>

Perspective3DStack Link to Perspective3DStack

Cards stacked in perspective that fan out on hover or when open.

Live demo
  • Invoice #1041

    $1,200 · Paid

  • Invoice #1042

    $860 · Due in 5 days

  • Invoice #1043

    $2,450 · Overdue

Props

PropTypeDescription
items / children ReactNode[] Cards.
label string List name.
open boolean Fan out permanently.

Accessibility

A labelled list, so the number of cards is announced.

Code

ReactComing to Vue, Svelte and Angular.

Perspective3DStack · React
<Perspective3DStack label="Recent invoices" items={[<Invoice n={1} />, <Invoice n={2} />, <Invoice n={3} />]} />

Scene3D Link to Scene3D

The base of every WebGL component: bring your own Three.js setup and get theming, resizing, pausing and fallbacks.

Live demo
Loading 3D scene

Props

PropTypeDescription
setup (ctx) => SceneHandle | cleanup Build the scene; return { tick, cleanup, onColors }.
label / description string / ReactNode Text alternative (or decorative).
interactive boolean Pointer drag + keyboard orbit.
camera { fov, position, near, far } Camera options.
fallback ReactNode Shown without WebGL.

Accessibility

Scene3D keyboard support
KeyAction
Tab Focus the scene
Arrow keys Rotate the camera
+ / - Zoom in / out

role="img" with your label; the canvas itself is aria-hidden. Animation is limited to one frame under reduced motion and pauses off-screen.

Code

ReactComing to Vue, Svelte and Angular.

Scene3D · React
import { Scene3D } from '@pelagic-ui/three';
import { Mesh, TorusKnotGeometry, MeshStandardMaterial, DirectionalLight } from 'three';

<Scene3D label="Rotating torus knot" interactive setup={({ scene, colors }) => {
  const mesh = new Mesh(new TorusKnotGeometry(0.7, 0.22, 160, 24), new MeshStandardMaterial({ color: colors.primary }));
  scene.add(mesh, new DirectionalLight(0xffffff, 2));
  return { tick: (dt) => { mesh.rotation.y += dt * 0.6; } };
}} />

Globe3D Link to Globe3D

A dotted globe with labelled markers and animated arcs.

Live demo
Loading 3D scene

Props

PropTypeDescription
markers { lat, lng, label }[] Locations.
arcs { from, to, label? }[] Connections.
autoRotate / interactive boolean Motion and orbit controls.
showList boolean Visible list of locations (always available to screen readers).
dots number Dot density.

Accessibility

Globe3D keyboard support
KeyAction
Tab Focus the scene
Arrow keys Rotate the camera
+ / - Zoom in / out

Markers and connections are also rendered as lists, so the data is never locked inside the canvas.

Code

ReactComing to Vue, Svelte and Angular.

Globe3D · React
import { Globe3D } from '@pelagic-ui/three';

<Globe3D label="Our offices" showList
  markers={[{ lat: 31.95, lng: 35.93, label: 'Amman' }, { lat: 51.5, lng: -0.12, label: 'London' }]}
  arcs={[{ from: { lat: 31.95, lng: 35.93 }, to: { lat: 51.5, lng: -0.12 }, label: 'Amman → London' }]} />

ParticlesField Link to ParticlesField

An ambient drifting particle background in the theme colour.

Live demo
Loading 3D scene

Props

PropTypeDescription
count number Particles. Default 600.
speed number Drift speed multiplier.
background boolean Position behind content.
height string CSS height.

Accessibility

Decorative (aria-hidden); still under reduced motion.

Code

ReactComing to Vue, Svelte and Angular.

ParticlesField · React
<div style={{ position: 'relative' }}>
  <ParticlesField count={800} />
  <h1>Hero title</h1>
</div>

FloatingShapes Link to FloatingShapes

Glassy geometric shapes floating slowly — for hero backgrounds.

Live demo
Loading 3D scene

Props

PropTypeDescription
count number Shapes. Default 5.
background boolean Position behind content.
height string CSS height.

Accessibility

Decorative (aria-hidden).

Code

ReactComing to Vue, Svelte and Angular.

FloatingShapes · React
<FloatingShapes count={6} height="20rem" />

Chart3D Link to Chart3D

A 3D bar chart with an always-available data table.

Live demo
Loading 3D scene

Props

PropTypeDescription
title string Caption (required).
data { label, value }[] Bars.
format (value) => string Value formatting.
showTable boolean Show the table visibly (it is always present for screen readers).
valueLabel / categoryLabel string Table headers.

Accessibility

Chart3D keyboard support
KeyAction
Tab Focus the scene
Arrow keys Rotate the camera
+ / - Zoom in / out

Code

ReactComing to Vue, Svelte and Angular.

Chart3D · React
<Chart3D title="Revenue by region ($M)" showTable format={(v) => '$' + v + 'M'}
  data={[{ label: 'MENA', value: 12.4 }, { label: 'Europe', value: 9.1 }, { label: 'Americas', value: 7.6 }]} />

ModelViewer Link to ModelViewer

Loads and displays a glTF/GLB model with orbit controls, progress and an error state.

The demo builds a small model in your browser with GLTFExporter and loads it from a blob URL — no external file.

Live demo
Loading 3D scene

Props

PropTypeDescription
src string URL of a .glb / .gltf file.
alt string Text alternative (required).
autoRotate / interactive boolean Motion and controls.
loadingLabel / errorText / fallback … States.
onLoad / onError callbacks Lifecycle.

Accessibility

ModelViewer keyboard support
KeyAction
Tab Focus the scene
Arrow keys Rotate the camera
+ / - Zoom in / out

Code

ReactComing to Vue, Svelte and Angular.

ModelViewer · React
import { ModelViewer } from '@pelagic-ui/three';

<ModelViewer src="/models/chair.glb" alt="Walnut lounge chair" autoRotate height="22rem" />

Search Pelagic UI