@buoy-gg/core 7.0.15 → 7.0.16

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 (99) hide show
  1. package/lib/commonjs/floatingMenu/AppHost.web.js +359 -0
  2. package/lib/commonjs/floatingMenu/AppHostLogic.js +6 -0
  3. package/lib/commonjs/floatingMenu/DevToolsSettingsModal.web.js +787 -418
  4. package/lib/commonjs/floatingMenu/FloatingDevTools.js +1 -1
  5. package/lib/commonjs/floatingMenu/FloatingDevTools.web.js +244 -36
  6. package/lib/commonjs/floatingMenu/FloatingMenu.js +2 -2
  7. package/lib/commonjs/floatingMenu/MinimizedToolsContext.js +2 -3
  8. package/lib/commonjs/floatingMenu/MinimizedToolsStack.web.js +287 -0
  9. package/lib/commonjs/floatingMenu/autoDiscoverPresets.js +16 -0
  10. package/lib/commonjs/floatingMenu/autoExternalSync.js +9 -0
  11. package/lib/commonjs/floatingMenu/dial/DialDevTools.js +7 -4
  12. package/lib/commonjs/floatingMenu/dial/DialDevTools.web.js +373 -231
  13. package/lib/commonjs/floatingMenu/dial/DialIcon.js +25 -3
  14. package/lib/commonjs/floatingMenu/dial/OnboardingTooltip.js +1 -1
  15. package/lib/commonjs/floatingMenu/dial/OnboardingTooltip.web.js +154 -0
  16. package/lib/commonjs/floatingMenu/dial/onboardingConstants.web.js +34 -0
  17. package/lib/commonjs/floatingMenu/floatingTools.js +3 -3
  18. package/lib/commonjs/floatingMenu/floatingTools.web.js +191 -28
  19. package/lib/commonjs/index.js +2 -2
  20. package/lib/commonjs/index.web.js +19 -0
  21. package/lib/commonjs/utils/autoDiscoverPresets.web.js +50 -5
  22. package/lib/module/floatingMenu/AppHost.web.js +351 -0
  23. package/lib/module/floatingMenu/AppHostLogic.js +6 -0
  24. package/lib/module/floatingMenu/DevToolsSettingsModal.web.js +792 -422
  25. package/lib/module/floatingMenu/FloatingDevTools.js +2 -2
  26. package/lib/module/floatingMenu/FloatingDevTools.web.js +247 -38
  27. package/lib/module/floatingMenu/FloatingMenu.js +2 -2
  28. package/lib/module/floatingMenu/MinimizedToolsContext.js +2 -3
  29. package/lib/module/floatingMenu/MinimizedToolsStack.web.js +284 -0
  30. package/lib/module/floatingMenu/autoDiscoverPresets.js +16 -0
  31. package/lib/module/floatingMenu/autoExternalSync.js +9 -0
  32. package/lib/module/floatingMenu/dial/DialDevTools.js +8 -5
  33. package/lib/module/floatingMenu/dial/DialDevTools.web.js +375 -233
  34. package/lib/module/floatingMenu/dial/DialIcon.js +26 -4
  35. package/lib/module/floatingMenu/dial/OnboardingTooltip.js +1 -1
  36. package/lib/module/floatingMenu/dial/OnboardingTooltip.web.js +149 -0
  37. package/lib/module/floatingMenu/dial/onboardingConstants.web.js +27 -0
  38. package/lib/module/floatingMenu/floatingTools.js +3 -3
  39. package/lib/module/floatingMenu/floatingTools.web.js +190 -28
  40. package/lib/module/index.js +2 -2
  41. package/lib/module/index.web.js +5 -0
  42. package/lib/module/utils/autoDiscoverPresets.web.js +53 -7
  43. package/lib/typescript/commonjs/floatingMenu/AppHost.web.d.ts +38 -0
  44. package/lib/typescript/commonjs/floatingMenu/AppHost.web.d.ts.map +1 -0
  45. package/lib/typescript/commonjs/floatingMenu/AppHostLogic.d.ts +21 -1
  46. package/lib/typescript/commonjs/floatingMenu/AppHostLogic.d.ts.map +1 -1
  47. package/lib/typescript/commonjs/floatingMenu/DevToolsSettingsModal.web.d.ts +5 -2
  48. package/lib/typescript/commonjs/floatingMenu/DevToolsSettingsModal.web.d.ts.map +1 -1
  49. package/lib/typescript/commonjs/floatingMenu/FloatingDevTools.web.d.ts +2 -14
  50. package/lib/typescript/commonjs/floatingMenu/FloatingDevTools.web.d.ts.map +1 -1
  51. package/lib/typescript/commonjs/floatingMenu/MinimizedToolsContext.d.ts +2 -20
  52. package/lib/typescript/commonjs/floatingMenu/MinimizedToolsContext.d.ts.map +1 -1
  53. package/lib/typescript/commonjs/floatingMenu/MinimizedToolsStack.web.d.ts +21 -0
  54. package/lib/typescript/commonjs/floatingMenu/MinimizedToolsStack.web.d.ts.map +1 -0
  55. package/lib/typescript/commonjs/floatingMenu/autoDiscoverPresets.d.ts.map +1 -1
  56. package/lib/typescript/commonjs/floatingMenu/autoExternalSync.d.ts.map +1 -1
  57. package/lib/typescript/commonjs/floatingMenu/dial/DialDevTools.d.ts.map +1 -1
  58. package/lib/typescript/commonjs/floatingMenu/dial/DialDevTools.web.d.ts +16 -2
  59. package/lib/typescript/commonjs/floatingMenu/dial/DialDevTools.web.d.ts.map +1 -1
  60. package/lib/typescript/commonjs/floatingMenu/dial/DialIcon.d.ts.map +1 -1
  61. package/lib/typescript/commonjs/floatingMenu/dial/OnboardingTooltip.web.d.ts +9 -0
  62. package/lib/typescript/commonjs/floatingMenu/dial/OnboardingTooltip.web.d.ts.map +1 -0
  63. package/lib/typescript/commonjs/floatingMenu/dial/onboardingConstants.web.d.ts +13 -0
  64. package/lib/typescript/commonjs/floatingMenu/dial/onboardingConstants.web.d.ts.map +1 -0
  65. package/lib/typescript/commonjs/floatingMenu/floatingTools.web.d.ts +29 -2
  66. package/lib/typescript/commonjs/floatingMenu/floatingTools.web.d.ts.map +1 -1
  67. package/lib/typescript/commonjs/index.web.d.ts +1 -0
  68. package/lib/typescript/commonjs/index.web.d.ts.map +1 -1
  69. package/lib/typescript/commonjs/utils/autoDiscoverPresets.web.d.ts +2 -0
  70. package/lib/typescript/commonjs/utils/autoDiscoverPresets.web.d.ts.map +1 -1
  71. package/lib/typescript/module/floatingMenu/AppHost.web.d.ts +38 -0
  72. package/lib/typescript/module/floatingMenu/AppHost.web.d.ts.map +1 -0
  73. package/lib/typescript/module/floatingMenu/AppHostLogic.d.ts +21 -1
  74. package/lib/typescript/module/floatingMenu/AppHostLogic.d.ts.map +1 -1
  75. package/lib/typescript/module/floatingMenu/DevToolsSettingsModal.web.d.ts +5 -2
  76. package/lib/typescript/module/floatingMenu/DevToolsSettingsModal.web.d.ts.map +1 -1
  77. package/lib/typescript/module/floatingMenu/FloatingDevTools.web.d.ts +2 -14
  78. package/lib/typescript/module/floatingMenu/FloatingDevTools.web.d.ts.map +1 -1
  79. package/lib/typescript/module/floatingMenu/MinimizedToolsContext.d.ts +2 -20
  80. package/lib/typescript/module/floatingMenu/MinimizedToolsContext.d.ts.map +1 -1
  81. package/lib/typescript/module/floatingMenu/MinimizedToolsStack.web.d.ts +21 -0
  82. package/lib/typescript/module/floatingMenu/MinimizedToolsStack.web.d.ts.map +1 -0
  83. package/lib/typescript/module/floatingMenu/autoDiscoverPresets.d.ts.map +1 -1
  84. package/lib/typescript/module/floatingMenu/autoExternalSync.d.ts.map +1 -1
  85. package/lib/typescript/module/floatingMenu/dial/DialDevTools.d.ts.map +1 -1
  86. package/lib/typescript/module/floatingMenu/dial/DialDevTools.web.d.ts +16 -2
  87. package/lib/typescript/module/floatingMenu/dial/DialDevTools.web.d.ts.map +1 -1
  88. package/lib/typescript/module/floatingMenu/dial/DialIcon.d.ts.map +1 -1
  89. package/lib/typescript/module/floatingMenu/dial/OnboardingTooltip.web.d.ts +9 -0
  90. package/lib/typescript/module/floatingMenu/dial/OnboardingTooltip.web.d.ts.map +1 -0
  91. package/lib/typescript/module/floatingMenu/dial/onboardingConstants.web.d.ts +13 -0
  92. package/lib/typescript/module/floatingMenu/dial/onboardingConstants.web.d.ts.map +1 -0
  93. package/lib/typescript/module/floatingMenu/floatingTools.web.d.ts +29 -2
  94. package/lib/typescript/module/floatingMenu/floatingTools.web.d.ts.map +1 -1
  95. package/lib/typescript/module/index.web.d.ts +1 -0
  96. package/lib/typescript/module/index.web.d.ts.map +1 -1
  97. package/lib/typescript/module/utils/autoDiscoverPresets.web.d.ts +2 -0
  98. package/lib/typescript/module/utils/autoDiscoverPresets.web.d.ts.map +1 -1
  99. package/package.json +5 -5
