← All elements

Aurora Ribbon

Surface

A solid glowing plane with flowing vertex displacement that mimics an aurora borealis.

Usage
Install: three @react-three/fiber @react-three/drei
Drop <AuroraRibbon /> inside your own <Canvas>.
Mood
Ethereal, expansive, serene.
Colors
Violet surface glow transitioning through cyan on near-black.
Motion
Slow undulating waves ripple across the surface continuously.
View component source
import { useMemo, useRef } from 'react';
import { useFrame } from '@react-three/fiber';
import * as THREE from 'three';
import type { Mesh, BufferAttribute } from 'three';

const SEGX = 96;
const SEGY = 48;

export default function AuroraRibbon({ scale = 1 }: { color?: string; scale?: number }) {
  const ref = useRef<Mesh>(null);

  // Fixed cyan -> violet -> magenta gradient baked as per-vertex colors across X.
  const colors = useMemo(() => {
    const nx = SEGX + 1;
    const ny = SEGY + 1;
    const c1 = new THREE.Color('#22e0ff');
    const c2 = new THREE.Color('#8a5cff');
    const c3 = new THREE.Color('#ff2fd0');
    const tmp = new THREE.Color();
    const arr = new Float32Array(nx * ny * 3);
    for (let iy = 0; iy < ny; iy++) {
      for (let ix = 0; ix < nx; ix++) {
        const t = ix / (nx - 1);
        if (t < 0.5) tmp.copy(c1).lerp(c2, t * 2);
        else tmp.copy(c2).lerp(c3, (t - 0.5) * 2);
        const idx = (iy * nx + ix) * 3;
        arr[idx] = tmp.r;
        arr[idx + 1] = tmp.g;
        arr[idx + 2] = tmp.b;
      }
    }
    return arr;
  }, []);

  useFrame((state) => {
    const mesh = ref.current;
    if (!mesh) return;
    const t = state.clock.elapsedTime;
    const pos = mesh.geometry.attributes.position as BufferAttribute;
    for (let i = 0; i < pos.count; i++) {
      const x = pos.getX(i);
      const y = pos.getY(i);
      pos.setZ(i, Math.sin(x * 1.4 + t) * 0.4 + Math.cos(y * 1.3 + t * 0.7) * 0.28);
    }
    pos.needsUpdate = true;
  });

  return (
    <mesh ref={ref} rotation={[-0.5, 0, 0]} scale={scale}>
      <planeGeometry args={[5, 3, SEGX, SEGY]}>
        <bufferAttribute attach="attributes-color" args={[colors, 3]} />
      </planeGeometry>
      <meshBasicMaterial vertexColors toneMapped={false} side={THREE.DoubleSide} transparent opacity={0.95} />
    </mesh>
  );
}