Studio KitAnimated Backgrounds and Visual Effectsno dependencies

Meteors

A meteor-shower background of glowing streaks falling at a configurable angle, driven entirely by CSS keyframes with deterministic per-meteor positions and timing.

Preview

Meteor Shower

Pure CSS streaks with deterministic timing.

Customize

4 props
14
1
135

Installation

Copies the component source and its CSS Module into your project.

npx motionfoundry add meteors

Writes components/ui/meteors.tsx and components/styles/meteors.module.css.

Usage

Updates live as you change the controls — only props that differ from the defaults are included.

example.tsx
1import { Meteors } from "@motionfoundry/ui";2 3export function Example() {4  return (5    <Meteors />6  );7}

Props

PropTypeDefault
count

Number of meteors in the shower.

number14
speed

Speed multiplier; each meteor's base fall time is 2-5s divided by this value.

number1
angle

Travel direction in degrees, clockwise from pointing right (135 = down-left).

number135
meteorColor

Color of the meteor head glow and trail.

string'#38bdf8'
children

Foreground content centered above the shower.

React.ReactNode'Meteor Shower' heading
className

Additional class merged onto the root element.

string''

Accessibility

The meteor layer is aria-hidden and pointer-events: none; foreground children keep their own semantics. Positions and timings come from a seeded rand(n) so SSR markup is stable. Under prefers-reduced-motion the animation is removed and meteors render as faint static streaks.

Toggle prefers-reduced-motion in your OS or browser devtools (Rendering → Emulate CSS media feature) to verify the reduced-motion state.

Source

components/ui/meteors.tsx
1"use client";2 3import * as React from "react";4import styles from "../styles/meteors.module.css";5 6export interface MeteorsProps {7  /** Number of meteors in the shower */8  count?: number;9  /** Speed multiplier (1 = base 2–5s fall per meteor) */10  speed?: number;11  /** Travel direction in degrees, clockwise from pointing right (135 = down-left) */12  angle?: number;13  /** Meteor head and trail color */14  meteorColor?: string;15  /** Foreground content rendered above the shower */16  children?: React.ReactNode;17  /** Optional className merged onto the root */18  className?: string;19}20 21const rand = (n: number) => {22  const x = Math.sin(n * 9301 + 49297) * 233280;23  return x - Math.floor(x);24};25 26export function Meteors({27  count = 14,28  speed = 1,29  angle = 135,30  meteorColor = "#38bdf8",31  children,32  className = "",33}: MeteorsProps) {34  const safeSpeed = speed > 0 ? speed : 1;35  const total = Math.max(0, Math.round(count));36  const styleVars = {37    "--mf-mt-color": meteorColor,38    "--mf-mt-angle": `${angle}deg`,39  } as React.CSSProperties;40 41  return (42    <div style={styleVars} className={`${styles.root} ${className}`.trim()}>43      <div aria-hidden="true" className={styles.sky}>44        {Array.from({ length: total }, (_, i) => (45          <span46            key={i}47            className={styles.meteor}48            style={{49              left: `${(rand(i) * 130 - 10).toFixed(2)}%`,50              top: `${(rand(i + 7) * 50 - 15).toFixed(2)}%`,51              animationDuration: `${((2 + rand(i + 1) * 3) / safeSpeed).toFixed(2)}s`,52              animationDelay: `-${(rand(i + 2) * 5).toFixed(2)}s`,53            }}54          />55        ))}56      </div>57      <div className={styles.content}>58        {children ?? (59          <div className={styles.copy}>60            <h3 className={styles.title}>Meteor Shower</h3>61            <p className={styles.subtitle}>Pure CSS streaks with deterministic timing.</p>62          </div>63        )}64      </div>65    </div>66  );67}