@shohojdhara/atomix 0.4.9 → 0.5.1

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 (67) hide show
  1. package/dist/atomix.css +95 -69
  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/charts.d.ts +1 -0
  6. package/dist/charts.js +231 -332
  7. package/dist/charts.js.map +1 -1
  8. package/dist/core.d.ts +1 -0
  9. package/dist/core.js +232 -333
  10. package/dist/core.js.map +1 -1
  11. package/dist/forms.d.ts +1 -0
  12. package/dist/forms.js +231 -332
  13. package/dist/forms.js.map +1 -1
  14. package/dist/heavy.d.ts +11 -2
  15. package/dist/heavy.js +233 -334
  16. package/dist/heavy.js.map +1 -1
  17. package/dist/index.d.ts +13 -2
  18. package/dist/index.esm.js +228 -327
  19. package/dist/index.esm.js.map +1 -1
  20. package/dist/index.js +227 -326
  21. package/dist/index.js.map +1 -1
  22. package/dist/index.min.js +1 -1
  23. package/dist/index.min.js.map +1 -1
  24. package/package.json +11 -1
  25. package/src/components/AtomixGlass/AtomixGlass.tsx +188 -128
  26. package/src/components/AtomixGlass/AtomixGlassContainer.tsx +62 -90
  27. package/src/components/AtomixGlass/PerformanceDashboard.tsx +153 -201
  28. package/src/components/AtomixGlass/glass-utils.ts +50 -0
  29. package/src/components/AtomixGlass/shader-utils.ts +1 -1
  30. package/src/components/AtomixGlass/stories/{Phase1-Animation.stories.tsx → AnimationFeatures.stories.tsx} +53 -47
  31. package/src/components/AtomixGlass/stories/Examples.stories.tsx +573 -236
  32. package/src/components/AtomixGlass/stories/Playground.stories.tsx +656 -44
  33. package/src/components/AtomixGlass/stories/argTypes.ts +384 -0
  34. package/src/components/AtomixGlass/stories/shared-components.tsx +82 -3
  35. package/src/components/AtomixGlass/stories/types.ts +127 -0
  36. package/src/lib/composables/useAtomixGlass.ts +108 -71
  37. package/src/lib/composables/useAtomixGlassStyles.ts +0 -2
  38. package/src/lib/constants/components.ts +1 -0
  39. package/src/lib/types/components.ts +1 -0
  40. package/src/lib/utils/displacement-generator.ts +1 -1
  41. package/src/styles/06-components/_components.atomix-glass.scss +158 -97
  42. package/scripts/cli/__tests__/README.md +0 -81
  43. package/scripts/cli/__tests__/basic.test.js +0 -116
  44. package/scripts/cli/__tests__/clean.test.js +0 -278
  45. package/scripts/cli/__tests__/component-generator.test.js +0 -332
  46. package/scripts/cli/__tests__/component-validator.test.js +0 -433
  47. package/scripts/cli/__tests__/generator.test.js +0 -613
  48. package/scripts/cli/__tests__/glass-motion.test.js +0 -256
  49. package/scripts/cli/__tests__/integration.test.js +0 -938
  50. package/scripts/cli/__tests__/migrate.test.js +0 -74
  51. package/scripts/cli/__tests__/security.test.js +0 -206
  52. package/scripts/cli/__tests__/test-setup.js +0 -135
  53. package/scripts/cli/__tests__/theme-bridge.test.js +0 -507
  54. package/scripts/cli/__tests__/token-manager.test.js +0 -251
  55. package/scripts/cli/__tests__/token-provider.test.js +0 -361
  56. package/scripts/cli/__tests__/utils.test.js +0 -165
  57. package/src/components/AtomixGlass/__snapshots__/AtomixGlass.test.tsx.snap +0 -216
  58. package/src/components/AtomixGlass/stories/Customization.stories.tsx +0 -131
  59. package/src/components/AtomixGlass/stories/Modes.stories.tsx +0 -1082
  60. package/src/components/AtomixGlass/stories/Overview.stories.tsx +0 -497
  61. package/src/components/AtomixGlass/stories/Performance.stories.tsx +0 -103
  62. package/src/components/AtomixGlass/stories/Phase1-Test.stories.tsx +0 -95
  63. package/src/components/AtomixGlass/stories/Shaders.stories.tsx +0 -395
  64. package/src/components/TypedButton/TypedButton.stories.tsx +0 -59
  65. package/src/components/TypedButton/TypedButton.tsx +0 -39
  66. package/src/components/TypedButton/index.ts +0 -2
  67. package/src/lib/composables/useTypedButton.ts +0 -66
