@shohojdhara/atomix 0.4.7 → 0.4.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. package/atomix.config.ts +58 -1
  2. package/dist/atomix.css +172 -157
  3. package/dist/atomix.css.map +1 -1
  4. package/dist/atomix.min.css +4 -4
  5. package/dist/atomix.min.css.map +1 -1
  6. package/dist/charts.d.ts +33 -0
  7. package/dist/charts.js +1274 -164
  8. package/dist/charts.js.map +1 -1
  9. package/dist/core.d.ts +33 -10
  10. package/dist/core.js +1099 -83
  11. package/dist/core.js.map +1 -1
  12. package/dist/forms.d.ts +33 -0
  13. package/dist/forms.js +2106 -1050
  14. package/dist/forms.js.map +1 -1
  15. package/dist/heavy.d.ts +42 -1
  16. package/dist/heavy.js +1663 -638
  17. package/dist/heavy.js.map +1 -1
  18. package/dist/index.d.ts +442 -270
  19. package/dist/index.esm.js +1947 -680
  20. package/dist/index.esm.js.map +1 -1
  21. package/dist/index.js +1982 -712
  22. package/dist/index.js.map +1 -1
  23. package/dist/index.min.js +1 -1
  24. package/dist/index.min.js.map +1 -1
  25. package/package.json +6 -3
  26. package/scripts/atomix-cli.js +136 -1827
  27. package/scripts/cli/__tests__/basic.test.js +3 -2
  28. package/scripts/cli/__tests__/clean.test.js +278 -0
  29. package/scripts/cli/__tests__/component-validator.test.js +433 -0
  30. package/scripts/cli/__tests__/generator.test.js +613 -0
  31. package/scripts/cli/__tests__/glass-motion.test.js +256 -0
  32. package/scripts/cli/__tests__/integration.test.js +719 -108
  33. package/scripts/cli/__tests__/migrate.test.js +74 -0
  34. package/scripts/cli/__tests__/security.test.js +206 -0
  35. package/scripts/cli/__tests__/test-setup.js +3 -1
  36. package/scripts/cli/__tests__/theme-bridge.test.js +507 -0
  37. package/scripts/cli/__tests__/token-provider.test.js +361 -0
  38. package/scripts/cli/__tests__/utils.test.js +5 -5
  39. package/scripts/cli/commands/benchmark.js +105 -0
  40. package/scripts/cli/commands/build-theme.js +115 -0
  41. package/scripts/cli/commands/clean.js +109 -0
  42. package/scripts/cli/commands/doctor.js +88 -0
  43. package/scripts/cli/commands/generate.js +218 -0
  44. package/scripts/cli/commands/init.js +73 -0
  45. package/scripts/cli/commands/migrate.js +106 -0
  46. package/scripts/cli/commands/sync-tokens.js +206 -0
  47. package/scripts/cli/commands/theme-bridge.js +248 -0
  48. package/scripts/cli/commands/tokens.js +157 -0
  49. package/scripts/cli/commands/validate.js +194 -0
  50. package/scripts/cli/internal/ai-engine.js +156 -0
  51. package/scripts/cli/internal/compiler.js +114 -0
  52. package/scripts/cli/internal/component-validator.js +443 -0
  53. package/scripts/cli/internal/config-loader.js +162 -0
  54. package/scripts/cli/internal/filesystem.js +158 -0
  55. package/scripts/cli/internal/generator.js +430 -0
  56. package/scripts/cli/internal/glass-generator.js +398 -0
  57. package/scripts/cli/internal/hook-generator.js +369 -0
  58. package/scripts/cli/internal/hooks.js +61 -0
  59. package/scripts/cli/internal/itcss-generator.js +565 -0
  60. package/scripts/cli/internal/motion-generator.js +679 -0
  61. package/scripts/cli/internal/template-engine.js +301 -0
  62. package/scripts/cli/internal/theme-bridge.js +664 -0
  63. package/scripts/cli/internal/tokens/engine.js +122 -0
  64. package/scripts/cli/internal/tokens/provider.js +34 -0
  65. package/scripts/cli/internal/tokens/providers/figma.js +50 -0
  66. package/scripts/cli/internal/tokens/providers/style-dictionary.js +48 -0
  67. package/scripts/cli/internal/tokens/providers/w3c.js +48 -0
  68. package/scripts/cli/internal/tokens/token-provider.js +443 -0
  69. package/scripts/cli/internal/tokens/token-validator.js +513 -0
  70. package/scripts/cli/internal/validator.js +276 -0
  71. package/scripts/cli/internal/wizard.js +115 -0
  72. package/scripts/cli/mappings.js +23 -0
  73. package/scripts/cli/migration-tools.js +164 -94
  74. package/scripts/cli/plugins/style-dictionary.js +46 -0
  75. package/scripts/cli/templates/README.md +525 -95
  76. package/scripts/cli/templates/common-templates.js +40 -14
  77. package/scripts/cli/templates/components/react-component.ts +282 -0
  78. package/scripts/cli/templates/config/project-config.ts +112 -0
  79. package/scripts/cli/templates/hooks/use-component.ts +477 -0
  80. package/scripts/cli/templates/index.js +19 -4
  81. package/scripts/cli/templates/index.ts +171 -0
  82. package/scripts/cli/templates/next-templates.js +72 -0
  83. package/scripts/cli/templates/react-templates.js +70 -126
  84. package/scripts/cli/templates/scss-templates.js +35 -35
  85. package/scripts/cli/templates/stories/storybook-story.ts +241 -0
  86. package/scripts/cli/templates/styles/scss-component.ts +255 -0
  87. package/scripts/cli/templates/tests/vitest-test.ts +229 -0
  88. package/scripts/cli/templates/token-templates.js +337 -1
  89. package/scripts/cli/templates/tokens/token-generators.ts +1088 -0
  90. package/scripts/cli/templates/types/component-types.ts +145 -0
  91. package/scripts/cli/templates/utils/testing-utils.ts +144 -0
  92. package/scripts/cli/templates/vanilla-templates.js +39 -0
  93. package/scripts/cli/token-manager.js +8 -2
  94. package/scripts/cli/utils/cache-manager.js +240 -0
  95. package/scripts/cli/utils/detector.js +46 -0
  96. package/scripts/cli/utils/diagnostics.js +289 -0
  97. package/scripts/cli/utils/error.js +89 -0
  98. package/scripts/cli/utils/helpers.js +67 -0
  99. package/scripts/cli/utils/logger.js +75 -0
  100. package/scripts/cli/utils/security.js +302 -0
  101. package/scripts/cli/utils/telemetry.js +115 -0
  102. package/scripts/cli/utils/validation.js +37 -0
  103. package/scripts/cli/utils.js +28 -341
  104. package/src/components/Accordion/Accordion.stories.tsx +0 -18
  105. package/src/components/Accordion/Accordion.test.tsx +0 -17
  106. package/src/components/Accordion/Accordion.tsx +0 -4
  107. package/src/components/AtomixGlass/AtomixGlass.test.tsx +37 -3
  108. package/src/components/AtomixGlass/AtomixGlass.tsx +143 -31
  109. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +129 -31
  110. package/src/components/AtomixGlass/PerformanceDashboard.tsx +219 -0
  111. package/src/components/AtomixGlass/README.md +25 -10
  112. package/src/components/AtomixGlass/__snapshots__/AtomixGlass.test.tsx.snap +216 -0
  113. package/src/components/AtomixGlass/animation-system.ts +578 -0
  114. package/src/components/AtomixGlass/shader-utils.ts +4 -1
  115. package/src/components/AtomixGlass/stories/Overview.stories.tsx +157 -6
  116. package/src/components/AtomixGlass/stories/Phase1-Animation.stories.tsx +653 -0
  117. package/src/components/AtomixGlass/stories/Phase1-Test.stories.tsx +95 -0
  118. package/src/components/AtomixGlass/stories/Playground.stories.tsx +51 -51
  119. package/src/components/AtomixGlass/stories/shared-components.tsx +6 -0
  120. package/src/components/Avatar/Avatar.tsx +1 -1
  121. package/src/components/Button/Button.stories.disabled-link.tsx +10 -0
  122. package/src/components/Button/Button.stories.tsx +10 -0
  123. package/src/components/Button/Button.test.tsx +16 -11
  124. package/src/components/Button/Button.tsx +4 -4
  125. package/src/components/Card/Card.tsx +1 -1
  126. package/src/components/Dropdown/Dropdown.tsx +12 -12
  127. package/src/components/Form/Select.tsx +62 -3
  128. package/src/components/Modal/Modal.tsx +14 -3
  129. package/src/components/Navigation/Navbar/Navbar.tsx +44 -0
  130. package/src/components/Slider/Slider.stories.tsx +3 -3
  131. package/src/components/Slider/Slider.tsx +38 -0
  132. package/src/components/Steps/Steps.tsx +3 -3
  133. package/src/components/Tabs/Tabs.tsx +77 -8
  134. package/src/components/Testimonial/Testimonial.tsx +1 -1
  135. package/src/components/TypedButton/TypedButton.stories.tsx +59 -0
  136. package/src/components/TypedButton/TypedButton.tsx +39 -0
  137. package/src/components/TypedButton/index.ts +2 -0
  138. package/src/components/VideoPlayer/VideoPlayer.tsx +11 -4
  139. package/src/lib/composables/index.ts +4 -7
  140. package/src/lib/composables/types.ts +45 -0
  141. package/src/lib/composables/useAccordion.ts +0 -7
  142. package/src/lib/composables/useAtomixGlass.ts +148 -6
  143. package/src/lib/composables/useAtomixGlassStyles.ts +9 -7
  144. package/src/lib/composables/useChartExport.ts +3 -13
  145. package/src/lib/composables/useDropdown.ts +66 -0
  146. package/src/lib/composables/useFocusTrap.ts +80 -0
  147. package/src/lib/composables/usePerformanceMonitor.ts +448 -0
  148. package/src/lib/composables/useResponsiveGlass.presets.ts +192 -0
  149. package/src/lib/composables/useResponsiveGlass.ts +441 -0
  150. package/src/lib/composables/useTooltip.ts +16 -0
  151. package/src/lib/composables/useTypedButton.ts +66 -0
  152. package/src/lib/config/index.ts +62 -5
  153. package/src/lib/constants/components.ts +62 -7
  154. package/src/lib/theme/devtools/__tests__/useHistory.test.tsx +150 -0
  155. package/src/lib/theme/tokens/centralized-tokens.ts +120 -0
  156. package/src/lib/theme/utils/__tests__/domUtils.test.ts +101 -0
  157. package/src/lib/types/components.ts +37 -11
  158. package/src/lib/types/glass.ts +35 -0
  159. package/src/lib/types/index.ts +1 -0
  160. package/src/lib/utils/displacement-generator.ts +1 -1
  161. package/src/styles/01-settings/_settings.testtypecheck.scss +53 -0
  162. package/src/styles/01-settings/_settings.typedbutton.scss +53 -0
  163. package/src/styles/06-components/_components.atomix-glass.scss +17 -21
  164. package/src/styles/06-components/_components.edge-panel.scss +1 -5
  165. package/src/styles/06-components/_components.modal.scss +1 -4
  166. package/src/styles/06-components/_components.navbar.scss +1 -1
  167. package/src/styles/06-components/_components.testbutton.scss +212 -0
  168. package/src/styles/06-components/_components.testtypecheck.scss +212 -0
  169. package/src/styles/06-components/_components.tooltip.scss +9 -5
  170. package/src/styles/06-components/_components.typedbutton.scss +212 -0
  171. package/src/styles/99-utilities/_index.scss +1 -0
  172. package/src/styles/99-utilities/_utilities.text.scss +1 -1
  173. package/src/styles/99-utilities/_utilities.touch-target.scss +36 -0
  174. package/scripts/cli/component-generator.js +0 -564
  175. package/scripts/cli/interactive-init.js +0 -357
  176. package/src/styles/06-components/old.chart.styles.scss +0 -2788
