npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

awesome-galaxy-orbit-carousel

v0.1.0

Published

A stunning galaxy-themed 3D orbital carousel React component with elliptical orbit rings, gravitational pull animations, per-slide accent colours, and a sci-fi core.

Readme

awesome-galaxy-orbit-carousel

A stunning galaxy-themed 3D orbital carousel React component. Slides orbit the central core on tilted elliptical rings with Kepler-inspired depth scaling, gravitational pull focus animations, a pulsing sci-fi core, starfield background, and full keyboard navigation — zero external dependencies beyond React.


Features

  • Multi-ring elliptical orbits — slides distributed across 1–4 rings, auto-computed from slide count or fully customisable
  • Kepler-inspired depth — slides closer to the viewer scale up and brighten; distant slides fade back
  • Gravitational pull animation — clicking or auto-advancing a slide triggers a visual "pull" before focus locks
  • Animated galaxy core — pulsing orb at center updates colour to match the focused slide
  • Orbit path rings — decorative ellipse outlines with per-ring accent tints
  • Starfield + nebula background — 120 blinking stars and radial nebula clouds
  • Autoplay with configurable interval — pauses on hover automatically
  • Keyboard navigation / to cycle slides, Enter to fire onClick
  • Planet cards — each slide renders as a card with image, tag badge, title, description, and an Explore CTA on focus
  • ESM + CJS dual build — works in Vite, Next.js, CRA, and any modern bundler
  • Full TypeScript types included

Installation

npm install awesome-galaxy-orbit-carousel
# or
yarn add awesome-galaxy-orbit-carousel
# or
pnpm add awesome-galaxy-orbit-carousel

Peer dependencies — React ≥ 17 and ReactDOM ≥ 17 must already be installed.


Importing Styles

The component relies on keyframe animations (pulseGlow, coreSpin, corePulse, ringPulse, fadeUp) and CSS custom properties (--font-display, --font-body) declared in a separate stylesheet. Import it once at your app root:

import 'awesome-galaxy-orbit-carousel/style.css';

For the best visual result, load these Google Fonts in your index.html <head>:

<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
  href="https://fonts.googleapis.com/css2?family=Syne:wght@700;800;900&family=DM+Sans:wght@300;400;500&display=swap"
  rel="stylesheet"
/>

The component still renders correctly without the fonts — it falls back to sans-serif.


Quick Start

import { AwesomeGalaxyOrbitCarousel } from 'awesome-galaxy-orbit-carousel';
import 'awesome-galaxy-orbit-carousel/style.css';

const slides = [
  { title: 'Aurora',   description: 'Northern lights over the tundra.', color: '#020d2e', tag: 'Nature'  },
  { title: 'Nebula',   description: 'Star-forming clouds in deep space.', color: '#120a2e', tag: 'Space'  },
  { title: 'Coral',    description: 'Vibrant reef ecosystems underwater.', color: '#0d1f0a', tag: 'Ocean'  },
  { title: 'Volcano',  description: 'Raw power erupting from the Earth.',  color: '#1a0a0a', tag: 'Earth'  },
  { title: 'Glacier',  description: 'Ancient ice slowly carving valleys.', color: '#0a1e2e', tag: 'Arctic' },
];

export default function App() {
  return (
    <div style={{ width: '100vw', height: '100vh' }}>
      <AwesomeGalaxyOrbitCarousel data={slides} />
    </div>
  );
}

Props

| Prop | Type | Default | Description | |---|---|---|---| | data | OrbitSlide[] | required | Array of slide objects. See OrbitSlide below. Minimum 2 slides recommended. | | rings | OrbitRingConfig[] | auto | Ring layout config. Auto-computed from slide count if omitted. | | intervalSeconds | number | 4 | Seconds between auto-focus advances. | | autoRotate | boolean | true | Whether slides auto-advance and the rings continuously rotate. | | onFocusChange | (index: number) => void | — | Fired after each focus transition completes with the new 0-based index. | | width | number \| string | '100%' | CSS width of the component container. | | height | number \| string | '100%' | CSS height of the component container. | | className | string | — | Optional CSS class applied to the root container. |

OrbitSlide object

