@shohojdhara/atomix 0.4.8 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/atomix.config.ts +58 -1
- package/dist/atomix.css +148 -120
- package/dist/atomix.css.map +1 -1
- package/dist/atomix.min.css +1 -1
- package/dist/atomix.min.css.map +1 -1
- package/dist/charts.d.ts +33 -0
- package/dist/charts.js +1227 -122
- package/dist/charts.js.map +1 -1
- package/dist/core.d.ts +33 -10
- package/dist/core.js +1052 -41
- package/dist/core.js.map +1 -1
- package/dist/forms.d.ts +33 -0
- package/dist/forms.js +2086 -1035
- package/dist/forms.js.map +1 -1
- package/dist/heavy.d.ts +42 -1
- package/dist/heavy.js +1620 -600
- package/dist/heavy.js.map +1 -1
- package/dist/index.d.ts +441 -270
- package/dist/index.esm.js +1900 -638
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1935 -670
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1 -1
- package/dist/index.min.js.map +1 -1
- package/package.json +6 -3
- package/scripts/atomix-cli.js +148 -4
- package/scripts/cli/__tests__/basic.test.js +3 -2
- package/scripts/cli/__tests__/clean.test.js +278 -0
- package/scripts/cli/__tests__/component-validator.test.js +433 -0
- package/scripts/cli/__tests__/generator.test.js +613 -0
- package/scripts/cli/__tests__/glass-motion.test.js +256 -0
- package/scripts/cli/__tests__/integration.test.js +719 -108
- package/scripts/cli/__tests__/migrate.test.js +74 -0
- package/scripts/cli/__tests__/security.test.js +206 -0
- package/scripts/cli/__tests__/test-setup.js +3 -1
- package/scripts/cli/__tests__/theme-bridge.test.js +507 -0
- package/scripts/cli/__tests__/token-provider.test.js +361 -0
- package/scripts/cli/__tests__/utils.test.js +5 -5
- package/scripts/cli/commands/benchmark.js +105 -0
- package/scripts/cli/commands/build-theme.js +4 -1
- package/scripts/cli/commands/clean.js +109 -0
- package/scripts/cli/commands/doctor.js +88 -0
- package/scripts/cli/commands/generate.js +135 -14
- package/scripts/cli/commands/init.js +45 -18
- package/scripts/cli/commands/migrate.js +106 -0
- package/scripts/cli/commands/sync-tokens.js +206 -0
- package/scripts/cli/commands/theme-bridge.js +248 -0
- package/scripts/cli/commands/tokens.js +157 -0
- package/scripts/cli/commands/validate.js +194 -0
- package/scripts/cli/internal/ai-engine.js +156 -0
- package/scripts/cli/internal/component-validator.js +443 -0
- package/scripts/cli/internal/config-loader.js +162 -0
- package/scripts/cli/internal/filesystem.js +102 -2
- package/scripts/cli/internal/generator.js +359 -39
- package/scripts/cli/internal/glass-generator.js +398 -0
- package/scripts/cli/internal/hook-generator.js +369 -0
- package/scripts/cli/internal/hooks.js +61 -0
- package/scripts/cli/internal/itcss-generator.js +565 -0
- package/scripts/cli/internal/motion-generator.js +679 -0
- package/scripts/cli/internal/template-engine.js +301 -0
- package/scripts/cli/internal/theme-bridge.js +664 -0
- package/scripts/cli/internal/tokens/engine.js +122 -0
- package/scripts/cli/internal/tokens/provider.js +34 -0
- package/scripts/cli/internal/tokens/providers/figma.js +50 -0
- package/scripts/cli/internal/tokens/providers/style-dictionary.js +48 -0
- package/scripts/cli/internal/tokens/providers/w3c.js +48 -0
- package/scripts/cli/internal/tokens/token-provider.js +443 -0
- package/scripts/cli/internal/tokens/token-validator.js +513 -0
- package/scripts/cli/internal/validator.js +276 -0
- package/scripts/cli/internal/wizard.js +60 -6
- package/scripts/cli/mappings.js +23 -0
- package/scripts/cli/migration-tools.js +164 -94
- package/scripts/cli/plugins/style-dictionary.js +46 -0
- package/scripts/cli/templates/README.md +525 -95
- package/scripts/cli/templates/common-templates.js +40 -14
- package/scripts/cli/templates/components/react-component.ts +282 -0
- package/scripts/cli/templates/config/project-config.ts +112 -0
- package/scripts/cli/templates/hooks/use-component.ts +477 -0
- package/scripts/cli/templates/index.js +19 -4
- package/scripts/cli/templates/index.ts +171 -0
- package/scripts/cli/templates/next-templates.js +72 -0
- package/scripts/cli/templates/react-templates.js +70 -126
- package/scripts/cli/templates/scss-templates.js +35 -35
- package/scripts/cli/templates/stories/storybook-story.ts +241 -0
- package/scripts/cli/templates/styles/scss-component.ts +255 -0
- package/scripts/cli/templates/tests/vitest-test.ts +229 -0
- package/scripts/cli/templates/token-templates.js +337 -1
- package/scripts/cli/templates/tokens/token-generators.ts +1088 -0
- package/scripts/cli/templates/types/component-types.ts +145 -0
- package/scripts/cli/templates/utils/testing-utils.ts +144 -0
- package/scripts/cli/templates/vanilla-templates.js +39 -0
- package/scripts/cli/token-manager.js +8 -2
- package/scripts/cli/utils/cache-manager.js +240 -0
- package/scripts/cli/utils/detector.js +46 -0
- package/scripts/cli/utils/diagnostics.js +289 -0
- package/scripts/cli/utils/error.js +45 -3
- package/scripts/cli/utils/helpers.js +24 -0
- package/scripts/cli/utils/logger.js +1 -1
- package/scripts/cli/utils/security.js +302 -0
- package/scripts/cli/utils/telemetry.js +115 -0
- package/scripts/cli/utils/validation.js +4 -38
- package/scripts/cli/utils.js +46 -0
- package/src/components/Accordion/Accordion.stories.tsx +0 -18
- package/src/components/Accordion/Accordion.test.tsx +0 -17
- package/src/components/Accordion/Accordion.tsx +0 -4
- package/src/components/AtomixGlass/AtomixGlass.tsx +102 -2
- package/src/components/AtomixGlass/AtomixGlassContainer.tsx +125 -12
- package/src/components/AtomixGlass/PerformanceDashboard.tsx +219 -0
- package/src/components/AtomixGlass/README.md +25 -10
- package/src/components/AtomixGlass/animation-system.ts +578 -0
- package/src/components/AtomixGlass/shader-utils.ts +3 -0
- package/src/components/AtomixGlass/stories/AnimationFeatures.stories.tsx +653 -0
- package/src/components/AtomixGlass/stories/AnimationTests.stories.tsx +95 -0
- package/src/components/AtomixGlass/stories/CardExamples.stories.tsx +212 -0
- package/src/components/AtomixGlass/stories/DashboardExamples.stories.tsx +348 -0
- package/src/components/AtomixGlass/stories/EcommerceExamples.stories.tsx +410 -0
- package/src/components/AtomixGlass/stories/FormExamples.stories.tsx +436 -0
- package/src/components/AtomixGlass/stories/HeroExamples.stories.tsx +264 -0
- package/src/components/AtomixGlass/stories/InteractivePlayground.stories.tsx +247 -0
- package/src/components/AtomixGlass/stories/MobileUIExamples.stories.tsx +418 -0
- package/src/components/AtomixGlass/stories/ModalExamples.stories.tsx +402 -0
- package/src/components/AtomixGlass/stories/Overview.stories.tsx +157 -6
- package/src/components/AtomixGlass/stories/Playground.stories.tsx +658 -93
- package/src/components/AtomixGlass/stories/PresetGallery.stories.tsx +335 -0
- package/src/components/AtomixGlass/stories/WidgetExamples.stories.tsx +441 -0
- package/src/components/AtomixGlass/stories/argTypes.ts +384 -0
- package/src/components/AtomixGlass/stories/shared-components.tsx +91 -1
- package/src/components/AtomixGlass/stories/types.ts +127 -0
- package/src/components/Avatar/Avatar.tsx +1 -1
- package/src/components/Button/Button.stories.disabled-link.tsx +10 -0
- package/src/components/Button/Button.stories.tsx +10 -0
- package/src/components/Button/Button.test.tsx +16 -11
- package/src/components/Button/Button.tsx +4 -4
- package/src/components/Card/Card.tsx +1 -1
- package/src/components/Dropdown/Dropdown.tsx +12 -12
- package/src/components/Form/Select.tsx +62 -3
- package/src/components/Modal/Modal.tsx +14 -3
- package/src/components/Navigation/Navbar/Navbar.tsx +44 -0
- package/src/components/Slider/Slider.stories.tsx +3 -3
- package/src/components/Slider/Slider.tsx +38 -0
- package/src/components/Steps/Steps.tsx +3 -3
- package/src/components/Tabs/Tabs.tsx +77 -8
- package/src/components/Testimonial/Testimonial.tsx +1 -1
- package/src/components/TypedButton/TypedButton.stories.tsx +59 -0
- package/src/components/TypedButton/TypedButton.tsx +39 -0
- package/src/components/TypedButton/index.ts +2 -0
- package/src/components/VideoPlayer/VideoPlayer.tsx +11 -4
- package/src/lib/composables/index.ts +4 -7
- package/src/lib/composables/types.ts +45 -0
- package/src/lib/composables/useAccordion.ts +0 -7
- package/src/lib/composables/useAtomixGlass.ts +144 -5
- package/src/lib/composables/useChartExport.ts +3 -13
- package/src/lib/composables/useDropdown.ts +66 -0
- package/src/lib/composables/useFocusTrap.ts +80 -0
- package/src/lib/composables/usePerformanceMonitor.ts +448 -0
- package/src/lib/composables/useResponsiveGlass.presets.ts +192 -0
- package/src/lib/composables/useResponsiveGlass.ts +441 -0
- package/src/lib/composables/useTooltip.ts +16 -0
- package/src/lib/composables/useTypedButton.ts +66 -0
- package/src/lib/config/index.ts +62 -5
- package/src/lib/constants/components.ts +55 -0
- package/src/lib/theme/devtools/__tests__/useHistory.test.tsx +150 -0
- package/src/lib/theme/tokens/centralized-tokens.ts +120 -0
- package/src/lib/theme/utils/__tests__/domUtils.test.ts +101 -0
- package/src/lib/types/components.ts +37 -11
- package/src/lib/types/glass.ts +35 -0
- package/src/lib/types/index.ts +1 -0
- package/src/lib/utils/displacement-generator.ts +1 -1
- package/src/styles/01-settings/_settings.testtypecheck.scss +53 -0
- package/src/styles/01-settings/_settings.typedbutton.scss +53 -0
- package/src/styles/06-components/_components.testbutton.scss +212 -0
- package/src/styles/06-components/_components.testtypecheck.scss +212 -0
- package/src/styles/06-components/_components.typedbutton.scss +212 -0
- package/src/styles/99-utilities/_index.scss +1 -0
- package/src/styles/99-utilities/_utilities.text.scss +1 -1
- package/src/styles/99-utilities/_utilities.touch-target.scss +36 -0
- 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,10 +117,18 @@ 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);
|
|
@@ -137,6 +158,8 @@ export function AtomixGlass({
|
|
|
137
158
|
globalMousePosition,
|
|
138
159
|
mouseOffset,
|
|
139
160
|
transformStyle,
|
|
161
|
+
getShaderTime,
|
|
162
|
+
applyTimeBasedDistortion,
|
|
140
163
|
handleMouseEnter,
|
|
141
164
|
handleMouseLeave,
|
|
142
165
|
handleMouseDown,
|
|
@@ -155,7 +178,6 @@ export function AtomixGlass({
|
|
|
155
178
|
withoutEffects,
|
|
156
179
|
elasticity,
|
|
157
180
|
onClick,
|
|
158
|
-
debugBorderRadius,
|
|
159
181
|
debugOverLight,
|
|
160
182
|
debugPerformance,
|
|
161
183
|
children,
|
|
@@ -165,8 +187,68 @@ export function AtomixGlass({
|
|
|
165
187
|
padding,
|
|
166
188
|
style,
|
|
167
189
|
isFixedOrSticky,
|
|
190
|
+
// Phase 1: Animation System props
|
|
191
|
+
withTimeAnimation,
|
|
192
|
+
animationSpeed,
|
|
193
|
+
withMultiLayerDistortion,
|
|
194
|
+
distortionOctaves,
|
|
195
|
+
distortionLacunarity,
|
|
196
|
+
distortionGain,
|
|
197
|
+
distortionQuality,
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
// ============================================================================
|
|
201
|
+
// Phase 3: Optimization & Adaptation Systems
|
|
202
|
+
// ============================================================================
|
|
203
|
+
|
|
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
|
|
208
|
+
|
|
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
|
|
168
229
|
});
|
|
169
230
|
|
|
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
|
+
|
|
170
252
|
const isOverLight = useMemo(() => overLightConfig.isOverLight, [overLightConfig.isOverLight]);
|
|
171
253
|
|
|
172
254
|
const shouldRenderOverLightLayers = withOverLightLayers && isOverLight;
|
|
@@ -479,6 +561,15 @@ export function AtomixGlass({
|
|
|
479
561
|
effectiveReducedMotion={effectiveReducedMotion}
|
|
480
562
|
shaderVariant={shaderVariant}
|
|
481
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}
|
|
482
573
|
>
|
|
483
574
|
{children}
|
|
484
575
|
</AtomixGlassContainer>
|
|
@@ -512,6 +603,15 @@ export function AtomixGlass({
|
|
|
512
603
|
<span className={ATOMIX_GLASS.BORDER_2_CLASS} />
|
|
513
604
|
</>
|
|
514
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
|
+
)}
|
|
515
615
|
</div>
|
|
516
616
|
);
|
|
517
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
|
}
|
|
@@ -128,6 +141,16 @@ export const AtomixGlassContainer = forwardRef<HTMLDivElement, AtomixGlassContai
|
|
|
128
141
|
shaderVariant = 'liquidGlass',
|
|
129
142
|
withLiquidBlur = false,
|
|
130
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
|
+
|
|
131
154
|
contentRef,
|
|
132
155
|
},
|
|
133
156
|
ref
|
|
@@ -147,11 +170,15 @@ export const AtomixGlassContainer = forwardRef<HTMLDivElement, AtomixGlassContai
|
|
|
147
170
|
|
|
148
171
|
// Use shared module-level cache (no per-instance cache needed)
|
|
149
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);
|
|
150
177
|
|
|
151
178
|
// Lazy load shader utilities only when shader mode is needed
|
|
152
179
|
useEffect(() => {
|
|
153
180
|
if (mode === 'shader') {
|
|
154
|
-
// Dynamic import shader utilities
|
|
181
|
+
// Dynamic import shader utilities with animation support
|
|
155
182
|
import('./shader-utils')
|
|
156
183
|
.then(shaderUtils => {
|
|
157
184
|
shaderUtilsRef.current = {
|
|
@@ -174,12 +201,7 @@ export const AtomixGlassContainer = forwardRef<HTMLDivElement, AtomixGlassContai
|
|
|
174
201
|
// Generate shader map with debouncing and caching
|
|
175
202
|
useEffect(() => {
|
|
176
203
|
// Enhanced validation for shader mode
|
|
177
|
-
if (
|
|
178
|
-
mode === 'shader' &&
|
|
179
|
-
glassSize &&
|
|
180
|
-
validateGlassSize(glassSize) &&
|
|
181
|
-
shaderUtilsRef.current
|
|
182
|
-
) {
|
|
204
|
+
if (mode === 'shader' && glassSize && validateGlassSize(glassSize)) {
|
|
183
205
|
// Create cache key from size and variant
|
|
184
206
|
const cacheKey = `${glassSize.width}x${glassSize.height}-${shaderVariant}`;
|
|
185
207
|
|
|
@@ -213,10 +235,11 @@ export const AtomixGlassContainer = forwardRef<HTMLDivElement, AtomixGlassContai
|
|
|
213
235
|
fragment: selectedShader,
|
|
214
236
|
});
|
|
215
237
|
|
|
216
|
-
|
|
217
|
-
setTimeout(() => {
|
|
238
|
+
shaderUpdateTimeoutRef.current = setTimeout(() => {
|
|
218
239
|
const url = shaderGeneratorRef.current?.updateShader() || '';
|
|
219
|
-
|
|
240
|
+
if (url) {
|
|
241
|
+
setCachedShader(cacheKey, url);
|
|
242
|
+
}
|
|
220
243
|
setShaderMapUrl(url);
|
|
221
244
|
}, 100);
|
|
222
245
|
} catch (error) {
|
|
@@ -238,6 +261,10 @@ export const AtomixGlassContainer = forwardRef<HTMLDivElement, AtomixGlassContai
|
|
|
238
261
|
clearTimeout(shaderDebounceTimeoutRef.current);
|
|
239
262
|
shaderDebounceTimeoutRef.current = null;
|
|
240
263
|
}
|
|
264
|
+
if (shaderUpdateTimeoutRef.current) {
|
|
265
|
+
clearTimeout(shaderUpdateTimeoutRef.current);
|
|
266
|
+
shaderUpdateTimeoutRef.current = null;
|
|
267
|
+
}
|
|
241
268
|
try {
|
|
242
269
|
shaderGeneratorRef.current?.destroy();
|
|
243
270
|
} catch (error) {
|
|
@@ -248,6 +275,92 @@ export const AtomixGlassContainer = forwardRef<HTMLDivElement, AtomixGlassContai
|
|
|
248
275
|
};
|
|
249
276
|
}, [mode, glassSize, shaderVariant]);
|
|
250
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
|
+
|
|
251
364
|
// Removed forced reflow to avoid layout thrash and potential feedback sizing loops
|
|
252
365
|
|
|
253
366
|
const [rectCache, setRectCache] = useState<DOMRect | null>(null);
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import React, { useMemo } from 'react';
|
|
2
|
+
import type { PerformanceMetrics } from '../../lib/composables/usePerformanceMonitor';
|
|
3
|
+
|
|
4
|
+
interface PerformanceDashboardProps {
|
|
5
|
+
metrics: PerformanceMetrics;
|
|
6
|
+
isVisible?: boolean;
|
|
7
|
+
onClose?: () => void;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* PerformanceDashboard - Real-time performance monitoring overlay
|
|
12
|
+
*
|
|
13
|
+
* Displays:
|
|
14
|
+
* - Current FPS with color coding
|
|
15
|
+
* - Frame time statistics
|
|
16
|
+
* - Quality level indicator
|
|
17
|
+
* - GPU memory usage (if available)
|
|
18
|
+
* - Auto-scaling status
|
|
19
|
+
*/
|
|
20
|
+
export const PerformanceDashboard: React.FC<PerformanceDashboardProps> = ({
|
|
21
|
+
metrics,
|
|
22
|
+
isVisible = true,
|
|
23
|
+
onClose
|
|
24
|
+
}) => {
|
|
25
|
+
// Get color for FPS display
|
|
26
|
+
const getFpsColor = (fps: number): string => {
|
|
27
|
+
if (fps >= 58) return '#4ade80'; // Green - good
|
|
28
|
+
if (fps >= 45) return '#fbbf24'; // Yellow - warning
|
|
29
|
+
return '#ef4444'; // Red - critical
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// Get quality level badge color
|
|
33
|
+
const getQualityColor = (quality: string): string => {
|
|
34
|
+
switch (quality) {
|
|
35
|
+
case 'high': return '#4ade80';
|
|
36
|
+
case 'medium': return '#fbbf24';
|
|
37
|
+
case 'low': return '#ef4444';
|
|
38
|
+
default: return '#9ca3af';
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// Dashboard styles
|
|
43
|
+
const dashboardStyle: React.CSSProperties = useMemo(() => ({
|
|
44
|
+
position: 'fixed',
|
|
45
|
+
top: '16px',
|
|
46
|
+
right: '16px',
|
|
47
|
+
padding: '12px 16px',
|
|
48
|
+
backgroundColor: 'rgba(17, 24, 39, 0.95)',
|
|
49
|
+
borderRadius: '8px',
|
|
50
|
+
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)',
|
|
51
|
+
fontFamily: 'monospace',
|
|
52
|
+
fontSize: '12px',
|
|
53
|
+
color: '#fff',
|
|
54
|
+
zIndex: 9999,
|
|
55
|
+
minWidth: '200px',
|
|
56
|
+
backdropFilter: 'blur(8px)',
|
|
57
|
+
border: '1px solid rgba(255, 255, 255, 0.1)',
|
|
58
|
+
transition: 'opacity 0.3s ease',
|
|
59
|
+
opacity: isVisible ? 1 : 0,
|
|
60
|
+
pointerEvents: isVisible ? 'auto' : 'none',
|
|
61
|
+
}), [isVisible]);
|
|
62
|
+
|
|
63
|
+
const headerStyle: React.CSSProperties = useMemo(() => ({
|
|
64
|
+
display: 'flex',
|
|
65
|
+
justifyContent: 'space-between',
|
|
66
|
+
alignItems: 'center',
|
|
67
|
+
marginBottom: '8px',
|
|
68
|
+
paddingBottom: '8px',
|
|
69
|
+
borderBottom: '1px solid rgba(255, 255, 255, 0.1)',
|
|
70
|
+
}), []);
|
|
71
|
+
|
|
72
|
+
const titleStyle: React.CSSProperties = useMemo(() => ({
|
|
73
|
+
fontWeight: 'bold',
|
|
74
|
+
fontSize: '13px',
|
|
75
|
+
color: '#fff',
|
|
76
|
+
}), []);
|
|
77
|
+
|
|
78
|
+
const closeButtonStyle: React.CSSProperties = useMemo(() => ({
|
|
79
|
+
background: 'transparent',
|
|
80
|
+
border: 'none',
|
|
81
|
+
color: '#9ca3af',
|
|
82
|
+
cursor: 'pointer',
|
|
83
|
+
fontSize: '16px',
|
|
84
|
+
padding: '0',
|
|
85
|
+
lineHeight: '1',
|
|
86
|
+
}), []);
|
|
87
|
+
|
|
88
|
+
const metricRowStyle: React.CSSProperties = useMemo(() => ({
|
|
89
|
+
display: 'flex',
|
|
90
|
+
justifyContent: 'space-between',
|
|
91
|
+
alignItems: 'center',
|
|
92
|
+
marginBottom: '6px',
|
|
93
|
+
}), []);
|
|
94
|
+
|
|
95
|
+
const labelStyle: React.CSSProperties = useMemo(() => ({
|
|
96
|
+
color: '#9ca3af',
|
|
97
|
+
marginRight: '12px',
|
|
98
|
+
}), []);
|
|
99
|
+
|
|
100
|
+
const valueStyle: React.CSSProperties = useMemo(() => ({
|
|
101
|
+
fontWeight: 'bold',
|
|
102
|
+
}), []);
|
|
103
|
+
|
|
104
|
+
if (!isVisible) return null;
|
|
105
|
+
|
|
106
|
+
return (
|
|
107
|
+
<div style={dashboardStyle}>
|
|
108
|
+
{/* Header */}
|
|
109
|
+
<div style={headerStyle}>
|
|
110
|
+
<span style={titleStyle}>Performance Monitor</span>
|
|
111
|
+
{onClose && (
|
|
112
|
+
<button
|
|
113
|
+
style={closeButtonStyle}
|
|
114
|
+
onClick={onClose}
|
|
115
|
+
aria-label="Close performance dashboard"
|
|
116
|
+
>
|
|
117
|
+
×
|
|
118
|
+
</button>
|
|
119
|
+
)}
|
|
120
|
+
</div>
|
|
121
|
+
|
|
122
|
+
{/* FPS Display */}
|
|
123
|
+
<div style={metricRowStyle}>
|
|
124
|
+
<span style={labelStyle}>FPS</span>
|
|
125
|
+
<span
|
|
126
|
+
style={{
|
|
127
|
+
...valueStyle,
|
|
128
|
+
color: getFpsColor(metrics.fps)
|
|
129
|
+
}}
|
|
130
|
+
>
|
|
131
|
+
{Math.round(metrics.fps)}
|
|
132
|
+
</span>
|
|
133
|
+
</div>
|
|
134
|
+
|
|
135
|
+
{/* Frame Time */}
|
|
136
|
+
<div style={metricRowStyle}>
|
|
137
|
+
<span style={labelStyle}>Frame Time</span>
|
|
138
|
+
<span style={valueStyle}>
|
|
139
|
+
{metrics.frameTime.toFixed(2)}ms
|
|
140
|
+
</span>
|
|
141
|
+
</div>
|
|
142
|
+
|
|
143
|
+
{/* Quality Level */}
|
|
144
|
+
<div style={metricRowStyle}>
|
|
145
|
+
<span style={labelStyle}>Quality</span>
|
|
146
|
+
<span
|
|
147
|
+
style={{
|
|
148
|
+
...valueStyle,
|
|
149
|
+
color: getQualityColor(metrics.qualityLevel),
|
|
150
|
+
textTransform: 'uppercase',
|
|
151
|
+
fontSize: '11px',
|
|
152
|
+
}}
|
|
153
|
+
>
|
|
154
|
+
{metrics.qualityLevel}
|
|
155
|
+
</span>
|
|
156
|
+
</div>
|
|
157
|
+
|
|
158
|
+
{/* GPU Memory (if available) */}
|
|
159
|
+
{metrics.gpuMemory && (
|
|
160
|
+
<div style={metricRowStyle}>
|
|
161
|
+
<span style={labelStyle}>GPU Memory</span>
|
|
162
|
+
<span style={valueStyle}>
|
|
163
|
+
~{Math.round(metrics.gpuMemory / 1024)}MB
|
|
164
|
+
</span>
|
|
165
|
+
</div>
|
|
166
|
+
)}
|
|
167
|
+
|
|
168
|
+
{/* Auto-scaling Status */}
|
|
169
|
+
{metrics.isAutoScaling && (
|
|
170
|
+
<div style={{
|
|
171
|
+
marginTop: '8px',
|
|
172
|
+
paddingTop: '8px',
|
|
173
|
+
borderTop: '1px solid rgba(255, 255, 255, 0.1)',
|
|
174
|
+
fontSize: '10px',
|
|
175
|
+
color: '#6b7280',
|
|
176
|
+
textAlign: 'center',
|
|
177
|
+
}}>
|
|
178
|
+
Auto-scaling active
|
|
179
|
+
</div>
|
|
180
|
+
)}
|
|
181
|
+
|
|
182
|
+
{/* Performance Status Indicator */}
|
|
183
|
+
<div style={{
|
|
184
|
+
marginTop: '8px',
|
|
185
|
+
paddingTop: '8px',
|
|
186
|
+
borderTop: '1px solid rgba(255, 255, 255, 0.1)',
|
|
187
|
+
display: 'flex',
|
|
188
|
+
alignItems: 'center',
|
|
189
|
+
gap: '6px',
|
|
190
|
+
}}>
|
|
191
|
+
<div style={{
|
|
192
|
+
width: '8px',
|
|
193
|
+
height: '8px',
|
|
194
|
+
borderRadius: '50%',
|
|
195
|
+
backgroundColor: getFpsColor(metrics.fps),
|
|
196
|
+
animation: metrics.fps < 45 ? 'pulse 1s infinite' : 'none',
|
|
197
|
+
}} />
|
|
198
|
+
<span style={{
|
|
199
|
+
fontSize: '10px',
|
|
200
|
+
color: metrics.fps >= 58 ? '#4ade80' : metrics.fps >= 45 ? '#fbbf24' : '#ef4444',
|
|
201
|
+
}}>
|
|
202
|
+
{metrics.fps >= 58 ? 'Optimal' : metrics.fps >= 45 ? 'Warning' : 'Critical'}
|
|
203
|
+
</span>
|
|
204
|
+
</div>
|
|
205
|
+
</div>
|
|
206
|
+
);
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
// Add pulse animation for critical FPS
|
|
210
|
+
if (typeof document !== 'undefined') {
|
|
211
|
+
const styleSheet = document.createElement('style');
|
|
212
|
+
styleSheet.textContent = `
|
|
213
|
+
@keyframes pulse {
|
|
214
|
+
0%, 100% { opacity: 1; }
|
|
215
|
+
50% { opacity: 0.5; }
|
|
216
|
+
}
|
|
217
|
+
`;
|
|
218
|
+
document.head.appendChild(styleSheet);
|
|
219
|
+
}
|
|
@@ -40,25 +40,38 @@ function MyComponent() {
|
|
|
40
40
|
| Prop | Type | Default | Description |
|
|
41
41
|
|------|------|---------|-------------|
|
|
42
42
|
| `children` | ReactNode | - | Content to be rendered inside the glass container |
|
|
43
|
-
| `displacementScale` | number |
|
|
44
|
-
| `blurAmount` | number |
|
|
45
|
-
| `saturation` | number |
|
|
46
|
-
| `aberrationIntensity` | number |
|
|
47
|
-
| `elasticity` | number | 0.
|
|
43
|
+
| `displacementScale` | number | 70 | Controls the intensity of the displacement effect |
|
|
44
|
+
| `blurAmount` | number | 0 | Controls the intensity of the blur effect |
|
|
45
|
+
| `saturation` | number | 140 | Controls the color saturation (100 is normal) |
|
|
46
|
+
| `aberrationIntensity` | number | 2 | Controls the chromatic aberration effect intensity |
|
|
47
|
+
| `elasticity` | number | 0.15 | Controls how responsive the glass is to mouse movement |
|
|
48
48
|
| `borderRadius` | number | 15 | Border radius of the glass container |
|
|
49
49
|
| `globalMousePos` | boolean | false | Whether to use global mouse position instead of local |
|
|
50
50
|
| `mouseOffset` | { x: number, y: number } | { x: 0, y: 0 } | Offset for mouse position calculation |
|
|
51
51
|
| `mouseContainer` | RefObject<HTMLElement> | null | Container to use for mouse position calculation |
|
|
52
|
-
| `padding` |
|
|
52
|
+
| `padding` | string | '0' | Additional padding around the content |
|
|
53
|
+
| `height` | string \| number | undefined | Height of the glass component |
|
|
54
|
+
| `width` | string \| number | undefined | Width of the glass component |
|
|
53
55
|
| `style` | CSSProperties | {} | Additional CSS styles |
|
|
54
56
|
| `overLight` | boolean \| 'auto' \| OverLightObjectConfig | 'auto' | OverLight configuration. See [OverLight Configuration](#overlight-configuration) section for details |
|
|
55
57
|
| `withOverLightLayers` | boolean | true | Whether to render additional overlay layers for overLight mode |
|
|
56
58
|
| `debugOverLight` | boolean | false | Enable debug logging for overLight detection and configuration |
|
|
57
59
|
| `mode` | 'standard' \| 'polar' \| 'prominent' \| 'shader' | 'standard' | The glass effect mode |
|
|
58
60
|
| `onClick` | function | undefined | Click handler |
|
|
59
|
-
| `
|
|
60
|
-
| `
|
|
61
|
-
| `
|
|
61
|
+
| `withBorder` | boolean | true | Whether to show border effects |
|
|
62
|
+
| `withLiquidBlur` | boolean | false | Whether to enable liquid blur effects |
|
|
63
|
+
| `withoutEffects` | boolean | false | Whether to disable all visual effects |
|
|
64
|
+
| `reducedMotion` | boolean | false | Force reduced motion preference |
|
|
65
|
+
| `highContrast` | boolean | false | Force high contrast mode |
|
|
66
|
+
| `withTimeAnimation` | boolean | true | Enable time-based animation (Phase 1) |
|
|
67
|
+
| `animationSpeed` | number | 1.0 | Animation speed multiplier (Phase 1) |
|
|
68
|
+
| `withMultiLayerDistortion` | boolean | false | Enable multi-layer distortion using FBM (Phase 1) |
|
|
69
|
+
| `distortionOctaves` | number | 5 | Number of octaves for FBM (Phase 1) |
|
|
70
|
+
| `distortionLacunarity` | number | 2.0 | Lacunarity for FBM (Phase 1) |
|
|
71
|
+
| `distortionGain` | number | 0.5 | Gain for FBM (Phase 1) |
|
|
72
|
+
| `distortionQuality` | 'low' \| 'medium' \| 'high' \| 'ultra' | 'high' | Quality preset for FBM (Phase 1) |
|
|
73
|
+
| `debugPerformance` | boolean | false | Enable performance monitoring dashboard (development only) |
|
|
74
|
+
| `debugBorderRadius` | boolean | false | Debug mode for corner radius extraction |
|
|
62
75
|
|
|
63
76
|
## Glass Effect Modes
|
|
64
77
|
|
|
@@ -80,8 +93,10 @@ The AtomixGlass component uses several advanced CSS features and SVG filters tha
|
|
|
80
93
|
|
|
81
94
|
1. Use sparingly on pages with many instances
|
|
82
95
|
2. Consider disabling effects on lower-end devices
|
|
83
|
-
3. Use the `
|
|
96
|
+
3. Use the `withoutEffects` prop to disable non-essential effects when needed
|
|
84
97
|
4. Avoid using very high values for `displacementScale` and `blurAmount`
|
|
98
|
+
5. Use `reducedMotion` for users with vestibular disorders
|
|
99
|
+
6. Consider using lower `distortionQuality` presets on mobile devices
|
|
85
100
|
|
|
86
101
|
## Accessibility
|
|
87
102
|
|