@@ -3,6 +3,11 @@ import type { AtomixGlassProps } from '../../lib/types/components';
3
3
  import { ATOMIX_GLASS } from '../../lib/constants/components';
4
4
  import { AtomixGlassContainer } from './AtomixGlassContainer';
5
5
  import { useAtomixGlass } from '../../lib/composables/useAtomixGlass';
6
+ // Phase 3: Optimization & Adaptation
7
+ import { useResponsiveGlass } from '../../lib/composables/useResponsiveGlass';
8
+ import { usePerformanceMonitor } from '../../lib/composables/usePerformanceMonitor';
9
+ import { PerformanceDashboard } from './PerformanceDashboard';
10
+ import { getDevicePreset, MOBILE_OPTIMIZED_BREAKPOINTS } from '../../lib/composables/useResponsiveGlass.presets';
6
11
 
7
12
  /**
8
13
  * AtomixGlass - A high-performance glass morphism component with liquid distortion effects
@@ -18,6 +23,8 @@ import { useAtomixGlass } from '../../lib/composables/useAtomixGlass';
18
23
  * - Focus ring support for keyboard navigation
19
24
  * - Responsive breakpoints for mobile optimization
20
25
  * - Enhanced ARIA attributes for screen readers
26
+ * - Time-based animation system with FBM distortion
27
+ * - Device preset optimization for performance/quality balance
21
28
  *
22
29
  * Design System Compliance:
23
30
  * - Uses design tokens for opacity, spacing, and colors
@@ -74,6 +81,12 @@ import { useAtomixGlass } from '../../lib/composables/useAtomixGlass';
74
81
  * <AtomixGlass overLight="auto" debugOverLight={true}>
75
82
  * <div>Content with debug logging enabled</div>
76
83
  * </AtomixGlass>
84
+ *
85
+ * @example
86
+ * // Performance-optimized for mobile devices
87
+ * <AtomixGlass devicePreset="performance" disableResponsiveBreakpoints={false}>
88
+ * <div>Mobile-optimized glass effect</div>
89
+ * </AtomixGlass>
77
90
  */
