@shohojdhara/atomix 0.6.4 → 0.6.6

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 (83) hide show
  1. package/dist/atomix.css +117 -38
  2. package/dist/atomix.css.map +1 -1
  3. package/dist/atomix.min.css +1 -1
  4. package/dist/atomix.min.css.map +1 -1
  5. package/dist/atomix.umd.js +1 -1
  6. package/dist/atomix.umd.js.map +1 -1
  7. package/dist/atomix.umd.min.js +1 -1
  8. package/dist/charts.d.ts +30 -1
  9. package/dist/charts.js +625 -846
  10. package/dist/charts.js.map +1 -1
  11. package/dist/core.d.ts +30 -1
  12. package/dist/core.js +659 -873
  13. package/dist/core.js.map +1 -1
  14. package/dist/forms.d.ts +30 -1
  15. package/dist/forms.js +1171 -1402
  16. package/dist/forms.js.map +1 -1
  17. package/dist/heavy.d.ts +31 -89
  18. package/dist/heavy.js +975 -1195
  19. package/dist/heavy.js.map +1 -1
  20. package/dist/index.d.ts +383 -140
  21. package/dist/index.esm.js +1567 -1679
  22. package/dist/index.esm.js.map +1 -1
  23. package/dist/index.js +1556 -1667
  24. package/dist/index.js.map +1 -1
  25. package/dist/index.min.js +1 -1
  26. package/dist/index.min.js.map +1 -1
  27. package/package.json +1 -1
  28. package/src/components/Accordion/Accordion.tsx +2 -5
  29. package/src/components/AtomixGlass/AtomixGlass.test.tsx +14 -16
  30. package/src/components/AtomixGlass/AtomixGlass.tsx +137 -364
  31. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +32 -251
  32. package/src/components/AtomixGlass/GlassFilter.tsx +62 -68
  33. package/src/components/AtomixGlass/README.md +2 -1
  34. package/src/components/AtomixGlass/__snapshots__/AtomixGlass.test.tsx.snap +19 -18
  35. package/src/components/AtomixGlass/glass-border-styles.test.ts +58 -0
  36. package/src/components/AtomixGlass/glass-border-styles.ts +136 -0
  37. package/src/components/AtomixGlass/glass-utils.ts +456 -22
  38. package/src/components/AtomixGlass/shader-utils.ts +19 -77
  39. package/src/components/AtomixGlass/stories/AnimationFeatures.stories.tsx +158 -537
  40. package/src/components/AtomixGlass/stories/Border.stories.tsx +149 -0
  41. package/src/components/AtomixGlass/stories/Examples.stories.tsx +229 -89
  42. package/src/components/AtomixGlass/stories/Playground.stories.tsx +29 -340
  43. package/src/components/AtomixGlass/stories/argTypes.ts +30 -13
  44. package/src/components/AtomixGlass/stories/premium-presets.ts +206 -0
  45. package/src/components/AtomixGlass/stories/shared-components.tsx +52 -8
  46. package/src/components/Badge/Badge.tsx +4 -4
  47. package/src/components/Button/Button.tsx +2 -6
  48. package/src/components/Callout/Callout.test.tsx +4 -3
  49. package/src/components/Callout/Callout.tsx +2 -5
  50. package/src/components/Dropdown/Dropdown.tsx +3 -7
  51. package/src/components/Form/Checkbox.tsx +2 -8
  52. package/src/components/Form/Input.tsx +2 -9
  53. package/src/components/Form/Radio.tsx +2 -9
  54. package/src/components/Form/Select.test.tsx +6 -6
  55. package/src/components/Form/Select.tsx +2 -7
  56. package/src/components/Form/Textarea.stories.tsx +5 -5
  57. package/src/components/Form/Textarea.tsx +2 -9
  58. package/src/components/Messages/Messages.tsx +2 -8
  59. package/src/components/Modal/Modal.tsx +4 -5
  60. package/src/components/Navigation/Nav/Nav.tsx +2 -6
  61. package/src/components/Navigation/Navbar/Navbar.tsx +2 -9
  62. package/src/components/Navigation/SideMenu/SideMenu.tsx +2 -6
  63. package/src/components/Pagination/Pagination.tsx +2 -10
  64. package/src/components/Popover/Popover.tsx +2 -9
  65. package/src/components/Progress/Progress.tsx +2 -7
  66. package/src/components/Rating/Rating.tsx +2 -10
  67. package/src/components/Spinner/Spinner.tsx +2 -7
  68. package/src/components/Steps/Steps.tsx +2 -10
  69. package/src/components/Tabs/Tabs.tsx +2 -9
  70. package/src/components/Toggle/Toggle.tsx +2 -10
  71. package/src/components/Tooltip/Tooltip.tsx +2 -5
  72. package/src/lib/composables/useAtomixGlass.ts +42 -143
  73. package/src/lib/composables/useAtomixGlassStyles.ts +61 -77
  74. package/src/lib/composables/usePerformanceMonitor.ts +5 -66
  75. package/src/lib/constants/components.ts +363 -46
  76. package/src/lib/types/components.ts +33 -1
  77. package/src/styles/01-settings/_settings.atomix-glass.scss +66 -28
  78. package/src/styles/02-tools/_tools.button.scss +51 -42
  79. package/src/styles/02-tools/_tools.glass.scss +45 -3
  80. package/src/styles/06-components/_components.atomix-glass.scss +116 -79
  81. package/src/components/AtomixGlass/PerformanceDashboard.tsx +0 -171
  82. package/src/components/AtomixGlass/animation-system.ts +0 -578
  83. package/src/components/AtomixGlass/deprecated/AtomixGlass.deprecated.tsx +0 -390
