Skip to content
Black FridayBlack Friday launch price: Lifetime $149 until 30 Nov. Regular price $299 from 1 Dec.ends in 15d 03:13:37Get Lifetime →
loopkit
proNew281 lines · framer-motion, three

Hero Ribbon 3D

A tube of light, undulating across the page. A hero with copy stacked above a wide three.js ribbon: a tube mesh following a fixed S-curve, rippling via a per-vertex travelling-wave displacement in a custom shader, so no geometry is rebuilt per frame.

Use it for
Release trains, roadmaps or 'always in motion' product pitches that want a wide decorative 3D element without a geometry-heavy scene.
Themes
Light + dark
License
Commercial use
Live
Flow · Release train

A ribbon that never stops moving

A three.js tube mesh, undulating in real time, running the width of the page behind your pitch.

tsx
"use client";

import * as React from "react";
import { motion, useReducedMotion } from "framer-motion";
import { cn } from "@/lib/utils";

function useReducedMotionSafe() {
  const prefersReduced = useReducedMotion();
  const [mounted, setMounted] = React.useState(false);
  React.useEffect(() => setMounted(true), []);
  return mounted ? !!prefersReduced : false;
}

/**
 * Hero with copy stacked above a wide three.js ribbon: a tube mesh following a
 * fixed S-curve, undulating via a per-vertex travelling-wave displacement in a
 * custom shader (no geometry rebuilt per frame). three.js is imported lazily.
 */

export interface HeroRibbon3dProps {
  eyebrow?: string;
  headline?: string;

The rest is in Pro.

Full source, the rebuild prompt and registry install unlock with Pro or Lifetime.

Get Pro

How it behaves

  • →A THREE.TubeGeometry is built once from a fixed Catmull-Rom S-curve; a custom ShaderMaterial displaces each vertex along its normal by sin(uv.x * 14 + time), so the ripple travels the length of the ribbon without touching the geometry buffers.
  • →speed scales the time fed into the ripple; thickness sets the tube radius (rebuilds the geometry); colorway swaps which two design tokens the ribbon's length-wise gradient blends between (signal: --signal/--info, cool: --info/--lime, mono: --foreground/--muted-foreground).
  • →The whole mesh gets a small secondary sway (rotation.y/z) driven by slow sine functions, independent of the shader ripple, for extra depth.
  • →Colours are read from computed CSS custom properties and refreshed on every .dark class toggle via MutationObserver.
  • →If the WebGLRenderer can't acquire a context, a flat gradient bar stands in for the ribbon.
  • →Render loop pauses off-screen and when the tab is hidden; prefers-reduced-motion renders one still frame.
  • →On unmount: cancels the frame, disposes the geometry and shader material, calls renderer.dispose() + renderer.forceContextLoss(), and removes the canvas.

Accessibility

  • ✓The ribbon canvas and its fallback bar are aria-hidden; only the eyebrow, heading, copy and two real <a> CTAs are exposed to assistive tech.
  • ✓Headline is a single <h1>; the three text blocks and the ribbon band stack cleanly on narrow screens.
  • ✓CTAs keep the design system's visible focus ring.
  • ✓Honours prefers-reduced-motion.