astro-component-kit 0.1.1 → 0.3.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 (59) hide show
  1. package/README.md +4 -4
  2. package/package.json +24 -10
  3. package/src/components/index.ts +15 -9
  4. package/src/components/lib/AnimatedGalaxy.astro +4 -2
  5. package/src/components/lib/Galaxy3D.astro +237 -185
  6. package/src/components/lib/LogoWithGalaxy.astro +2 -2
  7. package/src/components/lib/buttons/index.ts +4 -1
  8. package/src/components/lib/cards/index.ts +3 -0
  9. package/src/components/lib/charts/AreaChart.astro +210 -0
  10. package/src/components/lib/charts/BarChart.astro +190 -0
  11. package/src/components/lib/charts/DonutChart.astro +177 -0
  12. package/src/components/lib/charts/index.ts +6 -0
  13. package/src/components/lib/data/index.ts +3 -0
  14. package/src/components/lib/feedback/index.ts +3 -0
  15. package/src/components/lib/forms/index.ts +3 -0
  16. package/src/components/lib/index.ts +17 -6
  17. package/src/components/lib/layout/BentoGrid3.astro +79 -9
  18. package/src/components/lib/layout/CenterFixedBox.astro +52 -2
  19. package/src/components/lib/layout/CenteredContainer.astro +44 -5
  20. package/src/components/lib/layout/ClusterHorizontal.astro +36 -2
  21. package/src/components/lib/layout/FeatureHero.astro +119 -50
  22. package/src/components/lib/layout/FooterCenteredMinimal.astro +57 -9
  23. package/src/components/lib/layout/FullBleedSection.astro +44 -2
  24. package/src/components/lib/layout/GalleryGrid4.astro +35 -3
  25. package/src/components/lib/layout/GlassCardGrid.astro +24 -2
  26. package/src/components/lib/layout/GlassSectionHeader.astro +72 -11
  27. package/src/components/lib/layout/LandingSectionSplit.astro +83 -8
  28. package/src/components/lib/layout/MasonryGrid.astro +42 -3
  29. package/src/components/lib/layout/MinimalFooterGrid.astro +83 -11
  30. package/src/components/lib/layout/ScrollSnapSection.astro +37 -3
  31. package/src/components/lib/layout/SectionDividerText.astro +44 -4
  32. package/src/components/lib/layout/SidebarLayoutWrapper.astro +62 -7
  33. package/src/components/lib/layout/SplitScreenLayout.astro +62 -6
  34. package/src/components/lib/layout/StepLayoutVertical.astro +83 -10
  35. package/src/components/lib/layout/StickySidebarWrapper.astro +69 -6
  36. package/src/components/lib/layout/VerticalStack.astro +35 -5
  37. package/src/components/lib/layout/index.ts +17 -14
  38. package/src/components/lib/navigation/index.ts +3 -0
  39. package/src/components/lib/overlays/index.ts +3 -0
  40. package/src/components/lib/sections/ContactGlassForm.astro +361 -0
  41. package/src/components/lib/sections/CtaAppDownload.astro +258 -0
  42. package/src/components/lib/sections/CtaGlowBanner.astro +267 -0
  43. package/src/components/lib/sections/FaqAccordionSection.astro +349 -0
  44. package/src/components/lib/sections/FeatureBentoGrid.astro +449 -0
  45. package/src/components/lib/sections/FeatureTimelineFlow.astro +254 -0
  46. package/src/components/lib/sections/PricingComparisonMatrix.astro +468 -0
  47. package/src/components/lib/sections/PricingTierCards.astro +256 -0
  48. package/src/components/lib/sections/StatsMetricShowcase.astro +332 -0
  49. package/src/components/lib/sections/TeamGridSection.astro +333 -0
  50. package/src/components/lib/sections/TestimonialWallGlass.astro +406 -0
  51. package/src/components/lib/sections/index.ts +22 -0
  52. package/src/components/lib/typography/index.ts +3 -0
  53. package/src/components/lib/AnimatedInput.astro +0 -82
  54. package/src/components/lib/Badge.astro +0 -52
  55. package/src/components/lib/GlassButton.astro +0 -87
  56. package/src/components/lib/GlassCard.astro +0 -72
  57. package/src/components/lib/GlassNavbar.astro +0 -67
  58. package/src/components/lib/GlowButton.astro +0 -60
  59. /package/src/components/lib/buttons/{3dPushButton.astro → ThreeDPushButton.astro} +0 -0
