Skip to content

FreeIn reviewv1.0.0

Aurora

Curtains of northern light over a night sky and a mountain ridge, drawn toward the pointer.
npx shadcn@latest add @vibebox/aurora

Controls

1
1
<Aurora />

About

An aurora drawn as ribbons instead of a volume. Each ribbon's centre line meanders across the frame on two slow waves and some noise; brightness is a sharp lower edge with a long fade upward, multiplied by vertical striations of gradient noise (the rays) and a slower curl. The colour runs from the base colour at the lower edge through the body to the crown. Three stars layers sit behind, a ridge in front lit faintly by the sky's own light.

Use it when

  • A hotel, lodge or tour operator sells the north or the stars.
  • A software, AI or analytics product wants a calm, atmospheric night hero.
  • An event or festival page wants colour without a photo.

Skip it when

  • The brand is bright and light; use Cloudscape or Satin.
  • Long body copy sits directly on the curtains.

Install

  1. 1Add the VibeBox registry to components.json:
    {
      "registries": {
        "@vibebox": "https://motion.vibeboxph.com/r/{name}.json"
      }
    }
  2. 2Add the component with the shadcn CLI:
    npx shadcn@latest add @vibebox/aurora
  3. 3Use it:
    import { Aurora } from "@/components/vibebox/aurora";
    
    <Aurora preset="arctic" className="min-h-[560px] rounded-xl">
      <div className="p-12 text-white">
        <h1 className="text-4xl font-semibold">Dark skies, long nights, one fire.</h1>
      </div>
    </Aurora>

Code

3 files
components/vibebox/aurora/aurora.client.tsx
/**
 * VibeBox Motion · Aurora
 * Copyright (c) 2026 VibeBox. Licensed under the VibeBox Motion Free License:
 * https://motion.vibeboxph.com/license
 * Use it in unlimited personal, commercial and client projects.
 * Do not sell or redistribute it as a component, kit, template or builder.
 */
"use client";

import type { ReactNode } from "react";
import { BackdropCanvas, type PosterSpec } from "@/lib/vibebox/backdrop-canvas";
import { auroraPiece, presets, type AuroraPreset } from "./aurora.shader";

export type AuroraColor = "sky" | "base" | "mid" | "crown" | "ridge";
export type AuroraValue = "bands" | "height" | "rays" | "stars" | "hill";

export type AuroraProps = {
  /** What sits on the scene: a heading, a call to action, a whole section. */
  children?: ReactNode;
  /** A named look: `arctic`, `violet`, `rose`, `ember`, `pastel`. */
  preset?: AuroraPreset;
  /** Overrides single palette colours with any CSS colour. */
  colors?: Partial<Record<AuroraColor, string>>;
  /** Multiplies the preset's speed (1 keeps it, 0 holds the scene still). */
  speed?: number;
  /** Multiplies the preset's brightness. */
  intensity?: number;
  /** The pointer and touch move the scene. */
  interactive?: boolean;
  /** Accessible name; leave it out when the scene is only a background. */
  label?: string;
  /** Hold one still frame until this is false (for a gallery card). */
  still?: boolean;
  className?: string;
} & Partial<Record<AuroraValue, number>>;

const POSTER: PosterSpec = { type: "linear", from: "sky", to: "ridge", mid: "sky", angle: 180, blobs: [{ color: "base", at: [30, 38], size: 55 }, { color: "mid", at: [72, 28], size: 50 }, { color: "crown", at: [50, 8], size: 45 }] };

export function Aurora({ children, preset, colors, speed, intensity, interactive = true, label, still, className, bands, height, rays, stars, hill }: AuroraProps) {
  return (
    <BackdropCanvas
      slug="aurora"
      piece={auroraPiece}
      presets={presets}
      fallback="arctic"
      preset={preset}
      colors={colors}
      values={{ bands, height, rays, stars, hill }}
      speed={speed}
      intensity={intensity}
      poster={POSTER}
      scale={0.5}
      stillTime={3}
      still={still}
      interactive={interactive}
      label={label}
      className={className}
    >
      {children}
    </BackdropCanvas>
  );
}
components/vibebox/aurora/aurora.shader.ts
/**
 * VibeBox Motion · Aurora
 * Copyright (c) 2026 VibeBox. Licensed under the VibeBox Motion Free License:
 * https://motion.vibeboxph.com/license
 * Use it in unlimited personal, commercial and client projects.
 * Do not sell or redistribute it as a component, kit, template or builder.
 */
import { compose, createScenePiece, type ScenePreset } from "@/lib/vibebox/engine/backdrops";

/*
 * Curtains of light over a night sky. Three ribbons wander across the frame; each is a band whose
 * brightness streaks vertically (the rays), fades upward and takes its colour from a ramp, from
 * the base colour at the bottom edge to the crown colour at the top. Stars sit behind, a ridge
 * silhouette in front, and the pointer draws the curtains toward it.
 */

