partycles 1.1.3 → 1.1.5

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.
package/README.md CHANGED
@@ -12,11 +12,11 @@ A lightweight, performant React library for adding delightful animation effects
12
12
  ## ✨ Features
13
13
 
14
14
  - 🎯 **Simple API** - Just one hook to rule them all
15
- - 🎨 **17 Beautiful Animations** - Confetti, sparkles, hearts, stars, fireworks, bubbles, snow, emoji, coins, lightning, petals, aurora, fireflies, paint, music, balloons, and galaxy
15
+ - 🎨 **19 Beautiful Animations** - Confetti, sparkles, hearts, stars, fireworks, bubbles, snow, emoji, coins, petals, aurora, fireflies, paint, balloons, galaxy, glitch, magicdust, crystals, and leaves
16
16
  - 📦 **Tiny Bundle** - Zero dependencies, optimized for performance
17
17
  - 🚀 **Performant** - Optimized animations using requestAnimationFrame
18
18
  - 🎮 **Full Control** - Customize colors, particle count, physics, and more
19
- - 📱 **Responsive** - Works seamlessly on all devices
19
+ - 📱 **Mobile Optimized** - Automatic performance optimizations for mobile devices
20
20
  - 🔧 **TypeScript Support** - Fully typed for excellent DX
21
21
  - ⚡ **React 18 Ready** - Built with the latest React features
22
22
 
@@ -52,7 +52,7 @@ That's it! No configuration needed - it just works. 🎊
52
52
 
53
53
  - **Zero Dependencies** - No bloat, just pure React code
54
54
  - **One Hook** - Simple `useReward` hook handles everything
55
- - **11 Animations** - From confetti to lightning, we've got you covered
55
+ - **19 Animations** - From confetti to magical effects, we've got you covered
56
56
  - **Fully Typed** - Great TypeScript support out of the box
57
57
  - **Customizable** - Tweak colors, physics, particle count, and more
58
58
  - **Performant** - Optimized animations that won't slow down your app
@@ -66,7 +66,7 @@ The main hook for creating reward animations.
66
66
  #### Parameters
67
67
 
68
68
  - `elementId` (string): The ID of the element to animate from
69
- - `animationType` (string): One of: `'confetti'`, `'sparkles'`, `'hearts'`, `'stars'`, `'fireworks'`, `'bubbles'`, `'snow'`, `'emoji'`, `'coins'`, `'lightning'`, `'petals'`
69
+ - `animationType` (string): One of: `'confetti'`, `'sparkles'`, `'hearts'`, `'stars'`, `'fireworks'`, `'bubbles'`, `'snow'`, `'emoji'`, `'coins'`, `'petals'`, `'aurora'`, `'fireflies'`, `'paint'`, `'balloons'`, `'galaxy'`, `'glitch'`, `'magicdust'`, `'crystals'`, `'leaves'`
70
70
  - `config` (optional): Animation configuration object
71
71
 
72
72
  #### Returns
@@ -91,6 +91,15 @@ interface AnimationConfig {
91
91
  wind?: number; // Horizontal wind force (default: 0)
92
92
  friction?: number; // Air friction (default: 0.99)
93
93
  };
94
+ // NEW: Optional enhanced effects
95
+ effects?: {
96
+ flutter?: boolean; // Paper-like floating for confetti
97
+ twinkle?: boolean; // Brightness variation for stars/sparkles
98
+ pulse?: boolean; // Heartbeat effect for hearts
99
+ spin3D?: boolean; // 3D rotation for coins
100
+ wobble?: boolean; // Realistic wobble for bubbles
101
+ windDrift?: boolean; // Horizontal drift for snow/leaves
102
+ };
94
103
  }
95
104
  ```
96
105
 
@@ -103,7 +112,9 @@ Classic celebration effect with colorful paper pieces.
103
112
  const { reward } = useReward('buttonId', 'confetti', {
104
113
  particleCount: 30,
105
114
  spread: 60,
106
- colors: ['#ff0000', '#00ff00', '#0000ff']
115
+ colors: ['#ff0000', '#00ff00', '#0000ff'],
116
+ // NEW: Enable paper flutter effect
117
+ effects: { flutter: true }
107
118
  });
108
119
  ```
109
120
 
@@ -202,16 +213,6 @@ const { reward } = useReward('buttonId', 'coins', {
202
213
  });
203
214
  ```
204
215
 
205
- ### Lightning ⚡
206
- Electric energy bursts for powerful actions.
207
-
208
- ```tsx
209
- const { reward } = useReward('buttonId', 'lightning', {
210
- particleCount: 20,
211
- spread: 360
212
- });
213
- ```
214
-
215
216
  ### Petals 🌸
216
217
  Delicate flower petals floating in the wind.
217
218
 
@@ -252,16 +253,6 @@ const { reward } = useReward('buttonId', 'paint', {
252
253
  });
253
254
  ```
254
255
 
255
- ### Music 🎵
256
- Musical notes floating upward.
257
-
258
- ```tsx
259
- const { reward } = useReward('buttonId', 'music', {
260
- particleCount: 20,
261
- physics: { gravity: -0.08 }
262
- });
263
- ```
264
-
265
256
  ### Balloons 🎈
266
257
  Floating balloons with realistic physics.
