@shohojdhara/atomix 0.4.8 → 0.4.9

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 (165) 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 +4 -1
  112. package/src/components/AtomixGlass/stories/Overview.stories.tsx +157 -6
  113. package/src/components/AtomixGlass/stories/Phase1-Animation.stories.tsx +653 -0
  114. package/src/components/AtomixGlass/stories/Phase1-Test.stories.tsx +95 -0
  115. package/src/components/AtomixGlass/stories/Playground.stories.tsx +51 -51
  116. package/src/components/AtomixGlass/stories/shared-components.tsx +6 -0
  117. package/src/components/Avatar/Avatar.tsx +1 -1
  118. package/src/components/Button/Button.stories.disabled-link.tsx +10 -0
  119. package/src/components/Button/Button.stories.tsx +10 -0
  120. package/src/components/Button/Button.test.tsx +16 -11
  121. package/src/components/Button/Button.tsx +4 -4
  122. package/src/components/Card/Card.tsx +1 -1
  123. package/src/components/Dropdown/Dropdown.tsx +12 -12
  124. package/src/components/Form/Select.tsx +62 -3
  125. package/src/components/Modal/Modal.tsx +14 -3
  126. package/src/components/Navigation/Navbar/Navbar.tsx +44 -0
  127. package/src/components/Slider/Slider.stories.tsx +3 -3
  128. package/src/components/Slider/Slider.tsx +38 -0
  129. package/src/components/Steps/Steps.tsx +3 -3
  130. package/src/components/Tabs/Tabs.tsx +77 -8
  131. package/src/components/Testimonial/Testimonial.tsx +1 -1
  132. package/src/components/TypedButton/TypedButton.stories.tsx +59 -0
  133. package/src/components/TypedButton/TypedButton.tsx +39 -0
  134. package/src/components/TypedButton/index.ts +2 -0
  135. package/src/components/VideoPlayer/VideoPlayer.tsx +11 -4
  136. package/src/lib/composables/index.ts +4 -7
  137. package/src/lib/composables/types.ts +45 -0
  138. package/src/lib/composables/useAccordion.ts +0 -7
  139. package/src/lib/composables/useAtomixGlass.ts +144 -5
  140. package/src/lib/composables/useChartExport.ts +3 -13
  141. package/src/lib/composables/useDropdown.ts +66 -0
  142. package/src/lib/composables/useFocusTrap.ts +80 -0
  143. package/src/lib/composables/usePerformanceMonitor.ts +448 -0
  144. package/src/lib/composables/useResponsiveGlass.presets.ts +192 -0
  145. package/src/lib/composables/useResponsiveGlass.ts +441 -0
  146. package/src/lib/composables/useTooltip.ts +16 -0
  147. package/src/lib/composables/useTypedButton.ts +66 -0
  148. package/src/lib/config/index.ts +62 -5
  149. package/src/lib/constants/components.ts +55 -0
  150. package/src/lib/theme/devtools/__tests__/useHistory.test.tsx +150 -0
  151. package/src/lib/theme/tokens/centralized-tokens.ts +120 -0
  152. package/src/lib/theme/utils/__tests__/domUtils.test.ts +101 -0
  153. package/src/lib/types/components.ts +37 -11
  154. package/src/lib/types/glass.ts +35 -0
  155. package/src/lib/types/index.ts +1 -0
  156. package/src/lib/utils/displacement-generator.ts +1 -1
  157. package/src/styles/01-settings/_settings.testtypecheck.scss +53 -0
  158. package/src/styles/01-settings/_settings.typedbutton.scss +53 -0
  159. package/src/styles/06-components/_components.testbutton.scss +212 -0
  160. package/src/styles/06-components/_components.testtypecheck.scss +212 -0
  161. package/src/styles/06-components/_components.typedbutton.scss +212 -0
  162. package/src/styles/99-utilities/_index.scss +1 -0
  163. package/src/styles/99-utilities/_utilities.text.scss +1 -1
  164. package/src/styles/99-utilities/_utilities.touch-target.scss +36 -0
  165. package/src/styles/06-components/old.chart.styles.scss +0 -2788
package/dist/core.js CHANGED
@@ -92,7 +92,7 @@ var match, version, createPropertyDescriptor$2 = function(bitmap, value) {
92
92
  return "object" == typeof it ? null !== it : isCallable$7(it);
93
93
  }, path$3 = {}, path$2 = path$3, globalThis$a = globalThis_1, isCallable$6 = isCallable$8, aFunction = function(variable) {
94
94
  return isCallable$6(variable) ? variable : void 0;
95
- }, navigator = globalThis_1.navigator, userAgent$1 = navigator && navigator.userAgent, globalThis$8 = globalThis_1, userAgent = userAgent$1 ? String(userAgent$1) : "", process$1 = globalThis$8.process, Deno = globalThis$8.Deno, versions = process$1 && process$1.versions || Deno && Deno.version, v8 = versions && versions.v8;
95
+ }, navigator$1 = globalThis_1.navigator, userAgent$1 = navigator$1 && navigator$1.userAgent, globalThis$8 = globalThis_1, userAgent = userAgent$1 ? String(userAgent$1) : "", process$1 = globalThis$8.process, Deno = globalThis$8.Deno, versions = process$1 && process$1.versions || Deno && Deno.version, v8 = versions && versions.v8;
96
96
 
97
97
  v8 && (
98
98
  // in old Chrome, versions of V8 isn't V8 = Chrome / 10
@@ -564,7 +564,16 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
564
564
  PADDING: "0",
565
565
  MODE: "standard",
566
566
  OVER_LIGHT: !1,
567
- ENABLE_OVER_LIGHT_LAYERS: !0
567
+ ENABLE_OVER_LIGHT_LAYERS: !0,
568
+ // Phase 1: Time-Based Animation System defaults
569
+ WITH_TIME_ANIMATION: !0,
570
+ ANIMATION_SPEED: 1,
571
+ // Phase 1: Multi-Layer Distortion System defaults
572
+ WITH_MULTI_LAYER_DISTORTION: !1,
573
+ DISTORTION_OCTAVES: 5,
574
+ DISTORTION_LACUNARITY: 2,
575
+ DISTORTION_GAIN: .5,
576
+ DISTORTION_QUALITY: "high"
568
577
  },
569
578
  CONSTANTS: {
570
579
  ACTIVATION_ZONE: 200,
@@ -727,6 +736,44 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
727
736
  // Saturation constants
728
737
  SATURATION: {
729
738
  HIGH_CONTRAST: 200
739
+ },
740
+ // Phase 1: Animation System Constants
741
+ ANIMATION: {
742
+ // Breathing effect timing (in milliseconds)
743
+ BREATHING_CYCLE: 2e3,
744
+ // 2-second breathing cycle
745
+ // Flow animation speed
746
+ FLOW_SPEED_X: .1,
747
+ // Horizontal flow speed
748
+ FLOW_SPEED_Y: .15,
749
+ // Vertical flow speed
750
+ // Wave propagation
751
+ WAVE_SPEED: .05,
752
+ // Radial wave speed
753
+ WAVE_AMPLITUDE: .02
754
+ },
755
+ // Phase 1: Multi-Layer Distortion Quality Presets
756
+ DISTORTION_QUALITY_PRESETS: {
757
+ low: {
758
+ octaves: 2,
759
+ lacunarity: 2,
760
+ gain: .5
761
+ },
762
+ medium: {
763
+ octaves: 4,
764
+ lacunarity: 2,
765
+ gain: .5
766
+ },
767
+ high: {
768
+ octaves: 5,
769
+ lacunarity: 2,
770
+ gain: .5
771
+ },
772
+ ultra: {
773
+ octaves: 7,
774
+ lacunarity: 2,
775
+ gain: .5
776
+ }
730
777
  }
731
778
  }
732
779
  }, {CONSTANTS: CONSTANTS$2} = ATOMIX_GLASS, calculateDistance = (pos1, pos2) => {
@@ -805,7 +852,7 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
805
852
  // Silently handle errors
806
853
  }
807
854
  return CONSTANTS$2.DEFAULT_CORNER_RADIUS;
