react-native-confetti-reanimated 0.1.4 → 0.1.6
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/lib/commonjs/ConfettiParticle.js +46 -18
- package/lib/commonjs/ConfettiParticle.js.map +1 -1
- package/lib/module/ConfettiParticle.js +46 -18
- package/lib/module/ConfettiParticle.js.map +1 -1
- package/lib/typescript/ConfettiParticle.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/ConfettiParticle.tsx +46 -17
|
@@ -24,6 +24,7 @@ const ConfettiParticle = ({
|
|
|
24
24
|
const velX = (0, _reactNativeReanimated.useSharedValue)(particle.velocity.x);
|
|
25
25
|
const velY = (0, _reactNativeReanimated.useSharedValue)(particle.velocity.y);
|
|
26
26
|
const startTime = (0, _reactNativeReanimated.useSharedValue)(Date.now());
|
|
27
|
+
const lastFrameTime = (0, _reactNativeReanimated.useSharedValue)(Date.now());
|
|
27
28
|
const isComplete = (0, _reactNativeReanimated.useSharedValue)(false);
|
|
28
29
|
|
|
29
30
|
// Canvas-confetti realistic wobble and tilt variables
|
|
@@ -36,7 +37,9 @@ const ConfettiParticle = ({
|
|
|
36
37
|
const tick = (0, _reactNativeReanimated.useSharedValue)(0);
|
|
37
38
|
const totalTicks = (0, _reactNativeReanimated.useSharedValue)(Math.max(1, Math.round(config.ticks ?? config.tickDuration ?? duration / 1000 * 60)));
|
|
38
39
|
(0, _react.useEffect)(() => {
|
|
39
|
-
|
|
40
|
+
const now = Date.now();
|
|
41
|
+
startTime.value = now;
|
|
42
|
+
lastFrameTime.value = now;
|
|
40
43
|
tick.value = 0;
|
|
41
44
|
totalTicks.value = Math.max(1, Math.round(config.ticks ?? config.tickDuration ?? duration / 1000 * 60));
|
|
42
45
|
|
|
@@ -54,54 +57,79 @@ const ConfettiParticle = ({
|
|
|
54
57
|
(0, _reactNativeReanimated.cancelAnimation)(rotation);
|
|
55
58
|
(0, _reactNativeReanimated.cancelAnimation)(opacity);
|
|
56
59
|
};
|
|
57
|
-
}, [config.tickDuration, config.ticks, duration, onComplete, opacity, isComplete, startTime, totalTicks, translateX, translateY, rotation, tick]);
|
|
60
|
+
}, [config.tickDuration, config.ticks, duration, onComplete, opacity, isComplete, startTime, lastFrameTime, totalTicks, translateX, translateY, rotation, tick]);
|
|
58
61
|
|
|
59
62
|
// Real-time physics simulation using frame callback
|
|
60
|
-
|
|
63
|
+
// Frame-rate independent: uses deltaTime to ensure consistent speed across devices
|
|
64
|
+
(0, _reactNativeReanimated.useFrameCallback)(frameInfo => {
|
|
61
65
|
'worklet';
|
|
62
66
|
|
|
63
67
|
if (isComplete.value) {
|
|
64
68
|
return;
|
|
65
69
|
}
|
|
66
|
-
|
|
70
|
+
|
|
71
|
+
// Use frameInfo.timestamp for better performance (runs on UI thread)
|
|
72
|
+
// Fallback to Date.now() if timestamp not available
|
|
73
|
+
const currentTime = frameInfo?.timestamp ?? Date.now();
|
|
74
|
+
const elapsed = currentTime - startTime.value;
|
|
67
75
|
if (elapsed >= duration) {
|
|
68
76
|
isComplete.value = true;
|
|
69
77
|
return;
|
|
70
78
|
}
|
|
71
79
|
|
|
72
|
-
//
|
|
73
|
-
|
|
74
|
-
|
|
80
|
+
// Calculate deltaTime normalized to 60fps (16.67ms per frame)
|
|
81
|
+
// This ensures consistent animation speed regardless of device frame rate
|
|
82
|
+
// Use timeSincePreviousFrame if available, otherwise calculate manually
|
|
83
|
+
const frameDelta = frameInfo?.timeSincePreviousFrame ?? currentTime - lastFrameTime.value;
|
|
84
|
+
|
|
85
|
+
// Handle first frame or invalid deltas
|
|
86
|
+
if (frameDelta <= 0 || frameDelta > 1000) {
|
|
87
|
+
lastFrameTime.value = currentTime;
|
|
88
|
+
return; // Skip this frame
|
|
89
|
+
}
|
|
90
|
+
const deltaTime = frameDelta / 16.67;
|
|
91
|
+
lastFrameTime.value = currentTime;
|
|
92
|
+
|
|
93
|
+
// Clamp deltaTime to prevent large jumps (e.g., when app resumes from background)
|
|
94
|
+
// Max 2.0 means we allow up to 2x normal frame time (30fps equivalent)
|
|
95
|
+
const clampedDelta = Math.min(deltaTime, 2.0);
|
|
96
|
+
|
|
97
|
+
// Update position based on current velocity (scaled by deltaTime for frame-rate independence)
|
|
98
|
+
// Velocity is in pixels per frame at 60fps, so we scale by deltaTime
|
|
99
|
+
translateX.value += velX.value * clampedDelta;
|
|
100
|
+
translateY.value += velY.value * clampedDelta;
|
|
75
101
|
|
|
76
102
|
// Apply gravity (increases downward velocity) - realistic physics!
|
|
77
|
-
|
|
103
|
+
// Gravity is per frame at 60fps, so scale by deltaTime
|
|
104
|
+
velY.value += config.gravity * clampedDelta;
|
|
78
105
|
|
|
79
106
|
// Apply drift (horizontal wind)
|
|
80
|
-
velX.value += config.drift;
|
|
107
|
+
velX.value += config.drift * clampedDelta;
|
|
81
108
|
|
|
82
|
-
// Apply decay (air resistance)
|
|
83
|
-
velX.value *= config.decay;
|
|
84
|
-
velY.value *= config.decay;
|
|
109
|
+
// Apply decay (air resistance) - decay per frame, so raise to power of deltaTime
|
|
110
|
+
velX.value *= Math.pow(config.decay, clampedDelta);
|
|
111
|
+
velY.value *= Math.pow(config.decay, clampedDelta);
|
|
85
112
|
|
|
86
113
|
// Update rotation - ALL particles spin faster when moving fast, slower when slowing down
|
|
87
114
|
const speed = Math.sqrt(velX.value * velX.value + velY.value * velY.value);
|
|
88
115
|
const speedBoost = 1 + speed / 20;
|
|
89
|
-
rotation.value += particle.rotationVelocity * speedBoost;
|
|
116
|
+
rotation.value += particle.rotationVelocity * speedBoost * clampedDelta;
|
|
90
117
|
|
|
91
118
|
// Canvas-confetti wobble effect (creates side-to-side flutter)
|
|
92
|
-
wobble.value += wobbleSpeed.value;
|
|
119
|
+
wobble.value += wobbleSpeed.value * clampedDelta;
|
|
93
120
|
|
|
94
121
|
// Canvas-confetti tilt animation (creates 3D tumbling effect)
|
|
95
|
-
tiltAngle.value += 0.1;
|
|
122
|
+
tiltAngle.value += 0.1 * clampedDelta;
|
|
96
123
|
tiltSin.value = Math.sin(tiltAngle.value);
|
|
97
124
|
tiltCos.value = Math.cos(tiltAngle.value);
|
|
98
125
|
random.value = Math.random() + 2;
|
|
99
126
|
|
|
100
|
-
// Update tick for progressive opacity fade
|
|
101
|
-
|
|
127
|
+
// Update tick for progressive opacity fade (time-based, not frame-based)
|
|
128
|
+
// Use elapsed time instead of frame count for frame-rate independence
|
|
129
|
+
const progress = Math.min(1, elapsed / duration);
|
|
130
|
+
tick.value = progress * totalTicks.value;
|
|
102
131
|
|
|
103
132
|
// Canvas-confetti progressive fade: opacity decreases linearly over lifetime
|
|
104
|
-
const progress = Math.min(1, tick.value / totalTicks.value);
|
|
105
133
|
opacity.value = 1 - progress;
|
|
106
134
|
});
|
|
107
135
|
const animatedStyle = (0, _reactNativeReanimated.useAnimatedStyle)(() => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_react","_interopRequireWildcard","require","_reactNative","_reactNativeReanimated","_jsxRuntime","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","ConfettiParticle","particle","config","duration","onComplete","translateX","useSharedValue","translateY","rotation","opacity","velX","velocity","x","velY","y","startTime","Date","now","isComplete","wobble","Math","random","wobbleSpeed","min","tiltAngle","tiltSin","tiltCos","tick","totalTicks","max","round","ticks","tickDuration","useEffect","value","timer","setTimeout","clearTimeout","cancelAnimation","useFrameCallback","elapsed","gravity","drift","decay","speed","sqrt","speedBoost","rotationVelocity","sin","cos","progress","animatedStyle","useAnimatedStyle","wobbleX","scalar","wobbleY","x1","y1","x2","y2","scaleX","abs","scaleY","transform","rotate","renderShape","shape","size","width","jsx","View","style","styles","circle","height","backgroundColor","color","fontSize","Text","star","textShadowColor","children","container","left","top","exports","StyleSheet","create","position","borderRadius","textShadowOffset","textShadowRadius"],"sourceRoot":"../../src","sources":["ConfettiParticle.tsx"],"mappings":";;;;;;AAAA,IAAAA,MAAA,GAAAC,uBAAA,CAAAC,OAAA;AACA,IAAAC,YAAA,GAAAD,OAAA;AACA,IAAAE,sBAAA,GAAAH,uBAAA,CAAAC,OAAA;AAKiC,IAAAG,WAAA,GAAAH,OAAA;AAAA,SAAAD,wBAAAK,CAAA,EAAAC,CAAA,6BAAAC,OAAA,MAAAC,CAAA,OAAAD,OAAA,IAAAE,CAAA,OAAAF,OAAA,YAAAP,uBAAA,YAAAA,CAAAK,CAAA,EAAAC,CAAA,SAAAA,CAAA,IAAAD,CAAA,IAAAA,CAAA,CAAAK,UAAA,SAAAL,CAAA,MAAAM,CAAA,EAAAC,CAAA,EAAAC,CAAA,KAAAC,SAAA,QAAAC,OAAA,EAAAV,CAAA,iBAAAA,CAAA,uBAAAA,CAAA,yBAAAA,CAAA,SAAAQ,CAAA,MAAAF,CAAA,GAAAL,CAAA,GAAAG,CAAA,GAAAD,CAAA,QAAAG,CAAA,CAAAK,GAAA,CAAAX,CAAA,UAAAM,CAAA,CAAAM,GAAA,CAAAZ,CAAA,GAAAM,CAAA,CAAAO,GAAA,CAAAb,CAAA,EAAAQ,CAAA,gBAAAP,CAAA,IAAAD,CAAA,gBAAAC,CAAA,OAAAa,cAAA,CAAAC,IAAA,CAAAf,CAAA,EAAAC,CAAA,OAAAM,CAAA,IAAAD,CAAA,GAAAU,MAAA,CAAAC,cAAA,KAAAD,MAAA,CAAAE,wBAAA,CAAAlB,CAAA,EAAAC,CAAA,OAAAM,CAAA,CAAAK,GAAA,IAAAL,CAAA,CAAAM,GAAA,IAAAP,CAAA,CAAAE,CAAA,EAAAP,CAAA,EAAAM,CAAA,IAAAC,CAAA,CAAAP,CAAA,IAAAD,CAAA,CAAAC,CAAA,WAAAO,CAAA,KAAAR,CAAA,EAAAC,CAAA;AAU1B,MAAMkB,gBAAiC,GAAGA,CAAC;EAAEC,QAAQ;EAAEC,MAAM;EAAEC,QAAQ;EAAEC;AAAW,CAAC,KAAK;EAC/F,MAAMC,UAAU,GAAG,IAAAC,qCAAc,EAAC,CAAC,CAAC;EACpC,MAAMC,UAAU,GAAG,IAAAD,qCAAc,EAAC,CAAC,CAAC;EACpC,MAAME,QAAQ,GAAG,IAAAF,qCAAc,EAACL,QAAQ,CAACO,QAAQ,CAAC;EAClD,MAAMC,OAAO,GAAG,IAAAH,qCAAc,EAAC,CAAC,CAAC;;EAEjC;EACA,MAAMI,IAAI,GAAG,IAAAJ,qCAAc,EAACL,QAAQ,CAACU,QAAQ,CAACC,CAAC,CAAC;EAChD,MAAMC,IAAI,GAAG,IAAAP,qCAAc,EAACL,QAAQ,CAACU,QAAQ,CAACG,CAAC,CAAC;EAChD,MAAMC,SAAS,GAAG,IAAAT,qCAAc,EAACU,IAAI,CAACC,GAAG,CAAC,CAAC,CAAC;EAC5C,MAAMC,
|
|
1
|
+
{"version":3,"names":["_react","_interopRequireWildcard","require","_reactNative","_reactNativeReanimated","_jsxRuntime","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","ConfettiParticle","particle","config","duration","onComplete","translateX","useSharedValue","translateY","rotation","opacity","velX","velocity","x","velY","y","startTime","Date","now","lastFrameTime","isComplete","wobble","Math","random","wobbleSpeed","min","tiltAngle","tiltSin","tiltCos","tick","totalTicks","max","round","ticks","tickDuration","useEffect","value","timer","setTimeout","clearTimeout","cancelAnimation","useFrameCallback","frameInfo","currentTime","timestamp","elapsed","frameDelta","timeSincePreviousFrame","deltaTime","clampedDelta","gravity","drift","pow","decay","speed","sqrt","speedBoost","rotationVelocity","sin","cos","progress","animatedStyle","useAnimatedStyle","wobbleX","scalar","wobbleY","x1","y1","x2","y2","scaleX","abs","scaleY","transform","rotate","renderShape","shape","size","width","jsx","View","style","styles","circle","height","backgroundColor","color","fontSize","Text","star","textShadowColor","children","container","left","top","exports","StyleSheet","create","position","borderRadius","textShadowOffset","textShadowRadius"],"sourceRoot":"../../src","sources":["ConfettiParticle.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -19,6 +19,7 @@ export const ConfettiParticle = ({
|
|
|
19
19
|
const velX = useSharedValue(particle.velocity.x);
|
|
20
20
|
const velY = useSharedValue(particle.velocity.y);
|
|
21
21
|
const startTime = useSharedValue(Date.now());
|
|
22
|
+
const lastFrameTime = useSharedValue(Date.now());
|
|
22
23
|
const isComplete = useSharedValue(false);
|
|
23
24
|
|
|
24
25
|
// Canvas-confetti realistic wobble and tilt variables
|
|
@@ -31,7 +32,9 @@ export const ConfettiParticle = ({
|
|
|
31
32
|
const tick = useSharedValue(0);
|
|
32
33
|
const totalTicks = useSharedValue(Math.max(1, Math.round(config.ticks ?? config.tickDuration ?? duration / 1000 * 60)));
|
|
33
34
|
useEffect(() => {
|
|
34
|
-
|
|
35
|
+
const now = Date.now();
|
|
36
|
+
startTime.value = now;
|
|
37
|
+
lastFrameTime.value = now;
|
|
35
38
|
tick.value = 0;
|
|
36
39
|
totalTicks.value = Math.max(1, Math.round(config.ticks ?? config.tickDuration ?? duration / 1000 * 60));
|
|
37
40
|
|
|
@@ -49,54 +52,79 @@ export const ConfettiParticle = ({
|
|
|
49
52
|
cancelAnimation(rotation);
|
|
50
53
|
cancelAnimation(opacity);
|
|
51
54
|
};
|
|
52
|
-
}, [config.tickDuration, config.ticks, duration, onComplete, opacity, isComplete, startTime, totalTicks, translateX, translateY, rotation, tick]);
|
|
55
|
+
}, [config.tickDuration, config.ticks, duration, onComplete, opacity, isComplete, startTime, lastFrameTime, totalTicks, translateX, translateY, rotation, tick]);
|
|
53
56
|
|
|
54
57
|
// Real-time physics simulation using frame callback
|
|
55
|
-
|
|
58
|
+
// Frame-rate independent: uses deltaTime to ensure consistent speed across devices
|
|
59
|
+
useFrameCallback(frameInfo => {
|
|
56
60
|
'worklet';
|
|
57
61
|
|
|
58
62
|
if (isComplete.value) {
|
|
59
63
|
return;
|
|
60
64
|
}
|
|
61
|
-
|
|
65
|
+
|
|
66
|
+
// Use frameInfo.timestamp for better performance (runs on UI thread)
|
|
67
|
+
// Fallback to Date.now() if timestamp not available
|
|
68
|
+
const currentTime = frameInfo?.timestamp ?? Date.now();
|
|
69
|
+
const elapsed = currentTime - startTime.value;
|
|
62
70
|
if (elapsed >= duration) {
|
|
63
71
|
isComplete.value = true;
|
|
64
72
|
return;
|
|
65
73
|
}
|
|
66
74
|
|
|
67
|
-
//
|
|
68
|
-
|
|
69
|
-
|
|
75
|
+
// Calculate deltaTime normalized to 60fps (16.67ms per frame)
|
|
76
|
+
// This ensures consistent animation speed regardless of device frame rate
|
|
77
|
+
// Use timeSincePreviousFrame if available, otherwise calculate manually
|
|
78
|
+
const frameDelta = frameInfo?.timeSincePreviousFrame ?? currentTime - lastFrameTime.value;
|
|
79
|
+
|
|
80
|
+
// Handle first frame or invalid deltas
|
|
81
|
+
if (frameDelta <= 0 || frameDelta > 1000) {
|
|
82
|
+
lastFrameTime.value = currentTime;
|
|
83
|
+
return; // Skip this frame
|
|
84
|
+
}
|
|
85
|
+
const deltaTime = frameDelta / 16.67;
|
|
86
|
+
lastFrameTime.value = currentTime;
|
|
87
|
+
|
|
88
|
+
// Clamp deltaTime to prevent large jumps (e.g., when app resumes from background)
|
|
89
|
+
// Max 2.0 means we allow up to 2x normal frame time (30fps equivalent)
|
|
90
|
+
const clampedDelta = Math.min(deltaTime, 2.0);
|
|
91
|
+
|
|
92
|
+
// Update position based on current velocity (scaled by deltaTime for frame-rate independence)
|
|
93
|
+
// Velocity is in pixels per frame at 60fps, so we scale by deltaTime
|
|
94
|
+
translateX.value += velX.value * clampedDelta;
|
|
95
|
+
translateY.value += velY.value * clampedDelta;
|
|
70
96
|
|
|
71
97
|
// Apply gravity (increases downward velocity) - realistic physics!
|
|
72
|
-
|
|
98
|
+
// Gravity is per frame at 60fps, so scale by deltaTime
|
|
99
|
+
velY.value += config.gravity * clampedDelta;
|
|
73
100
|
|
|
74
101
|
// Apply drift (horizontal wind)
|
|
75
|
-
velX.value += config.drift;
|
|
102
|
+
velX.value += config.drift * clampedDelta;
|
|
76
103
|
|
|
77
|
-
// Apply decay (air resistance)
|
|
78
|
-
velX.value *= config.decay;
|
|
79
|
-
velY.value *= config.decay;
|
|
104
|
+
// Apply decay (air resistance) - decay per frame, so raise to power of deltaTime
|
|
105
|
+
velX.value *= Math.pow(config.decay, clampedDelta);
|
|
106
|
+
velY.value *= Math.pow(config.decay, clampedDelta);
|
|
80
107
|
|
|
81
108
|
// Update rotation - ALL particles spin faster when moving fast, slower when slowing down
|
|
82
109
|
const speed = Math.sqrt(velX.value * velX.value + velY.value * velY.value);
|
|
83
110
|
const speedBoost = 1 + speed / 20;
|
|
84
|
-
rotation.value += particle.rotationVelocity * speedBoost;
|
|
111
|
+
rotation.value += particle.rotationVelocity * speedBoost * clampedDelta;
|
|
85
112
|
|
|
86
113
|
// Canvas-confetti wobble effect (creates side-to-side flutter)
|
|
87
|
-
wobble.value += wobbleSpeed.value;
|
|
114
|
+
wobble.value += wobbleSpeed.value * clampedDelta;
|
|
88
115
|
|
|
89
116
|
// Canvas-confetti tilt animation (creates 3D tumbling effect)
|
|
90
|
-
tiltAngle.value += 0.1;
|
|
117
|
+
tiltAngle.value += 0.1 * clampedDelta;
|
|
91
118
|
tiltSin.value = Math.sin(tiltAngle.value);
|
|
92
119
|
tiltCos.value = Math.cos(tiltAngle.value);
|
|
93
120
|
random.value = Math.random() + 2;
|
|
94
121
|
|
|
95
|
-
// Update tick for progressive opacity fade
|
|
96
|
-
|
|
122
|
+
// Update tick for progressive opacity fade (time-based, not frame-based)
|
|
123
|
+
// Use elapsed time instead of frame count for frame-rate independence
|
|
124
|
+
const progress = Math.min(1, elapsed / duration);
|
|
125
|
+
tick.value = progress * totalTicks.value;
|
|
97
126
|
|
|
98
127
|
// Canvas-confetti progressive fade: opacity decreases linearly over lifetime
|
|
99
|
-
const progress = Math.min(1, tick.value / totalTicks.value);
|
|
100
128
|
opacity.value = 1 - progress;
|
|
101
129
|
});
|
|
102
130
|
const animatedStyle = useAnimatedStyle(() => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["React","useEffect","StyleSheet","Animated","useAnimatedStyle","useSharedValue","useFrameCallback","cancelAnimation","jsx","_jsx","ConfettiParticle","particle","config","duration","onComplete","translateX","translateY","rotation","opacity","velX","velocity","x","velY","y","startTime","Date","now","isComplete","wobble","Math","random","wobbleSpeed","min","tiltAngle","tiltSin","tiltCos","tick","totalTicks","max","round","ticks","tickDuration","value","timer","setTimeout","clearTimeout","elapsed","gravity","drift","decay","speed","sqrt","speedBoost","rotationVelocity","sin","cos","progress","animatedStyle","wobbleX","scalar","wobbleY","x1","y1","x2","y2","scaleX","abs","scaleY","transform","rotate","renderShape","shape","size","width","View","style","styles","circle","height","backgroundColor","color","fontSize","Text","star","textShadowColor","children","container","left","top","create","position","borderRadius","textShadowOffset","textShadowRadius"],"sourceRoot":"../../src","sources":["ConfettiParticle.tsx"],"mappings":";;AAAA,OAAOA,KAAK,IAAIC,SAAS,QAAQ,OAAO;AACxC,SAASC,UAAU,QAAQ,cAAc;AACzC,OAAOC,QAAQ,IACbC,gBAAgB,EAChBC,cAAc,EACdC,gBAAgB,EAChBC,eAAe,QACV,yBAAyB;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAUjC,OAAO,MAAMC,gBAAiC,GAAGA,CAAC;EAAEC,QAAQ;EAAEC,MAAM;EAAEC,QAAQ;EAAEC;AAAW,CAAC,KAAK;EAC/F,MAAMC,UAAU,GAAGV,cAAc,CAAC,CAAC,CAAC;EACpC,MAAMW,UAAU,GAAGX,cAAc,CAAC,CAAC,CAAC;EACpC,MAAMY,QAAQ,GAAGZ,cAAc,CAACM,QAAQ,CAACM,QAAQ,CAAC;EAClD,MAAMC,OAAO,GAAGb,cAAc,CAAC,CAAC,CAAC;;EAEjC;EACA,MAAMc,IAAI,GAAGd,cAAc,CAACM,QAAQ,CAACS,QAAQ,CAACC,CAAC,CAAC;EAChD,MAAMC,IAAI,GAAGjB,cAAc,CAACM,QAAQ,CAACS,QAAQ,CAACG,CAAC,CAAC;EAChD,MAAMC,SAAS,GAAGnB,cAAc,CAACoB,IAAI,CAACC,GAAG,CAAC,CAAC,CAAC;EAC5C,MAAMC,
|
|
1
|
+
{"version":3,"names":["React","useEffect","StyleSheet","Animated","useAnimatedStyle","useSharedValue","useFrameCallback","cancelAnimation","jsx","_jsx","ConfettiParticle","particle","config","duration","onComplete","translateX","translateY","rotation","opacity","velX","velocity","x","velY","y","startTime","Date","now","lastFrameTime","isComplete","wobble","Math","random","wobbleSpeed","min","tiltAngle","tiltSin","tiltCos","tick","totalTicks","max","round","ticks","tickDuration","value","timer","setTimeout","clearTimeout","frameInfo","currentTime","timestamp","elapsed","frameDelta","timeSincePreviousFrame","deltaTime","clampedDelta","gravity","drift","pow","decay","speed","sqrt","speedBoost","rotationVelocity","sin","cos","progress","animatedStyle","wobbleX","scalar","wobbleY","x1","y1","x2","y2","scaleX","abs","scaleY","transform","rotate","renderShape","shape","size","width","View","style","styles","circle","height","backgroundColor","color","fontSize","Text","star","textShadowColor","children","container","left","top","create","position","borderRadius","textShadowOffset","textShadowRadius"],"sourceRoot":"../../src","sources":["ConfettiParticle.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConfettiParticle.d.ts","sourceRoot":"","sources":["../../src/ConfettiParticle.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAoB,MAAM,OAAO,CAAC;AAQzC,OAAO,KAAK,EAAE,gBAAgB,IAAI,oBAAoB,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAExF,UAAU,KAAK;IACb,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,MAAM,EAAE,QAAQ,CAAC,cAAc,CAAC,CAAC;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;CACzB;AAED,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,KAAK,
|
|
1
|
+
{"version":3,"file":"ConfettiParticle.d.ts","sourceRoot":"","sources":["../../src/ConfettiParticle.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAoB,MAAM,OAAO,CAAC;AAQzC,OAAO,KAAK,EAAE,gBAAgB,IAAI,oBAAoB,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAExF,UAAU,KAAK;IACb,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,MAAM,EAAE,QAAQ,CAAC,cAAc,CAAC,CAAC;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;CACzB;AAED,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,KAAK,CA4O5C,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-confetti-reanimated",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "A high-performance confetti component for React Native using Reanimated 4, compatible with Expo",
|
|
5
5
|
"main": "lib/commonjs/index.js",
|
|
6
6
|
"module": "lib/module/index.js",
|
package/src/ConfettiParticle.tsx
CHANGED
|
@@ -25,6 +25,7 @@ export const ConfettiParticle: React.FC<Props> = ({ particle, config, duration,
|
|
|
25
25
|
const velX = useSharedValue(particle.velocity.x);
|
|
26
26
|
const velY = useSharedValue(particle.velocity.y);
|
|
27
27
|
const startTime = useSharedValue(Date.now());
|
|
28
|
+
const lastFrameTime = useSharedValue(Date.now());
|
|
28
29
|
const isComplete = useSharedValue(false);
|
|
29
30
|
|
|
30
31
|
// Canvas-confetti realistic wobble and tilt variables
|
|
@@ -40,7 +41,9 @@ export const ConfettiParticle: React.FC<Props> = ({ particle, config, duration,
|
|
|
40
41
|
);
|
|
41
42
|
|
|
42
43
|
useEffect(() => {
|
|
43
|
-
|
|
44
|
+
const now = Date.now();
|
|
45
|
+
startTime.value = now;
|
|
46
|
+
lastFrameTime.value = now;
|
|
44
47
|
tick.value = 0;
|
|
45
48
|
totalTicks.value = Math.max(
|
|
46
49
|
1,
|
|
@@ -70,6 +73,7 @@ export const ConfettiParticle: React.FC<Props> = ({ particle, config, duration,
|
|
|
70
73
|
opacity,
|
|
71
74
|
isComplete,
|
|
72
75
|
startTime,
|
|
76
|
+
lastFrameTime,
|
|
73
77
|
totalTicks,
|
|
74
78
|
translateX,
|
|
75
79
|
translateY,
|
|
@@ -78,52 +82,77 @@ export const ConfettiParticle: React.FC<Props> = ({ particle, config, duration,
|
|
|
78
82
|
]);
|
|
79
83
|
|
|
80
84
|
// Real-time physics simulation using frame callback
|
|
81
|
-
|
|
85
|
+
// Frame-rate independent: uses deltaTime to ensure consistent speed across devices
|
|
86
|
+
useFrameCallback((frameInfo) => {
|
|
82
87
|
'worklet';
|
|
83
88
|
|
|
84
89
|
if (isComplete.value) {
|
|
85
90
|
return;
|
|
86
91
|
}
|
|
87
92
|
|
|
88
|
-
|
|
93
|
+
// Use frameInfo.timestamp for better performance (runs on UI thread)
|
|
94
|
+
// Fallback to Date.now() if timestamp not available
|
|
95
|
+
const currentTime = frameInfo?.timestamp ?? Date.now();
|
|
96
|
+
const elapsed = currentTime - startTime.value;
|
|
89
97
|
if (elapsed >= duration) {
|
|
90
98
|
isComplete.value = true;
|
|
91
99
|
return;
|
|
92
100
|
}
|
|
93
101
|
|
|
94
|
-
//
|
|
95
|
-
|
|
96
|
-
|
|
102
|
+
// Calculate deltaTime normalized to 60fps (16.67ms per frame)
|
|
103
|
+
// This ensures consistent animation speed regardless of device frame rate
|
|
104
|
+
// Use timeSincePreviousFrame if available, otherwise calculate manually
|
|
105
|
+
const frameDelta = frameInfo?.timeSincePreviousFrame ?? (currentTime - lastFrameTime.value);
|
|
106
|
+
|
|
107
|
+
// Handle first frame or invalid deltas
|
|
108
|
+
if (frameDelta <= 0 || frameDelta > 1000) {
|
|
109
|
+
lastFrameTime.value = currentTime;
|
|
110
|
+
return; // Skip this frame
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const deltaTime = frameDelta / 16.67;
|
|
114
|
+
lastFrameTime.value = currentTime;
|
|
115
|
+
|
|
116
|
+
// Clamp deltaTime to prevent large jumps (e.g., when app resumes from background)
|
|
117
|
+
// Max 2.0 means we allow up to 2x normal frame time (30fps equivalent)
|
|
118
|
+
const clampedDelta = Math.min(deltaTime, 2.0);
|
|
119
|
+
|
|
120
|
+
// Update position based on current velocity (scaled by deltaTime for frame-rate independence)
|
|
121
|
+
// Velocity is in pixels per frame at 60fps, so we scale by deltaTime
|
|
122
|
+
translateX.value += velX.value * clampedDelta;
|
|
123
|
+
translateY.value += velY.value * clampedDelta;
|
|
97
124
|
|
|
98
125
|
// Apply gravity (increases downward velocity) - realistic physics!
|
|
99
|
-
|
|
126
|
+
// Gravity is per frame at 60fps, so scale by deltaTime
|
|
127
|
+
velY.value += config.gravity * clampedDelta;
|
|
100
128
|
|
|
101
129
|
// Apply drift (horizontal wind)
|
|
102
|
-
velX.value += config.drift;
|
|
130
|
+
velX.value += config.drift * clampedDelta;
|
|
103
131
|
|
|
104
|
-
// Apply decay (air resistance)
|
|
105
|
-
velX.value *= config.decay;
|
|
106
|
-
velY.value *= config.decay;
|
|
132
|
+
// Apply decay (air resistance) - decay per frame, so raise to power of deltaTime
|
|
133
|
+
velX.value *= Math.pow(config.decay, clampedDelta);
|
|
134
|
+
velY.value *= Math.pow(config.decay, clampedDelta);
|
|
107
135
|
|
|
108
136
|
// Update rotation - ALL particles spin faster when moving fast, slower when slowing down
|
|
109
137
|
const speed = Math.sqrt(velX.value * velX.value + velY.value * velY.value);
|
|
110
138
|
const speedBoost = 1 + speed / 20;
|
|
111
|
-
rotation.value += particle.rotationVelocity * speedBoost;
|
|
139
|
+
rotation.value += particle.rotationVelocity * speedBoost * clampedDelta;
|
|
112
140
|
|
|
113
141
|
// Canvas-confetti wobble effect (creates side-to-side flutter)
|
|
114
|
-
wobble.value += wobbleSpeed.value;
|
|
142
|
+
wobble.value += wobbleSpeed.value * clampedDelta;
|
|
115
143
|
|
|
116
144
|
// Canvas-confetti tilt animation (creates 3D tumbling effect)
|
|
117
|
-
tiltAngle.value += 0.1;
|
|
145
|
+
tiltAngle.value += 0.1 * clampedDelta;
|
|
118
146
|
tiltSin.value = Math.sin(tiltAngle.value);
|
|
119
147
|
tiltCos.value = Math.cos(tiltAngle.value);
|
|
120
148
|
random.value = Math.random() + 2;
|
|
121
149
|
|
|
122
|
-
// Update tick for progressive opacity fade
|
|
123
|
-
|
|
150
|
+
// Update tick for progressive opacity fade (time-based, not frame-based)
|
|
151
|
+
// Use elapsed time instead of frame count for frame-rate independence
|
|
152
|
+
const progress = Math.min(1, elapsed / duration);
|
|
153
|
+
tick.value = progress * totalTicks.value;
|
|
124
154
|
|
|
125
155
|
// Canvas-confetti progressive fade: opacity decreases linearly over lifetime
|
|
126
|
-
const progress = Math.min(1, tick.value / totalTicks.value);
|
|
127
156
|
opacity.value = 1 - progress;
|
|
128
157
|
});
|
|
129
158
|
|