package/dist/charts.js CHANGED
@@ -462,6 +462,44 @@ const _reduceInstanceProperty = getDefaultExportFromCjs((function(it) {
462
462
  POSITIONS: [ "top", "bottom", "left", "right" ],
463
463
  ACTION_VARIANTS: [ "primary", "secondary", "success", "info", "warning", "error" ]
464
464
  }
465
+ }, GLASS_BORDER_GRADIENT = {
466
+ BASE_ANGLE: 135,
467
+ ANGLE_MULTIPLIER: .5,
468
+ VELOCITY_ANGLE_MULTIPLIER: .5,
469
+ CHROMATIC_OFFSET: 1.5,
470
+ STOP_1: {
471
+ MIN: 10,
472
+ BASE: 33,
473
+ get MULTIPLIER() {
474
+ return .009 * this.BASE;
475
+ }
476
+ },
477
+ STOP_2: {
478
+ MAX: 90,
479
+ BASE: 66,
480
+ get MULTIPLIER() {
481
+ return .006 * this.BASE;
482
+ }
483
+ },
484
+ OPACITY: {
485
+ /** Matches $glass-border-1-opacity (0.08) */
486
+ BASE_1: .08,
487
+ get BASE_2() {
488
+ return 3.33 * this.BASE_1;
489
+ },
490
+ get BASE_3() {
491
+ return 2.66 * this.BASE_1;
492
+ },
493
+ get BASE_4() {
494
+ return 5 * this.BASE_1;
495
+ },
496
+ get MULTIPLIER_LOW() {
497
+ return .066 * this.BASE_1;
498
+ },
499
+ get MULTIPLIER_HIGH() {
500
+ return .1 * this.BASE_1;
501
+ }
502
+ }
465
503
  }, ATOMIX_GLASS = {
466
504
  BASE_CLASS: "c-atomix-glass",
467
505
  CONTAINER_CLASS: "c-atomix-glass__container",
@@ -473,6 +511,22 @@ const _reduceInstanceProperty = getDefaultExportFromCjs((function(it) {
473
511
  BORDER_BACKDROP_CLASS: "c-atomix-glass__border-backdrop",
474
512
  BORDER_1_CLASS: "c-atomix-glass__border-1",
475
513
  BORDER_2_CLASS: "c-atomix-glass__border-2",
514
+ /** Centralized liquid glass rim configuration */
515
+ BORDER: {
516
+ WIDTH_CSS_VAR: "--atomix-glass-border-width",
517
+ DEFAULT_WIDTH: "0.5px",
518
+ GRADIENT_CSS_VARS: {
519
+ GRADIENT_1: "--atomix-glass-border-gradient-1",
520
+ GRADIENT_2: "--atomix-glass-border-gradient-2"
521
+ },
522
+ GRADIENT: GLASS_BORDER_GRADIENT,
523
+ OVER_LIGHT: {
524
+ opacity: .7
525
+ },
526
+ DARK: {
527
+ opacity: .35
528
+ }
529
+ },
476
530
  HOVER_1_CLASS: "c-atomix-glass__hover-1",
477
531
  HOVER_2_CLASS: "c-atomix-glass__hover-2",
478
532
  HOVER_3_CLASS: "c-atomix-glass__hover-3",
@@ -501,25 +555,22 @@ const _reduceInstanceProperty = getDefaultExportFromCjs((function(it) {
501
555
  SHADER: "c-atomix-glass--shader"
502
556
  },
503
557
  DEFAULTS: {
504
- DISPLACEMENT_SCALE: 70,
558
+ /** Subtle refraction — Apple UI chrome avoids heavy liquid distortion */
559
+ DISPLACEMENT_SCALE: 28,
505
560
  get BLUR_AMOUNT() {
506
- return .15 * this.DISPLACEMENT_SCALE;
507
- // Dynamically computed based on displacement
508
- },
509
- get SATURATION() {
510
- return 100 + .5 * this.DISPLACEMENT_SCALE;
511
- // Saturate relative to intensity
512
- },
561
+ // Apple Music sidebar / player bar: ~20–40px frost (see $glass-backdrop-filter)
562
+ return Math.max(20, .72 * this.DISPLACEMENT_SCALE);
563
+ },
564
+ /** Fixed 180% matches Apple's saturate(180%) backdrop recipe */
565
+ SATURATION: 180,
513
566
  get ABERRATION_INTENSITY() {
514
- return .03 * this.DISPLACEMENT_SCALE;
515
- // Scale aberration with displacement
516
- },
517
- ELASTICITY: .15,
567
+ return .02 * this.DISPLACEMENT_SCALE;
568
+ },
569
+ ELASTICITY: .05,
518
570
  get CORNER_RADIUS() {
519
571
  return 16;
520
572
  // Use 16 to match SCSS design system (was 20)
521
573
  },
522
- PADDING: "0",
523
574
  MODE: "standard",
524
575
  OVER_LIGHT: !1,
525
576
  ENABLE_OVER_LIGHT_LAYERS: !0,
@@ -535,19 +586,29 @@ const _reduceInstanceProperty = getDefaultExportFromCjs((function(it) {
535
586
  },
536
587
  CONSTANTS: {
537
588
  ACTIVATION_ZONE: 200,
538
- LERP_FACTOR: .08,
589
+ LERP_FACTOR: .05,
590
+ // Lower = more viscous, liquid-smooth tracking (Apple feel)
539
591
  SMOOTHSTEP_POWER: 2.5,
540
592
  MIN_BLUR: .1,
541
593
  MOUSE_INFLUENCE_DIVISOR: 100,
542
594
  EDGE_FADE_PIXELS: 2,
543
- // Elasticity physics constants
544
- ELASTICITY_TRANSLATION_FACTOR: .1,
595
+ // Interaction intensity multipliers shared by the hook and the imperative style updater
596
+ INTERACTION: {
597
+ HOVER_INTENSITY: 1.4,
598
+ ACTIVE_INTENSITY: 1.6
599
+ },
600
+ // Elasticity physics constants — Apple-tuned: soft springs, fast settling, minimal stretch
601
+ ELASTICITY_TRANSLATION_FACTOR: .06,
602
+ // Subtler elastic shift (was 0.1)
545
603
  ELASTICITY_DISTANCE_THRESHOLD: 200,
546
604
  ELASTICITY_COMPRESSION_FACTOR: .3,
547
- ELASTICITY_STIFFNESS: .1,
548
- ELASTICITY_DAMPING: .76,
605
+ ELASTICITY_STIFFNESS: .06,
606
+ // Softer springs = gentler motion (was 0.1)
607
+ ELASTICITY_DAMPING: .88,
608
+ // Fast settling, no wobble (was 0.76)
549
609
  ELASTICITY_VELOCITY_FACTOR: .65,
550
- ELASTICITY_STRETCH_RATIO: .45,
610
+ ELASTICITY_STRETCH_RATIO: .25,
611
+ // Less visible surface tension stretch (was 0.45)
551
612
  ELASTICITY_MAGNIFICATION_BASE: 1.02,
552
613
  // Note: This default must match the SCSS variable --atomix-radius-md
553
614
  // @see src/styles/01-settings/_settings.global.scss
@@ -561,55 +622,16 @@ const _reduceInstanceProperty = getDefaultExportFromCjs((function(it) {
561
622
  },
562
623
  // Gradient calculation constants
563
624
  GRADIENT: {
564
- BASE_ANGLE: 135,
565
- // Base angle for border gradients (degrees)
566
- ANGLE_MULTIPLIER: 1.2,
567
- // Multiplier for mouse influence on angle
568
- VELOCITY_ANGLE_MULTIPLIER: 2.5,
569
- // How much velocity affects gradient rotation
570
- CHROMATIC_OFFSET: 1.5,
571
- // Degree offset for chromatic rim layers
572
- BORDER_STOP_1: {
573
- MIN: 10,
574
- // Minimum percentage for border stop 1
575
- BASE: 33,
576
- // Base percentage for border stop 1
577
- get MULTIPLIER() {
578
- return .009 * this.BASE;
579
- }
580
- },
581
- BORDER_STOP_2: {
582
- MAX: 90,
583
- // Maximum percentage for border stop 2
584
- BASE: 66,
585
- // Base percentage for border stop 2
586
- get MULTIPLIER() {
587
- return .006 * this.BASE;
588
- }
589
- },
590
- BORDER_OPACITY: {
591
- BASE_1: .12,
592
- // Base opacity for border gradient 1
593
- get BASE_2() {
594
- return 3.33 * this.BASE_1;
595
- },
596
- // Base opacity for border gradient 2
597
- get BASE_3() {
598
- return 2.66 * this.BASE_1;
599
- },
600
- // Base opacity for border gradient 3
601
- get BASE_4() {
602
- return 5 * this.BASE_1;
603
- },
604
- // Base opacity for border gradient 4
605
- get MULTIPLIER_LOW() {
606
- return .066 * this.BASE_1;
607
- },
608
- // Low multiplier for mouse influence on opacity
609
- get MULTIPLIER_HIGH() {
610
- return .1 * this.BASE_1;
611
- }
612
- },
625
+ BASE_ANGLE: GLASS_BORDER_GRADIENT.BASE_ANGLE,
626
+ ANGLE_MULTIPLIER: GLASS_BORDER_GRADIENT.ANGLE_MULTIPLIER,
627
+ VELOCITY_ANGLE_MULTIPLIER: GLASS_BORDER_GRADIENT.VELOCITY_ANGLE_MULTIPLIER,
628
+ CHROMATIC_OFFSET: GLASS_BORDER_GRADIENT.CHROMATIC_OFFSET,
629
+ /** @deprecated Use ATOMIX_GLASS.BORDER.GRADIENT.STOP_1 */
630
+ BORDER_STOP_1: GLASS_BORDER_GRADIENT.STOP_1,
631
+ /** @deprecated Use ATOMIX_GLASS.BORDER.GRADIENT.STOP_2 */
632
+ BORDER_STOP_2: GLASS_BORDER_GRADIENT.STOP_2,
633
+ /** @deprecated Use ATOMIX_GLASS.BORDER.GRADIENT.OPACITY */
634
+ BORDER_OPACITY: GLASS_BORDER_GRADIENT.OPACITY,
613
635
  CENTER_POSITION: 50,
614
636
  // Center position percentage (50%)
615
637
  HOVER_POSITION: {
@@ -642,8 +664,8 @@ const _reduceInstanceProperty = getDefaultExportFromCjs((function(it) {
642
664
  return 2 * this.BLACK_STOP;
643
665
  },
644
666
  // End percentage for black hover 1
645
- WHITE_START: .5,
646
- // Start opacity for white hover 1
667
+ WHITE_START: .35,
668
+ // Gentler hover flash Apple hover is barely visible
647
669
  get WHITE_STOP() {
648
670
  return this.BLACK_END - 10;
649
671
  }
@@ -661,8 +683,8 @@ const _reduceInstanceProperty = getDefaultExportFromCjs((function(it) {
661
683
  return 2 * this.BLACK_STOP;
662
684
  },
663
685
  // End percentage for black hover 2
664
- WHITE_START: 1,
665
- // Start opacity for white hover 2
686
+ WHITE_START: .7,
687
+ // Gentler hover flash
666
688
  get WHITE_STOP() {
667
689
  return this.BLACK_END;
668
690
  }
@@ -680,8 +702,8 @@ const _reduceInstanceProperty = getDefaultExportFromCjs((function(it) {
680
702
  return 2 * this.BLACK_STOP;
681
703
  },
682
704
  // End percentage for black hover 3
683
- WHITE_START: 1,
684
- // Start opacity for white hover 3
705
+ WHITE_START: .7,
706
+ // Gentler hover flash
685
707
  get WHITE_STOP() {
686
708
  return this.BLACK_END;
687
709
  }
@@ -691,13 +713,13 @@ const _reduceInstanceProperty = getDefaultExportFromCjs((function(it) {
691
713
  BASE_GRADIENT: {
692
714
  ANGLE: 135,
693
715
  // Gradient angle in degrees
694
- BLACK_START_BASE: .15,
716
+ BLACK_START_BASE: .1,
695
717
  // Base start opacity for black
696
718
  get BLACK_START_MULTIPLIER() {
697
719
  return .02 * this.BLACK_START_BASE;
698
720
  },
699
721
  // Multiplier for mouse X influence on start
700
- BLACK_MID_BASE: .1,
722
+ BLACK_MID_BASE: .07,
701
723
  // Base mid opacity for black
702
724
  get BLACK_MID_MULTIPLIER() {
703
725
  return .02 * this.BLACK_MID_BASE;
@@ -718,7 +740,7 @@ const _reduceInstanceProperty = getDefaultExportFromCjs((function(it) {
718
740
  }
719
741
  },
720
742
  OVERLAY_GRADIENT: {
721
- BLACK_START_BASE: .12,
743
+ BLACK_START_BASE: .08,
722
744
  // Base start opacity for black overlay
723
745
  get BLACK_START_MULTIPLIER() {
724
746
  return .025 * this.BLACK_START_BASE;
@@ -742,14 +764,14 @@ const _reduceInstanceProperty = getDefaultExportFromCjs((function(it) {
742
764
  return .416 * this.BLACK_START_BASE;
743
765
  }
744
766
  },
745
- // Overlay highlight constants
767
+ // Overlay highlight constants — Apple places specular at the top-center
746
768
  OVERLAY_HIGHLIGHT: {
747
- POSITION_X: 20,
748
- // X position percentage
749
- POSITION_Y: 20,
750
- // Y position percentage
751
- WHITE_OPACITY: .4,
752
- // White opacity in gradient
769
+ POSITION_X: 50,
770
+ // Centered horizontal — Apple's top-center specular
771
+ POSITION_Y: 5,
772
+ // Very top — catches light like a curved glass surface
773
+ WHITE_OPACITY: .28,
774
+ // Softer specular visible but not glaring
753
775
  get STOP() {
754
776
  return 150 * this.WHITE_OPACITY;
755
777
  },
@@ -770,6 +792,10 @@ const _reduceInstanceProperty = getDefaultExportFromCjs((function(it) {
770
792
  SATURATION: {
771
793
  HIGH_CONTRAST: 200
772
794
  },
795
+ // Container shadows — hairline inner catch + soft floating lift (Apple player bar)
796
+ CONTAINER_SHADOW: {
797
+ LIGHT: "inset 0 0.5px 0 rgba(255, 255, 255, 0.32), inset 0 1px 2px rgba(255, 255, 255, 0.06), 0 4px 16px rgba(0, 0, 0, 0.12), 0 1px 4px rgba(0, 0, 0, 0.08)"
798
+ },
773
799
  // Phase 1: Animation System Constants
774
800
  ANIMATION: {
775
801
  // Breathing effect timing (in milliseconds)
@@ -1664,9 +1690,38 @@ const ChartToolbar = memo( forwardRef((({chartType: chartType = "line", groups:
1664
1690
  });
1665
1691
  })));
1666
1692
 
1693
+ /**
1694
+ * Component Utilities
1695
+ *
1696
+ * Helper functions for component development with the new customization system
1697
+ */
1698
+ /**
1699
+ * Merge multiple class names
1700
+ */
1701
+ function mergeClassNames(...classes) {
1702
+ return classes.filter(Boolean).join(" ");
1703
+ }
1704
+
1705
+ /**
1706
+ * Utility to merge multiple React refs into one
1707
+ */ function setRef(ref, value) {
1708
+ "function" == typeof ref ? ref(value) : ref && (
1709
+ // This is safe because we're checking that ref exists first
1710
+ ref.current = value);
1711
+ }
1712
+
1713
+ /**
1714
+ * Combines two React refs into a single ref function
1715
+ * This is used when you need to use and forward a ref at the same time
1716
+ */ function useForkRef(refA, refB) {
1717
+ return React.useMemo((() => null == refA && null == refB ? null : refValue => {
1718
+ setRef(refA, refValue), setRef(refB, refValue);
1719
+ }), [ refA, refB ]);
1720
+ }
1721
+
1667
1722
  ChartToolbar.displayName = "ChartToolbar";
1668
1723
 
1669
- const {CONSTANTS: CONSTANTS$2} = ATOMIX_GLASS, calculateElementCenter = rect => rect ? {
1724
+ const {CONSTANTS: CONSTANTS$3} = ATOMIX_GLASS, calculateElementCenter = rect => rect ? {
1670
1725
  x: rect.left + rect.width / 2,
1671
1726
  y: rect.top + rect.height / 2
1672
1727
  } : {
@@ -1674,37 +1729,37 @@ const {CONSTANTS: CONSTANTS$2} = ATOMIX_GLASS, calculateElementCenter = rect =>
1674
1729
  y: 0
1675
1730
  }, calculateMouseInfluence = mouseOffset => {
1676
1731
  if (!mouseOffset || "number" != typeof mouseOffset.x || "number" != typeof mouseOffset.y) return 0;
1677
- // Bounded calculation keeps the glass effect subtle and stable
1678
- const influence = Math.sqrt(mouseOffset.x * mouseOffset.x + mouseOffset.y * mouseOffset.y) / CONSTANTS$2.MOUSE_INFLUENCE_DIVISOR;
1732
+ // Clamp influence to keep mouse response subtle and stable.
1733
+ const influence = Math.sqrt(mouseOffset.x * mouseOffset.x + mouseOffset.y * mouseOffset.y) / CONSTANTS$3.MOUSE_INFLUENCE_DIVISOR;
1679
1734
  return Math.min(.8, influence);
1680
1735
  // Tighter cap to prevent blur/filter blow-out
1681
- }, clampBlur = value => "number" != typeof value || isNaN(value) ? CONSTANTS$2.MIN_BLUR : Math.max(CONSTANTS$2.MIN_BLUR, Math.min(50, value)), validateGlassSize = size => size && "number" == typeof size.width && "number" == typeof size.height && size.width > 0 && size.height > 0 && size.width <= CONSTANTS$2.MAX_SIZE && size.height <= CONSTANTS$2.MAX_SIZE, parseBorderRadiusValue = value => {
1736
+ }, clampBlur = value => "number" != typeof value || isNaN(value) ? CONSTANTS$3.MIN_BLUR : Math.max(CONSTANTS$3.MIN_BLUR, Math.min(50, value)), validateGlassSize = size => size && "number" == typeof size.width && "number" == typeof size.height && size.width > 0 && size.height > 0 && size.width <= CONSTANTS$3.MAX_SIZE && size.height <= CONSTANTS$3.MAX_SIZE, parseBorderRadiusValue = value => {
1682
1737
  if ("number" == typeof value) return Math.max(0, value);
1683
- if ("string" != typeof value || !value.trim()) return CONSTANTS$2.DEFAULT_CORNER_RADIUS;
1738
+ if ("string" != typeof value || !value.trim()) return CONSTANTS$3.DEFAULT_CORNER_RADIUS;
1684
1739
  const trimmedValue = value.trim();
1685
1740
  // Handle px values
1686
1741
  if (trimmedValue.endsWith("px")) {
1687
1742
  const parsed = parseFloat(trimmedValue);
1688
- return isNaN(parsed) ? CONSTANTS$2.DEFAULT_CORNER_RADIUS : Math.max(0, parsed);
1743
+ return isNaN(parsed) ? CONSTANTS$3.DEFAULT_CORNER_RADIUS : Math.max(0, parsed);
1689
1744
  }
1690
1745
  // Handle rem values (assume 16px = 1rem)
1691
1746
  if (trimmedValue.endsWith("rem")) {
1692
1747
  const parsed = parseFloat(trimmedValue);
1693
- return isNaN(parsed) ? CONSTANTS$2.DEFAULT_CORNER_RADIUS : Math.max(0, 16 * parsed);
1748
+ return isNaN(parsed) ? CONSTANTS$3.DEFAULT_CORNER_RADIUS : Math.max(0, 16 * parsed);
1694
1749
  }
1695
1750
  // Handle em values (assume 16px = 1em for simplicity)
1696
1751
  if (trimmedValue.endsWith("em")) {
1697
1752
  const parsed = parseFloat(trimmedValue);
1698
- return isNaN(parsed) ? CONSTANTS$2.DEFAULT_CORNER_RADIUS : Math.max(0, 16 * parsed);
1753
+ return isNaN(parsed) ? CONSTANTS$3.DEFAULT_CORNER_RADIUS : Math.max(0, 16 * parsed);
1699
1754
  }
1700
1755
  // Handle percentage (convert to approximate px value, assuming 200px container)
1701
1756
  if (trimmedValue.endsWith("%")) {
1702
1757
  const parsed = parseFloat(trimmedValue);
1703
- return isNaN(parsed) ? CONSTANTS$2.DEFAULT_CORNER_RADIUS : Math.max(0, parsed / 100 * 200);
1758
+ return isNaN(parsed) ? CONSTANTS$3.DEFAULT_CORNER_RADIUS : Math.max(0, parsed / 100 * 200);
1704
1759
  }
1705
1760
  // Handle unitless numbers
1706
1761
  const numValue = parseFloat(trimmedValue);
1707
- return isNaN(numValue) ? CONSTANTS$2.DEFAULT_CORNER_RADIUS : Math.max(0, numValue);
1762
+ return isNaN(numValue) ? CONSTANTS$3.DEFAULT_CORNER_RADIUS : Math.max(0, numValue);
1708
1763
  }, extractBorderRadiusFromElement = element => {
1709
1764
  if (!element || !element.props) return null;
1710
1765
  // Check inline styles first (highest priority)
@@ -1720,11 +1775,11 @@ const {CONSTANTS: CONSTANTS$2} = ATOMIX_GLASS, calculateElementCenter = rect =>
1720
1775
  // If element has children, recursively check them
1721
1776
  if (element.props.children) {
1722
1777
  const childRadius = extractBorderRadiusFromChildren(element.props.children);
1723
- if (childRadius > 0 && childRadius !== CONSTANTS$2.DEFAULT_CORNER_RADIUS) return childRadius;
1778
+ if (childRadius > 0 && childRadius !== CONSTANTS$3.DEFAULT_CORNER_RADIUS) return childRadius;
1724
1779
  }
1725
1780
  return null;
1726
1781
  }, extractBorderRadiusFromChildren = children => {
1727
- if (!children) return CONSTANTS$2.DEFAULT_CORNER_RADIUS;
1782
+ if (!children) return CONSTANTS$3.DEFAULT_CORNER_RADIUS;
1728
1783
  try {
1729
1784
  const childArray = React.Children.toArray(children);
1730
1785
  for (let i = 0; i < childArray.length; i++) {
@@ -1737,17 +1792,78 @@ const {CONSTANTS: CONSTANTS$2} = ATOMIX_GLASS, calculateElementCenter = rect =>
1737
1792
  } catch (error) {
1738
1793
  // Silently handle errors
1739
1794
  }
1740
- return CONSTANTS$2.DEFAULT_CORNER_RADIUS;
1795
+ return CONSTANTS$3.DEFAULT_CORNER_RADIUS;
1741
1796
  }, smoothstep = t => {
1742
1797
  const clamped = Math.max(0, Math.min(1, t));
1743
1798
  return clamped * clamped * (3 - 2 * clamped);
1744
- }, lerp$1 = (a, b, t) => a + (b - a) * t, softClamp = (value, max) => max <= 0 ? 0 : max * (1 - Math.exp(-value / max)), calculateSpring = (current, target, velocity, stiffness = .1, damping = .8) => {
1799
+ }, lerp = (a, b, t) => a + (b - a) * t, softClamp = (value, max) => max <= 0 ? 0 : max * (1 - Math.exp(-value / max)), clamp = (value, min, max) => "number" != typeof value || isNaN(value) ? min : Math.max(min, Math.min(max, value)), smoothstepEdge = (edge0, edge1, x) => "number" != typeof edge0 || "number" != typeof edge1 || "number" != typeof x ? 0 : smoothstep((x - edge0) / (edge1 - edge0)), easeInOutCubic = t => {
1800
+ if ("number" != typeof t || isNaN(t)) return 0;
1801
+ const clamped = Math.max(0, Math.min(1, t));
1802
+ return clamped < .5 ? 4 * clamped * clamped * clamped : 1 - Math.pow(-2 * clamped + 2, 3) / 2;
1803
+ }, easeOutQuart = t => {
1804
+ if ("number" != typeof t || isNaN(t)) return 0;
1805
+ const clamped = Math.max(0, Math.min(1, t));
1806
+ return 1 - Math.pow(1 - clamped, 4);
1807
+ }, vec2Length = (x, y) => {
1808
+ if ("number" != typeof x || "number" != typeof y || isNaN(x) || isNaN(y)) return 0;
1809
+ const maxComponent = Math.max(Math.abs(x), Math.abs(y));
1810
+ if (0 === maxComponent) return 0;
1811
+ const scaledX = x / maxComponent, scaledY = y / maxComponent;
1812
+ return maxComponent * Math.sqrt(scaledX * scaledX + scaledY * scaledY);
1813
+ }, getInteractionIntensity = (isHovered, isActive) => ({
1814
+ hoverIntensity: isHovered ? CONSTANTS$3.INTERACTION.HOVER_INTENSITY : 1,
1815
+ activeIntensity: isActive ? CONSTANTS$3.INTERACTION.ACTIVE_INTENSITY : 1
1816
+ })
1817
+ /**
1818
+ * Spring-damper integration helper
1819
+ * Calculates the next value based on velocity, stiffness, and damping.
1820
+ */ , calculateSpring = (current, target, velocity, stiffness = .1, damping = .8) => {
1745
1821
  const newVelocity = (velocity + (target - current) * stiffness) * damping;
1746
1822
  return {
1747
1823
  value: current + newVelocity,
1748
1824
  velocity: newVelocity
1749
1825
  };
1750
- }, getDisplacementMap = (mode, displacementMap, polarDisplacementMap, prominentDisplacementMap, shaderMapUrl) => {
1826
+ };
1827
+
1828
+ /**
1829
+ * Calculate element center from bounding rect
1830
+ */
1831
+ /**
1832
+ * Normalizes a layout inset for use in CSS custom properties.
1833
+ *
1834
+ * @param value - Raw inset from `style` (number, px string, or `auto`).
1835
+ * @param fallback - Value used when `value` is undefined.
1836
+ */
1837
+ function formatGlassInsetValue(value, fallback = "auto") {
1838
+ return void 0 === value ? "number" == typeof fallback ? `${fallback}px` : String(fallback) : "auto" === value ? "auto" : "number" == typeof value ? `${value}px` : value;
1839
+ }
1840
+
1841
+ /**
1842
+ * Determines whether the glass should use fixed/sticky layout semantics.
1843
+ *
1844
+ * @param explicit - Value of the `isFixedOrSticky` prop.
1845
+ * @param position - `position` from the consumer `style` object.
1846
+ */
1847
+ /** Coerces a value to a finite number, returning `fallback` when invalid. */
1848
+ function toSafeNumber(value, fallback = 0) {
1849
+ return "number" != typeof value || isNaN(value) ? fallback : value;
1850
+ }
1851
+
1852
+ /**
1853
+ * Calculates the target frame rate for shader time-animation loops.
1854
+ *
1855
+ * Balances visual quality against distortion complexity and `animationSpeed`.
1856
+ */
1857
+ /**
1858
+ * Computes per-channel displacement scale for the SVG chromatic-aberration filter.
1859
+ */
1860
+ function getChromaticDisplacementScale(mode, displacementScale, aberrationIntensity, channelFactor) {
1861
+ return displacementScale * (("shader" === mode ? 1 : -1) - aberrationIntensity * channelFactor);
1862
+ }
1863
+
1864
+ /**
1865
+ * Get displacement map URL based on mode
1866
+ */ const getDisplacementMap = (mode, displacementMap, polarDisplacementMap, prominentDisplacementMap, shaderMapUrl) => {
1751
1867
  switch (mode) {
1752
1868
  case "standard":
1753
1869
  return displacementMap;
@@ -1764,13 +1880,28 @@ const {CONSTANTS: CONSTANTS$2} = ATOMIX_GLASS, calculateElementCenter = rect =>
1764
1880
  default:
1765
1881
  return console.warn("AtomixGlass: Invalid displacement mode"), displacementMap;
1766
1882
  }
1767
- }, sharedShaderCache = new Map, GlassFilterComponent = ({id: id, displacementScale: displacementScale, aberrationIntensity: aberrationIntensity, mode: mode, shaderMapUrl: shaderMapUrl, blurAmount: blurAmount}) => jsx("svg", {
1768
- style: {
1769
- position: "absolute",
1770
- width: "100%",
1771
- height: "100%",
1772
- inset: 0
1773
- },
1883
+ }, sharedShaderCache = new Map, CHROMATIC_CHANNELS = [ {
1884
+ result: "RED_DISPLACED",
1885
+ channelResult: "RED_CHANNEL",
1886
+ aberrationFactor: 0,
1887
+ colorMatrix: "1 0 0 0 0\n0 0 0 0 0\n0 0 0 0 0\n0 0 0 1 0"
1888
+ }, {
1889
+ result: "GREEN_DISPLACED",
1890
+ channelResult: "GREEN_CHANNEL",
1891
+ aberrationFactor: .02,
1892
+ colorMatrix: "0 0 0 0 0\n0 1 0 0 0\n0 0 0 0 0\n0 0 0 1 0"
1893
+ }, {
1894
+ result: "BLUE_DISPLACED",
1895
+ channelResult: "BLUE_CHANNEL",
1896
+ aberrationFactor: .03,
1897
+ colorMatrix: "0 0 0 0 0\n0 0 0 0 0\n0 0 1 0 0\n0 0 0 1 0"
1898
+ } ], FILTER_SVG_STYLE = {
1899
+ position: "absolute",
1900
+ width: "100%",
1901
+ height: "100%",
1902
+ inset: 0
1903
+ }, GlassFilterComponent = ({id: id, displacementScale: displacementScale, aberrationIntensity: aberrationIntensity, mode: mode, shaderMapUrl: shaderMapUrl, blurAmount: blurAmount}) => jsx("svg", {
1904
+ style: FILTER_SVG_STYLE,
1774
1905
  "aria-hidden": "true",
1775
1906
  children: jsxs("defs", {
1776
1907
  children: [ jsxs("radialGradient", {
@@ -1824,43 +1955,21 @@ const {CONSTANTS: CONSTANTS$2} = ATOMIX_GLASS, calculateElementCenter = rect =>
1824
1955
  dx: "0",
1825
1956
  dy: "0",
1826
1957
  result: "CENTER_ORIGINAL"
1827
- }), jsx("feDisplacementMap", {
1828
- in: "SourceGraphic",
1829
- in2: "DISPLACEMENT_MAP",
1830
- scale: displacementScale * ("shader" === mode ? 1 : -1),
1831
- xChannelSelector: "R",
1832
- yChannelSelector: "B",
1833
- result: "RED_DISPLACED"
1834
- }), jsx("feColorMatrix", {
1835
- in: "RED_DISPLACED",
1836
- type: "matrix",
1837
- values: "1 0 0 0 0\n 0 0 0 0 0\n 0 0 0 0 0\n 0 0 0 1 0",
1838
- result: "RED_CHANNEL"
1839
- }), jsx("feDisplacementMap", {
1840
- in: "SourceGraphic",
1841
- in2: "DISPLACEMENT_MAP",
1842
- scale: displacementScale * (("shader" === mode ? 1 : -1) - .02 * aberrationIntensity),
1843
- xChannelSelector: "R",
1844
- yChannelSelector: "B",
1845
- result: "GREEN_DISPLACED"
1846
- }), jsx("feColorMatrix", {
1847
- in: "GREEN_DISPLACED",
1848
- type: "matrix",
1849
- values: "0 0 0 0 0\n 0 1 0 0 0\n 0 0 0 0 0\n 0 0 0 1 0",
1850
- result: "GREEN_CHANNEL"
1851
- }), jsx("feDisplacementMap", {
1852
- in: "SourceGraphic",
1853
- in2: "DISPLACEMENT_MAP",
1854
- scale: displacementScale * (("shader" === mode ? 1 : -1) - .03 * aberrationIntensity),
1855
- xChannelSelector: "R",
1856
- yChannelSelector: "B",
1857
- result: "BLUE_DISPLACED"
1858
- }), jsx("feColorMatrix", {
1859
- in: "BLUE_DISPLACED",
1860
- type: "matrix",
1861
- values: "0 0 0 0 0\n 0 0 0 0 0\n 0 0 1 0 0\n 0 0 0 1 0",
1862
- result: "BLUE_CHANNEL"
1863
- }), jsx("feBlend", {
1958
+ }), CHROMATIC_CHANNELS.map((channel => jsxs(React.Fragment, {
1959
+ children: [ jsx("feDisplacementMap", {
1960
+ in: "SourceGraphic",
1961
+ in2: "DISPLACEMENT_MAP",
1962
+ scale: getChromaticDisplacementScale(mode, displacementScale, aberrationIntensity, channel.aberrationFactor),
1963
+ xChannelSelector: "R",
1964
+ yChannelSelector: "B",
1965
+ result: channel.result
1966
+ }), jsx("feColorMatrix", {
1967
+ in: channel.result,
1968
+ type: "matrix",
1969
+ values: channel.colorMatrix,
1970
+ result: channel.channelResult
1971
+ }) ]
1972
+ }, channel.channelResult))), jsx("feBlend", {
1864
1973
  in: "GREEN_CHANNEL",
1865
1974
  in2: "BLUE_CHANNEL",
1866
1975
  mode: "screen",
@@ -1901,21 +2010,22 @@ const {CONSTANTS: CONSTANTS$2} = ATOMIX_GLASS, calculateElementCenter = rect =>
1901
2010
  });
1902
2011
 
1903
2012
  /**
1904
- * Calculate distance between two points
2013
+ * Module-level LRU cache for shader displacement maps.
2014
+ *
2015
+ * Shared across all `AtomixGlassContainer` instances so identical size and
2016
+ * variant combinations are generated once.
1905
2017
  */ GlassFilterComponent.displayName = "GlassFilter";
1906
2018
 
1907
- // Memoize component to prevent unnecessary re-renders
2019
+ /** Shallow prop comparison to avoid redundant SVG filter regeneration. */
1908
2020
  const GlassFilter = memo(GlassFilterComponent, ((prevProps, nextProps) => prevProps.id === nextProps.id && prevProps.displacementScale === nextProps.displacementScale && prevProps.aberrationIntensity === nextProps.aberrationIntensity && prevProps.mode === nextProps.mode && prevProps.shaderMapUrl === nextProps.shaderMapUrl && prevProps.blurAmount === nextProps.blurAmount)), AtomixGlassContainer = forwardRef((({children: children, className: className = "", style: style, displacementScale: displacementScale = 25, blurAmount: blurAmount = .0625, saturation: saturation = 180, aberrationIntensity: aberrationIntensity = 2, mouseOffset: mouseOffset = {
1909
2021
  x: 0,
1910
2022
  y: 0
1911
- }, 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 = {
2023
+ }, onMouseEnter: onMouseEnter, onMouseLeave: onMouseLeave, onMouseDown: onMouseDown, onMouseUp: onMouseUp, isActive: isActive = !1, overLight: overLight = !1, overLightConfig: overLightConfig = {}, borderRadius: borderRadius = 0, glassSize: glassSize = {
1912
2024
  width: 0,
1913
2025
  height: 0
1914
- }, onClick: onClick, mode: mode = "standard", effectiveWithoutEffects: effectiveWithoutEffects = !1, effectiveReducedMotion: effectiveReducedMotion = !1, shaderVariant: shaderVariant = "liquidGlass", withLiquidBlur: withLiquidBlur = !1, isFixedOrSticky: isFixedOrSticky = !1,
1915
- // Phase 1: Animation System props
1916
- 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) => {
2026
+ }, onClick: onClick, mode: mode = "standard", effectiveWithoutEffects: effectiveWithoutEffects = !1, effectiveReducedMotion: effectiveReducedMotion = !1, shaderVariant: shaderVariant = "liquidGlass", withLiquidBlur: withLiquidBlur = !1, isFixedOrSticky: isFixedOrSticky = !1, withTimeAnimation: withTimeAnimation = !1, animationSpeed: animationSpeed = 1, withMultiLayerDistortion: withMultiLayerDistortion = !1, distortionOctaves: distortionOctaves = 3, distortionLacunarity: distortionLacunarity = 2, distortionGain: distortionGain = .5, distortionQuality: distortionQuality = "medium", contentRef: contentRef}, ref) => {
1917
2027
  // React 18 useId — stable, unique, and SSR-safe (no module-level counter)
1918
- const rawId = useId(), filterId = useMemo((() => `atomix-glass-filter-${rawId.replace(/:/g, "")}`), [ rawId ]), [shaderMapUrl, setShaderMapUrl] = useState(""), shaderGeneratorRef = useRef(null), shaderUtilsRef = useRef(null), shaderDebounceTimeoutRef = useRef(null), shaderUpdateTimeoutRef = useRef(null), animationFrameRef = useRef(null);
2028
+ const rawId = useId(), filterId = useMemo((() => `atomix-glass-filter-${rawId.replace(/:/g, "")}`), [ rawId ]), containerRef = useForkRef(ref, null), [shaderMapUrl, setShaderMapUrl] = useState(""), shaderGeneratorRef = useRef(null), shaderUtilsRef = useRef(null), shaderDebounceTimeoutRef = useRef(null), shaderUpdateTimeoutRef = useRef(null), animationFrameRef = useRef(null);
1919
2029
  // Lazy load shader utilities only when shader mode is needed
1920
2030
  useEffect((() => {
1921
2031
  "shader" === mode ?
@@ -1993,15 +2103,23 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
1993
2103
  shaderGeneratorRef.current = null;
1994
2104
  }
1995
2105
  };
1996
- }), [ mode, glassSize, shaderVariant ]),
1997
- // Phase 1: Time-Based Animation Loop - Continuous shader regeneration
1998
- useEffect((() => {
2106
+ }), [ mode, glassSize, shaderVariant ]), useEffect((() => {
1999
2107
  // Only run animations in shader mode with time animation enabled
2000
2108
  if ("shader" !== mode || !withTimeAnimation || effectiveReducedMotion || effectiveWithoutEffects)
2001
2109
  // Cancel any existing animation frame
2002
2110
  return void (null !== animationFrameRef.current && (cancelAnimationFrame(animationFrameRef.current),
2003
2111
  animationFrameRef.current = null));
2004
- 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)));
2112
+ const targetFps = function(options) {
2113
+ const {distortionQuality: distortionQuality, animationSpeed: animationSpeed = 1, withMultiLayerDistortion: withMultiLayerDistortion, distortionOctaves: distortionOctaves = 3, distortionLacunarity: distortionLacunarity = 2, distortionGain: distortionGain = .5} = options, baseFps = "ultra" === distortionQuality ? 60 : "high" === distortionQuality ? 30 : "medium" === distortionQuality ? 24 : 20, effectiveSpeed = Math.max(.5, Math.min(2, animationSpeed)), complexity = withMultiLayerDistortion ? Math.max(1, distortionOctaves / 3 + .25 * Math.max(0, distortionLacunarity - 2) + Math.max(0, distortionGain - .5)) : 1;
2114
+ return Math.max(12, Math.min(60, Math.round(baseFps * effectiveSpeed / complexity)));
2115
+ }({
2116
+ distortionQuality: distortionQuality,
2117
+ animationSpeed: animationSpeed,
2118
+ withMultiLayerDistortion: withMultiLayerDistortion,
2119
+ distortionOctaves: distortionOctaves,
2120
+ distortionLacunarity: distortionLacunarity,
2121
+ distortionGain: distortionGain
2122
+ }), frameInterval = 1e3 / targetFps;
2005
2123
  let lastUpdate = 0, isCancelled = !1;
2006
2124
  const animate = currentTime => {
2007
2125
  if (!isCancelled) {
@@ -2025,88 +2143,21 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
2025
2143
  };
2026
2144
  }), [ mode, withTimeAnimation, animationSpeed, displacementScale, withMultiLayerDistortion, distortionOctaves, distortionLacunarity, distortionGain, distortionQuality, effectiveReducedMotion, effectiveWithoutEffects, glassSize ]);
2027
2145
  // Removed forced reflow to avoid layout thrash and potential feedback sizing loops
2028
- const [rectCache, setRectCache] = useState(null);
2029
- useEffect((() => {
2030
- if (!ref || "function" == typeof ref) return;
2031
- const element = ref.current;
2032
- if (element) try {
2033
- setRectCache(element.getBoundingClientRect());
2034
- } catch (error) {
2035
- console.warn("AtomixGlassContainer: Error getting element bounds", error), setRectCache(null);
2036
- }
2037
- }), [ ref, glassSize ]);
2038
- const liquidBlur = useMemo((() => {
2039
- const defaultBlur = {
2040
- baseBlur: blurAmount,
2041
- edgeBlur: 1.25 * blurAmount,
2042
- centerBlur: 1.1 * blurAmount,
2043
- flowBlur: 1.2 * blurAmount
2044
- };
2045
- // Enhanced validation for liquid blur
2046
- if (!withLiquidBlur || !rectCache || !mouseOffset || "number" != typeof mouseOffset.x || "number" != typeof mouseOffset.y || isNaN(mouseOffset.x) || isNaN(mouseOffset.y)) return defaultBlur;
2146
+ const containerVars = useMemo((() => {
2047
2147
  try {
2048
- const mouseInfluence = calculateMouseInfluence(mouseOffset), maxBlur = 2 * blurAmount, baseBlur = Math.min(maxBlur, blurAmount + mouseInfluence * blurAmount * .15), edgeIntensity = .15 * mouseInfluence, edgeBlur = Math.min(maxBlur, baseBlur * (.8 + .4 * edgeIntensity)), centerIntensity = .1 * mouseInfluence, centerBlur = Math.min(maxBlur, baseBlur * (.3 + .3 * centerIntensity)), flowBlur = Math.min(maxBlur, 1.2 * baseBlur);
2049
- // NOTE: hover/active multipliers intentionally omitted here —
2050
- // they belong on opacity layers, not the blur filter itself.
2051
2148
  return {
2052
- baseBlur: clampBlur(baseBlur),
2053
- edgeBlur: clampBlur(edgeBlur),
2054
- centerBlur: clampBlur(centerBlur),
2055
- flowBlur: clampBlur(flowBlur)
2056
- };
2057
- } catch (error) {
2058
- return console.warn("AtomixGlassContainer: Error calculating liquid blur", error),
2059
- defaultBlur;
2060
- }
2061
- }), [ withLiquidBlur, blurAmount, mouseOffset, rectCache ]), backdropStyle = useMemo((() => {
2062
- try {
2063
- const dynamicSaturation = saturation + 20 * (liquidBlur.baseBlur || 0), validatedBaseBlur = "number" != typeof liquidBlur.baseBlur || isNaN(liquidBlur.baseBlur) ? 0 : liquidBlur.baseBlur, validatedEdgeBlur = "number" != typeof liquidBlur.edgeBlur || isNaN(liquidBlur.edgeBlur) ? 0 : liquidBlur.edgeBlur, validatedCenterBlur = "number" != typeof liquidBlur.centerBlur || isNaN(liquidBlur.centerBlur) ? 0 : liquidBlur.centerBlur, validatedFlowBlur = "number" != typeof liquidBlur.flowBlur || isNaN(liquidBlur.flowBlur) ? 0 : liquidBlur.flowBlur, area = rectCache ? rectCache.width * rectCache.height : 0;
2064
- // Validate blur values before using them
2065
- return !withLiquidBlur || effectiveReducedMotion || effectiveWithoutEffects || area > 18e4 ? {
2066
- backdropFilter: `blur(${clampBlur(Math.max(validatedBaseBlur, .8 * validatedEdgeBlur, 1.1 * validatedCenterBlur, .9 * validatedFlowBlur))}px) saturate(${Math.min(dynamicSaturation, 200)}%) contrast(${overLightConfig?.contrast || 1.05}) brightness(${overLightConfig?.brightness || 1.05})`
2067
- } : {
2068
- backdropFilter: `blur(${clampBlur(.4 * validatedBaseBlur + .25 * validatedEdgeBlur + .15 * validatedCenterBlur + .2 * validatedFlowBlur)}px) saturate(${Math.min(dynamicSaturation, 200)}%) contrast(${overLightConfig?.contrast || 1}) brightness(${overLightConfig?.brightness || 1})`
2069
- };
2070
- // Single-pass fallback: stronger radius to match perceived blur of multi-pass
2071
- } catch (error) {
2072
- return console.warn("AtomixGlassContainer: Error calculating backdrop style", error),
2073
- {
2074
- backdropFilter: `blur(${blurAmount}px) saturate(${saturation}%) contrast(1.05) brightness(1.05)`
2075
- };
2076
- }
2077
- }), [ liquidBlur, saturation, blurAmount, rectCache, effectiveReducedMotion, effectiveWithoutEffects, withLiquidBlur, overLightConfig ]), containerVars = useMemo((() => {
2078
- try {
2079
- // Safe extraction of mouse offset values
2080
- 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;
2081
- return {
2082
- "--atomix-glass-container-radius": `${"number" != typeof borderRadius || isNaN(borderRadius) ? 0 : borderRadius}px`,
2083
- "--atomix-glass-container-backdrop": backdropStyle?.backdropFilter || "none",
2084
- "--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",
2085
- "--atomix-glass-container-shadow-opacity": effectiveWithoutEffects ? 0 : 1,
2086
- // Background and shadow values use design token-aligned RGB values
2087
- "--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",
2088
- "--atomix-glass-container-text-shadow": overLight ? "0px 1px 2px rgba(255, 255, 255, 0.15)" : "0px 2px 12px rgba(0, 0, 0, 0.4)",
2089
- "--atomix-glass-container-box-shadow": overLight ? "0px 16px 70px rgba(0, 0, 0, 0.75)" : "0px 12px 40px rgba(0, 0, 0, 0.25)"
2149
+ "--atomix-glass-container-radius": `${"number" != typeof borderRadius || isNaN(borderRadius) ? 0 : borderRadius}px`
2090
2150
  };
2091
2151
  } catch (error) {
2092
2152
  return console.warn("AtomixGlassContainer: Error generating container variables", error),
2093
2153
  {
2094
- "--atomix-glass-container-padding": "0 0",
2095
- "--atomix-glass-container-radius": "0px",
2096
- "--atomix-glass-container-backdrop": "none",
2097
- "--atomix-glass-container-shadow": "none",
2098
- "--atomix-glass-container-shadow-opacity": 1,
2099
- "--atomix-glass-container-bg": "none",
2100
- "--atomix-glass-container-text-shadow": "none"
2154
+ "--atomix-glass-container-radius": "0px"
2101
2155
  };
2102
2156
  }
2103
- }), [ borderRadius, backdropStyle, mouseOffset, overLight, effectiveWithoutEffects, overLightConfig ]);
2157
+ }), [ borderRadius ]);
2104
2158
  return jsx("div", {
2105
- ref: el => {
2106
- // Handle forwarded ref
2107
- "function" == typeof ref ? ref(el) : ref && (ref.current = el);
2108
- },
2109
- className: `${ATOMIX_GLASS.CONTAINER_CLASS} ${className} ${isActive ? ATOMIX_GLASS.CLASSES.ACTIVE : ""} ${overLight ? ATOMIX_GLASS.CLASSES.OVER_LIGHT : ""}`,
2159
+ ref: containerRef,
2160
+ className: mergeClassNames(ATOMIX_GLASS.CONTAINER_CLASS, className, isActive && ATOMIX_GLASS.CLASSES.ACTIVE, overLight && ATOMIX_GLASS.CLASSES.OVER_LIGHT),
2110
2161
  style: {
2111
2162
  ...style,
2112
2163
  ...containerVars
@@ -2124,8 +2175,8 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
2124
2175
  blurAmount: blurAmount,
2125
2176
  mode: mode,
2126
2177
  id: filterId,
2127
- displacementScale: "number" != typeof displacementScale || isNaN(displacementScale) ? 0 : displacementScale,
2128
- aberrationIntensity: "number" != typeof aberrationIntensity || isNaN(aberrationIntensity) ? 0 : aberrationIntensity,
2178
+ displacementScale: toSafeNumber(displacementScale),
2179
+ aberrationIntensity: toSafeNumber(aberrationIntensity),
2129
2180
  shaderMapUrl: shaderMapUrl
2130
2181
  }), jsx("div", {
2131
2182
  className: ATOMIX_GLASS.FILTER_OVERLAY_CLASS,
@@ -2147,8 +2198,12 @@ shaderTime: shaderTime, withTimeAnimation: withTimeAnimation = !1, animationSpee
2147
2198
  });
2148
2199
  }));
2149
2200
 
2150
- // ─── Blur multiplier constants (module-level, never change at runtime) ────────
2151
- AtomixGlassContainer.displayName = "AtomixGlassContainer";
2201
+ /**
2202
+ * Internal glass surface that owns backdrop-filter, SVG distortion, and content.
2203
+ *
2204
+ * Layout and stacking styles are applied via the `style` prop from the parent.
2205
+ * The root wrapper supplies CSS custom properties only.
2206
+ */ AtomixGlassContainer.displayName = "AtomixGlassContainer";
2152
2207
 
2153
2208
  // Singleton instance
2154
2209
  const globalMouseTracker = new
@@ -2263,28 +2318,32 @@ class {
2263
2318
  */ getSubscriberCount() {
2264
2319
  return this.listeners.size;
2265
2320
  }
2266
- }, updateAtomixGlassStyles = (wrapperElement, containerElement, params) => {
2321
+ }, {BORDER: BORDER, CONSTANTS: CONSTANTS$2} = ATOMIX_GLASS, BORDER_GRADIENT = BORDER.GRADIENT, WHITE = CONSTANTS$2.PALETTE.WHITE, updateAtomixGlassStyles = (wrapperElement, containerElement, params) => {
2267
2322
  if (!wrapperElement && !containerElement) return;
2268
2323
  if (!validateGlassSize(params.glassSize)) return;
2269
- const {mouseOffset: mouseOffset, globalMousePosition: globalMousePosition, glassSize: glassSize, isHovered: isHovered, isActive: isActive, isOverLight: isOverLight, baseOverLightConfig: baseOverLightConfig, effectiveBorderRadius: effectiveBorderRadius, effectiveWithoutEffects: effectiveWithoutEffects, effectiveReducedMotion: effectiveReducedMotion, elasticity: elasticity, elasticTranslation: elasticTranslation, elasticVelocity: elasticVelocity, mouseVelocity: mouseVelocity, directionalScale: directionalScale, scaleBase: scaleBase, 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 = {
2324
+ const {mouseOffset: mouseOffset, globalMousePosition: globalMousePosition, glassSize: glassSize, isHovered: isHovered, isActive: isActive, isOverLight: isOverLight, baseOverLightConfig: baseOverLightConfig, effectiveBorderRadius: effectiveBorderRadius, effectiveWithoutEffects: effectiveWithoutEffects, effectiveReducedMotion: effectiveReducedMotion, elasticity: elasticity, elasticTranslation: elasticTranslation, elasticVelocity: elasticVelocity, mouseVelocity: mouseVelocity, directionalScale: directionalScale, scaleBase: scaleBase, onClick: onClick, withLiquidBlur: withLiquidBlur, blurAmount: blurAmount = ATOMIX_GLASS.DEFAULTS.BLUR_AMOUNT, saturation: saturation = ATOMIX_GLASS.DEFAULTS.SATURATION, isFixedOrSticky: isFixedOrSticky = !1, borderAnimated: borderAnimated = !0, borderOpacityMultiplier: borderOpacityMultiplier = 1} = params, mouseInfluence = calculateMouseInfluence(mouseOffset), {hoverIntensity: hoverIntensity, activeIntensity: activeIntensity} = getInteractionIntensity(isHovered, isActive), overLightConfig = {
2270
2325
  opacity: baseOverLightConfig.opacity * hoverIntensity * activeIntensity,
2271
2326
  contrast: Math.min(1.6, baseOverLightConfig.contrast + .1 * mouseInfluence),
2272
2327
  brightness: Math.min(1.1, baseOverLightConfig.brightness + .05 * mouseInfluence),
2273
2328
  shadowIntensity: Math.min(1.2, Math.max(.5, baseOverLightConfig.shadowIntensity + .2 * mouseInfluence)),
2274
2329
  borderOpacity: Math.min(1, Math.max(.3, baseOverLightConfig.borderOpacity + .1 * mouseInfluence)),
2275
2330
  saturationBoost: baseOverLightConfig.saturationBoost
2276
- }, scaleX = directionalScale.x * scaleBase, scaleY = directionalScale.y * scaleBase, transformStyle = effectiveWithoutEffects ? `scale(${scaleBase})` : `translate(${elasticTranslation.x}px, ${elasticTranslation.y}px) scaleX(${scaleX}) scaleY(${scaleY})`, stretchMagnitude = ((pos1, pos2) => {
2277
- if (!pos1 || !pos2 || "number" != typeof pos1.x || "number" != typeof pos1.y || "number" != typeof pos2.x || "number" != typeof pos2.y) return 0;
2278
- const deltaX = pos1.x - pos2.x, deltaY = pos1.y - pos2.y;
2279
- return Math.sqrt(deltaX * deltaX + deltaY * deltaY);
2280
- })({
2281
- x: 0,
2282
- y: 0
2283
- }, elasticTranslation), tensionFactor = smoothstep(stretchMagnitude / 80), lightingContrast = Math.min(1.8, overLightConfig.contrast + .2 * tensionFactor), lightingBrightness = Math.min(1.2, overLightConfig.brightness + .1 * tensionFactor);
2331
+ }, scaleX = directionalScale.x * scaleBase, scaleY = directionalScale.y * scaleBase, transformStyle = effectiveWithoutEffects ? `scale(${scaleBase})` : `translate(${elasticTranslation.x}px, ${elasticTranslation.y}px) scaleX(${scaleX}) scaleY(${scaleY})`, tensionFactor =
2332
+ /**
2333
+ * Computes tension factor from elastic translation magnitude (0–1).
2334
+ */
2335
+ function(elasticTranslation) {
2336
+ const magnitude = Math.hypot(elasticTranslation.x, elasticTranslation.y);
2337
+ return smoothstep(magnitude / 80);
2338
+ }
2339
+ /**
2340
+ * Updates the styles of the AtomixGlass wrapper and container elements imperatively
2341
+ * to avoid React re-renders on mouse movement.
2342
+ */ (elasticTranslation), lightingContrast = Math.min(1.8, overLightConfig.contrast + .2 * tensionFactor), lightingBrightness = Math.min(1.2, overLightConfig.brightness + .1 * tensionFactor);
2284
2343
  // Calculate mouse influence
2285
2344
  // Update Wrapper Styles (glassVars)
2286
2345
  if (wrapperElement) {
2287
- const mx = mouseOffset.x, my = mouseOffset.y, absMx = Math.abs(mx), absMy = Math.abs(my), GRADIENT = ATOMIX_GLASS.CONSTANTS.GRADIENT, velocityRotation = (mouseVelocity.x + elasticVelocity.x) * (GRADIENT.VELOCITY_ANGLE_MULTIPLIER || 2.5), borderGradientAngle = GRADIENT.BASE_ANGLE + mx * GRADIENT.ANGLE_MULTIPLIER + velocityRotation, chromaticOffset = GRADIENT.CHROMATIC_OFFSET || 1.5, angleR = borderGradientAngle - chromaticOffset, angleB = borderGradientAngle + chromaticOffset, borderStop1 = Math.max(GRADIENT.BORDER_STOP_1.MIN, GRADIENT.BORDER_STOP_1.BASE + my * GRADIENT.BORDER_STOP_1.MULTIPLIER), borderStop2 = Math.min(GRADIENT.BORDER_STOP_2.MAX, GRADIENT.BORDER_STOP_2.BASE + my * GRADIENT.BORDER_STOP_2.MULTIPLIER), tensionGlow = 1 + .5 * tensionFactor, borderOpacities = [ (GRADIENT.BORDER_OPACITY.BASE_1 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_LOW) * tensionGlow, (GRADIENT.BORDER_OPACITY.BASE_2 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_HIGH) * tensionGlow, (GRADIENT.BORDER_OPACITY.BASE_3 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_LOW) * tensionGlow, (GRADIENT.BORDER_OPACITY.BASE_4 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_HIGH) * tensionGlow ], configBorderOpacity = overLightConfig.borderOpacity, whiteColor = ATOMIX_GLASS.CONSTANTS.PALETTE.WHITE, blackColor = ATOMIX_GLASS.CONSTANTS.PALETTE.BLACK, hoverPositions = {
2346
+ const mx = mouseOffset.x, my = mouseOffset.y, absMx = Math.abs(mx), absMy = Math.abs(my), GRADIENT = ATOMIX_GLASS.CONSTANTS.GRADIENT, whiteColor = ATOMIX_GLASS.CONSTANTS.PALETTE.WHITE, blackColor = ATOMIX_GLASS.CONSTANTS.PALETTE.BLACK, hoverPositions = {
2288
2347
  hover1: {
2289
2348
  x: GRADIENT.CENTER_POSITION + mx / GRADIENT.HOVER_POSITION.DIVISOR_1,
2290
2349
  y: GRADIENT.CENTER_POSITION + my / GRADIENT.HOVER_POSITION.DIVISOR_1
@@ -2301,28 +2360,55 @@ class {
2301
2360
  x: GRADIENT.CENTER_POSITION + mx * GRADIENT.BASE_LAYER_MULTIPLIER,
2302
2361
  y: GRADIENT.CENTER_POSITION + my * GRADIENT.BASE_LAYER_MULTIPLIER
2303
2362
  }, opacityValues = {
2304
- hover1: isHovered || isActive ? .5 : 0,
2305
- hover2: isActive ? .5 : 0,
2306
- hover3: isHovered ? .4 : isActive ? .8 : 0,
2307
- base: isOverLight ? overLightConfig.opacity : 0,
2308
- over: isOverLight ? 1.1 * overLightConfig.opacity : 0
2363
+ // hover-1: ambient highlight glow present on hover and during press
2364
+ hover1: isHovered || isActive ? 1 : 0,
2365
+ // hover-2: press depth shadow only fires on active (mousedown)
2366
+ hover2: isActive ? 1 : 0,
2367
+ // hover-3: global soft-light surface shift half-strength on hover, full on press
2368
+ hover3: isActive ? 1 : isHovered ? .55 : 0,
2369
+ // Dark chrome: faint smoky tint; over-light keeps stronger fill
2370
+ base: isOverLight ? overLightConfig.opacity : .14,
2371
+ over: isOverLight ? 1.1 * overLightConfig.opacity : .1
2309
2372
  }, style = wrapperElement.style;
2310
2373
  style.setProperty("--atomix-glass-transform", transformStyle || "none");
2311
2374
  // Parallax for content (liquid refraction feel)
2312
2375
  const parallaxFactor = .38 + .12 * tensionFactor;
2313
2376
  style.setProperty("--atomix-glass-child-parallax", `translate(${elasticTranslation.x * -parallaxFactor}px, ${elasticTranslation.y * -parallaxFactor}px)`),
2314
- style.setProperty("--atomix-glass-contrast", lightingContrast.toString()), style.setProperty("--atomix-glass-brightness", lightingBrightness.toString()),
2377
+ style.setProperty("--atomix-glass-contrast", lightingContrast.toString()), style.setProperty("--atomix-glass-brightness", lightingBrightness.toString());
2315
2378
  // ── Chromatic Rim Lighting ──────────────────────────────────────
2316
- // Layer 1: Core White/Blue highlight
2317
- style.setProperty("--atomix-glass-border-gradient-1", `linear-gradient(${angleB}deg, rgba(${whiteColor}, 0) 0%, rgba(${whiteColor}, ${(borderOpacities[0] ?? 1) * configBorderOpacity}) ${borderStop1}%, rgba(${whiteColor}, ${(borderOpacities[1] ?? 1) * configBorderOpacity}) ${borderStop2}%, rgba(${whiteColor}, 0) 100%)`),
2318
- // Layer 2: Subtle Red/Warm highlight (offset angle)
2319
- style.setProperty("--atomix-glass-border-gradient-2", `linear-gradient(${angleR}deg, rgba(${whiteColor}, 0) 0%, rgba(${whiteColor}, ${(borderOpacities[2] ?? 1) * configBorderOpacity}) ${borderStop1}%, rgba(${whiteColor}, ${(borderOpacities[3] ?? 1) * configBorderOpacity}) ${borderStop2}%, rgba(${whiteColor}, 0) 100%)`),
2320
- // Hover gradients
2321
- style.setProperty("--atomix-glass-hover-1-gradient", isOverLight ? `radial-gradient(circle at ${hoverPositions.hover1.x}% ${hoverPositions.hover1.y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_START}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_STOP}%, rgba(${blackColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_END}%)` : `radial-gradient(circle at ${hoverPositions.hover1.x}% ${hoverPositions.hover1.y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.WHITE_STOP}%)`),
2322
- style.setProperty("--atomix-glass-hover-2-gradient", isOverLight ? `radial-gradient(circle at ${hoverPositions.hover2.x}% ${hoverPositions.hover2.y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_START}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_STOP}%, rgba(${blackColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_END}%)` : `radial-gradient(circle at ${hoverPositions.hover2.x}% ${hoverPositions.hover2.y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.WHITE_STOP}%)`),
2323
- style.setProperty("--atomix-glass-hover-3-gradient", isOverLight ? `radial-gradient(circle at ${hoverPositions.hover3.x}% ${hoverPositions.hover3.y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_START}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_STOP}%, rgba(${blackColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_END}%)` : `radial-gradient(circle at ${hoverPositions.hover3.x}% ${hoverPositions.hover3.y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.WHITE_STOP}%)`),
2324
- style.setProperty("--atomix-glass-base-gradient", isOverLight ? `linear-gradient(${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.ANGLE}deg, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_START_BASE + mx * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_START_MULTIPLIER}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_BASE + my * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_MULTIPLIER}) ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_STOP}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_END_BASE + absMx * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_END_MULTIPLIER}) 100%)` : `rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.WHITE_OPACITY})`),
2325
- style.setProperty("--atomix-glass-overlay-gradient", isOverLight ? `radial-gradient(circle at ${basePosition.x}% ${basePosition.y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_START_BASE + absMx * ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_START_MULTIPLIER}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_MID_STOP}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_END_BASE + absMy * ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_END_MULTIPLIER}) 100%)` : `rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.WHITE_OPACITY})`),
2379
+ const borderVars = ATOMIX_GLASS.BORDER.GRADIENT_CSS_VARS;
2380
+ if (borderAnimated && !effectiveWithoutEffects) {
2381
+ const borderCssVars =
2382
+ /**
2383
+ * Builds animated chromatic rim CSS variables for border layers 1 and 2.
2384
+ * When empty, SCSS static conic/linear fallbacks apply.
2385
+ */
2386
+ function(params) {
2387
+ const {mouseOffset: mouseOffset, mouseVelocity: mouseVelocity, elasticVelocity: elasticVelocity, borderOpacity: borderOpacity, opacityMultiplier: opacityMultiplier = 1, tensionFactor: tensionFactor = 0} = params, mx = mouseOffset.x, my = mouseOffset.y, absMx = Math.abs(mx), velocityRotation = (mouseVelocity.x + elasticVelocity.x) * BORDER_GRADIENT.VELOCITY_ANGLE_MULTIPLIER, borderGradientAngle = BORDER_GRADIENT.BASE_ANGLE + mx * BORDER_GRADIENT.ANGLE_MULTIPLIER + velocityRotation, chromaticOffset = BORDER_GRADIENT.CHROMATIC_OFFSET, angleR = borderGradientAngle - chromaticOffset, angleB = borderGradientAngle + chromaticOffset, borderStop1 = Math.max(BORDER_GRADIENT.STOP_1.MIN, BORDER_GRADIENT.STOP_1.BASE + my * BORDER_GRADIENT.STOP_1.MULTIPLIER), borderStop2 = Math.min(BORDER_GRADIENT.STOP_2.MAX, BORDER_GRADIENT.STOP_2.BASE + my * BORDER_GRADIENT.STOP_2.MULTIPLIER), tensionGlow = 1 + .5 * tensionFactor, opacities = BORDER_GRADIENT.OPACITY, borderOpacities = [ (opacities.BASE_1 + absMx * opacities.MULTIPLIER_LOW) * tensionGlow, (opacities.BASE_2 + absMx * opacities.MULTIPLIER_HIGH) * tensionGlow, (opacities.BASE_3 + absMx * opacities.MULTIPLIER_LOW) * tensionGlow, (opacities.BASE_4 + absMx * opacities.MULTIPLIER_HIGH) * tensionGlow ], configBorderOpacity = borderOpacity * opacityMultiplier, gradient1 = `linear-gradient(${angleB}deg, rgba(${WHITE}, 0) 0%, rgba(${WHITE}, ${(borderOpacities[0] ?? 1) * configBorderOpacity}) ${borderStop1}%, rgba(${WHITE}, ${(borderOpacities[1] ?? 1) * configBorderOpacity}) ${borderStop2}%, rgba(${WHITE}, 0) 100%)`, gradient2 = `linear-gradient(${angleR}deg, rgba(${WHITE}, 0) 0%, rgba(${WHITE}, ${(borderOpacities[2] ?? 1) * configBorderOpacity}) ${borderStop1}%, rgba(${WHITE}, ${(borderOpacities[3] ?? 1) * configBorderOpacity}) ${borderStop2}%, rgba(${WHITE}, 0) 100%)`;
2388
+ return {
2389
+ [BORDER.GRADIENT_CSS_VARS.GRADIENT_1]: gradient1,
2390
+ [BORDER.GRADIENT_CSS_VARS.GRADIENT_2]: gradient2
2391
+ };
2392
+ }({
2393
+ mouseOffset: mouseOffset,
2394
+ mouseVelocity: mouseVelocity,
2395
+ elasticVelocity: elasticVelocity,
2396
+ borderOpacity: overLightConfig.borderOpacity,
2397
+ opacityMultiplier: borderOpacityMultiplier,
2398
+ tensionFactor: tensionFactor
2399
+ });
2400
+ style.setProperty(borderVars.GRADIENT_1, borderCssVars[borderVars.GRADIENT_1] ?? ""),
2401
+ style.setProperty(borderVars.GRADIENT_2, borderCssVars[borderVars.GRADIENT_2] ?? "");
2402
+ } else style.removeProperty(borderVars.GRADIENT_1), style.removeProperty(borderVars.GRADIENT_2);
2403
+ // Hover gradients — cursor-relative radial positions for realistic light tracking.
2404
+ // hover-1: white overlay highlight following cursor (works on both dark + light)
2405
+ style.setProperty("--atomix-glass-hover-1-gradient", `radial-gradient(65% 55% at ${hoverPositions.hover1.x}% ${hoverPositions.hover1.y}%, rgba(${whiteColor}, 0.24) 0%, rgba(${whiteColor}, 0.06) 45%, rgba(${whiteColor}, 0) 72%)`),
2406
+ // hover-2: press depth — darkens at cursor with multiply blend, isOverLight uses stronger black
2407
+ style.setProperty("--atomix-glass-hover-2-gradient", isOverLight ? `radial-gradient(60% 50% at ${hoverPositions.hover2.x}% ${hoverPositions.hover2.y}%, rgba(${blackColor}, 0.22) 0%, rgba(${blackColor}, 0.06) 50%, rgba(${blackColor}, 0) 72%)` : `radial-gradient(60% 50% at ${hoverPositions.hover2.x}% ${hoverPositions.hover2.y}%, rgba(${blackColor}, 0.18) 0%, rgba(${blackColor}, 0.04) 50%, rgba(${blackColor}, 0) 72%)`),
2408
+ // hover-3: full-surface soft-light tint; linear gradient angled with cursor X
2409
+ style.setProperty("--atomix-glass-hover-3-gradient", `linear-gradient(${150 + .3 * mx}deg, rgba(${whiteColor}, ${isOverLight ? .08 : .12}) 0%, rgba(${whiteColor}, 0.04) 55%, rgba(${whiteColor}, 0) 100%)`),
2410
+ style.setProperty("--atomix-glass-base-gradient", isOverLight ? `linear-gradient(${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.ANGLE}deg, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_START_BASE + mx * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_START_MULTIPLIER}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_BASE + my * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_MULTIPLIER}) ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_STOP}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_END_BASE + absMx * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_END_MULTIPLIER}) 100%)` : `linear-gradient(180deg, rgba(${blackColor}, 0.42) 0%, rgba(${blackColor}, 0.22) 55%, rgba(${blackColor}, 0.12) 100%)`),
2411
+ style.setProperty("--atomix-glass-overlay-gradient", isOverLight ? `radial-gradient(circle at ${basePosition.x}% ${basePosition.y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_START_BASE + absMx * ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_START_MULTIPLIER}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_MID_STOP}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_END_BASE + absMy * ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_END_MULTIPLIER}) 100%)` : `radial-gradient(120% 80% at 50% 0%, rgba(${whiteColor}, 0.14) 0%, rgba(${whiteColor}, 0) 55%)`),
2326
2412
  // Opacities
2327
2413
  style.setProperty("--atomix-glass-hover-1-opacity", opacityValues.hover1.toString()),
2328
2414
  style.setProperty("--atomix-glass-hover-2-opacity", opacityValues.hover2.toString()),
@@ -2359,151 +2445,16 @@ class {
2359
2445
  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, 250)}%) contrast(${lightingContrast}) brightness(${lightingBrightness})` : `blur(${clampBlur(.4 * liquidBlur.baseBlur + .25 * liquidBlur.edgeBlur + .15 * liquidBlur.centerBlur + .2 * liquidBlur.flowBlur)}px) saturate(${Math.min(dynamicSaturation, 250)}%) contrast(${lightingContrast}) brightness(${lightingBrightness})`;
2360
2446
  // Container variables
2361
2447
  const style = containerElement.style;
2362
- style.setProperty("--atomix-glass-container-padding", padding), style.setProperty("--atomix-glass-container-radius", `${effectiveBorderRadius}px`),
2448
+ style.setProperty("--atomix-glass-container-radius", `${effectiveBorderRadius}px`),
2363
2449
  style.setProperty("--atomix-glass-container-backdrop", backdropFilterString),
2364
2450
  // Shadows
2365
- 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"),
2451
+ style.setProperty("--atomix-glass-container-shadow", isOverLight ? [ `inset 0 1px 0 rgba(255, 255, 255, ${(.35 + .002 * mx) * (overLightConfig.shadowIntensity || 1)})`, `inset 0 -1px 0 rgba(0, 0, 0, ${(.15 + .001 * Math.abs(my)) * (overLightConfig.shadowIntensity || 1)})`, `inset 0 0 20px rgba(0, 0, 0, ${(.06 + .001 * Math.abs(mx + my)) * (overLightConfig.shadowIntensity || 1)})`, `0 2px 12px rgba(0, 0, 0, ${(.08 + .002 * Math.abs(my)) * (overLightConfig.shadowIntensity || 1)})` ].join(", ") : ATOMIX_GLASS.CONSTANTS.CONTAINER_SHADOW.LIGHT),
2366
2452
  style.setProperty("--atomix-glass-container-shadow-opacity", effectiveWithoutEffects ? "0" : "1"),
2367
2453
  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"),
2368
2454
  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)"),
2369
- 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)");
2455
+ style.setProperty("--atomix-glass-container-box-shadow", isOverLight ? "0px 16px 70px rgba(0, 0, 0, 0.75)" : "0 4px 16px rgba(0, 0, 0, 0.14), 0 1px 4px rgba(0, 0, 0, 0.10)");
2370
2456
  }
2371
- };
2372
-
2373
- /**
2374
- * Updates the styles of the AtomixGlass wrapper and container elements imperatively
2375
- * to avoid React re-renders on mouse movement.
2376
- */
2377
- /**
2378
- * Animation System for AtomixGlass Component
2379
- *
2380
- * Implements Phase 1 features from the AtomixGlass Feature Implementation Roadmap:
2381
- * - Feature 1.1: Time-Based Animation System
2382
- * - Feature 1.2: Multi-Layer Distortion System (FBM)
2383
- *
2384
- * @packageDocumentation
2385
- */
2386
- // ============================================================================
2387
- // Noise Functions for FBM (Feature 1.2)
2388
- // ============================================================================
2389
- /**
2390
- * Perlin noise implementation for smooth gradient noise
2391
- *
2392
- * @param x - X coordinate
2393
- * @param y - Y coordinate
2394
- * @returns Noise value in range [0, 1]
2395
- */
2396
- function perlinNoise(x, y) {
2397
- // Simplified Perlin noise using pseudo-random gradients
2398
- 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);
2399
- // Scale to [0, 1] range
2400
- return (lerp(lerpX1, lerpX2, v) + 1) / 2;
2401
- }
2402
-
2403
- // ============================================================================
2404
- // Fractal Brownian Motion (FBM) Engine (Feature 1.2)
2405
- // ============================================================================
2406
- /**
2407
- * Creates an FBM engine with configurable parameters
2408
- *
2409
- * @param config - FBM configuration (octaves, lacunarity, gain)
2410
- * @returns Object with fbm function
2411
- *
2412
- * @example
2413
- * ```typescript
2414
- * const fbmEngine = createFBMEngine({ octaves: 5, lacunarity: 2, gain: 0.5 });
2415
- *
2416
- * // Generate noise at position (0.5, 0.5) with time animation
2417
- * const noiseValue = fbmEngine.fbm(0.5, 0.5, Date.now());
2418
- * ```
2419
- */ function createFBMEngine(config) {
2420
- /**
2421
- * Fractal Brownian Motion function
2422
- * Combines multiple octaves of noise for complex, natural patterns
2423
- *
2424
- * @param x - X coordinate
2425
- * @param y - Y coordinate
2426
- * @param time - Optional time value for animation
2427
- * @returns FBM noise value in range [0, 1]
2428
- */
2429
- const fbm = (x, y, time = 0) => {
2430
- let value = 0, amplitude = .5, frequency = 1, phase = .001 * time;
2431
- // Convert to seconds for reasonable animation speed
2432
- for (let i = 0; i < config.octaves; i++)
2433
- // Apply time-based phase shift to all octaves
2434
- value += perlinNoise(x * frequency + phase, y * frequency + phase) * amplitude,
2435
- frequency *= config.lacunarity, // Increase frequency
2436
- amplitude *= config.gain;
2437
- return value;
2438
- };
2439
- /**
2440
- * Get FBM with simple time factor
2441
- */ return {
2442
- fbm: fbm,
2443
- fbmWithTime: (x, y, time) => fbm(x, y, time)
2444
- };
2445
- }
2446
-
2447
- /**
2448
- * Gets optimal FBM config based on quality preset
2449
- *
2450
- * @param quality - Quality preset level
2451
- * @returns FBM configuration for the quality level
2452
- */ const fbmEngineCache = new Map;
2453
-
2454
- // ============================================================================
2455
- // Shader Utility Functions for Time-Based Effects
2456
- // ============================================================================
2457
- /**
2458
- * Liquid glass distortion with time-based animation
2459
- * Uses FBM to create organic, flowing liquid effects
2460
- *
2461
- * @param uv - UV coordinates (normalized 0-1)
2462
- * @param time - Elapsed time in milliseconds
2463
- * @param config - FBM configuration
2464
- * @returns Distorted UV coordinates
2465
- */ function liquidGlassWithTime(uv, time, config) {
2466
- const configKey = `${config.octaves}-${config.lacunarity}-${config.gain}`;
2467
- let fbmEngine = fbmEngineCache.get(configKey);
2468
- fbmEngine || (fbmEngine = createFBMEngine(config), fbmEngineCache.set(configKey, fbmEngine));
2469
- // Animate noise with time
2470
- const animatedNoise = fbmEngine.fbmWithTime(2 * uv.x + 1e-4 * time, 2 * uv.y + 15e-5 * time, time);
2471
- return {
2472
- x: uv.x + .04 * (animatedNoise - .5),
2473
- y: uv.y + .04 * (animatedNoise - .5)
2474
- };
2475
- }
2476
-
2477
- // ============================================================================
2478
- // Helper Functions
2479
- // ============================================================================
2480
- /**
2481
- * Fade curve for smooth interpolation (Perlin's fade function)
2482
- */ function fade(t) {
2483
- return t * t * t * (t * (6 * t - 15) + 10);
2484
- }
2485
-
2486
- /**
2487
- * Linear interpolation
2488
- */ function lerp(a, b, t) {
2489
- return a + t * (b - a);
2490
- }
2491
-
2492
- /**
2493
- * Gradient calculation for Perlin noise
2494
- */ function grad(hash, x, y) {
2495
- const h = 15 & hash, u = h < 8 ? x : y, v = h < 4 ? y : 12 === h || 14 === h ? x : 0;
2496
- return (1 & h ? -u : u) + (2 & h ? -v : v);
2497
- }
2498
-
2499
- /**
2500
- * Permutation table for Perlin noise
2501
- */ const p = (() => {
2502
- const permutation = [];
2503
- for (let i = 0; i < 256; i++) permutation[i] = Math.floor(256 * Math.random());
2504
- // Duplicate for overflow handling
2505
- return [ ...permutation, ...permutation ];
2506
- })(), {CONSTANTS: CONSTANTS$1} = ATOMIX_GLASS;
2457
+ }, {CONSTANTS: CONSTANTS$1} = ATOMIX_GLASS;
2507
2458
 
2508
2459
  const {CONSTANTS: CONSTANTS} = ATOMIX_GLASS, backgroundDetectionCache = new WeakMap, setCachedBackgroundDetection = (parentElement, overLightConfig, result, threshold) => {
2509
2460
  parentElement && backgroundDetectionCache.set(parentElement, {
@@ -2518,12 +2469,35 @@ const {CONSTANTS: CONSTANTS} = ATOMIX_GLASS, backgroundDetectionCache = new Weak
2518
2469
  * Composable hook for AtomixGlass component logic
2519
2470
  * Manages all state, calculations, and event handlers
2520
2471
  */
2521
- 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 = ATOMIX_GLASS.DEFAULTS.ELASTICITY, onClick: onClick, debugBorderRadius: debugBorderRadius = !1, debugOverLight: debugOverLight = !1, children: children, blurAmount: blurAmount, saturation: saturation, padding: padding, withLiquidBlur: withLiquidBlur, isFixedOrSticky: isFixedOrSticky = !1, priority: priority = 1, withTimeAnimation:
2522
- // Default priority
2523
- // Phase 1: Animation System Props
2524
- 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}) {
2472
+ 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, border: border, withBorder: withBorder = !0, elasticity: elasticity = ATOMIX_GLASS.DEFAULTS.ELASTICITY, onClick: onClick, debugBorderRadius: debugBorderRadius = !1, debugOverLight: debugOverLight = !1, children: children, blurAmount: blurAmount, saturation: saturation, withLiquidBlur: withLiquidBlur, isFixedOrSticky: isFixedOrSticky = !1, priority: priority = 1}) {
2525
2473
  // State
2526
- const [isHovered, setIsHovered] = useState(!1), [isActive, setIsActive] = useState(!1), cachedRectRef = useRef(null), internalGlobalMousePositionRef = useRef({
2474
+ const [isHovered, setIsHovered] = useState(!1), [isActive, setIsActive] = useState(!1), resolvedBorder = useMemo((() =>
2475
+ /**
2476
+ * Resolves `border` and legacy `withBorder` into a single configuration object.
2477
+ */
2478
+ function(border, withBorder) {
2479
+ const legacyDefault = withBorder ?? !0;
2480
+ return void 0 === border ? {
2481
+ enabled: legacyDefault,
2482
+ width: BORDER.DEFAULT_WIDTH,
2483
+ opacityMultiplier: 1,
2484
+ animated: !0
2485
+ } : "boolean" == typeof border ? {
2486
+ enabled: border,
2487
+ width: BORDER.DEFAULT_WIDTH,
2488
+ opacityMultiplier: 1,
2489
+ animated: !0
2490
+ } : {
2491
+ enabled: border.enabled ?? legacyDefault,
2492
+ width: (value = border.width, void 0 === value ? BORDER.DEFAULT_WIDTH : "number" == typeof value ? `${value}px` : value),
2493
+ opacityMultiplier: border.opacity ?? 1,
2494
+ animated: !1 !== border.animated
2495
+ };
2496
+ /**
2497
+ * Formats border width for CSS custom properties.
2498
+ */
2499
+ var value;
2500
+ }(border, withBorder)), [ border, withBorder ]), cachedRectRef = useRef(null), internalGlobalMousePositionRef = useRef({
2527
2501
  x: 0,
2528
2502
  y: 0
2529
2503
  }), internalMouseOffsetRef = useRef({
@@ -2547,52 +2521,10 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
2547
2521
  }), scaleVelocityRef = useRef({
2548
2522
  x: 0,
2549
2523
  y: 0
2550
- });
2551
- useRef(0);
2552
- const mouseVelocityRef = useRef({
2524
+ }), mouseVelocityRef = useRef({
2553
2525
  x: 0,
2554
2526
  y: 0
2555
- }), [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((() => {
2556
- // If quality preset is provided, use it as base
2557
- const preset = (quality = distortionQuality, ATOMIX_GLASS.CONSTANTS.DISTORTION_QUALITY_PRESETS[quality]);
2558
- // Override with custom values if provided
2559
- var quality;
2560
- return {
2561
- octaves: distortionOctaves ?? preset.octaves,
2562
- lacunarity: distortionLacunarity ?? preset.lacunarity,
2563
- gain: distortionGain ?? preset.gain
2564
- };
2565
- }), [ distortionQuality, distortionOctaves, distortionLacunarity, distortionGain ]), fbmEngine = useMemo((() => withMultiLayerDistortion ? createFBMEngine(fbmConfig) : null), [ withMultiLayerDistortion, fbmConfig ]), effectiveReducedMotion = useMemo((() => reducedMotion || userPrefersReducedMotion), [ reducedMotion, userPrefersReducedMotion ]), effectiveWithTimeAnimation = useMemo((() => withTimeAnimation && !effectiveReducedMotion), [ withTimeAnimation, effectiveReducedMotion ]);
2566
- /**
2567
- * Animation loop for time-based effects
2568
- */
2569
- useEffect((() => {
2570
- if (!effectiveWithTimeAnimation || "undefined" == typeof window) return;
2571
- let lastFrameTime = performance.now();
2572
- /**
2573
- * Animation frame handler
2574
- */ const animate = currentTime => {
2575
- // Calculate delta time
2576
- const deltaTime = currentTime - lastFrameTime;
2577
- lastFrameTime = currentTime;
2578
- // Apply animation speed multiplier
2579
- const scaledDelta = deltaTime * animationSpeed;
2580
- elapsedTimeRef.current += scaledDelta, shaderTimeRef.current = elapsedTimeRef.current,
2581
- // Continue animation loop
2582
- animationFrameIdRef.current = requestAnimationFrame(animate);
2583
- };
2584
- // Start animation
2585
- // Cleanup
2586
- return animationStartTimeRef.current = performance.now(), animationFrameIdRef.current = requestAnimationFrame(animate),
2587
- () => {
2588
- null !== animationFrameIdRef.current && (cancelAnimationFrame(animationFrameIdRef.current),
2589
- animationFrameIdRef.current = null);
2590
- };
2591
- }), [ effectiveWithTimeAnimation, animationSpeed ]);
2592
- /**
2593
- * Get current shader time for animations
2594
- */
2595
- 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}) {
2527
+ }), [userPrefersReducedMotion, setUserPrefersReducedMotion] = useState(!1), [userPrefersHighContrast, setUserPrefersHighContrast] = useState(!1), [detectedOverLight, setDetectedOverLight] = useState(!1), effectiveReducedMotion = useMemo((() => reducedMotion || userPrefersReducedMotion), [ reducedMotion, userPrefersReducedMotion ]), effectiveBorderRadius = useMemo((() => void 0 !== borderRadius ? Math.max(0, borderRadius) : Math.max(0, dynamicBorderRadius)), [ borderRadius, dynamicBorderRadius ]), {glassSize: glassSize} = function({glassRef: glassRef, effectiveBorderRadius: effectiveBorderRadius, cachedRectRef: cachedRectRef}) {
2596
2528
  const [glassSize, setGlassSize] = useState({
2597
2529
  width: 270,
2598
2530
  height: 69
@@ -2652,9 +2584,6 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
2652
2584
  effectiveBorderRadius: effectiveBorderRadius,
2653
2585
  cachedRectRef: cachedRectRef
2654
2586
  }), effectiveHighContrast = useMemo((() => highContrast || userPrefersHighContrast), [ highContrast, userPrefersHighContrast ]), effectiveWithoutEffects = useMemo((() => withoutEffects || effectiveReducedMotion), [ withoutEffects, effectiveReducedMotion ]), globalMousePosition = externalGlobalMousePosition || internalGlobalMousePositionRef.current, mouseOffset = externalMouseOffset || internalMouseOffsetRef.current;
2655
- /**
2656
- * Apply time-based distortion to UV coordinates
2657
- */
2658
2587
  // Extract border-radius from children
2659
2588
  useEffect((() => {
2660
2589
  const extractRadius = () => {
@@ -2814,25 +2743,26 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
2814
2743
  * Get effective overLight value based on configuration
2815
2744
  */
2816
2745
  const getEffectiveOverLight = useCallback((() => "boolean" == typeof overLight ? overLight : ("auto" === overLight || "object" == typeof overLight && null !== overLight) && detectedOverLight), [ overLight, detectedOverLight ]), validateConfigValue = useCallback(((value, min, max, defaultValue) => "number" != typeof value || isNaN(value) || !isFinite(value) ? defaultValue : Math.min(max, Math.max(min, value))), []), overLightConfig = useMemo((() => {
2817
- const isOverLight = getEffectiveOverLight(), hoverIntensity = isHovered ? 1.4 : 1, activeIntensity = isActive ? 1.6 : 1, baseConfig = {
2746
+ const isOverLight = getEffectiveOverLight(), {hoverIntensity: hoverIntensity, activeIntensity: activeIntensity} = getInteractionIntensity(isHovered, isActive), baseConfig = {
2818
2747
  isOverLight: isOverLight,
2819
2748
  threshold: .7,
2820
2749
  opacity: isOverLight ? Math.min(.6, Math.max(.2, .5 * hoverIntensity * activeIntensity)) : 0,
2821
- contrast: 1.4,
2822
- brightness: .9,
2823
- saturationBoost: 1.3,
2824
- // Fixed value dynamic saturation amplifies perceived displacement
2825
- shadowIntensity: .9,
2826
- borderOpacity: .7
2750
+ // Dark UI (Apple Music): neutral contrast + slight brightness lift
2751
+ contrast: isOverLight ? 1.4 : 1.02,
2752
+ brightness: isOverLight ? .9 : 1.02,
2753
+ saturationBoost: isOverLight ? 1.3 : 1,
2754
+ shadowIntensity: isOverLight ? .9 : 1,
2755
+ borderOpacity: isOverLight ? ATOMIX_GLASS.BORDER.OVER_LIGHT.opacity : ATOMIX_GLASS.BORDER.DARK.opacity
2827
2756
  };
2828
2757
  if ("object" == typeof overLight && null !== overLight) {
2829
- const objConfig = overLight, validatedThreshold = validateConfigValue(objConfig.threshold, .1, 1, baseConfig.threshold), validatedOpacity = validateConfigValue(objConfig.opacity, .1, 1, baseConfig.opacity), validatedContrast = validateConfigValue(objConfig.contrast, .5, 2.5, baseConfig.contrast), validatedBrightness = validateConfigValue(objConfig.brightness, .5, 2, baseConfig.brightness), validatedSaturationBoost = validateConfigValue(objConfig.saturationBoost, .5, 3, baseConfig.saturationBoost), finalConfig = {
2758
+ const objConfig = overLight, validatedThreshold = validateConfigValue(objConfig.threshold, .1, 1, baseConfig.threshold), validatedOpacity = validateConfigValue(objConfig.opacity, .1, 1, baseConfig.opacity), validatedContrast = validateConfigValue(objConfig.contrast, .5, 2.5, baseConfig.contrast), validatedBrightness = validateConfigValue(objConfig.brightness, .5, 2, baseConfig.brightness), validatedSaturationBoost = validateConfigValue(objConfig.saturationBoost, .5, 3, baseConfig.saturationBoost), validatedBorderOpacity = validateConfigValue(objConfig.borderOpacity, .1, 1, baseConfig.borderOpacity), finalConfig = {
2830
2759
  ...baseConfig,
2831
2760
  threshold: validatedThreshold,
2832
2761
  opacity: validatedOpacity * hoverIntensity * activeIntensity,
2833
2762
  contrast: validatedContrast,
2834
2763
  brightness: validatedBrightness,
2835
- saturationBoost: validatedSaturationBoost
2764
+ saturationBoost: validatedSaturationBoost,
2765
+ borderOpacity: validatedBorderOpacity
2836
2766
  };
2837
2767
  return "undefined" == typeof process || process.env, finalConfig;
2838
2768
  }
@@ -2857,8 +2787,8 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
2857
2787
  };
2858
2788
  const curG = internalGlobalMousePositionRef.current, tgtG = targetGlobalMousePositionRef.current;
2859
2789
  internalGlobalMousePositionRef.current = {
2860
- x: lerp$1(curG.x, tgtG.x, CONSTANTS.LERP_FACTOR),
2861
- y: lerp$1(curG.y, tgtG.y, CONSTANTS.LERP_FACTOR)
2790
+ x: lerp(curG.x, tgtG.x, CONSTANTS.LERP_FACTOR),
2791
+ y: lerp(curG.y, tgtG.y, CONSTANTS.LERP_FACTOR)
2862
2792
  };
2863
2793
  // ── Calculate Elastic Physics ─────────────────────────────────────
2864
2794
  let targetElasticTranslation = {
@@ -2930,12 +2860,13 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
2930
2860
  withLiquidBlur: withLiquidBlur,
2931
2861
  blurAmount: blurAmount,
2932
2862
  saturation: saturation,
2933
- padding: padding,
2934
- isFixedOrSticky: isFixedOrSticky
2863
+ isFixedOrSticky: isFixedOrSticky,
2864
+ borderAnimated: resolvedBorder.animated,
2865
+ borderOpacityMultiplier: resolvedBorder.opacityMultiplier
2935
2866
  }), Math.abs(mouseVelocityRef.current.x) < .001 && Math.abs(mouseVelocityRef.current.y) < .001 && Math.abs(elasticVelocityRef.current.x) < .001 && Math.abs(elasticVelocityRef.current.y) < .001 && Math.abs(scaleVelocityRef.current.x) < .001 && Math.abs(scaleVelocityRef.current.y) < .001 && Math.abs(internalMouseOffsetRef.current.x - targetMouseOffsetRef.current.x) < .001 && Math.abs(internalMouseOffsetRef.current.y - targetMouseOffsetRef.current.y) < .001 ? stopLerpLoop() : lerpRafRef.current = requestAnimationFrame(tick);
2936
2867
  };
2937
2868
  lerpRafRef.current = requestAnimationFrame(tick);
2938
- }), [ glassRef, wrapperRef, glassSize, isHovered, isActive, overLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, onClick, withLiquidBlur, blurAmount, saturation, padding, isFixedOrSticky, stopLerpLoop ]), handleGlobalMousePosition = useCallback((globalPos => {
2869
+ }), [ glassRef, wrapperRef, glassSize, isHovered, isActive, overLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, onClick, withLiquidBlur, blurAmount, saturation, isFixedOrSticky, resolvedBorder.animated, resolvedBorder.opacityMultiplier, stopLerpLoop ]), handleGlobalMousePosition = useCallback((globalPos => {
2939
2870
  if (externalGlobalMousePosition && externalMouseOffset) return;
2940
2871
  if (effectiveWithoutEffects) return;
2941
2872
  const container = mouseContainer?.current || glassRef.current;
@@ -2999,9 +2930,10 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
2999
2930
  withLiquidBlur: withLiquidBlur,
3000
2931
  blurAmount: blurAmount,
3001
2932
  saturation: saturation,
3002
- padding: padding
2933
+ borderAnimated: resolvedBorder.animated,
2934
+ borderOpacityMultiplier: resolvedBorder.opacityMultiplier
3003
2935
  });
3004
- }), [ isHovered, isActive, glassSize, overLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, wrapperRef, glassRef, externalMouseOffset, externalGlobalMousePosition, withLiquidBlur, blurAmount, saturation, padding, onClick ]);
2936
+ }), [ isHovered, isActive, glassSize, overLightConfig, effectiveBorderRadius, effectiveWithoutEffects, effectiveReducedMotion, elasticity, wrapperRef, glassRef, externalMouseOffset, externalGlobalMousePosition, withLiquidBlur, blurAmount, saturation, resolvedBorder.animated, resolvedBorder.opacityMultiplier, onClick ]);
3005
2937
  // Event handlers
3006
2938
  const handleMouseEnter = useCallback((() => setIsHovered(!0)), []), handleMouseLeave = useCallback((() => setIsHovered(!1)), []), handleMouseDown = useCallback((() => setIsActive(!0)), []), handleMouseUp = useCallback((() => setIsActive(!1)), []), handleKeyDown = useCallback((e => {
3007
2939
  !onClick || "Enter" !== e.key && " " !== e.key || (e.preventDefault(), onClick());
@@ -3021,9 +2953,8 @@ withTimeAnimation = ATOMIX_GLASS.DEFAULTS.WITH_TIME_ANIMATION, animationSpeed: a
3021
2953
  mouseOffset: mouseOffset,
3022
2954
  // This is now static (refs or props) unless prop changes
3023
2955
  overLightConfig: overLightConfig,
2956
+ resolvedBorder: resolvedBorder,
3024
2957
  transformStyle: transformStyle,
3025
- getShaderTime: getShaderTime,
3026
- applyTimeBasedDistortion: applyTimeBasedDistortion,
3027
2958
  handleMouseEnter: handleMouseEnter,
3028
2959
  handleMouseLeave: handleMouseLeave,
3029
2960
  handleMouseDown: handleMouseDown,
@@ -3171,148 +3102,6 @@ const _includesInstanceProperty = getDefaultExportFromCjs((function(it) {
3171
3102
  /**
3172
3103
  * Get GPU memory info if available (Chrome DevTools only)
3173
3104
  */
3174
- /** Map an FPS value to a semantic color token string. */
3175
- const getQualityColor = quality => {
3176
- switch (quality) {
3177
- case "high":
3178
- return "var(--atomix-color-success, #4ade80)";
3179
-
3180
- case "medium":
3181
- return "var(--atomix-color-warning, #fbbf24)";
3182
-
3183
- case "low":
3184
- return "var(--atomix-color-danger, #ef4444)";
3185
-
3186
- default:
3187
- return "#9ca3af";
3188
- }
3189
- }, getFpsLabel = fps => fps >= 58 ? "Optimal" : fps >= 45 ? "Warning" : "Critical";
3190
-
3191
- /** Map a quality level string to a semantic color token string. */
3192
- // Inject keyframes once
3193
- if ("undefined" != typeof document) {
3194
- const styleId = "perf-dashboard-keyframes";
3195
- if (!document.getElementById(styleId)) {
3196
- const styleEl = document.createElement("style");
3197
- styleEl.id = styleId, styleEl.textContent = "\n@keyframes perf-dashboard-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.5; }\n}\n",
3198
- document.head.appendChild(styleEl);
3199
- }
3200
- }
3201
-
3202
- /**
3203
- * PerformanceDashboard - Real-time performance monitoring overlay.
3204
- *
3205
- * Displays FPS, frame time, quality level, GPU memory, and auto-scaling status.
3206
- * Rendered only when `debugPerformance={true}` on the parent `AtomixGlass`.
3207
- */ const PerformanceDashboard = memo((({metrics: metrics, isVisible: isVisible = !0, onClose: onClose}) => {
3208
- if (!isVisible) return null;
3209
- const fpsColor = (fps = metrics.fps) >= 58 ? "var(--atomix-color-success, #4ade80)" : fps >= 45 ? "var(--atomix-color-warning, #fbbf24)" : "var(--atomix-color-danger, #ef4444)";
3210
- var fps;
3211
- const isCritical = metrics.fps < 45;
3212
- return jsxs("div", {
3213
- className: "c-perf-dashboard u-position-fixed u-top-4 u-end-4 u-p-3 u-px-4 u-text-xs u-font-mono u-text-white u-rounded-md u-border u-border-white-alpha-10 u-shadow-lg",
3214
- style: {
3215
- zIndex: 9999,
3216
- minWidth: "12.5rem",
3217
- // 200px
3218
- backgroundColor: "rgba(17, 24, 39, 0.95)",
3219
- backdropFilter: "blur(8px)",
3220
- transition: "opacity 0.3s ease"
3221
- },
3222
- children: [ jsxs("div", {
3223
- className: "u-flex u-items-center u-justify-between u-mb-2 u-pb-2 u-border-b u-border-white-alpha-10",
3224
- children: [ jsx("span", {
3225
- className: "u-text-sm u-font-bold u-text-white",
3226
- children: "Performance Monitor"
3227
- }), onClose && jsx("button", {
3228
- className: "u-bg-transparent u-border-none u-p-0 u-line-height-1 u-text-base u-text-gray-400 u-cursor-pointer hover:u-text-white",
3229
- onClick: onClose,
3230
- "aria-label": "Close performance dashboard",
3231
- style: {
3232
- transition: "color 0.2s ease"
3233
- },
3234
- children: "×"
3235
- }) ]
3236
- }), jsxs("div", {
3237
- className: "u-flex u-items-center u-justify-between u-mb-1-5",
3238
- children: [ jsx("span", {
3239
- className: "u-text-gray-400 u-me-3",
3240
- children: "FPS"
3241
- }), jsx("span", {
3242
- className: "u-font-bold",
3243
- style: {
3244
- color: fpsColor
3245
- },
3246
- children: Math.round(metrics.fps)
3247
- }) ]
3248
- }), jsxs("div", {
3249
- className: "u-flex u-items-center u-justify-between u-mb-1-5",
3250
- children: [ jsx("span", {
3251
- className: "u-text-gray-400 u-me-3",
3252
- children: "Frame Time"
3253
- }), jsxs("span", {
3254
- className: "u-font-bold",
3255
- children: [ metrics.frameTime.toFixed(2), "ms" ]
3256
- }) ]
3257
- }), jsxs("div", {
3258
- className: "u-flex u-items-center u-justify-between u-mb-1-5",
3259
- children: [ jsx("span", {
3260
- className: "u-text-gray-400 u-me-3",
3261
- children: "Quality"
3262
- }), jsx("span", {
3263
- className: "u-font-bold u-text-uppercase",
3264
- style: {
3265
- fontSize: "0.6875rem",
3266
- // 11px
3267
- color: getQualityColor(metrics.qualityLevel)
3268
- },
3269
- children: metrics.qualityLevel
3270
- }) ]
3271
- }), metrics.gpuMemory && jsxs("div", {
3272
- className: "u-flex u-items-center u-justify-between u-mb-1-5",
3273
- children: [ jsx("span", {
3274
- className: "u-text-gray-400 u-me-3",
3275
- children: "GPU Memory"
3276
- }), jsxs("span", {
3277
- className: "u-font-bold",
3278
- children: [ "~", Math.round(metrics.gpuMemory / 1024), "MB" ]
3279
- }) ]
3280
- }), metrics.isAutoScaling && jsx("div", {
3281
- className: "u-mt-2 u-pt-2 u-border-t u-border-white-alpha-10 u-text-center",
3282
- style: {
3283
- fontSize: "0.625rem",
3284
- // 10px
3285
- color: "#6b7280"
3286
- },
3287
- children: "Auto-scaling active"
3288
- }), jsxs("div", {
3289
- className: "u-flex u-items-center u-gap-2 u-mt-2 u-pt-2 u-border-t u-border-white-alpha-10",
3290
- children: [ jsx("div", {
3291
- className: "u-rounded-full",
3292
- style: {
3293
- width: "0.5rem",
3294
- height: "0.5rem",
3295
- flexShrink: 0,
3296
- backgroundColor: fpsColor,
3297
- ...isCritical && {
3298
- animation: "perf-dashboard-pulse 1s infinite"
3299
- }
3300
- }
3301
- }), jsx("span", {
3302
- className: "u-text-xs",
3303
- style: {
3304
- fontSize: "0.625rem",
3305
- // 10px
3306
- color: fpsColor
3307
- },
3308
- children: getFpsLabel(metrics.fps)
3309
- }) ]
3310
- }) ]
3311
- });
3312
- }));
3313
-
3314
- PerformanceDashboard.displayName = "PerformanceDashboard";
3315
-
3316
3105
  /**
3317
3106
  * Mobile optimization presets
3318
3107
  *
@@ -3432,18 +3221,13 @@ const PERFORMANCE_PRESET = {
3432
3221
  saturation: 70
3433
3222
  }
3434
3223
  }
3435
- }, AtomixGlassInner = forwardRef((function({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, isFixedOrSticky: propsIsFixedOrSticky, ...rest}, ref) {
3436
- const glassRef = useRef(null), contentRef = useRef(null), internalWrapperRef = useRef(null), mergedRef = useMemo((() =>
3437
- // Helper to merge refs
3438
- function(...refs) {
3439
- return node => {
3440
- refs.forEach((ref => {
3441
- "function" == typeof ref ? ref(node) : null != ref && (ref.current = node);
3442
- }));
3443
- };
3444
- }
3445
- // Internal implementation with forwardRef
3446
- (ref, internalWrapperRef)), [ ref ]), {zIndex: customZIndex, ...restStyle} = style, isFixedOrSticky = propsIsFixedOrSticky || "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, handleMouseEnter: handleMouseEnter, handleMouseLeave: handleMouseLeave, handleMouseDown: handleMouseDown, handleMouseUp: handleMouseUp, handleKeyDown: handleKeyDown} = useAtomixGlass({
3224
+ }, AtomixGlassInner = forwardRef((function({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 = "", 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, border: border, withBorder: withBorder = !0, debugBorderRadius: debugBorderRadius = !1, 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, isFixedOrSticky: propsIsFixedOrSticky, ...rest}, ref) {
3225
+ const glassRef = useRef(null), contentRef = useRef(null), internalWrapperRef = useRef(null), mergedRef = useForkRef(ref, internalWrapperRef), {zIndex: customZIndex, ...restStyle} = style, isFixedOrSticky = (explicit = propsIsFixedOrSticky,
3226
+ position = restStyle.position, Boolean(explicit || "fixed" === position || "sticky" === position));
3227
+ var explicit, position;
3228
+ /**
3229
+ * Extracts layout-related properties from a React `CSSProperties` object.
3230
+ */ const {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, resolvedBorder: resolvedBorder} = useAtomixGlass({
3447
3231
  glassRef: glassRef,
3448
3232
  contentRef: contentRef,
3449
3233
  wrapperRef: internalWrapperRef,
@@ -3463,20 +3247,13 @@ const PERFORMANCE_PRESET = {
3463
3247
  blurAmount: blurAmount,
3464
3248
  saturation: saturation,
3465
3249
  withLiquidBlur: withLiquidBlur,
3466
- padding: padding,
3250
+ border: border,
3251
+ withBorder: withBorder,
3252
+ debugBorderRadius: debugBorderRadius,
3467
3253
  style: style,
3468
- isFixedOrSticky: isFixedOrSticky,
3469
- // Phase 1: Animation System props
3470
- withTimeAnimation: withTimeAnimation,
3471
- animationSpeed: animationSpeed,
3472
- withMultiLayerDistortion: withMultiLayerDistortion,
3473
- distortionOctaves: distortionOctaves,
3474
- distortionLacunarity: distortionLacunarity,
3475
- distortionGain: distortionGain,
3476
- distortionQuality: distortionQuality
3254
+ isFixedOrSticky: isFixedOrSticky
3477
3255
  });
3478
- // Responsive breakpoint system - automatically adjusts parameters based on viewport
3479
- !
3256
+ (
3480
3257
  /**
3481
3258
  * Responsive Glass Parameters Hook
3482
3259
  *
@@ -3631,7 +3408,7 @@ const PERFORMANCE_PRESET = {
3631
3408
  }), [ enabled ]), useCallback((() => {
3632
3409
  calculateParams();
3633
3410
  }), [ calculateParams ]);
3634
- }({
3411
+ })({
3635
3412
  baseParams: {
3636
3413
  ...useMemo((() =>
3637
3414
  /**
@@ -3665,9 +3442,7 @@ const PERFORMANCE_PRESET = {
3665
3442
  breakpoints: MOBILE_OPTIMIZED_BREAKPOINTS,
3666
3443
  enabled: !disableResponsiveBreakpoints && "undefined" != typeof window,
3667
3444
  debug: !1
3668
- });
3669
- // Performance monitoring - tracks FPS, frame time, memory usage
3670
- const {metrics: performanceMetrics, toggleMonitoring: toggleMonitoring} =
3445
+ }),
3671
3446
  /**
3672
3447
  * Performance Monitor Hook
3673
3448
  *
@@ -3702,7 +3477,13 @@ const PERFORMANCE_PRESET = {
3702
3477
  timestamp: 0,
3703
3478
  isAutoScaling: !0,
3704
3479
  lowFpsCount: 0
3705
- }), [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 => {
3480
+ }), [manualOverride, setManualOverride] = useState(!1), [isEnabled, setIsEnabled] = useState(enabled);
3481
+ // Sync external `enabled` prop changes into internal state
3482
+ useEffect((() => {
3483
+ setIsEnabled(enabled ?? !0);
3484
+ }), [ enabled ]);
3485
+ // Refs for frame tracking
3486
+ const frameCountRef = useRef(0), lastFpsUpdateRef = useRef(0), lastFrameTimeRef = useRef(0), animationFrameRef = useRef(null), lowFpsCountRef = useRef(0), highFpsCountRef = useRef(0), qualityLevelRef = useRef("medium"), updateMetrics = useCallback((newMetrics => {
3706
3487
  setMetrics((prev => ({
3707
3488
  ...prev,
3708
3489
  ...newMetrics,
@@ -3822,191 +3603,214 @@ const PERFORMANCE_PRESET = {
3822
3603
  /**
3823
3604
  * Reset to auto-scaling mode
3824
3605
  */ var fps, currentQuality;
3825
- return {
3826
- metrics: metrics,
3827
- recommendedQuality: (fps = metrics.fps, currentQuality = metrics.qualityLevel, fps >= 58 ? "high" : fps >= 45 ? "high" === currentQuality ? "high" : "medium" : "low"),
3828
- isUnderperforming: metrics.fps < minFps,
3829
- setQualityLevel: setQualityLevel,
3830
- resetAutoScaling: resetAutoScaling,
3831
- toggleMonitoring: toggleMonitoring
3832
- };
3606
+ fps = metrics.fps, currentQuality = metrics.qualityLevel, metrics.fps;
3833
3607
  }({
3834
3608
  enabled: debugPerformance,
3835
- // Enable when debugPerformance is true
3836
3609
  debug: !1,
3837
3610
  showOverlay: !1
3838
3611
  });
3839
- // Auto-start performance monitoring when debugPerformance is enabled
3840
- React.useEffect((() => {
3841
- debugPerformance && toggleMonitoring();
3842
- // eslint-disable-next-line react-hooks/exhaustive-deps
3843
- }), [ debugPerformance ]);
3844
- // Re-run when debugPerformance changes
3845
- const isOverLight = useMemo((() => overLightConfig.isOverLight), [ overLightConfig.isOverLight ]), shouldRenderOverLightLayers = withOverLightLayers && isOverLight, rootLayoutStyle = useMemo((() => {
3846
- if (!isFixedOrSticky) return {};
3847
- const {position: p, top: t, left: l, right: r, bottom: b} = restStyle;
3848
- return {
3849
- ...p && {
3850
- position: p
3851
- },
3852
- ...void 0 !== t && {
3853
- top: t
3854
- },
3855
- ...void 0 !== l && {
3856
- left: l
3857
- },
3858
- ...void 0 !== r && {
3859
- right: r
3860
- },
3861
- ...void 0 !== b && {
3862
- bottom: b
3863
- }
3864
- };
3865
- }), [ isFixedOrSticky, restStyle ]);
3866
- // Calculate base style with transforms
3867
- // When layout is hoisted to the root, strip those props from the container
3868
- useMemo((() => {
3869
- if (isFixedOrSticky) {
3870
- const {position: _p, top: _t, left: _l, right: _r, bottom: _b, ...visualStyle} = restStyle;
3871
- return {
3872
- ...visualStyle
3873
- };
3612
+ const isOverLight = useMemo((() => overLightConfig.isOverLight), [ overLightConfig.isOverLight ]), shouldRenderOverLightLayers = withOverLightLayers && isOverLight, containerStyle = useMemo((() => ({
3613
+ ...restStyle,
3614
+ ...void 0 !== customZIndex && {
3615
+ zIndex: customZIndex
3874
3616
  }
3617
+ })), [ restStyle, customZIndex ]), componentClassName = mergeClassNames(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), positionStyles = useMemo((() =>
3618
+ /**
3619
+ * Returns the internal positioning context for effect layers relative to the root.
3620
+ */
3621
+ function(isFixedOrSticky, restStyle) {
3875
3622
  return {
3876
- ...restStyle
3623
+ position: isFixedOrSticky ? "absolute" : restStyle.position || "absolute",
3624
+ top: 0,
3625
+ left: 0,
3626
+ right: "auto",
3627
+ bottom: "auto"
3877
3628
  };
3878
- }), [ isFixedOrSticky, restStyle ]);
3879
- // Build className with state modifiers
3880
- 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((() => ({
3881
- position: isFixedOrSticky ? "absolute" : restStyle.position || "absolute",
3882
- top: isFixedOrSticky ? restStyle.top ?? 0 : 0,
3883
- left: isFixedOrSticky ? restStyle.left ?? 0 : 0,
3884
- right: isFixedOrSticky ? restStyle.right ?? "auto" : "auto",
3885
- bottom: isFixedOrSticky ? restStyle.bottom ?? "auto" : "auto"
3886
- })), [ isFixedOrSticky, restStyle.position, restStyle.top, restStyle.left, restStyle.right, restStyle.bottom ]), adjustedSize = useMemo((() => {
3887
- // Keep a reference to positionStyles to avoid unused-variable lint,
3888
- // but sizing is driven by explicit width/height or measured size.
3889
- positionStyles.position;
3890
- const resolveLength = (value, measured) => void 0 !== value && isFixedOrSticky ? "number" == typeof value ? `${value}px` : value : measured > 0 && isFixedOrSticky ? `${measured}px` : "100%", effectiveWidth = width ?? restStyle.width, effectiveHeight = height ?? restStyle.height;
3629
+ }
3630
+ /**
3631
+ * Computes `--atomix-glass-width` and `--atomix-glass-height` values.
3632
+ *
3633
+ * Fixed/sticky elements prefer explicit dimensions or measured size; in-flow
3634
+ * elements default to `100%`.
3635
+ */ (isFixedOrSticky, restStyle)), [ isFixedOrSticky, restStyle ]), adjustedSize = useMemo((() => function(options) {
3636
+ const {width: width, height: height, restStyle: restStyle, glassSize: glassSize, isFixedOrSticky: isFixedOrSticky} = options, resolveLength = (value, measured) => void 0 !== value && isFixedOrSticky ? "number" == typeof value ? `${value}px` : value : measured > 0 && isFixedOrSticky ? `${measured}px` : "100%", effectiveWidth = width ?? restStyle.width, effectiveHeight = height ?? restStyle.height;
3891
3637
  return {
3892
3638
  width: resolveLength(effectiveWidth, glassSize.width),
3893
3639
  height: resolveLength(effectiveHeight, glassSize.height)
3894
3640
  };
3895
- }), [ width, height, restStyle.width, restStyle.height, positionStyles.position, glassSize.width, glassSize.height, isFixedOrSticky ]), gradientValues = useMemo((() => {
3896
- const mx = mouseOffset.x, my = mouseOffset.y, absMx = Math.abs(mx), absMy = Math.abs(my), GRADIENT = ATOMIX_GLASS.CONSTANTS.GRADIENT;
3897
- return {
3898
- borderGradientAngle: GRADIENT.BASE_ANGLE + mx * GRADIENT.ANGLE_MULTIPLIER,
3899
- borderStop1: Math.max(GRADIENT.BORDER_STOP_1.MIN, GRADIENT.BORDER_STOP_1.BASE + my * GRADIENT.BORDER_STOP_1.MULTIPLIER),
3900
- borderStop2: Math.min(GRADIENT.BORDER_STOP_2.MAX, GRADIENT.BORDER_STOP_2.BASE + my * GRADIENT.BORDER_STOP_2.MULTIPLIER),
3901
- borderOpacities: [ GRADIENT.BORDER_OPACITY.BASE_1 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_LOW, GRADIENT.BORDER_OPACITY.BASE_2 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_HIGH, GRADIENT.BORDER_OPACITY.BASE_3 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_LOW, GRADIENT.BORDER_OPACITY.BASE_4 + absMx * GRADIENT.BORDER_OPACITY.MULTIPLIER_HIGH ],
3902
- hoverPositions: {
3903
- hover1: {
3904
- x: GRADIENT.CENTER_POSITION + mx / GRADIENT.HOVER_POSITION.DIVISOR_1,
3905
- y: GRADIENT.CENTER_POSITION + my / GRADIENT.HOVER_POSITION.DIVISOR_1
3906
- },
3907
- hover2: {
3908
- x: GRADIENT.CENTER_POSITION + mx / GRADIENT.HOVER_POSITION.DIVISOR_2,
3909
- y: GRADIENT.CENTER_POSITION + my / GRADIENT.HOVER_POSITION.DIVISOR_2
3910
- },
3911
- hover3: {
3912
- x: GRADIENT.CENTER_POSITION + mx * GRADIENT.HOVER_POSITION.MULTIPLIER_3,
3913
- y: GRADIENT.CENTER_POSITION + my * GRADIENT.HOVER_POSITION.MULTIPLIER_3
3914
- }
3915
- },
3916
- basePosition: {
3917
- x: GRADIENT.CENTER_POSITION + mx * GRADIENT.BASE_LAYER_MULTIPLIER,
3918
- y: GRADIENT.CENTER_POSITION + my * GRADIENT.BASE_LAYER_MULTIPLIER
3919
- },
3920
- mx: mx,
3921
- my: my,
3922
- absMx: absMx,
3923
- absMy: absMy
3924
- };
3925
- }), [ mouseOffset.x, mouseOffset.y ]), clampedOverLightOpacity = Math.max(0, Math.min(1, overLightConfig?.opacity ?? .4)), clampedBorderOpacity = Math.max(0, Math.min(1, overLightConfig?.borderOpacity ?? 1)), opacityValues = useMemo((() => ({
3926
- hover1: isHovered || isActive ? .5 : 0,
3927
- hover2: isActive ? .5 : 0,
3928
- hover3: isHovered ? .4 : isActive ? .8 : 0,
3929
- base: isOverLight ? clampedOverLightOpacity || .4 : 0,
3930
- over: isOverLight ? 1.1 * (clampedOverLightOpacity || .4) : 0
3931
- })), [ isHovered, isActive, isOverLight, clampedOverLightOpacity ]), glassVars = useMemo((() => {
3932
- const whiteColor = ATOMIX_GLASS.CONSTANTS.PALETTE.WHITE, blackColor = ATOMIX_GLASS.CONSTANTS.PALETTE.BLACK, {borderGradientAngle: borderGradientAngle, borderStop1: borderStop1, borderStop2: borderStop2, borderOpacities: borderOpacities, hoverPositions: hoverPositions, basePosition: basePosition, mx: mx, my: my, absMx: absMx, absMy: absMy} = gradientValues;
3641
+ }
3642
+ /**
3643
+ * Builds the CSS custom properties applied to the root `.c-atomix-glass` element.
3644
+ *
3645
+ * These variables drive layer geometry, transforms, and stacking offsets. They
3646
+ * must not include layout properties that would interfere with backdrop-filter.
3647
+ */ ({
3648
+ width: width,
3649
+ height: height,
3650
+ restStyle: restStyle,
3651
+ glassSize: glassSize,
3652
+ isFixedOrSticky: isFixedOrSticky
3653
+ })), [ width, height, restStyle, glassSize, isFixedOrSticky ]), glassVars = useMemo((() => function(input) {
3654
+ const {effectiveBorderRadius: effectiveBorderRadius, transformStyle: transformStyle, adjustedSize: adjustedSize, isOverLight: isOverLight, customZIndex: customZIndex, isFixedOrSticky: isFixedOrSticky, positionStyles: positionStyles, restStyle: restStyle, borderWidth: borderWidth = ATOMIX_GLASS.BORDER.DEFAULT_WIDTH} = input, layerPosition =
3655
+ /**
3656
+ * Resolves the `--atomix-glass-position` value for decorative layers.
3657
+ *
3658
+ * Fixed/sticky layers use the same positioning mode as the container; in-flow
3659
+ * layers default to the internal absolute positioning context.
3660
+ */
3661
+ function(isFixedOrSticky, positionStyles, restStyle) {
3662
+ return isFixedOrSticky ? `${function(style) {
3663
+ const {position: position, top: top, left: left, right: right, bottom: bottom, inset: inset} = style;
3664
+ return {
3665
+ ...null != position && {
3666
+ position: position
3667
+ },
3668
+ ...void 0 !== top && {
3669
+ top: top
3670
+ },
3671
+ ...void 0 !== left && {
3672
+ left: left
3673
+ },
3674
+ ...void 0 !== right && {
3675
+ right: right
3676
+ },
3677
+ ...void 0 !== bottom && {
3678
+ bottom: bottom
3679
+ },
3680
+ ...void 0 !== inset && {
3681
+ inset: inset
3682
+ }
3683
+ };
3684
+ }
3685
+ /**
3686
+ * Resolves inset custom properties for decorative layers (hover, borders, backgrounds).
3687
+ *
3688
+ * For fixed and sticky modes, insets mirror the container so sibling layers remain
3689
+ * aligned. In-flow modes, insets follow the consumer `style` when a non-default
3690
+ * `position` is provided.
3691
+ */ (restStyle).position ?? restStyle.position ?? "fixed"}` : `${positionStyles.position}`;
3692
+ }(isFixedOrSticky, positionStyles, restStyle), layerInsets = function(isFixedOrSticky, restStyle) {
3693
+ if (isFixedOrSticky) return {
3694
+ top: formatGlassInsetValue(restStyle.top, 0),
3695
+ left: formatGlassInsetValue(restStyle.left, 0),
3696
+ right: formatGlassInsetValue(restStyle.right, "auto"),
3697
+ bottom: formatGlassInsetValue(restStyle.bottom, "auto")
3698
+ };
3699
+ const position = restStyle.position;
3700
+ return null != position && "static" !== position && "relative" !== position ? {
3701
+ top: formatGlassInsetValue(restStyle.top, 0),
3702
+ left: formatGlassInsetValue(restStyle.left, 0),
3703
+ right: formatGlassInsetValue(restStyle.right, "auto"),
3704
+ bottom: formatGlassInsetValue(restStyle.bottom, "auto")
3705
+ } : {
3706
+ top: "0px",
3707
+ left: "0px",
3708
+ right: "auto",
3709
+ bottom: "auto"
3710
+ };
3711
+ }(isFixedOrSticky, restStyle);
3933
3712
  return {
3934
3713
  ...void 0 !== customZIndex && {
3935
3714
  "--atomix-glass-base-z-index": customZIndex
3936
3715
  },
3937
3716
  "--atomix-glass-radius": `${effectiveBorderRadius}px`,
3938
3717
  "--atomix-glass-transform": transformStyle || "none",
3939
- "--atomix-glass-container-position": `${isFixedOrSticky ? rootLayoutStyle.position : positionStyles.position}`,
3940
- "--atomix-glass-position": `${isFixedOrSticky ? rootLayoutStyle.position : positionStyles.position}`,
3941
- "--atomix-glass-top": `${isFixedOrSticky ? restStyle.top ?? 0 : 0}px`,
3942
- "--atomix-glass-left": `${isFixedOrSticky ? restStyle.left ?? 0 : 0}px`,
3943
- "--atomix-glass-right": isFixedOrSticky ? restStyle.right ?? "auto" : "auto",
3944
- "--atomix-glass-bottom": isFixedOrSticky ? restStyle.bottom ?? "auto" : "auto",
3718
+ "--atomix-glass-container-position": layerPosition,
3719
+ "--atomix-glass-position": layerPosition,
3720
+ "--atomix-glass-top": layerInsets.top,
3721
+ "--atomix-glass-left": layerInsets.left,
3722
+ "--atomix-glass-right": layerInsets.right,
3723
+ "--atomix-glass-bottom": layerInsets.bottom,
3945
3724
  "--atomix-glass-width": adjustedSize.width,
3946
3725
  "--atomix-glass-height": adjustedSize.height,
3947
- "--atomix-glass-border-width": "var(--atomix-spacing-0-5, 0.125rem)",
3948
- "--atomix-glass-blend-mode": isOverLight ? "multiply" : "overlay",
3949
- "--atomix-glass-border-gradient-1": `linear-gradient(${borderGradientAngle}deg, rgba(${whiteColor}, 0) 0%, rgba(${whiteColor}, ${(borderOpacities[0] ?? 1) * clampedBorderOpacity}) ${borderStop1}%, rgba(${whiteColor}, ${(borderOpacities[1] ?? 1) * clampedBorderOpacity}) ${borderStop2}%, rgba(${whiteColor}, 0) 100%)`,
3950
- "--atomix-glass-border-gradient-2": `linear-gradient(${borderGradientAngle}deg, rgba(${whiteColor}, 0) 0%, rgba(${whiteColor}, ${(borderOpacities[2] ?? 1) * clampedBorderOpacity}) ${borderStop1}%, rgba(${whiteColor}, ${(borderOpacities[3] ?? 1) * clampedBorderOpacity}) ${borderStop2}%, rgba(${whiteColor}, 0) 100%)`,
3951
- "--atomix-glass-hover-1-opacity": opacityValues.hover1,
3952
- "--atomix-glass-hover-1-gradient": isOverLight ? `radial-gradient(circle at ${hoverPositions.hover1.x}% ${hoverPositions.hover1.y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_START}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_STOP}%, rgba(${blackColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.BLACK_END}%)` : `radial-gradient(circle at ${hoverPositions.hover1.x}% ${hoverPositions.hover1.y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_1.WHITE_STOP}%)`,
3953
- "--atomix-glass-hover-2-opacity": opacityValues.hover2,
3954
- "--atomix-glass-hover-2-gradient": isOverLight ? `radial-gradient(circle at ${hoverPositions.hover2.x}% ${hoverPositions.hover2.y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_START}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_STOP}%, rgba(${blackColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.BLACK_END}%)` : `radial-gradient(circle at ${hoverPositions.hover2.x}% ${hoverPositions.hover2.y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_2.WHITE_STOP}%)`,
3955
- "--atomix-glass-hover-3-opacity": opacityValues.hover3,
3956
- "--atomix-glass-hover-3-gradient": isOverLight ? `radial-gradient(circle at ${hoverPositions.hover3.x}% ${hoverPositions.hover3.y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_START}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_STOP}%, rgba(${blackColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.BLACK_END}%)` : `radial-gradient(circle at ${hoverPositions.hover3.x}% ${hoverPositions.hover3.y}%, rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.WHITE_START}) 0%, rgba(${whiteColor}, 0) ${ATOMIX_GLASS.CONSTANTS.GRADIENT_OPACITY.HOVER_3.WHITE_STOP}%)`,
3957
- "--atomix-glass-base-opacity": opacityValues.base,
3958
- "--atomix-glass-base-gradient": isOverLight ? `linear-gradient(${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.ANGLE}deg, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_START_BASE + mx * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_START_MULTIPLIER}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_BASE + my * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_MULTIPLIER}) ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_MID_STOP}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_END_BASE + absMx * ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.BLACK_END_MULTIPLIER}) 100%)` : `rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.BASE_GRADIENT.WHITE_OPACITY})`,
3959
- "--atomix-glass-overlay-opacity": opacityValues.over,
3960
- "--atomix-glass-overlay-gradient": isOverLight ? `radial-gradient(circle at ${basePosition.x}% ${basePosition.y}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_START_BASE + absMx * ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_START_MULTIPLIER}) 0%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_MID}) ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_MID_STOP}%, rgba(${blackColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_END_BASE + absMy * ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.BLACK_END_MULTIPLIER}) 100%)` : `rgba(${whiteColor}, ${ATOMIX_GLASS.CONSTANTS.OVERLAY_GRADIENT.WHITE_OPACITY})`,
3961
- "--atomix-glass-overlay-highlight-opacity": opacityValues.over * ATOMIX_GLASS.CONSTANTS.OVERLAY_HIGHLIGHT.OPACITY_MULTIPLIER,
3962
- "--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}%)`
3726
+ // Aliases maintained for backward compatibility and consumer overrides.
3727
+ "--atomix-glass-container-width": adjustedSize.width,
3728
+ "--atomix-glass-container-height": adjustedSize.height,
3729
+ [ATOMIX_GLASS.BORDER.WIDTH_CSS_VAR]: borderWidth,
3730
+ "--atomix-glass-blend-mode": isOverLight ? "multiply" : "overlay"
3963
3731
  };
3964
- }), [ gradientValues, opacityValues, effectiveBorderRadius, transformStyle, adjustedSize, isOverLight, clampedBorderOpacity, customZIndex, isFixedOrSticky, positionStyles.position, rootLayoutStyle.position, restStyle.top, restStyle.left, restStyle.right, restStyle.bottom ]), renderBackgroundLayer = layerType => jsx("div", {
3965
- 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(" ")
3732
+ }
3733
+ /**
3734
+ * Applies mode-specific multipliers and accessibility overrides to container effects.
3735
+ */ ({
3736
+ effectiveBorderRadius: effectiveBorderRadius,
3737
+ transformStyle: transformStyle,
3738
+ adjustedSize: adjustedSize,
3739
+ isOverLight: isOverLight,
3740
+ customZIndex: customZIndex,
3741
+ isFixedOrSticky: isFixedOrSticky,
3742
+ positionStyles: positionStyles,
3743
+ restStyle: restStyle,
3744
+ borderWidth: resolvedBorder.width
3745
+ })), [ effectiveBorderRadius, transformStyle, adjustedSize, isOverLight, customZIndex, isFixedOrSticky, positionStyles, restStyle, resolvedBorder.width ]), containerEffects = useMemo((() => function(options) {
3746
+ const {MULTIPLIERS: MULTIPLIERS, SATURATION: SATURATION} = ATOMIX_GLASS.CONSTANTS, zeroMouse = {
3747
+ x: 0,
3748
+ y: 0
3749
+ }, resolveSaturation = () => options.effectiveHighContrast ? SATURATION.HIGH_CONTRAST : options.isOverLight ? options.saturation * options.saturationBoost : options.saturation;
3750
+ if (options.effectiveWithoutEffects) return {
3751
+ displacementScale: 0,
3752
+ blurAmount: 0,
3753
+ saturation: resolveSaturation(),
3754
+ aberrationIntensity: 0,
3755
+ mouseOffset: zeroMouse,
3756
+ globalMousePosition: zeroMouse
3757
+ };
3758
+ let resolvedDisplacement = options.displacementScale;
3759
+ "shader" === options.mode ? resolvedDisplacement *= MULTIPLIERS.SHADER_DISPLACEMENT : options.isOverLight && (resolvedDisplacement *= MULTIPLIERS.OVER_LIGHT_DISPLACEMENT);
3760
+ let resolvedAberration = options.aberrationIntensity;
3761
+ return "shader" === options.mode && (resolvedAberration *= MULTIPLIERS.SHADER_ABERRATION),
3762
+ {
3763
+ displacementScale: resolvedDisplacement,
3764
+ blurAmount: options.blurAmount,
3765
+ saturation: resolveSaturation(),
3766
+ aberrationIntensity: resolvedAberration,
3767
+ mouseOffset: options.mouseOffset,
3768
+ globalMousePosition: options.globalMousePosition
3769
+ };
3770
+ }({
3771
+ displacementScale: displacementScale,
3772
+ blurAmount: blurAmount,
3773
+ saturation: saturation,
3774
+ aberrationIntensity: aberrationIntensity,
3775
+ mode: mode,
3776
+ effectiveWithoutEffects: effectiveWithoutEffects,
3777
+ effectiveHighContrast: effectiveHighContrast,
3778
+ isOverLight: isOverLight,
3779
+ saturationBoost: overLightConfig.saturationBoost,
3780
+ mouseOffset: mouseOffset,
3781
+ globalMousePosition: globalMousePosition
3782
+ })), [ displacementScale, blurAmount, saturation, aberrationIntensity, mode, effectiveWithoutEffects, effectiveHighContrast, isOverLight, overLightConfig.saturationBoost, mouseOffset, globalMousePosition ]), renderBackgroundLayer = layerType => jsx("div", {
3783
+ "aria-hidden": "true",
3784
+ className: mergeClassNames(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)
3966
3785
  });
3967
- // Calculate position and size styles for internal layers
3968
- // When root is fixed/sticky, internal layers use absolute (relative to root)
3969
- return jsxs("div", {
3786
+ return jsxs("div", {
3970
3787
  ...rest,
3971
3788
  ref: mergedRef,
3972
3789
  className: componentClassName,
3973
- style: {
3974
- ...glassVars
3975
- },
3790
+ style: glassVars,
3976
3791
  role: role || (onClick ? "button" : void 0),
3977
3792
  tabIndex: onClick ? tabIndex ?? 0 : tabIndex,
3978
3793
  "aria-label": ariaLabel,
3979
3794
  "aria-describedby": ariaDescribedBy,
3980
3795
  "aria-disabled": !(!onClick || !effectiveWithoutEffects) || !onClick && void 0,
3981
- "aria-pressed": onClick ? isActive : void 0,
3982
3796
  onKeyDown: onClick ? handleKeyDown : void 0,
3983
3797
  children: [ jsx(AtomixGlassContainer, {
3984
3798
  ref: glassRef,
3985
3799
  contentRef: contentRef,
3986
3800
  className: className,
3987
- style: {
3988
- ...restStyle
3989
- },
3801
+ style: containerStyle,
3990
3802
  borderRadius: effectiveBorderRadius,
3991
- displacementScale: effectiveWithoutEffects ? 0 : "shader" === mode ? displacementScale * ATOMIX_GLASS.CONSTANTS.MULTIPLIERS.SHADER_DISPLACEMENT : isOverLight ? displacementScale * ATOMIX_GLASS.CONSTANTS.MULTIPLIERS.OVER_LIGHT_DISPLACEMENT : displacementScale,
3992
- blurAmount: effectiveWithoutEffects ? 0 : blurAmount,
3993
- saturation: effectiveHighContrast ? ATOMIX_GLASS.CONSTANTS.SATURATION.HIGH_CONTRAST : isOverLight ? saturation * overLightConfig.saturationBoost : saturation,
3994
- aberrationIntensity: effectiveWithoutEffects ? 0 : "shader" === mode ? aberrationIntensity * ATOMIX_GLASS.CONSTANTS.MULTIPLIERS.SHADER_ABERRATION : aberrationIntensity,
3803
+ displacementScale: containerEffects.displacementScale,
3804
+ blurAmount: containerEffects.blurAmount,
3805
+ saturation: containerEffects.saturation,
3806
+ aberrationIntensity: containerEffects.aberrationIntensity,
3995
3807
  glassSize: glassSize,
3996
- padding: padding,
3997
- mouseOffset: effectiveWithoutEffects ? {
3998
- x: 0,
3999
- y: 0
4000
- } : mouseOffset,
4001
- globalMousePosition: effectiveWithoutEffects ? {
4002
- x: 0,
4003
- y: 0
4004
- } : globalMousePosition,
3808
+ mouseOffset: containerEffects.mouseOffset,
3809
+ globalMousePosition: containerEffects.globalMousePosition,
4005
3810
  onMouseEnter: handleMouseEnter,
4006
3811
  onMouseLeave: handleMouseLeave,
4007
3812
  onMouseDown: handleMouseDown,
4008
3813
  onMouseUp: handleMouseUp,
4009
- isHovered: isHovered,
4010
3814
  isActive: isActive,
4011
3815
  overLight: isOverLight,
4012
3816
  overLightConfig: {
@@ -4022,8 +3826,6 @@ const PERFORMANCE_PRESET = {
4022
3826
  shaderVariant: shaderVariant,
4023
3827
  withLiquidBlur: withLiquidBlur,
4024
3828
  isFixedOrSticky: isFixedOrSticky,
4025
- // Phase 1: Animation System props
4026
- shaderTime: getShaderTime(),
4027
3829
  withTimeAnimation: withTimeAnimation,
4028
3830
  animationSpeed: animationSpeed,
4029
3831
  withMultiLayerDistortion: withMultiLayerDistortion,
@@ -4034,32 +3836,39 @@ const PERFORMANCE_PRESET = {
4034
3836
  children: children
4035
3837
  }), Boolean(onClick) && jsxs(Fragment, {
4036
3838
  children: [ jsx("div", {
3839
+ "aria-hidden": "true",
4037
3840
  className: ATOMIX_GLASS.HOVER_1_CLASS
4038
3841
  }), jsx("div", {
3842
+ "aria-hidden": "true",
4039
3843
  className: ATOMIX_GLASS.HOVER_2_CLASS
4040
3844
  }), jsx("div", {
3845
+ "aria-hidden": "true",
4041
3846
  className: ATOMIX_GLASS.HOVER_3_CLASS
4042
3847
  }) ]
4043
- }), renderBackgroundLayer("dark"), renderBackgroundLayer("black"), shouldRenderOverLightLayers && jsxs(Fragment, {
3848
+ }), [ "dark", "black" ].map((layerType => jsx(React.Fragment, {
3849
+ children: renderBackgroundLayer(layerType)
3850
+ }, layerType))), shouldRenderOverLightLayers && jsxs(Fragment, {
4044
3851
  children: [ jsx("div", {
3852
+ "aria-hidden": "true",
4045
3853
  className: ATOMIX_GLASS.BASE_LAYER_CLASS
4046
3854
  }), jsx("div", {
3855
+ "aria-hidden": "true",
4047
3856
  className: ATOMIX_GLASS.OVERLAY_LAYER_CLASS
4048
3857
  }), jsx("div", {
3858
+ "aria-hidden": "true",
4049
3859
  className: ATOMIX_GLASS.OVERLAY_HIGHLIGHT_CLASS
4050
3860
  }) ]
4051
- }), withBorder && jsxs(Fragment, {
3861
+ }), resolvedBorder.enabled && jsxs(Fragment, {
4052
3862
  children: [ jsx("span", {
3863
+ "aria-hidden": "true",
4053
3864
  className: ATOMIX_GLASS.BORDER_BACKDROP_CLASS
4054
3865
  }), jsx("span", {
3866
+ "aria-hidden": "true",
4055
3867
  className: ATOMIX_GLASS.BORDER_1_CLASS
4056
3868
  }), jsx("span", {
3869
+ "aria-hidden": "true",
4057
3870
  className: ATOMIX_GLASS.BORDER_2_CLASS
4058
3871
  }) ]
4059
- }), debugPerformance && performanceMetrics && jsx(PerformanceDashboard, {
4060
- metrics: performanceMetrics,
4061
- isVisible: !0,
4062
- onClose: () => {}
4063
3872
  }) ]
4064
3873
  });
4065
3874
  }));
@@ -4069,10 +3878,7 @@ const PERFORMANCE_PRESET = {
4069
3878
  * Default preset for most mobile devices
4070
3879
  */ AtomixGlassInner.displayName = "AtomixGlass";
4071
3880
 
4072
- /**
4073
- * AtomixGlass - wrapped with React.memo to prevent unnecessary re-renders.
4074
- * Ref is forwarded to the root `<div>` element.
4075
- */
3881
+ /** Memoized public export. Ref targets the root `.c-atomix-glass` wrapper. */
4076
3882
  const AtomixGlass = memo(AtomixGlassInner), ChartContext = createContext(null), Chart = memo( forwardRef((({children: children, type: type = "line", size: size = "md", variant: variant = "primary", title: title, subtitle: subtitle, loading: loading = !1, error: error, className: className = "", "aria-label": ariaLabel, onFullscreen: onFullscreen, onExport: onExport, onRefresh: onRefresh, showToolbar: showToolbar = !1, enableFullscreen: enableFullscreen = !1, enableExport: enableExport = !1, enableRefresh: enableRefresh = !1, exportFormats: exportFormats = [ "png", "svg", "csv" ], datasets: datasets, config: config,
4077
3883
  // Destructure non-DOM props to prevent passing to DOM element
4078
3884
  toolbarConfig: toolbarConfig, customToolbarActions: customToolbarActions, customToolbarGroups: customToolbarGroups, data: data, showLegend: showLegend, interactive: interactive, fullscreen: fullscreen, onDataPointClick: onDataPointClick, onLegendItemClick: onLegendItemClick, glass: glass, ...props}, ref) => {
@@ -7388,40 +7194,15 @@ WaterfallChart.displayName = "WaterfallChart";
7388
7194
 
7389
7195
  // Adapted from https://github.com/shuding/liquid-glass
7390
7196
  // Constants
7391
- const smoothStep = (a, b, t) => {
7392
- // Add input validation
7393
- if ("number" != typeof a || "number" != typeof b || "number" != typeof t) return 0;
7394
- const clamped = Math.max(0, Math.min(1, (t - a) / (b - a)));
7395
- return clamped * clamped * (3 - 2 * clamped);
7396
- }, calculateLength = (x, y) => {
7397
- // Add input validation and error handling
7398
- if ("number" != typeof x || "number" != typeof y || isNaN(x) || isNaN(y)) return 0;
7399
- // Prevent potential overflow
7400
- const maxX = Math.max(Math.abs(x), Math.abs(y));
7401
- if (0 === maxX) return 0;
7402
- const scaledX = x / maxX, scaledY = y / maxX;
7403
- return maxX * Math.sqrt(scaledX * scaledX + scaledY * scaledY);
7404
- }, roundedRectSDF = (x, y, width, height, radius) => {
7197
+ const roundedRectSDF = (x, y, width, height, radius) => {
7405
7198
  // Add input validation
7406
7199
  if ("number" != typeof x || "number" != typeof y || "number" != typeof width || "number" != typeof height || "number" != typeof radius) return 0;
7407
7200
  const qx = Math.abs(x) - width + radius, qy = Math.abs(y) - height + radius;
7408
- return Math.min(Math.max(qx, qy), 0) + calculateLength(Math.max(qx, 0), Math.max(qy, 0)) - radius;
7201
+ return Math.min(Math.max(qx, qy), 0) + vec2Length(Math.max(qx, 0), Math.max(qy, 0)) - radius;
7409
7202
  }, createTexture = (x, y) => ({
7410
7203
  x: "number" != typeof x || isNaN(x) ? .5 : Math.max(0, Math.min(1, x)),
7411
7204
  y: "number" != typeof y || isNaN(y) ? .5 : Math.max(0, Math.min(1, y))
7412
- }), validateVec2 = vec => vec && "number" == typeof vec.x && "number" == typeof vec.y && !isNaN(vec.x) && !isNaN(vec.y), clampValue = (value, min, max) =>
7413
- // Add input validation
7414
- "number" != typeof value || "number" != typeof min || "number" != typeof max || isNaN(value) ? min : isNaN(min) ? 0 : isNaN(max) ? 1 : Math.max(min, Math.min(max, value)), easeInOutCubic = t => {
7415
- // Add input validation
7416
- if ("number" != typeof t || isNaN(t)) return 0;
7417
- const clampedT = Math.max(0, Math.min(1, t));
7418
- return clampedT < .5 ? 4 * clampedT * clampedT * clampedT : 1 - Math.pow(-2 * clampedT + 2, 3) / 2;
7419
- }, easeOutQuart = t => {
7420
- // Add input validation
7421
- if ("number" != typeof t || isNaN(t)) return 0;
7422
- const clampedT = Math.max(0, Math.min(1, t));
7423
- return 1 - Math.pow(1 - clampedT, 4);
7424
- }, noise2D = (x, y) => {
7205
+ }), validateVec2 = vec => vec && "number" == typeof vec.x && "number" == typeof vec.y && !isNaN(vec.x) && !isNaN(vec.y), noise2D = (x, y) => {
7425
7206
  // Add input validation
7426
7207
  if ("number" != typeof x || "number" != typeof y || isNaN(x) || isNaN(y)) return 0;
7427
7208
  const X = 255 & Math.floor(x), Y = 255 & Math.floor(y), xf = x - Math.floor(x), yf = y - Math.floor(y), u = easeInOutCubic(xf), v = easeInOutCubic(yf), hash = (i, j) => {
@@ -7460,13 +7241,13 @@ const smoothStep = (a, b, t) => {
7460
7241
  x: .5,
7461
7242
  y: .5
7462
7243
  };
7463
- const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now(), mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, mouseDistance = calculateLength(mouseX, mouseY), mouseFalloff = easeOutQuart(1 - Math.min(2 * mouseDistance, 1)), organicFlow = fbm(12 * (ix + .5 * mouseX) + time, 12 * (iy + .5 * mouseY) + .7 * time, 3) - .5, distanceToEdge = roundedRectSDF(ix, iy, .4, .3, .35), baseDisplacement = smoothStep(.8, 0, distanceToEdge - .05), radialDist = ((x, y, strength) => {
7244
+ const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now(), mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, mouseDistance = vec2Length(mouseX, mouseY), mouseFalloff = easeOutQuart(1 - Math.min(2 * mouseDistance, 1)), organicFlow = fbm(12 * (ix + .5 * mouseX) + time, 12 * (iy + .5 * mouseY) + .7 * time, 3) - .5, distanceToEdge = roundedRectSDF(ix, iy, .4, .3, .35), baseDisplacement = smoothstepEdge(.8, 0, distanceToEdge - .05), radialDist = ((x, y, strength) => {
7464
7245
  // Add input validation
7465
7246
  if ("number" != typeof x || "number" != typeof y || isNaN(x) || isNaN(y) || isNaN(strength)) return {
7466
7247
  x: 0,
7467
7248
  y: 0
7468
7249
  };
7469
- const distance = calculateLength(x, y), distortion = Math.pow(Math.min(distance, 10), 2) * strength;
7250
+ const distance = vec2Length(x, y), distortion = Math.pow(Math.min(distance, 10), 2) * strength;
7470
7251
  // Limit distance to prevent extreme values
7471
7252
  return {
7472
7253
  x: x * (1 + distortion),
@@ -7478,7 +7259,7 @@ const smoothStep = (a, b, t) => {
7478
7259
  x: 0,
7479
7260
  y: 0
7480
7261
  };
7481
- const distance = calculateLength(x, y);
7262
+ const distance = vec2Length(x, y);
7482
7263
  // Prevent division by zero and extreme values
7483
7264
  if (0 === distance) return {
7484
7265
  x: 0,
@@ -7489,8 +7270,8 @@ const smoothStep = (a, b, t) => {
7489
7270
  x: Math.cos(angle) * distance * intensity,
7490
7271
  y: Math.sin(angle) * distance * intensity
7491
7272
  };
7492
- })(ix, iy, .015 * baseDisplacement), scaled = smoothStep(0, 1, 1.15 * baseDisplacement), finalX = ix + totalDistortionX + .5 * chromaticOffset.x, finalY = iy + totalDistortionY + .5 * chromaticOffset.y;
7493
- return createTexture(clampValue(finalX * scaled + .5, 0, 1), clampValue(finalY * scaled + .5, 0, 1));
7273
+ })(ix, iy, .015 * baseDisplacement), scaled = smoothstepEdge(0, 1, 1.15 * baseDisplacement), finalX = ix + totalDistortionX + .5 * chromaticOffset.x, finalY = iy + totalDistortionY + .5 * chromaticOffset.y;
7274
+ return createTexture(clamp(finalX * scaled + .5, 0, 1), clamp(finalY * scaled + .5, 0, 1));
7494
7275
  },
7495
7276
  // Premium Apple-style fluid glass with enhanced organic flow
7496
7277
  appleFluid: (uv, mousePosition) => {
@@ -7498,8 +7279,8 @@ const smoothStep = (a, b, t) => {
7498
7279
  x: .5,
7499
7280
  y: .5
7500
7281
  };
7501
- const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now() * .6, mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, mouseDistance = calculateLength(mouseX, mouseY), mouseFalloff = easeOutQuart(1 - Math.min(1.5 * mouseDistance, 1)), organicX = fbm(10 * (ix + .3 * mouseX) + time, 10 * (iy + .3 * mouseY), 5) - .5, organicY = fbm(10 * (ix - .3 * mouseX), 10 * (iy - .3 * mouseY) + .8 * time, 5) - .5, distanceToEdge = roundedRectSDF(ix, iy, .42, .32, .38), mask = smoothStep(.85, -.1, distanceToEdge), fluidVelocityX = Math.sin(6 * ix + 2 * time) * Math.cos(4 * iy - time) * .025, fluidVelocityY = Math.cos(4 * ix - time) * Math.sin(6 * iy + 2 * time) * .025, vortexAngle = Math.atan2(iy - mouseY, ix - mouseX), vortexStrength = mouseFalloff * mouseDistance * .08, vortexX = Math.cos(vortexAngle + time) * vortexStrength, totalY = iy + (.035 * organicY + fluidVelocityY + Math.sin(vortexAngle + time) * vortexStrength) * mask;
7502
- return createTexture(clampValue(ix + (.035 * organicX + fluidVelocityX + vortexX) * mask + .5, 0, 1), clampValue(totalY + .5, 0, 1));
7282
+ const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now() * .6, mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, mouseDistance = vec2Length(mouseX, mouseY), mouseFalloff = easeOutQuart(1 - Math.min(1.5 * mouseDistance, 1)), organicX = fbm(10 * (ix + .3 * mouseX) + time, 10 * (iy + .3 * mouseY), 5) - .5, organicY = fbm(10 * (ix - .3 * mouseX), 10 * (iy - .3 * mouseY) + .8 * time, 5) - .5, distanceToEdge = roundedRectSDF(ix, iy, .42, .32, .38), mask = smoothstepEdge(.85, -.1, distanceToEdge), fluidVelocityX = Math.sin(6 * ix + 2 * time) * Math.cos(4 * iy - time) * .025, fluidVelocityY = Math.cos(4 * ix - time) * Math.sin(6 * iy + 2 * time) * .025, vortexAngle = Math.atan2(iy - mouseY, ix - mouseX), vortexStrength = mouseFalloff * mouseDistance * .08, vortexX = Math.cos(vortexAngle + time) * vortexStrength, totalY = iy + (.035 * organicY + fluidVelocityY + Math.sin(vortexAngle + time) * vortexStrength) * mask;
7283
+ return createTexture(clamp(ix + (.035 * organicX + fluidVelocityX + vortexX) * mask + .5, 0, 1), clamp(totalY + .5, 0, 1));
7503
7284
  },
7504
7285
  // High-end glass with advanced refraction and depth
7505
7286
  premiumGlass: (uv, mousePosition) => {
@@ -7507,7 +7288,7 @@ const smoothStep = (a, b, t) => {
7507
7288
  x: .5,
7508
7289
  y: .5
7509
7290
  };
7510
- const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now() * .4, mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, mouseDistance = calculateLength(mouseX, mouseY), centerDistance = calculateLength(ix, iy), refractionStrength = .3 * Math.pow(Math.min(centerDistance, 1), 1.5), refractionAngle = Math.atan2(iy, ix);
7291
+ const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now() * .4, mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, mouseDistance = vec2Length(mouseX, mouseY), centerDistance = vec2Length(ix, iy), refractionStrength = .3 * Math.pow(Math.min(centerDistance, 1), 1.5), refractionAngle = Math.atan2(iy, ix);
7511
7292
  // Multi-layer depth effect
7512
7293
  let depthX = 0, depthY = 0;
7513
7294
  for (let layer = 0; layer < 3; layer++) {
@@ -7515,8 +7296,8 @@ const smoothStep = (a, b, t) => {
7515
7296
  depthX += Math.sin(ix * layerScale + layerTime) * layerStrength, depthY += Math.cos(iy * layerScale - layerTime) * layerStrength;
7516
7297
  }
7517
7298
  // Glass refraction with mouse influence
7518
- const refractionX = Math.cos(refractionAngle) * refractionStrength * (1 + .5 * mouseDistance), refractionY = Math.sin(refractionAngle) * refractionStrength * (1 + .5 * mouseDistance), organicNoise = fbm(8 * ix + time, 8 * iy - time, 2) - .5, distanceToEdge = roundedRectSDF(ix, iy, .43, .33, .36), edgeMask = smoothStep(.9, -.05, distanceToEdge), finalY = iy + (refractionY + depthY + .015 * organicNoise) * edgeMask;
7519
- return createTexture(clampValue(ix + (refractionX + depthX + .015 * organicNoise) * edgeMask + .5, 0, 1), clampValue(finalY + .5, 0, 1));
7299
+ const refractionX = Math.cos(refractionAngle) * refractionStrength * (1 + .5 * mouseDistance), refractionY = Math.sin(refractionAngle) * refractionStrength * (1 + .5 * mouseDistance), organicNoise = fbm(8 * ix + time, 8 * iy - time, 2) - .5, distanceToEdge = roundedRectSDF(ix, iy, .43, .33, .36), edgeMask = smoothstepEdge(.9, -.05, distanceToEdge), finalY = iy + (refractionY + depthY + .015 * organicNoise) * edgeMask;
7300
+ return createTexture(clamp(ix + (refractionX + depthX + .015 * organicNoise) * edgeMask + .5, 0, 1), clamp(finalY + .5, 0, 1));
7520
7301
  },
7521
7302
  // Metallic liquid effect with shimmer
7522
7303
  liquidMetal: (uv, mousePosition) => {
@@ -7524,8 +7305,8 @@ const smoothStep = (a, b, t) => {
7524
7305
  x: .5,
7525
7306
  y: .5
7526
7307
  };
7527
- const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now() * 1.2, mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, wave1 = Math.sin(20 * ix + 4 * time) * Math.cos(15 * iy - 3 * time) * .02, wave2 = Math.cos(15 * ix - 2 * time) * Math.sin(20 * iy + 5 * time) * .015, shimmer = .025 * fbm(25 * ix + 2 * time, 25 * iy - 2 * time, 4), flowAngle = Math.atan2(iy - mouseY, ix - mouseX), flowDistance = calculateLength(ix - mouseX, iy - mouseY), flowEffect = .02 * Math.sin(15 * flowDistance - 6 * time) * easeOutQuart(1 - Math.min(2 * flowDistance, 1)), distanceToEdge = roundedRectSDF(ix, iy, .41, .31, .37), mask = smoothStep(.88, -.08, distanceToEdge), totalX = ix + (wave1 + shimmer + Math.cos(flowAngle) * flowEffect) * mask, totalY = iy + (wave2 + .8 * shimmer + Math.sin(flowAngle) * flowEffect) * mask;
7528
- return createTexture(clampValue(totalX + .5, 0, 1), clampValue(totalY + .5, 0, 1));
7308
+ const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now() * 1.2, mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, wave1 = Math.sin(20 * ix + 4 * time) * Math.cos(15 * iy - 3 * time) * .02, wave2 = Math.cos(15 * ix - 2 * time) * Math.sin(20 * iy + 5 * time) * .015, shimmer = .025 * fbm(25 * ix + 2 * time, 25 * iy - 2 * time, 4), flowAngle = Math.atan2(iy - mouseY, ix - mouseX), flowDistance = vec2Length(ix - mouseX, iy - mouseY), flowEffect = .02 * Math.sin(15 * flowDistance - 6 * time) * easeOutQuart(1 - Math.min(2 * flowDistance, 1)), distanceToEdge = roundedRectSDF(ix, iy, .41, .31, .37), mask = smoothstepEdge(.88, -.08, distanceToEdge), totalX = ix + (wave1 + shimmer + Math.cos(flowAngle) * flowEffect) * mask, totalY = iy + (wave2 + .8 * shimmer + Math.sin(flowAngle) * flowEffect) * mask;
7309
+ return createTexture(clamp(totalX + .5, 0, 1), clamp(totalY + .5, 0, 1));
7529
7310
  },
7530
7311
  // basiBasi - Expert Premium Glass Shader
7531
7312
  // The most advanced shader with caustics, spectral dispersion, parallax depth, and volumetric effects
@@ -7534,7 +7315,7 @@ const smoothStep = (a, b, t) => {
7534
7315
  x: .5,
7535
7316
  y: .5
7536
7317
  };
7537
- const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now() * .5, mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, mouseDistance = calculateLength(mouseX, mouseY), mouseFalloff = easeOutQuart(1 - Math.min(1.2 * mouseDistance, 1)), causticIntensity = ((x, y, time, intensity = 1) =>
7318
+ const ix = uv.x - .5, iy = uv.y - .5, time = 8e-4 * Date.now() * .5, mouseX = mousePosition && validateVec2(mousePosition) ? mousePosition.x - .5 : 0, mouseY = mousePosition && validateVec2(mousePosition) ? mousePosition.y - .5 : 0, mouseDistance = vec2Length(mouseX, mouseY), mouseFalloff = easeOutQuart(1 - Math.min(1.2 * mouseDistance, 1)), causticIntensity = ((x, y, time, intensity = 1) =>
7538
7319
  // Add input validation
7539
7320
  "number" != typeof x || "number" != typeof y || "number" != typeof time || "number" != typeof intensity || isNaN(x) || isNaN(y) || isNaN(time) || isNaN(intensity) ? .5 : .5 * (Math.sin(8 * x + 2 * time) * Math.cos(8 * y - 2 * time) * .5 + Math.sin(8 * (x + .5) * 1.3 - 2 * time * .8) * Math.cos(8 * (y - .3) * 1.3 + 2 * time * .8) * .3 + Math.sin(8 * (x - .3) * .7 + 2 * time * 1.2) * Math.cos(8 * (y + .4) * .7 - 2 * time * 1.2) * .2 + 1) * intensity)(ix, iy, time, .8), causticDistortion = .02 * (causticIntensity - .5), refractionAngle = Math.atan2(iy, ix), spectralDispersion = ((x, y, angle) => {
7540
7321
  // Add input validation
@@ -7552,7 +7333,7 @@ const smoothStep = (a, b, t) => {
7552
7333
  y: 0
7553
7334
  }
7554
7335
  };
7555
- const distance = calculateLength(x, y), dispersionStrength = Math.min(.025 * distance, 1), redOffset = .8 * dispersionStrength, greenOffset = 1 * dispersionStrength, blueOffset = 1.2 * dispersionStrength;
7336
+ const distance = vec2Length(x, y), dispersionStrength = Math.min(.025 * distance, 1), redOffset = .8 * dispersionStrength, greenOffset = 1 * dispersionStrength, blueOffset = 1.2 * dispersionStrength;
7556
7337
  return {
7557
7338
  r: {
7558
7339
  x: Math.cos(angle) * redOffset,
@@ -7592,8 +7373,8 @@ const smoothStep = (a, b, t) => {
7592
7373
  return turbulence;
7593
7374
  })(6 * ix, 6 * iy, time, 6), turbulenceX = .012 * Math.cos(turbulence * Math.PI * 2), turbulenceY = .012 * Math.sin(turbulence * Math.PI * 2), microSurface = ((x, y, time) =>
7594
7375
  // Add input validation
7595
- "number" != typeof x || "number" != typeof y || "number" != typeof time || isNaN(x) || isNaN(y) || isNaN(time) ? .5 : .5 * (.7 * fbm(40 * x + .3 * time, 40 * y - .3 * time, 6) + .3 * fbm(80 * x, 80 * y, 4)))(ix, iy, time), microDetailX = .008 * (microSurface - .5), microDetailY = .008 * (microSurface - .5), centerDistance = calculateLength(ix, iy), dynamicRefraction = .35 * Math.pow(Math.min(centerDistance, 1), 1.8) * (1 + mouseFalloff * mouseDistance * .8), refractionX = Math.cos(refractionAngle) * dynamicRefraction, refractionY = Math.sin(refractionAngle) * dynamicRefraction, vortexAngle = Math.atan2(iy - mouseY, ix - mouseX), vortexDistance = calculateLength(ix - mouseX, iy - mouseY), vortexStrength = mouseFalloff * Math.sin(10 * vortexDistance - 3 * time) * .025, vortexX = Math.cos(vortexAngle + 2 * time) * vortexStrength, vortexY = Math.sin(vortexAngle + 2 * time) * vortexStrength, fluidX = Math.sin(10 * ix + 5 * mouseX + 2.5 * time) * Math.cos(8 * iy - 2 * time) * .018, fluidY = Math.cos(8 * ix - 2 * time) * Math.sin(10 * iy + 5 * mouseY + 2.5 * time) * .018, rippleEffect = (.012 * Math.sin(15 * Math.min(centerDistance, 10) - 4 * time) + .008 * Math.cos(20 * Math.min(centerDistance, 10) + 3 * time)) * mouseFalloff, rippleX = Math.cos(refractionAngle) * rippleEffect, rippleY = Math.sin(refractionAngle) * rippleEffect, distanceToEdge = roundedRectSDF(ix, iy, .44, .34, .39), edgeMask = smoothStep(.92, -.12, distanceToEdge), edgeSoftness = smoothStep(.85, .1, distanceToEdge), finalY = iy + (1.2 * refractionY + .8 * spectralY + 1.5 * parallaxY + .9 * scatteringY + 1 * turbulenceY + .6 * microDetailY + 1.3 * vortexY + 1.1 * fluidY + .7 * rippleY + .8 * causticDistortion) * edgeMask * edgeSoftness * .85;
7596
- return createTexture(clampValue(ix + (1.2 * refractionX + .8 * spectralX + 1.5 * parallaxX + .9 * scatteringX + 1 * turbulenceX + .6 * microDetailX + 1.3 * vortexX + 1.1 * fluidX + .7 * rippleX + causticDistortion) * edgeMask * edgeSoftness * .85 + .5, 0, 1), clampValue(finalY + .5, 0, 1));
7376
+ "number" != typeof x || "number" != typeof y || "number" != typeof time || isNaN(x) || isNaN(y) || isNaN(time) ? .5 : .5 * (.7 * fbm(40 * x + .3 * time, 40 * y - .3 * time, 6) + .3 * fbm(80 * x, 80 * y, 4)))(ix, iy, time), microDetailX = .008 * (microSurface - .5), microDetailY = .008 * (microSurface - .5), centerDistance = vec2Length(ix, iy), dynamicRefraction = .35 * Math.pow(Math.min(centerDistance, 1), 1.8) * (1 + mouseFalloff * mouseDistance * .8), refractionX = Math.cos(refractionAngle) * dynamicRefraction, refractionY = Math.sin(refractionAngle) * dynamicRefraction, vortexAngle = Math.atan2(iy - mouseY, ix - mouseX), vortexDistance = vec2Length(ix - mouseX, iy - mouseY), vortexStrength = mouseFalloff * Math.sin(10 * vortexDistance - 3 * time) * .025, vortexX = Math.cos(vortexAngle + 2 * time) * vortexStrength, vortexY = Math.sin(vortexAngle + 2 * time) * vortexStrength, fluidX = Math.sin(10 * ix + 5 * mouseX + 2.5 * time) * Math.cos(8 * iy - 2 * time) * .018, fluidY = Math.cos(8 * ix - 2 * time) * Math.sin(10 * iy + 5 * mouseY + 2.5 * time) * .018, rippleEffect = (.012 * Math.sin(15 * Math.min(centerDistance, 10) - 4 * time) + .008 * Math.cos(20 * Math.min(centerDistance, 10) + 3 * time)) * mouseFalloff, rippleX = Math.cos(refractionAngle) * rippleEffect, rippleY = Math.sin(refractionAngle) * rippleEffect, distanceToEdge = roundedRectSDF(ix, iy, .44, .34, .39), edgeMask = smoothstepEdge(.92, -.12, distanceToEdge), edgeSoftness = smoothstepEdge(.85, .1, distanceToEdge), finalY = iy + (1.2 * refractionY + .8 * spectralY + 1.5 * parallaxY + .9 * scatteringY + 1 * turbulenceY + .6 * microDetailY + 1.3 * vortexY + 1.1 * fluidY + .7 * rippleY + .8 * causticDistortion) * edgeMask * edgeSoftness * .85;
7377
+ return createTexture(clamp(ix + (1.2 * refractionX + .8 * spectralX + 1.5 * parallaxX + .9 * scatteringX + 1 * turbulenceX + .6 * microDetailX + 1.3 * vortexX + 1.1 * fluidX + .7 * rippleX + causticDistortion) * edgeMask * edgeSoftness * .85 + .5, 0, 1), clamp(finalY + .5, 0, 1));
7597
7378
  },
7598
7379
  // Aliases for compatibility
7599
7380
  plasma: (uv, mousePosition) => fragmentShaders.premiumGlass(uv, mousePosition),
@@ -7635,8 +7416,8 @@ const smoothStep = (a, b, t) => {
7635
7416
  let dx = pos.x * w - x, dy = pos.y * h - y;
7636
7417
  // Apply edge smoothing for Apple-like effect
7637
7418
  const edgeX = 2 * Math.min(x / w, (w - x) / w), edgeY = 2 * Math.min(y / h, (h - y) / h), edgeFactor = Math.min(edgeX, edgeY);
7638
- dx *= smoothStep(0, .2, edgeFactor), dy *= smoothStep(0, .2, edgeFactor), maxScale = Math.max(maxScale, Math.abs(dx), Math.abs(dy)),
7639
- rawValues.push(dx, dy);
7419
+ dx *= smoothstepEdge(0, .2, edgeFactor), dy *= smoothstepEdge(0, .2, edgeFactor),
7420
+ maxScale = Math.max(maxScale, Math.abs(dx), Math.abs(dy)), rawValues.push(dx, dy);
7640
7421
  }
7641
7422
  // Improved normalization to prevent artifacts while maintaining intensity
7642
7423
  maxScale = Math.max(maxScale, 1);
@@ -7646,9 +7427,9 @@ const smoothStep = (a, b, t) => {
7646
7427
  let rawIndex = 0;
7647
7428
  for (let y = 0; y < h; y++) for (let x = 0; x < w; x++) {
7648
7429
  const dx = rawValues[rawIndex++] || 0, dy = rawValues[rawIndex++] || 0, edgeDistance = Math.min(x, y, w - x - 1, h - y - 1), edgeFactor = Math.min(1, edgeDistance / 2), r = dx * edgeFactor / maxScale + .5, g = dy * edgeFactor / maxScale + .5, pixelIndex = 4 * (y * w + x);
7649
- data[pixelIndex] = clampValue(255 * r, 0, 255), // Red channel (X displacement)
7650
- data[pixelIndex + 1] = clampValue(255 * g, 0, 255), // Green channel (Y displacement)
7651
- data[pixelIndex + 2] = clampValue(255 * g, 0, 255), // Blue channel (Y displacement for SVG filter compatibility)
7430
+ data[pixelIndex] = clamp(255 * r, 0, 255), // Red channel (X displacement)
7431
+ data[pixelIndex + 1] = clamp(255 * g, 0, 255), // Green channel (Y displacement)
7432
+ data[pixelIndex + 2] = clamp(255 * g, 0, 255), // Blue channel (Y displacement for SVG filter compatibility)
7652
7433
  data[pixelIndex + 3] = 255;
7653
7434
  }
7654
7435
  return this.context.putImageData(imageData, 0, 0), this.canvas.toDataURL();
@@ -7676,9 +7457,7 @@ const smoothStep = (a, b, t) => {
7676
7457
  return this.canvasDPI;
7677
7458
  }
7678
7459
  },
7679
- createFBMEngine: createFBMEngine,
7680
- fragmentShaders: fragmentShaders,
7681
- liquidGlassWithTime: liquidGlassWithTime
7460
+ fragmentShaders: fragmentShaders
7682
7461
  }, Symbol.toStringTag, {
7683
7462
  value: "Module"
7684
7463
  }));