@@ -0,0 +1,284 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * MinimizedToolsStack — Web twin of MinimizedToolsStack.tsx +
5
+ * shared-ui's ExpandablePopover (inlined: the popover is only used here on
6
+ * web). A vertical stack of minimized-tool icons fused to the top of the
7
+ * floating bubble's drag handle:
8
+ * - collapsed: a 28px "peek" tab (chevron-up + count) with top corners only
9
+ * - expanded: animated-height panel, icons newest-first, collapse chevron
10
+ * - expanded state persists under "@react_buoy_minimized_stack_expanded"
11
+ * - each icon runs the native randomized glitch loop (translateX shake +
12
+ * opacity flicker + scale pulse, 80ms), scheduled every 2-6s + index*300ms
13
+ *
14
+ * Data comes from the web AppHost (openApps with minimized === true) instead
15
+ * of the native MinimizedToolsContext — same derivation the MinimizedDock
16
+ * used before this replaced it.
17
+ */
18
+
19
+ import { useCallback, useEffect, useRef, useState } from 'react';
20
+ import { persistentStorage } from '@buoy-gg/shared-ui';
21
+ import { useAppHost } from "./AppHost.web.js";
22
+
23
+ // native MinimizedToolsStack.tsx constants
24
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
25
+ const PEEK_HEIGHT = 28;
26
+ const TOOL_ITEM_SIZE = 32;
27
+ const ICON_GAP = 6;
28
+ const TOOLBAR_PADDING = 8;
29
+ const COLLAPSE_BUTTON_SIZE = 24;
30
+ const STORAGE_KEY_EXPANDED = '@react_buoy_minimized_stack_expanded';
31
+ const GLITCH_DURATION_MS = 80;
32
+ const MIN_GLITCH_DELAY = 2000;
33
+ const MAX_GLITCH_DELAY = 6000;
34
+
35
+ // native shared-ui buoyColors (gameUIColors.ts) — card + textMuted
36
+ const CARD = '#1A1A1A';
37
+ const TEXT_MUTED = '#888888';
38
+ function ChevronGlyph({
39
+ down = false
40
+ }) {
41
+ // native: ChevronUp size 12, strokeWidth 2, buoyColors.textMuted
42
+ return /*#__PURE__*/_jsx("svg", {
43
+ width: 12,
44
+ height: 12,
45
+ viewBox: "0 0 24 24",
46
+ "aria-hidden": "true",
47
+ style: {
48
+ transform: down ? 'rotate(180deg)' : undefined
49
+ },
50
+ children: /*#__PURE__*/_jsx("path", {
51
+ d: "M18 15l-6-6-6 6",
52
+ fill: "none",
53
+ stroke: TEXT_MUTED,
54
+ strokeWidth: "2",
55
+ strokeLinecap: "round",
56
+ strokeLinejoin: "round"
57
+ })
58
+ });
59
+ }
60
+ function GlitchToolButton({
61
+ title,
62
+ icon,
63
+ index,
64
+ onPress
65
+ }) {
66
+ const innerRef = useRef(null);
67
+ useEffect(() => {
68
+ let mounted = true;
69
+ let timer;
70
+ const runGlitch = () => {
71
+ // native: parallel translateX shake / opacity flicker / scale pulse,
72
+ // all inside GLITCH_DURATION_MS — one WAAPI animation with offsets.
73
+ innerRef.current?.animate([{
74
+ transform: 'translateX(0) scale(1)',
75
+ opacity: 1,
76
+ offset: 0
77
+ }, {
78
+ transform: 'translateX(3px) scale(1.05)',
79
+ opacity: 0.4,
80
+ offset: 0.2
81
+ }, {
82
+ transform: 'translateX(-3px) scale(1.1)',
83
+ opacity: 1,
84
+ offset: 0.4
85
+ }, {
86
+ transform: 'translateX(2px) scale(1.0)',
87
+ opacity: 0.6,
88
+ offset: 0.6
89
+ }, {
90
+ transform: 'translateX(-1px) scale(0.95)',
91
+ opacity: 1,
92
+ offset: 0.8
93
+ }, {
94
+ transform: 'translateX(0) scale(1)',
95
+ opacity: 1,
96
+ offset: 1
97
+ }], {
98
+ duration: GLITCH_DURATION_MS,
99
+ easing: 'linear'
100
+ });
101
+ };
102
+ const schedule = initial => {
103
+ const delay = initial ? 500 + Math.random() * 1500 + index * 200 : MIN_GLITCH_DELAY + Math.random() * (MAX_GLITCH_DELAY - MIN_GLITCH_DELAY) + index * 300;
104
+ timer = setTimeout(() => {
105
+ if (!mounted) return;
106
+ runGlitch();
107
+ schedule(false);
108
+ }, delay);
109
+ };
110
+ schedule(true);
111
+ return () => {
112
+ mounted = false;
113
+ clearTimeout(timer);
114
+ };
115
+ }, [index]);
116
+ return /*#__PURE__*/_jsx("button", {
117
+ type: "button",
118
+ "aria-label": `Restore ${title}`,
119
+ onClick: onPress,
120
+ style: {
121
+ width: TOOL_ITEM_SIZE,
122
+ height: TOOL_ITEM_SIZE,
123
+ display: 'flex',
124
+ alignItems: 'center',
125
+ justifyContent: 'center',
126
+ background: 'none',
127
+ border: 'none',
128
+ padding: 0,
129
+ cursor: 'pointer'
130
+ },
131
+ children: /*#__PURE__*/_jsx("div", {
132
+ ref: innerRef,
133
+ style: {
134
+ display: 'flex',
135
+ alignItems: 'center',
136
+ justifyContent: 'center'
137
+ },
138
+ children: icon
139
+ })
140
+ });
141
+ }
142
+ export function MinimizedToolsStack({
143
+ containerWidth = 32
144
+ }) {
145
+ const {
146
+ openApps,
147
+ restore
148
+ } = useAppHost();
149
+ const minimized = openApps.filter(app => app.minimized && app.launchMode !== 'toggle-only');
150
+ const [isExpanded, setIsExpanded] = useState(false);
151
+ const [isStateRestored, setIsStateRestored] = useState(false);
152
+
153
+ // Restore + persist the expanded flag (native ExpandablePopover persistState).
154
+ useEffect(() => {
155
+ let cancelled = false;
156
+ const load = async () => {
157
+ const saved = await persistentStorage.getItem(STORAGE_KEY_EXPANDED);
158
+ if (!cancelled && saved === 'true') setIsExpanded(true);
159
+ if (!cancelled) setIsStateRestored(true);
160
+ };
161
+ void load();
162
+ return () => {
163
+ cancelled = true;
164
+ };
165
+ }, []);
166
+ useEffect(() => {
167
+ if (!isStateRestored) return;
168
+ void persistentStorage.setItem(STORAGE_KEY_EXPANDED, isExpanded ? 'true' : 'false');
169
+ }, [isExpanded, isStateRestored]);
170
+ const handleRestore = useCallback(instanceId => {
171
+ restore(instanceId);
172
+ }, [restore]);
173
+ if (minimized.length === 0) return null;
174
+
175
+ // native: expandedHeight = padding + n*item + (n-1)*gap + gap + collapse + 4
176
+ const expandedHeight = TOOLBAR_PADDING + minimized.length * TOOL_ITEM_SIZE + (minimized.length - 1) * ICON_GAP + ICON_GAP + COLLAPSE_BUTTON_SIZE + 4;
177
+ const frame = {
178
+ // native peekButton/expandedContainer: card bg, top corners 6, 1px border
179
+ // on top/left/right only (fuses with the bubble below)
180
+ backgroundColor: CARD,
181
+ borderTopLeftRadius: 6,
182
+ borderTopRightRadius: 6,
183
+ borderTop: `1px solid ${TEXT_MUTED}66`,
184
+ borderLeft: `1px solid ${TEXT_MUTED}66`,
185
+ borderRight: `1px solid ${TEXT_MUTED}66`,
186
+ borderBottom: 'none',
187
+ boxSizing: 'border-box'
188
+ };
189
+ return /*#__PURE__*/_jsxs("div", {
190
+ style: {
191
+ height: PEEK_HEIGHT,
192
+ overflow: 'visible',
193
+ position: 'relative'
194
+ },
195
+ children: [/*#__PURE__*/_jsx("div", {
196
+ style: {
197
+ position: 'absolute',
198
+ bottom: 0,
199
+ left: 0,
200
+ width: containerWidth,
201
+ height: isExpanded ? expandedHeight : 0,
202
+ opacity: isExpanded ? 1 : 0,
203
+ overflow: 'hidden',
204
+ transition: 'height 200ms ease, opacity 200ms ease',
205
+ pointerEvents: isExpanded ? 'auto' : 'none',
206
+ ...frame
207
+ },
208
+ children: /*#__PURE__*/_jsxs("div", {
209
+ style: {
210
+ height: expandedHeight,
211
+ display: 'flex',
212
+ flexDirection: 'column',
213
+ alignItems: 'center',
214
+ paddingTop: TOOLBAR_PADDING,
215
+ gap: ICON_GAP,
216
+ boxSizing: 'border-box'
217
+ },
218
+ children: [[...minimized].reverse().map((app, index) => /*#__PURE__*/_jsx(GlitchToolButton, {
219
+ title: app.title || app.id,
220
+ icon: app.icon ?? /*#__PURE__*/_jsx("span", {
221
+ style: {
222
+ color: '#fff',
223
+ fontSize: 13
224
+ },
225
+ children: (app.title || app.id).slice(0, 1).toUpperCase()
226
+ }),
227
+ index: index,
228
+ onPress: () => handleRestore(app.instanceId)
229
+ }, app.instanceId)), /*#__PURE__*/_jsx("button", {
230
+ type: "button",
231
+ "aria-label": "Collapse",
232
+ onClick: () => setIsExpanded(false),
233
+ style: {
234
+ width: '100%',
235
+ height: COLLAPSE_BUTTON_SIZE,
236
+ marginTop: 3,
237
+ display: 'flex',
238
+ alignItems: 'center',
239
+ justifyContent: 'center',
240
+ background: 'none',
241
+ border: 'none',
242
+ cursor: 'pointer',
243
+ padding: 0
244
+ },
245
+ children: /*#__PURE__*/_jsx(ChevronGlyph, {
246
+ down: true
247
+ })
248
+ })]
249
+ })
250
+ }), /*#__PURE__*/_jsxs("button", {
251
+ type: "button",
252
+ "aria-label": `Show ${minimized.length} minimized tools`,
253
+ onClick: () => setIsExpanded(true),
254
+ style: {
255
+ position: 'absolute',
256
+ bottom: 0,
257
+ left: 0,
258
+ width: containerWidth,
259
+ height: PEEK_HEIGHT,
260
+ display: 'flex',
261
+ flexDirection: 'row',
262
+ alignItems: 'center',
263
+ justifyContent: 'center',
264
+ gap: 2,
265
+ cursor: 'pointer',
266
+ padding: 0,
267
+ opacity: isExpanded ? 0 : 1,
268
+ transform: isExpanded ? 'scale(0.9)' : 'scale(1)',
269
+ transition: 'opacity 200ms ease, transform 200ms ease',
270
+ pointerEvents: isExpanded ? 'none' : 'auto',
271
+ ...frame
272
+ },
273
+ children: [/*#__PURE__*/_jsx(ChevronGlyph, {}), minimized.length > 1 && /*#__PURE__*/_jsx("span", {
274
+ style: {
275
+ fontSize: 9,
276
+ fontWeight: 600,
277
+ color: TEXT_MUTED,
278
+ marginLeft: 1
279
+ },
280
+ children: minimized.length
281
+ })]
282
+ })]
283
+ });
284
+ }
@@ -314,6 +314,22 @@ export function autoDiscoverPresets() {
314
314
  return null;
315
315
  }