| Field | Type | Required | Description | |---|---|---|---| | title | string | ✅ | Main heading on the planet card. Also used as the two-letter placeholder when no image is provided. | | description | string | ➖ | Short body text shown on the card. | | image | string | ➖ | URL of a cover image displayed at the top of the card. | | tag | string | ➖ | Small badge shown top-right of the card image area. | | color | string | ➖ | Hex background colour of the card (e.g. '#020d2e'). Maps to a vibrant accent used for glows and borders. | | onClick | () => void | ➖ | Fired when the focused card's Explore → button is clicked, or when Enter is pressed while the slide is focused. |

OrbitRingConfig object

Only needed if you want to override the automatic ring layout.

| Field | Type | Required | Description | |---|---|---|---| | count | number | ✅ | Number of slides to place on this ring. | | radiusX | number | ✅ | Semi-major axis in px (horizontal spread). | | radiusY | number | ✅ | Semi-minor axis in px (vertical spread — smaller = more elliptical). | | period | number | ✅ | Orbital period in seconds. Negative value reverses direction. | | phaseOffset | number | ➖ | Starting angle offset in radians. Staggers ring start positions. | | tilt | number | ➖ | Tilt of the orbital plane in degrees — creates the 3D inclined look. |


Examples

Example 1 — Minimal, no images

import { AwesomeGalaxyOrbitCarousel } from 'awesome-galaxy-orbit-carousel';
import 'awesome-galaxy-orbit-carousel/style.css';

var slides = [
  { title: 'Mercury', description: 'Closest planet to the Sun.',          color: '#1a1a1a', tag: 'Planet' },
  { title: 'Venus',   description: 'Hottest planet in the solar system.', color: '#1a1200', tag: 'Planet' },
  { title: 'Earth',   description: 'Our pale blue dot.',                   color: '#0a1628', tag: 'Planet' },
  { title: 'Mars',    description: 'The red, dusty frontier.',             color: '#1a0a0a', tag: 'Planet' },
  { title: 'Jupiter', description: 'King of the gas giants.',              color: '#120f0a', tag: 'Planet' },
  { title: 'Saturn',  description: 'Famous for its ring system.',          color: '#141008', tag: 'Planet' },
];

export default function PlanetsDemo() {
  return (
    <div style={{ width: '100vw', height: '100vh' }}>
      <AwesomeGalaxyOrbitCarousel data={slides} />
    </div>
  );
}

Example 2 — Full featured with images, callbacks, and custom size

import { useState } from 'react';
import { AwesomeGalaxyOrbitCarousel } from 'awesome-galaxy-orbit-carousel';
import 'awesome-galaxy-orbit-carousel/style.css';

var slides = [
  {
    title: 'Arctic',
    description: 'Vast frozen tundra lit only by the polar glow.',
    tag: 'Explore',
    color: '#020d2e',
    image: 'https://images.unsplash.com/photo-1517411032315-54ef2cb783bb?w=600',
    onClick: function() { window.open('https://example.com/arctic', '_blank'); },
  },
  {
    title: 'Desert',
    description: 'Golden sand sculpted by the wind into endless dunes.',
    tag: 'Journey',
    color: '#1a0f00',
    image: 'https://images.unsplash.com/photo-1509316785289-025f5b846b35?w=600',
    onClick: function() { window.open('https://example.com/desert', '_blank'); },
  },
  {
    title: 'Jungle',
    description: 'A cathedral of ancient trees alive with unseen creatures.',
    tag: 'Wildlife',
    color: '#0d1f0a',
    image: 'https://images.unsplash.com/photo-1448375240586-882707db888b?w=600',
    onClick: function() { window.open('https://example.com/jungle', '_blank'); },
  },
  {
    title: 'Abyss',
    description: "The deep ocean floor — Earth's last frontier.",
    tag: 'Discovery',
    color: '#001820',
    image: 'https://images.unsplash.com/photo-1518020382113-a7e8fc38eac9?w=600',
    onClick: function() { window.open('https://example.com/abyss', '_blank'); },
  },
  {
    title: 'Summit',
    description: 'Where the air thins and the world lies below.',
    tag: 'Adventure',
    color: '#0f0f18',
    image: 'https://images.unsplash.com/photo-1464822759023-fed622ff2c3b?w=600',
    onClick: function() { window.open('https://example.com/summit', '_blank'); },
  },
];