267
258
 
@@ -282,6 +273,46 @@ const { reward } = useReward('buttonId', 'galaxy', {
282
273
  });
283
274
  ```
284
275
 
276
+ ### Glitch 📺
277
+ Digital glitch effect for tech themes.
278
+
279
+ ```tsx
280
+ const { reward } = useReward('buttonId', 'glitch', {
281
+ particleCount: 30,
282
+ elementSize: 40
283
+ });
284
+ ```
285
+
286
+ ### Magic Dust ✨
287
+ Magical sparkling dust particles.
288
+
289
+ ```tsx
290
+ const { reward } = useReward('buttonId', 'magicdust', {
291
+ particleCount: 35,
292
+ colors: ['#9c27b0', '#673ab7', '#3f51b5']
293
+ });
294
+ ```
295
+
296
+ ### Crystals 💎
297
+ Shimmering crystal fragments.
298
+
299
+ ```tsx
300
+ const { reward } = useReward('buttonId', 'crystals', {
301
+ particleCount: 20,
302
+ elementSize: 25
303
+ });
304
+ ```
305
+
306
+ ### Leaves 🍃
307
+ Falling autumn leaves with natural movement.
308
+
309
+ ```tsx
310
+ const { reward } = useReward('buttonId', 'leaves', {
311
+ particleCount: 30,
312
+ physics: { gravity: 0.05, wind: 0.2 }
313
+ });
314
+ ```
315
+
285
316
  ## 💡 Examples
286
317
 
287
318
  ### Form Submission Success
@@ -354,6 +385,54 @@ function Achievement({ unlocked, name }) {
354
385
  }
355
386
  ```
356
387
 
388
+ ## ✨ Enhanced Effects (v1.1.5+)
389
+
390
+ Make animations more realistic with optional effects:
391
+
392
+ ```tsx
393
+ // Confetti with paper flutter
394
+ const { reward } = useReward('confetti-btn', 'confetti', {
395
+ effects: { flutter: true }
396
+ });
397
+
398
+ // Stars with twinkling
399
+ const { reward } = useReward('star-btn', 'stars', {
400
+ effects: { twinkle: true }
401
+ });
402
+
403
+ // Hearts with pulse/heartbeat
404
+ const { reward } = useReward('heart-btn', 'hearts', {
405
+ effects: { pulse: true }
406
+ });
407
+
408
+ // Coins with 3D spin
409
+ const { reward } = useReward('coin-btn', 'coins', {
410
+ effects: { spin3D: true }
411
+ });
412
+
413
+ // Snow with wind drift
414
+ const { reward } = useReward('snow-btn', 'snow', {
415
+ effects: { windDrift: true }
416
+ });
417
+
418
+ // Bubbles with wobble
419
+ const { reward } = useReward('bubble-btn', 'bubbles', {
420
+ effects: { wobble: true }
421
+ });
422
+
423
+ // Combine multiple effects
424
+ const { reward } = useReward('magic-btn', 'sparkles', {
425
+ effects: {
426
+ twinkle: true,
427
+ // Other effects work too!
428
+ },
429
+ physics: {
430
+ gravity: 0.2,
431
+ wind: 0.1
432
+ }
433
+ });
434
+ ```
435
+
357
436
  ## 🎯 Best Practices
358
437
 
359
438
  1. **Unique IDs**: Ensure each animated element has a unique ID
@@ -448,6 +527,17 @@ We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) f
448
527
  4. Push to the branch (`git push origin feature/amazing-feature`)
449
528
  5. Open a Pull Request
450
529
 
530
+ ## 📈 Changelog
531
+
532
+ ### v1.1.3 (Latest)
533
+ - 🚀 Added automatic mobile performance optimizations
534
+ - 🐛 Fixed Safari compatibility issues
535
+ - 📦 Streamlined bundle size by removing 7 animations
536
+ - 🔧 Fixed CI/CD pipeline and npm publishing
537
+
538
+ ### v1.0.0
539
+ - 🎉 Initial release with 26 animations
540
+
451
541
  ## 📄 License
452
542
 
453
543
  MIT © Jonathan Leane
@@ -4,5 +4,7 @@ export declare const createCoinParticles: (origin: {
4
4
  x: number;
5
5
  y: number;
6
6
  }, config: AnimationConfig) => Particle[];
7
- export declare const renderCoinParticle: (particle: Particle) => React.ReactNode;
7
+ export declare const renderCoinParticle: (particle: Particle & {
8
+ config?: AnimationConfig;
9
+ }) => React.ReactNode;
8
10
  //# sourceMappingURL=coins.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"coins.d.ts","sourceRoot":"","sources":["../../src/animations/coins.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAKrD,eAAO,MAAM,mBAAmB,GAC9B,QAAQ;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,EAChC,QAAQ,eAAe,KACtB,QAAQ,EAiCV,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,UAAU,QAAQ,KAAG,KAAK,CAAC,SA0C7D,CAAC"}