const SCENE = /* glsl */ `
uniform vec3 uSky;
uniform vec3 uBase;
uniform vec3 uMid;
uniform vec3 uCrown;
uniform vec3 uRidge;
uniform float uBands;
uniform float uHeight;
uniform float uRays;
uniform float uStars;
uniform float uHill;
uniform float uSpeed;
uniform float uIntensity;

float T;

float starLayer(vec2 uv, float scale, float seed) {
  vec2 g = uv * scale;
  ivec2 c = ivec2(floor(g)) + ivec2(int(seed) * 37, int(seed) * 11);
  vec2 f = fract(g);
  vec2 o = h22(c) * 0.7 + 0.15;
  float r = h2(c + ivec2(3, 8));
  float d = length(f - o);
  float tw = 0.6 + 0.4 * sin(T * (0.7 + r * 2.5) + r * 31.0);
  return smoothstep(0.06 + r * 0.03, 0.0, d) * step(0.82, r) * tw;
}

/* One curtain: a ribbon whose centre line meanders across the frame. */
vec3 curtain(vec2 uv, float k, vec2 pull) {
  float kk = float(k);
  float x = uv.x * (1.1 + 0.2 * kk) + pull.x * 0.25 + kk * 3.7;
  // The centre line of the curtain, wandering with two slow waves and a little noise.
  float baseline = -0.02 + 0.1 * sin(x * 1.7 + T * 0.12 + kk * 1.3) + 0.05 * sin(x * 3.9 - T * 0.2 + kk) + (fbm3(vec2(x * 1.3, T * 0.04 + kk * 9.0)) - 0.5) * 0.18;
  float dy = uv.y - baseline - 0.06 * kk - pull.y * 0.12;
  // Brightness along the height: a sharp lower edge and a long fade upward.
  float up = clamp(dy / (0.36 * uHeight), 0.0, 1.0);
  float body = smoothstep(-0.02, 0.025, dy) * pow(1.0 - up, 1.6);
  // Rays: vertical striations that shimmer.
  float rays = 0.5 + 0.5 * gnoise(vec2(x * 22.0 * uRays, T * 0.25 + kk * 4.0));
  rays = mix(1.0, pow(rays, 1.5) * 1.6, 0.8);
  float curl = 0.65 + 0.35 * gnoise(vec2(x * 3.2 + T * 0.1, kk * 5.0 + dy * 2.0));
  float a = body * rays * curl;
  // Colour: base at the lower edge, mid through the body, crown at the top.
  vec3 c = mix(lin(uBase), lin(uMid), smoothstep(0.0, 0.35, up));
  c = mix(c, lin(uCrown), smoothstep(0.35, 1.0, up));
  return c * a;
}

void main() {
  vec2 uv = centred(gl_FragCoord.xy);
  T = uTime * uSpeed;
  float aspect = uResolution.x / uResolution.y;
  vec2 pu = vec2((uPointer.x - 0.5) * aspect, uPointer.y - 0.5);
  vec2 pull = (pu - uv) * 0.2 * uHover * exp(-length(pu - uv) * 1.6);

  vec3 sky = lin(uSky);
  vec3 col = mix(sky * 1.6, sky * 0.5, smoothstep(-0.45, 0.5, uv.y));
  // Stars, three depths.
  float stars = starLayer(uv + vec2(T * 0.002, 0.0), 46.0, 1.0) * 1.0 + starLayer(uv * 1.0, 80.0, 2.0) * 0.7 + starLayer(uv, 130.0, 3.0) * 0.5;
  col += vec3(0.85, 0.92, 1.0) * stars * uStars * smoothstep(-0.3, 0.2, uv.y);

  // The curtains, additive.
  vec3 glow = vec3(0.0);
  for (int i = 0; i < 3; i++) {
    if (float(i) >= uBands) break;
    glow += curtain(uv, float(i), pull) * (1.0 - 0.18 * float(i));
  }
  col += glow * 1.35;
  // A faint wash of the mid colour across the whole sky.
  col += lin(uMid) * 0.05 * smoothstep(0.3, -0.2, uv.y) * uBands;

  // The ridge in front.
  float hx = uv.x * 1.3 + 1.7;
  float ridge = -0.34 + uHill * (0.1 * (fbm3(vec2(hx * 1.4, 1.0)) - 0.5) + 0.14 * (ridged(vec2(hx * 0.9, 5.0)) - 0.5) * 2.0);
  float edge = smoothstep(ridge + 0.004, ridge - 0.004, uv.y);
  // The sky's light falls faintly on the nearest slope.
  vec3 ridgeCol = lin(uRidge) + glow * 0.12;
  col = mix(col, ridgeCol, edge);

  col *= uIntensity;
  col *= 1.0 - 0.3 * smoothstep(0.55, 1.2, length(uv * vec2(0.9, 1.05)));
  fragColor = vec4(finish(col, gl_FragCoord.xy), 1.0);
}
`;

export const fragment = compose(SCENE);

