@buoy-gg/floating-tools-core 2.1.4-beta.2 → 2.1.4

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 (107) hide show
  1. package/lib/commonjs/FloatingToolsStore.js +1 -501
  2. package/lib/commonjs/colors.js +1 -54
  3. package/lib/commonjs/constants.js +1 -31
  4. package/lib/commonjs/devToolsState.js +1 -325
  5. package/lib/commonjs/dial.js +1 -617
  6. package/lib/commonjs/easing.js +1 -69
  7. package/lib/commonjs/icons/benchmark-icon.js +1 -24
  8. package/lib/commonjs/icons/env-icon.js +1 -24
  9. package/lib/commonjs/icons/events-icon.js +1 -24
  10. package/lib/commonjs/icons/highlight-icon.js +1 -24
  11. package/lib/commonjs/icons/icon-data.js +1 -2268
  12. package/lib/commonjs/icons/icon-factories.js +1 -173
  13. package/lib/commonjs/icons/icon-primitives.js +1 -559
  14. package/lib/commonjs/icons/icon-primitives.native.js +1 -779
  15. package/lib/commonjs/icons/icon-renderer.js +1 -260
  16. package/lib/commonjs/icons/network-icon.js +1 -24
  17. package/lib/commonjs/icons/query-icon.js +1 -24
  18. package/lib/commonjs/icons/redux-icon.js +1 -85
  19. package/lib/commonjs/icons/renders-icon.js +1 -33
  20. package/lib/commonjs/icons/routes-icon.js +1 -49
  21. package/lib/commonjs/icons/sentry-icon.js +1 -24
  22. package/lib/commonjs/icons/storage-icon.js +1 -24
  23. package/lib/commonjs/icons/wifi-icon.js +1 -24
  24. package/lib/commonjs/index.js +1 -723
  25. package/lib/commonjs/settings.js +1 -588
  26. package/lib/commonjs/utils.js +1 -72
  27. package/lib/module/FloatingToolsStore.js +1 -496
  28. package/lib/module/colors.js +1 -49
  29. package/lib/module/constants.js +1 -27
  30. package/lib/module/devToolsState.js +1 -318
  31. package/lib/module/dial.js +1 -603
  32. package/lib/module/easing.js +1 -62
  33. package/lib/module/icons/benchmark-icon.js +1 -15
  34. package/lib/module/icons/env-icon.js +1 -15
  35. package/lib/module/icons/events-icon.js +1 -15
  36. package/lib/module/icons/highlight-icon.js +1 -15
  37. package/lib/module/icons/icon-data.js +1 -2264
  38. package/lib/module/icons/icon-factories.js +1 -163
  39. package/lib/module/icons/icon-primitives.js +1 -547
  40. package/lib/module/icons/icon-primitives.native.js +1 -767
  41. package/lib/module/icons/icon-renderer.js +1 -255
  42. package/lib/module/icons/network-icon.js +1 -15
  43. package/lib/module/icons/query-icon.js +1 -15
  44. package/lib/module/icons/redux-icon.js +1 -81
  45. package/lib/module/icons/renders-icon.js +1 -17
  46. package/lib/module/icons/routes-icon.js +1 -41
  47. package/lib/module/icons/sentry-icon.js +1 -15
  48. package/lib/module/icons/storage-icon.js +1 -15
  49. package/lib/module/icons/wifi-icon.js +1 -15
  50. package/lib/module/index.js +1 -103
  51. package/lib/module/settings.js +1 -576
  52. package/lib/module/utils.js +1 -66
  53. package/package.json +1 -1
  54. package/lib/typescript/commonjs/FloatingToolsStore.d.ts.map +0 -1
  55. package/lib/typescript/commonjs/colors.d.ts.map +0 -1
  56. package/lib/typescript/commonjs/constants.d.ts.map +0 -1
  57. package/lib/typescript/commonjs/devToolsState.d.ts.map +0 -1
  58. package/lib/typescript/commonjs/dial.d.ts.map +0 -1
  59. package/lib/typescript/commonjs/easing.d.ts.map +0 -1
  60. package/lib/typescript/commonjs/icons/benchmark-icon.d.ts.map +0 -1
  61. package/lib/typescript/commonjs/icons/env-icon.d.ts.map +0 -1
  62. package/lib/typescript/commonjs/icons/events-icon.d.ts.map +0 -1
  63. package/lib/typescript/commonjs/icons/highlight-icon.d.ts.map +0 -1
  64. package/lib/typescript/commonjs/icons/icon-data.d.ts.map +0 -1
  65. package/lib/typescript/commonjs/icons/icon-factories.d.ts.map +0 -1
  66. package/lib/typescript/commonjs/icons/icon-primitives.d.ts.map +0 -1
  67. package/lib/typescript/commonjs/icons/icon-primitives.native.d.ts.map +0 -1
  68. package/lib/typescript/commonjs/icons/icon-renderer.d.ts.map +0 -1
  69. package/lib/typescript/commonjs/icons/network-icon.d.ts.map +0 -1
  70. package/lib/typescript/commonjs/icons/query-icon.d.ts.map +0 -1
  71. package/lib/typescript/commonjs/icons/redux-icon.d.ts.map +0 -1
  72. package/lib/typescript/commonjs/icons/renders-icon.d.ts.map +0 -1
  73. package/lib/typescript/commonjs/icons/routes-icon.d.ts.map +0 -1
  74. package/lib/typescript/commonjs/icons/sentry-icon.d.ts.map +0 -1
  75. package/lib/typescript/commonjs/icons/storage-icon.d.ts.map +0 -1
  76. package/lib/typescript/commonjs/icons/wifi-icon.d.ts.map +0 -1
  77. package/lib/typescript/commonjs/index.d.ts.map +0 -1
  78. package/lib/typescript/commonjs/settings.d.ts.map +0 -1
  79. package/lib/typescript/commonjs/types.d.ts.map +0 -1
  80. package/lib/typescript/commonjs/utils.d.ts.map +0 -1
  81. package/lib/typescript/module/FloatingToolsStore.d.ts.map +0 -1
  82. package/lib/typescript/module/colors.d.ts.map +0 -1
  83. package/lib/typescript/module/constants.d.ts.map +0 -1
  84. package/lib/typescript/module/devToolsState.d.ts.map +0 -1
  85. package/lib/typescript/module/dial.d.ts.map +0 -1
  86. package/lib/typescript/module/easing.d.ts.map +0 -1
  87. package/lib/typescript/module/icons/benchmark-icon.d.ts.map +0 -1
  88. package/lib/typescript/module/icons/env-icon.d.ts.map +0 -1
  89. package/lib/typescript/module/icons/events-icon.d.ts.map +0 -1
  90. package/lib/typescript/module/icons/highlight-icon.d.ts.map +0 -1
  91. package/lib/typescript/module/icons/icon-data.d.ts.map +0 -1
  92. package/lib/typescript/module/icons/icon-factories.d.ts.map +0 -1
  93. package/lib/typescript/module/icons/icon-primitives.d.ts.map +0 -1
  94. package/lib/typescript/module/icons/icon-primitives.native.d.ts.map +0 -1
  95. package/lib/typescript/module/icons/icon-renderer.d.ts.map +0 -1
  96. package/lib/typescript/module/icons/network-icon.d.ts.map +0 -1
  97. package/lib/typescript/module/icons/query-icon.d.ts.map +0 -1
  98. package/lib/typescript/module/icons/redux-icon.d.ts.map +0 -1
  99. package/lib/typescript/module/icons/renders-icon.d.ts.map +0 -1
  100. package/lib/typescript/module/icons/routes-icon.d.ts.map +0 -1
  101. package/lib/typescript/module/icons/sentry-icon.d.ts.map +0 -1
  102. package/lib/typescript/module/icons/storage-icon.d.ts.map +0 -1
  103. package/lib/typescript/module/icons/wifi-icon.d.ts.map +0 -1
  104. package/lib/typescript/module/index.d.ts.map +0 -1
  105. package/lib/typescript/module/settings.d.ts.map +0 -1
  106. package/lib/typescript/module/types.d.ts.map +0 -1
  107. package/lib/typescript/module/utils.d.ts.map +0 -1