@@ -1,4 +1,12 @@
1
1
  ---
2
+ /**
3
+ * Galaxy3D — Interactive 3D galaxy background with mouse-reactive particle distortion.
4
+ *
5
+ * Renders a spiral galaxy with thousands of particles using Three.js.
6
+ * Mouse movement creates a repulsion force that distorts nearby particles in real-time.
7
+ *
8
+ * @param {string} className - Additional CSS class
9
+ */
2
10
  interface Props {
3
11
  className?: string;
4
12
  }
@@ -6,7 +14,7 @@ interface Props {
6
14
  const { className = '' } = Astro.props;
7
15
  ---
8
16
 
9
- <div class="galaxy-3d-container {className}" id="galaxy-3d-wrapper">
17
+ <div class="galaxy-3d-container {className}" id="galaxy-3d-wrapper" aria-hidden="true">
10
18
  <canvas id="galaxy-3d-canvas"></canvas>
11
19
  </div>
12
20
 
@@ -17,7 +25,7 @@ const { className = '' } = Astro.props;
17
25
  width: 100%;
18
26
  height: 100%;
19
27
  z-index: 0;
20
- pointer-events: none;
28
+ pointer-events: auto;
21
29
  }
22
30
  #galaxy-3d-canvas {
23
31
  position: absolute;
@@ -28,21 +36,19 @@ const { className = '' } = Astro.props;
28
36
  }
29
37
  </style>
30
38
 
