partycles 1.0.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/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/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 +58 -6
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +58 -4
- package/dist/index.js.map +1 -1
- package/dist/mobileOptimizations.d.ts +6 -0
- package/dist/mobileOptimizations.d.ts.map +1 -0
- package/dist/useReward.d.ts.map +1 -1
- package/package.json +13 -2
package/dist/index.js
CHANGED
@@ -1152,12 +1152,57 @@ const animations = {
|
|
1152
1152
|
},
|
1153
1153
|
};
|
1154
1154
|
|
1155
|
+
const isMobileDevice = () => {
|
1156
|
+
if (typeof window === 'undefined')
|
1157
|
+
return false;
|
1158
|
+
// Check user agent
|
1159
|
+
const userAgent = navigator.userAgent || navigator.vendor || window.opera;
|
1160
|
+
const isMobileUA = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent);
|
1161
|
+
// Check viewport width
|
1162
|
+
const isMobileWidth = window.innerWidth <= 768;
|
1163
|
+
// Check touch support
|
1164
|
+
const hasTouch = 'ontouchstart' in window || navigator.maxTouchPoints > 0;
|
1165
|
+
return isMobileUA || (isMobileWidth && hasTouch);
|
1166
|
+
};
|
1167
|
+
const optimizeConfigForMobile = (config) => {
|
1168
|
+
var _a, _b, _c;
|
1169
|
+
if (!isMobileDevice())
|
1170
|
+
return config;
|
1171
|
+
return Object.assign(Object.assign({}, config), {
|
1172
|
+
// Reduce particle count by 40%
|
1173
|
+
particleCount: Math.floor((config.particleCount || 50) * 0.6),
|
1174
|
+
// Reduce element size by 20%
|
1175
|
+
elementSize: Math.floor((config.elementSize || 20) * 0.8),
|
1176
|
+
// Reduce lifetime by 20%
|
1177
|
+
lifetime: Math.floor((config.lifetime || 150) * 0.8),
|
1178
|
+
// Simplify physics
|
1179
|
+
physics: Object.assign(Object.assign({}, config.physics), {
|
1180
|
+
// Reduce precision for mobile
|
1181
|
+
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 }) });
|
1182
|
+
};
|
1183
|
+
// Frame skipping for mobile
|
1184
|
+
const shouldSkipFrame = (frameCount) => {
|
1185
|
+
if (!isMobileDevice())
|
1186
|
+
return false;
|
1187
|
+
// Skip every 3rd frame on mobile
|
1188
|
+
return frameCount % 3 === 0;
|
1189
|
+
};
|
1190
|
+
|
1155
1191
|
const useReward = (elementId, animationType, config) => {
|
1156
1192
|
const [isAnimating, setIsAnimating] = React.useState(false);
|
1157
1193
|
const animationFrameRef = React.useRef();
|
1158
1194
|
const particlesRef = React.useRef([]);
|
1159
1195
|
const containerRef = React.useRef(null);
|
1160
1196
|
const rootRef = React.useRef(null);
|
1197
|
+
const isTabVisible = React.useRef(true);
|
1198
|
+
// Monitor tab visibility
|
1199
|
+
React.useEffect(() => {
|
1200
|
+
const handleVisibilityChange = () => {
|
1201
|
+
isTabVisible.current = !document.hidden;
|
1202
|
+
};
|
1203
|
+
document.addEventListener('visibilitychange', handleVisibilityChange);
|
1204
|
+
return () => document.removeEventListener('visibilitychange', handleVisibilityChange);
|
1205
|
+
}, []);
|
1161
1206
|
const animate = React.useCallback(() => {
|
1162
1207
|
var _a, _b, _c, _d, _e, _f;
|
1163
1208
|
const element = document.getElementById(elementId);
|
@@ -1173,8 +1218,10 @@ const useReward = (elementId, animationType, config) => {
|
|
1173
1218
|
console.error(`Animation type "${animationType}" not found`);
|
1174
1219
|
return;
|
1175
1220
|
}
|
1221
|
+
// Apply mobile performance optimizations
|
1222
|
+
const optimizedConfig = config ? optimizeConfigForMobile(config) : undefined;
|
1176
1223
|
// Create particles
|
1177
|
-
particlesRef.current = animationHandler.createParticles(origin,
|
1224
|
+
particlesRef.current = animationHandler.createParticles(origin, optimizedConfig || {});
|
1178
1225
|
// Create container
|
1179
1226
|
const container = document.createElement('div');
|
1180
1227
|
container.style.position = 'fixed';
|
@@ -1195,8 +1242,13 @@ const useReward = (elementId, animationType, config) => {
|
|
1195
1242
|
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;
|
1196
1243
|
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;
|
1197
1244
|
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;
|
1245
|
+
// Track frame count for mobile optimization
|
1246
|
+
let frameCount = 0;
|
1198
1247
|
const updateParticles = () => {
|
1199
1248
|
let activeParticles = 0;
|
1249
|
+
frameCount++;
|
1250
|
+
// Skip frame rendering on mobile to improve performance
|
1251
|
+
const skipFrame = shouldSkipFrame(frameCount);
|
1200
1252
|
particlesRef.current = particlesRef.current.map((particle) => {
|
1201
1253
|
if (particle.life <= 0)
|
1202
1254
|
return particle;
|
@@ -1224,13 +1276,13 @@ const useReward = (elementId, animationType, config) => {
|
|
1224
1276
|
}
|
1225
1277
|
return particle;
|
1226
1278
|
});
|
1227
|
-
// Render particles
|
1228
|
-
if (rootRef.current) {
|
1279
|
+
// Render particles (skip rendering on mobile for some frames)
|
1280
|
+
if (rootRef.current && !skipFrame) {
|
1229
1281
|
rootRef.current.render(React.createElement(React.Fragment, null, particlesRef.current
|
1230
1282
|
.filter((p) => p.life > 0)
|
1231
1283
|
.map((particle) => (React.createElement("div", { key: particle.id, style: createParticleStyle(particle, containerRect) }, animationHandler.renderParticle(particle))))));
|
1232
1284
|
}
|
1233
|
-
if (activeParticles > 0) {
|
1285
|
+
if (activeParticles > 0 && isTabVisible.current) {
|
1234
1286
|
animationFrameRef.current = requestAnimationFrame(updateParticles);
|
1235
1287
|
}
|
1236
1288
|
else {
|
@@ -1277,5 +1329,7 @@ const useReward = (elementId, animationType, config) => {
|
|
1277
1329
|
};
|
1278
1330
|
|
1279
1331
|
exports.emojiPresets = emojiPresets;
|
1332
|
+
exports.isMobileDevice = isMobileDevice;
|
1333
|
+
exports.optimizeConfigForMobile = optimizeConfigForMobile;
|
1280
1334
|
exports.useReward = useReward;
|
1281
1335
|
//# sourceMappingURL=index.js.map
|