@@ -1,603 +1 @@
1
- "use strict";
2
-
3
- /**
4
- * Dial Menu - Shared layout calculations, colors, and styling.
5
- *
6
- * Pure configuration and math functions for the dial menu.
7
- * No React or platform-specific code.
8
- */
9
-
10
- import { floatingToolsColors, withAlpha } from "./colors.js";
11
-
12
- // =============================
13
- // Constants
14
- // =============================
15
-
16
- /** Maximum number of slots in the dial */
17
- export const MAX_DIAL_SLOTS = 6;
18
-
19
- /** Starting angle for first icon (top of circle, -90 degrees in radians) */
20
- export const DIAL_START_ANGLE = -1 * Math.PI / 2;
21
-
22
- /** Default button size in the center */
23
- export const DIAL_BUTTON_SIZE = 80;
24
-
25
- /** Default icon view size */
26
- export const DIAL_ICON_SIZE = 60;
27
-
28
- /** Padding from edge of circle to icons */
29
- export const DIAL_ICON_PADDING = 20;
30
-
31
- /** Number of grid lines in the dial */
32
- export const DIAL_GRID_LINE_COUNT = 6;
33
-
34
- // =============================
35
- // Dial Colors
36
- // =============================
37
-
38
- /**
39
- * Color palette for the dial menu.
40
- * Derived from floatingToolsColors for consistency.
41
- *
42
- * Property names match existing mobile implementation for compatibility.
43
- */
44
- export const dialColors = {
45
- /** Background color for the dial circle */
46
- dialBackground: '#000000',
47
- /** Gradient layer colors (with alpha) */
48
- dialGradient1: withAlpha(floatingToolsColors.info, '10'),
49
- dialGradient2: withAlpha(floatingToolsColors.info, '08'),
50
- dialGradient3: withAlpha(floatingToolsColors.info, '15'),
51
- /** Border color for dial and buttons */
52
- dialBorder: withAlpha(floatingToolsColors.info, '40'),
53
- /** Shadow/glow color */
54
- dialShadow: floatingToolsColors.info,
55
- /** Grid line color */
56
- dialGridLine: withAlpha(floatingToolsColors.info, '26'),
57
- /** Backdrop overlay color */
58
- dialBackdrop: 'rgba(0, 0, 0, 0.85)',
59
- /** Center button text color */
60
- centerText: floatingToolsColors.secondary,
61
- /** Center button text glow */
62
- centerTextGlow: floatingToolsColors.info,
63
- /** Icon label color */
64
- iconLabel: floatingToolsColors.secondary,
65
- /** Empty slot dot background */
66
- emptyDotBackground: withAlpha(floatingToolsColors.muted, '15'),
67
- /** Empty slot dot border */
68
- emptyDotBorder: withAlpha(floatingToolsColors.muted, '50')
69
- };
70
- // =============================
71
- // Dial Styling Configuration
72
- // =============================
73
-
74
- /**
75
- * Styling configuration for the dial menu.
76
- * All numeric values that affect appearance.
77
- */
78
- export const dialStyles = {
79
- // Backdrop
80
- backdrop: {
81
- opacity: 0.85
82
- },
83
- // Main circle
84
- circle: {
85
- borderWidth: 1,
86
- shadowOpacity: 0.5,
87
- shadowRadius: 20
88
- },
89
- // Gradient layers (for depth effect)
90
- gradientLayers: [{
91
- opacity: 0.6,
92
- offsetPercent: 0
93
- }, {
94
- opacity: 0.4,
95
- offsetPercent: 30
96
- }, {
97
- opacity: 0.3,
98
- offsetPercent: 50
99
- }],
100
- // Grid lines
101
- grid: {
102
- lineCount: 6,
103
- lineHeight: 1,
104
- /** Rotation angles in degrees for each line */
105
- getLineRotations: () => Array.from({
106
- length: 6
107
- }, (_, i) => i * 60)
108
- },
109
- // Center button
110
- centerButton: {
111
- /** Button container is this multiple of button size */
112
- containerRatio: 1.5,
113
- /** Button border wrapper is this multiple of button size */
114
- borderRatio: 1.2,
115
- /** Border radius ratio */
116
- borderRadiusRatio: 0.6,
117
- borderWidth: 2,
118
- text: {
119
- fontSize: 10,
120
- fontWeight: '900',
121
- letterSpacing: 1,
122
- fontFamily: 'monospace'
123
- },
124
- proText: {
125
- fontSize: 8,
126
- letterSpacing: 2
127
- }
128
- },
129
- // Icon items
130
- icon: {
131
- /** Background gradient size as percent of icon size */
132
- gradientBgSizePercent: 85,
133
- gradientBgBorderRadius: 12,
134
- gradientBgOpacity: 0.3,
135
- /** Inner glow size as percent of icon size */
136
- innerGlowSizePercent: 70,
137
- innerGlowBorderRadius: 10,
138
- innerGlowOpacity: 0.5,
139
- label: {
140
- fontSize: 8,
141
- fontWeight: '900',
142
- letterSpacing: 0.3,
143
- fontFamily: 'monospace',
144
- marginTop: 2
145
- },
146
- /** Icon wrapper margin bottom */
147
- wrapperMarginBottom: 4
148
- },
149
- // Empty slot
150
- emptySlot: {
151
- dotSize: 12,
152
- borderWidth: 1
153
- }
154
- };
155
-
156
- // =============================
157
- // Helper to generate grid line rotations
158
- // =============================
159
-
160
- /**
161
- * Get rotation angles for grid lines.
162
- * @param count - Number of grid lines (default: 6)
163
- * @returns Array of rotation angles in degrees
164
- */
165
- export function getGridLineRotations(count = DIAL_GRID_LINE_COUNT) {
166
- return Array.from({
167
- length: count
168
- }, (_, i) => i * (360 / count));
169
- }
170
-
171
- // =============================
172
- // Layout Calculations
173
- // =============================
174
-
175
- /**
176
- * Calculate dial layout dimensions based on screen size.
177
- */
178
- export function getDialLayout(config) {
179
- const {
180
- screenWidth,
181
- maxCircleSize = 320,
182
- circleSizeRatio = 0.75,
183
- iconSize = DIAL_ICON_SIZE,
184
- iconPadding = DIAL_ICON_PADDING
185
- } = config;
186
- const circleSize = Math.min(screenWidth * circleSizeRatio, maxCircleSize);
187
- const circleRadius = circleSize / 2;
188
- const iconRadius = circleRadius - iconSize / 2 - iconPadding;
189
- return {
190
- circleSize,
191
- circleRadius,
192
- iconRadius,
193
- iconSize,
194
- buttonSize: DIAL_BUTTON_SIZE
195
- };
196
- }
197
-
198
- // =============================
199
- // Icon Position Calculations
200
- // =============================
201
-
202
- /**
203
- * Get the angle for an icon at a given index.
204
- *
205
- * @param index - Icon index (0-based)
206
- * @param totalIcons - Total number of icon slots
207
- * @param startAngle - Starting angle in radians (default: top of circle)
208
- */
209
- export function getIconAngle(index, totalIcons, startAngle = DIAL_START_ANGLE) {
210
- const anglePerIcon = 2 * Math.PI / totalIcons;
211
- return startAngle + anglePerIcon * index;
212
- }
213
-
214
- /**
215
- * Get the position for an icon at a given index.
216
- *
217
- * @param index - Icon index (0-based)
218
- * @param totalIcons - Total number of icon slots
219
- * @param radius - Distance from center to icon
220
- * @param startAngle - Starting angle in radians (default: top of circle)
221
- */
222
- export function getIconPosition(index, totalIcons, radius, startAngle = DIAL_START_ANGLE) {
223
- const angle = getIconAngle(index, totalIcons, startAngle);
224
- return {
225
- x: radius * Math.cos(angle),
226
- y: radius * Math.sin(angle),
227
- angle
228
- };
229
- }
230
-
231
- /**
232
- * Get positions for all icons in the dial.
233
- *
234
- * @param totalIcons - Total number of icon slots
235
- * @param radius - Distance from center to icons
236
- * @param startAngle - Starting angle in radians (default: top of circle)
237
- */
238
- export function getAllIconPositions(totalIcons, radius, startAngle = DIAL_START_ANGLE) {
239
- return Array.from({
240
- length: totalIcons
241
- }, (_, index) => getIconPosition(index, totalIcons, radius, startAngle));
242
- }
243
-
244
- // =============================
245
- // Animation Timing
246
- // =============================
247
-
248
- /**
249
- * Get the interpolation input range for staggered icon animation.
250
- * Used to create smooth entrance animations with stagger.
251
- *
252
- * @param index - Icon index (0-based)
253
- * @param totalIcons - Total number of icons
254
- * @param staggerRatio - Delay ratio per icon (default: 0.1)
255
- */
256
- export function getIconStaggerInputRange(index, totalIcons, staggerRatio = 0.1) {
257
- const staggerDelay = index * staggerRatio;
258
- const maxStagger = (totalIcons - 1) * staggerRatio;
259
- return [0, staggerDelay, staggerDelay + (1 - maxStagger), 1];
260
- }
261
-
262
- // =============================
263
- // Comprehensive Animation Config
264
- // =============================
265
-
266
- /**
267
- * Easing function names used in animations.
268
- */
269
-
270
- /**
271
- * Spring animation configuration.
272
- */
273
-
274
- /**
275
- * Comprehensive animation configuration for the dial menu.
276
- * All timing, easing, and effect parameters in one place.
277
- */
278
- export const dialAnimationConfig = {
279
- /** Entrance animation sequence */
280
- entrance: {
281
- /** Backdrop fade in */
282
- backdrop: {
283
- duration: 400,
284
- easing: 'linear'
285
- },
286
- /** Dial circle animations */
287
- dial: {
288
- /** Spring scale from 0 to 1 */
289
- scale: {
290
- type: 'spring',
291
- damping: 15,
292
- stiffness: 150,
293
- mass: 1
294
- },
295
- /** 360 degree rotation on entrance */
296
- rotation: {
297
- duration: 800,
298
- degrees: 360,
299
- easing: 'easeOutCubic'
300
- }
301
- },
302
- /** Center button spring scale with delay */
303
- centerButton: {
304
- delay: 300,
305
- type: 'spring',
306
- damping: 10,
307
- stiffness: 200
308
- },
309
- /** Icons stagger entrance */
310
- icons: {
311
- delay: 500,
312
- duration: 600,
313
- easing: 'easeOutCubic'
314
- },
315
- /** Circuit traces fade in */
316
- circuitTraces: {
317
- delay: 600,
318
- duration: 1000
319
- }
320
- },
321
- /** Exit animation sequence */
322
- exit: {
323
- /** Icons collapse back to center */
324
- icons: {
325
- duration: 300,
326
- easing: 'easeInCubic'
327
- },
328
- /** Center button scale down */
329
- centerButton: {
330
- duration: 200,
331
- easing: 'easeInCubic'
332
- },
333
- /** Dial scale down */
334
- dialScale: {
335
- duration: 250,
336
- easing: 'easeInCubic'
337
- },
338
- /** Backdrop fade out */
339
- backdrop: {
340
- duration: 200
341
- }
342
- },
343
- /** Continuous looping effects */
344
- continuous: {
345
- /** Glitch effect - horizontal jitter */
346
- glitch: {
347
- interval: 3000,
348
- offset: 2,
349
- stepDuration: 50
350
- },
351
- /** Pulse effect - subtle scale oscillation */
352
- pulse: {
353
- minScale: 0.98,
354
- maxScale: 1.02,
355
- duration: 1000,
356
- easing: 'easeInOutCubic'
357
- },
358
- /** Floating effect - vertical bobbing */
359
- floating: {
360
- minY: 0,
361
- maxY: -8,
362
- duration: 3000,
363
- easing: 'easeInOutCubic'
364
- },
365
- /** Breathing effect - scale on center button */
366
- breathing: {
367
- minScale: 0.98,
368
- maxScale: 1.05,
369
- duration: 2500,
370
- easing: 'easeInOutCubic'
371
- }
372
- },
373
- /** Icon-specific animations */
374
- icons: {
375
- /** Stagger ratio for entrance (0-1 per icon) */
376
- staggerRatio: 0.1,
377
- /** Spiral effect parameters */
378
- spiral: {
379
- /** Start rotation in radians (2π = full rotation) */
380
- startRotation: Math.PI * 2,
381
- /** End rotation in radians */
382
- endRotation: 0
383
- },
384
- /** Opacity interpolation during entrance */
385
- opacity: {
386
- inputRange: [0, 0.3, 1],
387
- outputRange: [0, 0.3, 1]
388
- },
389
- /** Press in animation */
390
- pressIn: {
391
- scale: 0.95,
392
- type: 'spring',
393
- damping: 15,
394
- stiffness: 400
395
- },
396
- /** Press out animation */
397
- pressOut: {
398
- scale: 1,
399
- type: 'spring',
400
- damping: 15,
401
- stiffness: 400
402
- }
403
- },
404
- /** User interaction animations */
405
- interaction: {
406
- /** Icon selection pulse effect */
407
- iconSelect: {
408
- pulse: [{
409
- scale: 0.9,
410
- damping: 15,
411
- stiffness: 500
412
- }, {
413
- scale: 1,
414
- damping: 10,
415
- stiffness: 200
416
- }],
417
- actionDelay: 50
418
- },
419
- /** Center button hover effect */
420
- centerHover: {
421
- scale: 1.05,
422
- duration: 150
423
- }
424
- }
425
- };
426
- // =============================
427
- // CSS Bezier Curve Equivalents
428
- // =============================
429
-
430
- /**
431
- * CSS cubic-bezier approximations for React Native springs.
432
- * These provide similar visual feel in CSS transitions/animations.
433
- */
434
- export const dialCSSBeziers = {
435
- // Spring approximations (derived from damping/stiffness values)
436
- /** Spring: damping 15, stiffness 150 (dial scale) */
437
- dialScale: 'cubic-bezier(0.34, 1.56, 0.64, 1)',
438
- /** Spring: damping 10, stiffness 200 (center button) */
439
- centerButton: 'cubic-bezier(0.25, 1.7, 0.55, 1)',
440
- /** Spring: damping 15, stiffness 400 (icon press) */
441
- iconPress: 'cubic-bezier(0.22, 1.2, 0.36, 1)',
442
- /** Spring: damping 15, stiffness 500 (icon select pulse) */
443
- iconSelectPulse: 'cubic-bezier(0.18, 1.15, 0.32, 1)',
444
- // Standard easing curves
445
- /** Decelerate - for entrance animations */
446
- easeOutCubic: 'cubic-bezier(0.33, 1, 0.68, 1)',
447
- /** Accelerate - for exit animations */
448
- easeInCubic: 'cubic-bezier(0.32, 0, 0.67, 0)',
449
- /** Smooth in-out - for continuous effects */
450
- easeInOutCubic: 'cubic-bezier(0.65, 0, 0.35, 1)',
451
- /** Linear */
452
- linear: 'linear'
453
- };
454
- // =============================
455
- // CSS Keyframe Generators
456
- // =============================
457
-
458
- /**
459
- * Generate CSS @keyframes definitions for dial animations.
460
- * Can be injected into a <style> tag or used with CSS-in-JS.
461
- */
462
- export function generateDialCSSKeyframes() {
463
- const c = dialAnimationConfig.continuous;
464
- return {
465
- /** Glitch effect - horizontal jitter */
466
- dialGlitch: `@keyframes dialGlitch {
467
- 0%, 100% { transform: translateX(0); }
468
- 33% { transform: translateX(${c.glitch.offset}px); }
469
- 66% { transform: translateX(-${c.glitch.offset}px); }
470
- }`,
471
- /** Pulse effect - scale oscillation */
472
- dialPulse: `@keyframes dialPulse {
473
- 0%, 100% { transform: scale(1); }
474
- 50% { transform: scale(${c.pulse.maxScale}); }
475
- }`,
476
- /** Floating effect - vertical bob */
477
- dialFloating: `@keyframes dialFloating {
478
- 0%, 100% { transform: translateY(0); }
479
- 50% { transform: translateY(${c.floating.maxY}px); }
480
- }`,
481
- /** Breathing effect - scale pulse */
482
- dialBreathing: `@keyframes dialBreathing {
483
- 0%, 100% { transform: scale(1); }
484
- 50% { transform: scale(${c.breathing.maxScale}); }
485
- }`,
486
- /** Dial rotation entrance */
487
- dialRotation: `@keyframes dialRotation {
488
- from { transform: rotate(0deg); }
489
- to { transform: rotate(${dialAnimationConfig.entrance.dial.rotation.degrees}deg); }
490
- }`
491
- };
492
- }
493
-
494
- /**
495
- * Get CSS animation shorthand values for continuous effects.
496
- * Use these in the `animation` CSS property.
497
- */
498
- export function getDialCSSAnimationStyles() {
499
- const c = dialAnimationConfig.continuous;
500
- return {
501
- /** Glitch: triggered periodically via JS interval */
502
- glitch: `dialGlitch ${c.glitch.stepDuration * 3}ms ease`,
503
- /** Pulse: infinite loop */
504
- pulse: `dialPulse ${c.pulse.duration * 2}ms ${dialCSSBeziers.easeInOutCubic} infinite`,
505
- /** Floating: infinite loop */
506
- floating: `dialFloating ${c.floating.duration * 2}ms ${dialCSSBeziers.easeInOutCubic} infinite`,
507
- /** Breathing: infinite loop */
508
- breathing: `dialBreathing ${c.breathing.duration * 2}ms ${dialCSSBeziers.easeInOutCubic} infinite`,
509
- /** Dial rotation: plays once on entrance */
510
- dialRotation: `dialRotation ${dialAnimationConfig.entrance.dial.rotation.duration}ms ${dialCSSBeziers.easeOutCubic}`
511
- };
512
- }
513
-
514
- /**
515
- * Get all keyframes as a single CSS string for injection.
516
- */
517
- export function getDialCSSKeyframesString() {
518
- return Object.values(generateDialCSSKeyframes()).join('\n\n');
519
- }
520
-
521
- // =============================
522
- // Spiral Animation Utilities
523
- // =============================
524
-
525
- /**
526
- * Position and visual state during spiral animation.
527
- */
528
-
529
- /**
530
- * Calculate icon position during spiral entrance animation.
531
- *
532
- * @param progress - Animation progress (0 = start at center, 1 = final position)
533
- * @param index - Icon index (0-based)
534
- * @param totalIcons - Total number of icons
535
- * @param radius - Final radius from center
536
- * @param startAngle - Starting angle for icon layout (default: top of circle)
537
- */
538
- export function getSpiralAnimationPosition(progress, index, totalIcons, radius, startAngle = DIAL_START_ANGLE) {
539
- const finalPos = getIconPosition(index, totalIcons, radius, startAngle);
540
- const spiral = dialAnimationConfig.icons.spiral;
541
- const opacityConfig = dialAnimationConfig.icons.opacity;
542
-
543
- // Clamp progress to 0-1
544
- const p = Math.max(0, Math.min(1, progress));
545
-
546
- // Spiral rotation: interpolate from startRotation to endRotation
547
- const rotation = spiral.startRotation + (spiral.endRotation - spiral.startRotation) * p;
548
-
549
- // Distance from center grows with progress
550
- const distance = radius * p;
551
-
552
- // Calculate position along spiral path
553
- const spiralAngle = finalPos.angle + rotation;
554
-
555
- // Interpolate from spiral position to final position
556
- const spiralX = distance * Math.cos(spiralAngle);
557
- const spiralY = distance * Math.sin(spiralAngle);
558
-
559
- // Blend spiral position with final position based on progress
560
- const x = spiralX + (finalPos.x - spiralX) * p;
561
- const y = spiralY + (finalPos.y - spiralY) * p;
562
-
563
- // Opacity interpolation with configurable curve
564
- let opacity;
565
- if (p <= opacityConfig.inputRange[0]) {
566
- opacity = opacityConfig.outputRange[0];
567
- } else if (p <= opacityConfig.inputRange[1]) {
568
- const t = (p - opacityConfig.inputRange[0]) / (opacityConfig.inputRange[1] - opacityConfig.inputRange[0]);
569
- opacity = opacityConfig.outputRange[0] + (opacityConfig.outputRange[1] - opacityConfig.outputRange[0]) * t;
570
- } else {
571
- const t = (p - opacityConfig.inputRange[1]) / (opacityConfig.inputRange[2] - opacityConfig.inputRange[1]);
572
- opacity = opacityConfig.outputRange[1] + (opacityConfig.outputRange[2] - opacityConfig.outputRange[1]) * t;
573
- }
574
- return {
575
- x,
576
- y,
577
- rotation,
578
- scale: p,
579
- opacity
580
- };
581
- }
582
-
583
- /**
584
- * Calculate staggered progress for an icon based on master progress.
585
- * Applies the stagger delay so icons animate in sequence.
586
- *
587
- * @param masterProgress - Overall animation progress (0-1)
588
- * @param index - Icon index (0-based)
589
- * @param totalIcons - Total number of icons
590
- */
591
- export function getStaggeredIconProgress(masterProgress, index, totalIcons) {
592
- const inputRange = getIconStaggerInputRange(index, totalIcons, dialAnimationConfig.icons.staggerRatio);
593
-
594
- // Map master progress through stagger input range
595
- if (masterProgress <= inputRange[0]) return 0;
596
- if (masterProgress <= inputRange[1]) return 0;
597
- if (masterProgress >= inputRange[3]) return 1;
598
- if (masterProgress >= inputRange[2]) return 1;
599
-
600
- // Interpolate between inputRange[1] and inputRange[2]
601
- const t = (masterProgress - inputRange[1]) / (inputRange[2] - inputRange[1]);
602
- return Math.max(0, Math.min(1, t));
603
- }
1
+ "use strict";import{floatingToolsColors,withAlpha}from"./colors.js";export const MAX_DIAL_SLOTS=6;export const DIAL_START_ANGLE=-1*Math.PI/2;export const DIAL_BUTTON_SIZE=80;export const DIAL_ICON_SIZE=60;export const DIAL_ICON_PADDING=20;export const DIAL_GRID_LINE_COUNT=6;export const dialColors={dialBackground:"#000000",dialGradient1:withAlpha(floatingToolsColors.info,"10"),dialGradient2:withAlpha(floatingToolsColors.info,"08"),dialGradient3:withAlpha(floatingToolsColors.info,"15"),dialBorder:withAlpha(floatingToolsColors.info,"40"),dialShadow:floatingToolsColors.info,dialGridLine:withAlpha(floatingToolsColors.info,"26"),dialBackdrop:"rgba(0, 0, 0, 0.85)",centerText:floatingToolsColors.secondary,centerTextGlow:floatingToolsColors.info,iconLabel:floatingToolsColors.secondary,emptyDotBackground:withAlpha(floatingToolsColors.muted,"15"),emptyDotBorder:withAlpha(floatingToolsColors.muted,"50")};export const dialStyles={backdrop:{opacity:.85},circle:{borderWidth:1,shadowOpacity:.5,shadowRadius:20},gradientLayers:[{opacity:.6,offsetPercent:0},{opacity:.4,offsetPercent:30},{opacity:.3,offsetPercent:50}],grid:{lineCount:6,lineHeight:1,getLineRotations:()=>Array.from({length:6},(t,n)=>60*n)},centerButton:{containerRatio:1.5,borderRatio:1.2,borderRadiusRatio:.6,borderWidth:2,text:{fontSize:10,fontWeight:"900",letterSpacing:1,fontFamily:"monospace"},proText:{fontSize:8,letterSpacing:2}},icon:{gradientBgSizePercent:85,gradientBgBorderRadius:12,gradientBgOpacity:.3,innerGlowSizePercent:70,innerGlowBorderRadius:10,innerGlowOpacity:.5,label:{fontSize:8,fontWeight:"900",letterSpacing:.3,fontFamily:"monospace",marginTop:2},wrapperMarginBottom:4},emptySlot:{dotSize:12,borderWidth:1}};export function getGridLineRotations(t=6){return Array.from({length:t},(n,i)=>i*(360/t))}export function getDialLayout(t){const{screenWidth:n,maxCircleSize:i=320,circleSizeRatio:e=.75,iconSize:o=DIAL_ICON_SIZE,iconPadding:a=DIAL_ICON_PADDING}=t,r=Math.min(n*e,i),s=r/2;return{circleSize:r,circleRadius:s,iconRadius:s-o/2-a,iconSize:o,buttonSize:80}}export function getIconAngle(t,n,i=DIAL_START_ANGLE){return i+2*Math.PI/n*t}export function getIconPosition(t,n,i,e=DIAL_START_ANGLE){const o=getIconAngle(t,n,e);return{x:i*Math.cos(o),y:i*Math.sin(o),angle:o}}export function getAllIconPositions(t,n,i=DIAL_START_ANGLE){return Array.from({length:t},(e,o)=>getIconPosition(o,t,n,i))}export function getIconStaggerInputRange(t,n,i=.1){const e=t*i;return[0,e,e+(1-(n-1)*i),1]}export const dialAnimationConfig={entrance:{backdrop:{duration:400,easing:"linear"},dial:{scale:{type:"spring",damping:15,stiffness:150,mass:1},rotation:{duration:800,degrees:360,easing:"easeOutCubic"}},centerButton:{delay:300,type:"spring",damping:10,stiffness:200},icons:{delay:500,duration:600,easing:"easeOutCubic"},circuitTraces:{delay:600,duration:1e3}},exit:{icons:{duration:300,easing:"easeInCubic"},centerButton:{duration:200,easing:"easeInCubic"},dialScale:{duration:250,easing:"easeInCubic"},backdrop:{duration:200}},continuous:{glitch:{interval:3e3,offset:2,stepDuration:50},pulse:{minScale:.98,maxScale:1.02,duration:1e3,easing:"easeInOutCubic"},floating:{minY:0,maxY:-8,duration:3e3,easing:"easeInOutCubic"},breathing:{minScale:.98,maxScale:1.05,duration:2500,easing:"easeInOutCubic"}},icons:{staggerRatio:.1,spiral:{startRotation:2*Math.PI,endRotation:0},opacity:{inputRange:[0,.3,1],outputRange:[0,.3,1]},pressIn:{scale:.95,type:"spring",damping:15,stiffness:400},pressOut:{scale:1,type:"spring",damping:15,stiffness:400}},interaction:{iconSelect:{pulse:[{scale:.9,damping:15,stiffness:500},{scale:1,damping:10,stiffness:200}],actionDelay:50},centerHover:{scale:1.05,duration:150}}};export const dialCSSBeziers={dialScale:"cubic-bezier(0.34, 1.56, 0.64, 1)",centerButton:"cubic-bezier(0.25, 1.7, 0.55, 1)",iconPress:"cubic-bezier(0.22, 1.2, 0.36, 1)",iconSelectPulse:"cubic-bezier(0.18, 1.15, 0.32, 1)",easeOutCubic:"cubic-bezier(0.33, 1, 0.68, 1)",easeInCubic:"cubic-bezier(0.32, 0, 0.67, 0)",easeInOutCubic:"cubic-bezier(0.65, 0, 0.35, 1)",linear:"linear"};export function generateDialCSSKeyframes(){const t=dialAnimationConfig.continuous;return{dialGlitch:`@keyframes dialGlitch {\n 0%, 100% { transform: translateX(0); }\n 33% { transform: translateX(${t.glitch.offset}px); }\n 66% { transform: translateX(-${t.glitch.offset}px); }\n }`,dialPulse:`@keyframes dialPulse {\n 0%, 100% { transform: scale(1); }\n 50% { transform: scale(${t.pulse.maxScale}); }\n }`,dialFloating:`@keyframes dialFloating {\n 0%, 100% { transform: translateY(0); }\n 50% { transform: translateY(${t.floating.maxY}px); }\n }`,dialBreathing:`@keyframes dialBreathing {\n 0%, 100% { transform: scale(1); }\n 50% { transform: scale(${t.breathing.maxScale}); }\n }`,dialRotation:`@keyframes dialRotation {\n from { transform: rotate(0deg); }\n to { transform: rotate(${dialAnimationConfig.entrance.dial.rotation.degrees}deg); }\n }`}}export function getDialCSSAnimationStyles(){const t=dialAnimationConfig.continuous;return{glitch:`dialGlitch ${3*t.glitch.stepDuration}ms ease`,pulse:`dialPulse ${2*t.pulse.duration}ms ${dialCSSBeziers.easeInOutCubic} infinite`,floating:`dialFloating ${2*t.floating.duration}ms ${dialCSSBeziers.easeInOutCubic} infinite`,breathing:`dialBreathing ${2*t.breathing.duration}ms ${dialCSSBeziers.easeInOutCubic} infinite`,dialRotation:`dialRotation ${dialAnimationConfig.entrance.dial.rotation.duration}ms ${dialCSSBeziers.easeOutCubic}`}}export function getDialCSSKeyframesString(){return Object.values(generateDialCSSKeyframes()).join("\n\n")}export function getSpiralAnimationPosition(t,n,i,e,o=DIAL_START_ANGLE){const a=getIconPosition(n,i,e,o),r=dialAnimationConfig.icons.spiral,s=dialAnimationConfig.icons.opacity,l=Math.max(0,Math.min(1,t)),c=r.startRotation+(r.endRotation-r.startRotation)*l,u=e*l,g=a.angle+c,d=u*Math.cos(g),f=u*Math.sin(g),p=d+(a.x-d)*l,m=f+(a.y-f)*l;let S;if(l<=s.inputRange[0])S=s.outputRange[0];else if(l<=s.inputRange[1]){const t=(l-s.inputRange[0])/(s.inputRange[1]-s.inputRange[0]);S=s.outputRange[0]+(s.outputRange[1]-s.outputRange[0])*t}else{const t=(l-s.inputRange[1])/(s.inputRange[2]-s.inputRange[1]);S=s.outputRange[1]+(s.outputRange[2]-s.outputRange[1])*t}return{x:p,y:m,rotation:c,scale:l,opacity:S}}export function getStaggeredIconProgress(t,n,i){const e=getIconStaggerInputRange(n,i,dialAnimationConfig.icons.staggerRatio);if(t<=e[0])return 0;if(t<=e[1])return 0;if(t>=e[3])return 1;if(t>=e[2])return 1;const o=(t-e[1])/(e[2]-e[1]);return Math.max(0,Math.min(1,o))}
@@ -1,62 +1 @@
1
- "use strict";
2
-
3
- /**
4
- * Animation easing functions.
5
- * Platform-agnostic - used by both web (RAF) and mobile (Animated).
6
- */
7
-
8
- /**
9
- * Easing functions for animations.
10
- * All functions take progress (0-1) and return eased value (0-1).
11
- */
12
- export const easing = {
13
- /**
14
- * Linear - no easing.
15
- */
16
- linear: t => t,
17
- /**
18
- * Ease out cubic - decelerates towards end.
19
- * Used for hide/show animations.
20
- */
21
- easeOutCubic: t => 1 - Math.pow(1 - t, 3),
22
- /**
23
- * Ease in cubic - accelerates from start.
24
- */
25
- easeInCubic: t => t * t * t,
26
- /**
27
- * Ease in-out cubic - smooth acceleration and deceleration.
28
- */
29
- easeInOutCubic: t => t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2,
30
- /**
31
- * Ease out quad - lighter deceleration than cubic.
32
- */
33
- easeOutQuad: t => 1 - (1 - t) * (1 - t),
34
- /**
35
- * Ease out expo - strong deceleration (snappy feel).
36
- */
37
- easeOutExpo: t => t === 1 ? 1 : 1 - Math.pow(2, -10 * t)
38
- };
39
- /**
40
- * Get an easing function by name.
41
- */
42
- export function getEasing(name) {
43
- return easing[name];
44
- }
45
-
46
- /**
47
- * Interpolate between two values using an easing function.
48
- */
49
- export function interpolate(from, to, progress, easingFn = easing.easeOutCubic) {
50
- const eased = easingFn(Math.max(0, Math.min(1, progress)));
51
- return from + (to - from) * eased;
52
- }
53
-
54
- /**
55
- * Interpolate a position (x, y) using an easing function.
56
- */
57
- export function interpolatePosition(from, to, progress, easingFn = easing.easeOutCubic) {
58
- return {
59
- x: interpolate(from.x, to.x, progress, easingFn),
60
- y: interpolate(from.y, to.y, progress, easingFn)
61
- };
62
- }
1
+ "use strict";export const easing={linear:e=>e,easeOutCubic:e=>1-Math.pow(1-e,3),easeInCubic:e=>e*e*e,easeInOutCubic:e=>e<.5?4*e*e*e:1-Math.pow(-2*e+2,3)/2,easeOutQuad:e=>1-(1-e)*(1-e),easeOutExpo:e=>1===e?1:1-Math.pow(2,-10*e)};export function getEasing(e){return easing[e]}export function interpolate(e,t,a,n=easing.easeOutCubic){return e+(t-e)*n(Math.max(0,Math.min(1,a)))}export function interpolatePosition(e,t,a,n=easing.easeOutCubic){return{x:interpolate(e.x,t.x,a,n),y:interpolate(e.y,t.y,a,n)}}
@@ -1,15 +1 @@
1
- "use strict";
2
-
3
- /**
4
- * BenchmarkIcon - Data-driven icon
5
- *
6
- * The icon is defined as pure data in icon-data.ts
7
- * The renderer transforms it to components.
8
- *
9
- * To change: edit benchmarkIconData in icon-data.ts
10
- */
11
-
12
- import { createIcon } from "./icon-renderer.js";
13
- import { benchmarkIconData, BENCHMARK_ICON_COLOR } from "./icon-data.js";
14
- export { BENCHMARK_ICON_COLOR };
15
- export const BenchmarkIcon = createIcon(benchmarkIconData);
1
+ "use strict";import{createIcon}from"./icon-renderer.js";import{benchmarkIconData,BENCHMARK_ICON_COLOR}from"./icon-data.js";export{BENCHMARK_ICON_COLOR};export const BenchmarkIcon=createIcon(benchmarkIconData);