@shohojdhara/atomix 0.4.8 → 0.5.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.
Files changed (177) hide show
  1. package/atomix.config.ts +58 -1
  2. package/dist/atomix.css +148 -120
  3. package/dist/atomix.css.map +1 -1
  4. package/dist/atomix.min.css +1 -1
  5. package/dist/atomix.min.css.map +1 -1
  6. package/dist/charts.d.ts +33 -0
  7. package/dist/charts.js +1227 -122
  8. package/dist/charts.js.map +1 -1
  9. package/dist/core.d.ts +33 -10
  10. package/dist/core.js +1052 -41
  11. package/dist/core.js.map +1 -1
  12. package/dist/forms.d.ts +33 -0
  13. package/dist/forms.js +2086 -1035
  14. package/dist/forms.js.map +1 -1
  15. package/dist/heavy.d.ts +42 -1
  16. package/dist/heavy.js +1620 -600
  17. package/dist/heavy.js.map +1 -1
  18. package/dist/index.d.ts +441 -270
  19. package/dist/index.esm.js +1900 -638
  20. package/dist/index.esm.js.map +1 -1
  21. package/dist/index.js +1935 -670
  22. package/dist/index.js.map +1 -1
  23. package/dist/index.min.js +1 -1
  24. package/dist/index.min.js.map +1 -1
  25. package/package.json +6 -3
  26. package/scripts/atomix-cli.js +148 -4
  27. package/scripts/cli/__tests__/basic.test.js +3 -2
  28. package/scripts/cli/__tests__/clean.test.js +278 -0
  29. package/scripts/cli/__tests__/component-validator.test.js +433 -0
  30. package/scripts/cli/__tests__/generator.test.js +613 -0
  31. package/scripts/cli/__tests__/glass-motion.test.js +256 -0
  32. package/scripts/cli/__tests__/integration.test.js +719 -108
  33. package/scripts/cli/__tests__/migrate.test.js +74 -0
  34. package/scripts/cli/__tests__/security.test.js +206 -0
  35. package/scripts/cli/__tests__/test-setup.js +3 -1
  36. package/scripts/cli/__tests__/theme-bridge.test.js +507 -0
  37. package/scripts/cli/__tests__/token-provider.test.js +361 -0
  38. package/scripts/cli/__tests__/utils.test.js +5 -5
  39. package/scripts/cli/commands/benchmark.js +105 -0
  40. package/scripts/cli/commands/build-theme.js +4 -1
  41. package/scripts/cli/commands/clean.js +109 -0
  42. package/scripts/cli/commands/doctor.js +88 -0
  43. package/scripts/cli/commands/generate.js +135 -14
  44. package/scripts/cli/commands/init.js +45 -18
  45. package/scripts/cli/commands/migrate.js +106 -0
  46. package/scripts/cli/commands/sync-tokens.js +206 -0
  47. package/scripts/cli/commands/theme-bridge.js +248 -0
  48. package/scripts/cli/commands/tokens.js +157 -0
  49. package/scripts/cli/commands/validate.js +194 -0
  50. package/scripts/cli/internal/ai-engine.js +156 -0
  51. package/scripts/cli/internal/component-validator.js +443 -0
  52. package/scripts/cli/internal/config-loader.js +162 -0
  53. package/scripts/cli/internal/filesystem.js +102 -2
  54. package/scripts/cli/internal/generator.js +359 -39
  55. package/scripts/cli/internal/glass-generator.js +398 -0
  56. package/scripts/cli/internal/hook-generator.js +369 -0
  57. package/scripts/cli/internal/hooks.js +61 -0
  58. package/scripts/cli/internal/itcss-generator.js +565 -0
  59. package/scripts/cli/internal/motion-generator.js +679 -0
  60. package/scripts/cli/internal/template-engine.js +301 -0
  61. package/scripts/cli/internal/theme-bridge.js +664 -0
  62. package/scripts/cli/internal/tokens/engine.js +122 -0
  63. package/scripts/cli/internal/tokens/provider.js +34 -0
  64. package/scripts/cli/internal/tokens/providers/figma.js +50 -0
  65. package/scripts/cli/internal/tokens/providers/style-dictionary.js +48 -0
  66. package/scripts/cli/internal/tokens/providers/w3c.js +48 -0
  67. package/scripts/cli/internal/tokens/token-provider.js +443 -0
  68. package/scripts/cli/internal/tokens/token-validator.js +513 -0
  69. package/scripts/cli/internal/validator.js +276 -0
  70. package/scripts/cli/internal/wizard.js +60 -6
  71. package/scripts/cli/mappings.js +23 -0
  72. package/scripts/cli/migration-tools.js +164 -94
  73. package/scripts/cli/plugins/style-dictionary.js +46 -0
  74. package/scripts/cli/templates/README.md +525 -95
  75. package/scripts/cli/templates/common-templates.js +40 -14
  76. package/scripts/cli/templates/components/react-component.ts +282 -0
  77. package/scripts/cli/templates/config/project-config.ts +112 -0
  78. package/scripts/cli/templates/hooks/use-component.ts +477 -0
  79. package/scripts/cli/templates/index.js +19 -4
  80. package/scripts/cli/templates/index.ts +171 -0
  81. package/scripts/cli/templates/next-templates.js +72 -0
  82. package/scripts/cli/templates/react-templates.js +70 -126
  83. package/scripts/cli/templates/scss-templates.js +35 -35
  84. package/scripts/cli/templates/stories/storybook-story.ts +241 -0
  85. package/scripts/cli/templates/styles/scss-component.ts +255 -0
  86. package/scripts/cli/templates/tests/vitest-test.ts +229 -0
  87. package/scripts/cli/templates/token-templates.js +337 -1
  88. package/scripts/cli/templates/tokens/token-generators.ts +1088 -0
  89. package/scripts/cli/templates/types/component-types.ts +145 -0
  90. package/scripts/cli/templates/utils/testing-utils.ts +144 -0
  91. package/scripts/cli/templates/vanilla-templates.js +39 -0
  92. package/scripts/cli/token-manager.js +8 -2
  93. package/scripts/cli/utils/cache-manager.js +240 -0
  94. package/scripts/cli/utils/detector.js +46 -0
  95. package/scripts/cli/utils/diagnostics.js +289 -0
  96. package/scripts/cli/utils/error.js +45 -3
  97. package/scripts/cli/utils/helpers.js +24 -0
  98. package/scripts/cli/utils/logger.js +1 -1
  99. package/scripts/cli/utils/security.js +302 -0
  100. package/scripts/cli/utils/telemetry.js +115 -0
  101. package/scripts/cli/utils/validation.js +4 -38
  102. package/scripts/cli/utils.js +46 -0
  103. package/src/components/Accordion/Accordion.stories.tsx +0 -18
  104. package/src/components/Accordion/Accordion.test.tsx +0 -17
  105. package/src/components/Accordion/Accordion.tsx +0 -4
  106. package/src/components/AtomixGlass/AtomixGlass.tsx +102 -2
  107. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +125 -12
  108. package/src/components/AtomixGlass/PerformanceDashboard.tsx +219 -0
  109. package/src/components/AtomixGlass/README.md +25 -10
  110. package/src/components/AtomixGlass/animation-system.ts +578 -0
  111. package/src/components/AtomixGlass/shader-utils.ts +3 -0
  112. package/src/components/AtomixGlass/stories/AnimationFeatures.stories.tsx +653 -0
  113. package/src/components/AtomixGlass/stories/AnimationTests.stories.tsx +95 -0
  114. package/src/components/AtomixGlass/stories/CardExamples.stories.tsx +212 -0
  115. package/src/components/AtomixGlass/stories/DashboardExamples.stories.tsx +348 -0
  116. package/src/components/AtomixGlass/stories/EcommerceExamples.stories.tsx +410 -0
  117. package/src/components/AtomixGlass/stories/FormExamples.stories.tsx +436 -0
  118. package/src/components/AtomixGlass/stories/HeroExamples.stories.tsx +264 -0
  119. package/src/components/AtomixGlass/stories/InteractivePlayground.stories.tsx +247 -0
  120. package/src/components/AtomixGlass/stories/MobileUIExamples.stories.tsx +418 -0
  121. package/src/components/AtomixGlass/stories/ModalExamples.stories.tsx +402 -0
  122. package/src/components/AtomixGlass/stories/Overview.stories.tsx +157 -6
  123. package/src/components/AtomixGlass/stories/Playground.stories.tsx +658 -93
  124. package/src/components/AtomixGlass/stories/PresetGallery.stories.tsx +335 -0
  125. package/src/components/AtomixGlass/stories/WidgetExamples.stories.tsx +441 -0
  126. package/src/components/AtomixGlass/stories/argTypes.ts +384 -0
  127. package/src/components/AtomixGlass/stories/shared-components.tsx +91 -1
  128. package/src/components/AtomixGlass/stories/types.ts +127 -0
  129. package/src/components/Avatar/Avatar.tsx +1 -1
  130. package/src/components/Button/Button.stories.disabled-link.tsx +10 -0
  131. package/src/components/Button/Button.stories.tsx +10 -0
  132. package/src/components/Button/Button.test.tsx +16 -11
  133. package/src/components/Button/Button.tsx +4 -4
  134. package/src/components/Card/Card.tsx +1 -1
  135. package/src/components/Dropdown/Dropdown.tsx +12 -12
  136. package/src/components/Form/Select.tsx +62 -3
  137. package/src/components/Modal/Modal.tsx +14 -3
  138. package/src/components/Navigation/Navbar/Navbar.tsx +44 -0
  139. package/src/components/Slider/Slider.stories.tsx +3 -3
  140. package/src/components/Slider/Slider.tsx +38 -0
  141. package/src/components/Steps/Steps.tsx +3 -3
  142. package/src/components/Tabs/Tabs.tsx +77 -8
  143. package/src/components/Testimonial/Testimonial.tsx +1 -1
  144. package/src/components/TypedButton/TypedButton.stories.tsx +59 -0
  145. package/src/components/TypedButton/TypedButton.tsx +39 -0
  146. package/src/components/TypedButton/index.ts +2 -0
  147. package/src/components/VideoPlayer/VideoPlayer.tsx +11 -4
  148. package/src/lib/composables/index.ts +4 -7
  149. package/src/lib/composables/types.ts +45 -0
  150. package/src/lib/composables/useAccordion.ts +0 -7
  151. package/src/lib/composables/useAtomixGlass.ts +144 -5
  152. package/src/lib/composables/useChartExport.ts +3 -13
  153. package/src/lib/composables/useDropdown.ts +66 -0
  154. package/src/lib/composables/useFocusTrap.ts +80 -0
  155. package/src/lib/composables/usePerformanceMonitor.ts +448 -0
  156. package/src/lib/composables/useResponsiveGlass.presets.ts +192 -0
  157. package/src/lib/composables/useResponsiveGlass.ts +441 -0
  158. package/src/lib/composables/useTooltip.ts +16 -0
  159. package/src/lib/composables/useTypedButton.ts +66 -0
  160. package/src/lib/config/index.ts +62 -5
  161. package/src/lib/constants/components.ts +55 -0
  162. package/src/lib/theme/devtools/__tests__/useHistory.test.tsx +150 -0
  163. package/src/lib/theme/tokens/centralized-tokens.ts +120 -0
  164. package/src/lib/theme/utils/__tests__/domUtils.test.ts +101 -0
  165. package/src/lib/types/components.ts +37 -11
  166. package/src/lib/types/glass.ts +35 -0
  167. package/src/lib/types/index.ts +1 -0
  168. package/src/lib/utils/displacement-generator.ts +1 -1
  169. package/src/styles/01-settings/_settings.testtypecheck.scss +53 -0
  170. package/src/styles/01-settings/_settings.typedbutton.scss +53 -0
  171. package/src/styles/06-components/_components.testbutton.scss +212 -0
  172. package/src/styles/06-components/_components.testtypecheck.scss +212 -0
  173. package/src/styles/06-components/_components.typedbutton.scss +212 -0
  174. package/src/styles/99-utilities/_index.scss +1 -0
  175. package/src/styles/99-utilities/_utilities.text.scss +1 -1
  176. package/src/styles/99-utilities/_utilities.touch-target.scss +36 -0
  177. package/src/styles/06-components/old.chart.styles.scss +0 -2788
