awesome-galaxy-orbit-carousel 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +348 -0
  3. package/dist/assets/index-BsEGzit1.css +1 -0
  4. package/dist/assets/index-EEJeq21F.js +49 -0
  5. package/dist/cjs/index.js +2 -0
  6. package/dist/cjs/index.js.map +1 -0
  7. package/dist/esm/index.js +469 -0
  8. package/dist/esm/index.js.map +1 -0
  9. package/dist/index.html +17 -0
  10. package/dist/style.css +61 -0
  11. package/dist/types/App.d.ts +2 -0
  12. package/dist/types/App.d.ts.map +1 -0
  13. package/dist/types/components/AwesomeGalaxyOrbitCarousel/AwesomeGalaxyOrbitCarousel.d.ts +3 -0
  14. package/dist/types/components/AwesomeGalaxyOrbitCarousel/AwesomeGalaxyOrbitCarousel.d.ts.map +1 -0
  15. package/dist/types/components/AwesomeGalaxyOrbitCarousel/GalaxyCore.d.ts +12 -0
  16. package/dist/types/components/AwesomeGalaxyOrbitCarousel/GalaxyCore.d.ts.map +1 -0
  17. package/dist/types/components/AwesomeGalaxyOrbitCarousel/OrbitRing.d.ts +18 -0
  18. package/dist/types/components/AwesomeGalaxyOrbitCarousel/OrbitRing.d.ts.map +1 -0
  19. package/dist/types/components/AwesomeGalaxyOrbitCarousel/index.d.ts +3 -0
  20. package/dist/types/components/AwesomeGalaxyOrbitCarousel/index.d.ts.map +1 -0
  21. package/dist/types/components/AwesomeGalaxyOrbitCarousel/orbitalMath.d.ts +52 -0
  22. package/dist/types/components/AwesomeGalaxyOrbitCarousel/orbitalMath.d.ts.map +1 -0
  23. package/dist/types/components/AwesomeGalaxyOrbitCarousel/types.d.ts +37 -0
  24. package/dist/types/components/AwesomeGalaxyOrbitCarousel/types.d.ts.map +1 -0
  25. package/dist/types/hooks/useAutoplay.d.ts +15 -0
  26. package/dist/types/hooks/useAutoplay.d.ts.map +1 -0
  27. package/dist/types/hooks/useDragRotation.d.ts +13 -0
  28. package/dist/types/hooks/useDragRotation.d.ts.map +1 -0
  29. package/dist/types/hooks/useRotationPhysics.d.ts +20 -0
  30. package/dist/types/hooks/useRotationPhysics.d.ts.map +1 -0
  31. package/dist/types/hooks/useSphereLayout.d.ts +7 -0
  32. package/dist/types/hooks/useSphereLayout.d.ts.map +1 -0
  33. package/dist/types/index.d.ts +3 -0
  34. package/dist/types/index.d.ts.map +1 -0
  35. package/dist/types/main.d.ts +2 -0
  36. package/dist/types/main.d.ts.map +1 -0
  37. package/dist/types/math/sphericalCoordinates.d.ts +27 -0
  38. package/dist/types/math/sphericalCoordinates.d.ts.map +1 -0
  39. package/dist/types/themes/index.d.ts +20 -0
  40. package/dist/types/themes/index.d.ts.map +1 -0
  41. package/package.json +59 -0
