partycles 0.4.0 → 1.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.
- package/README.md +27 -1
- package/dist/animations/animations/index.d.ts.map +1 -1
- package/dist/animations/index.d.ts +1 -0
- package/dist/animations/index.d.ts.map +1 -1
- package/dist/animations/mobileOptimizations.d.ts +6 -0
- package/dist/animations/mobileOptimizations.d.ts.map +1 -0
- package/dist/animations/types.d.ts +1 -1
- package/dist/animations/types.d.ts.map +1 -1
- package/dist/animations/useReward.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +103 -1237
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +103 -1235
- package/dist/index.js.map +1 -1
- package/dist/mobileOptimizations.d.ts +6 -0
- package/dist/mobileOptimizations.d.ts.map +1 -0
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/useReward.d.ts.map +1 -1
- package/package.json +14 -3
package/dist/index.esm.js
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
import React, { useState, useRef,
|
1
|
+
import React, { useState, useRef, useEffect, useCallback } from 'react';
|
2
2
|
import { createRoot } from 'react-dom/client';
|
3
3
|
|
4
4
|
const randomInRange = (min, max) => {
|
@@ -26,9 +26,9 @@ const createParticleStyle = (particle, containerRect) => {
|
|
26
26
|
};
|
27
27
|
};
|
28
28
|
|
29
|
-
const defaultColors$
|
29
|
+
const defaultColors$3 = ['#f44336', '#e91e63', '#9c27b0', '#673ab7', '#3f51b5', '#2196f3', '#03a9f4', '#00bcd4', '#009688', '#4caf50', '#8bc34a', '#cddc39', '#ffeb3b', '#ffc107', '#ff9800', '#ff5722'];
|
30
30
|
const createConfettiParticles = (origin, config) => {
|
31
|
-
const { particleCount = 50, startVelocity = 20, colors = defaultColors$
|
31
|
+
const { particleCount = 50, startVelocity = 20, colors = defaultColors$3, elementSize = 20 } = config;
|
32
32
|
const particles = [];
|
33
33
|
for (let i = 0; i < particleCount; i++) {
|
34
34
|
const angle = randomInRange(0, 360);
|
@@ -359,61 +359,6 @@ const renderCoinParticle = (particle) => {
|
|
359
359
|
} }, "$")));
|
360
360
|
};
|
361
361
|
|
362
|
-
const lightningColors = ['#FFFF00', '#FFFFFF', '#00FFFF', '#FF00FF'];
|
363
|
-
const createLightningParticles = (origin, config) => {
|
364
|
-
const { particleCount = 20, spread = 360, startVelocity = 50, colors = lightningColors, elementSize = 30 } = config;
|
365
|
-
const particles = [];
|
366
|
-
for (let i = 0; i < particleCount; i++) {
|
367
|
-
const angle = randomInRange(0, spread) * (Math.PI / 180);
|
368
|
-
const velocity = randomInRange(startVelocity * 0.7, startVelocity * 1.3);
|
369
|
-
particles.push({
|
370
|
-
id: generateId(),
|
371
|
-
x: origin.x,
|
372
|
-
y: origin.y,
|
373
|
-
vx: Math.sin(angle) * velocity,
|
374
|
-
vy: -Math.abs(Math.cos(angle) * velocity * 0.5), // Mostly horizontal movement
|
375
|
-
life: config.lifetime || 60, // Quick flashes
|
376
|
-
opacity: 1,
|
377
|
-
size: randomInRange(elementSize * 0.5, elementSize * 1.5),
|
378
|
-
rotation: randomInRange(0, 360),
|
379
|
-
color: colors[Math.floor(Math.random() * colors.length)] || colors[0] || '#ffffff',
|
380
|
-
});
|
381
|
-
}
|
382
|
-
return particles;
|
383
|
-
};
|
384
|
-
const renderLightningParticle = (particle) => {
|
385
|
-
// Create zigzag pattern based on particle life
|
386
|
-
const zigzagOffset = Math.sin(particle.life * 0.5) * 10;
|
387
|
-
return (React.createElement("div", { key: particle.id, style: {
|
388
|
-
width: `${particle.size}px`,
|
389
|
-
height: `${particle.size * 0.3}px`,
|
390
|
-
position: 'relative',
|
391
|
-
filter: `blur(0.5px) brightness(2)`,
|
392
|
-
transform: `translateX(${zigzagOffset}px) rotate(${particle.rotation}deg)`,
|
393
|
-
} },
|
394
|
-
React.createElement("div", { style: {
|
395
|
-
position: 'absolute',
|
396
|
-
width: '100%',
|
397
|
-
height: '100%',
|
398
|
-
background: particle.color,
|
399
|
-
clipPath: 'polygon(0% 0%, 60% 0%, 40% 45%, 100% 45%, 0% 100%, 40% 55%, 20% 55%, 35% 100%)',
|
400
|
-
boxShadow: `
|
401
|
-
0 0 10px ${particle.color},
|
402
|
-
0 0 20px ${particle.color},
|
403
|
-
0 0 30px ${particle.color}
|
404
|
-
`,
|
405
|
-
} }),
|
406
|
-
React.createElement("div", { style: {
|
407
|
-
position: 'absolute',
|
408
|
-
top: '-50%',
|
409
|
-
left: '-50%',
|
410
|
-
width: '200%',
|
411
|
-
height: '200%',
|
412
|
-
background: `radial-gradient(circle, ${particle.color}88 0%, transparent 70%)`,
|
413
|
-
animation: `electricPulse ${randomInRange(100, 200)}ms infinite`,
|
414
|
-
} })));
|
415
|
-
};
|
416
|
-
|
417
362
|
const petalColors = ['#FFB6C1', '#FFC0CB', '#FF69B4', '#FF1493', '#FFF0F5'];
|
418
363
|
const createPetalParticles = (origin, config) => {
|
419
364
|
const { particleCount = 40, spread = 100, startVelocity = 8, colors = petalColors, elementSize = 20 } = config;
|
@@ -679,84 +624,6 @@ const renderPaintParticle = (particle) => {
|
|
679
624
|
} }))));
|
680
625
|
};
|
681
626
|
|
682
|
-
const musicColors = ['#FF006E', '#8338EC', '#3A86FF', '#FB5607', '#FFBE0B'];
|
683
|
-
const createMusicParticles = (origin, config) => {
|
684
|
-
const { particleCount = 20, spread = 100, startVelocity = 8, colors = musicColors, elementSize = 25 } = config;
|
685
|
-
const particles = [];
|
686
|
-
const notes = ['♪', '♫', '♬', '♩', '♭', '♯'];
|
687
|
-
for (let i = 0; i < particleCount; i++) {
|
688
|
-
const angle = randomInRange(-spread / 2, spread / 2) * (Math.PI / 180);
|
689
|
-
const velocity = randomInRange(startVelocity * 0.5, startVelocity);
|
690
|
-
particles.push({
|
691
|
-
id: generateId(),
|
692
|
-
x: origin.x + randomInRange(-20, 20),
|
693
|
-
y: origin.y,
|
694
|
-
vx: Math.sin(angle) * velocity * 0.3,
|
695
|
-
vy: -Math.abs(Math.cos(angle)) * velocity * 0.5, // Always go up slowly
|
696
|
-
life: config.lifetime || 200,
|
697
|
-
opacity: 1,
|
698
|
-
size: randomInRange(elementSize * 0.8, elementSize * 1.2),
|
699
|
-
rotation: i % notes.length, // Store which note to use
|
700
|
-
color: colors[Math.floor(Math.random() * colors.length)] || colors[0] || '#ffffff',
|
701
|
-
});
|
702
|
-
}
|
703
|
-
return particles;
|
704
|
-
};
|
705
|
-
const renderMusicParticle = (particle) => {
|
706
|
-
const notes = ['♪', '♫', '♬', '♩', '♭', '♯'];
|
707
|
-
const note = notes[Math.floor(particle.rotation)];
|
708
|
-
// Wave motion as notes float up
|
709
|
-
const waveX = Math.sin(particle.life * 0.05) * 20;
|
710
|
-
const wobble = Math.sin(particle.life * 0.1) * 10;
|
711
|
-
// Simple fade based on particle life
|
712
|
-
// Assume default lifetime of 300 if not set
|
713
|
-
const totalLife = 300;
|
714
|
-
const age = totalLife - particle.life; // How old the particle is
|
715
|
-
// Fade in during first 20 frames
|
716
|
-
const fadeIn = age < 20 ? age / 20 : 1;
|
717
|
-
// Fade out during last 50 frames
|
718
|
-
const fadeOut = particle.life < 50 ? particle.life / 50 : 1;
|
719
|
-
const opacity = Math.min(fadeIn, fadeOut) * particle.opacity;
|
720
|
-
return (React.createElement("div", { key: particle.id, style: {
|
721
|
-
fontSize: `${particle.size}px`,
|
722
|
-
fontWeight: 'bold',
|
723
|
-
position: 'relative',
|
724
|
-
transform: `
|
725
|
-
translateX(${waveX}px)
|
726
|
-
rotate(${wobble}deg)
|
727
|
-
scale(${0.8 + opacity * 0.2})
|
728
|
-
`,
|
729
|
-
color: particle.color,
|
730
|
-
opacity,
|
731
|
-
textShadow: `
|
732
|
-
0 0 10px ${particle.color}88,
|
733
|
-
0 0 20px ${particle.color}44,
|
734
|
-
2px 2px 3px rgba(0,0,0,0.3)
|
735
|
-
`,
|
736
|
-
transition: 'transform 0.3s ease',
|
737
|
-
userSelect: 'none',
|
738
|
-
} },
|
739
|
-
note,
|
740
|
-
React.createElement("div", { style: {
|
741
|
-
position: 'absolute',
|
742
|
-
top: '40%',
|
743
|
-
left: '-20%',
|
744
|
-
width: '140%',
|
745
|
-
height: '1px',
|
746
|
-
background: `linear-gradient(90deg, transparent, ${particle.color}33, transparent)`,
|
747
|
-
opacity: opacity * 0.5,
|
748
|
-
} }),
|
749
|
-
React.createElement("div", { style: {
|
750
|
-
position: 'absolute',
|
751
|
-
top: '60%',
|
752
|
-
left: '-20%',
|
753
|
-
width: '140%',
|
754
|
-
height: '1px',
|
755
|
-
background: `linear-gradient(90deg, transparent, ${particle.color}33, transparent)`,
|
756
|
-
opacity: opacity * 0.3,
|
757
|
-
} })));
|
758
|
-
};
|
759
|
-
|
760
627
|
const balloonColors = ['#FF006E', '#FB5607', '#FFBE0B', '#8338EC', '#3A86FF', '#06FFB4', '#FF4081'];
|
761
628
|
const createBalloonParticles = (origin, config) => {
|
762
629
|
const { particleCount = 15, spread = 80, startVelocity = 10, colors = balloonColors, elementSize = 35 } = config;
|
@@ -938,88 +805,6 @@ const renderGalaxyParticle = (particle) => {
|
|
938
805
|
} }))));
|
939
806
|
};
|
940
807
|
|
941
|
-
const matrixChars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン';
|
942
|
-
const createMatrixParticles = (origin, config) => {
|
943
|
-
const { particleCount = 50, elementSize = 300 } = config;
|
944
|
-
const particles = [];
|
945
|
-
const columns = Math.floor(elementSize / 20);
|
946
|
-
for (let i = 0; i < columns; i++) {
|
947
|
-
const columnX = origin.x - elementSize / 2 + (i / columns) * elementSize;
|
948
|
-
const columnParticles = Math.floor(Math.random() * 15) + 10;
|
949
|
-
for (let j = 0; j < columnParticles; j++) {
|
950
|
-
const charIndex = Math.floor(Math.random() * matrixChars.length);
|
951
|
-
const speed = randomInRange(80, 120);
|
952
|
-
particles.push({
|
953
|
-
id: generateId(),
|
954
|
-
x: columnX + randomInRange(-10, 10),
|
955
|
-
y: origin.y - elementSize / 2 - j * 25 - randomInRange(0, 100),
|
956
|
-
vx: columnParticles, // Store columnHeight in vx (since we don't use horizontal movement)
|
957
|
-
vy: speed,
|
958
|
-
life: config.lifetime || 150,
|
959
|
-
opacity: 1,
|
960
|
-
size: 20 + (j * 0.1), // Store fadeDelay as decimal part
|
961
|
-
rotation: charIndex + (columnParticles * 1000), // Store charIndex and columnHeight
|
962
|
-
color: '#00ff00',
|
963
|
-
});
|
964
|
-
}
|
965
|
-
}
|
966
|
-
return particles.slice(0, particleCount);
|
967
|
-
};
|
968
|
-
const renderMatrixParticle = (particle) => {
|
969
|
-
// Extract stored values
|
970
|
-
const charIndex = Math.floor(particle.rotation % 1000);
|
971
|
-
const columnHeight = Math.floor(particle.rotation / 1000);
|
972
|
-
const fadeDelay = (particle.size - Math.floor(particle.size));
|
973
|
-
const character = matrixChars[charIndex] || matrixChars[0];
|
974
|
-
const brightness = 1 - (fadeDelay / columnHeight) * 0.5;
|
975
|
-
return (React.createElement("div", { key: particle.id, style: {
|
976
|
-
fontSize: '20px',
|
977
|
-
fontFamily: 'monospace',
|
978
|
-
fontWeight: 'bold',
|
979
|
-
color: `rgba(${0}, ${255 * brightness}, ${0}, ${particle.opacity})`,
|
980
|
-
textShadow: `0 0 10px rgba(0, ${255 * brightness}, 0, ${particle.opacity * 0.8})`,
|
981
|
-
userSelect: 'none',
|
982
|
-
} }, character));
|
983
|
-
};
|
984
|
-
|
985
|
-
const pixelColors = ['#FF0000', '#00FF00', '#0000FF', '#FFFF00', '#FF00FF', '#00FFFF', '#FFA500', '#FF1493'];
|
986
|
-
const createPixelParticles = (origin, config) => {
|
987
|
-
const { particleCount = 30, colors = pixelColors, elementSize = 20 } = config;
|
988
|
-
const particles = [];
|
989
|
-
const gridSize = Math.floor(Math.sqrt(particleCount));
|
990
|
-
const spacing = 30;
|
991
|
-
for (let i = 0; i < gridSize; i++) {
|
992
|
-
for (let j = 0; j < gridSize; j++) {
|
993
|
-
const targetX = origin.x + (i - gridSize / 2) * spacing;
|
994
|
-
const targetY = origin.y + (j - gridSize / 2) * spacing;
|
995
|
-
const angle = randomInRange(0, 360);
|
996
|
-
const velocity = randomInRange(150, 300);
|
997
|
-
particles.push({
|
998
|
-
id: generateId(),
|
999
|
-
x: targetX,
|
1000
|
-
y: targetY,
|
1001
|
-
vx: Math.cos(degreesToRadians(angle)) * velocity,
|
1002
|
-
vy: Math.sin(degreesToRadians(angle)) * velocity,
|
1003
|
-
life: config.lifetime || 150,
|
1004
|
-
opacity: 1,
|
1005
|
-
size: randomInRange(elementSize * 0.6, elementSize),
|
1006
|
-
// Store targetX offset in rotation (from -500 to 500, add 1000 to make positive)
|
1007
|
-
rotation: ((targetX - origin.x) + 500) + ((targetY - origin.y) + 500) * 1000,
|
1008
|
-
color: getRandomColor(colors),
|
1009
|
-
});
|
1010
|
-
}
|
1011
|
-
}
|
1012
|
-
return particles.slice(0, particleCount);
|
1013
|
-
};
|
1014
|
-
const renderPixelParticle = (particle) => {
|
1015
|
-
return (React.createElement("div", { key: particle.id, style: {
|
1016
|
-
width: `${particle.size}px`,
|
1017
|
-
height: `${particle.size}px`,
|
1018
|
-
backgroundColor: particle.color,
|
1019
|
-
boxShadow: `0 0 ${particle.size / 2}px ${particle.color}`,
|
1020
|
-
} }));
|
1021
|
-
};
|
1022
|
-
|
1023
808
|
const createGlitchParticles = (origin, config) => {
|
1024
809
|
const { particleCount = 20, elementSize = 200 } = config;
|
1025
810
|
const particles = [];
|
@@ -1082,119 +867,9 @@ const renderGlitchParticle = (particle) => {
|
|
1082
867
|
} }));
|
1083
868
|
};
|
1084
869
|
|
1085
|
-
const
|
1086
|
-
const faces = ['⚀', '⚁', '⚂', '⚃', '⚄', '⚅'];
|
1087
|
-
return faces[value - 1] || '⚀';
|
1088
|
-
};
|
1089
|
-
const createDiceParticles = (origin, config) => {
|
1090
|
-
const { particleCount = 8, startVelocity = 25, elementSize = 40 } = config;
|
1091
|
-
const particles = [];
|
1092
|
-
for (let i = 0; i < particleCount; i++) {
|
1093
|
-
const angle = randomInRange(0, 360);
|
1094
|
-
const velocity = randomInRange(startVelocity * 0.5, startVelocity);
|
1095
|
-
const diceValue = Math.floor(randomInRange(1, 7));
|
1096
|
-
particles.push({
|
1097
|
-
id: generateId(),
|
1098
|
-
x: origin.x,
|
1099
|
-
y: origin.y,
|
1100
|
-
vx: Math.cos(degreesToRadians(angle)) * velocity,
|
1101
|
-
vy: Math.sin(degreesToRadians(angle)) * velocity - 30,
|
1102
|
-
life: config.lifetime || 150,
|
1103
|
-
opacity: 1,
|
1104
|
-
size: randomInRange(elementSize * 0.8, elementSize * 1.2),
|
1105
|
-
// Store dice value (1-6) in lower bits, and rotation angles in upper bits
|
1106
|
-
rotation: diceValue + (Math.floor(randomInRange(0, 360)) * 10),
|
1107
|
-
color: '#ffffff',
|
1108
|
-
});
|
1109
|
-
}
|
1110
|
-
return particles;
|
1111
|
-
};
|
1112
|
-
const renderDiceParticle = (particle) => {
|
1113
|
-
const diceValue = particle.rotation % 10;
|
1114
|
-
const rotationAngle = Math.floor(particle.rotation / 10);
|
1115
|
-
return (React.createElement("div", { key: particle.id, style: {
|
1116
|
-
width: `${particle.size}px`,
|
1117
|
-
height: `${particle.size}px`,
|
1118
|
-
fontSize: `${particle.size * 0.8}px`,
|
1119
|
-
display: 'flex',
|
1120
|
-
alignItems: 'center',
|
1121
|
-
justifyContent: 'center',
|
1122
|
-
backgroundColor: '#fff',
|
1123
|
-
color: '#000',
|
1124
|
-
borderRadius: `${particle.size * 0.2}px`,
|
1125
|
-
transform: `rotate(${rotationAngle}deg)`,
|
1126
|
-
transformStyle: 'preserve-3d',
|
1127
|
-
boxShadow: '0 4px 8px rgba(0,0,0,0.3), inset 0 1px 0 rgba(255,255,255,0.5)',
|
1128
|
-
border: '2px solid #333',
|
1129
|
-
fontWeight: 'bold',
|
1130
|
-
} }, getDiceFace(diceValue)));
|
1131
|
-
};
|
1132
|
-
|
1133
|
-
const levelUpTexts = ['+1', '+10', '+100', 'XP', '+XP', 'LEVEL UP!', 'CRITICAL!', 'COMBO!', 'PERFECT!'];
|
1134
|
-
const levelUpColors = [
|
1135
|
-
{ text: '#FFD700', glow: '#FFA500' }, // Gold
|
1136
|
-
{ text: '#00FF00', glow: '#00AA00' }, // Green
|
1137
|
-
{ text: '#00FFFF', glow: '#0088FF' }, // Cyan
|
1138
|
-
{ text: '#FF00FF', glow: '#AA00AA' }, // Magenta
|
1139
|
-
{ text: '#FFFF00', glow: '#FFAA00' }, // Yellow
|
1140
|
-
];
|
1141
|
-
const createLevelUpParticles = (origin, config) => {
|
1142
|
-
const { particleCount = 10, startVelocity = 20, elementSize = 30 } = config;
|
1143
|
-
const particles = [];
|
1144
|
-
for (let i = 0; i < particleCount; i++) {
|
1145
|
-
const angle = randomInRange(-45, 45);
|
1146
|
-
const velocity = randomInRange(startVelocity * 0.5, startVelocity * 1.5);
|
1147
|
-
const colorSetIndex = Math.floor(Math.random() * levelUpColors.length);
|
1148
|
-
const colorSet = levelUpColors[colorSetIndex] || levelUpColors[0];
|
1149
|
-
const textIndex = Math.floor(Math.random() * levelUpTexts.length);
|
1150
|
-
const text = levelUpTexts[textIndex];
|
1151
|
-
const isMainText = text === 'LEVEL UP!' || text === 'CRITICAL!';
|
1152
|
-
const fontSize = isMainText ? randomInRange(elementSize * 1.3, elementSize * 2) : randomInRange(elementSize * 0.7, elementSize * 1.2);
|
1153
|
-
particles.push({
|
1154
|
-
id: generateId(),
|
1155
|
-
x: origin.x,
|
1156
|
-
y: origin.y,
|
1157
|
-
vx: Math.sin(degreesToRadians(angle)) * velocity,
|
1158
|
-
vy: -Math.cos(degreesToRadians(angle)) * velocity - 10,
|
1159
|
-
life: config.lifetime || 150,
|
1160
|
-
opacity: 1,
|
1161
|
-
size: fontSize, // Store fontSize in size
|
1162
|
-
// Store textIndex (0-8) + colorSetIndex (0-4) * 10 + delay (0-50) * 100
|
1163
|
-
rotation: textIndex + (colorSetIndex * 10) + (Math.floor(i * 5) * 100),
|
1164
|
-
color: colorSet.text,
|
1165
|
-
});
|
1166
|
-
}
|
1167
|
-
return particles;
|
1168
|
-
};
|
1169
|
-
const renderLevelUpParticle = (particle) => {
|
1170
|
-
// Extract encoded values
|
1171
|
-
const textIndex = particle.rotation % 10;
|
1172
|
-
const colorSetIndex = Math.floor((particle.rotation % 100) / 10);
|
1173
|
-
const delay = Math.floor(particle.rotation / 100) / 100;
|
1174
|
-
const text = levelUpTexts[textIndex] || levelUpTexts[0];
|
1175
|
-
const colorSet = levelUpColors[colorSetIndex] || levelUpColors[0];
|
1176
|
-
return (React.createElement("div", { key: particle.id, style: {
|
1177
|
-
fontSize: `${particle.size}px`,
|
1178
|
-
fontWeight: 'bold',
|
1179
|
-
fontFamily: 'Arial, sans-serif',
|
1180
|
-
color: particle.color,
|
1181
|
-
textShadow: `
|
1182
|
-
0 0 10px ${colorSet.glow},
|
1183
|
-
0 0 20px ${colorSet.glow},
|
1184
|
-
0 0 30px ${particle.color},
|
1185
|
-
0 2px 4px rgba(0,0,0,0.5)
|
1186
|
-
`,
|
1187
|
-
letterSpacing: '2px',
|
1188
|
-
textTransform: 'uppercase',
|
1189
|
-
whiteSpace: 'nowrap',
|
1190
|
-
userSelect: 'none',
|
1191
|
-
animationDelay: `${delay}s`,
|
1192
|
-
} }, text));
|
1193
|
-
};
|
1194
|
-
|
1195
|
-
const defaultColors$e = ['#9C27B0', '#E91E63', '#FF00FF', '#00FFFF', '#FFD700', '#FF69B4', '#DA70D6', '#9370DB'];
|
870
|
+
const defaultColors$2 = ['#9C27B0', '#E91E63', '#FF00FF', '#00FFFF', '#FFD700', '#FF69B4', '#DA70D6', '#9370DB'];
|
1196
871
|
const createMagicDustParticles = (origin, config) => {
|
1197
|
-
const { particleCount = 40, startVelocity = 8, colors = defaultColors$
|
872
|
+
const { particleCount = 40, startVelocity = 8, colors = defaultColors$2, elementSize = 12 } = config;
|
1198
873
|
const particles = [];
|
1199
874
|
for (let i = 0; i < particleCount; i++) {
|
1200
875
|
// Create particles in a circular pattern with some randomness
|
@@ -1265,97 +940,9 @@ const renderMagicDustParticle = (particle) => {
|
|
1265
940
|
} }))));
|
1266
941
|
};
|
1267
942
|
|
1268
|
-
const defaultColors$
|
1269
|
-
const createGhostParticles = (origin, config) => {
|
1270
|
-
const { particleCount = 8, startVelocity = 5, colors = defaultColors$d, elementSize = 30 } = config;
|
1271
|
-
const particles = [];
|
1272
|
-
for (let i = 0; i < particleCount; i++) {
|
1273
|
-
// Ghosts float upward with slight horizontal movement
|
1274
|
-
const angle = randomInRange(250, 290); // Mostly upward
|
1275
|
-
const velocity = randomInRange(startVelocity * 0.5, startVelocity);
|
1276
|
-
const color = getRandomColor(colors);
|
1277
|
-
particles.push({
|
1278
|
-
id: generateId(),
|
1279
|
-
x: origin.x + randomInRange(-50, 50),
|
1280
|
-
y: origin.y + randomInRange(-20, 20),
|
1281
|
-
vx: Math.cos(degreesToRadians(angle)) * velocity,
|
1282
|
-
vy: Math.sin(degreesToRadians(angle)) * velocity,
|
1283
|
-
life: config.lifetime || 200,
|
1284
|
-
opacity: randomInRange(0.5, 0.8),
|
1285
|
-
size: randomInRange(elementSize * 0.8, elementSize * 1.2),
|
1286
|
-
rotation: randomInRange(-15, 15),
|
1287
|
-
color,
|
1288
|
-
});
|
1289
|
-
}
|
1290
|
-
return particles;
|
1291
|
-
};
|
1292
|
-
const renderGhostParticle = (particle) => {
|
1293
|
-
// Calculate wave effect for tail
|
1294
|
-
const waveOffset = Math.sin(Date.now() * 0.003 + particle.x * 0.01) * 3;
|
1295
|
-
return (React.createElement("div", { key: particle.id, style: {
|
1296
|
-
width: `${particle.size}px`,
|
1297
|
-
height: `${particle.size * 1.4}px`,
|
1298
|
-
position: 'relative',
|
1299
|
-
transform: `rotate(${particle.rotation}deg)`,
|
1300
|
-
} },
|
1301
|
-
React.createElement("div", { style: {
|
1302
|
-
position: 'absolute',
|
1303
|
-
width: '100%',
|
1304
|
-
height: '70%',
|
1305
|
-
backgroundColor: particle.color,
|
1306
|
-
borderRadius: '50% 50% 0 0',
|
1307
|
-
boxShadow: `0 0 20px rgba(255, 255, 255, 0.5), inset 0 0 10px rgba(0, 0, 0, 0.1)`,
|
1308
|
-
} }),
|
1309
|
-
React.createElement("div", { style: {
|
1310
|
-
position: 'absolute',
|
1311
|
-
bottom: 0,
|
1312
|
-
width: '100%',
|
1313
|
-
height: '40%',
|
1314
|
-
backgroundColor: particle.color,
|
1315
|
-
clipPath: `polygon(
|
1316
|
-
0 0,
|
1317
|
-
100% 0,
|
1318
|
-
100% 60%,
|
1319
|
-
${75 + waveOffset}% 80%,
|
1320
|
-
${50 - waveOffset}% 100%,
|
1321
|
-
${25 + waveOffset}% 80%,
|
1322
|
-
0 60%
|
1323
|
-
)`,
|
1324
|
-
} }),
|
1325
|
-
React.createElement("div", { style: {
|
1326
|
-
position: 'absolute',
|
1327
|
-
top: '30%',
|
1328
|
-
left: '25%',
|
1329
|
-
width: '15%',
|
1330
|
-
height: '15%',
|
1331
|
-
backgroundColor: '#000',
|
1332
|
-
borderRadius: '50%',
|
1333
|
-
} }),
|
1334
|
-
React.createElement("div", { style: {
|
1335
|
-
position: 'absolute',
|
1336
|
-
top: '30%',
|
1337
|
-
right: '25%',
|
1338
|
-
width: '15%',
|
1339
|
-
height: '15%',
|
1340
|
-
backgroundColor: '#000',
|
1341
|
-
borderRadius: '50%',
|
1342
|
-
} }),
|
1343
|
-
React.createElement("div", { style: {
|
1344
|
-
position: 'absolute',
|
1345
|
-
top: '45%',
|
1346
|
-
left: '50%',
|
1347
|
-
transform: 'translateX(-50%)',
|
1348
|
-
width: '25%',
|
1349
|
-
height: '15%',
|
1350
|
-
border: '2px solid #000',
|
1351
|
-
borderTop: 'none',
|
1352
|
-
borderRadius: '0 0 50% 50%',
|
1353
|
-
} })));
|
1354
|
-
};
|
1355
|
-
|
1356
|
-
const defaultColors$c = ['#FF1493', '#00CED1', '#FFD700', '#FF69B4', '#7B68EE', '#00FA9A', '#FF6347', '#4169E1'];
|
943
|
+
const defaultColors$1 = ['#FF1493', '#00CED1', '#FFD700', '#FF69B4', '#7B68EE', '#00FA9A', '#FF6347', '#4169E1'];
|
1357
944
|
const createCrystalParticles = (origin, config) => {
|
1358
|
-
const { particleCount = 15, startVelocity = 15, colors = defaultColors$
|
945
|
+
const { particleCount = 15, startVelocity = 15, colors = defaultColors$1, elementSize = 25 } = config;
|
1359
946
|
const particles = [];
|
1360
947
|
for (let i = 0; i < particleCount; i++) {
|
1361
948
|
// Crystals explode outward and fall with gravity
|
@@ -1427,762 +1014,61 @@ const renderCrystalParticle = (particle) => {
|
|
1427
1014
|
} })));
|
1428
1015
|
};
|
1429
1016
|
|
1430
|
-
const defaultColors
|
1431
|
-
const
|
1432
|
-
const { particleCount =
|
1017
|
+
const defaultColors = ['#D2691E', '#CD853F', '#8B4513', '#A0522D', '#FF8C00', '#FF6347'];
|
1018
|
+
const createLeafParticles = (origin, config) => {
|
1019
|
+
const { particleCount = 10, colors = defaultColors, elementSize = 25 } = config;
|
1433
1020
|
const particles = [];
|
1434
1021
|
for (let i = 0; i < particleCount; i++) {
|
1435
|
-
// Dragons fly in various directions with swooping motion
|
1436
|
-
const angle = randomInRange(0, 360);
|
1437
|
-
const velocity = randomInRange(startVelocity * 0.7, startVelocity);
|
1438
|
-
const color = getRandomColor(colors);
|
1439
1022
|
particles.push({
|
1440
1023
|
id: generateId(),
|
1441
|
-
x: origin.x + randomInRange(-
|
1442
|
-
y: origin.y + randomInRange(-
|
1443
|
-
vx:
|
1444
|
-
vy:
|
1445
|
-
life: config.lifetime ||
|
1024
|
+
x: origin.x + randomInRange(-100, 100),
|
1025
|
+
y: origin.y + randomInRange(-50, 0),
|
1026
|
+
vx: randomInRange(-1, 1),
|
1027
|
+
vy: randomInRange(0.5, 2),
|
1028
|
+
life: config.lifetime || 300,
|
1446
1029
|
opacity: 1,
|
1447
|
-
size: randomInRange(elementSize * 0.
|
1448
|
-
rotation
|
1449
|
-
|
1030
|
+
size: randomInRange(elementSize * 0.6, elementSize),
|
1031
|
+
// Encode tumble phase (0-360), sway phase (0-360), and sway amount (20-40) + rotation speed (-3 to 3)
|
1032
|
+
rotation: Math.floor(randomInRange(0, 360)) +
|
1033
|
+
(Math.floor(randomInRange(0, 360)) * 1000) +
|
1034
|
+
(Math.floor(randomInRange(20, 40)) * 1000000) +
|
1035
|
+
((Math.floor(randomInRange(-3, 3)) + 3) * 100000000),
|
1036
|
+
color: getRandomColor(colors),
|
1450
1037
|
});
|
1451
1038
|
}
|
1452
1039
|
return particles;
|
1453
1040
|
};
|
1454
|
-
const
|
1455
|
-
//
|
1456
|
-
const
|
1457
|
-
|
1458
|
-
const
|
1041
|
+
const renderLeafParticle = (particle) => {
|
1042
|
+
// Extract encoded values
|
1043
|
+
const tumblePhase = particle.rotation % 1000;
|
1044
|
+
const swayPhase = Math.floor((particle.rotation % 1000000) / 1000);
|
1045
|
+
const swayAmount = Math.floor((particle.rotation % 100000000) / 1000000);
|
1046
|
+
const rotationSpeed = (Math.floor(particle.rotation / 100000000) - 3);
|
1047
|
+
// Calculate tumbling and swaying
|
1048
|
+
const tumble = Math.sin((Date.now() * 0.002 + tumblePhase) * Math.PI / 180) * 30;
|
1049
|
+
const swayX = Math.sin((Date.now() * 0.001 + swayPhase) * Math.PI / 180) * swayAmount;
|
1050
|
+
const rotation = (Date.now() * rotationSpeed * 0.01 + tumble) % 360;
|
1459
1051
|
return (React.createElement("div", { key: particle.id, style: {
|
1460
1052
|
width: `${particle.size}px`,
|
1461
1053
|
height: `${particle.size}px`,
|
1462
1054
|
position: 'relative',
|
1463
|
-
transform: `rotate(${
|
1055
|
+
transform: `translateX(${swayX}px) rotate(${rotation}deg)`,
|
1464
1056
|
} },
|
1465
|
-
React.createElement("
|
1466
|
-
position: 'absolute',
|
1467
|
-
width: '60%',
|
1468
|
-
height: '40%',
|
1469
|
-
top: '30%',
|
1470
|
-
left: '20%',
|
1471
|
-
backgroundColor: particle.color,
|
1472
|
-
borderRadius: '50% 40% 40% 50%',
|
1473
|
-
boxShadow: `0 2px 10px rgba(0, 0, 0, 0.3)`,
|
1474
|
-
} }),
|
1475
|
-
React.createElement("div", { style: {
|
1057
|
+
React.createElement("svg", { width: particle.size, height: particle.size, viewBox: `-${particle.size / 2} -${particle.size / 2} ${particle.size} ${particle.size}`, style: {
|
1476
1058
|
position: 'absolute',
|
1477
|
-
|
1478
|
-
|
1479
|
-
top: '25%',
|
1480
|
-
right: '15%',
|
1481
|
-
backgroundColor: particle.color,
|
1482
|
-
borderRadius: '40% 50% 50% 40%',
|
1483
|
-
transform: 'rotate(-10deg)',
|
1059
|
+
top: 0,
|
1060
|
+
left: 0,
|
1484
1061
|
} },
|
1485
|
-
React.createElement("
|
1486
|
-
|
1487
|
-
|
1488
|
-
|
1489
|
-
|
1490
|
-
|
1491
|
-
|
1492
|
-
|
1493
|
-
|
1494
|
-
|
1495
|
-
React.createElement("div", { style: {
|
1496
|
-
position: 'absolute',
|
1497
|
-
width: '40%',
|
1498
|
-
height: '50%',
|
1499
|
-
top: '15%',
|
1500
|
-
left: '30%',
|
1501
|
-
backgroundColor: `${particle.color}CC`,
|
1502
|
-
clipPath: 'polygon(0% 100%, 50% 0%, 100% 30%, 90% 60%, 100% 90%, 50% 100%)',
|
1503
|
-
transform: `rotateX(${wingFlap}deg)`,
|
1504
|
-
transformOrigin: 'bottom center',
|
1505
|
-
} }),
|
1506
|
-
React.createElement("div", { style: {
|
1507
|
-
position: 'absolute',
|
1508
|
-
width: '40%',
|
1509
|
-
height: '50%',
|
1510
|
-
top: '35%',
|
1511
|
-
left: '30%',
|
1512
|
-
backgroundColor: `${particle.color}AA`,
|
1513
|
-
clipPath: 'polygon(0% 0%, 50% 0%, 100% 30%, 90% 60%, 100% 90%, 50% 100%)',
|
1514
|
-
transform: `rotateX(${-wingFlap}deg)`,
|
1515
|
-
transformOrigin: 'top center',
|
1516
|
-
} }),
|
1517
|
-
React.createElement("div", { style: {
|
1518
|
-
position: 'absolute',
|
1519
|
-
width: '40%',
|
1520
|
-
height: '15%',
|
1521
|
-
top: '35%',
|
1522
|
-
left: '5%',
|
1523
|
-
backgroundColor: particle.color,
|
1524
|
-
clipPath: 'polygon(0% 50%, 70% 0%, 100% 20%, 100% 80%, 70% 100%, 0% 50%)',
|
1525
|
-
} }),
|
1526
|
-
React.createElement("div", { style: {
|
1527
|
-
position: 'absolute',
|
1528
|
-
width: '30%',
|
1529
|
-
height: '20%',
|
1530
|
-
top: '35%',
|
1531
|
-
right: '5%',
|
1532
|
-
background: `radial-gradient(ellipse, #FFD700 0%, #FF4500 50%, transparent 100%)`,
|
1533
|
-
transform: `scale(${0.8 + firePulse * 0.4})`,
|
1534
|
-
opacity: 0.8 + firePulse * 0.2,
|
1535
|
-
filter: 'blur(1px)',
|
1536
|
-
} }),
|
1537
|
-
React.createElement("div", { style: {
|
1538
|
-
position: 'absolute',
|
1539
|
-
width: '25%',
|
1540
|
-
height: '15%',
|
1541
|
-
top: '37%',
|
1542
|
-
right: '0%',
|
1543
|
-
background: `radial-gradient(ellipse, #FFA500 0%, #FF6347 50%, transparent 100%)`,
|
1544
|
-
transform: `scale(${0.6 + firePulse * 0.6})`,
|
1545
|
-
opacity: 0.6 + firePulse * 0.4,
|
1546
|
-
filter: 'blur(2px)',
|
1547
|
-
} })));
|
1548
|
-
};
|
1549
|
-
|
1550
|
-
const defaultColors$a = ['#9C27B0', '#673AB7', '#3F51B5', '#00BCD4', '#4CAF50', '#FFEB3B', '#FF9800'];
|
1551
|
-
// Ancient rune symbols
|
1552
|
-
const runeSymbols = [
|
1553
|
-
'ᚠ', 'ᚢ', 'ᚦ', 'ᚨ', 'ᚱ', 'ᚲ', 'ᚷ', 'ᚹ', 'ᚺ', 'ᚾ', 'ᛁ', 'ᛃ', 'ᛇ', 'ᛈ', 'ᛉ', 'ᛋ', 'ᛏ', 'ᛒ', 'ᛖ', 'ᛗ', 'ᛚ', 'ᛜ', 'ᛞ', 'ᛟ'
|
1554
|
-
];
|
1555
|
-
const createRuneParticles = (origin, config) => {
|
1556
|
-
const { particleCount = 12, startVelocity = 6, colors = defaultColors$a, elementSize = 35 } = config;
|
1557
|
-
const particles = [];
|
1558
|
-
for (let i = 0; i < particleCount; i++) {
|
1559
|
-
// Runes float upward in a mystical pattern
|
1560
|
-
const angle = randomInRange(250, 290); // Mostly upward
|
1561
|
-
const velocity = randomInRange(startVelocity * 0.3, startVelocity * 0.7);
|
1562
|
-
const color = getRandomColor(colors);
|
1563
|
-
// Create circular spawn pattern
|
1564
|
-
const spawnAngle = (i / particleCount) * 360;
|
1565
|
-
const spawnRadius = randomInRange(20, 60);
|
1566
|
-
const runeIndex = Math.floor(Math.random() * runeSymbols.length);
|
1567
|
-
particles.push({
|
1568
|
-
id: generateId(),
|
1569
|
-
x: origin.x + Math.cos(degreesToRadians(spawnAngle)) * spawnRadius,
|
1570
|
-
y: origin.y + Math.sin(degreesToRadians(spawnAngle)) * spawnRadius,
|
1571
|
-
vx: Math.cos(degreesToRadians(angle)) * velocity + randomInRange(-1, 1),
|
1572
|
-
vy: Math.sin(degreesToRadians(angle)) * velocity,
|
1573
|
-
life: config.lifetime || 160,
|
1574
|
-
opacity: 0,
|
1575
|
-
size: randomInRange(elementSize * 0.8, elementSize * 1.2),
|
1576
|
-
// Store runeIndex in lower bits of rotation, keep rotation angle in upper bits
|
1577
|
-
rotation: runeIndex + (Math.floor(randomInRange(0, 360)) * 100),
|
1578
|
-
color,
|
1579
|
-
});
|
1580
|
-
}
|
1581
|
-
return particles;
|
1582
|
-
};
|
1583
|
-
const renderRuneParticle = (particle) => {
|
1584
|
-
// Extract rune index and rotation from encoded value
|
1585
|
-
const runeIndex = particle.rotation % 100;
|
1586
|
-
const rotationAngle = Math.floor(particle.rotation / 100);
|
1587
|
-
const runeSymbol = runeSymbols[runeIndex] || runeSymbols[0];
|
1588
|
-
// Calculate pulsing glow effect
|
1589
|
-
const glowIntensity = (Math.sin(Date.now() * 0.003 + particle.x * 0.01) + 1) / 2;
|
1590
|
-
// Fade in and out based on life
|
1591
|
-
const fadeProgress = particle.life > 120 ? (160 - particle.life) / 40 : particle.life < 40 ? particle.life / 40 : 1;
|
1592
|
-
return (React.createElement("div", { key: particle.id, style: {
|
1593
|
-
width: `${particle.size}px`,
|
1594
|
-
height: `${particle.size}px`,
|
1595
|
-
position: 'relative',
|
1596
|
-
transform: `rotate(${rotationAngle}deg)`,
|
1597
|
-
opacity: fadeProgress,
|
1598
|
-
} },
|
1599
|
-
React.createElement("div", { style: {
|
1600
|
-
position: 'absolute',
|
1601
|
-
width: '100%',
|
1602
|
-
height: '100%',
|
1603
|
-
borderRadius: '50%',
|
1604
|
-
background: `radial-gradient(circle, ${particle.color}44 0%, transparent 70%)`,
|
1605
|
-
transform: `scale(${1.5 + glowIntensity * 0.5})`,
|
1606
|
-
filter: 'blur(4px)',
|
1607
|
-
} }),
|
1608
|
-
React.createElement("div", { style: {
|
1609
|
-
position: 'absolute',
|
1610
|
-
width: '100%',
|
1611
|
-
height: '100%',
|
1612
|
-
borderRadius: '50%',
|
1613
|
-
background: `radial-gradient(circle, ${particle.color}88 0%, ${particle.color}44 50%, transparent 100%)`,
|
1614
|
-
transform: `scale(${1.2 + glowIntensity * 0.3})`,
|
1615
|
-
} }),
|
1616
|
-
React.createElement("div", { style: {
|
1617
|
-
position: 'absolute',
|
1618
|
-
width: '100%',
|
1619
|
-
height: '100%',
|
1620
|
-
display: 'flex',
|
1621
|
-
alignItems: 'center',
|
1622
|
-
justifyContent: 'center',
|
1623
|
-
fontSize: `${particle.size * 0.7}px`,
|
1624
|
-
fontWeight: 'bold',
|
1625
|
-
color: '#FFFFFF',
|
1626
|
-
textShadow: `
|
1627
|
-
0 0 10px ${particle.color},
|
1628
|
-
0 0 20px ${particle.color},
|
1629
|
-
0 0 30px ${particle.color},
|
1630
|
-
0 0 40px ${particle.color}
|
1631
|
-
`,
|
1632
|
-
filter: `brightness(${1.5 + glowIntensity * 0.5})`,
|
1633
|
-
} }, runeSymbol),
|
1634
|
-
[0, 72, 144, 216, 288].map((angle, index) => (React.createElement("div", { key: index, style: {
|
1635
|
-
position: 'absolute',
|
1636
|
-
width: '4px',
|
1637
|
-
height: '4px',
|
1638
|
-
backgroundColor: '#FFFFFF',
|
1639
|
-
borderRadius: '50%',
|
1640
|
-
top: '50%',
|
1641
|
-
left: '50%',
|
1642
|
-
transform: `
|
1643
|
-
translate(-50%, -50%)
|
1644
|
-
rotate(${angle + rotationAngle}deg)
|
1645
|
-
translateY(-${particle.size * 0.6}px)
|
1646
|
-
scale(${0.5 + glowIntensity})
|
1647
|
-
`,
|
1648
|
-
boxShadow: '0 0 6px #FFFFFF',
|
1649
|
-
opacity: glowIntensity,
|
1650
|
-
} })))));
|
1651
|
-
};
|
1652
|
-
|
1653
|
-
const defaultColors$9 = ['#FF6B6B', '#4ECDC4', '#45B7D1', '#F7DC6F', '#BB8FCE'];
|
1654
|
-
const createButterflyParticles = (origin, config) => {
|
1655
|
-
const { particleCount = 6, startVelocity = 3, colors = defaultColors$9, elementSize = 40 } = config;
|
1656
|
-
const particles = [];
|
1657
|
-
for (let i = 0; i < particleCount; i++) {
|
1658
|
-
const angle = randomInRange(0, 360);
|
1659
|
-
const velocity = randomInRange(startVelocity * 0.5, startVelocity);
|
1660
|
-
particles.push({
|
1661
|
-
id: generateId(),
|
1662
|
-
x: origin.x + randomInRange(-50, 50),
|
1663
|
-
y: origin.y + randomInRange(-30, 30),
|
1664
|
-
vx: Math.cos(angle * Math.PI / 180) * velocity,
|
1665
|
-
vy: -Math.abs(Math.sin(angle * Math.PI / 180) * velocity * 0.5), // Float upward
|
1666
|
-
life: config.lifetime || 200,
|
1667
|
-
opacity: 1,
|
1668
|
-
size: randomInRange(elementSize * 0.8, elementSize * 1.2),
|
1669
|
-
// Encode wing phase (0-360), wobble phase (0-360), and rotation speed (-10 to 10)
|
1670
|
-
rotation: Math.floor(randomInRange(0, 360)) + (Math.floor(randomInRange(0, 360)) * 1000) + ((Math.floor(randomInRange(-10, 10)) + 10) * 1000000),
|
1671
|
-
color: getRandomColor(colors),
|
1672
|
-
});
|
1673
|
-
}
|
1674
|
-
return particles;
|
1675
|
-
};
|
1676
|
-
const renderButterflyParticle = (particle) => {
|
1677
|
-
// Extract encoded values
|
1678
|
-
const wingPhase = (particle.rotation % 1000);
|
1679
|
-
const wobblePhase = Math.floor((particle.rotation % 1000000) / 1000);
|
1680
|
-
const rotationSpeed = (Math.floor(particle.rotation / 1000000) - 10) / 10;
|
1681
|
-
// Calculate wing flapping and wobble
|
1682
|
-
const wingAngle = Math.sin((Date.now() * 0.01 + wingPhase) * Math.PI / 180) * 30;
|
1683
|
-
const wobbleX = Math.sin((Date.now() * 0.003 + wobblePhase) * Math.PI / 180) * 10;
|
1684
|
-
const rotation = (Date.now() * rotationSpeed * 0.01) % 360;
|
1685
|
-
return (React.createElement("div", { key: particle.id, style: {
|
1686
|
-
width: `${particle.size}px`,
|
1687
|
-
height: `${particle.size}px`,
|
1688
|
-
position: 'relative',
|
1689
|
-
transform: `translateX(${wobbleX}px) rotate(${rotation}deg)`,
|
1690
|
-
} },
|
1691
|
-
React.createElement("svg", { width: particle.size, height: particle.size, viewBox: "-25 -25 50 50", style: {
|
1692
|
-
position: 'absolute',
|
1693
|
-
top: 0,
|
1694
|
-
left: 0,
|
1695
|
-
} },
|
1696
|
-
React.createElement("ellipse", { cx: "-8", cy: "0", rx: "12", ry: "18", fill: particle.color, opacity: "0.8", transform: `rotate(${-wingAngle} 0 0)` }),
|
1697
|
-
React.createElement("ellipse", { cx: "-6", cy: "-10", rx: "8", ry: "12", fill: particle.color, opacity: "0.6", transform: `rotate(${-wingAngle - 15} 0 0)` }),
|
1698
|
-
React.createElement("ellipse", { cx: "8", cy: "0", rx: "12", ry: "18", fill: particle.color, opacity: "0.8", transform: `rotate(${wingAngle} 0 0)` }),
|
1699
|
-
React.createElement("ellipse", { cx: "6", cy: "-10", rx: "8", ry: "12", fill: particle.color, opacity: "0.6", transform: `rotate(${wingAngle + 15} 0 0)` }),
|
1700
|
-
React.createElement("ellipse", { cx: "0", cy: "0", rx: "3", ry: "15", fill: "#333" }),
|
1701
|
-
React.createElement("line", { x1: "0", y1: "-12", x2: "-3", y2: "-18", stroke: "#333", strokeWidth: "1" }),
|
1702
|
-
React.createElement("line", { x1: "0", y1: "-12", x2: "3", y2: "-18", stroke: "#333", strokeWidth: "1" }),
|
1703
|
-
React.createElement("circle", { cx: "-8", cy: "0", r: "3", fill: "white", opacity: "0.4" }),
|
1704
|
-
React.createElement("circle", { cx: "8", cy: "0", r: "3", fill: "white", opacity: "0.4" }),
|
1705
|
-
React.createElement("circle", { cx: "-6", cy: "-8", r: "2", fill: "black", opacity: "0.3" }),
|
1706
|
-
React.createElement("circle", { cx: "6", cy: "-8", r: "2", fill: "black", opacity: "0.3" }))));
|
1707
|
-
};
|
1708
|
-
|
1709
|
-
const defaultColors$8 = ['#D2691E', '#CD853F', '#8B4513', '#A0522D', '#FF8C00', '#FF6347'];
|
1710
|
-
const createLeafParticles = (origin, config) => {
|
1711
|
-
const { particleCount = 10, colors = defaultColors$8, elementSize = 25 } = config;
|
1712
|
-
const particles = [];
|
1713
|
-
for (let i = 0; i < particleCount; i++) {
|
1714
|
-
particles.push({
|
1715
|
-
id: generateId(),
|
1716
|
-
x: origin.x + randomInRange(-100, 100),
|
1717
|
-
y: origin.y + randomInRange(-50, 0),
|
1718
|
-
vx: randomInRange(-1, 1),
|
1719
|
-
vy: randomInRange(0.5, 2),
|
1720
|
-
life: config.lifetime || 300,
|
1721
|
-
opacity: 1,
|
1722
|
-
size: randomInRange(elementSize * 0.6, elementSize),
|
1723
|
-
// Encode tumble phase (0-360), sway phase (0-360), and sway amount (20-40) + rotation speed (-3 to 3)
|
1724
|
-
rotation: Math.floor(randomInRange(0, 360)) +
|
1725
|
-
(Math.floor(randomInRange(0, 360)) * 1000) +
|
1726
|
-
(Math.floor(randomInRange(20, 40)) * 1000000) +
|
1727
|
-
((Math.floor(randomInRange(-3, 3)) + 3) * 100000000),
|
1728
|
-
color: getRandomColor(colors),
|
1729
|
-
});
|
1730
|
-
}
|
1731
|
-
return particles;
|
1732
|
-
};
|
1733
|
-
const renderLeafParticle = (particle) => {
|
1734
|
-
// Extract encoded values
|
1735
|
-
const tumblePhase = particle.rotation % 1000;
|
1736
|
-
const swayPhase = Math.floor((particle.rotation % 1000000) / 1000);
|
1737
|
-
const swayAmount = Math.floor((particle.rotation % 100000000) / 1000000);
|
1738
|
-
const rotationSpeed = (Math.floor(particle.rotation / 100000000) - 3);
|
1739
|
-
// Calculate tumbling and swaying
|
1740
|
-
const tumble = Math.sin((Date.now() * 0.002 + tumblePhase) * Math.PI / 180) * 30;
|
1741
|
-
const swayX = Math.sin((Date.now() * 0.001 + swayPhase) * Math.PI / 180) * swayAmount;
|
1742
|
-
const rotation = (Date.now() * rotationSpeed * 0.01 + tumble) % 360;
|
1743
|
-
return (React.createElement("div", { key: particle.id, style: {
|
1744
|
-
width: `${particle.size}px`,
|
1745
|
-
height: `${particle.size}px`,
|
1746
|
-
position: 'relative',
|
1747
|
-
transform: `translateX(${swayX}px) rotate(${rotation}deg)`,
|
1748
|
-
} },
|
1749
|
-
React.createElement("svg", { width: particle.size, height: particle.size, viewBox: `-${particle.size / 2} -${particle.size / 2} ${particle.size} ${particle.size}`, style: {
|
1750
|
-
position: 'absolute',
|
1751
|
-
top: 0,
|
1752
|
-
left: 0,
|
1753
|
-
} },
|
1754
|
-
React.createElement("path", { d: `
|
1755
|
-
M 0,-${particle.size / 2}
|
1756
|
-
C -${particle.size / 3},-${particle.size / 3} -${particle.size / 3},${particle.size / 3} 0,${particle.size / 2}
|
1757
|
-
C ${particle.size / 3},${particle.size / 3} ${particle.size / 3},-${particle.size / 3} 0,-${particle.size / 2}
|
1758
|
-
`, fill: particle.color, opacity: "0.9" }),
|
1759
|
-
React.createElement("line", { x1: "0", y1: -particle.size / 2, x2: "0", y2: particle.size / 2, stroke: "#8B4513", strokeWidth: "1", opacity: "0.5" }),
|
1760
|
-
React.createElement("line", { x1: "0", y1: -particle.size / 4, x2: -particle.size / 4, y2: -particle.size / 8, stroke: "#8B4513", strokeWidth: "0.5", opacity: "0.5" }),
|
1761
|
-
React.createElement("line", { x1: "0", y1: -particle.size / 4, x2: particle.size / 4, y2: -particle.size / 8, stroke: "#8B4513", strokeWidth: "0.5", opacity: "0.5" }),
|
1762
|
-
React.createElement("line", { x1: "0", y1: particle.size / 4, x2: -particle.size / 4, y2: particle.size / 8, stroke: "#8B4513", strokeWidth: "0.5", opacity: "0.5" }),
|
1763
|
-
React.createElement("line", { x1: "0", y1: particle.size / 4, x2: particle.size / 4, y2: particle.size / 8, stroke: "#8B4513", strokeWidth: "0.5", opacity: "0.5" }))));
|
1764
|
-
};
|
1765
|
-
|
1766
|
-
const defaultColors$7 = ['#4A90E2', '#5BA0F2', '#6BB0FF', '#3A80D2'];
|
1767
|
-
const createRainParticles = (origin, config) => {
|
1768
|
-
const { particleCount = 50, colors = defaultColors$7, elementSize = 300 } = config;
|
1769
|
-
const particles = [];
|
1770
|
-
for (let i = 0; i < particleCount; i++) {
|
1771
|
-
particles.push({
|
1772
|
-
id: generateId(),
|
1773
|
-
x: randomInRange(origin.x - elementSize / 2, origin.x + elementSize / 2),
|
1774
|
-
y: origin.y - randomInRange(0, elementSize),
|
1775
|
-
vx: randomInRange(-0.5, 0.5),
|
1776
|
-
vy: randomInRange(8, 12),
|
1777
|
-
life: config.lifetime || 150,
|
1778
|
-
opacity: randomInRange(0.3, 0.7),
|
1779
|
-
size: randomInRange(2, 4),
|
1780
|
-
// Encode: length (15-25) + splashing state (0 or 1) * 100 + splash frame (0-15) * 1000
|
1781
|
-
rotation: Math.floor(randomInRange(15, 25)),
|
1782
|
-
color: getRandomColor(colors),
|
1783
|
-
});
|
1784
|
-
}
|
1785
|
-
return particles;
|
1786
|
-
};
|
1787
|
-
const renderRainParticle = (particle) => {
|
1788
|
-
// Extract encoded values
|
1789
|
-
const length = particle.rotation % 100;
|
1790
|
-
const isSplashing = Math.floor((particle.rotation % 1000) / 100) === 1;
|
1791
|
-
const splashFrame = Math.floor(particle.rotation / 1000);
|
1792
|
-
// Render splash effect
|
1793
|
-
if (isSplashing && splashFrame < 15) {
|
1794
|
-
const splashRadius = splashFrame * 2;
|
1795
|
-
const splashOpacity = Math.max(0, 1 - splashFrame / 15) * 0.5;
|
1796
|
-
return (React.createElement("div", { key: particle.id, style: { position: 'relative' } },
|
1797
|
-
React.createElement("svg", { width: splashRadius * 4, height: splashRadius * 2, style: {
|
1798
|
-
position: 'absolute',
|
1799
|
-
left: -splashRadius * 2,
|
1800
|
-
top: -splashRadius,
|
1801
|
-
} },
|
1802
|
-
React.createElement("ellipse", { cx: splashRadius * 2, cy: splashRadius, rx: splashRadius, ry: splashRadius / 3, fill: "none", stroke: particle.color, strokeWidth: "1", opacity: splashOpacity }),
|
1803
|
-
[0, 1, 2, 3].map((i) => {
|
1804
|
-
const angle = (i * 90 + 45) * Math.PI / 180;
|
1805
|
-
const distance = splashFrame * 1.5;
|
1806
|
-
const dropX = splashRadius * 2 + Math.cos(angle) * distance;
|
1807
|
-
const dropY = splashRadius - Math.sin(angle) * distance + splashFrame * 0.5;
|
1808
|
-
return (React.createElement("circle", { key: i, cx: dropX, cy: dropY, r: "1.5", fill: particle.color, opacity: splashOpacity }));
|
1809
|
-
}))));
|
1810
|
-
}
|
1811
|
-
// Render falling raindrop
|
1812
|
-
return (React.createElement("div", { key: particle.id, style: { position: 'relative' } },
|
1813
|
-
React.createElement("svg", { width: particle.size * 2, height: length + particle.size * 3, style: {
|
1814
|
-
position: 'absolute',
|
1815
|
-
left: -particle.size,
|
1816
|
-
top: -length,
|
1817
|
-
} },
|
1818
|
-
React.createElement("line", { x1: particle.size, y1: 0, x2: particle.size, y2: length, stroke: particle.color, strokeWidth: particle.size, strokeLinecap: "round", opacity: particle.opacity * 0.3 }),
|
1819
|
-
React.createElement("ellipse", { cx: particle.size, cy: length + particle.size * 1.5, rx: particle.size, ry: particle.size * 1.5, fill: particle.color, opacity: particle.opacity }))));
|
1820
|
-
};
|
1821
|
-
|
1822
|
-
const defaultColors$6 = ['#FFFFFF', '#F5F5F5', '#FAFAFA'];
|
1823
|
-
const createDandelionParticles = (origin, config) => {
|
1824
|
-
const { particleCount = 15, colors = defaultColors$6, elementSize = 15 } = config;
|
1825
|
-
const particles = [];
|
1826
|
-
for (let i = 0; i < particleCount; i++) {
|
1827
|
-
particles.push({
|
1828
|
-
id: generateId(),
|
1829
|
-
x: origin.x + randomInRange(-20, 20),
|
1830
|
-
y: origin.y + randomInRange(-20, 20),
|
1831
|
-
vx: randomInRange(-2, 2),
|
1832
|
-
vy: randomInRange(-1, -0.3),
|
1833
|
-
life: config.lifetime || 200,
|
1834
|
-
opacity: 1,
|
1835
|
-
size: randomInRange(elementSize * 0.8, elementSize * 1.2),
|
1836
|
-
// Encode: rotation angle + float phase * 1000 + drift phase * 1000000
|
1837
|
-
rotation: Math.floor(randomInRange(0, 360)) +
|
1838
|
-
(Math.floor(randomInRange(0, 360)) * 1000) +
|
1839
|
-
(Math.floor(randomInRange(0, 360)) * 1000000),
|
1840
|
-
color: getRandomColor(colors),
|
1841
|
-
});
|
1842
|
-
}
|
1843
|
-
return particles;
|
1844
|
-
};
|
1845
|
-
const renderDandelionParticle = (particle) => {
|
1846
|
-
// Extract encoded values
|
1847
|
-
const rotationAngle = particle.rotation % 1000;
|
1848
|
-
const floatPhase = Math.floor((particle.rotation % 1000000) / 1000);
|
1849
|
-
const driftPhase = Math.floor(particle.rotation / 1000000);
|
1850
|
-
// Calculate floating effects
|
1851
|
-
const floatY = Math.sin((Date.now() * 0.002 + floatPhase) * Math.PI / 180) * 5;
|
1852
|
-
const driftX = Math.sin((Date.now() * 0.001 + driftPhase) * Math.PI / 180) * 3;
|
1853
|
-
const rotation = (Date.now() * 0.01 + rotationAngle) % 360;
|
1854
|
-
const seedCount = 7;
|
1855
|
-
return (React.createElement("div", { key: particle.id, style: {
|
1856
|
-
width: `${particle.size * 2}px`,
|
1857
|
-
height: `${particle.size * 2}px`,
|
1858
|
-
position: 'relative',
|
1859
|
-
transform: `translate(${driftX}px, ${floatY}px) rotate(${rotation}deg)`,
|
1860
|
-
opacity: particle.opacity,
|
1861
|
-
} },
|
1862
|
-
React.createElement("svg", { width: particle.size * 2, height: particle.size * 2, viewBox: `-${particle.size} -${particle.size} ${particle.size * 2} ${particle.size * 2}`, style: {
|
1863
|
-
position: 'absolute',
|
1864
|
-
top: 0,
|
1865
|
-
left: 0,
|
1866
|
-
} },
|
1867
|
-
React.createElement("circle", { cx: "0", cy: "0", r: "2", fill: "#F5F5DC" }),
|
1868
|
-
Array.from({ length: seedCount }).map((_, i) => {
|
1869
|
-
const angle = (i * 360 / seedCount) * Math.PI / 180;
|
1870
|
-
const endX = Math.cos(angle) * particle.size;
|
1871
|
-
const endY = Math.sin(angle) * particle.size;
|
1872
|
-
const midX = Math.cos(angle) * particle.size * 0.7;
|
1873
|
-
const midY = Math.sin(angle) * particle.size * 0.7;
|
1874
|
-
return (React.createElement("g", { key: i },
|
1875
|
-
React.createElement("line", { x1: "0", y1: "0", x2: endX, y2: endY, stroke: "#E5E5E5", strokeWidth: "0.5", opacity: "0.8" }),
|
1876
|
-
React.createElement("circle", { cx: endX, cy: endY, r: "3", fill: particle.color, opacity: "0.6" }),
|
1877
|
-
React.createElement("circle", { cx: midX, cy: midY, r: "2", fill: particle.color, opacity: "0.4" }),
|
1878
|
-
[0, 1, 2].map((j) => {
|
1879
|
-
const filamentAngle = angle + (j - 1) * 0.1;
|
1880
|
-
const filamentX = endX + Math.cos(filamentAngle) * 2;
|
1881
|
-
const filamentY = endY + Math.sin(filamentAngle) * 2;
|
1882
|
-
return (React.createElement("line", { key: j, x1: endX, y1: endY, x2: filamentX, y2: filamentY, stroke: "#E5E5E5", strokeWidth: "0.3", opacity: "0.6" }));
|
1883
|
-
})));
|
1884
|
-
}))));
|
1885
|
-
};
|
1886
|
-
|
1887
|
-
const defaultColors$5 = ['#FFD700', '#FFA500'];
|
1888
|
-
const createBeeParticles = (origin, config) => {
|
1889
|
-
const { particleCount = 5, colors = defaultColors$5, elementSize = 18 } = config;
|
1890
|
-
const particles = [];
|
1891
|
-
for (let i = 0; i < particleCount; i++) {
|
1892
|
-
particles.push({
|
1893
|
-
id: generateId(),
|
1894
|
-
x: origin.x + randomInRange(-50, 50),
|
1895
|
-
y: origin.y + randomInRange(-50, 50),
|
1896
|
-
vx: randomInRange(2, 4),
|
1897
|
-
vy: randomInRange(-1, 1),
|
1898
|
-
life: config.lifetime || 300,
|
1899
|
-
opacity: 1,
|
1900
|
-
size: randomInRange(elementSize * 0.8, elementSize * 1.1),
|
1901
|
-
// Encode: zigzag phase (0-360) + wing phase (0-360) * 1000 + buzz phase (0-360) * 1000000
|
1902
|
-
rotation: Math.floor(randomInRange(0, 360)) +
|
1903
|
-
(Math.floor(randomInRange(0, 360)) * 1000) +
|
1904
|
-
(Math.floor(randomInRange(0, 360)) * 1000000),
|
1905
|
-
color: getRandomColor(colors),
|
1906
|
-
});
|
1907
|
-
}
|
1908
|
-
return particles;
|
1909
|
-
};
|
1910
|
-
const renderBeeParticle = (particle) => {
|
1911
|
-
// Extract encoded values
|
1912
|
-
const zigzagPhase = particle.rotation % 1000;
|
1913
|
-
const wingPhase = Math.floor((particle.rotation % 1000000) / 1000);
|
1914
|
-
const buzzPhase = Math.floor(particle.rotation / 1000000);
|
1915
|
-
// Calculate animations
|
1916
|
-
const zigzagY = Math.sin((Date.now() * 0.005 + zigzagPhase) * Math.PI / 180) * 15;
|
1917
|
-
const wingAngle = Math.sin((Date.now() * 0.02 + wingPhase) * Math.PI / 180) * 20;
|
1918
|
-
const buzzOffset = Math.sin((Date.now() * 0.015 + buzzPhase) * Math.PI / 180) * 2;
|
1919
|
-
// Calculate rotation based on movement direction
|
1920
|
-
const movementAngle = Math.atan2(particle.vy, particle.vx) * 180 / Math.PI;
|
1921
|
-
return (React.createElement("div", { key: particle.id, style: {
|
1922
|
-
width: `${particle.size * 2}px`,
|
1923
|
-
height: `${particle.size * 2}px`,
|
1924
|
-
position: 'relative',
|
1925
|
-
transform: `translate(${buzzOffset}px, ${zigzagY}px) rotate(${movementAngle}deg)`,
|
1926
|
-
} },
|
1927
|
-
React.createElement("svg", { width: particle.size * 2, height: particle.size * 2, viewBox: "-15 -10 30 20", style: {
|
1928
|
-
position: 'absolute',
|
1929
|
-
top: 0,
|
1930
|
-
left: 0,
|
1931
|
-
} },
|
1932
|
-
React.createElement("ellipse", { cx: "-2", cy: "-3", rx: "8", ry: "4", fill: "#E5E5E5", opacity: "0.7", transform: `rotate(${-wingAngle - 20} -2 -3)` }),
|
1933
|
-
React.createElement("ellipse", { cx: "-2", cy: "3", rx: "8", ry: "4", fill: "#E5E5E5", opacity: "0.7", transform: `rotate(${wingAngle + 20} -2 3)` }),
|
1934
|
-
React.createElement("ellipse", { cx: "0", cy: "0", rx: "8", ry: "6", fill: particle.color }),
|
1935
|
-
React.createElement("ellipse", { cx: "-6", cy: "0", rx: "6", ry: "5", fill: "#333" }),
|
1936
|
-
React.createElement("rect", { x: "-3", y: "-6", width: "2", height: "12", fill: "#333" }),
|
1937
|
-
React.createElement("rect", { x: "1", y: "-6", width: "2", height: "12", fill: "#333" }),
|
1938
|
-
React.createElement("rect", { x: "5", y: "-5", width: "2", height: "10", fill: "#333" }),
|
1939
|
-
React.createElement("circle", { cx: "8", cy: "0", r: "4", fill: "#333" }),
|
1940
|
-
React.createElement("circle", { cx: "9", cy: "-1.5", r: "1", fill: "#FFF" }),
|
1941
|
-
React.createElement("circle", { cx: "9", cy: "1.5", r: "1", fill: "#FFF" }),
|
1942
|
-
React.createElement("line", { x1: "10", y1: "-2", x2: "12", y2: "-4", stroke: "#333", strokeWidth: "0.5" }),
|
1943
|
-
React.createElement("line", { x1: "10", y1: "2", x2: "12", y2: "4", stroke: "#333", strokeWidth: "0.5" }),
|
1944
|
-
React.createElement("polygon", { points: "-10,0 -12,1 -12,-1", fill: "#333" }))));
|
1945
|
-
};
|
1946
|
-
|
1947
|
-
const defaultColors$4 = ['#FFE5B4', '#FFF8DC', '#FFFACD', '#FFF5EE'];
|
1948
|
-
const createPopcornParticles = (origin, config) => {
|
1949
|
-
const { particleCount = 20, startVelocity = 25, colors = defaultColors$4, elementSize = 20 } = config;
|
1950
|
-
const particles = [];
|
1951
|
-
for (let i = 0; i < particleCount; i++) {
|
1952
|
-
const angle = randomInRange(0, 360);
|
1953
|
-
const velocity = randomInRange(startVelocity * 0.5, startVelocity);
|
1954
|
-
particles.push({
|
1955
|
-
id: generateId(),
|
1956
|
-
x: origin.x,
|
1957
|
-
y: origin.y,
|
1958
|
-
vx: Math.cos(degreesToRadians(angle)) * velocity,
|
1959
|
-
vy: Math.sin(degreesToRadians(angle)) * velocity - 10, // Initial upward boost
|
1960
|
-
life: config.lifetime || 150,
|
1961
|
-
opacity: 1,
|
1962
|
-
size: randomInRange(elementSize * 0.8, elementSize * 1.2),
|
1963
|
-
rotation: randomInRange(0, 360),
|
1964
|
-
color: getRandomColor(colors),
|
1965
|
-
});
|
1966
|
-
}
|
1967
|
-
return particles;
|
1968
|
-
};
|
1969
|
-
const renderPopcornParticle = (particle) => {
|
1970
|
-
// Add some rotation animation
|
1971
|
-
const rotation = particle.rotation + (150 - particle.life) * 3;
|
1972
|
-
// Add bounce effect
|
1973
|
-
const bounceProgress = (150 - particle.life) / 150;
|
1974
|
-
const scale = 0.5 + Math.sin(bounceProgress * Math.PI) * 0.5;
|
1975
|
-
return (React.createElement("div", { key: particle.id, style: {
|
1976
|
-
fontSize: `${particle.size}px`,
|
1977
|
-
transform: `rotate(${rotation}deg) scale(${scale})`,
|
1978
|
-
opacity: particle.opacity,
|
1979
|
-
userSelect: 'none',
|
1980
|
-
} }, "\uD83C\uDF7F"));
|
1981
|
-
};
|
1982
|
-
|
1983
|
-
const defaultColors$3 = ['#F0E68C', '#FFD700', '#FFF8DC', '#FFFACD', '#F5DEB3'];
|
1984
|
-
const createChampagneParticles = (origin, config) => {
|
1985
|
-
const { particleCount = 40, startVelocity = 30, colors = defaultColors$3, elementSize = 12 } = config;
|
1986
|
-
const particles = [];
|
1987
|
-
for (let i = 0; i < particleCount; i++) {
|
1988
|
-
const isBubble = i < particleCount * 0.7;
|
1989
|
-
const angle = isBubble
|
1990
|
-
? randomInRange(60, 120) // Mostly upward for bubbles
|
1991
|
-
: randomInRange(0, 360); // Any direction for cork
|
1992
|
-
const velocity = randomInRange(startVelocity * 0.5, startVelocity);
|
1993
|
-
particles.push({
|
1994
|
-
id: generateId(),
|
1995
|
-
x: origin.x,
|
1996
|
-
y: origin.y,
|
1997
|
-
vx: Math.cos(degreesToRadians(angle)) * velocity,
|
1998
|
-
vy: Math.sin(degreesToRadians(angle)) * velocity * (isBubble ? -1 : 1),
|
1999
|
-
life: config.lifetime || 200,
|
2000
|
-
opacity: isBubble ? 0.6 : 1,
|
2001
|
-
size: isBubble ? randomInRange(4, 8) : elementSize,
|
2002
|
-
// Encode: isBubble (0 or 1) + wobble phase * 10
|
2003
|
-
rotation: (isBubble ? 0 : 1) + Math.floor(randomInRange(0, 360)) * 10,
|
2004
|
-
color: getRandomColor(colors),
|
2005
|
-
});
|
2006
|
-
}
|
2007
|
-
return particles;
|
2008
|
-
};
|
2009
|
-
const renderChampagneParticle = (particle) => {
|
2010
|
-
const isBubble = (particle.rotation % 10) === 0;
|
2011
|
-
const wobblePhase = Math.floor(particle.rotation / 10);
|
2012
|
-
if (isBubble) {
|
2013
|
-
// Render bubble
|
2014
|
-
const wobble = Math.sin((Date.now() * 0.003 + wobblePhase) * Math.PI / 180) * 10;
|
2015
|
-
return (React.createElement("div", { key: particle.id, style: {
|
2016
|
-
width: `${particle.size}px`,
|
2017
|
-
height: `${particle.size}px`,
|
2018
|
-
borderRadius: '50%',
|
2019
|
-
backgroundColor: particle.color,
|
2020
|
-
opacity: particle.opacity,
|
2021
|
-
border: `1px solid ${particle.color}`,
|
2022
|
-
transform: `translateX(${wobble}px)`,
|
2023
|
-
boxShadow: `inset -2px -2px 4px rgba(0,0,0,0.1), inset 2px 2px 4px rgba(255,255,255,0.5)`,
|
2024
|
-
} }));
|
2025
|
-
}
|
2026
|
-
// Render cork (champagne bottle)
|
2027
|
-
const rotation = (Date.now() * 0.2 + wobblePhase) % 360;
|
2028
|
-
return (React.createElement("div", { key: particle.id, style: {
|
2029
|
-
fontSize: `${particle.size}px`,
|
2030
|
-
transform: `rotate(${rotation}deg)`,
|
2031
|
-
opacity: particle.opacity,
|
2032
|
-
userSelect: 'none',
|
2033
|
-
} }, "\uD83C\uDF7E"));
|
2034
|
-
};
|
2035
|
-
|
2036
|
-
const defaultColors$2 = ['#FF69B4', '#FF1493', '#FFB6C1', '#FFC0CB', '#FF6347', '#FFA500', '#FFD700', '#98FB98', '#87CEEB', '#DDA0DD'];
|
2037
|
-
const candyEmojis = ['🍬', '🍭', '🍮', '🍯'];
|
2038
|
-
const createCandyParticles = (origin, config) => {
|
2039
|
-
const { particleCount = 20, startVelocity = 20, colors = defaultColors$2, elementSize = 25 } = config;
|
2040
|
-
const particles = [];
|
2041
|
-
for (let i = 0; i < particleCount; i++) {
|
2042
|
-
const angle = randomInRange(-30, 30); // Mostly falling down
|
2043
|
-
const velocity = randomInRange(startVelocity * 0.5, startVelocity);
|
2044
|
-
particles.push({
|
2045
|
-
id: generateId(),
|
2046
|
-
x: origin.x,
|
2047
|
-
y: origin.y - 50, // Start above origin
|
2048
|
-
vx: Math.sin(angle * Math.PI / 180) * velocity * 0.5,
|
2049
|
-
vy: randomInRange(3, 6), // Fall down
|
2050
|
-
life: config.lifetime || 180,
|
2051
|
-
opacity: 1,
|
2052
|
-
size: randomInRange(elementSize * 0.7, elementSize * 1.3),
|
2053
|
-
// Encode candy type (0-3) + initial rotation * 10
|
2054
|
-
rotation: Math.floor(Math.random() * candyEmojis.length) + (Math.floor(randomInRange(0, 360)) * 10),
|
2055
|
-
color: getRandomColor(colors),
|
2056
|
-
});
|
2057
|
-
}
|
2058
|
-
return particles;
|
2059
|
-
};
|
2060
|
-
const renderCandyParticle = (particle) => {
|
2061
|
-
const candyIndex = particle.rotation % 10;
|
2062
|
-
const initialRotation = Math.floor(particle.rotation / 10);
|
2063
|
-
const candy = candyEmojis[candyIndex] || candyEmojis[0];
|
2064
|
-
// Add tumbling rotation
|
2065
|
-
const tumbleSpeed = 5;
|
2066
|
-
const rotation = initialRotation + (180 - particle.life) * tumbleSpeed;
|
2067
|
-
// Add sway effect
|
2068
|
-
const swayAmount = Math.sin((180 - particle.life) * 0.05) * 20;
|
2069
|
-
return (React.createElement("div", { key: particle.id, style: {
|
2070
|
-
fontSize: `${particle.size}px`,
|
2071
|
-
transform: `translateX(${swayAmount}px) rotate(${rotation}deg)`,
|
2072
|
-
opacity: particle.opacity,
|
2073
|
-
userSelect: 'none',
|
2074
|
-
} }, candy));
|
2075
|
-
};
|
2076
|
-
|
2077
|
-
const defaultColors$1 = ['#FFB6C1', '#FF69B4', '#FFD700', '#FF6347', '#98D8C8', '#F7DC6F', '#BB8FCE', '#85C1E2'];
|
2078
|
-
const createDonutParticles = (origin, config) => {
|
2079
|
-
const { particleCount = 15, startVelocity = 25, colors = defaultColors$1, elementSize = 30 } = config;
|
2080
|
-
const particles = [];
|
2081
|
-
for (let i = 0; i < particleCount; i++) {
|
2082
|
-
const angle = randomInRange(0, 360);
|
2083
|
-
const velocity = randomInRange(startVelocity * 0.5, startVelocity);
|
2084
|
-
particles.push({
|
2085
|
-
id: generateId(),
|
2086
|
-
x: origin.x,
|
2087
|
-
y: origin.y,
|
2088
|
-
vx: Math.cos(degreesToRadians(angle)) * velocity,
|
2089
|
-
vy: Math.sin(degreesToRadians(angle)) * velocity - 10, // Initial upward boost
|
2090
|
-
life: config.lifetime || 200,
|
2091
|
-
opacity: 1,
|
2092
|
-
size: randomInRange(elementSize * 0.6, elementSize * 1.4),
|
2093
|
-
rotation: randomInRange(0, 360),
|
2094
|
-
color: getRandomColor(colors),
|
2095
|
-
});
|
2096
|
-
}
|
2097
|
-
return particles;
|
2098
|
-
};
|
2099
|
-
const renderDonutParticle = (particle) => {
|
2100
|
-
// Add spinning animation
|
2101
|
-
const spinSpeed = 8;
|
2102
|
-
const rotation = particle.rotation + (200 - particle.life) * spinSpeed;
|
2103
|
-
// Add bounce effect
|
2104
|
-
const bounceProgress = (200 - particle.life) / 200;
|
2105
|
-
const scale = 0.9 + Math.sin(bounceProgress * Math.PI * 2) * 0.1;
|
2106
|
-
return (React.createElement("div", { key: particle.id, style: {
|
2107
|
-
fontSize: `${particle.size}px`,
|
2108
|
-
transform: `rotate(${rotation}deg) scale(${scale})`,
|
2109
|
-
opacity: particle.opacity,
|
2110
|
-
userSelect: 'none',
|
2111
|
-
position: 'relative',
|
2112
|
-
} },
|
2113
|
-
"\uD83C\uDF69",
|
2114
|
-
[0, 120, 240].map((angle, i) => (React.createElement("div", { key: i, style: {
|
2115
|
-
position: 'absolute',
|
2116
|
-
width: '3px',
|
2117
|
-
height: '8px',
|
2118
|
-
backgroundColor: particle.color,
|
2119
|
-
borderRadius: '40%',
|
2120
|
-
top: '50%',
|
2121
|
-
left: '50%',
|
2122
|
-
transform: `
|
2123
|
-
translate(-50%, -50%)
|
2124
|
-
rotate(${angle + rotation}deg)
|
2125
|
-
translateY(${particle.size * 0.3}px)
|
2126
|
-
scale(${scale})
|
2127
|
-
`,
|
2128
|
-
opacity: particle.opacity * 0.8,
|
2129
|
-
} })))));
|
2130
|
-
};
|
2131
|
-
|
2132
|
-
const defaultColors = ['#FF6347', '#FFD700', '#98D8C8', '#FF8C00', '#DC143C'];
|
2133
|
-
const createPizzaParticles = (origin, config) => {
|
2134
|
-
const { particleCount = 12, startVelocity = 30, colors = defaultColors, elementSize = 35 } = config;
|
2135
|
-
const particles = [];
|
2136
|
-
for (let i = 0; i < particleCount; i++) {
|
2137
|
-
const angle = randomInRange(0, 360);
|
2138
|
-
const velocity = randomInRange(startVelocity * 0.5, startVelocity);
|
2139
|
-
particles.push({
|
2140
|
-
id: generateId(),
|
2141
|
-
x: origin.x,
|
2142
|
-
y: origin.y,
|
2143
|
-
vx: Math.cos(degreesToRadians(angle)) * velocity,
|
2144
|
-
vy: Math.sin(degreesToRadians(angle)) * velocity - 15, // Initial upward boost
|
2145
|
-
life: config.lifetime || 180,
|
2146
|
-
opacity: 1,
|
2147
|
-
size: randomInRange(elementSize * 0.5, elementSize * 1.2),
|
2148
|
-
rotation: randomInRange(0, 360),
|
2149
|
-
color: getRandomColor(colors),
|
2150
|
-
});
|
2151
|
-
}
|
2152
|
-
return particles;
|
2153
|
-
};
|
2154
|
-
const renderPizzaParticle = (particle) => {
|
2155
|
-
// Add spinning and flipping animation
|
2156
|
-
const spinSpeed = 10;
|
2157
|
-
const rotation = particle.rotation + (180 - particle.life) * spinSpeed;
|
2158
|
-
const flipAngle = (180 - particle.life) * 2;
|
2159
|
-
// Add wobble effect
|
2160
|
-
const wobble = Math.sin((180 - particle.life) * 0.1) * 10;
|
2161
|
-
// Scale animation
|
2162
|
-
const progress = (180 - particle.life) / 180;
|
2163
|
-
const scale = 0.8 + Math.sin(progress * Math.PI) * 0.2;
|
2164
|
-
return (React.createElement("div", { key: particle.id, style: {
|
2165
|
-
fontSize: `${particle.size}px`,
|
2166
|
-
transform: `
|
2167
|
-
translateX(${wobble}px)
|
2168
|
-
rotate(${rotation}deg)
|
2169
|
-
rotateX(${flipAngle}deg)
|
2170
|
-
scale(${scale})
|
2171
|
-
`,
|
2172
|
-
transformStyle: 'preserve-3d',
|
2173
|
-
opacity: particle.opacity,
|
2174
|
-
userSelect: 'none',
|
2175
|
-
position: 'relative',
|
2176
|
-
} },
|
2177
|
-
"\uD83C\uDF55",
|
2178
|
-
Math.random() > 0.5 && (React.createElement("div", { style: {
|
2179
|
-
position: 'absolute',
|
2180
|
-
fontSize: `${particle.size * 0.4}px`,
|
2181
|
-
top: `${10 + Math.random() * 30}%`,
|
2182
|
-
left: `${10 + Math.random() * 30}%`,
|
2183
|
-
transform: `rotate(${Math.random() * 360}deg)`,
|
2184
|
-
opacity: particle.opacity * 0.8,
|
2185
|
-
} }, ['🍅', '🧀', '🌶️'][Math.floor(Math.random() * 3)]))));
|
1062
|
+
React.createElement("path", { d: `
|
1063
|
+
M 0,-${particle.size / 2}
|
1064
|
+
C -${particle.size / 3},-${particle.size / 3} -${particle.size / 3},${particle.size / 3} 0,${particle.size / 2}
|
1065
|
+
C ${particle.size / 3},${particle.size / 3} ${particle.size / 3},-${particle.size / 3} 0,-${particle.size / 2}
|
1066
|
+
`, fill: particle.color, opacity: "0.9" }),
|
1067
|
+
React.createElement("line", { x1: "0", y1: -particle.size / 2, x2: "0", y2: particle.size / 2, stroke: "#8B4513", strokeWidth: "1", opacity: "0.5" }),
|
1068
|
+
React.createElement("line", { x1: "0", y1: -particle.size / 4, x2: -particle.size / 4, y2: -particle.size / 8, stroke: "#8B4513", strokeWidth: "0.5", opacity: "0.5" }),
|
1069
|
+
React.createElement("line", { x1: "0", y1: -particle.size / 4, x2: particle.size / 4, y2: -particle.size / 8, stroke: "#8B4513", strokeWidth: "0.5", opacity: "0.5" }),
|
1070
|
+
React.createElement("line", { x1: "0", y1: particle.size / 4, x2: -particle.size / 4, y2: particle.size / 8, stroke: "#8B4513", strokeWidth: "0.5", opacity: "0.5" }),
|
1071
|
+
React.createElement("line", { x1: "0", y1: particle.size / 4, x2: particle.size / 4, y2: particle.size / 8, stroke: "#8B4513", strokeWidth: "0.5", opacity: "0.5" }))));
|
2186
1072
|
};
|
2187
1073
|
|
2188
1074
|
const animations = {
|
@@ -2222,10 +1108,6 @@ const animations = {
|
|
2222
1108
|
createParticles: createCoinParticles,
|
2223
1109
|
renderParticle: renderCoinParticle,
|
2224
1110
|
},
|
2225
|
-
lightning: {
|
2226
|
-
createParticles: createLightningParticles,
|
2227
|
-
renderParticle: renderLightningParticle,
|
2228
|
-
},
|
2229
1111
|
petals: {
|
2230
1112
|
createParticles: createPetalParticles,
|
2231
1113
|
renderParticle: renderPetalParticle,
|
@@ -2242,10 +1124,6 @@ const animations = {
|
|
2242
1124
|
createParticles: createPaintParticles,
|
2243
1125
|
renderParticle: renderPaintParticle,
|
2244
1126
|
},
|
2245
|
-
music: {
|
2246
|
-
createParticles: createMusicParticles,
|
2247
|
-
renderParticle: renderMusicParticle,
|
2248
|
-
},
|
2249
1127
|
balloons: {
|
2250
1128
|
createParticles: createBalloonParticles,
|
2251
1129
|
renderParticle: renderBalloonParticle,
|
@@ -2254,86 +1132,58 @@ const animations = {
|
|
2254
1132
|
createParticles: createGalaxyParticles,
|
2255
1133
|
renderParticle: renderGalaxyParticle,
|
2256
1134
|
},
|
2257
|
-
matrix: {
|
2258
|
-
createParticles: createMatrixParticles,
|
2259
|
-
renderParticle: renderMatrixParticle,
|
2260
|
-
},
|
2261
|
-
pixels: {
|
2262
|
-
createParticles: createPixelParticles,
|
2263
|
-
renderParticle: renderPixelParticle,
|
2264
|
-
},
|
2265
1135
|
glitch: {
|
2266
1136
|
createParticles: createGlitchParticles,
|
2267
1137
|
renderParticle: renderGlitchParticle,
|
2268
1138
|
},
|
2269
|
-
dice: {
|
2270
|
-
createParticles: createDiceParticles,
|
2271
|
-
renderParticle: renderDiceParticle,
|
2272
|
-
},
|
2273
|
-
levelup: {
|
2274
|
-
createParticles: createLevelUpParticles,
|
2275
|
-
renderParticle: renderLevelUpParticle,
|
2276
|
-
},
|
2277
1139
|
magicdust: {
|
2278
1140
|
createParticles: createMagicDustParticles,
|
2279
1141
|
renderParticle: renderMagicDustParticle,
|
2280
1142
|
},
|
2281
|
-
ghosts: {
|
2282
|
-
createParticles: createGhostParticles,
|
2283
|
-
renderParticle: renderGhostParticle,
|
2284
|
-
},
|
2285
1143
|
crystals: {
|
2286
1144
|
createParticles: createCrystalParticles,
|
2287
1145
|
renderParticle: renderCrystalParticle,
|
2288
1146
|
},
|
2289
|
-
dragons: {
|
2290
|
-
createParticles: createDragonParticles,
|
2291
|
-
renderParticle: renderDragonParticle,
|
2292
|
-
},
|
2293
|
-
runes: {
|
2294
|
-
createParticles: createRuneParticles,
|
2295
|
-
renderParticle: renderRuneParticle,
|
2296
|
-
},
|
2297
|
-
butterflies: {
|
2298
|
-
createParticles: createButterflyParticles,
|
2299
|
-
renderParticle: renderButterflyParticle,
|
2300
|
-
},
|
2301
1147
|
leaves: {
|
2302
1148
|
createParticles: createLeafParticles,
|
2303
1149
|
renderParticle: renderLeafParticle,
|
2304
1150
|
},
|
2305
|
-
|
2306
|
-
|
2307
|
-
|
2308
|
-
|
2309
|
-
|
2310
|
-
|
2311
|
-
|
2312
|
-
|
2313
|
-
|
2314
|
-
|
2315
|
-
|
2316
|
-
|
2317
|
-
|
2318
|
-
|
2319
|
-
|
2320
|
-
|
2321
|
-
|
2322
|
-
|
2323
|
-
|
2324
|
-
|
2325
|
-
|
2326
|
-
|
2327
|
-
|
2328
|
-
|
2329
|
-
|
2330
|
-
|
2331
|
-
|
2332
|
-
|
2333
|
-
|
2334
|
-
|
2335
|
-
|
2336
|
-
|
1151
|
+
};
|
1152
|
+
|
1153
|
+
const isMobileDevice = () => {
|
1154
|
+
if (typeof window === 'undefined')
|
1155
|
+
return false;
|
1156
|
+
// Check user agent
|
1157
|
+
const userAgent = navigator.userAgent || navigator.vendor || window.opera;
|
1158
|
+
const isMobileUA = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent);
|
1159
|
+
// Check viewport width
|
1160
|
+
const isMobileWidth = window.innerWidth <= 768;
|
1161
|
+
// Check touch support
|
1162
|
+
const hasTouch = 'ontouchstart' in window || navigator.maxTouchPoints > 0;
|
1163
|
+
return isMobileUA || (isMobileWidth && hasTouch);
|
1164
|
+
};
|
1165
|
+
const optimizeConfigForMobile = (config) => {
|
1166
|
+
var _a, _b, _c;
|
1167
|
+
if (!isMobileDevice())
|
1168
|
+
return config;
|
1169
|
+
return Object.assign(Object.assign({}, config), {
|
1170
|
+
// Reduce particle count by 40%
|
1171
|
+
particleCount: Math.floor((config.particleCount || 50) * 0.6),
|
1172
|
+
// Reduce element size by 20%
|
1173
|
+
elementSize: Math.floor((config.elementSize || 20) * 0.8),
|
1174
|
+
// Reduce lifetime by 20%
|
1175
|
+
lifetime: Math.floor((config.lifetime || 150) * 0.8),
|
1176
|
+
// Simplify physics
|
1177
|
+
physics: Object.assign(Object.assign({}, config.physics), {
|
1178
|
+
// Reduce precision for mobile
|
1179
|
+
gravity: Math.round((((_a = config.physics) === null || _a === void 0 ? void 0 : _a.gravity) || 0) * 100) / 100, wind: Math.round((((_b = config.physics) === null || _b === void 0 ? void 0 : _b.wind) || 0) * 100) / 100, friction: Math.round((((_c = config.physics) === null || _c === void 0 ? void 0 : _c.friction) || 0.98) * 100) / 100 }) });
|
1180
|
+
};
|
1181
|
+
// Frame skipping for mobile
|
1182
|
+
const shouldSkipFrame = (frameCount) => {
|
1183
|
+
if (!isMobileDevice())
|
1184
|
+
return false;
|
1185
|
+
// Skip every 3rd frame on mobile
|
1186
|
+
return frameCount % 3 === 0;
|
2337
1187
|
};
|
2338
1188
|
|
2339
1189
|
const useReward = (elementId, animationType, config) => {
|
@@ -2342,6 +1192,15 @@ const useReward = (elementId, animationType, config) => {
|
|
2342
1192
|
const particlesRef = useRef([]);
|
2343
1193
|
const containerRef = useRef(null);
|
2344
1194
|
const rootRef = useRef(null);
|
1195
|
+
const isTabVisible = useRef(true);
|
1196
|
+
// Monitor tab visibility
|
1197
|
+
useEffect(() => {
|
1198
|
+
const handleVisibilityChange = () => {
|
1199
|
+
isTabVisible.current = !document.hidden;
|
1200
|
+
};
|
1201
|
+
document.addEventListener('visibilitychange', handleVisibilityChange);
|
1202
|
+
return () => document.removeEventListener('visibilitychange', handleVisibilityChange);
|
1203
|
+
}, []);
|
2345
1204
|
const animate = useCallback(() => {
|
2346
1205
|
var _a, _b, _c, _d, _e, _f;
|
2347
1206
|
const element = document.getElementById(elementId);
|
@@ -2357,8 +1216,10 @@ const useReward = (elementId, animationType, config) => {
|
|
2357
1216
|
console.error(`Animation type "${animationType}" not found`);
|
2358
1217
|
return;
|
2359
1218
|
}
|
1219
|
+
// Apply mobile performance optimizations
|
1220
|
+
const optimizedConfig = config ? optimizeConfigForMobile(config) : undefined;
|
2360
1221
|
// Create particles
|
2361
|
-
particlesRef.current = animationHandler.createParticles(origin,
|
1222
|
+
particlesRef.current = animationHandler.createParticles(origin, optimizedConfig || {});
|
2362
1223
|
// Create container
|
2363
1224
|
const container = document.createElement('div');
|
2364
1225
|
container.style.position = 'fixed';
|
@@ -2379,8 +1240,13 @@ const useReward = (elementId, animationType, config) => {
|
|
2379
1240
|
const gravity = (_b = (_a = config === null || config === void 0 ? void 0 : config.physics) === null || _a === void 0 ? void 0 : _a.gravity) !== null && _b !== void 0 ? _b : defaultGravity;
|
2380
1241
|
const friction = (_d = (_c = config === null || config === void 0 ? void 0 : config.physics) === null || _c === void 0 ? void 0 : _c.friction) !== null && _d !== void 0 ? _d : 0.98;
|
2381
1242
|
const wind = (_f = (_e = config === null || config === void 0 ? void 0 : config.physics) === null || _e === void 0 ? void 0 : _e.wind) !== null && _f !== void 0 ? _f : 0;
|
1243
|
+
// Track frame count for mobile optimization
|
1244
|
+
let frameCount = 0;
|
2382
1245
|
const updateParticles = () => {
|
2383
1246
|
let activeParticles = 0;
|
1247
|
+
frameCount++;
|
1248
|
+
// Skip frame rendering on mobile to improve performance
|
1249
|
+
const skipFrame = shouldSkipFrame(frameCount);
|
2384
1250
|
particlesRef.current = particlesRef.current.map((particle) => {
|
2385
1251
|
if (particle.life <= 0)
|
2386
1252
|
return particle;
|
@@ -2408,13 +1274,13 @@ const useReward = (elementId, animationType, config) => {
|
|
2408
1274
|
}
|
2409
1275
|
return particle;
|
2410
1276
|
});
|
2411
|
-
// Render particles
|
2412
|
-
if (rootRef.current) {
|
1277
|
+
// Render particles (skip rendering on mobile for some frames)
|
1278
|
+
if (rootRef.current && !skipFrame) {
|
2413
1279
|
rootRef.current.render(React.createElement(React.Fragment, null, particlesRef.current
|
2414
1280
|
.filter((p) => p.life > 0)
|
2415
1281
|
.map((particle) => (React.createElement("div", { key: particle.id, style: createParticleStyle(particle, containerRect) }, animationHandler.renderParticle(particle))))));
|
2416
1282
|
}
|
2417
|
-
if (activeParticles > 0) {
|
1283
|
+
if (activeParticles > 0 && isTabVisible.current) {
|
2418
1284
|
animationFrameRef.current = requestAnimationFrame(updateParticles);
|
2419
1285
|
}
|
2420
1286
|
else {
|
@@ -2460,5 +1326,5 @@ const useReward = (elementId, animationType, config) => {
|
|
2460
1326
|
return { reward, isAnimating };
|
2461
1327
|
};
|
2462
1328
|
|
2463
|
-
export { emojiPresets, useReward };
|
1329
|
+
export { emojiPresets, isMobileDevice, optimizeConfigForMobile, useReward };
|
2464
1330
|
//# sourceMappingURL=index.esm.js.map
|