export default function FullFeaturedDemo() {
  var [activeIndex, setActiveIndex] = useState(0);

  return (
    <div style={{ position: 'relative', width: '100vw', height: '100vh' }}>

      {/* Slide counter overlay */}
      <div style={{
        position: 'absolute', top: 20, right: 24, zIndex: 100,
        color: '#00f5ff', fontFamily: 'monospace', fontSize: '13px',
        background: 'rgba(0,0,0,0.4)', padding: '6px 14px', borderRadius: '20px',
        border: '1px solid rgba(0,245,255,0.2)',
      }}>
        {activeIndex + 1} / {slides.length} — {slides[activeIndex].title}
      </div>

      <AwesomeGalaxyOrbitCarousel
        data={slides}
        intervalSeconds={5}
        autoRotate={true}
        width="100%"
        height="100%"
        onFocusChange={function(index) { setActiveIndex(index); }}
      />
    </div>
  );
}

Example 3 — Custom ring layout (autoRotate={false} + manual rings)

Override the automatic ring layout and disable autoplay to drive navigation with your own buttons.

import { useState } from 'react';
import { AwesomeGalaxyOrbitCarousel } from 'awesome-galaxy-orbit-carousel';
import 'awesome-galaxy-orbit-carousel/style.css';

var slides = [
  { title: 'Hydrogen', description: 'The most abundant element.', color: '#080022', tag: '#1'  },
  { title: 'Helium',   description: 'Noble gas, second lightest.', color: '#020d2e', tag: '#2'  },
  { title: 'Carbon',   description: 'Basis of all organic life.',  color: '#0d1f0a', tag: '#6'  },
  { title: 'Oxygen',   description: 'Essential for respiration.',  color: '#001820', tag: '#8'  },
  { title: 'Iron',     description: 'Core of the Earth itself.',   color: '#1a0a0a', tag: '#26' },
  { title: 'Gold',     description: 'Prized across all cultures.', color: '#1a1200', tag: '#79' },
  { title: 'Uranium',  description: 'Heaviest natural element.',   color: '#0a1e2e', tag: '#92' },
];

// Two custom rings: 3 slides on inner, 4 on outer
var customRings = [
  { count: 3, radiusX: 200, radiusY: 85,  period: 10, phaseOffset: 0,              tilt: 14 },
  { count: 4, radiusX: 340, radiusY: 130, period: 18, phaseOffset: Math.PI / 4,    tilt: 22 },
];

var btnStyle = {
  padding: '10px 28px',
  background: 'rgba(0,245,255,0.08)',
  border: '1px solid rgba(0,245,255,0.3)',
  color: '#00f5ff',
  borderRadius: '100px',
  cursor: 'pointer',
  fontFamily: 'sans-serif',
  fontSize: '13px',
  letterSpacing: '0.08em',
};

export default function CustomRingsDemo() {
  var [focused, setFocused] = useState(0);
  var total = slides.length;

  function prev() {
    setFocused(function(i) { return (i - 1 + total) % total; });
  }
  function next() {
    setFocused(function(i) { return (i + 1) % total; });
  }

  return (
    <div style={{ position: 'relative', width: '100vw', height: '100vh' }}>

      <AwesomeGalaxyOrbitCarousel
        key={focused}
        data={slides}
        rings={customRings}
        autoRotate={false}
        width="100%"
        height="100%"
        onFocusChange={setFocused}
      />

      {/* Navigation buttons */}
      <div style={{
        position: 'absolute', bottom: 40, left: '50%',
        transform: 'translateX(-50%)',
        display: 'flex', gap: '16px', zIndex: 100,
      }}>
        <button style={btnStyle} onClick={prev}>← Prev</button>
        <button style={btnStyle} onClick={next}>Next →</button>
      </div>

      {/* Focused slide label */}
      <div style={{
        position: 'absolute', top: 24, left: '50%',
        transform: 'translateX(-50%)',
        color: '#fff', fontFamily: 'sans-serif', fontSize: '14px',
        background: 'rgba(0,0,0,0.5)', padding: '6px 18px', borderRadius: '20px',
        border: '1px solid rgba(255,255,255,0.12)',
        whiteSpace: 'nowrap', zIndex: 100,
      }}>
        Focused: {slides[focused].title}
      </div>

    </div>
  );
}

CSS Custom Properties

Override fonts in your own :root:

:root {
  --font-display: 'Your Display Font', sans-serif;
  --font-body:    'Your Body Font', sans-serif;
}

Default values are 'Syne' (display, weights 700–900) and 'DM Sans' (body, weights 300–500).


Keyboard Controls

| Key | Action | |---|---| | | Focus next slide | | | Focus previous slide | | Enter | Fire onClick of the currently focused slide |


License

MIT