316
316
  }
317
+ },
318
+ // ASSETS — bundled-asset inventory (sizes / scale coverage / unused)
319
+ {
320
+ name: "@buoy-gg/assets",
321
+ loader: () => {
322
+ try {
323
+ // @ts-ignore - Dynamic import that may not exist
324
+ const {
325
+ assetsToolPreset
326
+ } = require("@buoy-gg/assets");
327
+ return assetsToolPreset;
328
+ } catch (e) {
329
+ reportOptionalRequireError("@buoy-gg/assets", e);
330
+ return null;
331
+ }
332
+ }
317
333
  }];
318
334
 
319
335
  // Attempt to load each preset
@@ -46,6 +46,7 @@ let impersonateModule = null;
46
46
  let perfMonitorModule = null;
47
47
  let jsTopModule = null;
48
48
  let imagesModule = null;
49
+ let assetsModule = null;
49
50
  let expoConstantsModule = null;
50
51
 
51
52
  // Catch bodies report through reportOptionalRequireError: silent for a
@@ -136,6 +137,11 @@ try {
136
137
  } catch (e) {
137
138
  reportOptionalRequireError("@buoy-gg/images", e);
138
139
  }
140
+ try {
141
+ assetsModule = require("@buoy-gg/assets");
142
+ } catch (e) {
143
+ reportOptionalRequireError("@buoy-gg/assets", e);
144
+ }
139
145
  try {
140
146
  expoConstantsModule = require("expo-constants");
141
147
  } catch (e) {
@@ -270,6 +276,9 @@ export function AutoExternalSync({
270
276
  if (imagesModule?.imagesSyncAdapter) {
271
277
  map.images = imagesModule.imagesSyncAdapter;
272
278
  }
279
+ if (assetsModule?.assetsSyncAdapter) {
280
+ map.assets = assetsModule.assetsSyncAdapter;
281
+ }
273
282
  return map;
274
283
  }, [queryAdapter, requiredEnvVars]);
275
284
  useExternalSync({
@@ -11,9 +11,9 @@ import { getRankedToolIds, isDialUsageLoaded, loadDialUsage, recordToolUsage } f
11
11
  import { persistentStorage, useHintsDisabled, devToolsStorageKeys, buoyColors } from "@buoy-gg/shared-ui";
12
12
  import { DevToolsSettingsModal, useDevToolsSettings } from "../DevToolsSettingsModal";
13
13
  import { useProAccess } from "@buoy-gg/license";
14
- import { useAppHost } from "../AppHost.js";
15
- import { OnboardingTooltip } from "./OnboardingTooltip.js";
16
- import { getDialLayout, MAX_DIAL_SLOTS, DIAL_BUTTON_SIZE, DIAL_ICON_SIZE, dialAnimationConfig, dialColors } from "@buoy-gg/floating-tools-core";
14
+ import { useAppHost } from "../AppHost";
15
+ import { OnboardingTooltip } from "./OnboardingTooltip";
16
+ import { getDialLayout, MAX_DIAL_SLOTS, DIAL_BUTTON_SIZE, DIAL_ICON_GLYPH_SIZE, dialAnimationConfig, dialColors } from "@buoy-gg/floating-tools-core";
17
17
 
18
18
  // The circle size depends on the live window width, so it's computed inside
19
19
  // the component via useWindowDimensions — a module-scope Dimensions.get
@@ -227,8 +227,11 @@ export const DialDevTools = ({
227
227
  map.set(tool.id, {
228
228
  id: tool.id,
229
229
  name: tool.name,
230
- // Pre-render the icon at the standard dial slot size so it looks correct.
231
- icon: tool.renderIcon(DIAL_ICON_SIZE),
230
+ // Pre-render the icon at the standard GLYPH size (not the slot size —
231
+ // the slot also holds the label + "Unavailable" caption, so a glyph
232
+ // rendered at DIAL_ICON_SIZE overflows the slot and looks ~2x bigger
233
+ // than installed tools' icons).
234
+ icon: tool.renderIcon(DIAL_ICON_GLYPH_SIZE),
232
235
  iconComponent: undefined,
233
236
  color: tool.color,
234
237
  unavailable: true,