package/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
package/README.md ADDED
@@ -0,0 +1,348 @@
1
+ # awesome-galaxy-orbit-carousel
2
+
3
+ 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.
4
+
5
+ ---
6
+
7
+ ## Features
8
+
9
+ - **Multi-ring elliptical orbits** — slides distributed across 1–4 rings, auto-computed from slide count or fully customisable
10
+ - **Kepler-inspired depth** — slides closer to the viewer scale up and brighten; distant slides fade back
11
+ - **Gravitational pull animation** — clicking or auto-advancing a slide triggers a visual "pull" before focus locks
12
+ - **Animated galaxy core** — pulsing orb at center updates colour to match the focused slide
13
+ - **Orbit path rings** — decorative ellipse outlines with per-ring accent tints
14
+ - **Starfield + nebula background** — 120 blinking stars and radial nebula clouds
15
+ - **Autoplay with configurable interval** — pauses on hover automatically
16
+ - **Keyboard navigation** — `←` / `→` to cycle slides, `Enter` to fire `onClick`
17
+ - **Planet cards** — each slide renders as a card with image, tag badge, title, description, and an Explore CTA on focus
18
+ - **ESM + CJS dual build** — works in Vite, Next.js, CRA, and any modern bundler
19
+ - **Full TypeScript types** included
20
+
21
+ ---
22
+
23
+ ## Installation
24
+
25
+ ```bash
26
+ npm install awesome-galaxy-orbit-carousel
27
+ # or
28
+ yarn add awesome-galaxy-orbit-carousel
29
+ # or
30
+ pnpm add awesome-galaxy-orbit-carousel
31
+ ```
32
+
33
+ > **Peer dependencies** — React ≥ 17 and ReactDOM ≥ 17 must already be installed.
34
+
35
+ ---
36
+
37
+ ## Importing Styles
38
+
39
+ 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:
40
+
41
+ ```js
42
+ import 'awesome-galaxy-orbit-carousel/style.css';
43
+ ```
44
+
45
+ For the best visual result, load these Google Fonts in your `index.html` `<head>`:
46
+
47
+ ```html
48
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
49
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
50
+ <link
51
+ href="https://fonts.googleapis.com/css2?family=Syne:wght@700;800;900&family=DM+Sans:wght@300;400;500&display=swap"
52
+ rel="stylesheet"
53
+ />
54
+ ```
55
+
56
+ > The component still renders correctly without the fonts — it falls back to `sans-serif`.
57
+
58
+ ---
59
+
60
+ ## Quick Start
61
+
62
+ ```jsx
63
+ import { AwesomeGalaxyOrbitCarousel } from 'awesome-galaxy-orbit-carousel';
64
+ import 'awesome-galaxy-orbit-carousel/style.css';
65
+
66
+ const slides = [
67
+ { title: 'Aurora', description: 'Northern lights over the tundra.', color: '#020d2e', tag: 'Nature' },
68
+ { title: 'Nebula', description: 'Star-forming clouds in deep space.', color: '#120a2e', tag: 'Space' },
69
+ { title: 'Coral', description: 'Vibrant reef ecosystems underwater.', color: '#0d1f0a', tag: 'Ocean' },
70
+ { title: 'Volcano', description: 'Raw power erupting from the Earth.', color: '#1a0a0a', tag: 'Earth' },
71
+ { title: 'Glacier', description: 'Ancient ice slowly carving valleys.', color: '#0a1e2e', tag: 'Arctic' },
72
+ ];
73
+
74
+ export default function App() {
75
+ return (
76
+ <div style={{ width: '100vw', height: '100vh' }}>
77
+ <AwesomeGalaxyOrbitCarousel data={slides} />
78
+ </div>
79
+ );
80
+ }
81
+ ```
82
+
83
+ ---
84
+
85
+ ## Props
86
+
87
+ | Prop | Type | Default | Description |
88
+ |---|---|---|---|
89
+ | `data` | `OrbitSlide[]` | **required** | Array of slide objects. See `OrbitSlide` below. Minimum 2 slides recommended. |
90
+ | `rings` | `OrbitRingConfig[]` | auto | Ring layout config. Auto-computed from slide count if omitted. |
91
+ | `intervalSeconds` | `number` | `4` | Seconds between auto-focus advances. |
92
+ | `autoRotate` | `boolean` | `true` | Whether slides auto-advance and the rings continuously rotate. |
93
+ | `onFocusChange` | `(index: number) => void` | — | Fired after each focus transition completes with the new 0-based index. |
94
+ | `width` | `number \| string` | `'100%'` | CSS width of the component container. |
95
+ | `height` | `number \| string` | `'100%'` | CSS height of the component container. |
96
+ | `className` | `string` | — | Optional CSS class applied to the root container. |
97
+
98
+ ### `OrbitSlide` object
99
+
100
+ | Field | Type | Required | Description |
101
+ |---|---|---|---|
102
+ | `title` | `string` | ✅ | Main heading on the planet card. Also used as the two-letter placeholder when no image is provided. |
103
+ | `description` | `string` | ➖ | Short body text shown on the card. |
104
+ | `image` | `string` | ➖ | URL of a cover image displayed at the top of the card. |
105
+ | `tag` | `string` | ➖ | Small badge shown top-right of the card image area. |
106
+ | `color` | `string` | ➖ | Hex background colour of the card (e.g. `'#020d2e'`). Maps to a vibrant accent used for glows and borders. |
107
+ | `onClick` | `() => void` | ➖ | Fired when the focused card's **Explore →** button is clicked, or when `Enter` is pressed while the slide is focused. |
108
+
109
+ ### `OrbitRingConfig` object
110
+
111
+ Only needed if you want to override the automatic ring layout.
112
+
113
+ | Field | Type | Required | Description |
114
+ |---|---|---|---|
115
+ | `count` | `number` | ✅ | Number of slides to place on this ring. |
116
+ | `radiusX` | `number` | ✅ | Semi-major axis in px (horizontal spread). |
117
+ | `radiusY` | `number` | ✅ | Semi-minor axis in px (vertical spread — smaller = more elliptical). |
118
+ | `period` | `number` | ✅ | Orbital period in seconds. Negative value reverses direction. |
119
+ | `phaseOffset` | `number` | ➖ | Starting angle offset in radians. Staggers ring start positions. |
120
+ | `tilt` | `number` | ➖ | Tilt of the orbital plane in degrees — creates the 3D inclined look. |
121
+
122
+ ---
123
+
124
+ ## Examples
125
+
126
+ ### Example 1 — Minimal, no images
127
+
128
+ ```jsx
129
+ import { AwesomeGalaxyOrbitCarousel } from 'awesome-galaxy-orbit-carousel';
130
+ import 'awesome-galaxy-orbit-carousel/style.css';
131
+
132
+ var slides = [
133
+ { title: 'Mercury', description: 'Closest planet to the Sun.', color: '#1a1a1a', tag: 'Planet' },
134
+ { title: 'Venus', description: 'Hottest planet in the solar system.', color: '#1a1200', tag: 'Planet' },
135
+ { title: 'Earth', description: 'Our pale blue dot.', color: '#0a1628', tag: 'Planet' },
136
+ { title: 'Mars', description: 'The red, dusty frontier.', color: '#1a0a0a', tag: 'Planet' },
137
+ { title: 'Jupiter', description: 'King of the gas giants.', color: '#120f0a', tag: 'Planet' },
138
+ { title: 'Saturn', description: 'Famous for its ring system.', color: '#141008', tag: 'Planet' },
139
+ ];
140
+
141
+ export default function PlanetsDemo() {
142
+ return (
143
+ <div style={{ width: '100vw', height: '100vh' }}>
144
+ <AwesomeGalaxyOrbitCarousel data={slides} />
145
+ </div>
146
+ );
147
+ }
148
+ ```
149
+
150
+ ---
151
+
152
+ ### Example 2 — Full featured with images, callbacks, and custom size
153
+
154
+ ```jsx
155
+ import { useState } from 'react';
156
+ import { AwesomeGalaxyOrbitCarousel } from 'awesome-galaxy-orbit-carousel';
157
+ import 'awesome-galaxy-orbit-carousel/style.css';
158
+
159
+ var slides = [
160
+ {
161
+ title: 'Arctic',
162
+ description: 'Vast frozen tundra lit only by the polar glow.',
163
+ tag: 'Explore',
164
+ color: '#020d2e',
165
+ image: 'https://images.unsplash.com/photo-1517411032315-54ef2cb783bb?w=600',
166
+ onClick: function() { window.open('https://example.com/arctic', '_blank'); },
167
+ },
168
+ {
169
+ title: 'Desert',
170
+ description: 'Golden sand sculpted by the wind into endless dunes.',
171
+ tag: 'Journey',
172
+ color: '#1a0f00',
173
+ image: 'https://images.unsplash.com/photo-1509316785289-025f5b846b35?w=600',
174
+ onClick: function() { window.open('https://example.com/desert', '_blank'); },
175
+ },
176
+ {
177
+ title: 'Jungle',
178
+ description: 'A cathedral of ancient trees alive with unseen creatures.',
179
+ tag: 'Wildlife',
180
+ color: '#0d1f0a',
181
+ image: 'https://images.unsplash.com/photo-1448375240586-882707db888b?w=600',
182
+ onClick: function() { window.open('https://example.com/jungle', '_blank'); },
183
+ },
184
+ {
185
+ title: 'Abyss',
186
+ description: "The deep ocean floor — Earth's last frontier.",
187
+ tag: 'Discovery',
188
+ color: '#001820',
189
+ image: 'https://images.unsplash.com/photo-1518020382113-a7e8fc38eac9?w=600',
190
+ onClick: function() { window.open('https://example.com/abyss', '_blank'); },
191
+ },
192
+ {
193
+ title: 'Summit',
194
+ description: 'Where the air thins and the world lies below.',
195
+ tag: 'Adventure',
196
+ color: '#0f0f18',
197
+ image: 'https://images.unsplash.com/photo-1464822759023-fed622ff2c3b?w=600',
198
+ onClick: function() { window.open('https://example.com/summit', '_blank'); },
199
+ },
200
+ ];
201
+
202
+ export default function FullFeaturedDemo() {
203
+ var [activeIndex, setActiveIndex] = useState(0);
204
+
205
+ return (
206
+ <div style={{ position: 'relative', width: '100vw', height: '100vh' }}>
207
+
208
+ {/* Slide counter overlay */}
209
+ <div style={{
210
+ position: 'absolute', top: 20, right: 24, zIndex: 100,
211
+ color: '#00f5ff', fontFamily: 'monospace', fontSize: '13px',
212
+ background: 'rgba(0,0,0,0.4)', padding: '6px 14px', borderRadius: '20px',
213
+ border: '1px solid rgba(0,245,255,0.2)',
214
+ }}>
215
+ {activeIndex + 1} / {slides.length} — {slides[activeIndex].title}
216
+ </div>
217
+
218
+ <AwesomeGalaxyOrbitCarousel
219
+ data={slides}
220
+ intervalSeconds={5}
221
+ autoRotate={true}
222
+ width="100%"
223
+ height="100%"
224
+ onFocusChange={function(index) { setActiveIndex(index); }}
225
+ />
226
+ </div>
227
+ );
228
+ }
229
+ ```
230
+
231
+ ---
232
+
233
+ ### Example 3 — Custom ring layout (`autoRotate={false}` + manual rings)
234
+
235
+ Override the automatic ring layout and disable autoplay to drive navigation with your own buttons.
236
+
237
+ ```jsx
238
+ import { useState } from 'react';
239
+ import { AwesomeGalaxyOrbitCarousel } from 'awesome-galaxy-orbit-carousel';
240
+ import 'awesome-galaxy-orbit-carousel/style.css';
241
+
242
+ var slides = [
243
+ { title: 'Hydrogen', description: 'The most abundant element.', color: '#080022', tag: '#1' },
244
+ { title: 'Helium', description: 'Noble gas, second lightest.', color: '#020d2e', tag: '#2' },
245
+ { title: 'Carbon', description: 'Basis of all organic life.', color: '#0d1f0a', tag: '#6' },
246
+ { title: 'Oxygen', description: 'Essential for respiration.', color: '#001820', tag: '#8' },
247
+ { title: 'Iron', description: 'Core of the Earth itself.', color: '#1a0a0a', tag: '#26' },
248
+ { title: 'Gold', description: 'Prized across all cultures.', color: '#1a1200', tag: '#79' },
249
+ { title: 'Uranium', description: 'Heaviest natural element.', color: '#0a1e2e', tag: '#92' },
250
+ ];
251
+
252
+ // Two custom rings: 3 slides on inner, 4 on outer
253
+ var customRings = [
254
+ { count: 3, radiusX: 200, radiusY: 85, period: 10, phaseOffset: 0, tilt: 14 },
255
+ { count: 4, radiusX: 340, radiusY: 130, period: 18, phaseOffset: Math.PI / 4, tilt: 22 },
256
+ ];
257
+
258
+ var btnStyle = {
259
+ padding: '10px 28px',
260
+ background: 'rgba(0,245,255,0.08)',
261
+ border: '1px solid rgba(0,245,255,0.3)',
262
+ color: '#00f5ff',
263
+ borderRadius: '100px',
264
+ cursor: 'pointer',
265
+ fontFamily: 'sans-serif',
266
+ fontSize: '13px',
267
+ letterSpacing: '0.08em',
268
+ };
269
+
270
+ export default function CustomRingsDemo() {
271
+ var [focused, setFocused] = useState(0);
272
+ var total = slides.length;
273
+
274
+ function prev() {
275
+ setFocused(function(i) { return (i - 1 + total) % total; });
276
+ }
277
+ function next() {
278
+ setFocused(function(i) { return (i + 1) % total; });
279
+ }
280
+
281
+ return (
282
+ <div style={{ position: 'relative', width: '100vw', height: '100vh' }}>
283
+
284
+ <AwesomeGalaxyOrbitCarousel
285
+ key={focused}
286
+ data={slides}
287
+ rings={customRings}
288
+ autoRotate={false}
289
+ width="100%"
290
+ height="100%"
291
+ onFocusChange={setFocused}
292
+ />
293
+
294
+ {/* Navigation buttons */}
295
+ <div style={{
296
+ position: 'absolute', bottom: 40, left: '50%',
297
+ transform: 'translateX(-50%)',
298
+ display: 'flex', gap: '16px', zIndex: 100,
299
+ }}>
300
+ <button style={btnStyle} onClick={prev}>← Prev</button>
301
+ <button style={btnStyle} onClick={next}>Next →</button>
302
+ </div>
303
+
304
+ {/* Focused slide label */}
305
+ <div style={{
306
+ position: 'absolute', top: 24, left: '50%',
307
+ transform: 'translateX(-50%)',
308
+ color: '#fff', fontFamily: 'sans-serif', fontSize: '14px',
309
+ background: 'rgba(0,0,0,0.5)', padding: '6px 18px', borderRadius: '20px',
310
+ border: '1px solid rgba(255,255,255,0.12)',
311
+ whiteSpace: 'nowrap', zIndex: 100,
312
+ }}>
313
+ Focused: {slides[focused].title}
314
+ </div>
315
+
316
+ </div>
317
+ );
318
+ }
319
+ ```
320
+
321
+ ## CSS Custom Properties
322
+
323
+ Override fonts in your own `:root`:
324
+
325
+ ```css
326
+ :root {
327
+ --font-display: 'Your Display Font', sans-serif;
328
+ --font-body: 'Your Body Font', sans-serif;
329
+ }
330
+ ```
331
+
332
+ Default values are `'Syne'` (display, weights 700–900) and `'DM Sans'` (body, weights 300–500).
333
+
334
+ ---
335
+
336
+ ## Keyboard Controls
337
+
338
+ | Key | Action |
339
+ |---|---|
340
+ | `→` | Focus next slide |
341
+ | `←` | Focus previous slide |
342
+ | `Enter` | Fire `onClick` of the currently focused slide |
343
+
344
+ ---
345
+
346
+ ## License
347
+
348
+ MIT
@@ -0,0 +1 @@
1
+ *,*:before,*:after{box-sizing:border-box;margin:0;padding:0}:root{--bg-primary: #030712;--bg-secondary: #0a0f1e;--accent-cyan: #00f5ff;--accent-violet: #7c3aed;--accent-amber: #f59e0b;--text-primary: #f1f5f9;--text-secondary: #94a3b8;--font-display: "Syne", sans-serif;--font-body: "DM Sans", sans-serif}html,body,#root{width:100%;height:100%;overflow:hidden}body{background:var(--bg-primary);color:var(--text-primary);font-family:var(--font-body);-webkit-font-smoothing:antialiased}@keyframes pulseGlow{0%,to{opacity:.3;transform:scale(1)}50%{opacity:.9;transform:scale(1.3)}}@keyframes fadeUp{0%{opacity:0;transform:translate(-50%) translateY(12px)}to{opacity:1;transform:translate(-50%) translateY(0)}}@keyframes coreSpin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}@keyframes corePulse{0%,to{box-shadow:0 0 30px #00f5ff66,0 0 60px #00f5ff22;transform:scale(1)}50%{box-shadow:0 0 50px #00f5ffaa,0 0 100px #00f5ff44;transform:scale(1.08)}}@keyframes ringPulse{0%,to{opacity:.06;transform:scale(1)}50%{opacity:.18;transform:scale(1.06)}}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{opacity:1;filter:invert(1) brightness(.5)}