78
91
  export function AtomixGlass({
79
92
  children,
@@ -104,15 +117,34 @@ export function AtomixGlass({
104
117
  withBorder = true,
105
118
  withOverLightLayers = ATOMIX_GLASS.DEFAULTS.ENABLE_OVER_LIGHT_LAYERS,
106
119
  debugPerformance = false,
107
- debugBorderRadius = false,
108
120
  debugOverLight = false,
109
121
  height,
110
122
  width,
123
+ withTimeAnimation = false,
124
+ animationSpeed = 1.0,
125
+ withMultiLayerDistortion = false,
126
+ distortionOctaves = 3,
127
+ distortionLacunarity = 2.0,
128
+ distortionGain = 0.5,
129
+ distortionQuality = 'medium',
130
+ devicePreset = 'balanced',
131
+ disableResponsiveBreakpoints = false,
111
132
  ...rest
112
133
  }: AtomixGlassProps) {
113
134
  const glassRef = useRef<HTMLDivElement>(null);
114
135
  const contentRef = useRef<HTMLDivElement>(null);
115
136
 
137
+ // ── Layout hoisting ──────────────────────────────────────────────────
138
+ // When position is fixed/sticky the layout props must live on the ROOT
139
+ // `.c-atomix-glass` element so that every decorative layer (borders,
140
+ // backgrounds, hover effects) stays in the same stacking context.
141
+
142
+ // Extract zIndex from style so it becomes the base for ALL internal
143
+ // layers via --atomix-glass-base-z-index. It must NOT be applied as a
144
+ // real z-index on the root element — that would break the glass effect.
145
+ const { zIndex: customZIndex, ...restStyle } = style;
146
+ const isFixedOrSticky = restStyle.position === 'fixed' || restStyle.position === 'sticky';
147
+
116
148
  // Use composable hook for all state and logic
117
149
  const {
118
150
  isHovered,
@@ -126,6 +158,8 @@ export function AtomixGlass({
126
158
  globalMousePosition,
127
159
  mouseOffset,
128
160
  transformStyle,
161
+ getShaderTime,
162
+ applyTimeBasedDistortion,
129
163
  handleMouseEnter,
130
164
  handleMouseLeave,
131
165
  handleMouseDown,
@@ -144,7 +178,6 @@ export function AtomixGlass({
144
178
  withoutEffects,
145
179
  elasticity,
146
180
  onClick,
147
- debugBorderRadius,
148
181
  debugOverLight,
149
182
  debugPerformance,
150
183
  children,
@@ -153,22 +186,72 @@ export function AtomixGlass({
153
186
  withLiquidBlur,
154
187
  padding,
155
188
  style,
189
+ isFixedOrSticky,
190
+ // Phase 1: Animation System props
191
+ withTimeAnimation,
192
+ animationSpeed,
193
+ withMultiLayerDistortion,
194
+ distortionOctaves,
195
+ distortionLacunarity,
196
+ distortionGain,
197
+ distortionQuality,
156
198
  });
157
199
 
158
- const isOverLight = useMemo(() => overLightConfig.isOverLight, [overLightConfig.isOverLight]);
200
+ // ============================================================================
201
+ // Phase 3: Optimization & Adaptation Systems
202
+ // ============================================================================
159
203
 
160
- const shouldRenderOverLightLayers = withOverLightLayers && isOverLight;
204
+ // Get device preset parameters - memoized to prevent recalculation
205
+ const devicePresetParams = useMemo(() => {
206
+ return getDevicePreset(devicePreset);
207
+ }, [devicePreset]); // Re-calculate only when devicePreset changes
161
208
 
162
- // ── Layout hoisting ──────────────────────────────────────────────────
163
- // When position is fixed/sticky the layout props must live on the ROOT
164
- // `.c-atomix-glass` element so that every decorative layer (borders,
165
- // backgrounds, hover effects) stays in the same stacking context.
209
+ // Responsive breakpoint system - automatically adjusts parameters based on viewport
210
+ const {
211
+ responsiveParams,
212
+ currentBreakpoint,
213
+ performanceTier,
214
+ isActive: isResponsiveActive
215
+ } = useResponsiveGlass({
216
+ baseParams: {
217
+ ...devicePresetParams,
218
+ distortionOctaves: Math.round((displacementScale || ATOMIX_GLASS.DEFAULTS.DISPLACEMENT_SCALE) / 25),
219
+ displacementScale: displacementScale || ATOMIX_GLASS.DEFAULTS.DISPLACEMENT_SCALE,
220
+ blurAmount: blurAmount || ATOMIX_GLASS.DEFAULTS.BLUR_AMOUNT,
221
+ saturation: saturation || ATOMIX_GLASS.DEFAULTS.SATURATION,
222
+ aberrationIntensity: aberrationIntensity || ATOMIX_GLASS.DEFAULTS.ABERRATION_INTENSITY,
223
+ animationSpeed: 1.0,
224
+ chromaticIntensity: aberrationIntensity || ATOMIX_GLASS.DEFAULTS.ABERRATION_INTENSITY,
225
+ },
226
+ breakpoints: MOBILE_OPTIMIZED_BREAKPOINTS,
227
+ enabled: !disableResponsiveBreakpoints && typeof window !== 'undefined', // Enable unless disabled
228
+ debug: false
229
+ });
166
230
 
167
- // Extract zIndex from style so it becomes the base for ALL internal
168
- // layers via --atomix-glass-base-z-index. It must NOT be applied as a
169
- // real z-index on the root element — that would break the glass effect.
170
- const { zIndex: customZIndex, ...restStyle } = style;
171
- const isFixedOrSticky = restStyle.position === 'fixed' || restStyle.position === 'sticky';
231
+ // Performance monitoring - tracks FPS, frame time, memory usage
232
+ const {
233
+ metrics: performanceMetrics,
234
+ recommendedQuality,
235
+ isUnderperforming,
236
+ setQualityLevel,
237
+ toggleMonitoring
238
+ } = usePerformanceMonitor({
239
+ enabled: false, // We'll toggle manually based on prop
240
+ debug: false,
241
+ showOverlay: false
242
+ });
243
+
244
+ // Auto-start performance monitoring if enabled (only in development)
245
+ React.useEffect(() => {
246
+ if (process.env.NODE_ENV === 'development' && (window as any)?.enablePerformanceMonitoring) {
247
+ toggleMonitoring();
248
+ }
249
+ // eslint-disable-next-line react-hooks/exhaustive-deps
250
+ }, []); // Only run once on mount
251
+
252
+ const isOverLight = useMemo(() => overLightConfig.isOverLight, [overLightConfig.isOverLight]);
253
+
254
+ const shouldRenderOverLightLayers = withOverLightLayers && isOverLight;
172
255
 
173
256
  const rootLayoutStyle = useMemo<React.CSSProperties>(() => {
174
257
  if (!isFixedOrSticky) return {};
@@ -223,21 +306,26 @@ export function AtomixGlass({
223
306
  );
224
307
 
225
308
  const adjustedSize = useMemo(() => {
226
- const resolveSize = (
227
- propValue: string | number | undefined,
228
- styleValue: string | number | undefined,
229
- measuredSize: number
230
- ) => {
231
- const explicitSize = propValue ?? styleValue;
232
- if (explicitSize !== undefined) {
233
- return typeof explicitSize === 'number' ? `${explicitSize}px` : explicitSize;
309
+ // Keep a reference to positionStyles to avoid unused-variable lint,
310
+ // but sizing is driven by explicit width/height or measured size.
311
+ const _position = positionStyles.position;
312
+
313
+ const resolveLength = (value: string | number | undefined, measured: number): string => {
314
+ if (value !== undefined) {
315
+ return typeof value === 'number' ? `${value}px` : value;
234
316
  }
235
- return positionStyles.position === 'fixed' ? `${Math.max(measuredSize, 0)}px` : '100%';
317
+ if (measured > 0) {
318
+ return `${measured}px`;
319
+ }
320
+ return '100%';
236
321
  };
237
322
 
323
+ const effectiveWidth = width ?? restStyle.width;
324
+ const effectiveHeight = height ?? restStyle.height;
325
+
238
326
  return {
239
- width: resolveSize(width, restStyle.width, glassSize.width),
240
- height: resolveSize(height, restStyle.height, glassSize.height),
327
+ width: resolveLength(effectiveWidth, glassSize.width),
328
+ height: resolveLength(effectiveHeight, glassSize.height),
241
329
  };
242
330
  }, [
243
331
  width,
@@ -338,9 +426,10 @@ export function AtomixGlass({
338
426
  ...(customZIndex !== undefined && { '--atomix-glass-base-z-index': customZIndex }),
339
427
  '--atomix-glass-radius': `${effectiveBorderRadius}px`,
340
428
  '--atomix-glass-transform': transformStyle || 'none',
341
- '--atomix-glass-position': positionStyles.position,
342
- '--atomix-glass-top': positionStyles.top !== 'fixed' ? `${positionStyles.top}px` : '0',
343
- '--atomix-glass-left': positionStyles.left !== 'fixed' ? `${positionStyles.left}px` : '0',
429
+ // Internal decorative layers are positioned relative to the root;
430
+ '--atomix-glass-position': rootLayoutStyle.position,
431
+ '--atomix-glass-top': `${isFixedOrSticky ? rootLayoutStyle.top : 0}px`,
432
+ '--atomix-glass-left': `${isFixedOrSticky ? rootLayoutStyle.left : 0}px`,
344
433
  '--atomix-glass-width': adjustedSize.width,
345
434
  '--atomix-glass-height': adjustedSize.height,
346
435
  '--atomix-glass-border-width': 'var(--atomix-spacing-0-5, 0.09375rem)',
@@ -376,11 +465,12 @@ export function AtomixGlass({
376
465
  opacityValues,
377
466
  effectiveBorderRadius,
378
467
  transformStyle,
379
- positionStyles,
380
468
  adjustedSize,
381
469
  isOverLight,
382
470
  overLightConfig.borderOpacity,
383
471
  customZIndex,
472
+ rootLayoutStyle,
473
+ isFixedOrSticky,
384
474
  ]);
385
475
 
386
476
  // Helper function to render background layers
@@ -417,7 +507,12 @@ export function AtomixGlass({
417
507
  ref={glassRef}
418
508
  contentRef={contentRef}
419
509
  className={className}
420
- style={rootLayoutStyle}
510
+ style={{
511
+ ...restStyle,
512
+ ...(!isFixedOrSticky && {
513
+ position: 'relative',
514
+ }),
515
+ }}
421
516
  borderRadius={effectiveBorderRadius}
422
517
  displacementScale={
423
518
  effectiveWithoutEffects
@@ -462,11 +557,19 @@ export function AtomixGlass({
462
557
  }}
463
558
  onClick={onClick}
464
559
  mode={mode}
465
- transform={baseStyle.transform}
466
560
  effectiveWithoutEffects={effectiveWithoutEffects}
467
561
  effectiveReducedMotion={effectiveReducedMotion}
468
562
  shaderVariant={shaderVariant}
469
563
  withLiquidBlur={withLiquidBlur}
564
+ // Phase 1: Animation System props
565
+ shaderTime={getShaderTime()}
566
+ withTimeAnimation={withTimeAnimation}
567
+ animationSpeed={animationSpeed}
568
+ withMultiLayerDistortion={withMultiLayerDistortion}
569
+ distortionOctaves={distortionOctaves}
570
+ distortionLacunarity={distortionLacunarity}
571
+ distortionGain={distortionGain}
572
+ distortionQuality={distortionQuality}
470
573
  >
471
574
  {children}
472
575
  </AtomixGlassContainer>
@@ -480,7 +583,7 @@ export function AtomixGlass({
480
583
  )}
481
584
 
482
585
  {/* Background layers for over-light mode */}
483
- {/* Static styles (pointer-events, will-change) are in SCSS */}
586
+ {/* Static styles (pointer-events) are in SCSS; will-change is managed via .u-glass-clean-root utility for backdrop-filter stability */}
484
587
  {renderBackgroundLayer('dark')}
485
588
  {renderBackgroundLayer('black')}
486
589
  {shouldRenderOverLightLayers && (
@@ -500,6 +603,15 @@ export function AtomixGlass({
500
603
  <span className={ATOMIX_GLASS.BORDER_2_CLASS} />
501
604
  </>
502
605
  )}
606
+
607
+ {/* Phase 3: Performance Monitoring Dashboard - Only in development with debugPerformance enabled */}
608
+ {debugPerformance && performanceMetrics && (
609
+ <PerformanceDashboard
610
+ metrics={performanceMetrics}
611
+ isVisible={true}
612
+ onClose={() => {}} // No-op, dashboard always visible when debugPerformance is true
613
+ />
614
+ )}
503
615
  </div>
504
616
  );
505
617
  }
@@ -1,6 +1,6 @@
1
1
  import React, { forwardRef, useRef, useState, useEffect, useMemo } from 'react';
2
2
  import type { CSSProperties } from 'react';
3
- import type { DisplacementMode, MousePosition, GlassSize } from '../../lib/types/components';
3
+ import type { DisplacementMode, MousePosition, GlassSize, AtomixGlassProps } from '../../lib/types/components';
4
4
  import type { FragmentShaderType } from './shader-utils';
5
5
  import { GlassFilter } from './GlassFilter';
6
6
  import { calculateMouseInfluence, clampBlur, validateGlassSize } from './glass-utils';
@@ -59,7 +59,17 @@ const setCachedShader = (key: string, url: string): void => {
59
59
  }
60
60
  };
61
61
 
62
- interface AtomixGlassContainerProps {
62
+ interface AtomixGlassContainerProps
63
+ extends Pick<
64
+ AtomixGlassProps,
65
+ | 'withTimeAnimation'
66
+ | 'animationSpeed'
67
+ | 'withMultiLayerDistortion'
68
+ | 'distortionOctaves'
69
+ | 'distortionLacunarity'
70
+ | 'distortionGain'
71
+ | 'distortionQuality'
72
+ > {
63
73
  className?: string;
64
74
  style?: React.CSSProperties;
65
75
  displacementScale?: number;
@@ -92,6 +102,9 @@ interface AtomixGlassContainerProps {
92
102
  shaderVariant?: FragmentShaderType;
93
103
  withLiquidBlur?: boolean;
94
104
 
105
+ // Phase 1: Animation System props
106
+ shaderTime?: number;
107
+
95
108
  contentRef?: React.RefObject<HTMLDivElement>;
96
109
  children?: React.ReactNode;
97
110
  }
@@ -111,12 +124,10 @@ export const AtomixGlassContainer = forwardRef<HTMLDivElement, AtomixGlassContai
111
124
  saturation = 180,
112
125
  aberrationIntensity = 2,
113
126
  mouseOffset = { x: 0, y: 0 },
114
- globalMousePosition = { x: 0, y: 0 },
115
127
  onMouseEnter,
116
128
  onMouseLeave,
117
129
  onMouseDown,
118
130
  onMouseUp,
119
- isHovered = false,
120
131
  isActive = false,
121
132
  overLight = false,
122
133
  overLightConfig = {},
@@ -130,6 +141,16 @@ export const AtomixGlassContainer = forwardRef<HTMLDivElement, AtomixGlassContai
130
141
  shaderVariant = 'liquidGlass',
131
142
  withLiquidBlur = false,
132
143
 
144
+ // Phase 1: Animation System props
145
+ shaderTime,
146
+ withTimeAnimation = false,
147
+ animationSpeed = 1.0,
148
+ withMultiLayerDistortion = false,
149
+ distortionOctaves = 3,
150
+ distortionLacunarity = 2.0,
151
+ distortionGain = 0.5,
152
+ distortionQuality = 'medium',
153
+
133
154
  contentRef,
134
155
  },
135
156
  ref
@@ -149,11 +170,15 @@ export const AtomixGlassContainer = forwardRef<HTMLDivElement, AtomixGlassContai
149
170
 
150
171
  // Use shared module-level cache (no per-instance cache needed)
151
172
  const shaderDebounceTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
173
+ const shaderUpdateTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
174
+
175
+ // Phase 1: Animation frame ref for continuous shader updates
176
+ const animationFrameRef = useRef<number | null>(null);
152
177
 
153
178
  // Lazy load shader utilities only when shader mode is needed
154
179
  useEffect(() => {
155
180
  if (mode === 'shader') {
156
- // Dynamic import shader utilities
181
+ // Dynamic import shader utilities with animation support
157
182
  import('./shader-utils')
158
183
  .then(shaderUtils => {
159
184
  shaderUtilsRef.current = {
@@ -176,12 +201,7 @@ export const AtomixGlassContainer = forwardRef<HTMLDivElement, AtomixGlassContai
176
201
  // Generate shader map with debouncing and caching
177
202
  useEffect(() => {
178
203
  // Enhanced validation for shader mode
179
- if (
180
- mode === 'shader' &&
181
- glassSize &&
182
- validateGlassSize(glassSize) &&
183
- shaderUtilsRef.current
184
- ) {
204
+ if (mode === 'shader' && glassSize && validateGlassSize(glassSize)) {
185
205
  // Create cache key from size and variant
186
206
  const cacheKey = `${glassSize.width}x${glassSize.height}-${shaderVariant}`;
187
207
 
@@ -215,10 +235,11 @@ export const AtomixGlassContainer = forwardRef<HTMLDivElement, AtomixGlassContai
215
235
  fragment: selectedShader,
216
236
  });
217
237
 
218
- // Defer shader generation with longer delay to avoid blocking
219
- setTimeout(() => {
238
+ shaderUpdateTimeoutRef.current = setTimeout(() => {
220
239
  const url = shaderGeneratorRef.current?.updateShader() || '';
221
- setCachedShader(cacheKey, url);
240
+ if (url) {
241
+ setCachedShader(cacheKey, url);
242
+ }
222
243
  setShaderMapUrl(url);
223
244
  }, 100);
224
245
  } catch (error) {
@@ -240,6 +261,10 @@ export const AtomixGlassContainer = forwardRef<HTMLDivElement, AtomixGlassContai
240
261
  clearTimeout(shaderDebounceTimeoutRef.current);
241
262
  shaderDebounceTimeoutRef.current = null;
242
263
  }
264
+ if (shaderUpdateTimeoutRef.current) {
265
+ clearTimeout(shaderUpdateTimeoutRef.current);
266
+ shaderUpdateTimeoutRef.current = null;
267
+ }
243
268
  try {
244
269
  shaderGeneratorRef.current?.destroy();
245
270
  } catch (error) {
@@ -250,6 +275,92 @@ export const AtomixGlassContainer = forwardRef<HTMLDivElement, AtomixGlassContai
250
275
  };
251
276
  }, [mode, glassSize, shaderVariant]);
252
277
 
278
+ // Phase 1: Time-Based Animation Loop - Continuous shader regeneration
279
+ useEffect(() => {
280
+ // Only run animations in shader mode with time animation enabled
281
+ if (
282
+ mode !== 'shader' ||
283
+ !withTimeAnimation ||
284
+ effectiveReducedMotion ||
285
+ effectiveWithoutEffects
286
+ ) {
287
+ // Cancel any existing animation frame
288
+ if (animationFrameRef.current !== null) {
289
+ cancelAnimationFrame(animationFrameRef.current);
290
+ animationFrameRef.current = null;
291
+ }
292
+ return;
293
+ }
294
+
295
+ const baseFps =
296
+ distortionQuality === 'ultra'
297
+ ? 60
298
+ : distortionQuality === 'high'
299
+ ? 30
300
+ : distortionQuality === 'medium'
301
+ ? 24
302
+ : 20;
303
+ const effectiveSpeed = Math.max(0.5, Math.min(2, animationSpeed || 1));
304
+ const complexity =
305
+ withMultiLayerDistortion
306
+ ? Math.max(
307
+ 1,
308
+ (distortionOctaves || 3) / 3 +
309
+ Math.max(0, (distortionLacunarity || 2) - 2) * 0.25 +
310
+ Math.max(0, (distortionGain || 0.5) - 0.5)
311
+ )
312
+ : 1;
313
+ const targetFps = Math.max(12, Math.min(60, Math.round((baseFps * effectiveSpeed) / complexity)));
314
+ const frameInterval = 1000 / targetFps;
315
+ let lastUpdate = 0;
316
+ let isCancelled = false;
317
+
318
+ const animate = (currentTime: number) => {
319
+ if (isCancelled) {
320
+ return;
321
+ }
322
+
323
+ if (currentTime - lastUpdate >= frameInterval && shaderGeneratorRef.current) {
324
+ lastUpdate = currentTime;
325
+ try {
326
+ const animatedShaderUrl = shaderGeneratorRef.current.updateShader();
327
+ if (animatedShaderUrl) {
328
+ setShaderMapUrl(animatedShaderUrl);
329
+ }
330
+ } catch (error) {
331
+ console.warn('AtomixGlassContainer: Error in animation loop', error);
332
+ }
333
+ }
334
+
335
+ animationFrameRef.current = requestAnimationFrame(animate);
336
+ };
337
+
338
+ // Start animation loop
339
+ animationFrameRef.current = requestAnimationFrame(animate);
340
+
341
+ // Cleanup animation on unmount or dependency change
342
+ return () => {
343
+ isCancelled = true;
344
+ if (animationFrameRef.current !== null) {
345
+ cancelAnimationFrame(animationFrameRef.current);
346
+ animationFrameRef.current = null;
347
+ }
348
+ };
349
+ }, [
350
+ mode,
351
+ withTimeAnimation,
352
+ animationSpeed,
353
+ displacementScale,
354
+ withMultiLayerDistortion,
355
+ distortionOctaves,
356
+ distortionLacunarity,
357
+ distortionGain,
358
+ distortionQuality,
359
+ effectiveReducedMotion,
360
+ effectiveWithoutEffects,
361
+ glassSize,
362
+ ]);
363
+
253
364
  // Removed forced reflow to avoid layout thrash and potential feedback sizing loops
254
365
 
255
366
  const [rectCache, setRectCache] = useState<DOMRect | null>(null);
@@ -401,6 +512,7 @@ export const AtomixGlassContainer = forwardRef<HTMLDivElement, AtomixGlassContai
401
512
  effectiveReducedMotion,
402
513
  effectiveWithoutEffects,
403
514
  withLiquidBlur,
515
+ overLightConfig,
404
516
  ]);
405
517
 
406
518
  const containerVars = useMemo(() => {
@@ -415,9 +527,6 @@ export const AtomixGlassContainer = forwardRef<HTMLDivElement, AtomixGlassContai
415
527
  ? mouseOffset.y
416
528
  : 0;
417
529
  return {
418
- '--atomix-glass-container-width': `${glassSize?.width}`,
419
- '--atomix-glass-container-height': `${glassSize?.height}`,
420
- '--atomix-glass-container-padding': padding || '0 0',
421
530
  '--atomix-glass-container-radius': `${typeof borderRadius === 'number' && !isNaN(borderRadius) ? borderRadius : 0}px`,
422
531
  '--atomix-glass-container-backdrop': backdropStyle?.backdropFilter || 'none',
423
532
  '--atomix-glass-container-shadow': overLight
@@ -434,7 +543,7 @@ export const AtomixGlassContainer = forwardRef<HTMLDivElement, AtomixGlassContai
434
543
  ? `linear-gradient(${180 + mx * 0.5}deg, rgba(255, 255, 255, 0.1) 0%, transparent 20%, transparent 80%, rgba(0, 0, 0, 0.05) 100%)`
435
544
  : 'none',
436
545
  '--atomix-glass-container-text-shadow': overLight
437
- ? '0px 2px 12px rgba(0, 0, 0, 0)'
546
+ ? '0px 1px 2px rgba(255, 255, 255, 0.15)'
438
547
  : '0px 2px 12px rgba(0, 0, 0, 0.4)',
439
548
  '--atomix-glass-container-box-shadow': overLight
440
549
  ? '0px 16px 70px rgba(0, 0, 0, 0.75)'
@@ -453,24 +562,14 @@ export const AtomixGlassContainer = forwardRef<HTMLDivElement, AtomixGlassContai
453
562
  } as React.CSSProperties;
454
563
  }
455
564
  }, [
456
- glassSize,
457
- padding,
458
- borderRadius,
565
+ borderRadius,
459
566
  backdropStyle,
460
567
  mouseOffset,
461
568
  overLight,
462
569
  effectiveWithoutEffects,
570
+ overLightConfig,
463
571
  ]);
464
572
 
465
- // Helper to force no transition/animation overrides with !important
466
- const setForceNoTransition = (el: HTMLElement | null) => {
467
- if (el) {
468
- el.style.setProperty('transition-duration', '0s', 'important');
469
- el.style.setProperty('animation-duration', '0s', 'important');
470
- el.style.setProperty('transition-delay', '0s', 'important');
471
- }
472
- };
473
-
474
573
  return (
475
574
  <div
476
575
  ref={el => {
@@ -513,7 +612,6 @@ export const AtomixGlassContainer = forwardRef<HTMLDivElement, AtomixGlassContai
513
612
  />
514
613
  {/* Enhanced Apple Liquid Glass Inner Shadow Layer */}
515
614
  <div
516
- ref={setForceNoTransition}
517
615
  className={ATOMIX_GLASS.FILTER_OVERLAY_CLASS}
518
616
  style={{
519
617
  filter: `url(#${filterId})`,