@shohojdhara/atomix 0.4.7 → 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 (176) hide show
  1. package/atomix.config.ts +58 -1
  2. package/dist/atomix.css +172 -157
  3. package/dist/atomix.css.map +1 -1
  4. package/dist/atomix.min.css +4 -4
  5. package/dist/atomix.min.css.map +1 -1
  6. package/dist/charts.d.ts +33 -0
  7. package/dist/charts.js +1274 -164
  8. package/dist/charts.js.map +1 -1
  9. package/dist/core.d.ts +33 -10
  10. package/dist/core.js +1099 -83
  11. package/dist/core.js.map +1 -1
  12. package/dist/forms.d.ts +33 -0
  13. package/dist/forms.js +2106 -1050
  14. package/dist/forms.js.map +1 -1
  15. package/dist/heavy.d.ts +42 -1
  16. package/dist/heavy.js +1663 -638
  17. package/dist/heavy.js.map +1 -1
  18. package/dist/index.d.ts +442 -270
  19. package/dist/index.esm.js +1947 -680
  20. package/dist/index.esm.js.map +1 -1
  21. package/dist/index.js +1982 -712
  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 +136 -1827
  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 +115 -0
  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 +218 -0
  44. package/scripts/cli/commands/init.js +73 -0
  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/compiler.js +114 -0
  52. package/scripts/cli/internal/component-validator.js +443 -0
  53. package/scripts/cli/internal/config-loader.js +162 -0
  54. package/scripts/cli/internal/filesystem.js +158 -0
  55. package/scripts/cli/internal/generator.js +430 -0
  56. package/scripts/cli/internal/glass-generator.js +398 -0
  57. package/scripts/cli/internal/hook-generator.js +369 -0
  58. package/scripts/cli/internal/hooks.js +61 -0
  59. package/scripts/cli/internal/itcss-generator.js +565 -0
  60. package/scripts/cli/internal/motion-generator.js +679 -0
  61. package/scripts/cli/internal/template-engine.js +301 -0
  62. package/scripts/cli/internal/theme-bridge.js +664 -0
  63. package/scripts/cli/internal/tokens/engine.js +122 -0
  64. package/scripts/cli/internal/tokens/provider.js +34 -0
  65. package/scripts/cli/internal/tokens/providers/figma.js +50 -0
  66. package/scripts/cli/internal/tokens/providers/style-dictionary.js +48 -0
  67. package/scripts/cli/internal/tokens/providers/w3c.js +48 -0
  68. package/scripts/cli/internal/tokens/token-provider.js +443 -0
  69. package/scripts/cli/internal/tokens/token-validator.js +513 -0
  70. package/scripts/cli/internal/validator.js +276 -0
  71. package/scripts/cli/internal/wizard.js +115 -0
  72. package/scripts/cli/mappings.js +23 -0
  73. package/scripts/cli/migration-tools.js +164 -94
  74. package/scripts/cli/plugins/style-dictionary.js +46 -0
  75. package/scripts/cli/templates/README.md +525 -95
  76. package/scripts/cli/templates/common-templates.js +40 -14
  77. package/scripts/cli/templates/components/react-component.ts +282 -0
  78. package/scripts/cli/templates/config/project-config.ts +112 -0
  79. package/scripts/cli/templates/hooks/use-component.ts +477 -0
  80. package/scripts/cli/templates/index.js +19 -4
  81. package/scripts/cli/templates/index.ts +171 -0
  82. package/scripts/cli/templates/next-templates.js +72 -0
  83. package/scripts/cli/templates/react-templates.js +70 -126
  84. package/scripts/cli/templates/scss-templates.js +35 -35
  85. package/scripts/cli/templates/stories/storybook-story.ts +241 -0
  86. package/scripts/cli/templates/styles/scss-component.ts +255 -0
  87. package/scripts/cli/templates/tests/vitest-test.ts +229 -0
  88. package/scripts/cli/templates/token-templates.js +337 -1
  89. package/scripts/cli/templates/tokens/token-generators.ts +1088 -0
  90. package/scripts/cli/templates/types/component-types.ts +145 -0
  91. package/scripts/cli/templates/utils/testing-utils.ts +144 -0
  92. package/scripts/cli/templates/vanilla-templates.js +39 -0
  93. package/scripts/cli/token-manager.js +8 -2
  94. package/scripts/cli/utils/cache-manager.js +240 -0
  95. package/scripts/cli/utils/detector.js +46 -0
  96. package/scripts/cli/utils/diagnostics.js +289 -0
  97. package/scripts/cli/utils/error.js +89 -0
  98. package/scripts/cli/utils/helpers.js +67 -0
  99. package/scripts/cli/utils/logger.js +75 -0
  100. package/scripts/cli/utils/security.js +302 -0
  101. package/scripts/cli/utils/telemetry.js +115 -0
  102. package/scripts/cli/utils/validation.js +37 -0
  103. package/scripts/cli/utils.js +28 -341
  104. package/src/components/Accordion/Accordion.stories.tsx +0 -18
  105. package/src/components/Accordion/Accordion.test.tsx +0 -17
  106. package/src/components/Accordion/Accordion.tsx +0 -4
  107. package/src/components/AtomixGlass/AtomixGlass.test.tsx +37 -3
  108. package/src/components/AtomixGlass/AtomixGlass.tsx +143 -31
  109. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +129 -31
  110. package/src/components/AtomixGlass/PerformanceDashboard.tsx +219 -0
  111. package/src/components/AtomixGlass/README.md +25 -10
  112. package/src/components/AtomixGlass/__snapshots__/AtomixGlass.test.tsx.snap +216 -0
  113. package/src/components/AtomixGlass/animation-system.ts +578 -0
  114. package/src/components/AtomixGlass/shader-utils.ts +4 -1
  115. package/src/components/AtomixGlass/stories/Overview.stories.tsx +157 -6
  116. package/src/components/AtomixGlass/stories/Phase1-Animation.stories.tsx +653 -0
  117. package/src/components/AtomixGlass/stories/Phase1-Test.stories.tsx +95 -0
  118. package/src/components/AtomixGlass/stories/Playground.stories.tsx +51 -51
  119. package/src/components/AtomixGlass/stories/shared-components.tsx +6 -0
  120. package/src/components/Avatar/Avatar.tsx +1 -1
  121. package/src/components/Button/Button.stories.disabled-link.tsx +10 -0
  122. package/src/components/Button/Button.stories.tsx +10 -0
  123. package/src/components/Button/Button.test.tsx +16 -11
  124. package/src/components/Button/Button.tsx +4 -4
  125. package/src/components/Card/Card.tsx +1 -1
  126. package/src/components/Dropdown/Dropdown.tsx +12 -12
  127. package/src/components/Form/Select.tsx +62 -3
  128. package/src/components/Modal/Modal.tsx +14 -3
  129. package/src/components/Navigation/Navbar/Navbar.tsx +44 -0
  130. package/src/components/Slider/Slider.stories.tsx +3 -3
  131. package/src/components/Slider/Slider.tsx +38 -0
  132. package/src/components/Steps/Steps.tsx +3 -3
  133. package/src/components/Tabs/Tabs.tsx +77 -8
  134. package/src/components/Testimonial/Testimonial.tsx +1 -1
  135. package/src/components/TypedButton/TypedButton.stories.tsx +59 -0
  136. package/src/components/TypedButton/TypedButton.tsx +39 -0
  137. package/src/components/TypedButton/index.ts +2 -0
  138. package/src/components/VideoPlayer/VideoPlayer.tsx +11 -4
  139. package/src/lib/composables/index.ts +4 -7
  140. package/src/lib/composables/types.ts +45 -0
  141. package/src/lib/composables/useAccordion.ts +0 -7
  142. package/src/lib/composables/useAtomixGlass.ts +148 -6
  143. package/src/lib/composables/useAtomixGlassStyles.ts +9 -7
  144. package/src/lib/composables/useChartExport.ts +3 -13
  145. package/src/lib/composables/useDropdown.ts +66 -0
  146. package/src/lib/composables/useFocusTrap.ts +80 -0
  147. package/src/lib/composables/usePerformanceMonitor.ts +448 -0
  148. package/src/lib/composables/useResponsiveGlass.presets.ts +192 -0
  149. package/src/lib/composables/useResponsiveGlass.ts +441 -0
  150. package/src/lib/composables/useTooltip.ts +16 -0
  151. package/src/lib/composables/useTypedButton.ts +66 -0
  152. package/src/lib/config/index.ts +62 -5
  153. package/src/lib/constants/components.ts +62 -7
  154. package/src/lib/theme/devtools/__tests__/useHistory.test.tsx +150 -0
  155. package/src/lib/theme/tokens/centralized-tokens.ts +120 -0
  156. package/src/lib/theme/utils/__tests__/domUtils.test.ts +101 -0
  157. package/src/lib/types/components.ts +37 -11
  158. package/src/lib/types/glass.ts +35 -0
  159. package/src/lib/types/index.ts +1 -0
  160. package/src/lib/utils/displacement-generator.ts +1 -1
  161. package/src/styles/01-settings/_settings.testtypecheck.scss +53 -0
  162. package/src/styles/01-settings/_settings.typedbutton.scss +53 -0
  163. package/src/styles/06-components/_components.atomix-glass.scss +17 -21
  164. package/src/styles/06-components/_components.edge-panel.scss +1 -5
  165. package/src/styles/06-components/_components.modal.scss +1 -4
  166. package/src/styles/06-components/_components.navbar.scss +1 -1
  167. package/src/styles/06-components/_components.testbutton.scss +212 -0
  168. package/src/styles/06-components/_components.testtypecheck.scss +212 -0
  169. package/src/styles/06-components/_components.tooltip.scss +9 -5
  170. package/src/styles/06-components/_components.typedbutton.scss +212 -0
  171. package/src/styles/99-utilities/_index.scss +1 -0
  172. package/src/styles/99-utilities/_utilities.text.scss +1 -1
  173. package/src/styles/99-utilities/_utilities.touch-target.scss +36 -0
  174. package/scripts/cli/component-generator.js +0 -564
  175. package/scripts/cli/interactive-init.js +0 -357
  176. 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
