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/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, config || {});
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