export const PRESET_NAMES = ["arctic", "violet", "rose", "ember", "pastel"] as const;
export type AuroraPreset = (typeof PRESET_NAMES)[number];

export const presets: Record<AuroraPreset, ScenePreset> = {
  arctic: {
    colors: { sky: "#050b1a", base: "#4dffa8", mid: "#19c9a6", crown: "#7a6bff", ridge: "#02060d" },
    values: { bands: 3, height: 1, rays: 1, stars: 1, hill: 1, speed: 0.8, intensity: 1 },
  },
  violet: {
    colors: { sky: "#08061a", base: "#7cf0ff", mid: "#7b5cff", crown: "#ff5fd2", ridge: "#030212" },
    values: { bands: 3, height: 1.1, rays: 1.1, stars: 1, hill: 1, speed: 0.8, intensity: 1 },
  },
  rose: {
    colors: { sky: "#120816", base: "#ff9ec2", mid: "#ff5f9f", crown: "#8f6bff", ridge: "#08030c" },
    values: { bands: 2, height: 1, rays: 0.9, stars: 0.8, hill: 1, speed: 0.7, intensity: 1 },
  },
  ember: {
    colors: { sky: "#0d0707", base: "#ffd36a", mid: "#ff7a3a", crown: "#d6336c", ridge: "#050202" },
    values: { bands: 3, height: 0.95, rays: 1.2, stars: 0.7, hill: 1, speed: 0.75, intensity: 1 },
  },
  pastel: {
    colors: { sky: "#1c2142", base: "#bff3e0", mid: "#a8c8ff", crown: "#f2b8ff", ridge: "#10152b" },
    values: { bands: 3, height: 1.15, rays: 0.7, stars: 0.9, hill: 0.8, speed: 0.55, intensity: 0.72 },
  },
};

export const auroraPiece = createScenePiece("aurora", fragment);
components/vibebox/aurora/index.tsx
/**
 * VibeBox Motion · Aurora
 * Copyright (c) 2026 VibeBox. Licensed under the VibeBox Motion Free License:
 * https://motion.vibeboxph.com/license
 * Use it in unlimited personal, commercial and client projects.
 * Do not sell or redistribute it as a component, kit, template or builder.
 */
export { Aurora, type AuroraProps, type AuroraColor, type AuroraValue } from "./aurora.client";
export { PRESET_NAMES as AURORA_PRESETS, presets as auroraPresets, type AuroraPreset } from "./aurora.shader";

Props

PropTypeDefaultDescription
childrenReactNode—What sits on the scene: a heading, a call to action, a whole section.
preset"arctic" | "violet" | "rose" | "ember" | "pastel""arctic"The look: arctic, violet, rose, ember, pastel.
colors{ sky?: string; base?: string; mid?: string; crown?: string; ridge?: string }—Overrides single palette colours with any CSS colour: sky (the night sky), base (the lower edge of the curtain), mid (the body of the curtain), crown (the crown, high in the curtain), ridge (the mountain silhouette).
speednumber1Multiplies the preset's speed; 0 holds the scene still.
intensitynumber1Multiplies the preset's brightness, 0.5 to 1.4.
bandsnumber3How many ribbons of light (1 to 3) (1 to 3; each look sets its own).
heightnumber1How tall the curtains rise (0.5 to 1.6; each look sets its own).
raysnumber1How fine the vertical striations are (0.4 to 2; each look sets its own).
starsnumber1How many stars show (0 to 1.5; each look sets its own).
hillnumber1How tall and rugged the ridge is (0 to 1.5; each look sets its own).
interactivebooleantrueThe pointer draws the curtains toward it.
labelstring—Accessible name; leave it out when the scene is only a background.
stillbooleanfalseHold one composed frame until false (a gallery card that plays on hover).
classNamestring—Merged with cn(); give it a size and a radius.

Accessibility and motion

Keyboard
Not focusable; content on it keeps its own focus order.
Screen readers
Decorative by default; with label it is an image with that name.
Touch
A finger moves the scene like the cursor does; scrolling is never blocked.
Reduced motion
One still frame of the aurora; the curtains do not move.

Edge cases and limits

  • The curtains are the brightest thing in the frame: put copy in the dark sky or on the ridge.
  • The pastel look is gentler; check white text on it.
  • More than two ribbons on a phone fills the small sky; set bands to 2.
  • A dusk skyline of lit towers under an orange and violet sky

    A skyline of lit windows against a glowing sky, with a road of light trails in front.

    Backgrounds · WebGL2

  • A sea of white cloud under a peach sunrise sky

    A sea of cloud seen from above, or a ceiling of it seen from below, lit by a low sun.

    Backgrounds · WebGL2

  • Warm amber bokeh lights of different sizes on a dark background

    Bokeh

    Free

    Out-of-focus lights in three depths, brighter at the rim and drifting with the pointer.

    Backgrounds · WebGL2

↑ ↓ to move↵ to openesc to close