1
+ {"version":3,"file":"coins.d.ts","sourceRoot":"","sources":["../../src/animations/coins.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAKrD,eAAO,MAAM,mBAAmB,GAC9B,QAAQ;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,EAChC,QAAQ,eAAe,KACtB,QAAQ,EAiCV,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,UAAU,QAAQ,GAAG;IAAE,MAAM,CAAC,EAAE,eAAe,CAAA;CAAE,KAAG,KAAK,CAAC,SAoD5F,CAAC"}
@@ -4,5 +4,7 @@ export declare const createHeartParticles: (origin: {
4
4
  x: number;
5
5
  y: number;
6
6
  }, config: AnimationConfig) => Particle[];
7
- export declare const renderHeartParticle: (particle: Particle) => React.ReactNode;
7
+ export declare const renderHeartParticle: (particle: Particle & {
8
+ config?: AnimationConfig;
9
+ }) => React.ReactNode;
8
10
  //# sourceMappingURL=hearts.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hearts.d.ts","sourceRoot":"","sources":["../../src/animations/hearts.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAKrD,eAAO,MAAM,oBAAoB,GAC/B,QAAQ;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,EAChC,QAAQ,eAAe,KACtB,QAAQ,EA8BV,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAI,UAAU,QAAQ,KAAG,KAAK,CAAC,SAe9D,CAAC"}
1
+ {"version":3,"file":"hearts.d.ts","sourceRoot":"","sources":["../../src/animations/hearts.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAKrD,eAAO,MAAM,oBAAoB,GAC/B,QAAQ;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,EAChC,QAAQ,eAAe,KACtB,QAAQ,EA8BV,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAI,UAAU,QAAQ,GAAG;IAAE,MAAM,CAAC,EAAE,eAAe,CAAA;CAAE,KAAG,KAAK,CAAC,SAqB7F,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/animations/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAmCpE,MAAM,MAAM,eAAe,GAAG,CAC5B,MAAM,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,EAChC,MAAM,EAAE,eAAe,KACpB,QAAQ,EAAE,CAAC;AAChB,MAAM,MAAM,gBAAgB,GAAG,CAAC,QAAQ,EAAE,QAAQ,KAAK,KAAK,CAAC,SAAS,CAAC;AAEvE,UAAU,gBAAgB;IACxB,eAAe,EAAE,eAAe,CAAC;IACjC,cAAc,EAAE,gBAAgB,CAAC;CAClC;AAED,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,aAAa,EAAE,gBAAgB,CA6E9D,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/animations/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAsBpE,MAAM,MAAM,eAAe,GAAG,CAC5B,MAAM,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,EAChC,MAAM,EAAE,eAAe,KACpB,QAAQ,EAAE,CAAC;AAChB,MAAM,MAAM,gBAAgB,GAAG,CAAC,QAAQ,EAAE,QAAQ,KAAK,KAAK,CAAC,SAAS,CAAC;AAEvE,UAAU,gBAAgB;IACxB,eAAe,EAAE,eAAe,CAAC;IACjC,cAAc,EAAE,gBAAgB,CAAC;CAClC;AAED,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,aAAa,EAAE,gBAAgB,CA6E9D,CAAC"}
@@ -4,5 +4,7 @@ export declare const createCoinParticles: (origin: {
4
4
  x: number;
5
5
  y: number;
6
6
  }, config: AnimationConfig) => Particle[];
7
- export declare const renderCoinParticle: (particle: Particle) => React.ReactNode;
7
+ export declare const renderCoinParticle: (particle: Particle & {
8
+ config?: AnimationConfig;
9
+ }) => React.ReactNode;
8
10
  //# sourceMappingURL=coins.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"coins.d.ts","sourceRoot":"","sources":["../../src/animations/coins.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAKrD,eAAO,MAAM,mBAAmB,GAC9B,QAAQ;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,EAChC,QAAQ,eAAe,KACtB,QAAQ,EAiCV,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,UAAU,QAAQ,KAAG,KAAK,CAAC,SA0C7D,CAAC"}
1
+ {"version":3,"file":"coins.d.ts","sourceRoot":"","sources":["../../src/animations/coins.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAKrD,eAAO,MAAM,mBAAmB,GAC9B,QAAQ;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,EAChC,QAAQ,eAAe,KACtB,QAAQ,EAiCV,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,UAAU,QAAQ,GAAG;IAAE,MAAM,CAAC,EAAE,eAAe,CAAA;CAAE,KAAG,KAAK,CAAC,SAoD5F,CAAC"}
@@ -4,5 +4,7 @@ export declare const createHeartParticles: (origin: {
4
4
  x: number;
5
5
  y: number;
6
6
  }, config: AnimationConfig) => Particle[];
7
- export declare const renderHeartParticle: (particle: Particle) => React.ReactNode;
7
+ export declare const renderHeartParticle: (particle: Particle & {
8
+ config?: AnimationConfig;
9
+ }) => React.ReactNode;
8
10
  //# sourceMappingURL=hearts.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hearts.d.ts","sourceRoot":"","sources":["../../src/animations/hearts.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAKrD,eAAO,MAAM,oBAAoB,GAC/B,QAAQ;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,EAChC,QAAQ,eAAe,KACtB,QAAQ,EA8BV,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAI,UAAU,QAAQ,KAAG,KAAK,CAAC,SAe9D,CAAC"}
1
+ {"version":3,"file":"hearts.d.ts","sourceRoot":"","sources":["../../src/animations/hearts.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAKrD,eAAO,MAAM,oBAAoB,GAC/B,QAAQ;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,EAChC,QAAQ,eAAe,KACtB,QAAQ,EA8BV,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAAI,UAAU,QAAQ,GAAG;IAAE,MAAM,CAAC,EAAE,eAAe,CAAA;CAAE,KAAG,KAAK,CAAC,SAqB7F,CAAC"}
@@ -34,8 +34,14 @@ const createHeartParticles = (origin, config) => {
34
34
  return particles;
35
35
  };
36
36
  const renderHeartParticle = (particle) => {
37
- return (React.createElement("svg", { key: particle.id, width: particle.size, height: particle.size, viewBox: "0 0 24 24", fill: particle.color, style: {
37
+ var _a, _b;
38
+ // Calculate pulse effect if enabled
39
+ const pulse = ((_b = (_a = particle.config) === null || _a === void 0 ? void 0 : _a.effects) === null || _b === void 0 ? void 0 : _b.pulse)
40
+ ? 1 + Math.sin(particle.life * 0.2) * 0.1
41
+ : 1;
42
+ return (React.createElement("svg", { key: particle.id, width: particle.size * pulse, height: particle.size * pulse, viewBox: "0 0 24 24", fill: particle.color, style: {
38
43
  filter: `drop-shadow(0 0 ${particle.size * 0.15}px ${particle.color})`,
44
+ transition: 'width 0.1s ease-out, height 0.1s ease-out',
39
45
  } },
40
46
  React.createElement("path", { d: "M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z" })));
41
47
  };
@@ -1 +1 @@
1
- {"version":3,"file":"hearts.esm.js","sources":["../../src/utils.ts","../../src/animations/hearts.tsx"],"sourcesContent":["import { Particle } from './types';\n\nexport const randomInRange = (min: number, max: number): number => {\n return Math.random() * (max - min) + min;\n};\n\nexport const degreesToRadians = (degrees: number): number => {\n return (degrees * Math.PI) / 180;\n};\n\nexport const generateId = (): string => {\n return Math.random().toString(36).substring(2, 9);\n};\n\nexport const getRandomColor = (colors: string[]): string => {\n return (\n colors[Math.floor(Math.random() * colors.length)] || colors[0] || '#ffffff'\n );\n};\n\nexport const createParticleStyle = (\n particle: Particle,\n containerRect: DOMRect\n): React.CSSProperties => {\n return {\n position: 'absolute',\n left: `${particle.x - containerRect.left}px`,\n top: `${particle.y - containerRect.top}px`,\n transform: `rotate(${particle.rotation}deg)`,\n opacity: particle.opacity,\n pointerEvents: 'none',\n transition: 'none',\n willChange: 'transform, opacity',\n };\n};\n","import React from 'react';\nimport { AnimationConfig, Particle } from '../types';\nimport { randomInRange, generateId, getRandomColor } from '../utils';\n\nconst heartColors = ['#ff1744', '#e91e63', '#ff4569', '#ff6b6b', '#ee5a70'];\n\nexport const createHeartParticles = (\n origin: { x: number; y: number },\n config: AnimationConfig\n): Particle[] => {\n const {\n particleCount = 25,\n startVelocity = 12,\n colors = heartColors,\n elementSize = 30,\n } = config;\n\n const particles: Particle[] = [];\n\n for (let i = 0; i < particleCount; i++) {\n const angle = randomInRange(-45, -135);\n const velocity = randomInRange(startVelocity * 0.7, startVelocity * 1.3);\n const horizontalDrift = randomInRange(-2, 2);\n\n particles.push({\n id: generateId(),\n x: origin.x + randomInRange(-10, 10),\n y: origin.y,\n vx: Math.cos((angle * Math.PI) / 180) * velocity + horizontalDrift,\n vy: Math.sin((angle * Math.PI) / 180) * velocity,\n life: config.lifetime || 180,\n opacity: 1,\n size: randomInRange(elementSize * 0.6, elementSize * 1.2),\n rotation: randomInRange(-20, 20),\n color: getRandomColor(colors),\n });\n }\n\n return particles;\n};\n\nexport const renderHeartParticle = (particle: Particle): React.ReactNode => {\n return (\n <svg\n key={particle.id}\n width={particle.size}\n height={particle.size}\n viewBox=\"0 0 24 24\"\n fill={particle.color}\n style={{\n filter: `drop-shadow(0 0 ${particle.size * 0.15}px ${particle.color})`,\n }}\n >\n <path d=\"M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z\" />\n </svg>\n );\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hearts.esm.js","sources":["../../src/utils.ts","../../src/animations/hearts.tsx"],"sourcesContent":["import { Particle } from './types';\n\nexport const randomInRange = (min: number, max: number): number => {\n return Math.random() * (max - min) + min;\n};\n\nexport const degreesToRadians = (degrees: number): number => {\n return (degrees * Math.PI) / 180;\n};\n\nexport const generateId = (): string => {\n return Math.random().toString(36).substring(2, 9);\n};\n\nexport const getRandomColor = (colors: string[]): string => {\n return (\n colors[Math.floor(Math.random() * colors.length)] || colors[0] || '#ffffff'\n );\n};\n\nexport const createParticleStyle = (\n particle: Particle,\n containerRect: DOMRect\n): React.CSSProperties => {\n return {\n position: 'absolute',\n left: `${particle.x - containerRect.left}px`,\n top: `${particle.y - containerRect.top}px`,\n transform: `rotate(${particle.rotation}deg)`,\n opacity: particle.opacity,\n pointerEvents: 'none',\n transition: 'none',\n willChange: 'transform, opacity',\n };\n};\n","import React from 'react';\nimport { AnimationConfig, Particle } from '../types';\nimport { randomInRange, generateId, getRandomColor } from '../utils';\n\nconst heartColors = ['#ff1744', '#e91e63', '#ff4569', '#ff6b6b', '#ee5a70'];\n\nexport const createHeartParticles = (\n origin: { x: number; y: number },\n config: AnimationConfig\n): Particle[] => {\n const {\n particleCount = 25,\n startVelocity = 12,\n colors = heartColors,\n elementSize = 30,\n } = config;\n\n const particles: Particle[] = [];\n\n for (let i = 0; i < particleCount; i++) {\n const angle = randomInRange(-45, -135);\n const velocity = randomInRange(startVelocity * 0.7, startVelocity * 1.3);\n const horizontalDrift = randomInRange(-2, 2);\n\n particles.push({\n id: generateId(),\n x: origin.x + randomInRange(-10, 10),\n y: origin.y,\n vx: Math.cos((angle * Math.PI) / 180) * velocity + horizontalDrift,\n vy: Math.sin((angle * Math.PI) / 180) * velocity,\n life: config.lifetime || 180,\n opacity: 1,\n size: randomInRange(elementSize * 0.6, elementSize * 1.2),\n rotation: randomInRange(-20, 20),\n color: getRandomColor(colors),\n });\n }\n\n return particles;\n};\n\nexport const renderHeartParticle = (particle: Particle & { config?: AnimationConfig }): React.ReactNode => {\n // Calculate pulse effect if enabled\n const pulse = particle.config?.effects?.pulse \n ? 1 + Math.sin(particle.life * 0.2) * 0.1 \n : 1;\n \n return (\n <svg\n key={particle.id}\n width={particle.size * pulse}\n height={particle.size * pulse}\n viewBox=\"0 0 24 24\"\n fill={particle.color}\n style={{\n filter: `drop-shadow(0 0 ${particle.size * 0.15}px ${particle.color})`,\n transition: 'width 0.1s ease-out, height 0.1s ease-out',\n }}\n >\n <path d=\"M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z\" />\n </svg>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -36,8 +36,14 @@ const createHeartParticles = (origin, config) => {
36
36
  return particles;
37
37
  };
38
38
  const renderHeartParticle = (particle) => {
39
- return (React.createElement("svg", { key: particle.id, width: particle.size, height: particle.size, viewBox: "0 0 24 24", fill: particle.color, style: {
39
+ var _a, _b;
40
+ // Calculate pulse effect if enabled
41
+ const pulse = ((_b = (_a = particle.config) === null || _a === void 0 ? void 0 : _a.effects) === null || _b === void 0 ? void 0 : _b.pulse)
42
+ ? 1 + Math.sin(particle.life * 0.2) * 0.1
43
+ : 1;
44
+ return (React.createElement("svg", { key: particle.id, width: particle.size * pulse, height: particle.size * pulse, viewBox: "0 0 24 24", fill: particle.color, style: {
40
45
  filter: `drop-shadow(0 0 ${particle.size * 0.15}px ${particle.color})`,
46
+ transition: 'width 0.1s ease-out, height 0.1s ease-out',
41
47
  } },
42
48
  React.createElement("path", { d: "M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z" })));
43
49
  };
@@ -1 +1 @@
1
- {"version":3,"file":"hearts.js","sources":["../../src/utils.ts","../../src/animations/hearts.tsx"],"sourcesContent":["import { Particle } from './types';\n\nexport const randomInRange = (min: number, max: number): number => {\n return Math.random() * (max - min) + min;\n};\n\nexport const degreesToRadians = (degrees: number): number => {\n return (degrees * Math.PI) / 180;\n};\n\nexport const generateId = (): string => {\n return Math.random().toString(36).substring(2, 9);\n};\n\nexport const getRandomColor = (colors: string[]): string => {\n return (\n colors[Math.floor(Math.random() * colors.length)] || colors[0] || '#ffffff'\n );\n};\n\nexport const createParticleStyle = (\n particle: Particle,\n containerRect: DOMRect\n): React.CSSProperties => {\n return {\n position: 'absolute',\n left: `${particle.x - containerRect.left}px`,\n top: `${particle.y - containerRect.top}px`,\n transform: `rotate(${particle.rotation}deg)`,\n opacity: particle.opacity,\n pointerEvents: 'none',\n transition: 'none',\n willChange: 'transform, opacity',\n };\n};\n","import React from 'react';\nimport { AnimationConfig, Particle } from '../types';\nimport { randomInRange, generateId, getRandomColor } from '../utils';\n\nconst heartColors = ['#ff1744', '#e91e63', '#ff4569', '#ff6b6b', '#ee5a70'];\n\nexport const createHeartParticles = (\n origin: { x: number; y: number },\n config: AnimationConfig\n): Particle[] => {\n const {\n particleCount = 25,\n startVelocity = 12,\n colors = heartColors,\n elementSize = 30,\n } = config;\n\n const particles: Particle[] = [];\n\n for (let i = 0; i < particleCount; i++) {\n const angle = randomInRange(-45, -135);\n const velocity = randomInRange(startVelocity * 0.7, startVelocity * 1.3);\n const horizontalDrift = randomInRange(-2, 2);\n\n particles.push({\n id: generateId(),\n x: origin.x + randomInRange(-10, 10),\n y: origin.y,\n vx: Math.cos((angle * Math.PI) / 180) * velocity + horizontalDrift,\n vy: Math.sin((angle * Math.PI) / 180) * velocity,\n life: config.lifetime || 180,\n opacity: 1,\n size: randomInRange(elementSize * 0.6, elementSize * 1.2),\n rotation: randomInRange(-20, 20),\n color: getRandomColor(colors),\n });\n }\n\n return particles;\n};\n\nexport const renderHeartParticle = (particle: Particle): React.ReactNode => {\n return (\n <svg\n key={particle.id}\n width={particle.size}\n height={particle.size}\n viewBox=\"0 0 24 24\"\n fill={particle.color}\n style={{\n filter: `drop-shadow(0 0 ${particle.size * 0.15}px ${particle.color})`,\n }}\n >\n <path d=\"M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z\" />\n </svg>\n );\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hearts.js","sources":["../../src/utils.ts","../../src/animations/hearts.tsx"],"sourcesContent":["import { Particle } from './types';\n\nexport const randomInRange = (min: number, max: number): number => {\n return Math.random() * (max - min) + min;\n};\n\nexport const degreesToRadians = (degrees: number): number => {\n return (degrees * Math.PI) / 180;\n};\n\nexport const generateId = (): string => {\n return Math.random().toString(36).substring(2, 9);\n};\n\nexport const getRandomColor = (colors: string[]): string => {\n return (\n colors[Math.floor(Math.random() * colors.length)] || colors[0] || '#ffffff'\n );\n};\n\nexport const createParticleStyle = (\n particle: Particle,\n containerRect: DOMRect\n): React.CSSProperties => {\n return {\n position: 'absolute',\n left: `${particle.x - containerRect.left}px`,\n top: `${particle.y - containerRect.top}px`,\n transform: `rotate(${particle.rotation}deg)`,\n opacity: particle.opacity,\n pointerEvents: 'none',\n transition: 'none',\n willChange: 'transform, opacity',\n };\n};\n","import React from 'react';\nimport { AnimationConfig, Particle } from '../types';\nimport { randomInRange, generateId, getRandomColor } from '../utils';\n\nconst heartColors = ['#ff1744', '#e91e63', '#ff4569', '#ff6b6b', '#ee5a70'];\n\nexport const createHeartParticles = (\n origin: { x: number; y: number },\n config: AnimationConfig\n): Particle[] => {\n const {\n particleCount = 25,\n startVelocity = 12,\n colors = heartColors,\n elementSize = 30,\n } = config;\n\n const particles: Particle[] = [];\n\n for (let i = 0; i < particleCount; i++) {\n const angle = randomInRange(-45, -135);\n const velocity = randomInRange(startVelocity * 0.7, startVelocity * 1.3);\n const horizontalDrift = randomInRange(-2, 2);\n\n particles.push({\n id: generateId(),\n x: origin.x + randomInRange(-10, 10),\n y: origin.y,\n vx: Math.cos((angle * Math.PI) / 180) * velocity + horizontalDrift,\n vy: Math.sin((angle * Math.PI) / 180) * velocity,\n life: config.lifetime || 180,\n opacity: 1,\n size: randomInRange(elementSize * 0.6, elementSize * 1.2),\n rotation: randomInRange(-20, 20),\n color: getRandomColor(colors),\n });\n }\n\n return particles;\n};\n\nexport const renderHeartParticle = (particle: Particle & { config?: AnimationConfig }): React.ReactNode => {\n // Calculate pulse effect if enabled\n const pulse = particle.config?.effects?.pulse \n ? 1 + Math.sin(particle.life * 0.2) * 0.1 \n : 1;\n \n return (\n <svg\n key={particle.id}\n width={particle.size * pulse}\n height={particle.size * pulse}\n viewBox=\"0 0 24 24\"\n fill={particle.color}\n style={{\n filter: `drop-shadow(0 0 ${particle.size * 0.15}px ${particle.color})`,\n transition: 'width 0.1s ease-out, height 0.1s ease-out',\n }}\n >\n <path d=\"M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z\" />\n </svg>\n );\n};\n"],"names":[],"mappings":"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"}
@@ -10,6 +10,7 @@ export interface Particle {
10
10
  rotation: number;
11
11
  color: string;
12
12
  element?: React.ReactNode;
13
+ config?: AnimationConfig;
13
14
  }
14
15
  export interface AnimationConfig {
15
16
  particleCount?: number;
@@ -25,6 +26,14 @@ export interface AnimationConfig {
25
26
  wind?: number;
26
27
  friction?: number;
27
28
  };
29
+ effects?: {
30
+ flutter?: boolean;
31
+ twinkle?: boolean;
32
+ pulse?: boolean;
33
+ spin3D?: boolean;
34
+ wobble?: boolean;
35
+ windDrift?: boolean;
36
+ };
28
37
  }
29
38
  export type AnimationType = 'confetti' | 'sparkles' | 'fireworks' | 'hearts' | 'stars' | 'bubbles' | 'snow' | 'emoji' | 'coins' | 'petals' | 'aurora' | 'fireflies' | 'paint' | 'balloons' | 'galaxy' | 'leaves' | 'glitch' | 'magicdust' | 'crystals';
30
39
  export interface UseRewardConfig extends AnimationConfig {
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAED,MAAM,WAAW,eAAe;IAC9B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE;QACR,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;CACH;AAED,MAAM,MAAM,aAAa,GACrB,UAAU,GACV,UAAU,GACV,WAAW,GACX,QAAQ,GACR,OAAO,GACP,SAAS,GACT,MAAM,GACN,OAAO,GACP,OAAO,GACP,QAAQ,GACR,QAAQ,GACR,WAAW,GACX,OAAO,GACP,UAAU,GACV,QAAQ,GACR,QAAQ,GACR,QAAQ,GACR,WAAW,GACX,UAAU,CAAC;AAEf,MAAM,WAAW,eAAgB,SAAQ,eAAe;IACtD,aAAa,EAAE,aAAa,CAAC;CAC9B"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,MAAM,CAAC,EAAE,eAAe,CAAC;CAC1B;AAED,MAAM,WAAW,eAAe;IAC9B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE;QACR,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;IAEF,OAAO,CAAC,EAAE;QACR,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,KAAK,CAAC,EAAE,OAAO,CAAC;QAChB,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,SAAS,CAAC,EAAE,OAAO,CAAC;KACrB,CAAC;CACH;AAED,MAAM,MAAM,aAAa,GACrB,UAAU,GACV,UAAU,GACV,WAAW,GACX,QAAQ,GACR,OAAO,GACP,SAAS,GACT,MAAM,GACN,OAAO,GACP,OAAO,GACP,QAAQ,GACR,QAAQ,GACR,WAAW,GACX,OAAO,GACP,UAAU,GACV,QAAQ,GACR,QAAQ,GACR,QAAQ,GACR,WAAW,GACX,UAAU,CAAC;AAEf,MAAM,WAAW,eAAgB,SAAQ,eAAe;IACtD,aAAa,EAAE,aAAa,CAAC;CAC9B"}
@@ -1 +1 @@
1
- {"version":3,"file":"useReward.d.ts","sourceRoot":"","sources":["../src/useReward.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,eAAe,EAAY,MAAM,SAAS,CAAC;AAQnE,UAAU,eAAe;IACvB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,eAAO,MAAM,SAAS,GACpB,WAAW,MAAM,EACjB,eAAe,aAAa,EAC5B,SAAS,eAAe,KACvB,eAwLF,CAAC"}
1
+ {"version":3,"file":"useReward.d.ts","sourceRoot":"","sources":["../src/useReward.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,eAAe,EAAY,MAAM,SAAS,CAAC;AAQnE,UAAU,eAAe;IACvB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,eAAO,MAAM,SAAS,GACpB,WAAW,MAAM,EACjB,eAAe,aAAa,EAC5B,SAAS,eAAe,KACvB,eAsNF,CAAC"}
package/dist/index.esm.js CHANGED
@@ -131,8 +131,14 @@ const createHeartParticles = (origin, config) => {
131
131
  return particles;
132
132
  };
133
133
  const renderHeartParticle = (particle) => {
134
- return (React.createElement("svg", { key: particle.id, width: particle.size, height: particle.size, viewBox: "0 0 24 24", fill: particle.color, style: {
134
+ var _a, _b;
135
+ // Calculate pulse effect if enabled
136
+ const pulse = ((_b = (_a = particle.config) === null || _a === void 0 ? void 0 : _a.effects) === null || _b === void 0 ? void 0 : _b.pulse)
137
+ ? 1 + Math.sin(particle.life * 0.2) * 0.1
138
+ : 1;
139
+ return (React.createElement("svg", { key: particle.id, width: particle.size * pulse, height: particle.size * pulse, viewBox: "0 0 24 24", fill: particle.color, style: {
135
140
  filter: `drop-shadow(0 0 ${particle.size * 0.15}px ${particle.color})`,
141
+ transition: 'width 0.1s ease-out, height 0.1s ease-out',
136
142
  } },
137
143
  React.createElement("path", { d: "M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z" })));
138
144
  };
@@ -368,14 +374,21 @@ const createCoinParticles = (origin, config) => {
368
374
  return particles;
369
375
  };
370
376
  const renderCoinParticle = (particle) => {
371
- const spinSpeed = 8; // Degrees per frame
377
+ var _a, _b, _c, _d, _e, _f, _g, _h;
378
+ const spinSpeed = ((_b = (_a = particle.config) === null || _a === void 0 ? void 0 : _a.effects) === null || _b === void 0 ? void 0 : _b.spin3D) ? 8 : 2; // Faster spin with 3D effect
372
379
  const currentRotation = particle.rotation + (120 - particle.life) * spinSpeed;
380
+ // 3D effect: scale X based on rotation to simulate perspective
381
+ const scaleX = ((_d = (_c = particle.config) === null || _c === void 0 ? void 0 : _c.effects) === null || _d === void 0 ? void 0 : _d.spin3D)
382
+ ? Math.abs(Math.cos((currentRotation * Math.PI) / 180))
383
+ : 1;
373
384
  return (React.createElement("div", { key: particle.id, style: {
374
385
  width: `${particle.size}px`,
375
386
  height: `${particle.size}px`,
376
387
  background: `radial-gradient(ellipse at 30% 30%, ${particle.color}, #B8860B)`,
377
388
  borderRadius: '50%',
378
- transform: `rotateY(${currentRotation}deg)`,
389
+ transform: ((_f = (_e = particle.config) === null || _e === void 0 ? void 0 : _e.effects) === null || _f === void 0 ? void 0 : _f.spin3D)
390
+ ? `rotateY(${currentRotation}deg) scaleX(${scaleX})`
391
+ : `rotate(${currentRotation}deg)`,
379
392
  transformStyle: 'preserve-3d',
380
393
  boxShadow: `
381
394
  inset -2px -2px 4px rgba(0, 0, 0, 0.3),
@@ -385,6 +398,7 @@ const renderCoinParticle = (particle) => {
385
398
  border: `1px solid ${particle.color}`,
386
399
  position: 'relative',
387
400
  overflow: 'hidden',
401
+ backfaceVisibility: 'hidden',
388
402
  } },
389
403
  React.createElement("div", { style: {
390
404
  position: 'absolute',
@@ -396,6 +410,8 @@ const renderCoinParticle = (particle) => {
396
410
  color: '#B8860B',
397
411
  textShadow: '1px 1px 1px rgba(0, 0, 0, 0.3)',
398
412
  fontFamily: 'Arial, sans-serif',
413
+ opacity: ((_h = (_g = particle.config) === null || _g === void 0 ? void 0 : _g.effects) === null || _h === void 0 ? void 0 : _h.spin3D) && scaleX < 0.3 ? 0 : 1,
414
+ transition: 'opacity 0.1s',
399
415
  } }, "$")));
400
416
  };
401
417
 
@@ -1331,7 +1347,8 @@ const useReward = (elementId, animationType, config) => {
1331
1347
  ? optimizeConfigForMobile(config)
1332
1348
  : undefined;
1333
1349
  // Create particles
1334
- particlesRef.current = animationHandler.createParticles(origin, optimizedConfig || {});
1350
+ particlesRef.current = animationHandler.createParticles(origin, optimizedConfig || {}).map(particle => (Object.assign(Object.assign({}, particle), { config: optimizedConfig || config // Store config in particle for render functions
1351
+ })));
1335
1352
  // Create container
1336
1353
  const container = document.createElement('div');
1337
1354
  container.style.position = 'fixed';
@@ -1376,6 +1393,22 @@ const useReward = (elementId, animationType, config) => {
1376
1393
  particle.vy *= friction;
1377
1394
  particle.rotation += particle.vx * 2;
1378
1395
  particle.life -= 1.2;
1396
+ // Apply optional effects
1397
+ const effects = config === null || config === void 0 ? void 0 : config.effects;
1398
+ // Flutter effect for confetti
1399
+ if ((effects === null || effects === void 0 ? void 0 : effects.flutter) && animationType === 'confetti') {
1400
+ particle.x += Math.sin(particle.life * 0.1) * 0.5;
1401
+ particle.rotation += Math.sin(particle.life * 0.05) * 2;
1402
+ }
1403
+ // Wind drift for snow/leaves
1404
+ if ((effects === null || effects === void 0 ? void 0 : effects.windDrift) && (animationType === 'snow' || animationType === 'leaves')) {
1405
+ particle.x += Math.sin(particle.life * 0.05 + particle.id.charCodeAt(0)) * 0.8;
1406
+ }
1407
+ // Wobble effect for bubbles
1408
+ if ((effects === null || effects === void 0 ? void 0 : effects.wobble) && animationType === 'bubbles') {
1409
+ particle.x += Math.sin(particle.life * 0.08) * 0.3;
1410
+ particle.y += Math.cos(particle.life * 0.08) * 0.2;
1411
+ }
1379
1412
  // Special opacity handling for sparkles
1380
1413
  if (animationType === 'sparkles') {
1381
1414
  if (particle.life > 70) {
@@ -1384,6 +1417,14 @@ const useReward = (elementId, animationType, config) => {
1384
1417
  else if (particle.life < 30) {
1385
1418
  particle.opacity = particle.life / 30;
1386
1419
  }
1420
+ // Twinkle effect
1421
+ if (effects === null || effects === void 0 ? void 0 : effects.twinkle) {
1422
+ particle.opacity *= 0.5 + Math.sin(particle.life * 0.3) * 0.5;
1423
+ }
1424
+ }
1425
+ else if (animationType === 'stars' && (effects === null || effects === void 0 ? void 0 : effects.twinkle)) {
1426
+ // Twinkle effect for stars
1427
+ particle.opacity = (particle.life / 100) * (0.5 + Math.sin(particle.life * 0.3) * 0.5);
1387
1428
  }
1388
1429
  else {
1389
1430
  particle.opacity = particle.life / 100;