@@ -0,0 +1,448 @@
1
+ import { useState, useEffect, useCallback, useRef } from 'react';
2
+
3
+ /**
4
+ * Performance metrics collected by the monitor
5
+ */
6
+ export interface PerformanceMetrics {
7
+ /** Frames per second (target: 60) */
8
+ fps: number;
9
+
10
+ /** Time to render last frame in milliseconds (target: <16ms) */
11
+ frameTime: number;
12
+
13
+ /** GPU memory usage in MB (if available, target: <50MB) */
14
+ gpuMemory: number | null;
15
+
16
+ /** Current quality level based on performance */
17
+ qualityLevel: 'low' | 'medium' | 'high';
18
+
19
+ /** Timestamp of last measurement */
20
+ timestamp: number;
21
+
22
+ /** Whether auto-scaling is active */
23
+ isAutoScaling: boolean;
24
+
25
+ /** Number of consecutive low-FPS frames */
26
+ lowFpsCount: number;
27
+ }
28
+
29
+ /**
30
+ * Configuration for performance monitor
31
+ */
32
+ export interface PerformanceMonitorConfig {
33
+ /** Enable/disable monitoring */
34
+ enabled?: boolean;
35
+
36
+ /** Target FPS for auto-scaling (default: 60) */
37
+ targetFps?: number;
38
+
39
+ /** Minimum acceptable FPS before scaling down (default: 45) */
40
+ minFps?: number;
41
+
42
+ /** FPS threshold to scale up (default: 58) */
43
+ scaleUpThreshold?: number;
44
+
45
+ /** Consecutive low-FPS frames before scaling down (default: 3) */
46
+ lowFpsFrames?: number;
47
+
48
+ /** Consecutive high-FPS frames before scaling up (default: 10) */
49
+ highFpsFrames?: number;
50
+
51
+ /** Enable debug logging */
52
+ debug?: boolean;
53
+
54
+ /** Show debug overlay on screen */
55
+ showOverlay?: boolean;
56
+ }
57
+
58
+ /**
59
+ * Return value from performance monitor hook
60
+ */
61
+ export interface UsePerformanceMonitorReturn {
62
+ /** Current performance metrics */
63
+ metrics: PerformanceMetrics;
64
+
65
+ /** Recommended quality level based on performance */
66
+ recommendedQuality: 'low' | 'medium' | 'high';
67
+
68
+ /** Whether performance is below target */
69
+ isUnderperforming: boolean;
70
+
71
+ /** Manually set quality level */
72
+ setQualityLevel: (level: 'low' | 'medium' | 'high') => void;
73
+
74
+ /** Reset auto-scaling state */
75
+ resetAutoScaling: () => void;
76
+
77
+ /** Toggle monitoring on/off */
78
+ toggleMonitoring: () => void;
79
+ }
80
+
81
+ /**
82
+ * Get GPU memory info if available (Chrome DevTools only)
83
+ */
84
+ const getGpuMemoryInfo = (): Promise<number | null> => {
85
+ return new Promise((resolve) => {
86
+ // Check for WebGL debug renderer info
87
+ if (typeof window !== 'undefined' && typeof document !== 'undefined') {
88
+ try {
89
+ const canvas = document.createElement('canvas');
90
+ const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
91
+
92
+ if (gl) {
93
+ const debugInfo = (gl as any).getExtension('WEBGL_debug_renderer_info');
94
+ if (debugInfo) {
95
+ // Note: Actual memory info is not directly available via WebGL
96
+ // We estimate based on renderer
97
+ const glContext = gl as WebGLRenderingContext;
98
+ const renderer = glContext.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL);
99
+
100
+ // Rough estimation based on renderer type
101
+ if (renderer?.includes('Integrated')) {
102
+ resolve(256); // Integrated graphics typically share system RAM
103
+ } else if (renderer?.includes('AMD') || renderer?.includes('NVIDIA')) {
104
+ resolve(512); // Dedicated GPU
105
+ } else {
106
+ resolve(null); // Unknown
107
+ }
108
+ return;
109
+ }
110
+ }
111
+ } catch (e) {
112
+ // WebGL not available or error occurred
113
+ }
114
+ }
115
+ resolve(null);
116
+ });
117
+ };
118
+
119
+ /**
120
+ * Calculate optimal quality level based on FPS
121
+ */
122
+ const calculateQualityLevel = (fps: number, currentQuality: 'low' | 'medium' | 'high'): 'low' | 'medium' | 'high' => {
123
+ if (fps >= 58) {
124
+ return 'high';
125
+ } else if (fps >= 45) {
126
+ return currentQuality === 'high' ? 'high' : 'medium';
127
+ } else {
128
+ return 'low';
129
+ }
130
+ };
131
+
132
+ /**
133
+ * Performance Monitor Hook
134
+ *
135
+ * Real-time performance tracking with automatic quality scaling.
136
+ * Monitors FPS, frame time, and GPU memory to optimize glass effects.
137
+ *
138
+ * Features:
139
+ * - Real-time FPS measurement
140
+ * - Frame timing analysis
141
+ * - Automatic quality scaling
142
+ * - Debug overlay option
143
+ * - Manual override capability
144
+ *
145
+ * @example
146
+ * ```typescript
147
+ * const { metrics, recommendedQuality, setQualityLevel } = usePerformanceMonitor({
148
+ * targetFps: 60,
149
+ * minFps: 45,
150
+ * debug: true,
151
+ * });
152
+ * ```
153
+ *
154
+ * @param config Monitor configuration
155
+ * @returns Performance metrics and controls
156
+ */
157
+ export function usePerformanceMonitor(
158
+ config: PerformanceMonitorConfig = {}
159
+ ): UsePerformanceMonitorReturn {
160
+ const {
161
+ enabled = true,
162
+ targetFps = 60,
163
+ minFps = 45,
164
+ scaleUpThreshold = 58,
165
+ lowFpsFrames = 3,
166
+ highFpsFrames = 10,
167
+ debug = false,
168
+ showOverlay = false,
169
+ } = config;
170
+
171
+ const [metrics, setMetrics] = useState<PerformanceMetrics>({
172
+ fps: 0,
173
+ frameTime: 0,
174
+ gpuMemory: null,
175
+ qualityLevel: 'medium',
176
+ timestamp: 0,
177
+ isAutoScaling: true,
178
+ lowFpsCount: 0,
179
+ });
180
+
181
+ const [manualOverride, setManualOverride] = useState(false);
182
+ const [isEnabled, setIsEnabled] = useState(enabled);
183
+
184
+ // Refs for frame tracking
185
+ const frameCountRef = useRef(0);
186
+ const lastFpsUpdateRef = useRef(0);
187
+ const lastFrameTimeRef = useRef(0);
188
+ const animationFrameRef = useRef<number | null>(null);
189
+ const lowFpsCountRef = useRef(0);
190
+ const highFpsCountRef = useRef(0);
191
+ const qualityLevelRef = useRef<'low' | 'medium' | 'high'>('medium');
192
+
193
+ /**
194
+ * Update metrics state
195
+ */
196
+ const updateMetrics = useCallback((newMetrics: Partial<PerformanceMetrics>) => {
197
+ setMetrics(prev => ({
198
+ ...prev,
199
+ ...newMetrics,
200
+ timestamp: performance.now(),
201
+ }));
202
+ }, []);
203
+
204
+ /**
205
+ * Auto-scaling logic
206
+ */
207
+ const applyAutoScaling = useCallback((currentFps: number) => {
208
+ if (manualOverride) return;
209
+
210
+ const currentQuality = qualityLevelRef.current;
211
+
212
+ // Check for low FPS
213
+ if (currentFps < minFps) {
214
+ lowFpsCountRef.current++;
215
+ highFpsCountRef.current = 0;
216
+
217
+ // Scale down after N consecutive low-FPS frames
218
+ if (lowFpsCountRef.current >= lowFpsFrames && currentQuality !== 'low') {
219
+ qualityLevelRef.current = 'low';
220
+ updateMetrics({ qualityLevel: 'low', lowFpsCount: lowFpsCountRef.current });
221
+
222
+ if (debug) {
223
+ console.log('[PerformanceMonitor] Scaling down to LOW quality. FPS:', currentFps);
224
+ }
225
+ }
226
+ }
227
+ // Check for high FPS
228
+ else if (currentFps >= scaleUpThreshold) {
229
+ highFpsCountRef.current++;
230
+ lowFpsCountRef.current = 0;
231
+
232
+ // Scale up after N consecutive high-FPS frames
233
+ if (highFpsCountRef.current >= highFpsFrames) {
234
+ const newQuality = currentQuality === 'low' ? 'medium' : 'high';
235
+ qualityLevelRef.current = newQuality;
236
+ updateMetrics({ qualityLevel: newQuality, lowFpsCount: 0 });
237
+
238
+ if (debug) {
239
+ console.log('[PerformanceMonitor] Scaling up to', newQuality.toUpperCase(), 'quality. FPS:', currentFps);
240
+ }
241
+
242
+ highFpsCountRef.current = 0;
243
+ }
244
+ } else {
245
+ // FPS in normal range, reset counters
246
+ lowFpsCountRef.current = 0;
247
+ highFpsCountRef.current = 0;
248
+ }
249
+ }, [manualOverride, minFps, scaleUpThreshold, lowFpsFrames, highFpsFrames, debug, updateMetrics]);
250
+
251
+ /**
252
+ * Animation frame handler - measures performance
253
+ */
254
+ const measureFrame = useCallback((currentTime: number) => {
255
+ if (!isEnabled) return;
256
+
257
+ frameCountRef.current++;
258
+
259
+ // Calculate frame time
260
+ const frameTime = currentTime - lastFrameTimeRef.current;
261
+ lastFrameTimeRef.current = currentTime;
262
+
263
+ // Update FPS every 100ms for responsiveness
264
+ if (currentTime - lastFpsUpdateRef.current >= 100) {
265
+ const elapsed = currentTime - lastFpsUpdateRef.current;
266
+ const fps = Math.round((frameCountRef.current * 1000) / elapsed);
267
+
268
+ // Apply auto-scaling
269
+ applyAutoScaling(fps);
270
+
271
+ updateMetrics({
272
+ fps,
273
+ frameTime,
274
+ qualityLevel: qualityLevelRef.current,
275
+ lowFpsCount: lowFpsCountRef.current,
276
+ });
277
+
278
+ // Reset for next measurement period
279
+ frameCountRef.current = 0;
280
+ lastFpsUpdateRef.current = currentTime;
281
+ }
282
+
283
+ // Continue measurement loop
284
+ animationFrameRef.current = requestAnimationFrame(measureFrame);
285
+ }, [isEnabled, applyAutoScaling, updateMetrics]);
286
+
287
+ /**
288
+ * Initialize GPU memory tracking
289
+ */
290
+ useEffect(() => {
291
+ if (!isEnabled || typeof window === 'undefined') return;
292
+
293
+ let mounted = true;
294
+
295
+ const initGpuMemory = async () => {
296
+ const memory = await getGpuMemoryInfo();
297
+ if (mounted) {
298
+ updateMetrics({ gpuMemory: memory });
299
+ }
300
+ };
301
+
302
+ initGpuMemory();
303
+
304
+ return () => {
305
+ mounted = false;
306
+ };
307
+ }, [isEnabled, updateMetrics]);
308
+
309
+ /**
310
+ * Start/stop monitoring based on enabled state
311
+ */
312
+ useEffect(() => {
313
+ if (!isEnabled) {
314
+ if (animationFrameRef.current !== null) {
315
+ cancelAnimationFrame(animationFrameRef.current);
316
+ animationFrameRef.current = null;
317
+ }
318
+ return;
319
+ }
320
+
321
+ // Initialize
322
+ lastFpsUpdateRef.current = performance.now();
323
+ lastFrameTimeRef.current = performance.now();
324
+ animationFrameRef.current = requestAnimationFrame(measureFrame);
325
+
326
+ // Cleanup
327
+ return () => {
328
+ if (animationFrameRef.current !== null) {
329
+ cancelAnimationFrame(animationFrameRef.current);
330
+ animationFrameRef.current = null;
331
+ }
332
+ };
333
+ // eslint-disable-next-line react-hooks/exhaustive-deps
334
+ }, [isEnabled]); // measureFrame is stable via useCallback, avoid re-creating RAF loop
335
+
336
+ /**
337
+ * Manually set quality level (disables auto-scaling)
338
+ */
339
+ const setQualityLevel = useCallback((level: 'low' | 'medium' | 'high') => {
340
+ setManualOverride(true);
341
+ qualityLevelRef.current = level;
342
+ updateMetrics({ qualityLevel: level, isAutoScaling: false });
343
+
344
+ if (debug) {
345
+ console.log('[PerformanceMonitor] Manual quality override:', level);
346
+ }
347
+ }, [updateMetrics, debug]);
348
+
349
+ /**
350
+ * Reset to auto-scaling mode
351
+ */
352
+ const resetAutoScaling = useCallback(() => {
353
+ setManualOverride(false);
354
+ lowFpsCountRef.current = 0;
355
+ highFpsCountRef.current = 0;
356
+ updateMetrics({ isAutoScaling: true, lowFpsCount: 0 });
357
+
358
+ if (debug) {
359
+ console.log('[PerformanceMonitor] Auto-scaling reset');
360
+ }
361
+ }, [updateMetrics, debug]);
362
+
363
+ /**
364
+ * Toggle monitoring on/off
365
+ */
366
+ const toggleMonitoring = useCallback(() => {
367
+ setIsEnabled(prev => !prev);
368
+ }, []);
369
+
370
+ // Calculate derived values
371
+ const recommendedQuality = calculateQualityLevel(metrics.fps, metrics.qualityLevel);
372
+ const isUnderperforming = metrics.fps < minFps;
373
+
374
+ return {
375
+ metrics,
376
+ recommendedQuality,
377
+ isUnderperforming,
378
+ setQualityLevel,
379
+ resetAutoScaling,
380
+ toggleMonitoring,
381
+ };
382
+ }
383
+
384
+ /**
385
+ * Debug Overlay Component (Optional)
386
+ *
387
+ * Shows real-time performance metrics on screen.
388
+ * Only rendered when showOverlay is enabled.
389
+ */
390
+ export function PerformanceOverlay({ metrics }: { metrics: PerformanceMetrics }) {
391
+ if (typeof window === 'undefined') return null;
392
+
393
+ const overlayStyle: React.CSSProperties = {
394
+ position: 'fixed',
395
+ top: '10px',
396
+ right: '10px',
397
+ padding: '10px',
398
+ backgroundColor: 'rgba(0, 0, 0, 0.8)',
399
+ color: '#fff',
400
+ fontFamily: 'monospace',
401
+ fontSize: '12px',
402
+ borderRadius: '4px',
403
+ zIndex: 9999,
404
+ pointerEvents: 'none',
405
+ minWidth: '150px',
406
+ };
407
+
408
+ const getFpsColor = (fps: number) => {
409
+ if (fps >= 58) return '#4ade80'; // Green
410
+ if (fps >= 45) return '#fbbf24'; // Yellow
411
+ return '#ef4444'; // Red
412
+ };
413
+
414
+ // Performance overlay removed - will be implemented as separate component
415
+ return null;
416
+ }
417
+
418
+ /**
419
+ * Utility to get quality multipliers for glass parameters
420
+ */
421
+ export function getQualityMultipliers(quality: 'low' | 'medium' | 'high') {
422
+ switch (quality) {
423
+ case 'low':
424
+ return {
425
+ distortionOctaves: 2,
426
+ displacementScale: 0.6,
427
+ blurAmount: 0.7,
428
+ animationSpeed: 0.8,
429
+ chromaticIntensity: 0.5,
430
+ };
431
+ case 'medium':
432
+ return {
433
+ distortionOctaves: 4,
434
+ displacementScale: 0.85,
435
+ blurAmount: 0.9,
436
+ animationSpeed: 0.95,
437
+ chromaticIntensity: 0.75,
438
+ };
439
+ case 'high':
440
+ return {
441
+ distortionOctaves: 5,
442
+ displacementScale: 1.0,
443
+ blurAmount: 1.0,
444
+ animationSpeed: 1.0,
445
+ chromaticIntensity: 1.0,
446
+ };
447
+ }
448
+ }
@@ -0,0 +1,192 @@
1
+ import type { GlassParams, ResponsiveBreakpoint } from '../../lib/types/glass';
2
+
3
+ /**
4
+ * Mobile optimization presets
5
+ *
6
+ * These presets adjust glass effect parameters based on device performance tier
7
+ * to ensure smooth animations and responsive interactions.
8
+ */
9
+
10
+ /**
11
+ * Performance preset - Maximum FPS, reduced quality
12
+ * Best for low-end devices or when battery saving is priority
13
+ */
14
+ export const PERFORMANCE_PRESET: GlassParams = {
15
+ distortionOctaves: 2, // Minimal FBM layers
16
+ displacementScale: 50, // Subtle displacement
17
+ blurAmount: 5, // Light blur
18
+ saturation: 80, // Reduced saturation
19
+ aberrationIntensity: 0.3, // Minimal chromatic aberration
20
+ animationSpeed: 0.8, // Slightly slower for performance
21
+ chromaticIntensity: 0.3, // Low chromatic effect
22
+ distortionLacunarity: 1.5, // Simpler noise pattern
23
+ distortionGain: 0.3, // Lower gain for smoother effect
24
+ };
25
+
26
+ /**
27
+ * Balanced preset - Good quality with reasonable performance
28
+ * Default preset for most mobile devices
29
+ */
30
+ export const BALANCED_PRESET: GlassParams = {
31
+ distortionOctaves: 3, // Moderate FBM layers
32
+ displacementScale: 75, // Medium displacement
33
+ blurAmount: 8, // Moderate blur
34
+ saturation: 90, // Near-full saturation
35
+ aberrationIntensity: 0.5, // Moderate chromatic aberration
36
+ animationSpeed: 1.0, // Normal speed
37
+ chromaticIntensity: 0.5, // Moderate chromatic effect
38
+ distortionLacunarity: 2.0, // Standard noise pattern
39
+ distortionGain: 0.4, // Balanced gain
40
+ };
41
+
42
+ /**
43
+ * Quality preset - Maximum visual fidelity
44
+ * For high-end devices with powerful GPUs
45
+ */
46
+ export const QUALITY_PRESET: GlassParams = {
47
+ distortionOctaves: 4, // More FBM layers for detail
48
+ displacementScale: 100, // Stronger displacement
49
+ blurAmount: 12, // Smoother blur
50
+ saturation: 100, // Full saturation
51
+ aberrationIntensity: 0.7, // Pronounced chromatic aberration
52
+ animationSpeed: 1.2, // Slightly faster for drama
53
+ chromaticIntensity: 0.7, // Strong chromatic effect
54
+ distortionLacunarity: 2.2, // Richer noise pattern
55
+ distortionGain: 0.5, // Higher gain for more contrast
56
+ };
57
+
58
+ /**
59
+ * Get preset by name
60
+ */
61
+ export function getDevicePreset(presetName: 'performance' | 'balanced' | 'quality'): GlassParams {
62
+ switch (presetName) {
63
+ case 'performance':
64
+ return PERFORMANCE_PRESET;
65
+ case 'balanced':
66
+ return BALANCED_PRESET;
67
+ case 'quality':
68
+ return QUALITY_PRESET;
69
+ default:
70
+ return BALANCED_PRESET;
71
+ }
72
+ }
73
+
74
+ /**
75
+ * Mobile-optimized responsive breakpoints
76
+ * Automatically applies appropriate presets based on viewport size
77
+ */
78
+ export const MOBILE_OPTIMIZED_BREAKPOINTS: Record<string, ResponsiveBreakpoint> = {
79
+ /** Desktop - Full quality */
80
+ desktop: {
81
+ minWidth: 1024,
82
+ params: {
83
+ distortionOctaves: 6,
84
+ displacementScale: 150,
85
+ blurAmount: 15,
86
+ saturation: 100,
87
+ aberrationIntensity: 1.0,
88
+ animationSpeed: 1.0,
89
+ chromaticIntensity: 1.0,
90
+ distortionLacunarity: 2.5,
91
+ distortionGain: 0.6,
92
+ }
93
+ },
94
+
95
+ /** Laptop - High quality */
96
+ laptop: {
97
+ minWidth: 768,
98
+ params: {
99
+ ...QUALITY_PRESET,
100
+ distortionOctaves: 5,
101
+ displacementScale: 120,
102
+ }
103
+ },
104
+
105
+ /** Tablet - Balanced quality */
106
+ tablet: {
107
+ minWidth: 640,
108
+ params: {
109
+ ...BALANCED_PRESET,
110
+ distortionOctaves: 4,
111
+ displacementScale: 90,
112
+ }
113
+ },
114
+
115
+ /** Mobile - Performance optimized */
116
+ mobile: {
117
+ maxWidth: 639,
118
+ params: {
119
+ ...PERFORMANCE_PRESET,
120
+ distortionOctaves: 3,
121
+ displacementScale: 75,
122
+ blurAmount: 6,
123
+ }
124
+ },
125
+
126
+ /** Small mobile - Maximum performance */
127
+ mobileSmall: {
128
+ maxWidth: 375,
129
+ params: {
130
+ ...PERFORMANCE_PRESET,
131
+ distortionOctaves: 2,
132
+ displacementScale: 50,
133
+ blurAmount: 4,
134
+ saturation: 70,
135
+ }
136
+ },
137
+ };
138
+
139
+ /**
140
+ * Get mobile-optimized parameters for current viewport
141
+ * Can be used standalone or with useResponsiveGlass hook
142
+ */
143
+ export function getMobileOptimizedParams(viewportWidth: number): GlassParams {
144
+ if (viewportWidth >= 1024) {
145
+ return MOBILE_OPTIMIZED_BREAKPOINTS.desktop?.params || BALANCED_PRESET;
146
+ } else if (viewportWidth >= 768) {
147
+ return MOBILE_OPTIMIZED_BREAKPOINTS.laptop?.params || BALANCED_PRESET;
148
+ } else if (viewportWidth >= 640) {
149
+ return MOBILE_OPTIMIZED_BREAKPOINTS.tablet?.params || BALANCED_PRESET;
150
+ } else if (viewportWidth >= 375) {
151
+ return MOBILE_OPTIMIZED_BREAKPOINTS.mobile?.params || PERFORMANCE_PRESET;
152
+ } else {
153
+ return MOBILE_OPTIMIZED_BREAKPOINTS.mobileSmall?.params || PERFORMANCE_PRESET;
154
+ }
155
+ }
156
+
157
+ /**
158
+ * Device detection utilities
159
+ */
160
+ export const DeviceDetector = {
161
+ /** Check if device is mobile */
162
+ isMobile(): boolean {
163
+ if (typeof window === 'undefined') return false;
164
+ return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
165
+ },
166
+
167
+ /** Check if device is tablet */
168
+ isTablet(): boolean {
169
+ if (typeof window === 'undefined') return false;
170
+ const width = window.innerWidth;
171
+ return width >= 640 && width < 1024 && this.isMobile();
172
+ },
173
+
174
+ /** Get recommended preset based on device type */
175
+ getRecommendedPreset(): 'performance' | 'balanced' | 'quality' {
176
+ if (!this.isMobile()) return 'quality';
177
+ if (this.isTablet()) return 'balanced';
178
+ return 'performance';
179
+ },
180
+
181
+ /** Get device pixel ratio */
182
+ getPixelRatio(): number {
183
+ if (typeof window === 'undefined') return 1;
184
+ return window.devicePixelRatio || 1;
185
+ },
186
+
187
+ /** Check if device has touch support */
188
+ hasTouchSupport(): boolean {
189
+ if (typeof window === 'undefined') return false;
190
+ return 'ontouchstart' in window || navigator.maxTouchPoints > 0;
191
+ },
192
+ };