@@ -253,7 +253,7 @@ const BackgroundWrapper = ({
253
253
  <div
254
254
  key={bg.url}
255
255
  style={{
256
- position: 'absolute',
256
+ position: 'fixed',
257
257
  inset: 0,
258
258
  backgroundImage: `url(${bg.url})`,
259
259
  backgroundSize: 'cover',
@@ -289,7 +289,31 @@ const BackgroundWrapper = ({
289
289
  export const Playground: Story = {
290
290
  render: () => {
291
291
  // eslint-disable-next-line react-hooks/rules-of-hooks
292
- const [settings, setSettings] = useState({
292
+ const [settings, setSettings] = useState<{
293
+ displacementScale: number;
294
+ blurAmount: number;
295
+ saturation: number;
296
+ aberrationIntensity: number;
297
+ elasticity: number;
298
+ borderRadius: number;
299
+ overLight: boolean;
300
+ reducedMotion: boolean;
301
+ highContrast: boolean;
302
+ withoutEffects: boolean;
303
+ withLiquidBlur: boolean;
304
+ withBorder: boolean;
305
+ withTimeAnimation: boolean;
306
+ animationSpeed: number;
307
+ withMultiLayerDistortion: boolean;
308
+ distortionOctaves: number;
309
+ distortionLacunarity: number;
310
+ distortionGain: number;
311
+ distortionQuality: 'low' | 'medium' | 'high' | 'ultra';
312
+ devicePreset: 'performance' | 'balanced' | 'quality';
313
+ disableResponsiveBreakpoints: boolean;
314
+ debugPerformance: boolean;
315
+ debugOverLight: boolean;
316
+ }>({
293
317
  displacementScale: 40,
294
318
  blurAmount: 1,
295
319
  saturation: 140,
@@ -302,6 +326,17 @@ export const Playground: Story = {
302
326
  withoutEffects: false,
303
327
  withLiquidBlur: false,
304
328
  withBorder: true,
329
+ withTimeAnimation: true,
330
+ animationSpeed: 1.0,
331
+ withMultiLayerDistortion: false,
332
+ distortionOctaves: 3,
333
+ distortionLacunarity: 2.0,
334
+ distortionGain: 0.5,
335
+ distortionQuality: 'medium',
336
+ devicePreset: 'balanced',
337
+ disableResponsiveBreakpoints: false,
338
+ debugPerformance: false,
339
+ debugOverLight: false,
305
340
  });
306
341
 
307
342
  // eslint-disable-next-line react-hooks/rules-of-hooks
@@ -325,7 +360,9 @@ export const Playground: Story = {
325
360
  // eslint-disable-next-line react-hooks/rules-of-hooks
326
361
  const [copiedCode, setCopiedCode] = useState(false);
327
362
  // eslint-disable-next-line react-hooks/rules-of-hooks
328
- const [controlTab, setControlTab] = useState<'optics' | 'physics' | 'flags'>('optics');
363
+ const [controlTab, setControlTab] = useState<'optics' | 'animation' | 'responsive' | 'flags'>(
364
+ 'optics'
365
+ );
329
366
  // eslint-disable-next-line react-hooks/rules-of-hooks
330
367
  const backgroundsArrayRef = useRef<typeof backgrounds | null>(null);
331
368
 
@@ -346,6 +383,17 @@ export const Playground: Story = {
346
383
  withoutEffects: false,
347
384
  withLiquidBlur: false,
348
385
  withBorder: true,
386
+ withTimeAnimation: false,
387
+ animationSpeed: 1.0,
388
+ withMultiLayerDistortion: false,
389
+ distortionOctaves: 3,
390
+ distortionLacunarity: 2.0,
391
+ distortionGain: 0.5,
392
+ distortionQuality: 'medium' as const,
393
+ devicePreset: 'balanced' as const,
394
+ disableResponsiveBreakpoints: false,
395
+ debugPerformance: false,
396
+ debugOverLight: false,
349
397
  },
350
398
  mode: 'standard' as const,
351
399
  shader: 'liquidGlass' as const,
@@ -366,6 +414,17 @@ export const Playground: Story = {
366
414
  withoutEffects: false,
367
415
  withLiquidBlur: false,
368
416
  withBorder: true,
417
+ withTimeAnimation: true,
418
+ animationSpeed: 1.0,
419
+ withMultiLayerDistortion: false,
420
+ distortionOctaves: 3,
421
+ distortionLacunarity: 2.0,
422
+ distortionGain: 0.5,
423
+ distortionQuality: 'medium' as const,
424
+ devicePreset: 'balanced' as const,
425
+ disableResponsiveBreakpoints: false,
426
+ debugPerformance: false,
427
+ debugOverLight: false,
369
428
  },
370
429
  mode: 'standard' as const,
371
430
  shader: 'liquidGlass' as const,
@@ -386,6 +445,17 @@ export const Playground: Story = {
386
445
  withoutEffects: false,
387
446
  withLiquidBlur: true,
388
447
  withBorder: true,
448
+ withTimeAnimation: true,
449
+ animationSpeed: 1.2,
450
+ withMultiLayerDistortion: true,
451
+ distortionOctaves: 5,
452
+ distortionLacunarity: 2.5,
453
+ distortionGain: 0.6,
454
+ distortionQuality: 'high' as const,
455
+ devicePreset: 'quality' as const,
456
+ disableResponsiveBreakpoints: false,
457
+ debugPerformance: false,
458
+ debugOverLight: false,
389
459
  },
390
460
  mode: 'prominent' as const,
391
461
  shader: 'plasma' as const,
@@ -406,6 +476,17 @@ export const Playground: Story = {
406
476
  withoutEffects: false,
407
477
  withLiquidBlur: true,
408
478
  withBorder: true,
479
+ withTimeAnimation: true,
480
+ animationSpeed: 1.5,
481
+ withMultiLayerDistortion: true,
482
+ distortionOctaves: 6,
483
+ distortionLacunarity: 3.0,
484
+ distortionGain: 0.7,
485
+ distortionQuality: 'ultra' as const,
486
+ devicePreset: 'quality' as const,
487
+ disableResponsiveBreakpoints: false,
488
+ debugPerformance: false,
489
+ debugOverLight: false,
409
490
  },
410
491
  mode: 'shader' as const,
411
492
  shader: 'waves' as const,
@@ -435,6 +516,15 @@ export const Playground: Story = {
435
516
  withoutEffects={${settings.withoutEffects}}
436
517
  withLiquidBlur={${settings.withLiquidBlur}}
437
518
  withBorder={${settings.withBorder}}
519
+ withTimeAnimation={${settings.withTimeAnimation}}
520
+ animationSpeed={${settings.animationSpeed}}
521
+ withMultiLayerDistortion={${settings.withMultiLayerDistortion}}
522
+ distortionOctaves={${settings.distortionOctaves}}
523
+ distortionLacunarity={${settings.distortionLacunarity}}
524
+ distortionGain={${settings.distortionGain}}
525
+ distortionQuality="${settings.distortionQuality}"
526
+ devicePreset="${settings.devicePreset}"
527
+ disableResponsiveBreakpoints={${settings.disableResponsiveBreakpoints}}
438
528
  >
439
529
  <div className="your-content">
440
530
  {/* Your content here */}
@@ -851,7 +941,7 @@ export const Playground: Story = {
851
941
  border: '1px solid rgba(255,255,255,0.1)',
852
942
  }}
853
943
  >
854
- {(['optics', 'physics', 'flags'] as const).map(tab => (
944
+ {(['optics', 'animation', 'responsive', 'flags'] as const).map(tab => (
855
945
  <button
856
946
  key={tab}
857
947
  onClick={() => setControlTab(tab)}
@@ -968,69 +1058,190 @@ export const Playground: Story = {
968
1058
  </div>
969
1059
  )}
970
1060
 
971
- {/* === CONTROLS: PHYSICS === */}
972
- {controlTab === 'physics' && (
973
- <div className="u-mb-4 u-animation-fade-in">
974
- <div className="u-flex u-items-center u-gap-2 u-mb-3">
975
- <div
976
- style={{
977
- width: '3px',
978
- height: '14px',
979
- background: 'linear-gradient(180deg, #a78bfa 0%, #ec4899 100%)',
980
- borderRadius: '2px',
981
- flexShrink: 0,
982
- }}
983
- />
984
- <span
985
- className="u-text-xs u-font-bold u-opacity-60"
986
- style={{ letterSpacing: '1px', textTransform: 'uppercase' }}
987
- >
988
- Physics
989
- </span>
1061
+ {/* === CONTROLS: ANIMATION (PHASE 1) === */}
1062
+ {controlTab === 'animation' && (
1063
+ <>
1064
+ <div className="u-mb-4 u-animation-fade-in">
1065
+ <div className="u-flex u-items-center u-gap-2 u-mb-3">
1066
+ <div
1067
+ style={{
1068
+ width: '3px',
1069
+ height: '14px',
1070
+ background: 'linear-gradient(180deg, #a78bfa 0%, #ec4899 100%)',
1071
+ borderRadius: '2px',
1072
+ flexShrink: 0,
1073
+ }}
1074
+ />
1075
+ <span
1076
+ className="u-text-xs u-font-bold u-opacity-60"
1077
+ style={{ letterSpacing: '1px', textTransform: 'uppercase' }}
1078
+ >
1079
+ Physics
1080
+ </span>
1081
+ </div>
1082
+ {(['elasticity', 'borderRadius'] as const).map(key => {
1083
+ const value = settings[key];
1084
+ const max = key === 'borderRadius' ? 100 : 1;
1085
+ const step = key === 'elasticity' ? 0.01 : 1;
1086
+ const label = key
1087
+ .replace(/([A-Z])/g, ' $1')
1088
+ .replace(/^./, s => s.toUpperCase());
1089
+ return (
1090
+ <div key={key} className="u-mb-4">
1091
+ <div className="u-flex u-justify-between u-items-baseline u-mb-1">
1092
+ <label className="u-text-xs u-font-medium u-opacity-80">
1093
+ {label}
1094
+ </label>
1095
+ <span
1096
+ className="u-text-xs u-font-bold u-px-2 u-py-1 u-rounded"
1097
+ style={{
1098
+ background: 'rgba(167,139,250,0.12)',
1099
+ color: '#a78bfa',
1100
+ fontVariantNumeric: 'tabular-nums',
1101
+ minWidth: '40px',
1102
+ textAlign: 'center',
1103
+ }}
1104
+ >
1105
+ {(value as number).toFixed(key === 'elasticity' ? 2 : 0)}
1106
+ </span>
1107
+ </div>
1108
+ <div className="u-relative" style={{ height: '20px' }}>
1109
+ <input
1110
+ type="range"
1111
+ min={0}
1112
+ max={max}
1113
+ step={step}
1114
+ value={value as number}
1115
+ onChange={e =>
1116
+ setSettings(prev => ({
1117
+ ...prev,
1118
+ [key]: parseFloat(e.target.value),
1119
+ }))
1120
+ }
1121
+ className="premium-slider u-absolute u-w-100 u-m-0"
1122
+ style={{
1123
+ height: '2px',
1124
+ background: `linear-gradient(to right, #a78bfa ${((value as number) / max) * 100}%, rgba(255,255,255,0.15) ${((value as number) / max) * 100}%)`,
1125
+ borderRadius: '2px',
1126
+ outline: 'none',
1127
+ appearance: 'none',
1128
+ WebkitAppearance: 'none',
1129
+ top: '50%',
1130
+ transform: 'translateY(-50%)',
1131
+ }}
1132
+ />
1133
+ </div>
1134
+ </div>
1135
+ );
1136
+ })}
990
1137
  </div>
991
- {(['elasticity', 'borderRadius'] as const).map(key => {
992
- const value = settings[key];
993
- const max = key === 'borderRadius' ? 100 : 1;
994
- const step = key === 'elasticity' ? 0.01 : 1;
995
- const label = key
996
- .replace(/([A-Z])/g, ' $1')
997
- .replace(/^./, s => s.toUpperCase());
998
- return (
999
- <div key={key} className="u-mb-4">
1138
+
1139
+ {/* Animation System Controls */}
1140
+ <div className="u-mb-4 u-animation-fade-in">
1141
+ <div className="u-flex u-items-center u-gap-2 u-mb-3">
1142
+ <div
1143
+ style={{
1144
+ width: '3px',
1145
+ height: '14px',
1146
+ background: 'linear-gradient(180deg, #f472b6 0%, #a78bfa 100%)',
1147
+ borderRadius: '2px',
1148
+ flexShrink: 0,
1149
+ }}
1150
+ />
1151
+ <span
1152
+ className="u-text-xs u-font-bold u-opacity-60"
1153
+ style={{ letterSpacing: '1px', textTransform: 'uppercase' }}
1154
+ >
1155
+ Animation System
1156
+ </span>
1157
+ </div>
1158
+
1159
+ {/* Time Animation Toggle */}
1160
+ <div className="u-mb-3">
1161
+ <button
1162
+ onClick={() =>
1163
+ setSettings(prev => ({
1164
+ ...prev,
1165
+ withTimeAnimation: !prev.withTimeAnimation,
1166
+ }))
1167
+ }
1168
+ className="u-flex u-items-center u-gap-2 u-px-3 u-py-2 u-rounded u-text-start u-w-100"
1169
+ style={{
1170
+ background: settings.withTimeAnimation
1171
+ ? 'rgba(244,114,182,0.15)'
1172
+ : 'rgba(255,255,255,0.04)',
1173
+ border: settings.withTimeAnimation
1174
+ ? '1px solid rgba(244,114,182,0.45)'
1175
+ : '1px solid rgba(255,255,255,0.1)',
1176
+ cursor: 'pointer',
1177
+ transition: 'all 0.2s',
1178
+ }}
1179
+ >
1180
+ <div
1181
+ style={{
1182
+ width: '10px',
1183
+ height: '10px',
1184
+ borderRadius: '50%',
1185
+ background: settings.withTimeAnimation
1186
+ ? '#f472b6'
1187
+ : 'rgba(255,255,255,0.2)',
1188
+ flexShrink: 0,
1189
+ boxShadow: settings.withTimeAnimation
1190
+ ? '0 0 8px rgba(244,114,182,0.6)'
1191
+ : 'none',
1192
+ }}
1193
+ />
1194
+ <span
1195
+ className="u-text-xs u-font-medium"
1196
+ style={{
1197
+ color: settings.withTimeAnimation
1198
+ ? '#f472b6'
1199
+ : 'rgba(255,255,255,0.6)',
1200
+ flex: 1,
1201
+ }}
1202
+ >
1203
+ Time Animation
1204
+ </span>
1205
+ </button>
1206
+ </div>
1207
+
1208
+ {/* Animation Speed */}
1209
+ {settings.withTimeAnimation && (
1210
+ <div className="u-mb-4">
1000
1211
  <div className="u-flex u-justify-between u-items-baseline u-mb-1">
1001
1212
  <label className="u-text-xs u-font-medium u-opacity-80">
1002
- {label}
1213
+ Animation Speed
1003
1214
  </label>
1004
1215
  <span
1005
1216
  className="u-text-xs u-font-bold u-px-2 u-py-1 u-rounded"
1006
1217
  style={{
1007
- background: 'rgba(167,139,250,0.12)',
1008
- color: '#a78bfa',
1218
+ background: 'rgba(244,114,182,0.12)',
1219
+ color: '#f472b6',
1009
1220
  fontVariantNumeric: 'tabular-nums',
1010
1221
  minWidth: '40px',
1011
1222
  textAlign: 'center',
1012
1223
  }}
1013
1224
  >
1014
- {(value as number).toFixed(key === 'elasticity' ? 2 : 0)}
1225
+ {settings.animationSpeed.toFixed(1)}x
1015
1226
  </span>
1016
1227
  </div>
1017
1228
  <div className="u-relative" style={{ height: '20px' }}>
1018
1229
  <input
1019
1230
  type="range"
1020
1231
  min={0}
1021
- max={max}
1022
- step={step}
1023
- value={value as number}
1232
+ max={3}
1233
+ step={0.1}
1234
+ value={settings.animationSpeed}
1024
1235
  onChange={e =>
1025
1236
  setSettings(prev => ({
1026
1237
  ...prev,
1027
- [key]: parseFloat(e.target.value),
1238
+ animationSpeed: parseFloat(e.target.value),
1028
1239
  }))
1029
1240
  }
1030
1241
  className="premium-slider u-absolute u-w-100 u-m-0"
1031
1242
  style={{
1032
1243
  height: '2px',
1033
- background: `linear-gradient(to right, #a78bfa ${((value as number) / max) * 100}%, rgba(255,255,255,0.15) ${((value as number) / max) * 100}%)`,
1244
+ background: `linear-gradient(to right, #f472b6 ${(settings.animationSpeed / 3) * 100}%, rgba(255,255,255,0.15) ${(settings.animationSpeed / 3) * 100}%)`,
1034
1245
  borderRadius: '2px',
1035
1246
  outline: 'none',
1036
1247
  appearance: 'none',
@@ -1041,8 +1252,385 @@ export const Playground: Story = {
1041
1252
  />
1042
1253
  </div>
1043
1254
  </div>
1044
- );
1045
- })}
1255
+ )}
1256
+
1257
+ {/* Multi-Layer Distortion Toggle */}
1258
+ <div className="u-mb-3">
1259
+ <button
1260
+ onClick={() =>
1261
+ setSettings(prev => ({
1262
+ ...prev,
1263
+ withMultiLayerDistortion: !prev.withMultiLayerDistortion,
1264
+ }))
1265
+ }
1266
+ className="u-flex u-items-center u-gap-2 u-px-3 u-py-2 u-rounded u-text-start u-w-100"
1267
+ style={{
1268
+ background: settings.withMultiLayerDistortion
1269
+ ? 'rgba(167,139,250,0.15)'
1270
+ : 'rgba(255,255,255,0.04)',
1271
+ border: settings.withMultiLayerDistortion
1272
+ ? '1px solid rgba(167,139,250,0.45)'
1273
+ : '1px solid rgba(255,255,255,0.1)',
1274
+ cursor: 'pointer',
1275
+ transition: 'all 0.2s',
1276
+ }}
1277
+ >
1278
+ <div
1279
+ style={{
1280
+ width: '10px',
1281
+ height: '10px',
1282
+ borderRadius: '50%',
1283
+ background: settings.withMultiLayerDistortion
1284
+ ? '#a78bfa'
1285
+ : 'rgba(255,255,255,0.2)',
1286
+ flexShrink: 0,
1287
+ boxShadow: settings.withMultiLayerDistortion
1288
+ ? '0 0 8px rgba(167,139,250,0.6)'
1289
+ : 'none',
1290
+ }}
1291
+ />
1292
+ <span
1293
+ className="u-text-xs u-font-medium"
1294
+ style={{
1295
+ color: settings.withMultiLayerDistortion
1296
+ ? '#a78bfa'
1297
+ : 'rgba(255,255,255,0.6)',
1298
+ flex: 1,
1299
+ }}
1300
+ >
1301
+ Multi-Layer Distortion
1302
+ </span>
1303
+ </button>
1304
+ </div>
1305
+
1306
+ {/* FBM Parameters */}
1307
+ {settings.withMultiLayerDistortion && (
1308
+ <>
1309
+ {/* Octaves */}
1310
+ <div className="u-mb-3">
1311
+ <div className="u-flex u-justify-between u-items-baseline u-mb-1">
1312
+ <label className="u-text-xs u-font-medium u-opacity-80">
1313
+ Octaves
1314
+ </label>
1315
+ <span
1316
+ className="u-text-xs u-font-bold u-px-2 u-py-1 u-rounded"
1317
+ style={{
1318
+ background: 'rgba(167,139,250,0.12)',
1319
+ color: '#a78bfa',
1320
+ fontVariantNumeric: 'tabular-nums',
1321
+ minWidth: '40px',
1322
+ textAlign: 'center',
1323
+ }}
1324
+ >
1325
+ {settings.distortionOctaves}
1326
+ </span>
1327
+ </div>
1328
+ <div className="u-relative" style={{ height: '20px' }}>
1329
+ <input
1330
+ type="range"
1331
+ min={1}
1332
+ max={8}
1333
+ step={1}
1334
+ value={settings.distortionOctaves}
1335
+ onChange={e =>
1336
+ setSettings(prev => ({
1337
+ ...prev,
1338
+ distortionOctaves: parseInt(e.target.value),
1339
+ }))
1340
+ }
1341
+ className="premium-slider u-absolute u-w-100 u-m-0"
1342
+ style={{
1343
+ height: '2px',
1344
+ background: `linear-gradient(to right, #a78bfa ${(settings.distortionOctaves / 8) * 100}%, rgba(255,255,255,0.15) ${(settings.distortionOctaves / 8) * 100}%)`,
1345
+ borderRadius: '2px',
1346
+ outline: 'none',
1347
+ appearance: 'none',
1348
+ WebkitAppearance: 'none',
1349
+ top: '50%',
1350
+ transform: 'translateY(-50%)',
1351
+ }}
1352
+ />
1353
+ </div>
1354
+ </div>
1355
+
1356
+ {/* Lacunarity */}
1357
+ <div className="u-mb-3">
1358
+ <div className="u-flex u-justify-between u-items-baseline u-mb-1">
1359
+ <label className="u-text-xs u-font-medium u-opacity-80">
1360
+ Lacunarity
1361
+ </label>
1362
+ <span
1363
+ className="u-text-xs u-font-bold u-px-2 u-py-1 u-rounded"
1364
+ style={{
1365
+ background: 'rgba(167,139,250,0.12)',
1366
+ color: '#a78bfa',
1367
+ fontVariantNumeric: 'tabular-nums',
1368
+ minWidth: '40px',
1369
+ textAlign: 'center',
1370
+ }}
1371
+ >
1372
+ {settings.distortionLacunarity.toFixed(1)}
1373
+ </span>
1374
+ </div>
1375
+ <div className="u-relative" style={{ height: '20px' }}>
1376
+ <input
1377
+ type="range"
1378
+ min={1}
1379
+ max={4}
1380
+ step={0.1}
1381
+ value={settings.distortionLacunarity}
1382
+ onChange={e =>
1383
+ setSettings(prev => ({
1384
+ ...prev,
1385
+ distortionLacunarity: parseFloat(e.target.value),
1386
+ }))
1387
+ }
1388
+ className="premium-slider u-absolute u-w-100 u-m-0"
1389
+ style={{
1390
+ height: '2px',
1391
+ background: `linear-gradient(to right, #a78bfa ${((settings.distortionLacunarity - 1) / 3) * 100}%, rgba(255,255,255,0.15) ${((settings.distortionLacunarity - 1) / 3) * 100}%)`,
1392
+ borderRadius: '2px',
1393
+ outline: 'none',
1394
+ appearance: 'none',
1395
+ WebkitAppearance: 'none',
1396
+ top: '50%',
1397
+ transform: 'translateY(-50%)',
1398
+ }}
1399
+ />
1400
+ </div>
1401
+ </div>
1402
+
1403
+ {/* Gain */}
1404
+ <div className="u-mb-3">
1405
+ <div className="u-flex u-justify-between u-items-baseline u-mb-1">
1406
+ <label className="u-text-xs u-font-medium u-opacity-80">
1407
+ Gain
1408
+ </label>
1409
+ <span
1410
+ className="u-text-xs u-font-bold u-px-2 u-py-1 u-rounded"
1411
+ style={{
1412
+ background: 'rgba(167,139,250,0.12)',
1413
+ color: '#a78bfa',
1414
+ fontVariantNumeric: 'tabular-nums',
1415
+ minWidth: '40px',
1416
+ textAlign: 'center',
1417
+ }}
1418
+ >
1419
+ {settings.distortionGain.toFixed(2)}
1420
+ </span>
1421
+ </div>
1422
+ <div className="u-relative" style={{ height: '20px' }}>
1423
+ <input
1424
+ type="range"
1425
+ min={0.1}
1426
+ max={1}
1427
+ step={0.01}
1428
+ value={settings.distortionGain}
1429
+ onChange={e =>
1430
+ setSettings(prev => ({
1431
+ ...prev,
1432
+ distortionGain: parseFloat(e.target.value),
1433
+ }))
1434
+ }
1435
+ className="premium-slider u-absolute u-w-100 u-m-0"
1436
+ style={{
1437
+ height: '2px',
1438
+ background: `linear-gradient(to right, #a78bfa ${((settings.distortionGain - 0.1) / 0.9) * 100}%, rgba(255,255,255,0.15) ${((settings.distortionGain - 0.1) / 0.9) * 100}%)`,
1439
+ borderRadius: '2px',
1440
+ outline: 'none',
1441
+ appearance: 'none',
1442
+ WebkitAppearance: 'none',
1443
+ top: '50%',
1444
+ transform: 'translateY(-50%)',
1445
+ }}
1446
+ />
1447
+ </div>
1448
+ </div>
1449
+ </>
1450
+ )}
1451
+ </div>
1452
+ </>
1453
+ )}
1454
+
1455
+ {/* === CONTROLS: RESPONSIVE & PERFORMANCE === */}
1456
+ {controlTab === 'responsive' && (
1457
+ <div className="u-mb-4 u-animation-fade-in">
1458
+ <div className="u-flex u-items-center u-gap-2 u-mb-3">
1459
+ <div
1460
+ style={{
1461
+ width: '3px',
1462
+ height: '14px',
1463
+ background: 'linear-gradient(180deg, #10b981 0%, #3b82f6 100%)',
1464
+ borderRadius: '2px',
1465
+ flexShrink: 0,
1466
+ }}
1467
+ />
1468
+ <span
1469
+ className="u-text-xs u-font-bold u-opacity-60"
1470
+ style={{ letterSpacing: '1px', textTransform: 'uppercase' }}
1471
+ >
1472
+ Responsive & Performance
1473
+ </span>
1474
+ </div>
1475
+
1476
+ {/* Device Preset Selector */}
1477
+ <div className="u-mb-4">
1478
+ <label className="u-block u-mb-2 u-text-white u-font-semibold u-text-xs">
1479
+ Device Preset
1480
+ </label>
1481
+ <div
1482
+ className="u-grid u-gap-2"
1483
+ style={{ gridTemplateColumns: 'repeat(3, 1fr)' }}
1484
+ >
1485
+ {(['performance', 'balanced', 'quality'] as const).map(preset => (
1486
+ <button
1487
+ key={preset}
1488
+ onClick={() =>
1489
+ setSettings(prev => ({ ...prev, devicePreset: preset }))
1490
+ }
1491
+ className="u-py-2 u-rounded u-text-center u-text-xs u-font-bold"
1492
+ style={{
1493
+ background:
1494
+ settings.devicePreset === preset
1495
+ ? 'linear-gradient(135deg, rgba(16,185,129,0.3) 0%, rgba(59,130,246,0.2) 100%)'
1496
+ : 'rgba(255,255,255,0.05)',
1497
+ border:
1498
+ settings.devicePreset === preset
1499
+ ? '1px solid rgba(16,185,129,0.5)'
1500
+ : '1px solid rgba(255,255,255,0.1)',
1501
+ color:
1502
+ settings.devicePreset === preset
1503
+ ? '#10b981'
1504
+ : 'rgba(255,255,255,0.55)',
1505
+ cursor: 'pointer',
1506
+ transition: 'all 0.2s',
1507
+ outline: 'none',
1508
+ textTransform: 'capitalize',
1509
+ boxShadow:
1510
+ settings.devicePreset === preset
1511
+ ? '0 2px 12px rgba(16,185,129,0.15)'
1512
+ : 'none',
1513
+ }}
1514
+ >
1515
+ {preset}
1516
+ </button>
1517
+ ))}
1518
+ </div>
1519
+ <p className="u-mt-2 u-text-xs u-opacity-60">
1520
+ {settings.devicePreset === 'performance' &&
1521
+ '⚡ Optimized for low-end devices with reduced quality'}
1522
+ {settings.devicePreset === 'balanced' &&
1523
+ '⚖️ Balanced quality and performance (recommended)'}
1524
+ {settings.devicePreset === 'quality' &&
1525
+ '💎 Maximum visual quality for high-end devices'}
1526
+ </p>
1527
+ </div>
1528
+
1529
+ {/* Disable Responsive Breakpoints Toggle */}
1530
+ <div className="u-mb-4">
1531
+ <button
1532
+ onClick={() =>
1533
+ setSettings(prev => ({
1534
+ ...prev,
1535
+ disableResponsiveBreakpoints: !prev.disableResponsiveBreakpoints,
1536
+ }))
1537
+ }
1538
+ className="u-flex u-items-center u-gap-2 u-px-3 u-py-2 u-rounded u-text-start u-w-100"
1539
+ style={{
1540
+ background: settings.disableResponsiveBreakpoints
1541
+ ? 'rgba(239,68,68,0.15)'
1542
+ : 'rgba(255,255,255,0.04)',
1543
+ border: settings.disableResponsiveBreakpoints
1544
+ ? '1px solid rgba(239,68,68,0.45)'
1545
+ : '1px solid rgba(255,255,255,0.1)',
1546
+ cursor: 'pointer',
1547
+ transition: 'all 0.2s',
1548
+ }}
1549
+ >
1550
+ <div
1551
+ style={{
1552
+ width: '10px',
1553
+ height: '10px',
1554
+ borderRadius: '50%',
1555
+ background: settings.disableResponsiveBreakpoints
1556
+ ? '#ef4444'
1557
+ : 'rgba(255,255,255,0.2)',
1558
+ flexShrink: 0,
1559
+ boxShadow: settings.disableResponsiveBreakpoints
1560
+ ? '0 0 8px rgba(239,68,68,0.6)'
1561
+ : 'none',
1562
+ }}
1563
+ />
1564
+ <span
1565
+ className="u-text-xs u-font-medium"
1566
+ style={{
1567
+ color: settings.disableResponsiveBreakpoints
1568
+ ? '#ef4444'
1569
+ : 'rgba(255,255,255,0.6)',
1570
+ flex: 1,
1571
+ }}
1572
+ >
1573
+ Disable Responsive Breakpoints
1574
+ </span>
1575
+ </button>
1576
+ <p className="u-mt-1 u-text-xs u-opacity-50">
1577
+ When enabled, prevents automatic parameter adjustment based on viewport
1578
+ size
1579
+ </p>
1580
+ </div>
1581
+
1582
+ {/* Debug Options */}
1583
+ <div className="u-mb-3">
1584
+ <label className="u-block u-mb-2 u-text-white u-font-semibold u-text-xs">
1585
+ 🔍 Debug Options
1586
+ </label>
1587
+ <div
1588
+ className="u-grid u-gap-3"
1589
+ style={{ gridTemplateColumns: '1fr 1fr' }}
1590
+ >
1591
+ {(['debugPerformance', 'debugOverLight'] as const).map(key => {
1592
+ const isOn = settings[key] as boolean;
1593
+ const label = key
1594
+ .replace(/([A-Z])/g, ' $1')
1595
+ .replace(/^./, s => s.toUpperCase());
1596
+ return (
1597
+ <button
1598
+ key={key}
1599
+ onClick={() => setSettings(prev => ({ ...prev, [key]: !isOn }))}
1600
+ className="u-flex u-items-center u-gap-2 u-px-3 u-py-2 u-rounded u-text-start"
1601
+ style={{
1602
+ background: isOn
1603
+ ? 'rgba(59,130,246,0.15)'
1604
+ : 'rgba(255,255,255,0.04)',
1605
+ border: isOn
1606
+ ? '1px solid rgba(59,130,246,0.45)'
1607
+ : '1px solid rgba(255,255,255,0.1)',
1608
+ cursor: 'pointer',
1609
+ transition: 'all 0.2s',
1610
+ }}
1611
+ >
1612
+ <div
1613
+ style={{
1614
+ width: '10px',
1615
+ height: '10px',
1616
+ borderRadius: '50%',
1617
+ background: isOn ? '#3b82f6' : 'rgba(255,255,255,0.2)',
1618
+ flexShrink: 0,
1619
+ boxShadow: isOn ? '0 0 8px rgba(59,130,246,0.6)' : 'none',
1620
+ transition: 'all 0.2s',
1621
+ }}
1622
+ />
1623
+ <span
1624
+ className="u-text-xs u-font-medium"
1625
+ style={{ color: isOn ? '#3b82f6' : 'rgba(255,255,255,0.6)' }}
1626
+ >
1627
+ {label}
1628
+ </span>
1629
+ </button>
1630
+ );
1631
+ })}
1632
+ </div>
1633
+ </div>
1046
1634
  </div>
1047
1635
  )}
1048
1636
 
@@ -1464,7 +2052,10 @@ export const Playground: Story = {
1464
2052
  {backgrounds[backgroundIndex]?.tag}
1465
2053
  </span>
1466
2054
  </div>
1467
- <div className="u-mt-1 u-text-xs u-opacity-35" style={{ letterSpacing: '0.3px' }}>
2055
+ <div
2056
+ className="u-mt-1 u-text-xs u-opacity-35"
2057
+ style={{ letterSpacing: '0.3px' }}
2058
+ >
1468
2059
  Use ← → arrow keys to navigate
1469
2060
  </div>
1470
2061
  </div>
@@ -1516,6 +2107,17 @@ export const Playground: Story = {
1516
2107
  withoutEffects: false,
1517
2108
  withLiquidBlur: false,
1518
2109
  withBorder: true,
2110
+ withTimeAnimation: true,
2111
+ animationSpeed: 1.0,
2112
+ withMultiLayerDistortion: false,
2113
+ distortionOctaves: 3,
2114
+ distortionLacunarity: 2.0,
2115
+ distortionGain: 0.5,
2116
+ distortionQuality: 'medium',
2117
+ devicePreset: 'balanced',
2118
+ disableResponsiveBreakpoints: false,
2119
+ debugPerformance: false,
2120
+ debugOverLight: false,
1519
2121
  });
1520
2122
  setSelectedMode('standard');
1521
2123
  setSelectedShader('liquidGlass');
@@ -1608,6 +2210,16 @@ export const Playground: Story = {
1608
2210
  withoutEffects={settings.withoutEffects}
1609
2211
  withLiquidBlur={settings.withLiquidBlur}
1610
2212
  withBorder={settings.withBorder}
2213
+ withTimeAnimation={settings.withTimeAnimation}
2214
+ animationSpeed={settings.animationSpeed}
2215
+ withMultiLayerDistortion={settings.withMultiLayerDistortion}
2216
+ distortionOctaves={settings.distortionOctaves}
2217
+ distortionLacunarity={settings.distortionLacunarity}
2218
+ distortionGain={settings.distortionGain}
2219
+ distortionQuality={settings.distortionQuality}
2220
+ devicePreset={settings.devicePreset}
2221
+ disableResponsiveBreakpoints={settings.disableResponsiveBreakpoints}
2222
+ debugPerformance={settings.debugPerformance}
1611
2223
  >
1612
2224
  <div className="u-h-100 u-w-100 custom-scrollbar" style={{ overflowY: 'auto' }}>
1613
2225
  <div className="u-p-4 u-p-lg-5 u-text-center">