@@ -554,20 +554,29 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
554
554
  SHADER: "c-atomix-glass--shader"
555
555
  },
556
556
  DEFAULTS: {
557
- DISPLACEMENT_SCALE: 20,
558
- BLUR_AMOUNT: 1,
557
+ DISPLACEMENT_SCALE: 70,
558
+ BLUR_AMOUNT: 0,
559
559
  SATURATION: 140,
560
- ABERRATION_INTENSITY: 2.5,
561
- ELASTICITY: .05,
562
- CORNER_RADIUS: 16,
560
+ ABERRATION_INTENSITY: 2,
561
+ ELASTICITY: .15,
562
+ CORNER_RADIUS: 20,
563
563
  // Default border-radius matching design system
564
- PADDING: "0 0",
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
- ACTIVATION_ZONE: 350,
579
+ ACTIVATION_ZONE: 200,
571
580
  LERP_FACTOR: .08,
572
581
  SMOOTHSTEP_POWER: 2.5,
573
582
  MIN_BLUR: .1,
@@ -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;
@@ -975,20 +1022,19 @@ let idCounter = 0;
975
1022
  const sharedShaderCache = new Map, AtomixGlassContainer = forwardRef((({children: children, className: className = "", style: style, displacementScale: displacementScale = 25, blurAmount: blurAmount = .0625, saturation: saturation = 180, aberrationIntensity: aberrationIntensity = 2, mouseOffset: mouseOffset = {
976
1023
  x: 0,
977
1024
  y: 0
978
- }, globalMousePosition: globalMousePosition = {
979
- x: 0,
980
- y: 0
981
- }, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, onMouseDown: onMouseDown, onMouseUp: onMouseUp, isHovered: isHovered = !1, isActive: isActive = !1, overLight: overLight = !1, overLightConfig: overLightConfig = {}, borderRadius: borderRadius = 0, padding: padding = "0 0", glassSize: glassSize = {
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 = {
982
1026
  width: 0,
983
1027
  height: 0
984
- }, 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) => {
985
1031
  // Generate a stable, deterministic ID for SSR compatibility
986
1032
  // Use a module-level counter that's consistent across server and client
987
- 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);
988
1034
  // Lazy load shader utilities only when shader mode is needed
989
1035
  useEffect((() => {
990
1036
  "shader" === mode ?
991
- // Dynamic import shader utilities
1037
+ // Dynamic import shader utilities with animation support
992
1038
  Promise.resolve().then((() => shaderUtils)).then((shaderUtils => {
993
1039
  shaderUtilsRef.current = {
994
1040
  ShaderDisplacementGenerator: shaderUtils.ShaderDisplacementGenerator,
@@ -1003,7 +1049,7 @@ const sharedShaderCache = new Map, AtomixGlassContainer = forwardRef((({childre
1003
1049
  // Generate shader map with debouncing and caching
1004
1050
  useEffect((() => {
1005
1051
  // Enhanced validation for shader mode
1006
- if ("shader" === mode && glassSize && validateGlassSize(glassSize) && shaderUtilsRef.current) {
1052
+ if ("shader" === mode && glassSize && validateGlassSize(glassSize)) {
1007
1053
  // Create cache key from size and variant
1008
1054
  const cacheKey = `${glassSize.width}x${glassSize.height}-${shaderVariant}`, cachedUrl = (key => {
1009
1055
  const entry = sharedShaderCache.get(key);
@@ -1025,11 +1071,9 @@ const sharedShaderCache = new Map, AtomixGlassContainer = forwardRef((({childre
1025
1071
  width: glassSize.width,
1026
1072
  height: glassSize.height,
1027
1073
  fragment: selectedShader
1028
- }),
1029
- // Defer shader generation with longer delay to avoid blocking
1030
- setTimeout((() => {
1074
+ }), shaderUpdateTimeoutRef.current = setTimeout((() => {
1031
1075
  const url = shaderGeneratorRef.current?.updateShader() || "";
1032
- ((key, url) => {
1076
+ url && ((key, url) => {
1033
1077
  // Evict oldest entries if at capacity
1034
1078
  if (sharedShaderCache.size >= 15) {
1035
1079
  const entries = Array.from(sharedShaderCache.entries());
@@ -1061,7 +1105,8 @@ const sharedShaderCache = new Map, AtomixGlassContainer = forwardRef((({childre
1061
1105
  // Cleanup function with error handling
1062
1106
  return () => {
1063
1107
  shaderDebounceTimeoutRef.current && (clearTimeout(shaderDebounceTimeoutRef.current),
1064
- shaderDebounceTimeoutRef.current = null);
1108
+ shaderDebounceTimeoutRef.current = null), shaderUpdateTimeoutRef.current && (clearTimeout(shaderUpdateTimeoutRef.current),
1109
+ shaderUpdateTimeoutRef.current = null);
1065
1110
  try {
1066
1111
  shaderGeneratorRef.current?.destroy();
1067
1112
  } catch (error) {
@@ -1070,7 +1115,37 @@ const sharedShaderCache = new Map, AtomixGlassContainer = forwardRef((({childre
1070
1115
  shaderGeneratorRef.current = null;
1071
1116
  }
1072
1117
  };
1073
- }), [ 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 ]);
1074
1149
  // Removed forced reflow to avoid layout thrash and potential feedback sizing loops
1075
1150
  const [rectCache, setRectCache] = useState(null);
1076
1151
  useEffect((() => {
@@ -1122,21 +1197,18 @@ const sharedShaderCache = new Map, AtomixGlassContainer = forwardRef((({childre
1122
1197
  backdropFilter: `blur(${blurAmount}px) saturate(${saturation}%) contrast(1.05) brightness(1.05)`
1123
1198
  };
1124
1199
  }
1125
- }), [ liquidBlur, saturation, blurAmount, rectCache, effectiveReducedMotion, effectiveWithoutEffects, withLiquidBlur ]), containerVars = useMemo((() => {
1200
+ }), [ liquidBlur, saturation, blurAmount, rectCache, effectiveReducedMotion, effectiveWithoutEffects, withLiquidBlur, overLightConfig ]), containerVars = useMemo((() => {
1126
1201
  try {
1127
1202
  // Safe extraction of mouse offset values
1128
1203
  const mx = mouseOffset && "number" == typeof mouseOffset.x && !isNaN(mouseOffset.x) ? mouseOffset.x : 0, my = mouseOffset && "number" == typeof mouseOffset.y && !isNaN(mouseOffset.y) ? mouseOffset.y : 0;
1129
1204
  return {
1130
- "--atomix-glass-container-width": `${glassSize?.width}`,
1131
- "--atomix-glass-container-height": `${glassSize?.height}`,
1132
- "--atomix-glass-container-padding": padding || "0 0",
1133
1205
  "--atomix-glass-container-radius": `${"number" != typeof borderRadius || isNaN(borderRadius) ? 0 : borderRadius}px`,
1134
1206
  "--atomix-glass-container-backdrop": backdropStyle?.backdropFilter || "none",
1135
1207
  "--atomix-glass-container-shadow": overLight ? [ `inset 0 1px 0 rgba(255, 255, 255, ${(.4 + .002 * mx) * (overLightConfig?.shadowIntensity || 1)})`, `inset 0 -1px 0 rgba(0, 0, 0, ${(.2 + .001 * Math.abs(my)) * (overLightConfig?.shadowIntensity || 1)})`, `inset 0 0 20px rgba(0, 0, 0, ${(.08 + .001 * Math.abs(mx + my)) * (overLightConfig?.shadowIntensity || 1)})`, `0 2px 12px rgba(0, 0, 0, ${(.12 + .002 * Math.abs(my)) * (overLightConfig?.shadowIntensity || 1)})` ].join(", ") : "0 0 20px rgba(0, 0, 0, 0.15) inset, 0 4px 8px rgba(0, 0, 0, 0.08) inset",
1136
1208
  "--atomix-glass-container-shadow-opacity": effectiveWithoutEffects ? 0 : 1,
1137
1209
  // Background and shadow values use design token-aligned RGB values
1138
1210
  "--atomix-glass-container-bg": overLight ? `linear-gradient(${180 + .5 * mx}deg, rgba(255, 255, 255, 0.1) 0%, transparent 20%, transparent 80%, rgba(0, 0, 0, 0.05) 100%)` : "none",
1139
- "--atomix-glass-container-text-shadow": overLight ? "0px 2px 12px rgba(0, 0, 0, 0)" : "0px 2px 12px rgba(0, 0, 0, 0.4)",
1211
+ "--atomix-glass-container-text-shadow": overLight ? "0px 1px 2px rgba(255, 255, 255, 0.15)" : "0px 2px 12px rgba(0, 0, 0, 0.4)",
1140
1212
  "--atomix-glass-container-box-shadow": overLight ? "0px 16px 70px rgba(0, 0, 0, 0.75)" : "0px 12px 40px rgba(0, 0, 0, 0.25)"
1141
1213
  };
1142
1214
  } catch (error) {
@@ -1151,7 +1223,7 @@ const sharedShaderCache = new Map, AtomixGlassContainer = forwardRef((({childre
1151
1223
  "--atomix-glass-container-text-shadow": "none"
1152
1224
  };
1153
1225
  }
1154
- }), [ glassSize, padding, borderRadius, backdropStyle, mouseOffset, overLight, effectiveWithoutEffects ]);
1226
+ }), [ borderRadius, backdropStyle, mouseOffset, overLight, effectiveWithoutEffects, overLightConfig ]);
1155
1227
  return jsx("div", {
1156
1228
  ref: el => {
1157
1229
  // Apply force no-transition
@@ -1180,10 +1252,6 @@ const sharedShaderCache = new Map, AtomixGlassContainer = forwardRef((({childre
1180
1252
  aberrationIntensity: "number" != typeof aberrationIntensity || isNaN(aberrationIntensity) ? 0 : aberrationIntensity,
1181
1253
  shaderMapUrl: shaderMapUrl
1182
1254
  }), jsx("div", {
1183
- ref: el => {
1184
- el && (el.style.setProperty("transition-duration", "0s", "important"), el.style.setProperty("animation-duration", "0s", "important"),
1185
- el.style.setProperty("transition-delay", "0s", "important"));
1186
- },
1187
1255
  className: ATOMIX_GLASS.FILTER_OVERLAY_CLASS,
1188
1256
  style: {
1189
1257
  filter: `url(#${filterId})`
@@ -1288,7 +1356,7 @@ class {
1288
1356
  }
1289
1357
  }, updateAtomixGlassStyles = (wrapperElement, containerElement, params) => {
1290
1358
  if (!wrapperElement && !containerElement) return;
1291
- const {mouseOffset: mouseOffset, globalMousePosition: globalMousePosition, glassSize: glassSize, isHovered: isHovered, isActive: isActive, isOverLight: isOverLight, baseOverLightConfig: baseOverLightConfig, effectiveBorderRadius: effectiveBorderRadius, effectiveWithoutEffects: effectiveWithoutEffects, effectiveReducedMotion: effectiveReducedMotion, elasticity: elasticity, directionalScale: directionalScale, onClick: onClick, withLiquidBlur: withLiquidBlur, blurAmount: blurAmount = ATOMIX_GLASS.DEFAULTS.BLUR_AMOUNT, saturation: saturation = ATOMIX_GLASS.DEFAULTS.SATURATION, padding: padding = ATOMIX_GLASS.DEFAULTS.PADDING} = params, mouseInfluence = calculateMouseInfluence(mouseOffset), hoverIntensity = isHovered ? 1.4 : 1, activeIntensity = isActive ? 1.6 : 1, overLightConfig = {
1359
+ const {mouseOffset: mouseOffset, globalMousePosition: globalMousePosition, glassSize: glassSize, isHovered: isHovered, isActive: isActive, isOverLight: isOverLight, baseOverLightConfig: baseOverLightConfig, effectiveBorderRadius: effectiveBorderRadius, effectiveWithoutEffects: effectiveWithoutEffects, effectiveReducedMotion: effectiveReducedMotion, elasticity: elasticity, directionalScale: directionalScale, onClick: onClick, withLiquidBlur: withLiquidBlur, blurAmount: blurAmount = ATOMIX_GLASS.DEFAULTS.BLUR_AMOUNT, saturation: saturation = ATOMIX_GLASS.DEFAULTS.SATURATION, padding: padding = ATOMIX_GLASS.DEFAULTS.PADDING, isFixedOrSticky: isFixedOrSticky = !1} = params, mouseInfluence = calculateMouseInfluence(mouseOffset), hoverIntensity = isHovered ? 1.4 : 1, activeIntensity = isActive ? 1.6 : 1, overLightConfig = {
1292
1360
  opacity: baseOverLightConfig.opacity * hoverIntensity * activeIntensity,
1293
1361
  contrast: Math.min(1.6, baseOverLightConfig.contrast + .1 * mouseInfluence),
1294
1362
  brightness: Math.min(1.1, baseOverLightConfig.brightness + .05 * mouseInfluence),
@@ -1378,7 +1446,7 @@ class {
1378
1446
  }
1379
1447
  // Update Container Styles (containerVars)
1380
1448
  if (containerElement) {
1381
- const mx = mouseOffset.x, my = mouseOffset.y, EDGE_BLUR_MULTIPLIER = 1.25, CENTER_BLUR_MULTIPLIER = 1.1, FLOW_BLUR_MULTIPLIER = 1.2, MOUSE_INFLUENCE_BLUR_FACTOR = .15, EDGE_INTENSITY_MOUSE_FACTOR = .15, CENTER_INTENSITY_MOUSE_FACTOR = .1, MAX_BLUR_RELATIVE = 2, rect = containerElement.getBoundingClientRect();
1449
+ const mx = mouseOffset.x, my = mouseOffset.y, EDGE_BLUR_MULTIPLIER = .5, CENTER_BLUR_MULTIPLIER = .2, FLOW_BLUR_MULTIPLIER = .3, MOUSE_INFLUENCE_BLUR_FACTOR = .4, EDGE_INTENSITY_MOUSE_FACTOR = .15, CENTER_INTENSITY_MOUSE_FACTOR = .1, MAX_BLUR_RELATIVE = 2, rect = containerElement.getBoundingClientRect();
1382
1450
  let liquidBlur = {
1383
1451
  baseBlur: blurAmount,
1384
1452
  edgeBlur: blurAmount * EDGE_BLUR_MULTIPLIER,
@@ -1400,22 +1468,155 @@ class {
1400
1468
  backdropFilterString = !withLiquidBlur || effectiveReducedMotion || effectiveWithoutEffects || area > 18e4 ? `blur(${clampBlur(Math.max(liquidBlur.baseBlur, .8 * liquidBlur.edgeBlur, 1.1 * liquidBlur.centerBlur, .9 * liquidBlur.flowBlur))}px) saturate(${Math.min(dynamicSaturation, 200)}%) contrast(${overLightConfig.contrast}) brightness(${overLightConfig.brightness})` : `blur(${clampBlur(.4 * liquidBlur.baseBlur + .25 * liquidBlur.edgeBlur + .15 * liquidBlur.centerBlur + .2 * liquidBlur.flowBlur)}px) saturate(${Math.min(dynamicSaturation, 200)}%) contrast(${overLightConfig.contrast}) brightness(${overLightConfig.brightness})`;
1401
1469
  // Container variables
1402
1470
  const style = containerElement.style;
1403
- style.setProperty("--atomix-glass-container-width", `${glassSize.width}`), style.setProperty("--atomix-glass-container-height", `${glassSize.height}`),
1471
+ style.setProperty("--atomix-glass-container-width", isFixedOrSticky ? `${glassSize.width}` : "100%"),
1472
+ style.setProperty("--atomix-glass-container-height", isFixedOrSticky ? `${glassSize.height}` : "100%"),
1404
1473
  style.setProperty("--atomix-glass-container-padding", padding), style.setProperty("--atomix-glass-container-radius", `${effectiveBorderRadius}px`),
1405
1474
  style.setProperty("--atomix-glass-container-backdrop", backdropFilterString),
1406
1475
  // Shadows
1407
1476
  style.setProperty("--atomix-glass-container-shadow", isOverLight ? [ `inset 0 1px 0 rgba(255, 255, 255, ${(.4 + .002 * mx) * (overLightConfig.shadowIntensity || 1)})`, `inset 0 -1px 0 rgba(0, 0, 0, ${(.2 + .001 * Math.abs(my)) * (overLightConfig.shadowIntensity || 1)})`, `inset 0 0 20px rgba(0, 0, 0, ${(.08 + .001 * Math.abs(mx + my)) * (overLightConfig.shadowIntensity || 1)})`, `0 2px 12px rgba(0, 0, 0, ${(.12 + .002 * Math.abs(my)) * (overLightConfig.shadowIntensity || 1)})` ].join(", ") : "0 0 20px rgba(0, 0, 0, 0.15) inset, 0 4px 8px rgba(0, 0, 0, 0.08) inset"),
1408
1477
  style.setProperty("--atomix-glass-container-shadow-opacity", effectiveWithoutEffects ? "0" : "1"),
1409
1478
  style.setProperty("--atomix-glass-container-bg", isOverLight ? `linear-gradient(${180 + .5 * mx}deg, rgba(255, 255, 255, 0.1) 0%, transparent 20%, transparent 80%, rgba(0, 0, 0, 0.05) 100%)` : "none"),
1410
- style.setProperty("--atomix-glass-container-text-shadow", isOverLight ? "0px 2px 12px rgba(0, 0, 0, 0)" : "0px 2px 12px rgba(0, 0, 0, 0.4)"),
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)"),
1411
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)");
1412
1481
  }
1413
- }, {CONSTANTS: CONSTANTS$1} = ATOMIX_GLASS;
1482
+ };
1414
1483
 
1415
1484
  /**
1416
1485
  * Updates the styles of the AtomixGlass wrapper and container elements imperatively
1417
1486
  * to avoid React re-renders on mouse movement.
1418
- */ 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) => {
1419
1620
  parentElement && backgroundDetectionCache.set(parentElement, {
1420
1621
  result: result,
1421
1622
  timestamp: Date.now(),
@@ -1428,7 +1629,9 @@ class {
1428
1629
  * Composable hook for AtomixGlass component logic
1429
1630
  * Manages all state, calculations, and event handlers
1430
1631
  */
1431
- 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, debugPerformance: debugPerformance = !1, children: children, blurAmount: blurAmount, saturation: saturation, padding: padding, withLiquidBlur: withLiquidBlur}) {
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}) {
1432
1635
  // State
1433
1636
  const [isHovered, setIsHovered] = useState(!1), [isActive, setIsActive] = useState(!1), cachedRectRef = useRef(null), internalGlobalMousePositionRef = useRef({
1434
1637
  x: 0,
@@ -1442,7 +1645,47 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
1442
1645
  }), targetGlobalMousePositionRef = useRef({
1443
1646
  x: 0,
1444
1647
  y: 0
1445
- }), 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}) {
1446
1689
  const [glassSize, setGlassSize] = useState({
1447
1690
  width: 270,
1448
1691
  height: 69
@@ -1501,7 +1744,10 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
1501
1744
  glassRef: glassRef,
1502
1745
  effectiveBorderRadius: effectiveBorderRadius,
1503
1746
  cachedRectRef: cachedRectRef
1504
- }), 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
+ */
1505
1751
  // Extract border-radius from children
1506
1752
  useEffect((() => {
1507
1753
  const extractRadius = () => {
@@ -1704,6 +1950,8 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
1704
1950
  lerpActiveRef.current = !0;
1705
1951
  const LERP_T = CONSTANTS.LERP_FACTOR, tick = () => {
1706
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);
1707
1955
  const cur = internalMouseOffsetRef.current, tgt = targetMouseOffsetRef.current, dx = tgt.x - cur.x, dy = tgt.y - cur.y;
1708
1956
  // If we're close enough, snap and park
1709
1957
  if (Math.abs(dx) < .05 && Math.abs(dy) < .05) internalMouseOffsetRef.current = {
@@ -1712,17 +1960,17 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
1712
1960
  ...targetGlobalMousePositionRef.current
1713
1961
  }; else {
1714
1962
  internalMouseOffsetRef.current = {
1715
- x: lerp(cur.x, tgt.x, LERP_T),
1716
- 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)
1717
1965
  };
1718
1966
  const curG = internalGlobalMousePositionRef.current, tgtG = targetGlobalMousePositionRef.current;
1719
1967
  internalGlobalMousePositionRef.current = {
1720
- x: lerp(curG.x, tgtG.x, LERP_T),
1721
- 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)
1722
1970
  };
1723
1971
  }
1724
1972
  // Imperative style update with the smoothed values
1725
- updateAtomixGlassStyles(wrapperRef?.current || null, glassRef.current, {
1973
+ updateAtomixGlassStyles(wrapperRef.current, glassRef.current, {
1726
1974
  mouseOffset: internalMouseOffsetRef.current,
1727
1975
  globalMousePosition: internalGlobalMousePositionRef.current,
1728
1976
  glassSize: glassSize,
@@ -1739,12 +1987,13 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
1739
1987
  withLiquidBlur: withLiquidBlur,
1740
1988
  blurAmount: blurAmount,
1741
1989
  saturation: saturation,
1742
- padding: padding
1990
+ padding: padding,
1991
+ isFixedOrSticky: isFixedOrSticky
1743
1992
  }), lerpRafRef.current = requestAnimationFrame(tick);
1744
1993
  };
1745
1994
  // 0.08 – lower = more viscous
1746
1995
  lerpRafRef.current = requestAnimationFrame(tick);
1747
- }), [ glassRef, wrapperRef, glassSize, isHovered, isActive, overLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, onClick, withLiquidBlur, blurAmount, saturation, padding ]), stopLerpLoop = useCallback((() => {
1996
+ }), [ glassRef, wrapperRef, glassSize, isHovered, isActive, overLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, onClick, withLiquidBlur, blurAmount, saturation, padding, isFixedOrSticky ]), stopLerpLoop = useCallback((() => {
1748
1997
  lerpActiveRef.current = !1, null !== lerpRafRef.current && (cancelAnimationFrame(lerpRafRef.current),
1749
1998
  lerpRafRef.current = null);
1750
1999
  }), []);
@@ -1812,6 +2061,8 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
1812
2061
  // This is now static (refs or props) unless prop changes
1813
2062
  overLightConfig: overLightConfig,
1814
2063
  transformStyle: transformStyle,
2064
+ getShaderTime: getShaderTime,
2065
+ applyTimeBasedDistortion: applyTimeBasedDistortion,
1815
2066
  handleMouseEnter: handleMouseEnter,
1816
2067
  handleMouseLeave: handleMouseLeave,
1817
2068
  handleMouseDown: handleMouseDown,
@@ -1820,6 +2071,358 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
1820
2071
  };
1821
2072
  }
1822
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
+ */
1823
2426
  /**
1824
2427
  * AtomixGlass - A high-performance glass morphism component with liquid distortion effects
1825
2428
  *
@@ -1834,6 +2437,8 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
1834
2437
  * - Focus ring support for keyboard navigation
1835
2438
  * - Responsive breakpoints for mobile optimization
1836
2439
  * - Enhanced ARIA attributes for screen readers
2440
+ * - Time-based animation system with FBM distortion
2441
+ * - Device preset optimization for performance/quality balance
1837
2442
  *
1838
2443
  * Design System Compliance:
1839
2444
  * - Uses design tokens for opacity, spacing, and colors
@@ -1890,8 +2495,15 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
1890
2495
  * <AtomixGlass overLight="auto" debugOverLight={true}>
1891
2496
  * <div>Content with debug logging enabled</div>
1892
2497
  * </AtomixGlass>
1893
- */ 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}) {
1894
- const glassRef = useRef(null), contentRef = useRef(null), {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({
1895
2507
  glassRef: glassRef,
1896
2508
  contentRef: contentRef,
1897
2509
  borderRadius: borderRadius,
@@ -1904,7 +2516,6 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
1904
2516
  withoutEffects: withoutEffects,
1905
2517
  elasticity: elasticity,
1906
2518
  onClick: onClick,
1907
- debugBorderRadius: debugBorderRadius,
1908
2519
  debugOverLight: debugOverLight,
1909
2520
  debugPerformance: debugPerformance,
1910
2521
  children: children,
@@ -1912,8 +2523,390 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
1912
2523
  saturation: saturation,
1913
2524
  withLiquidBlur: withLiquidBlur,
1914
2525
  padding: padding,
1915
- style: style
1916
- }), isOverLight = useMemo((() => overLightConfig.isOverLight), [ overLightConfig.isOverLight ]), shouldRenderOverLightLayers = withOverLightLayers && isOverLight, {zIndex: customZIndex, ...restStyle} = style, isFixedOrSticky = "fixed" === restStyle.position || "sticky" === restStyle.position, rootLayoutStyle = useMemo((() => {
2526
+ style: style,
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((() => {
1917
2910
  if (!isFixedOrSticky) return {};
1918
2911
  const {position: p, top: t, left: l, right: r, bottom: b} = restStyle;
1919
2912
  return {
@@ -1933,7 +2926,10 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
1933
2926
  bottom: b
1934
2927
  }
1935
2928
  };
1936
- }), [ isFixedOrSticky, restStyle ]), baseStyle = useMemo((() => {
2929
+ }), [ isFixedOrSticky, restStyle ]);
2930
+ // Calculate base style with transforms
2931
+ // When layout is hoisted to the root, strip those props from the container
2932
+ useMemo((() => {
1937
2933
  if (isFixedOrSticky) {
1938
2934
  const {position: _p, top: _t, left: _l, right: _r, bottom: _b, ...visualStyle} = restStyle;
1939
2935
  return {
@@ -1949,18 +2945,20 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
1949
2945
  transform: transformStyle
1950
2946
  }
1951
2947
  };
1952
- }), [ isFixedOrSticky, restStyle, effectiveWithoutEffects, transformStyle ]), componentClassName = [ ATOMIX_GLASS.BASE_CLASS, effectiveReducedMotion && `${ATOMIX_GLASS.BASE_CLASS}--reduced-motion`, effectiveHighContrast && `${ATOMIX_GLASS.BASE_CLASS}--high-contrast`, effectiveWithoutEffects && `${ATOMIX_GLASS.BASE_CLASS}--disabled-effects`, className ].filter(Boolean).join(" "), positionStyles = useMemo((() => ({
2948
+ }), [ isFixedOrSticky, restStyle, effectiveWithoutEffects, transformStyle ]);
2949
+ // Build className with state modifiers
2950
+ const componentClassName = [ ATOMIX_GLASS.BASE_CLASS, effectiveReducedMotion && `${ATOMIX_GLASS.BASE_CLASS}--reduced-motion`, effectiveHighContrast && `${ATOMIX_GLASS.BASE_CLASS}--high-contrast`, effectiveWithoutEffects && `${ATOMIX_GLASS.BASE_CLASS}--disabled-effects`, className ].filter(Boolean).join(" "), positionStyles = useMemo((() => ({
1953
2951
  position: isFixedOrSticky ? "absolute" : restStyle.position || "absolute",
1954
2952
  top: isFixedOrSticky ? 0 : restStyle.top || 0,
1955
2953
  left: isFixedOrSticky ? 0 : restStyle.left || 0
1956
2954
  })), [ isFixedOrSticky, restStyle.position, restStyle.top, restStyle.left ]), adjustedSize = useMemo((() => {
1957
- const resolveSize = (propValue, styleValue, measuredSize) => {
1958
- const explicitSize = propValue ?? styleValue;
1959
- return void 0 !== explicitSize ? "number" == typeof explicitSize ? `${explicitSize}px` : explicitSize : "fixed" === positionStyles.position ? `${Math.max(measuredSize, 0)}px` : "100%";
1960
- };
2955
+ // Keep a reference to positionStyles to avoid unused-variable lint,
2956
+ // but sizing is driven by explicit width/height or measured size.
2957
+ positionStyles.position;
2958
+ const resolveLength = (value, measured) => void 0 !== value ? "number" == typeof value ? `${value}px` : value : measured > 0 ? `${measured}px` : "100%", effectiveWidth = width ?? restStyle.width, effectiveHeight = height ?? restStyle.height;
1961
2959
  return {
1962
- width: resolveSize(width, restStyle.width, glassSize.width),
1963
- height: resolveSize(height, restStyle.height, glassSize.height)
2960
+ width: resolveLength(effectiveWidth, glassSize.width),
2961
+ height: resolveLength(effectiveHeight, glassSize.height)
1964
2962
  };
1965
2963
  }), [ width, height, restStyle.width, restStyle.height, positionStyles.position, glassSize.width, glassSize.height ]), gradientValues = useMemo((() => {
1966
2964
  const mx = mouseOffset.x, my = mouseOffset.y, absMx = Math.abs(mx), absMy = Math.abs(my), GRADIENT = ATOMIX_GLASS.CONSTANTS.GRADIENT;
@@ -2009,9 +3007,10 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
2009
3007
  },
2010
3008
  "--atomix-glass-radius": `${effectiveBorderRadius}px`,
2011
3009
  "--atomix-glass-transform": transformStyle || "none",
2012
- "--atomix-glass-position": positionStyles.position,
2013
- "--atomix-glass-top": "fixed" !== positionStyles.top ? `${positionStyles.top}px` : "0",
2014
- "--atomix-glass-left": "fixed" !== positionStyles.left ? `${positionStyles.left}px` : "0",
3010
+ // Internal decorative layers are positioned relative to the root;
3011
+ "--atomix-glass-position": rootLayoutStyle.position,
3012
+ "--atomix-glass-top": `${isFixedOrSticky ? rootLayoutStyle.top : 0}px`,
3013
+ "--atomix-glass-left": `${isFixedOrSticky ? rootLayoutStyle.left : 0}px`,
2015
3014
  "--atomix-glass-width": adjustedSize.width,
2016
3015
  "--atomix-glass-height": adjustedSize.height,
2017
3016
  "--atomix-glass-border-width": "var(--atomix-spacing-0-5, 0.09375rem)",
@@ -2031,10 +3030,12 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
2031
3030
  "--atomix-glass-overlay-highlight-opacity": opacityValues.over * ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.OPACITY_MULTIPLIER,
2032
3031
  "--atomix-glass-overlay-highlight-bg": `radial-gradient(circle at ${ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.POSITION_X}% ${ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.POSITION_Y}%, rgba(255, 255, 255, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.WHITE_OPACITY}) 0%, transparent ${ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.STOP}%)`
2033
3032
  };
2034
- }), [ gradientValues, opacityValues, effectiveBorderRadius, transformStyle, positionStyles, adjustedSize, isOverLight, overLightConfig.borderOpacity, customZIndex ]), renderBackgroundLayer = layerType => jsx("div", {
3033
+ }), [ gradientValues, opacityValues, effectiveBorderRadius, transformStyle, adjustedSize, isOverLight, overLightConfig.borderOpacity, customZIndex, rootLayoutStyle, isFixedOrSticky ]), renderBackgroundLayer = layerType => jsx("div", {
2035
3034
  className: [ ATOMIX_GLASS.BACKGROUND_LAYER_CLASS, "dark" === layerType ? ATOMIX_GLASS.BACKGROUND_LAYER_DARK_CLASS : ATOMIX_GLASS.BACKGROUND_LAYER_BLACK_CLASS, isOverLight ? ATOMIX_GLASS.BACKGROUND_LAYER_OVER_LIGHT_CLASS : ATOMIX_GLASS.BACKGROUND_LAYER_HIDDEN_CLASS ].filter(Boolean).join(" ")
2036
3035
  });
2037
- return jsxs("div", {
3036
+ // Calculate position and size styles for internal layers
3037
+ // When root is fixed/sticky, internal layers use absolute (relative to root)
3038
+ return jsxs("div", {
2038
3039
  ...rest,
2039
3040
  className: componentClassName,
2040
3041
  style: {
@@ -2051,7 +3052,12 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
2051
3052
  ref: glassRef,
2052
3053
  contentRef: contentRef,
2053
3054
  className: className,
2054
- style: rootLayoutStyle,
3055
+ style: {
3056
+ ...restStyle,
3057
+ ...!isFixedOrSticky && {
3058
+ position: "relative"
3059
+ }
3060
+ },
2055
3061
  borderRadius: effectiveBorderRadius,
2056
3062
  displacementScale: effectiveWithoutEffects ? 0 : "shader" === mode ? displacementScale * ATOMIX_GLASS.CONSTANTS.MULTIPLIERS.SHADER_DISPLACEMENT : isOverLight ? displacementScale * ATOMIX_GLASS.CONSTANTS.MULTIPLIERS.OVER_LIGHT_DISPLACEMENT : displacementScale,
2057
3063
  blurAmount: effectiveWithoutEffects ? 0 : blurAmount,
@@ -2082,11 +3088,19 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
2082
3088
  },
2083
3089
  onClick: onClick,
2084
3090
  mode: mode,
2085
- transform: baseStyle.transform,
2086
3091
  effectiveWithoutEffects: effectiveWithoutEffects,
2087
3092
  effectiveReducedMotion: effectiveReducedMotion,
2088
3093
  shaderVariant: shaderVariant,
2089
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,
2090
3104
  children: children
2091
3105
  }), Boolean(onClick) && jsxs(Fragment, {
2092
3106
  children: [ jsx("div", {
@@ -2110,6 +3124,10 @@ function useAtomixGlass({glassRef: glassRef, contentRef: contentRef, wrapperRef:
2110
3124
  }), jsx("span", {
2111
3125
  className: ATOMIX_GLASS.BORDER_2_CLASS
2112
3126
  }) ]
3127
+ }), debugPerformance && performanceMetrics && jsx(PerformanceDashboard, {
3128
+ metrics: performanceMetrics,
3129
+ isVisible: !0,
3130
+ onClose: () => {}
2113
3131
  }) ]
2114
3132
  });
2115
3133
  }
@@ -2176,7 +3194,7 @@ const AccordionBody = forwardRef((({children: children, className: className =
2176
3194
 
2177
3195
  AccordionBody.displayName = "AccordionBody";
2178
3196
 
2179
- 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}) => {
2180
3198
  // Generate unique IDs for accessibility
2181
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} =
2182
3200
  /**
@@ -2220,9 +3238,7 @@ const AccordionImpl = memo((({title: title, children: children, defaultOpen: de
2220
3238
  toggle: () => {
2221
3239
  if (!defaultProps.disabled) {
2222
3240
  const nextOpen = !isOpen;
2223
- isControlled || setInternalOpen(nextOpen), defaultProps.onOpenChange?.(nextOpen),
2224
- // Call legacy handlers
2225
- nextOpen ? defaultProps.onOpen?.() : defaultProps.onClose?.();
3241
+ isControlled || setInternalOpen(nextOpen), defaultProps.onOpenChange?.(nextOpen);
2226
3242
  }
2227
3243
  },
2228
3244
  updatePanelHeight: updatePanelHeight,
@@ -2236,9 +3252,7 @@ const AccordionImpl = memo((({title: title, children: children, defaultOpen: de
2236
3252
  disabled: disabled,
2237
3253
  iconPosition: iconPosition,
2238
3254
  isOpen: controlledOpen,
2239
- onOpenChange: onOpenChange,
2240
- onOpen: onOpen,
2241
- onClose: onClose
3255
+ onOpenChange: onOpenChange
2242
3256
  }), headerClassNames = generateHeaderClassNames(), panelClassNames = ACCORDION.SELECTORS.PANEL.replace(".", ""), hasCompoundComponents = React.Children.toArray(children).some((child => {
2243
3257
  var _context;
2244
3258
 
@@ -2762,7 +3776,7 @@ class ThemeNaming {
2762
3776
  ThemeNaming.prefix = "atomix";
2763
3777
 
2764
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) => {
2765
- const isDisabled = disabled || loading, shouldRenderAsLink = Boolean(href && !isDisabled), iconElement = iconName ? jsx(Icon, {
3779
+ const isDisabled = disabled || loading, shouldRenderAsLink = Boolean(href), iconElement = iconName ? jsx(Icon, {
2766
3780
  name: iconName,
2767
3781
  size: iconSize
2768
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 => {
@@ -2818,8 +3832,8 @@ const Button = React.memo( forwardRef((({label: label, children: children, onCl
2818
3832
  ...buttonProps,
2819
3833
  ref: ref,
2820
3834
  // linkComponent usually forwards ref to anchor
2821
- href: href,
2822
- to: href,
3835
+ href: isDisabled ? void 0 : href,
3836
+ to: isDisabled ? void 0 : href,
2823
3837
  target: target,
2824
3838
  rel: "_blank" === target ? "noopener noreferrer" : void 0
2825
3839
  };
@@ -2832,7 +3846,7 @@ const Button = React.memo( forwardRef((({label: label, children: children, onCl
2832
3846
  content = jsx("a", {
2833
3847
  ...buttonProps,
2834
3848
  ref: ref,
2835
- href: href,
3849
+ href: isDisabled ? void 0 : href,
2836
3850
  target: target,
2837
3851
  rel: "_blank" === target ? "noopener noreferrer" : void 0,
2838
3852
  children: buttonContent
@@ -2874,7 +3888,7 @@ row: row = !1, flat: flat = !1,
2874
3888
  // States
2875
3889
  active: active = !1, disabled: disabled = !1, loading: loading = !1, selected: selected = !1, interactive: interactive = !1,
2876
3890
  // Content
2877
- 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,
2878
3892
  // Interaction
2879
3893
  onClick: onClick, onHover: onHover, onFocus: onFocus, href: href, target: target,
2880
3894
  // Custom Link
@@ -3679,7 +4693,9 @@ const smoothStep = (a, b, t) => {
3679
4693
  return this.canvasDPI;
3680
4694
  }
3681
4695
  },
3682
- fragmentShaders: fragmentShaders
4696
+ createFBMEngine: createFBMEngine,
4697
+ fragmentShaders: fragmentShaders,
4698
+ liquidGlassWithTime: liquidGlassWithTime
3683
4699
  }, Symbol.toStringTag, {
3684
4700
  value: "Module"
3685
4701
  }));