808
- }, lerp = (a, b, t) => a + (b - a) * t, softClamp = (value, max) => max <= 0 ? 0 : max * (1 - Math.exp(-value / max)), getDisplacementMap = (mode, displacementMap, polarDisplacementMap, prominentDisplacementMap, shaderMapUrl) => {
855
+ }, lerp$1 = (a, b, t) => a + (b - a) * t, softClamp = (value, max) => max <= 0 ? 0 : max * (1 - Math.exp(-value / max)), getDisplacementMap = (mode, displacementMap, polarDisplacementMap, prominentDisplacementMap, shaderMapUrl) => {
809
856
  switch (mode) {
810
857
  case "standard":
811
858
  return displacementMap;
@@ -978,14 +1025,16 @@ const sharedShaderCache = new Map, AtomixGlassContainer = forwardRef((({childre
978
1025
  }, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, onMouseDown: onMouseDown, onMouseUp: onMouseUp, isActive: isActive = !1, overLight: overLight = !1, overLightConfig: overLightConfig = {}, borderRadius: borderRadius = 0, padding: padding = "0 0", glassSize: glassSize = {
979
1026
  width: 0,
980
1027
  height: 0
981
- }, onClick: onClick, mode: mode = "standard", effectiveWithoutEffects: effectiveWithoutEffects = !1, effectiveReducedMotion: effectiveReducedMotion = !1, shaderVariant: shaderVariant = "liquidGlass", withLiquidBlur: withLiquidBlur = !1, contentRef: contentRef}, ref) => {
1028
+ }, onClick: onClick, mode: mode = "standard", effectiveWithoutEffects: effectiveWithoutEffects = !1, effectiveReducedMotion: effectiveReducedMotion = !1, shaderVariant: shaderVariant = "liquidGlass", withLiquidBlur: withLiquidBlur = !1,
1029
+ // Phase 1: Animation System props
1030
+ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpeed: animationSpeed = 1, withMultiLayerDistortion: withMultiLayerDistortion = !1, distortionOctaves: distortionOctaves = 3, distortionLacunarity: distortionLacunarity = 2, distortionGain: distortionGain = .5, distortionQuality: distortionQuality = "medium", contentRef: contentRef}, ref) => {
982
1031
  // Generate a stable, deterministic ID for SSR compatibility
983
1032
  // Use a module-level counter that's consistent across server and client
984
- const filterId = useMemo((() => "atomix-glass-filter-" + ++idCounter), []), [shaderMapUrl, setShaderMapUrl] = useState(""), shaderGeneratorRef = useRef(null), shaderUtilsRef = useRef(null), shaderDebounceTimeoutRef = useRef(null);
1033
+ const filterId = useMemo((() => "atomix-glass-filter-" + ++idCounter), []), [shaderMapUrl, setShaderMapUrl] = useState(""), shaderGeneratorRef = useRef(null), shaderUtilsRef = useRef(null), shaderDebounceTimeoutRef = useRef(null), shaderUpdateTimeoutRef = useRef(null), animationFrameRef = useRef(null);
985
1034
  // Lazy load shader utilities only when shader mode is needed
986
1035
  useEffect((() => {
987
1036
  "shader" === mode ?
988
- // Dynamic import shader utilities
1037
+ // Dynamic import shader utilities with animation support
989
1038
  Promise.resolve().then((() => shaderUtils)).then((shaderUtils => {
990
1039
  shaderUtilsRef.current = {
991
1040
  ShaderDisplacementGenerator: shaderUtils.ShaderDisplacementGenerator,
@@ -1000,7 +1049,7 @@ const sharedShaderCache = new Map, AtomixGlassContainer = forwardRef((({childre
1000
1049
  // Generate shader map with debouncing and caching
1001
1050
  useEffect((() => {
1002
1051
  // Enhanced validation for shader mode
1003
- if ("shader" === mode && glassSize && validateGlassSize(glassSize) && shaderUtilsRef.current) {
1052
+ if ("shader" === mode && glassSize && validateGlassSize(glassSize)) {
1004
1053
  // Create cache key from size and variant
1005
1054
  const cacheKey = `${glassSize.width}x${glassSize.height}-${shaderVariant}`, cachedUrl = (key => {
1006
1055
  const entry = sharedShaderCache.get(key);
@@ -1022,11 +1071,9 @@ const sharedShaderCache = new Map, AtomixGlassContainer = forwardRef((({childre
1022
1071
  width: glassSize.width,
1023
1072
  height: glassSize.height,
1024
1073
  fragment: selectedShader
1025
- }),
1026
- // Defer shader generation with longer delay to avoid blocking
1027
- setTimeout((() => {
1074
+ }), shaderUpdateTimeoutRef.current = setTimeout((() => {
1028
1075
  const url = shaderGeneratorRef.current?.updateShader() || "";
1029
- ((key, url) => {
1076
+ url && ((key, url) => {
1030
1077
  // Evict oldest entries if at capacity
1031
1078
  if (sharedShaderCache.size >= 15) {
1032
1079
  const entries = Array.from(sharedShaderCache.entries());
@@ -1058,7 +1105,8 @@ const sharedShaderCache = new Map, AtomixGlassContainer = forwardRef((({childre
1058
1105
  // Cleanup function with error handling
1059
1106
  return () => {
1060
1107
  shaderDebounceTimeoutRef.current && (clearTimeout(shaderDebounceTimeoutRef.current),
1061
- shaderDebounceTimeoutRef.current = null);
1108
+ shaderDebounceTimeoutRef.current = null), shaderUpdateTimeoutRef.current && (clearTimeout(shaderUpdateTimeoutRef.current),
1109
+ shaderUpdateTimeoutRef.current = null);
1062
1110
  try {
1063
1111
  shaderGeneratorRef.current?.destroy();
1064
1112
  } catch (error) {
@@ -1067,7 +1115,37 @@ const sharedShaderCache = new Map, AtomixGlassContainer = forwardRef((({childre
1067
1115
  shaderGeneratorRef.current = null;
1068
1116
  }
1069
1117
  };
1070
- }), [ mode, glassSize, shaderVariant ]);
1118
+ }), [ mode, glassSize, shaderVariant ]),
1119
+ // Phase 1: Time-Based Animation Loop - Continuous shader regeneration
1120
+ useEffect((() => {
1121
+ // Only run animations in shader mode with time animation enabled
1122
+ if ("shader" !== mode || !withTimeAnimation || effectiveReducedMotion || effectiveWithoutEffects)
1123
+ // Cancel any existing animation frame
1124
+ return void (null !== animationFrameRef.current && (cancelAnimationFrame(animationFrameRef.current),
1125
+ animationFrameRef.current = null));
1126
+ const baseFps = "ultra" === distortionQuality ? 60 : "high" === distortionQuality ? 30 : "medium" === distortionQuality ? 24 : 20, effectiveSpeed = Math.max(.5, Math.min(2, animationSpeed || 1)), complexity = withMultiLayerDistortion ? Math.max(1, (distortionOctaves || 3) / 3 + .25 * Math.max(0, (distortionLacunarity || 2) - 2) + Math.max(0, (distortionGain || .5) - .5)) : 1, frameInterval = 1e3 / Math.max(12, Math.min(60, Math.round(baseFps * effectiveSpeed / complexity)));
1127
+ let lastUpdate = 0, isCancelled = !1;
1128
+ const animate = currentTime => {
1129
+ if (!isCancelled) {
1130
+ if (currentTime - lastUpdate >= frameInterval && shaderGeneratorRef.current) {
1131
+ lastUpdate = currentTime;
1132
+ try {
1133
+ const animatedShaderUrl = shaderGeneratorRef.current.updateShader();
1134
+ animatedShaderUrl && setShaderMapUrl(animatedShaderUrl);
1135
+ } catch (error) {
1136
+ console.warn("AtomixGlassContainer: Error in animation loop", error);
1137
+ }
1138
+ }
1139
+ animationFrameRef.current = requestAnimationFrame(animate);
1140
+ }
1141
+ };
1142
+ // Start animation loop
1143
+ // Cleanup animation on unmount or dependency change
1144
+ return animationFrameRef.current = requestAnimationFrame(animate), () => {
1145
+ isCancelled = !0, null !== animationFrameRef.current && (cancelAnimationFrame(animationFrameRef.current),
1146
+ animationFrameRef.current = null);
1147
+ };
1148
+ }), [ mode, withTimeAnimation, animationSpeed, displacementScale, withMultiLayerDistortion, distortionOctaves, distortionLacunarity, distortionGain, distortionQuality, effectiveReducedMotion, effectiveWithoutEffects, glassSize ]);
1071
1149
  // Removed forced reflow to avoid layout thrash and potential feedback sizing loops
1072
1150
  const [rectCache, setRectCache] = useState(null);
1073
1151
  useEffect((() => {
@@ -1401,12 +1479,144 @@ class {
1401
1479
  style.setProperty("--atomix-glass-container-text-shadow", isOverLight ? "0px 1px 2px rgba(255, 255, 255, 0.15)" : "0px 2px 12px rgba(0, 0, 0, 0.4)"),
1402
1480
  style.setProperty("--atomix-glass-container-box-shadow", isOverLight ? "0px 16px 70px rgba(0, 0, 0, 0.75)" : "0px 12px 40px rgba(0, 0, 0, 0.25)");
1403
1481
  }
1404
- }, {CONSTANTS: CONSTANTS$1} = ATOMIX_GLASS;
1482
+ };
1405
1483
 
1406
1484
  /**
1407
1485
  * Updates the styles of the AtomixGlass wrapper and container elements imperatively
1408
1486
  * to avoid React re-renders on mouse movement.
1409
- */ const {CONSTANTS: CONSTANTS} = ATOMIX_GLASS, backgroundDetectionCache = new WeakMap, setCachedBackgroundDetection = (parentElement, overLightConfig, result, threshold) => {
1487
+ */
1488
+ /**
1489
+ * Animation System for AtomixGlass Component
1490
+ *
1491
+ * Implements Phase 1 features from the AtomixGlass Feature Implementation Roadmap:
1492
+ * - Feature 1.1: Time-Based Animation System
1493
+ * - Feature 1.2: Multi-Layer Distortion System (FBM)
1494
+ *
1495
+ * @packageDocumentation
1496
+ */
1497
+ // ============================================================================
1498
+ // Noise Functions for FBM (Feature 1.2)
1499
+ // ============================================================================
1500
+ /**
1501
+ * Perlin noise implementation for smooth gradient noise
1502
+ *
1503
+ * @param x - X coordinate
1504
+ * @param y - Y coordinate
1505
+ * @returns Noise value in range [0, 1]
1506
+ */
1507
+ function perlinNoise(x, y) {
1508
+ // Simplified Perlin noise using pseudo-random gradients
1509
+ const X = 255 & Math.floor(x), Y = 255 & Math.floor(y), xf = x - Math.floor(x), yf = y - Math.floor(y), u = fade(xf), v = fade(yf), A = p[X] + Y & 255, B = p[X + 1] + Y & 255, ga = grad(p[A], xf, yf), gb = grad(p[B], xf - 1, yf), gc = grad(p[A + 1 & 255], xf, yf - 1), gd = grad(p[B + 1 & 255], xf - 1, yf - 1), lerpX1 = lerp(ga, gb, u), lerpX2 = lerp(gc, gd, u);
1510
+ // Scale to [0, 1] range
1511
+ return (lerp(lerpX1, lerpX2, v) + 1) / 2;
1512
+ }
1513
+
1514
+ // ============================================================================
1515
+ // Fractal Brownian Motion (FBM) Engine (Feature 1.2)
1516
+ // ============================================================================
1517
+ /**
1518
+ * Creates an FBM engine with configurable parameters
1519
+ *
1520
+ * @param config - FBM configuration (octaves, lacunarity, gain)
1521
+ * @returns Object with fbm function
1522
+ *
1523
+ * @example
1524
+ * ```typescript
1525
+ * const fbmEngine = createFBMEngine({ octaves: 5, lacunarity: 2, gain: 0.5 });
1526
+ *
1527
+ * // Generate noise at position (0.5, 0.5) with time animation
1528
+ * const noiseValue = fbmEngine.fbm(0.5, 0.5, Date.now());
1529
+ * ```
1530
+ */ function createFBMEngine(config) {
1531
+ /**
1532
+ * Fractal Brownian Motion function
1533
+ * Combines multiple octaves of noise for complex, natural patterns
1534
+ *
1535
+ * @param x - X coordinate
1536
+ * @param y - Y coordinate
1537
+ * @param time - Optional time value for animation
1538
+ * @returns FBM noise value in range [0, 1]
1539
+ */
1540
+ const fbm = (x, y, time = 0) => {
1541
+ let value = 0, amplitude = .5, frequency = 1, phase = .001 * time;
1542
+ // Convert to seconds for reasonable animation speed
1543
+ for (let i = 0; i < config.octaves; i++)
1544
+ // Apply time-based phase shift to all octaves
1545
+ value += perlinNoise(x * frequency + phase, y * frequency + phase) * amplitude,
1546
+ frequency *= config.lacunarity, // Increase frequency
1547
+ amplitude *= config.gain;
1548
+ return value;
1549
+ };
1550
+ /**
1551
+ * Get FBM with simple time factor
1552
+ */ return {
1553
+ fbm: fbm,
1554
+ fbmWithTime: (x, y, time) => fbm(x, y, time)
1555
+ };
1556
+ }
1557
+
1558
+ /**
1559
+ * Gets optimal FBM config based on quality preset
1560
+ *
1561
+ * @param quality - Quality preset level
1562
+ * @returns FBM configuration for the quality level
1563
+ */ const fbmEngineCache = new Map;
1564
+
1565
+ // ============================================================================
1566
+ // Shader Utility Functions for Time-Based Effects
1567
+ // ============================================================================
1568
+ /**
1569
+ * Liquid glass distortion with time-based animation
1570
+ * Uses FBM to create organic, flowing liquid effects
1571
+ *
1572
+ * @param uv - UV coordinates (normalized 0-1)
1573
+ * @param time - Elapsed time in milliseconds
1574
+ * @param config - FBM configuration
1575
+ * @returns Distorted UV coordinates
1576
+ */ function liquidGlassWithTime(uv, time, config) {
1577
+ const configKey = `${config.octaves}-${config.lacunarity}-${config.gain}`;
1578
+ let fbmEngine = fbmEngineCache.get(configKey);
1579
+ fbmEngine || (fbmEngine = createFBMEngine(config), fbmEngineCache.set(configKey, fbmEngine));
1580
+ // Animate noise with time
1581
+ const animatedNoise = fbmEngine.fbmWithTime(2 * uv.x + 1e-4 * time, 2 * uv.y + 15e-5 * time, time);
1582
+ return {
1583
+ x: uv.x + .04 * (animatedNoise - .5),
1584
+ y: uv.y + .04 * (animatedNoise - .5)
1585
+ };
1586
+ }
1587
+
1588
+ // ============================================================================
1589
+ // Helper Functions
1590
+ // ============================================================================
1591
+ /**
1592
+ * Fade curve for smooth interpolation (Perlin's fade function)
1593
+ */ function fade(t) {
1594
+ return t * t * t * (t * (6 * t - 15) + 10);
1595
+ }
1596
+
1597
+ /**
1598
+ * Linear interpolation
1599
+ */ function lerp(a, b, t) {
1600
+ return a + t * (b - a);
1601
+ }
1602
+
1603
+ /**
1604
+ * Gradient calculation for Perlin noise
1605
+ */ function grad(hash, x, y) {
1606
+ const h = 15 & hash, u = h < 8 ? x : y, v = h < 4 ? y : 12 === h || 14 === h ? x : 0;
1607
+ return (1 & h ? -u : u) + (2 & h ? -v : v);
1608
+ }
1609
+
1610
+ /**
1611
+ * Permutation table for Perlin noise
1612
+ */ const p = (() => {
1613
+ const permutation = [];
1614
+ for (let i = 0; i < 256; i++) permutation[i] = Math.floor(256 * Math.random());
1615
+ // Duplicate for overflow handling
1616
+ return [ ...permutation, ...permutation ];
1617
+ })(), {CONSTANTS: CONSTANTS$1} = ATOMIX_GLASS;
1618
+
1619
+ const {CONSTANTS: CONSTANTS} = ATOMIX_GLASS, backgroundDetectionCache = new WeakMap, setCachedBackgroundDetection = (parentElement, overLightConfig, result, threshold) => {
1410
1620
  parentElement && backgroundDetectionCache.set(parentElement, {
1411
1621
  result: result,
1412
1622
  timestamp: Date.now(),
@@ -1419,7 +1629,9 @@ class {
1419
1629
  * Composable hook for AtomixGlass component logic
1420
1630
  * Manages all state, calculations, and event handlers
1421
1631
  */
1422
- function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef: wrapperRef, borderRadius: borderRadius, globalMousePosition: externalGlobalMousePosition, mouseOffset: externalMouseOffset, mouseContainer: mouseContainer, overLight: overLight = ATOMIX_GLASS.DEFAULTS.OVER_LIGHT, reducedMotion: reducedMotion = !1, highContrast: highContrast = !1, withoutEffects: withoutEffects = !1, elasticity: elasticity = .05, onClick: onClick, debugBorderRadius: debugBorderRadius = !1, debugOverLight: debugOverLight = !1, children: children, blurAmount: blurAmount, saturation: saturation, padding: padding, withLiquidBlur: withLiquidBlur, isFixedOrSticky: isFixedOrSticky = !1}) {
1632
+ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef: wrapperRef, borderRadius: borderRadius, globalMousePosition: externalGlobalMousePosition, mouseOffset: externalMouseOffset, mouseContainer: mouseContainer, overLight: overLight = ATOMIX_GLASS.DEFAULTS.OVER_LIGHT, reducedMotion: reducedMotion = !1, highContrast: highContrast = !1, withoutEffects: withoutEffects = !1, elasticity: elasticity = .05, onClick: onClick, debugBorderRadius: debugBorderRadius = !1, debugOverLight: debugOverLight = !1, children: children, blurAmount: blurAmount, saturation: saturation, padding: padding, withLiquidBlur: withLiquidBlur, isFixedOrSticky: isFixedOrSticky = !1, withTimeAnimation:
1633
+ // Phase 1: Animation System Props
1634
+ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: animationSpeed = ATOMIX_GLASS.DEFAULTS.ANIMATION_SPEED, withMultiLayerDistortion: withMultiLayerDistortion = ATOMIX_GLASS.DEFAULTS.WITH_MULTI_LAYER_DISTORTION, distortionOctaves: distortionOctaves = ATOMIX_GLASS.DEFAULTS.DISTORTION_OCTAVES, distortionLacunarity: distortionLacunarity = ATOMIX_GLASS.DEFAULTS.DISTORTION_LACUNARITY, distortionGain: distortionGain = ATOMIX_GLASS.DEFAULTS.DISTORTION_GAIN, distortionQuality: distortionQuality = ATOMIX_GLASS.DEFAULTS.DISTORTION_QUALITY}) {
1423
1635
  // State
1424
1636
  const [isHovered, setIsHovered] = useState(!1), [isActive, setIsActive] = useState(!1), cachedRectRef = useRef(null), internalGlobalMousePositionRef = useRef({
1425
1637
  x: 0,
@@ -1433,7 +1645,47 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
1433
1645
  }), targetGlobalMousePositionRef = useRef({
1434
1646
  x: 0,
1435
1647
  y: 0
1436
- }), lerpRafRef = useRef(null), lerpActiveRef = useRef(!1), [dynamicBorderRadius, setDynamicCornerRadius] = useState(CONSTANTS.DEFAULT_CORNER_RADIUS), [userPrefersReducedMotion, setUserPrefersReducedMotion] = useState(!1), [userPrefersHighContrast, setUserPrefersHighContrast] = useState(!1), [detectedOverLight, setDetectedOverLight] = useState(!1), effectiveBorderRadius = useMemo((() => void 0 !== borderRadius ? Math.max(0, borderRadius) : Math.max(0, dynamicBorderRadius)), [ borderRadius, dynamicBorderRadius ]), {glassSize: glassSize} = function({glassRef: glassRef, effectiveBorderRadius: effectiveBorderRadius, cachedRectRef: cachedRectRef}) {
1648
+ }), lerpRafRef = useRef(null), lerpActiveRef = useRef(!1), [dynamicBorderRadius, setDynamicCornerRadius] = useState(CONSTANTS.DEFAULT_CORNER_RADIUS), [userPrefersReducedMotion, setUserPrefersReducedMotion] = useState(!1), [userPrefersHighContrast, setUserPrefersHighContrast] = useState(!1), [detectedOverLight, setDetectedOverLight] = useState(!1), animationFrameIdRef = useRef(null), animationStartTimeRef = useRef(0), elapsedTimeRef = useRef(0), shaderTimeRef = useRef(0), fbmConfig = useMemo((() => {
1649
+ // If quality preset is provided, use it as base
1650
+ const preset = (quality = distortionQuality, ATOMIX_GLASS.CONSTANTS.DISTORTION_QUALITY_PRESETS[quality]);
1651
+ // Override with custom values if provided
1652
+ var quality;
1653
+ return {
1654
+ octaves: distortionOctaves ?? preset.octaves,
1655
+ lacunarity: distortionLacunarity ?? preset.lacunarity,
1656
+ gain: distortionGain ?? preset.gain
1657
+ };
1658
+ }), [ distortionQuality, distortionOctaves, distortionLacunarity, distortionGain ]), fbmEngine = useMemo((() => withMultiLayerDistortion ? createFBMEngine(fbmConfig) : null), [ withMultiLayerDistortion, fbmConfig ]), effectiveReducedMotion = useMemo((() => reducedMotion || userPrefersReducedMotion), [ reducedMotion, userPrefersReducedMotion ]), effectiveWithTimeAnimation = useMemo((() => withTimeAnimation && !effectiveReducedMotion), [ withTimeAnimation, effectiveReducedMotion ]);
1659
+ /**
1660
+ * Animation loop for time-based effects
1661
+ */
1662
+ useEffect((() => {
1663
+ if (!effectiveWithTimeAnimation || "undefined" == typeof window) return;
1664
+ let lastFrameTime = performance.now();
1665
+ /**
1666
+ * Animation frame handler
1667
+ */ const animate = currentTime => {
1668
+ // Calculate delta time
1669
+ const deltaTime = currentTime - lastFrameTime;
1670
+ lastFrameTime = currentTime;
1671
+ // Apply animation speed multiplier
1672
+ const scaledDelta = deltaTime * animationSpeed;
1673
+ elapsedTimeRef.current += scaledDelta, shaderTimeRef.current = elapsedTimeRef.current,
1674
+ // Continue animation loop
1675
+ animationFrameIdRef.current = requestAnimationFrame(animate);
1676
+ };
1677
+ // Start animation
1678
+ // Cleanup
1679
+ return animationStartTimeRef.current = performance.now(), animationFrameIdRef.current = requestAnimationFrame(animate),
1680
+ () => {
1681
+ null !== animationFrameIdRef.current && (cancelAnimationFrame(animationFrameIdRef.current),
1682
+ animationFrameIdRef.current = null);
1683
+ };
1684
+ }), [ effectiveWithTimeAnimation, animationSpeed ]);
1685
+ /**
1686
+ * Get current shader time for animations
1687
+ */
1688
+ const getShaderTime = useCallback((() => shaderTimeRef.current), []), applyTimeBasedDistortion = useCallback((uv => effectiveWithTimeAnimation && fbmEngine ? liquidGlassWithTime(uv, shaderTimeRef.current, fbmConfig) : uv), [ effectiveWithTimeAnimation, fbmEngine, fbmConfig ]), effectiveBorderRadius = useMemo((() => void 0 !== borderRadius ? Math.max(0, borderRadius) : Math.max(0, dynamicBorderRadius)), [ borderRadius, dynamicBorderRadius ]), {glassSize: glassSize} = function({glassRef: glassRef, effectiveBorderRadius: effectiveBorderRadius, cachedRectRef: cachedRectRef}) {
1437
1689
  const [glassSize, setGlassSize] = useState({
1438
1690
  width: 270,
1439
1691
  height: 69
@@ -1492,7 +1744,10 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
1492
1744
  glassRef: glassRef,
1493
1745
  effectiveBorderRadius: effectiveBorderRadius,
1494
1746
  cachedRectRef: cachedRectRef
1495
- }), effectiveReducedMotion = useMemo((() => reducedMotion || userPrefersReducedMotion), [ reducedMotion, userPrefersReducedMotion ]), effectiveHighContrast = useMemo((() => highContrast || userPrefersHighContrast), [ highContrast, userPrefersHighContrast ]), effectiveWithoutEffects = useMemo((() => withoutEffects || effectiveReducedMotion), [ withoutEffects, effectiveReducedMotion ]), globalMousePosition = externalGlobalMousePosition || internalGlobalMousePositionRef.current, mouseOffset = externalMouseOffset || internalMouseOffsetRef.current;
1747
+ }), effectiveHighContrast = useMemo((() => highContrast || userPrefersHighContrast), [ highContrast, userPrefersHighContrast ]), effectiveWithoutEffects = useMemo((() => withoutEffects || effectiveReducedMotion), [ withoutEffects, effectiveReducedMotion ]), globalMousePosition = externalGlobalMousePosition || internalGlobalMousePositionRef.current, mouseOffset = externalMouseOffset || internalMouseOffsetRef.current;
1748
+ /**
1749
+ * Apply time-based distortion to UV coordinates
1750
+ */
1496
1751
  // Extract border-radius from children
1497
1752
  useEffect((() => {
1498
1753
  const extractRadius = () => {
@@ -1695,6 +1950,8 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
1695
1950
  lerpActiveRef.current = !0;
1696
1951
  const LERP_T = CONSTANTS.LERP_FACTOR, tick = () => {
1697
1952
  if (!lerpActiveRef.current) return;
1953
+ // Add ref validity check to prevent memory leaks
1954
+ if (!glassRef.current || !wrapperRef?.current) return void (lerpActiveRef.current = !1);
1698
1955
  const cur = internalMouseOffsetRef.current, tgt = targetMouseOffsetRef.current, dx = tgt.x - cur.x, dy = tgt.y - cur.y;
1699
1956
  // If we're close enough, snap and park
1700
1957
  if (Math.abs(dx) < .05 && Math.abs(dy) < .05) internalMouseOffsetRef.current = {
@@ -1703,17 +1960,17 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
1703
1960
  ...targetGlobalMousePositionRef.current
1704
1961
  }; else {
1705
1962
  internalMouseOffsetRef.current = {
1706
- x: lerp(cur.x, tgt.x, LERP_T),
1707
- y: lerp(cur.y, tgt.y, LERP_T)
1963
+ x: lerp$1(cur.x, tgt.x, LERP_T),
1964
+ y: lerp$1(cur.y, tgt.y, LERP_T)
1708
1965
  };
1709
1966
  const curG = internalGlobalMousePositionRef.current, tgtG = targetGlobalMousePositionRef.current;
1710
1967
  internalGlobalMousePositionRef.current = {
1711
- x: lerp(curG.x, tgtG.x, LERP_T),
1712
- y: lerp(curG.y, tgtG.y, LERP_T)
1968
+ x: lerp$1(curG.x, tgtG.x, LERP_T),
1969
+ y: lerp$1(curG.y, tgtG.y, LERP_T)
1713
1970
  };
1714
1971
  }
1715
1972
  // Imperative style update with the smoothed values
1716
- updateAtomixGlassStyles(wrapperRef?.current || null, glassRef.current, {
1973
+ updateAtomixGlassStyles(wrapperRef.current, glassRef.current, {
1717
1974
  mouseOffset: internalMouseOffsetRef.current,
1718
1975
  globalMousePosition: internalGlobalMousePositionRef.current,
1719
1976
  glassSize: glassSize,
@@ -1804,6 +2061,8 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
1804
2061
  // This is now static (refs or props) unless prop changes
1805
2062
  overLightConfig: overLightConfig,
1806
2063
  transformStyle: transformStyle,
2064
+ getShaderTime: getShaderTime,
2065
+ applyTimeBasedDistortion: applyTimeBasedDistortion,
1807
2066
  handleMouseEnter: handleMouseEnter,
1808
2067
  handleMouseLeave: handleMouseLeave,
1809
2068
  handleMouseDown: handleMouseDown,
@@ -1812,6 +2071,358 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
1812
2071
  };
1813
2072
  }
1814
2073
 
2074
+ /**
2075
+ * Default responsive breakpoints configuration
2076
+ *
2077
+ * These breakpoints are optimized for glass effect performance across device classes:
2078
+ * - Mobile: Reduced complexity for 60 FPS target
2079
+ * - Tablet: Balanced quality and performance
2080
+ * - Desktop: Full fidelity effects
2081
+ */ const DEFAULT_BREAKPOINTS = {
2082
+ mobile: {
2083
+ maxWidth: 640,
2084
+ params: {
2085
+ distortionOctaves: 3,
2086
+ displacementScale: .7,
2087
+ blurAmount: .8,
2088
+ animationSpeed: .8,
2089
+ chromaticIntensity: .5
2090
+ }
2091
+ },
2092
+ tablet: {
2093
+ minWidth: 641,
2094
+ maxWidth: 1024,
2095
+ params: {
2096
+ distortionOctaves: 4,
2097
+ displacementScale: .85,
2098
+ blurAmount: .9,
2099
+ animationSpeed: .9,
2100
+ chromaticIntensity: .75
2101
+ }
2102
+ },
2103
+ desktop: {
2104
+ minWidth: 1025,
2105
+ params: {
2106
+ distortionOctaves: 5,
2107
+ displacementScale: 1,
2108
+ blurAmount: 1,
2109
+ animationSpeed: 1,
2110
+ chromaticIntensity: 1
2111
+ }
2112
+ }
2113
+ };
2114
+
2115
+ /**
2116
+ * Device performance tier detection
2117
+ *
2118
+ * Uses Device Memory API and Hardware Concurrency API to classify devices
2119
+ * into performance tiers for automatic quality adjustment.
2120
+ *
2121
+ * @returns Performance tier classification
2122
+ */
2123
+ /**
2124
+ * PerformanceDashboard - Real-time performance monitoring overlay
2125
+ *
2126
+ * Displays:
2127
+ * - Current FPS with color coding
2128
+ * - Frame time statistics
2129
+ * - Quality level indicator
2130
+ * - GPU memory usage (if available)
2131
+ * - Auto-scaling status
2132
+ */
2133
+ const PerformanceDashboard = ({metrics: metrics, isVisible: isVisible = !0, onClose: onClose}) => {
2134
+ // Get color for FPS display
2135
+ const getFpsColor = fps => fps >= 58 ? "#4ade80" : // Green - good
2136
+ fps >= 45 ? "#fbbf24" : "#ef4444" // Red - critical
2137
+ , dashboardStyle = useMemo((() => ({
2138
+ position: "fixed",
2139
+ top: "16px",
2140
+ right: "16px",
2141
+ padding: "12px 16px",
2142
+ backgroundColor: "rgba(17, 24, 39, 0.95)",
2143
+ borderRadius: "8px",
2144
+ boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)",
2145
+ fontFamily: "monospace",
2146
+ fontSize: "12px",
2147
+ color: "#fff",
2148
+ zIndex: 9999,
2149
+ minWidth: "200px",
2150
+ backdropFilter: "blur(8px)",
2151
+ border: "1px solid rgba(255, 255, 255, 0.1)",
2152
+ transition: "opacity 0.3s ease",
2153
+ opacity: isVisible ? 1 : 0,
2154
+ pointerEvents: isVisible ? "auto" : "none"
2155
+ })), [ isVisible ]), headerStyle = useMemo((() => ({
2156
+ display: "flex",
2157
+ justifyContent: "space-between",
2158
+ alignItems: "center",
2159
+ marginBottom: "8px",
2160
+ paddingBottom: "8px",
2161
+ borderBottom: "1px solid rgba(255, 255, 255, 0.1)"
2162
+ })), []), titleStyle = useMemo((() => ({
2163
+ fontWeight: "bold",
2164
+ fontSize: "13px",
2165
+ color: "#fff"
2166
+ })), []), closeButtonStyle = useMemo((() => ({
2167
+ background: "transparent",
2168
+ border: "none",
2169
+ color: "#9ca3af",
2170
+ cursor: "pointer",
2171
+ fontSize: "16px",
2172
+ padding: "0",
2173
+ lineHeight: "1"
2174
+ })), []), metricRowStyle = useMemo((() => ({
2175
+ display: "flex",
2176
+ justifyContent: "space-between",
2177
+ alignItems: "center",
2178
+ marginBottom: "6px"
2179
+ })), []), labelStyle = useMemo((() => ({
2180
+ color: "#9ca3af",
2181
+ marginRight: "12px"
2182
+ })), []), valueStyle = useMemo((() => ({
2183
+ fontWeight: "bold"
2184
+ })), []);
2185
+ // Get quality level badge color
2186
+ return isVisible ? jsxs("div", {
2187
+ style: dashboardStyle,
2188
+ children: [ jsxs("div", {
2189
+ style: headerStyle,
2190
+ children: [ jsx("span", {
2191
+ style: titleStyle,
2192
+ children: "Performance Monitor"
2193
+ }), onClose && jsx("button", {
2194
+ style: closeButtonStyle,
2195
+ onClick: onClose,
2196
+ "aria-label": "Close performance dashboard",
2197
+ children: "×"
2198
+ }) ]
2199
+ }), jsxs("div", {
2200
+ style: metricRowStyle,
2201
+ children: [ jsx("span", {
2202
+ style: labelStyle,
2203
+ children: "FPS"
2204
+ }), jsx("span", {
2205
+ style: {
2206
+ ...valueStyle,
2207
+ color: getFpsColor(metrics.fps)
2208
+ },
2209
+ children: Math.round(metrics.fps)
2210
+ }) ]
2211
+ }), jsxs("div", {
2212
+ style: metricRowStyle,
2213
+ children: [ jsx("span", {
2214
+ style: labelStyle,
2215
+ children: "Frame Time"
2216
+ }), jsxs("span", {
2217
+ style: valueStyle,
2218
+ children: [ metrics.frameTime.toFixed(2), "ms" ]
2219
+ }) ]
2220
+ }), jsxs("div", {
2221
+ style: metricRowStyle,
2222
+ children: [ jsx("span", {
2223
+ style: labelStyle,
2224
+ children: "Quality"
2225
+ }), jsx("span", {
2226
+ style: {
2227
+ ...valueStyle,
2228
+ color: (quality => {
2229
+ switch (quality) {
2230
+ case "high":
2231
+ return "#4ade80";
2232
+
2233
+ case "medium":
2234
+ return "#fbbf24";
2235
+
2236
+ case "low":
2237
+ return "#ef4444";
2238
+
2239
+ default:
2240
+ return "#9ca3af";
2241
+ }
2242
+ })(metrics.qualityLevel),
2243
+ textTransform: "uppercase",
2244
+ fontSize: "11px"
2245
+ },
2246
+ children: metrics.qualityLevel
2247
+ }) ]
2248
+ }), metrics.gpuMemory && jsxs("div", {
2249
+ style: metricRowStyle,
2250
+ children: [ jsx("span", {
2251
+ style: labelStyle,
2252
+ children: "GPU Memory"
2253
+ }), jsxs("span", {
2254
+ style: valueStyle,
2255
+ children: [ "~", Math.round(metrics.gpuMemory / 1024), "MB" ]
2256
+ }) ]
2257
+ }), metrics.isAutoScaling && jsx("div", {
2258
+ style: {
2259
+ marginTop: "8px",
2260
+ paddingTop: "8px",
2261
+ borderTop: "1px solid rgba(255, 255, 255, 0.1)",
2262
+ fontSize: "10px",
2263
+ color: "#6b7280",
2264
+ textAlign: "center"
2265
+ },
2266
+ children: "Auto-scaling active"
2267
+ }), jsxs("div", {
2268
+ style: {
2269
+ marginTop: "8px",
2270
+ paddingTop: "8px",
2271
+ borderTop: "1px solid rgba(255, 255, 255, 0.1)",
2272
+ display: "flex",
2273
+ alignItems: "center",
2274
+ gap: "6px"
2275
+ },
2276
+ children: [ jsx("div", {
2277
+ style: {
2278
+ width: "8px",
2279
+ height: "8px",
2280
+ borderRadius: "50%",
2281
+ backgroundColor: getFpsColor(metrics.fps),
2282
+ animation: metrics.fps < 45 ? "pulse 1s infinite" : "none"
2283
+ }
2284
+ }), jsx("span", {
2285
+ style: {
2286
+ fontSize: "10px",
2287
+ color: metrics.fps >= 58 ? "#4ade80" : metrics.fps >= 45 ? "#fbbf24" : "#ef4444"
2288
+ },
2289
+ children: metrics.fps >= 58 ? "Optimal" : metrics.fps >= 45 ? "Warning" : "Critical"
2290
+ }) ]
2291
+ }) ]
2292
+ }) : null;
2293
+ };
2294
+
2295
+ // Add pulse animation for critical FPS
2296
+ if ("undefined" != typeof document) {
2297
+ const styleSheet = document.createElement("style");
2298
+ styleSheet.textContent = "\n @keyframes pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.5; }\n }\n ",
2299
+ document.head.appendChild(styleSheet);
2300
+ }
2301
+
2302
+ /**
2303
+ * Mobile optimization presets
2304
+ *
2305
+ * These presets adjust glass effect parameters based on device performance tier
2306
+ * to ensure smooth animations and responsive interactions.
2307
+ */
2308
+ /**
2309
+ * Performance preset - Maximum FPS, reduced quality
2310
+ * Best for low-end devices or when battery saving is priority
2311
+ */ const PERFORMANCE_PRESET = {
2312
+ distortionOctaves: 2,
2313
+ // Minimal FBM layers
2314
+ displacementScale: 50,
2315
+ // Subtle displacement
2316
+ blurAmount: 5,
2317
+ // Light blur
2318
+ saturation: 80,
2319
+ // Reduced saturation
2320
+ aberrationIntensity: .3,
2321
+ // Minimal chromatic aberration
2322
+ animationSpeed: .8,
2323
+ // Slightly slower for performance
2324
+ chromaticIntensity: .3,
2325
+ // Low chromatic effect
2326
+ distortionLacunarity: 1.5,
2327
+ // Simpler noise pattern
2328
+ distortionGain: .3
2329
+ }, BALANCED_PRESET = {
2330
+ distortionOctaves: 3,
2331
+ // Moderate FBM layers
2332
+ displacementScale: 75,
2333
+ // Medium displacement
2334
+ blurAmount: 8,
2335
+ // Moderate blur
2336
+ saturation: 90,
2337
+ // Near-full saturation
2338
+ aberrationIntensity: .5,
2339
+ // Moderate chromatic aberration
2340
+ animationSpeed: 1,
2341
+ // Normal speed
2342
+ chromaticIntensity: .5,
2343
+ // Moderate chromatic effect
2344
+ distortionLacunarity: 2,
2345
+ // Standard noise pattern
2346
+ distortionGain: .4
2347
+ }, QUALITY_PRESET = {
2348
+ distortionOctaves: 4,
2349
+ // More FBM layers for detail
2350
+ displacementScale: 100,
2351
+ // Stronger displacement
2352
+ blurAmount: 12,
2353
+ // Smoother blur
2354
+ saturation: 100,
2355
+ // Full saturation
2356
+ aberrationIntensity: .7,
2357
+ // Pronounced chromatic aberration
2358
+ animationSpeed: 1.2,
2359
+ // Slightly faster for drama
2360
+ chromaticIntensity: .7,
2361
+ // Strong chromatic effect
2362
+ distortionLacunarity: 2.2,
2363
+ // Richer noise pattern
2364
+ distortionGain: .5
2365
+ }, MOBILE_OPTIMIZED_BREAKPOINTS = {
2366
+ /** Desktop - Full quality */
2367
+ desktop: {
2368
+ minWidth: 1024,
2369
+ params: {
2370
+ distortionOctaves: 6,
2371
+ displacementScale: 150,
2372
+ blurAmount: 15,
2373
+ saturation: 100,
2374
+ aberrationIntensity: 1,
2375
+ animationSpeed: 1,
2376
+ chromaticIntensity: 1,
2377
+ distortionLacunarity: 2.5,
2378
+ distortionGain: .6
2379
+ }
2380
+ },
2381
+ /** Laptop - High quality */
2382
+ laptop: {
2383
+ minWidth: 768,
2384
+ params: {
2385
+ ...QUALITY_PRESET,
2386
+ distortionOctaves: 5,
2387
+ displacementScale: 120
2388
+ }
2389
+ },
2390
+ /** Tablet - Balanced quality */
2391
+ tablet: {
2392
+ minWidth: 640,
2393
+ params: {
2394
+ ...BALANCED_PRESET,
2395
+ distortionOctaves: 4,
2396
+ displacementScale: 90
2397
+ }
2398
+ },
2399
+ /** Mobile - Performance optimized */
2400
+ mobile: {
2401
+ maxWidth: 639,
2402
+ params: {
2403
+ ...PERFORMANCE_PRESET,
2404
+ distortionOctaves: 3,
2405
+ displacementScale: 75,
2406
+ blurAmount: 6
2407
+ }
2408
+ },
2409
+ /** Small mobile - Maximum performance */
2410
+ mobileSmall: {
2411
+ maxWidth: 375,
2412
+ params: {
2413
+ ...PERFORMANCE_PRESET,
2414
+ distortionOctaves: 2,
2415
+ displacementScale: 50,
2416
+ blurAmount: 4,
2417
+ saturation: 70
2418
+ }
2419
+ }
2420
+ };
2421
+
2422
+ /**
2423
+ * Balanced preset - Good quality with reasonable performance
2424
+ * Default preset for most mobile devices
2425
+ */
1815
2426
  /**
1816
2427
  * AtomixGlass - A high-performance glass morphism component with liquid distortion effects
1817
2428
  *
@@ -1826,6 +2437,8 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
1826
2437
  * - Focus ring support for keyboard navigation
1827
2438
  * - Responsive breakpoints for mobile optimization
1828
2439
  * - Enhanced ARIA attributes for screen readers
2440
+ * - Time-based animation system with FBM distortion
2441
+ * - Device preset optimization for performance/quality balance
1829
2442
  *
1830
2443
  * Design System Compliance:
1831
2444
  * - Uses design tokens for opacity, spacing, and colors
@@ -1882,8 +2495,15 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
1882
2495
  * <AtomixGlass overLight="auto" debugOverLight={true}>
1883
2496
  * <div>Content with debug logging enabled</div>
1884
2497
  * </AtomixGlass>
1885
- */ function AtomixGlass({children: children, displacementScale: displacementScale = ATOMIX_GLASS.DEFAULTS.DISPLACEMENT_SCALE, blurAmount: blurAmount = ATOMIX_GLASS.DEFAULTS.BLUR_AMOUNT, saturation: saturation = ATOMIX_GLASS.DEFAULTS.SATURATION, aberrationIntensity: aberrationIntensity = ATOMIX_GLASS.DEFAULTS.ABERRATION_INTENSITY, elasticity: elasticity = ATOMIX_GLASS.DEFAULTS.ELASTICITY, borderRadius: borderRadius, globalMousePosition: externalGlobalMousePosition, mouseOffset: externalMouseOffset, mouseContainer: mouseContainer = null, className: className = "", padding: padding = ATOMIX_GLASS.DEFAULTS.PADDING, overLight: overLight = ATOMIX_GLASS.DEFAULTS.OVER_LIGHT, style: style = {}, mode: mode = ATOMIX_GLASS.DEFAULTS.MODE, onClick: onClick, shaderVariant: shaderVariant = "liquidGlass", "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, role: role, tabIndex: tabIndex, reducedMotion: reducedMotion = !1, highContrast: highContrast = !1, withoutEffects: withoutEffects = !1, withLiquidBlur: withLiquidBlur = !1, withBorder: withBorder = !0, withOverLightLayers: withOverLightLayers = ATOMIX_GLASS.DEFAULTS.ENABLE_OVER_LIGHT_LAYERS, debugPerformance: debugPerformance = !1, debugBorderRadius: debugBorderRadius = !1, debugOverLight: debugOverLight = !1, height: height, width: width, ...rest}) {
1886
- const glassRef = useRef(null), contentRef = useRef(null), {zIndex: customZIndex, ...restStyle} = style, isFixedOrSticky = "fixed" === restStyle.position || "sticky" === restStyle.position, {isHovered: isHovered, isActive: isActive, glassSize: glassSize, effectiveBorderRadius: effectiveBorderRadius, effectiveReducedMotion: effectiveReducedMotion, effectiveHighContrast: effectiveHighContrast, effectiveWithoutEffects: effectiveWithoutEffects, overLightConfig: overLightConfig, globalMousePosition: globalMousePosition, mouseOffset: mouseOffset, transformStyle: transformStyle, handleMouseEnter: handleMouseEnter, handleMouseLeave: handleMouseLeave, handleMouseDown: handleMouseDown, handleMouseUp: handleMouseUp, handleKeyDown: handleKeyDown} = useAtomixGlass({
2498
+ *
2499
+ * @example
2500
+ * // Performance-optimized for mobile devices
2501
+ * <AtomixGlass devicePreset="performance" disableResponsiveBreakpoints={false}>
2502
+ * <div>Mobile-optimized glass effect</div>
2503
+ * </AtomixGlass>
2504
+ */
2505
+ function AtomixGlass({children: children, displacementScale: displacementScale = ATOMIX_GLASS.DEFAULTS.DISPLACEMENT_SCALE, blurAmount: blurAmount = ATOMIX_GLASS.DEFAULTS.BLUR_AMOUNT, saturation: saturation = ATOMIX_GLASS.DEFAULTS.SATURATION, aberrationIntensity: aberrationIntensity = ATOMIX_GLASS.DEFAULTS.ABERRATION_INTENSITY, elasticity: elasticity = ATOMIX_GLASS.DEFAULTS.ELASTICITY, borderRadius: borderRadius, globalMousePosition: externalGlobalMousePosition, mouseOffset: externalMouseOffset, mouseContainer: mouseContainer = null, className: className = "", padding: padding = ATOMIX_GLASS.DEFAULTS.PADDING, overLight: overLight = ATOMIX_GLASS.DEFAULTS.OVER_LIGHT, style: style = {}, mode: mode = ATOMIX_GLASS.DEFAULTS.MODE, onClick: onClick, shaderVariant: shaderVariant = "liquidGlass", "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, role: role, tabIndex: tabIndex, reducedMotion: reducedMotion = !1, highContrast: highContrast = !1, withoutEffects: withoutEffects = !1, withLiquidBlur: withLiquidBlur = !1, withBorder: withBorder = !0, withOverLightLayers: withOverLightLayers = ATOMIX_GLASS.DEFAULTS.ENABLE_OVER_LIGHT_LAYERS, debugPerformance: debugPerformance = !1, debugOverLight: debugOverLight = !1, height: height, width: width, withTimeAnimation: withTimeAnimation = !1, animationSpeed: animationSpeed = 1, withMultiLayerDistortion: withMultiLayerDistortion = !1, distortionOctaves: distortionOctaves = 3, distortionLacunarity: distortionLacunarity = 2, distortionGain: distortionGain = .5, distortionQuality: distortionQuality = "medium", devicePreset: devicePreset = "balanced", disableResponsiveBreakpoints: disableResponsiveBreakpoints = !1, ...rest}) {
2506
+ const glassRef = useRef(null), contentRef = useRef(null), {zIndex: customZIndex, ...restStyle} = style, isFixedOrSticky = "fixed" === restStyle.position || "sticky" === restStyle.position, {isHovered: isHovered, isActive: isActive, glassSize: glassSize, effectiveBorderRadius: effectiveBorderRadius, effectiveReducedMotion: effectiveReducedMotion, effectiveHighContrast: effectiveHighContrast, effectiveWithoutEffects: effectiveWithoutEffects, overLightConfig: overLightConfig, globalMousePosition: globalMousePosition, mouseOffset: mouseOffset, transformStyle: transformStyle, getShaderTime: getShaderTime, applyTimeBasedDistortion: applyTimeBasedDistortion, handleMouseEnter: handleMouseEnter, handleMouseLeave: handleMouseLeave, handleMouseDown: handleMouseDown, handleMouseUp: handleMouseUp, handleKeyDown: handleKeyDown} = useAtomixGlass({
1887
2507
  glassRef: glassRef,
1888
2508
  contentRef: contentRef,
1889
2509
  borderRadius: borderRadius,
@@ -1896,7 +2516,6 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
1896
2516
  withoutEffects: withoutEffects,
1897
2517
  elasticity: elasticity,
1898
2518
  onClick: onClick,
1899
- debugBorderRadius: debugBorderRadius,
1900
2519
  debugOverLight: debugOverLight,
1901
2520
  debugPerformance: debugPerformance,
1902
2521
  children: children,
@@ -1905,8 +2524,389 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
1905
2524
  withLiquidBlur: withLiquidBlur,
1906
2525
  padding: padding,
1907
2526
  style: style,
1908
- isFixedOrSticky: isFixedOrSticky
1909
- }), isOverLight = useMemo((() => overLightConfig.isOverLight), [ overLightConfig.isOverLight ]), shouldRenderOverLightLayers = withOverLightLayers && isOverLight, rootLayoutStyle = useMemo((() => {
2527
+ isFixedOrSticky: isFixedOrSticky,
2528
+ // Phase 1: Animation System props
2529
+ withTimeAnimation: withTimeAnimation,
2530
+ animationSpeed: animationSpeed,
2531
+ withMultiLayerDistortion: withMultiLayerDistortion,
2532
+ distortionOctaves: distortionOctaves,
2533
+ distortionLacunarity: distortionLacunarity,
2534
+ distortionGain: distortionGain,
2535
+ distortionQuality: distortionQuality
2536
+ });
2537
+ // Re-calculate only when devicePreset changes
2538
+ // Responsive breakpoint system - automatically adjusts parameters based on viewport
2539
+ !
2540
+ /**
2541
+ * Responsive Glass Parameters Hook
2542
+ *
2543
+ * Automatically adjusts glass effect parameters based on:
2544
+ * 1. Screen size (mobile/tablet/desktop breakpoints)
2545
+ * 2. Device performance (RAM and CPU detection)
2546
+ * 3. Custom breakpoint configuration
2547
+ *
2548
+ * Features:
2549
+ * - Debounced resize handling
2550
+ * - Performance-based quality adjustment
2551
+ * - Smooth parameter transitions
2552
+ * - Debug mode for development
2553
+ *
2554
+ * @example
2555
+ * ```typescript
2556
+ * const { responsiveParams, currentBreakpoint } = useResponsiveGlass({
2557
+ * baseParams: {
2558
+ * distortionOctaves: 5,
2559
+ * displacementScale: 20,
2560
+ * blurAmount: 10,
2561
+ * },
2562
+ * debug: true,
2563
+ * });
2564
+ * ```
2565
+ *
2566
+ * @param options Hook configuration options
2567
+ * @returns Responsive parameters and metadata
2568
+ */
2569
+ function({baseParams: baseParams, breakpoints: breakpoints = DEFAULT_BREAKPOINTS, enabled: enabled = !0, enablePerformanceAdjustment: enablePerformanceAdjustment = !0, debug: debug = !1}) {
2570
+ const [responsiveParams, setResponsiveParams] = useState(baseParams), [currentBreakpoint, setCurrentBreakpoint] = useState("desktop"), [performanceTier, setPerformanceTier] = useState("high"), [isActive, setIsActive] = useState(enabled), baseParamsRef = useRef(baseParams), breakpointsRef = useRef(breakpoints);
2571
+ // Update refs when props change
2572
+ baseParamsRef.current = baseParams, breakpointsRef.current = breakpoints;
2573
+ /**
2574
+ * Calculate and apply responsive parameters
2575
+ */
2576
+ const calculateParams = useCallback((() => {
2577
+ if (!enabled || "undefined" == typeof window) return setIsActive(!1), setResponsiveParams(baseParamsRef.current),
2578
+ void setCurrentBreakpoint("disabled");
2579
+ setIsActive(!0);
2580
+ // Get current screen width
2581
+ const width = window.innerWidth, {name: name, params: breakpointParams} = ((width, breakpoints) => {
2582
+ // Convert breakpoints to array and sort by minWidth descending
2583
+ const sortedBreakpoints = Object.entries(breakpoints).filter((([_, bp]) => void 0 !== bp.minWidth)).sort(((a, b) => (b[1].minWidth || 0) - (a[1].minWidth || 0)));
2584
+ // Find first breakpoint where width >= minWidth
2585
+ for (const [name, bp] of sortedBreakpoints) if (width >= (bp.minWidth || 0)) return {
2586
+ name: name,
2587
+ params: bp.params
2588
+ };
2589
+ // If no minWidth matched, check maxWidth breakpoints
2590
+ const maxWidthBreakpoints = Object.entries(breakpoints).filter((([_, bp]) => void 0 !== bp.maxWidth)).sort(((a, b) => (a[1].maxWidth || 1 / 0) - (b[1].maxWidth || 1 / 0)));
2591
+ for (const [name, bp] of maxWidthBreakpoints) if (width <= (bp.maxWidth || 1 / 0)) return {
2592
+ name: name,
2593
+ params: bp.params
2594
+ };
2595
+ // Fallback to first available breakpoint
2596
+ const entries = Object.entries(breakpoints);
2597
+ if (0 === entries.length)
2598
+ // Ultimate fallback - return sensible defaults
2599
+ return {
2600
+ name: "desktop",
2601
+ params: {
2602
+ distortionOctaves: 5,
2603
+ displacementScale: 1,
2604
+ blurAmount: 1
2605
+ }
2606
+ };
2607
+ const firstEntry = entries[0];
2608
+ if (!firstEntry) return {
2609
+ name: "desktop",
2610
+ params: {
2611
+ distortionOctaves: 5,
2612
+ displacementScale: 1,
2613
+ blurAmount: 1
2614
+ }
2615
+ };
2616
+ const [fallbackName, fallbackBreakpoint] = firstEntry;
2617
+ return {
2618
+ name: fallbackName,
2619
+ params: fallbackBreakpoint.params
2620
+ };
2621
+ })(width, breakpointsRef.current);
2622
+ // Determine current breakpoint
2623
+ setCurrentBreakpoint(name);
2624
+ // Merge base params with breakpoint params
2625
+ let mergedParams = ((baseParams, breakpointParams) => {
2626
+ const result = {
2627
+ ...baseParams
2628
+ }, scaleProperties = [ "displacementScale", "blurAmount", "saturation", "aberrationIntensity", "animationSpeed", "chromaticIntensity" ];
2629
+ // Apply scaling for specific properties
2630
+ for (const prop of scaleProperties) void 0 !== breakpointParams[prop] && void 0 !== baseParams[prop] && (result[prop] = baseParams[prop] * breakpointParams[prop]);
2631
+ // Override properties that should be set directly (not scaled)
2632
+ const overrideProperties = [ "distortionOctaves", "distortionLacunarity", "distortionGain" ];
2633
+ for (const prop of overrideProperties) void 0 !== breakpointParams[prop] && (result[prop] = breakpointParams[prop]);
2634
+ return result;
2635
+ })(baseParamsRef.current, breakpointParams);
2636
+ // Apply performance adjustments if enabled
2637
+ if (enablePerformanceAdjustment) {
2638
+ const tier = (() => {
2639
+ // Check if we're in a browser environment
2640
+ if ("undefined" == typeof window || "undefined" == typeof navigator) return "high"; // Default to high for SSR
2641
+ // Device Memory API (Chrome, Edge, Opera)
2642
+ // Returns RAM in GB: 0.25, 0.5, 1, 2, 4, 8
2643
+ const deviceMemory = navigator.deviceMemory || 4, hardwareConcurrency = navigator.hardwareConcurrency || 4;
2644
+ // Hardware Concurrency API (logical CPU cores)
2645
+ // Low-end: ≤2GB RAM OR ≤2 CPU cores
2646
+ return deviceMemory <= 2 || hardwareConcurrency <= 2 ? "low" :
2647
+ // High-end: ≥4GB RAM AND ≥4 CPU cores
2648
+ deviceMemory >= 4 && hardwareConcurrency >= 4 ? "high" : "medium";
2649
+ })();
2650
+ setPerformanceTier(tier), mergedParams = ((baseParams, performanceTier) => {
2651
+ if ("high" === performanceTier) return baseParams;
2652
+ // No adjustment needed
2653
+ const multiplier = "low" === performanceTier ? .7 : .85;
2654
+ return {
2655
+ ...baseParams,
2656
+ distortionOctaves: Math.max(2, Math.round((baseParams.distortionOctaves || 5) * multiplier)),
2657
+ displacementScale: (baseParams.displacementScale || 1) * multiplier,
2658
+ blurAmount: (baseParams.blurAmount || 1) * multiplier,
2659
+ animationSpeed: (baseParams.animationSpeed || 1) * multiplier,
2660
+ chromaticIntensity: (baseParams.chromaticIntensity || 1) * multiplier
2661
+ };
2662
+ })(mergedParams, tier);
2663
+ }
2664
+ setResponsiveParams(mergedParams);
2665
+ }), [ enabled, enablePerformanceAdjustment, debug ]), debouncedCalculate = (func => {
2666
+ const timeoutRef = useRef(null);
2667
+ return useEffect((() => () => {
2668
+ timeoutRef.current && clearTimeout(timeoutRef.current);
2669
+ }), []), useCallback(((...args) => {
2670
+ timeoutRef.current && clearTimeout(timeoutRef.current), timeoutRef.current = setTimeout((() => {
2671
+ func(...args);
2672
+ }), 200);
2673
+ }), [ func, 200 ]);
2674
+ })(calculateParams);
2675
+ /**
2676
+ * Debounced parameter calculation for resize events
2677
+ */
2678
+ /**
2679
+ * Handle window resize
2680
+ */
2681
+ useEffect((() => {
2682
+ if (enabled)
2683
+ // Cleanup
2684
+ // Initial calculation
2685
+ return calculateParams(),
2686
+ // Listen for resize events
2687
+ window.addEventListener("resize", debouncedCalculate), () => {
2688
+ window.removeEventListener("resize", debouncedCalculate);
2689
+ };
2690
+ // eslint-disable-next-line react-hooks/exhaustive-deps
2691
+ }), [ enabled ]), useCallback((() => {
2692
+ calculateParams();
2693
+ }), [ calculateParams ]);
2694
+ }
2695
+ /**
2696
+ * Get GPU memory info if available (Chrome DevTools only)
2697
+ */ ({
2698
+ baseParams: {
2699
+ ...useMemo((() =>
2700
+ /**
2701
+ * Get preset by name
2702
+ */
2703
+ function(presetName) {
2704
+ switch (presetName) {
2705
+ case "performance":
2706
+ return PERFORMANCE_PRESET;
2707
+
2708
+ case "balanced":
2709
+ default:
2710
+ return BALANCED_PRESET;
2711
+
2712
+ case "quality":
2713
+ return QUALITY_PRESET;
2714
+ }
2715
+ }
2716
+ /**
2717
+ * Mobile-optimized responsive breakpoints
2718
+ * Automatically applies appropriate presets based on viewport size
2719
+ */ (devicePreset)), [ devicePreset ]),
2720
+ distortionOctaves: Math.round((displacementScale || ATOMIX_GLASS.DEFAULTS.DISPLACEMENT_SCALE) / 25),
2721
+ displacementScale: displacementScale || ATOMIX_GLASS.DEFAULTS.DISPLACEMENT_SCALE,
2722
+ blurAmount: blurAmount || ATOMIX_GLASS.DEFAULTS.BLUR_AMOUNT,
2723
+ saturation: saturation || ATOMIX_GLASS.DEFAULTS.SATURATION,
2724
+ aberrationIntensity: aberrationIntensity || ATOMIX_GLASS.DEFAULTS.ABERRATION_INTENSITY,
2725
+ animationSpeed: 1,
2726
+ chromaticIntensity: aberrationIntensity || ATOMIX_GLASS.DEFAULTS.ABERRATION_INTENSITY
2727
+ },
2728
+ breakpoints: MOBILE_OPTIMIZED_BREAKPOINTS,
2729
+ enabled: !disableResponsiveBreakpoints && "undefined" != typeof window,
2730
+ // Enable unless disabled
2731
+ debug: !1
2732
+ });
2733
+ // Performance monitoring - tracks FPS, frame time, memory usage
2734
+ const {metrics: performanceMetrics, recommendedQuality: recommendedQuality, isUnderperforming: isUnderperforming, setQualityLevel: setQualityLevel, toggleMonitoring: toggleMonitoring} =
2735
+ /**
2736
+ * Performance Monitor Hook
2737
+ *
2738
+ * Real-time performance tracking with automatic quality scaling.
2739
+ * Monitors FPS, frame time, and GPU memory to optimize glass effects.
2740
+ *
2741
+ * Features:
2742
+ * - Real-time FPS measurement
2743
+ * - Frame timing analysis
2744
+ * - Automatic quality scaling
2745
+ * - Debug overlay option
2746
+ * - Manual override capability
2747
+ *
2748
+ * @example
2749
+ * ```typescript
2750
+ * const { metrics, recommendedQuality, setQualityLevel } = usePerformanceMonitor({
2751
+ * targetFps: 60,
2752
+ * minFps: 45,
2753
+ * debug: true,
2754
+ * });
2755
+ * ```
2756
+ *
2757
+ * @param config Monitor configuration
2758
+ * @returns Performance metrics and controls
2759
+ */
2760
+ function(config = {}) {
2761
+ const {enabled: enabled = !0, targetFps: targetFps = 60, minFps: minFps = 45, scaleUpThreshold: scaleUpThreshold = 58, lowFpsFrames: lowFpsFrames = 3, highFpsFrames: highFpsFrames = 10, debug: debug = !1, showOverlay: showOverlay = !1} = config, [metrics, setMetrics] = useState({
2762
+ fps: 0,
2763
+ frameTime: 0,
2764
+ gpuMemory: null,
2765
+ qualityLevel: "medium",
2766
+ timestamp: 0,
2767
+ isAutoScaling: !0,
2768
+ lowFpsCount: 0
2769
+ }), [manualOverride, setManualOverride] = useState(!1), [isEnabled, setIsEnabled] = useState(enabled), frameCountRef = useRef(0), lastFpsUpdateRef = useRef(0), lastFrameTimeRef = useRef(0), animationFrameRef = useRef(null), lowFpsCountRef = useRef(0), highFpsCountRef = useRef(0), qualityLevelRef = useRef("medium"), updateMetrics = useCallback((newMetrics => {
2770
+ setMetrics((prev => ({
2771
+ ...prev,
2772
+ ...newMetrics,
2773
+ timestamp: performance.now()
2774
+ })));
2775
+ }), []), applyAutoScaling = useCallback((currentFps => {
2776
+ if (manualOverride) return;
2777
+ const currentQuality = qualityLevelRef.current;
2778
+ // Check for low FPS
2779
+ if (currentFps < minFps) lowFpsCountRef.current++, highFpsCountRef.current = 0,
2780
+ // Scale down after N consecutive low-FPS frames
2781
+ lowFpsCountRef.current >= lowFpsFrames && "low" !== currentQuality && (qualityLevelRef.current = "low",
2782
+ updateMetrics({
2783
+ qualityLevel: "low",
2784
+ lowFpsCount: lowFpsCountRef.current
2785
+ })); else if (currentFps >= scaleUpThreshold) {
2786
+ // Scale up after N consecutive high-FPS frames
2787
+ if (highFpsCountRef.current++, lowFpsCountRef.current = 0, highFpsCountRef.current >= highFpsFrames) {
2788
+ const newQuality = "low" === currentQuality ? "medium" : "high";
2789
+ qualityLevelRef.current = newQuality, updateMetrics({
2790
+ qualityLevel: newQuality,
2791
+ lowFpsCount: 0
2792
+ }), highFpsCountRef.current = 0;
2793
+ }
2794
+ } else
2795
+ // FPS in normal range, reset counters
2796
+ lowFpsCountRef.current = 0, highFpsCountRef.current = 0;
2797
+ }), [ manualOverride, minFps, scaleUpThreshold, lowFpsFrames, highFpsFrames, debug, updateMetrics ]), measureFrame = useCallback((currentTime => {
2798
+ if (!isEnabled) return;
2799
+ frameCountRef.current++;
2800
+ // Calculate frame time
2801
+ const frameTime = currentTime - lastFrameTimeRef.current;
2802
+ // Update FPS every 100ms for responsiveness
2803
+ if (lastFrameTimeRef.current = currentTime, currentTime - lastFpsUpdateRef.current >= 100) {
2804
+ const elapsed = currentTime - lastFpsUpdateRef.current, fps = Math.round(1e3 * frameCountRef.current / elapsed);
2805
+ // Apply auto-scaling
2806
+ applyAutoScaling(fps), updateMetrics({
2807
+ fps: fps,
2808
+ frameTime: frameTime,
2809
+ qualityLevel: qualityLevelRef.current,
2810
+ lowFpsCount: lowFpsCountRef.current
2811
+ }),
2812
+ // Reset for next measurement period
2813
+ frameCountRef.current = 0, lastFpsUpdateRef.current = currentTime;
2814
+ }
2815
+ // Continue measurement loop
2816
+ animationFrameRef.current = requestAnimationFrame(measureFrame);
2817
+ }), [ isEnabled, applyAutoScaling, updateMetrics ]);
2818
+ /**
2819
+ * Initialize GPU memory tracking
2820
+ */
2821
+ useEffect((() => {
2822
+ if (!isEnabled || "undefined" == typeof window) return;
2823
+ let mounted = !0;
2824
+ return (async () => {
2825
+ const memory = await new Promise((resolve => {
2826
+ // Check for WebGL debug renderer info
2827
+ if ("undefined" != typeof window && "undefined" != typeof document) try {
2828
+ const canvas = document.createElement("canvas"), gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
2829
+ if (gl) {
2830
+ const debugInfo = gl.getExtension("WEBGL_debug_renderer_info");
2831
+ if (debugInfo) {
2832
+ var _context, _context2, _context3;
2833
+ // Note: Actual memory info is not directly available via WebGL
2834
+ // We estimate based on renderer
2835
+ const renderer = gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL);
2836
+ // Rough estimation based on renderer type
2837
+ return void ((null == (_context = renderer) ? void 0 : Function.call.bind(_includesInstanceProperty(_context), _context))?.("Integrated") ? resolve(256) : (null == (_context2 = renderer) ? void 0 : Function.call.bind(_includesInstanceProperty(_context2), _context2))?.("AMD") || (null == (_context3 = renderer) ? void 0 : Function.call.bind(_includesInstanceProperty(_context3), _context3))?.("NVIDIA") ? resolve(512) : resolve(null));
2838
+ }
2839
+ }
2840
+ } catch (e) {
2841
+ // WebGL not available or error occurred
2842
+ }
2843
+ resolve(null);
2844
+ }));
2845
+ mounted && updateMetrics({
2846
+ gpuMemory: memory
2847
+ });
2848
+ })(), () => {
2849
+ mounted = !1;
2850
+ };
2851
+ }), [ isEnabled, updateMetrics ]),
2852
+ /**
2853
+ * Start/stop monitoring based on enabled state
2854
+ */
2855
+ useEffect((() => {
2856
+ if (isEnabled)
2857
+ // Cleanup
2858
+ // Initialize
2859
+ return lastFpsUpdateRef.current = performance.now(), lastFrameTimeRef.current = performance.now(),
2860
+ animationFrameRef.current = requestAnimationFrame(measureFrame), () => {
2861
+ null !== animationFrameRef.current && (cancelAnimationFrame(animationFrameRef.current),
2862
+ animationFrameRef.current = null);
2863
+ };
2864
+ // eslint-disable-next-line react-hooks/exhaustive-deps
2865
+ null !== animationFrameRef.current && (cancelAnimationFrame(animationFrameRef.current),
2866
+ animationFrameRef.current = null);
2867
+ }), [ isEnabled ]);
2868
+ // measureFrame is stable via useCallback, avoid re-creating RAF loop
2869
+ /**
2870
+ * Manually set quality level (disables auto-scaling)
2871
+ */
2872
+ const setQualityLevel = useCallback((level => {
2873
+ setManualOverride(!0), qualityLevelRef.current = level, updateMetrics({
2874
+ qualityLevel: level,
2875
+ isAutoScaling: !1
2876
+ });
2877
+ }), [ updateMetrics, debug ]), resetAutoScaling = useCallback((() => {
2878
+ setManualOverride(!1), lowFpsCountRef.current = 0, highFpsCountRef.current = 0,
2879
+ updateMetrics({
2880
+ isAutoScaling: !0,
2881
+ lowFpsCount: 0
2882
+ });
2883
+ }), [ updateMetrics, debug ]), toggleMonitoring = useCallback((() => {
2884
+ setIsEnabled((prev => !prev));
2885
+ }), []);
2886
+ /**
2887
+ * Reset to auto-scaling mode
2888
+ */ var fps, currentQuality;
2889
+ return {
2890
+ metrics: metrics,
2891
+ recommendedQuality: (fps = metrics.fps, currentQuality = metrics.qualityLevel, fps >= 58 ? "high" : fps >= 45 ? "high" === currentQuality ? "high" : "medium" : "low"),
2892
+ isUnderperforming: metrics.fps < minFps,
2893
+ setQualityLevel: setQualityLevel,
2894
+ resetAutoScaling: resetAutoScaling,
2895
+ toggleMonitoring: toggleMonitoring
2896
+ };
2897
+ }({
2898
+ enabled: !1,
2899
+ // We'll toggle manually based on prop
2900
+ debug: !1,
2901
+ showOverlay: !1
2902
+ });
2903
+ // Auto-start performance monitoring if enabled (only in development)
2904
+ React.useEffect((() => {
2905
+ "development" === process.env.NODE_ENV && window?.enablePerformanceMonitoring && toggleMonitoring();
2906
+ // eslint-disable-next-line react-hooks/exhaustive-deps
2907
+ }), []);
2908
+ // Only run once on mount
2909
+ const isOverLight = useMemo((() => overLightConfig.isOverLight), [ overLightConfig.isOverLight ]), shouldRenderOverLightLayers = withOverLightLayers && isOverLight, rootLayoutStyle = useMemo((() => {
1910
2910
  if (!isFixedOrSticky) return {};
1911
2911
  const {position: p, top: t, left: l, right: r, bottom: b} = restStyle;
1912
2912
  return {
@@ -2092,6 +3092,15 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
2092
3092
  effectiveReducedMotion: effectiveReducedMotion,
2093
3093
  shaderVariant: shaderVariant,
2094
3094
  withLiquidBlur: withLiquidBlur,
3095
+ // Phase 1: Animation System props
3096
+ shaderTime: getShaderTime(),
3097
+ withTimeAnimation: withTimeAnimation,
3098
+ animationSpeed: animationSpeed,
3099
+ withMultiLayerDistortion: withMultiLayerDistortion,
3100
+ distortionOctaves: distortionOctaves,
3101
+ distortionLacunarity: distortionLacunarity,
3102
+ distortionGain: distortionGain,
3103
+ distortionQuality: distortionQuality,
2095
3104
  children: children
2096
3105
  }), Boolean(onClick) && jsxs(Fragment, {
2097
3106
  children: [ jsx("div", {
@@ -2115,6 +3124,10 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
2115
3124
  }), jsx("span", {
2116
3125
  className: ATOMIX_GLASS.BORDER_2_CLASS
2117
3126
  }) ]
3127
+ }), debugPerformance && performanceMetrics && jsx(PerformanceDashboard, {
3128
+ metrics: performanceMetrics,
3129
+ isVisible: !0,
3130
+ onClose: () => {}
2118
3131
  }) ]
2119
3132
  });
2120
3133
  }
@@ -2181,7 +3194,7 @@ const AccordionBody = forwardRef((({children: children, className: className =
2181
3194
 
2182
3195
  AccordionBody.displayName = "AccordionBody";
2183
3196
 
2184
- const AccordionImpl = memo((({title: title, children: children, defaultOpen: defaultOpen = !1, isOpen: controlledOpen, onOpenChange: onOpenChange, onOpen: onOpen, onClose: onClose, disabled: disabled = !1, iconPosition: iconPosition = "right", icon: icon, className: className = "", style: style, glass: glass}) => {
3197
+ const AccordionImpl = memo((({title: title, children: children, defaultOpen: defaultOpen = !1, isOpen: controlledOpen, onOpenChange: onOpenChange, disabled: disabled = !1, iconPosition: iconPosition = "right", icon: icon, className: className = "", style: style, glass: glass}) => {
2185
3198
  // Generate unique IDs for accessibility
2186
3199
  const instanceId = useId(), buttonId = `accordion-header-${instanceId}`, panelId = `accordion-panel-${instanceId}`, {state: state, toggle: toggle, updatePanelHeight: updatePanelHeight, panelRef: panelRef, contentRef: contentRef, generateClassNames: generateClassNames, generateHeaderClassNames: generateHeaderClassNames} =
2187
3200
  /**
@@ -2225,9 +3238,7 @@ const AccordionImpl = memo((({title: title, children: children, defaultOpen: de
2225
3238
  toggle: () => {
2226
3239
  if (!defaultProps.disabled) {
2227
3240
  const nextOpen = !isOpen;
2228
- isControlled || setInternalOpen(nextOpen), defaultProps.onOpenChange?.(nextOpen),
2229
- // Call legacy handlers
2230
- nextOpen ? defaultProps.onOpen?.() : defaultProps.onClose?.();
3241
+ isControlled || setInternalOpen(nextOpen), defaultProps.onOpenChange?.(nextOpen);
2231
3242
  }
2232
3243
  },
2233
3244
  updatePanelHeight: updatePanelHeight,
@@ -2241,9 +3252,7 @@ const AccordionImpl = memo((({title: title, children: children, defaultOpen: de
2241
3252
  disabled: disabled,
2242
3253
  iconPosition: iconPosition,
2243
3254
  isOpen: controlledOpen,
2244
- onOpenChange: onOpenChange,
2245
- onOpen: onOpen,
2246
- onClose: onClose
3255
+ onOpenChange: onOpenChange
2247
3256
  }), headerClassNames = generateHeaderClassNames(), panelClassNames = ACCORDION.SELECTORS.PANEL.replace(".", ""), hasCompoundComponents = React.Children.toArray(children).some((child => {
2248
3257
  var _context;
2249
3258
 
@@ -2767,7 +3776,7 @@ class ThemeNaming {
2767
3776
  ThemeNaming.prefix = "atomix";
2768
3777
 
2769
3778
  const Button = React.memo( forwardRef((({label: label, children: children, onClick: onClick, variant: variant = "primary", size: size = "md", disabled: disabled = !1, loading: loading = !1, loadingText: loadingText, icon: icon, iconName: iconName, iconSize: iconSize = "sm", iconPosition: iconPosition = "start", iconOnly: iconOnly = !1, rounded: rounded = !1, fullWidth: fullWidth = !1, block: block = !1, active: active = !1, selected: selected = !1, type: type = "button", className: className = "", as: Component = "button", href: href, target: target, glass: glass, onHover: onHover, onFocus: onFocus, onBlur: onBlur, "aria-label": ariaLabel, "aria-describedby": ariaDescribedBy, "aria-expanded": ariaExpanded, "aria-controls": ariaControls, tabIndex: tabIndex, style: style, linkComponent: linkComponent, ...props}, ref) => {
2770
- const isDisabled = disabled || loading, shouldRenderAsLink = Boolean(href && !isDisabled), iconElement = iconName ? jsx(Icon, {
3779
+ const isDisabled = disabled || loading, shouldRenderAsLink = Boolean(href), iconElement = iconName ? jsx(Icon, {
2771
3780
  name: iconName,
2772
3781
  size: iconSize
2773
3782
  }) : icon, buttonClass = [ BUTTON.BASE_CLASS, ThemeNaming.variantClass("btn", variant), "md" !== size ? ThemeNaming.sizeClass("btn", size) : "", iconOnly ? ThemeNaming.stateClass("btn", "icon") : "", rounded ? ThemeNaming.stateClass("btn", "rounded") : "", isDisabled ? ThemeNaming.stateClass("btn", "disabled") : "", glass ? ThemeNaming.stateClass("btn", "glass") : "", loading ? BUTTON.CLASSES.LOADING : "", fullWidth ? BUTTON.CLASSES.FULL_WIDTH : "", block ? BUTTON.CLASSES.BLOCK : "", active ? BUTTON.CLASSES.ACTIVE : "", selected ? BUTTON.CLASSES.SELECTED : "", className ].filter(Boolean).join(" "), handleClickEvent = useCallback((event => {
@@ -2823,8 +3832,8 @@ const Button = React.memo( forwardRef((({label: label, children: children, onCl
2823
3832
  ...buttonProps,
2824
3833
  ref: ref,
2825
3834
  // linkComponent usually forwards ref to anchor
2826
- href: href,
2827
- to: href,
3835
+ href: isDisabled ? void 0 : href,
3836
+ to: isDisabled ? void 0 : href,
2828
3837
  target: target,
2829
3838
  rel: "_blank" === target ? "noopener noreferrer" : void 0
2830
3839
  };
@@ -2837,7 +3846,7 @@ const Button = React.memo( forwardRef((({label: label, children: children, onCl
2837
3846
  content = jsx("a", {
2838
3847
  ...buttonProps,
2839
3848
  ref: ref,
2840
- href: href,
3849
+ href: isDisabled ? void 0 : href,
2841
3850
  target: target,
2842
3851
  rel: "_blank" === target ? "noopener noreferrer" : void 0,
2843
3852
  children: buttonContent
@@ -2879,7 +3888,7 @@ row: row = !1, flat: flat = !1,
2879
3888
  // States
2880
3889
  active: active = !1, disabled: disabled = !1, loading: loading = !1, selected: selected = !1, interactive: interactive = !1,
2881
3890
  // Content
2882
- header: header, image: image, imageAlt: imageAlt = "", title: title, text: text, actions: actions, icon: icon, footer: footer, children: children,
3891
+ header: header, image: image, imageAlt: imageAlt = "Card image", title: title, text: text, actions: actions, icon: icon, footer: footer, children: children,
2883
3892
  // Interaction
2884
3893
  onClick: onClick, onHover: onHover, onFocus: onFocus, href: href, target: target,
2885
3894
  // Custom Link
@@ -3684,7 +4693,9 @@ const smoothStep = (a, b, t) => {
3684
4693
  return this.canvasDPI;
3685
4694
  }
3686
4695
  },
3687
- fragmentShaders: fragmentShaders
4696
+ createFBMEngine: createFBMEngine,
4697
+ fragmentShaders: fragmentShaders,
4698
+ liquidGlassWithTime: liquidGlassWithTime
3688
4699
  }, Symbol.toStringTag, {
3689
4700
  value: "Module"
3690
4701
  }));