CoreAdvanced Text Animationsno dependencies

OrbitingWords

Spatial typography composition where satellite labels orbit a focal phrase with 3D perspective depth, counter-rotation legibility, and static layout mode.

Preview

MotionFoundry Core
React 19TypeScriptMotion 14CSS ModulesCLI RegistryMIT License

Customize

5 props
108
18
22

Installation

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

npx motionfoundry add orbiting-words

Writes components/ui/orbiting-words.tsx and components/styles/orbiting-words.module.css.

Usage

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

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

Props

PropTypeDefault
centerPhrase

Focal anchor phrase rendered at the center.

string'MotionFoundry Core'
words

Satellite labels positioned along the orbital ring.

string[]['React 19', 'TypeScript', ...]
radius

Orbital ring radius in pixels.

number108
duration

Seconds per full 360-degree revolution.

number18
mode

Toggle continuous orbital rotation or fixed spatial layout.

'animated' | 'static''animated'
tilt

3D perspective pitch angle in degrees.

number22

Accessibility

Renders a semantic list of orbiting terms for assistive technology and switches automatically to a clean radial static badge layout when mode='static' or prefers-reduced-motion is enabled.

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

Source

components/ui/orbiting-words.tsx
1"use client";2 3import * as React from "react";4import styles from "../styles/orbiting-words.module.css";5 6export interface OrbitingWordsProps {7  /** Focal phrase in the center */8  centerPhrase?: string;9  /** Satellite labels orbiting the center */10  words?: string[];11  /** Orbit radius in pixels */12  radius?: number;13  /** Seconds per full revolution */14  duration?: number;15  /** Animated or static layout mode */16  mode?: "animated" | "static";17  /** Perspective pitch angle in degrees */18  tilt?: number;19  /** Optional className */20  className?: string;21}22 23const DEFAULT_WORDS = [24  "React 19",25  "TypeScript",26  "Motion 14",27  "CSS Modules",28  "CLI Registry",29  "MIT License",30];31 32export function OrbitingWords({33  centerPhrase = "MotionFoundry Core",34  words = DEFAULT_WORDS,35  radius = 108,36  duration = 18,37  mode = "animated",38  tilt = 22,39  className = "",40}: OrbitingWordsProps) {41  const safeWords = words.length > 0 ? words : DEFAULT_WORDS;42  const isStatic = mode === "static";43 44  return (45    <div46      style={47        {48          "--mf-orbit-radius": `${radius}px`,49          "--mf-orbit-duration": `${duration}s`,50          "--mf-orbit-tilt": `${tilt}deg`,51        } as React.CSSProperties52      }53      className={`${styles.stage} ${className}`.trim()}54    >55      <div className={styles.centerNode}>{centerPhrase}</div>56      <div57        aria-label={`Satellite capabilities: ${safeWords.join(", ")}`}58        className={`${styles.ring} ${isStatic ? styles.ringStatic : styles.ringAnimated}`}59      >60        {safeWords.map((word, idx) => {61          const angle = (360 / safeWords.length) * idx;62          const rad = (angle * Math.PI) / 180;63          const x = Math.cos(rad) * radius;64          const y = Math.sin(rad) * radius * 0.62;65          return (66            <span67              key={`${word}-${idx}`}68              style={{69                transform: `translate3d(${x.toFixed(1)}px, ${y.toFixed(1)}px, 0)`,70              }}71              className={`${styles.wordTag} ${isStatic ? "" : styles.counterRotate}`.trim()}72            >73              {word}74            </span>75          );76        })}77      </div>78    </div>79  );80}