31
- <script is:inline>
32
- (async function() {
33
- const THREE = await import('https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js');
39
+ <script is:inline type="module">
40
+ import * as THREE from 'https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js';
34
41
 
42
+ (function () {
35
43
  const canvas = document.getElementById('galaxy-3d-canvas');
36
44
  if (!canvas) return;
37
-
38
45
  const container = canvas.parentElement;
39
46
  if (!container) return;
40
47
 
41
- // Scene setup
48
+ // ===== SCENE =====
42
49
  const scene = new THREE.Scene();
43
50
  const camera = new THREE.PerspectiveCamera(75, 1, 0.1, 100);
44
51
  camera.position.set(0, 0, 5);
45
- camera.lookAt(0, 0, 0);
46
52
 
47
53
  const renderer = new THREE.WebGLRenderer({ canvas, alpha: true, antialias: true });
48
54
  renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
@@ -50,190 +56,153 @@ const { className = '' } = Astro.props;
50
56
  function resize() {
51
57
  const w = container.clientWidth;
52
58
  const h = container.clientHeight;
59
+ if (w === 0 || h === 0) return;
53
60
  renderer.setSize(w, h);
54
61
  camera.aspect = w / h;
55
62
  camera.updateProjectionMatrix();
56
63
  }
57
64
 
58
- resize();
65
+ requestAnimationFrame(() => resize());
66
+ setTimeout(resize, 100);
67
+ setTimeout(resize, 500);
59
68
  window.addEventListener('resize', resize);
60
69
 
61
- // Corporate color palette (gold, white, subtle blue accents)
62
- const galaxyColors = [
63
- new THREE.Color('#fef3c7'), // Light gold
64
- new THREE.Color('#fbbf24'), // Gold
65
- new THREE.Color('#d4a017'), // Dark gold
66
- new THREE.Color('#ffffff'), // White
67
- new THREE.Color('#b8860b'), // Darker gold
68
- ];
69
-
70
- const bgStarColors = [
71
- new THREE.Color('#ffffff'),
70
+ // ===== COLORS =====
71
+ const palette = [
72
72
  new THREE.Color('#fef3c7'),
73
+ new THREE.Color('#fbbf24'),
74
+ new THREE.Color('#d4a017'),
75
+ new THREE.Color('#ffffff'),
76
+ new THREE.Color('#b8860b'),
73
77
  new THREE.Color('#fde68a'),
74
78
  ];
75
79
 
76
- // ========== GALAXY ==========
80
+ // ===== GALAXY PARTICLES =====
81
+ const GALAXY_COUNT = 20000;
77
82
  const galaxyParams = {
78
- count: 8000,
79
- size: 0.025,
80
- radius: 2.8,
83
+ radius: 3.5,
81
84
  branches: 5,
82
85
  spin: 1.5,
83
- randomness: 0.35,
84
- randomnessPower: 2.5,
85
- colors: galaxyColors,
86
+ randomness: 0.5,
87
+ randomnessPower: 3,
88
+ inwardDrop: 0.05,
86
89
  };
87
90
 
88
- function createGalaxy() {
89
- const geometry = new THREE.BufferGeometry();
90
- const positions = new Float32Array(galaxyParams.count * 3);
91
- const colors = new Float32Array(galaxyParams.count * 3);
92
- const sizes = new Float32Array(galaxyParams.count);
93
- const randomness = new Float32Array(galaxyParams.count);
94
-
95
- for (let i = 0; i < galaxyParams.count; i++) {
96
- const i3 = i * 3;
97
- const radius = Math.random() * galaxyParams.radius;
98
- const spinAngle = radius * galaxyParams.spin;
99
- const branchIndex = i % galaxyParams.branches;
100
- const branchAngle = (branchIndex / galaxyParams.branches) * Math.PI * 2;
101
-
102
- const power = galaxyParams.randomnessPower;
103
- const randomX = Math.pow(Math.random(), power) * (Math.random() < 0.5 ? 1 : -1) * galaxyParams.randomness * radius;
104
- const randomY = Math.pow(Math.random(), power) * (Math.random() < 0.5 ? 1 : -1) * galaxyParams.randomness * radius * 0.15;
105
- const randomZ = Math.pow(Math.random(), power) * (Math.random() < 0.5 ? 1 : -1) * galaxyParams.randomness * radius;
106
-
107
- const angle = branchAngle + spinAngle;
108
- positions[i3] = Math.cos(angle) * radius + randomX;
109
- positions[i3 + 1] = randomY;
110
- positions[i3 + 2] = Math.sin(angle) * radius + randomZ;
111
-
112
- // Color based on radius
113
- const colorIndex = Math.floor(Math.random() * galaxyColors.length);
114
- const color = galaxyColors[colorIndex];
115
- const mixFactor = Math.random() * 0.3 + (radius / galaxyParams.radius) * 0.7;
116
- const finalColor = color.clone().lerp(galaxyColors[(colorIndex + 1) % galaxyColors.length], mixFactor);
117
-
118
- colors[i3] = finalColor.r;
119
- colors[i3 + 1] = finalColor.g;
120
- colors[i3 + 2] = finalColor.b;
121
-
122
- sizes[i] = (Math.random() + 0.8) * galaxyParams.size;
123
- randomness[i] = Math.random();
124
-
125
- // Store for animation
126
- randomness[i3] = randomX;
127
- randomness[i3 + 1] = randomY;
128
- randomness[i3 + 2] = randomZ;
129
- }
91
+ const galaxyGeometry = new THREE.BufferGeometry();
92
+ const galaxyPositions = new Float32Array(GALAXY_COUNT * 3);
93
+ const galaxyColors = new Float32Array(GALAXY_COUNT * 3);
94
+ const galaxyOriginalPositions = new Float32Array(GALAXY_COUNT * 3);
130
95
 
131
- geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
132
- geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));
133
- geometry.setAttribute('size', new THREE.BufferAttribute(sizes, 1));
134
-
135
- const material = new THREE.PointsMaterial({
136
- size: galaxyParams.size,
137
- sizeAttenuation: true,
138
- depthWrite: false,
139
- blending: THREE.AdditiveBlending,
140
- vertexColors: true,
141
- transparent: true,
142
- opacity: 0.85,
143
- });
144
-
145
- const points = new THREE.Points(geometry, material);
146
- // Tilt the galaxy slightly for dramatic effect
147
- points.rotation.x = -0.3;
148
- points.rotation.z = 0.15;
149
- scene.add(points);
150
-
151
- return { points, geometry };
96
+ for (let i = 0; i < GALAXY_COUNT; i++) {
97
+ const i3 = i * 3;
98
+ const radius = Math.random() * galaxyParams.radius;
99
+ const spinAngle = radius * galaxyParams.spin;
100
+ const branchIndex = i % galaxyParams.branches;
101
+ const branchAngle = (branchIndex / galaxyParams.branches) * Math.PI * 2;
102
+
103
+ const power = galaxyParams.randomnessPower;
104
+ const randomX = Math.pow(Math.random(), power) * (Math.random() < 0.5 ? 1 : -1) * galaxyParams.randomness * radius;
105
+ const randomY = Math.pow(Math.random(), power) * (Math.random() < 0.5 ? 1 : -1) * galaxyParams.randomness * radius * 0.1;
106
+ const randomZ = Math.pow(Math.random(), power) * (Math.random() < 0.5 ? 1 : -1) * galaxyParams.randomness * radius * 0.4;
107
+
108
+ const angle = branchAngle + spinAngle;
109
+ const spiralOffset = radius * galaxyParams.inwardDrop;
110
+
111
+ const x = Math.cos(angle) * radius + randomX + Math.cos(angle + Math.PI / 2) * spiralOffset;
112
+ const y = randomY;
113
+ const z = Math.sin(angle) * radius + randomZ + Math.sin(angle + Math.PI / 2) * spiralOffset;
114
+
115
+ galaxyPositions[i3] = x;
116
+ galaxyPositions[i3 + 1] = y;
117
+ galaxyPositions[i3 + 2] = z;
118
+
119
+ galaxyOriginalPositions[i3] = x;
120
+ galaxyOriginalPositions[i3 + 1] = y;
121
+ galaxyOriginalPositions[i3 + 2] = z;
122
+
123
+ const colorMix = radius / galaxyParams.radius;
124
+ const baseColor = palette[Math.floor(Math.random() * 3)];
125
+ const outerColor = palette[3 + Math.floor(Math.random() * 2)];
126
+ const finalColor = baseColor.clone().lerp(outerColor, colorMix);
127
+
128
+ galaxyColors[i3] = finalColor.r;
129
+ galaxyColors[i3 + 1] = finalColor.g;
130
+ galaxyColors[i3 + 2] = finalColor.b;
152
131
  }
153
132
 
154
- const galaxy = createGalaxy();
155
-
156
- // ========== BACKGROUND STARS ==========
157
- const bgStarsParams = {
158
- count: 1500,
159
- size: 0.012,
160
- spread: 15,
161
- };
162
-
163
- function createBgStars() {
164
- const geometry = new THREE.BufferGeometry();
165
- const positions = new Float32Array(bgStarsParams.count * 3);
166
- const colors = new Float32Array(bgStarsParams.count * 3);
167
- const opacities = new Float32Array(bgStarsParams.count);
133
+ galaxyGeometry.setAttribute('position', new THREE.BufferAttribute(galaxyPositions, 3));
134
+ galaxyGeometry.setAttribute('color', new THREE.BufferAttribute(galaxyColors, 3));
168
135
 
169
- for (let i = 0; i < bgStarsParams.count; i++) {
170
- const i3 = i * 3;
171
- positions[i3] = (Math.random() - 0.5) * bgStarsParams.spread;
172
- positions[i3 + 1] = (Math.random() - 0.5) * bgStarsParams.spread;
173
- positions[i3 + 2] = (Math.random() - 0.5) * bgStarsParams.spread * 0.5 - 3;
136
+ const galaxyMaterial = new THREE.PointsMaterial({
137
+ size: 0.008,
138
+ sizeAttenuation: true,
139
+ depthWrite: false,
140
+ blending: THREE.AdditiveBlending,
141
+ vertexColors: true,
142
+ transparent: true,
143
+ opacity: 0.95,
144
+ });
174
145
 
175
- const color = bgStarColors[Math.floor(Math.random() * bgStarColors.length)];
176
- colors[i3] = color.r;
177
- colors[i3 + 1] = color.g;
178
- colors[i3 + 2] = color.b;
146
+ const galaxyPoints = new THREE.Points(galaxyGeometry, galaxyMaterial);
147
+ galaxyPoints.rotation.x = -0.15;
148
+ galaxyPoints.rotation.z = 0.05;
149
+ scene.add(galaxyPoints);
179
150
 
180
- opacities[i] = Math.random() * 0.5 + 0.2;
181
- }
151
+ // ===== BACKGROUND STARS =====
152
+ const STAR_COUNT = 2000;
153
+ const starGeometry = new THREE.BufferGeometry();
154
+ const starPositions = new Float32Array(STAR_COUNT * 3);
182
155
 
183
- geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
184
- geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));
185
-
186
- const material = new THREE.PointsMaterial({
187
- size: bgStarsParams.size,
188
- sizeAttenuation: true,
189
- depthWrite: false,
190
- transparent: true,
191
- opacity: 0.5,
192
- vertexColors: true,
193
- blending: THREE.AdditiveBlending,
194
- });
195
-
196
- const stars = new THREE.Points(geometry, material);
197
- scene.add(stars);
198
- return stars;
156
+ for (let i = 0; i < STAR_COUNT; i++) {
157
+ const i3 = i * 3;
158
+ starPositions[i3] = (Math.random() - 0.5) * 20;
159
+ starPositions[i3 + 1] = (Math.random() - 0.5) * 20;
160
+ starPositions[i3 + 2] = (Math.random() - 0.5) * 10 - 5;
199
161
  }
200
162
 
201
- const bgStars = createBgStars();
163
+ starGeometry.setAttribute('position', new THREE.BufferAttribute(starPositions, 3));
202
164
 
203
- // ========== CENTRAL GLOW ==========
204
- const glowGeometry = new THREE.SphereGeometry(0.3, 16, 16);
205
- const glowMaterial = new THREE.MeshBasicMaterial({
206
- color: new THREE.Color('#fef3c7'),
165
+ const starMaterial = new THREE.PointsMaterial({
166
+ size: 0.008,
167
+ sizeAttenuation: true,
168
+ depthWrite: false,
207
169
  transparent: true,
208
- opacity: 0.15,
170
+ opacity: 0.5,
171
+ color: new THREE.Color('#ffffff'),
172
+ blending: THREE.AdditiveBlending,
209
173
  });
210
- const glow = new THREE.Mesh(glowGeometry, glowMaterial);
211
- glow.position.z = -0.2;
212
- scene.add(glow);
213
174
 
214
- // ========== AMBIENT PARTICLES (floating dust) ==========
215
- const dustCount = 500;
175
+ const stars = new THREE.Points(starGeometry, starMaterial);
176
+ scene.add(stars);
177
+
178
+ // ===== FLOATING DUST =====
179
+ const DUST_COUNT = 800;
216
180
  const dustGeometry = new THREE.BufferGeometry();
217
- const dustPositions = new Float32Array(dustCount * 3);
218
- const dustColors = new Float32Array(dustCount * 3);
181
+ const dustPositions = new Float32Array(DUST_COUNT * 3);
182
+ const dustColors = new Float32Array(DUST_COUNT * 3);
183
+ const dustVelocities = new Float32Array(DUST_COUNT * 3);
219
184
 
220
- for (let i = 0; i < dustCount; i++) {
185
+ for (let i = 0; i < DUST_COUNT; i++) {
221
186
  const i3 = i * 3;
222
- dustPositions[i3] = (Math.random() - 0.5) * 6;
223
- dustPositions[i3 + 1] = (Math.random() - 0.5) * 3;
224
- dustPositions[i3 + 2] = (Math.random() - 0.5) * 2;
225
-
226
- const color = galaxyColors[Math.floor(Math.random() * galaxyColors.length)];
227
- dustColors[i3] = color.r;
228
- dustColors[i3 + 1] = color.g;
229
- dustColors[i3 + 2] = color.b;
187
+ dustPositions[i3] = (Math.random() - 0.5) * 8;
188
+ dustPositions[i3 + 1] = (Math.random() - 0.5) * 4;
189
+ dustPositions[i3 + 2] = (Math.random() - 0.5) * 3;
190
+
191
+ const c = palette[Math.floor(Math.random() * palette.length)];
192
+ dustColors[i3] = c.r;
193
+ dustColors[i3 + 1] = c.g;
194
+ dustColors[i3 + 2] = c.b;
195
+
196
+ dustVelocities[i3] = (Math.random() - 0.5) * 0.3;
197
+ dustVelocities[i3 + 1] = (Math.random() - 0.5) * 0.2;
198
+ dustVelocities[i3 + 2] = (Math.random() - 0.5) * 0.15;
230
199
  }
231
200
 
232
201
  dustGeometry.setAttribute('position', new THREE.BufferAttribute(dustPositions, 3));
233
202
  dustGeometry.setAttribute('color', new THREE.BufferAttribute(dustColors, 3));
234
203
 
235
204
  const dustMaterial = new THREE.PointsMaterial({
236
- size: 0.008,
205
+ size: 0.005,
237
206
  sizeAttenuation: true,
238
207
  depthWrite: false,
239
208
  transparent: true,
@@ -245,59 +214,142 @@ const { className = '' } = Astro.props;
245
214
  const dust = new THREE.Points(dustGeometry, dustMaterial);
246
215
  scene.add(dust);
247
216
 
248
- // ========== MOUSE INTERACTION ==========
249
- const mouse = { x: 0, y: 0 };
250
- let targetMouseX = 0;
251
- let targetMouseY = 0;
217
+ // ===== CENTRAL GLOW =====
218
+ const glowGeo = new THREE.SphereGeometry(0.6, 16, 16);
219
+ const glowMat = new THREE.MeshBasicMaterial({
220
+ color: new THREE.Color('#fef3c7'),
221
+ transparent: true,
222
+ opacity: 0.18,
223
+ });
224
+ const glow = new THREE.Mesh(glowGeo, glowMat);
225
+ scene.add(glow);
226
+
227
+ // ===== GLOW RING =====
228
+ const ringGeo = new THREE.RingGeometry(0.8, 1.2, 32);
229
+ const ringMat = new THREE.MeshBasicMaterial({
230
+ color: new THREE.Color('#fbbf24'),
231
+ transparent: true,
232
+ opacity: 0.1,
233
+ side: THREE.DoubleSide,
234
+ });
235
+ const ring = new THREE.Mesh(ringGeo, ringMat);
236
+ ring.position.z = -0.3;
237
+ scene.add(ring);
238
+
239
+ // ===== MOUSE TRACKING =====
240
+ const mouse = { x: 0, y: 0, worldX: 0, worldY: 0 };
241
+ const targetMouse = { x: 0, y: 0 };
242
+ const raycaster = new THREE.Raycaster();
243
+ const mouseVec = new THREE.Vector2();
244
+ const plane = new THREE.Plane(new THREE.Vector3(0, 0, 1), 0);
245
+ const intersection = new THREE.Vector3();
246
+
247
+ const MOUSE_RADIUS = 0.8;
248
+ const MOUSE_FORCE = 0.25;
252
249
 
253
250
  container.addEventListener('mousemove', (e) => {
254
251
  const rect = canvas.getBoundingClientRect();
255
- targetMouseX = ((e.clientX - rect.left) / rect.width) * 2 - 1;
256
- targetMouseY = -((e.clientY - rect.top) / rect.height) * 2 + 1;
252
+ targetMouse.x = ((e.clientX - rect.left) / rect.width) * 2 - 1;
253
+ targetMouse.y = -((e.clientY - rect.top) / rect.height) * 2 + 1;
257
254
  });
258
255
 
259
256
  container.addEventListener('mouseleave', () => {
260
- targetMouseX = 0;
261
- targetMouseY = 0;
257
+ targetMouse.x = 0;
258
+ targetMouse.y = 0;
262
259
  });
263
260
 
264
- // ========== ANIMATION ==========
261
+ // ===== ANIMATION =====
265
262
  const clock = new THREE.Clock();
266
263
 
267
264
  function animate() {
268
265
  requestAnimationFrame(animate);
269
266
  const elapsed = clock.getElapsedTime();
270
267
 
271
- // Smooth mouse movement
272
- mouse.x += (targetMouseX - mouse.x) * 0.05;
273
- mouse.y += (targetMouseY - mouse.y) * 0.05;
268
+ // Ultra-smooth mouse interpolation
269
+ mouse.x += (targetMouse.x - mouse.x) * 0.03;
270
+ mouse.y += (targetMouse.y - mouse.y) * 0.03;
274
271
 
275
- // Rotate galaxy slowly
276
- if (galaxy.points) {
277
- galaxy.points.rotation.y = elapsed * 0.06;
278
- }
272
+ // Convert screen mouse to world coordinates
273
+ mouseVec.set(mouse.x, mouse.y);
274
+ raycaster.setFromCamera(mouseVec, camera);
275
+ raycaster.ray.intersectPlane(plane, intersection);
276
+ mouse.worldX = intersection.x;
277
+ mouse.worldY = intersection.y;
279
278
 
280
- // Rotate background stars
281
- bgStars.rotation.y = elapsed * 0.01;
282
- bgStars.rotation.x = elapsed * 0.005;
279
+ // Rotate galaxy gently
280
+ galaxyPoints.rotation.y = elapsed * 0.025;
283
281
 
284
- // Animate dust particles
285
- const dustPos = dust.geometry.attributes.position.array;
286
- for (let i = 0; i < dustCount; i++) {
282
+ // Animate galaxy particles with gentle mouse interaction
283
+ const pos = galaxyGeometry.attributes.position.array;
284
+ for (let i = 0; i < GALAXY_COUNT; i++) {
287
285
  const i3 = i * 3;
288
- dustPos[i3] += Math.sin(elapsed + i) * 0.0003;
289
- dustPos[i3 + 1] += Math.cos(elapsed * 0.8 + i) * 0.0002;
286
+
287
+ const ox = galaxyOriginalPositions[i3];
288
+ const oy = galaxyOriginalPositions[i3 + 1];
289
+ const oz = galaxyOriginalPositions[i3 + 2];
290
+
291
+ // Apply rotation
292
+ const ry = galaxyPoints.rotation.y;
293
+ const cosR = Math.cos(ry);
294
+ const sinR = Math.sin(ry);
295
+ const baseX = ox * cosR - oz * sinR;
296
+ const baseZ = ox * sinR + oz * cosR;
297
+ const baseY = oy;
298
+
299
+ // Subtle mouse deflection
300
+ const dx = baseX - mouse.worldX;
301
+ const dy = baseY - mouse.worldY;
302
+ const dist = Math.sqrt(dx * dx + dy * dy);
303
+
304
+ let pushX = 0, pushY = 0, pushZ = 0;
305
+
306
+ if (dist < MOUSE_RADIUS && dist > 0.01) {
307
+ const force = (1 - dist / MOUSE_RADIUS) * MOUSE_FORCE;
308
+ const nx = dx / dist;
309
+ const ny = dy / dist;
310
+ pushX = nx * force;
311
+ pushY = ny * force;
312
+ pushZ = (nx * ny) * force * 0.15;
313
+ }
314
+
315
+ const targetX = baseX + pushX;
316
+ const targetY = baseY + pushY;
317
+ const targetZ = baseZ + pushZ;
318
+
319
+ const spring = 0.03;
320
+ pos[i3] += (targetX - pos[i3]) * spring;
321
+ pos[i3 + 1] += (targetY - pos[i3 + 1]) * spring;
322
+ pos[i3 + 2] += (targetZ - pos[i3 + 2]) * spring;
290
323
  }
291
- dust.geometry.attributes.position.needsUpdate = true;
324
+ galaxyGeometry.attributes.position.needsUpdate = true;
325
+
326
+ // Animate dust
327
+ const dustPos = dustGeometry.attributes.position.array;
328
+ for (let i = 0; i < DUST_COUNT; i++) {
329
+ const i3 = i * 3;
330
+ dustPos[i3] += dustVelocities[i3] * 0.002 + Math.sin(elapsed * 0.3 + i) * 0.0001;
331
+ dustPos[i3 + 1] += dustVelocities[i3 + 1] * 0.002 + Math.cos(elapsed * 0.3 + i) * 0.0001;
332
+ dustPos[i3 + 2] += dustVelocities[i3 + 2] * 0.002;
333
+
334
+ if (dustPos[i3] > 4) dustPos[i3] = -4;
335
+ if (dustPos[i3] < -4) dustPos[i3] = 4;
336
+ if (dustPos[i3 + 1] > 2) dustPos[i3 + 1] = -2;
337
+ if (dustPos[i3 + 1] < -2) dustPos[i3 + 1] = 2;
338
+ }
339
+ dustGeometry.attributes.position.needsUpdate = true;
292
340
 
293
341
  // Central glow pulse
294
- const pulseScale = 1 + Math.sin(elapsed * 2) * 0.1;
342
+ const pulseScale = 1 + Math.sin(elapsed * 1.2) * 0.04;
295
343
  glow.scale.set(pulseScale, pulseScale, pulseScale);
296
- glowMaterial.opacity = 0.12 + Math.sin(elapsed * 2) * 0.03;
344
+ glowMat.opacity = 0.12 + Math.sin(elapsed * 1.2) * 0.02;
345
+
346
+ // Ring rotation
347
+ ring.rotation.z = elapsed * 0.08;
348
+ ringMat.opacity = 0.06 + Math.sin(elapsed * 1.5) * 0.015;
297
349
 
298
- // Camera follows mouse slightly
299
- camera.position.x = mouse.x * 0.3;
300
- camera.position.y = mouse.y * 0.3;
350
+ // Gentle camera mouse parallax
351
+ camera.position.x += (mouse.x * 0.15 - camera.position.x) * 0.015;
352
+ camera.position.y += (mouse.y * 0.1 - camera.position.y) * 0.015;
301
353
  camera.lookAt(0, 0, 0);
302
354
 
303
355
  renderer.render(scene, camera);
@@ -305,4 +357,4 @@ const { className = '' } = Astro.props;
305
357
 
306
358
  animate();
307
359
  })();
308
- </script>
360
+ </script>
@@ -17,10 +17,10 @@ const sizes = {
17
17
  const s = sizes[size];
18
18
  ---
19
19
 
20
- <div class="logo-container {className}">
20
+ <div class={`logo-container ${className}`.trim()}>
21
21
  <!-- Galaxy behind, bottom-left -->
22
22
  <div class="galaxy-wrap">
23
- <AnimatedGalaxy class="galaxy-svg" style={`width: ${s.galaxyWidth}; height: ${s.galaxyHeight};`} />
23
+ <AnimatedGalaxy className="galaxy-svg" style={`width: ${s.galaxyWidth}; height: ${s.galaxyHeight};`} />
24
24
  </div>
25
25
  <!-- Logo text on top -->
26
26
  <div class="logo-text">
@@ -1,3 +1,6 @@
1
+ // src/components/lib/buttons/index.ts
2
+ // Barrel export for button components
3
+
1
4
  export { default as AnimatedIconButton } from './AnimatedIconButton.astro';
2
5
  export { default as BorderDrawButton } from './BorderDrawButton.astro';
3
6
  export { default as CyberpunkButton } from './CyberpunkButton.astro';
@@ -16,4 +19,4 @@ export { default as RetroShadowButton } from './RetroShadowButton.astro';
16
19
  export { default as ShimmerButton } from './ShimmerButton.astro';
17
20
  export { default as ShinyButton } from './ShinyButton.astro';
18
21
  export { default as TiltGlowButton } from './TiltGlowButton.astro';
19
- export { default as ThreeDPushButton } from './3dPushButton.astro';
22
+ export { default as ThreeDPushButton } from './ThreeDPushButton.astro';
@@ -1,3 +1,6 @@
1
+ // src/components/lib/cards/index.ts
2
+ // Barrel export for card components
3
+
1
4
  export { default as BlogHorizontalCard } from './BlogHorizontalCard.astro';
2
5
  export { default as CyberFeatureCard } from './CyberFeatureCard.astro';
3
6
  export { default as EcommerceProductCard } from './EcommerceProductCard.astro';