@littlecarlito/blorktools 0.50.3 → 0.51.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.
Files changed (114) hide show
  1. package/bin/cli.js +69 -0
  2. package/package.json +13 -7
  3. package/src/asset_debugger/axis-indicator/axis-indicator.css +6 -0
  4. package/src/asset_debugger/axis-indicator/axis-indicator.html +20 -0
  5. package/src/asset_debugger/axis-indicator/axis-indicator.js +822 -0
  6. package/src/asset_debugger/debugger-scene/debugger-scene.css +142 -0
  7. package/src/asset_debugger/debugger-scene/debugger-scene.html +80 -0
  8. package/src/asset_debugger/debugger-scene/debugger-scene.js +791 -0
  9. package/src/asset_debugger/header/header.css +73 -0
  10. package/src/asset_debugger/header/header.html +24 -0
  11. package/src/asset_debugger/header/header.js +224 -0
  12. package/src/asset_debugger/index.html +76 -0
  13. package/src/asset_debugger/landing-page/landing-page.css +396 -0
  14. package/src/asset_debugger/landing-page/landing-page.html +81 -0
  15. package/src/asset_debugger/landing-page/landing-page.js +611 -0
  16. package/src/asset_debugger/loading-splash/loading-splash.css +195 -0
  17. package/src/asset_debugger/loading-splash/loading-splash.html +22 -0
  18. package/src/asset_debugger/loading-splash/loading-splash.js +59 -0
  19. package/src/asset_debugger/loading-splash/preview-loading-splash.js +66 -0
  20. package/src/asset_debugger/main.css +14 -0
  21. package/src/asset_debugger/modals/examples-modal/examples-modal.css +41 -0
  22. package/src/asset_debugger/modals/examples-modal/examples-modal.html +18 -0
  23. package/src/asset_debugger/modals/examples-modal/examples-modal.js +111 -0
  24. package/src/asset_debugger/modals/examples-modal/examples.js +125 -0
  25. package/src/asset_debugger/modals/html-editor-modal/html-editor-modal.css +452 -0
  26. package/src/asset_debugger/modals/html-editor-modal/html-editor-modal.html +87 -0
  27. package/src/asset_debugger/modals/html-editor-modal/html-editor-modal.js +675 -0
  28. package/src/asset_debugger/modals/mesh-info-modal/mesh-info-modal.css +219 -0
  29. package/src/asset_debugger/modals/mesh-info-modal/mesh-info-modal.html +20 -0
  30. package/src/asset_debugger/modals/mesh-info-modal/mesh-info-modal.js +548 -0
  31. package/src/asset_debugger/modals/settings-modal/settings-modal.css +103 -0
  32. package/src/asset_debugger/modals/settings-modal/settings-modal.html +158 -0
  33. package/src/asset_debugger/modals/settings-modal/settings-modal.js +475 -0
  34. package/src/asset_debugger/panels/asset-panel/asset-panel.css +263 -0
  35. package/src/asset_debugger/panels/asset-panel/asset-panel.html +123 -0
  36. package/src/asset_debugger/panels/asset-panel/asset-panel.js +136 -0
  37. package/src/asset_debugger/panels/asset-panel/atlas-heading/atlas-heading.css +94 -0
  38. package/src/asset_debugger/panels/asset-panel/atlas-heading/atlas-heading.js +312 -0
  39. package/src/asset_debugger/panels/asset-panel/mesh-heading/mesh-heading.css +129 -0
  40. package/src/asset_debugger/panels/asset-panel/mesh-heading/mesh-heading.js +486 -0
  41. package/src/asset_debugger/panels/asset-panel/rig-heading/rig-heading.css +545 -0
  42. package/src/asset_debugger/panels/asset-panel/rig-heading/rig-heading.js +538 -0
  43. package/src/asset_debugger/panels/asset-panel/uv-heading/uv-heading.css +70 -0
  44. package/src/asset_debugger/panels/asset-panel/uv-heading/uv-heading.js +586 -0
  45. package/src/asset_debugger/panels/world-panel/world-panel.css +364 -0
  46. package/src/asset_debugger/panels/world-panel/world-panel.html +173 -0
  47. package/src/asset_debugger/panels/world-panel/world-panel.js +1891 -0
  48. package/src/asset_debugger/router.js +190 -0
  49. package/src/asset_debugger/util/animation/playback/animation-playback-controller.js +150 -0
  50. package/src/asset_debugger/util/animation/playback/animation-preview-controller.js +316 -0
  51. package/src/asset_debugger/util/animation/playback/css3d-bounce-controller.js +400 -0
  52. package/src/asset_debugger/util/animation/playback/css3d-reversal-controller.js +821 -0
  53. package/src/asset_debugger/util/animation/render/css3d-prerender-controller.js +696 -0
  54. package/src/asset_debugger/util/animation/render/debug-texture-factory.js +0 -0
  55. package/src/asset_debugger/util/animation/render/iframe2texture-render-controller.js +199 -0
  56. package/src/asset_debugger/util/animation/render/image2texture-prerender-controller.js +461 -0
  57. package/src/asset_debugger/util/animation/render/pbr-material-factory.js +82 -0
  58. package/src/asset_debugger/util/common.css +280 -0
  59. package/src/asset_debugger/util/data/animation-classifier.js +323 -0
  60. package/src/asset_debugger/util/data/duplicate-handler.js +20 -0
  61. package/src/asset_debugger/util/data/glb-buffer-manager.js +407 -0
  62. package/src/asset_debugger/util/data/glb-classifier.js +290 -0
  63. package/src/asset_debugger/util/data/html-formatter.js +76 -0
  64. package/src/asset_debugger/util/data/html-linter.js +276 -0
  65. package/src/asset_debugger/util/data/localstorage-manager.js +265 -0
  66. package/src/asset_debugger/util/data/mesh-html-manager.js +295 -0
  67. package/src/asset_debugger/util/data/string-serder.js +303 -0
  68. package/src/asset_debugger/util/data/texture-classifier.js +663 -0
  69. package/src/asset_debugger/util/data/upload/background-file-handler.js +292 -0
  70. package/src/asset_debugger/util/data/upload/dropzone-preview-controller.js +396 -0
  71. package/src/asset_debugger/util/data/upload/file-upload-manager.js +495 -0
  72. package/src/asset_debugger/util/data/upload/glb-file-handler.js +36 -0
  73. package/src/asset_debugger/util/data/upload/glb-preview-controller.js +317 -0
  74. package/src/asset_debugger/util/data/upload/lighting-file-handler.js +194 -0
  75. package/src/asset_debugger/util/data/upload/model-file-manager.js +104 -0
  76. package/src/asset_debugger/util/data/upload/texture-file-handler.js +166 -0
  77. package/src/asset_debugger/util/data/upload/zip-handler.js +686 -0
  78. package/src/asset_debugger/util/loaders/html2canvas-loader.js +107 -0
  79. package/src/asset_debugger/util/rig/bone-kinematics.js +403 -0
  80. package/src/asset_debugger/util/rig/rig-constraint-manager.js +618 -0
  81. package/src/asset_debugger/util/rig/rig-controller.js +612 -0
  82. package/src/asset_debugger/util/rig/rig-factory.js +628 -0
  83. package/src/asset_debugger/util/rig/rig-handle-factory.js +46 -0
  84. package/src/asset_debugger/util/rig/rig-label-factory.js +441 -0
  85. package/src/asset_debugger/util/rig/rig-mouse-handler.js +377 -0
  86. package/src/asset_debugger/util/rig/rig-state-manager.js +175 -0
  87. package/src/asset_debugger/util/rig/rig-tooltip-manager.js +267 -0
  88. package/src/asset_debugger/util/rig/rig-ui-factory.js +700 -0
  89. package/src/asset_debugger/util/scene/background-manager.js +284 -0
  90. package/src/asset_debugger/util/scene/camera-controller.js +243 -0
  91. package/src/asset_debugger/util/scene/css3d-debug-controller.js +406 -0
  92. package/src/asset_debugger/util/scene/css3d-frame-factory.js +113 -0
  93. package/src/asset_debugger/util/scene/css3d-scene-manager.js +529 -0
  94. package/src/asset_debugger/util/scene/glb-controller.js +208 -0
  95. package/src/asset_debugger/util/scene/lighting-manager.js +690 -0
  96. package/src/asset_debugger/util/scene/threejs-model-manager.js +437 -0
  97. package/src/asset_debugger/util/scene/threejs-preview-manager.js +207 -0
  98. package/src/asset_debugger/util/scene/threejs-preview-setup.js +478 -0
  99. package/src/asset_debugger/util/scene/threejs-scene-controller.js +286 -0
  100. package/src/asset_debugger/util/scene/ui-manager.js +107 -0
  101. package/src/asset_debugger/util/state/animation-state.js +128 -0
  102. package/src/asset_debugger/util/state/css3d-state.js +83 -0
  103. package/src/asset_debugger/util/state/glb-preview-state.js +31 -0
  104. package/src/asset_debugger/util/state/log-util.js +197 -0
  105. package/src/asset_debugger/util/state/scene-state.js +452 -0
  106. package/src/asset_debugger/util/state/threejs-state.js +54 -0
  107. package/src/asset_debugger/util/workers/lighting-worker.js +61 -0
  108. package/src/asset_debugger/util/workers/model-worker.js +109 -0
  109. package/src/asset_debugger/util/workers/texture-worker.js +54 -0
  110. package/src/asset_debugger/util/workers/worker-manager.js +212 -0
  111. package/src/asset_debugger/widgets/mesh-info-widget.js +280 -0
  112. package/src/index.html +261 -0
  113. package/src/index.js +8 -0
  114. package/vite.config.js +66 -0
@@ -0,0 +1,312 @@
1
+ /**
2
+ * Texture Debugger - Atlas Panel Module
3
+ *
4
+ * This module handles texture atlas visualization in the UI.
5
+ */
6
+
7
+ import { getState, updateState } from '../../../util/state/scene-state.js';
8
+
9
+ // Track initialization state
10
+ let isInitialized = false;
11
+
12
+ /**
13
+ * Initialize the atlas panel and set up event listeners
14
+ */
15
+ export function initAtlasPanel() {
16
+ // Prevent duplicate logging but allow initialization to continue
17
+ if (isInitialized) {
18
+ return;
19
+ }
20
+
21
+ isInitialized = true;
22
+
23
+ // Initialize the panel once the atlas-heading-container is found and has content
24
+ const initCheck = setInterval(() => {
25
+ const container = document.getElementById('atlas-heading-container');
26
+ if (container && container.children.length > 0) {
27
+ clearInterval(initCheck);
28
+ setupAtlasPanelEvents();
29
+ }
30
+ }, 100);
31
+ }
32
+
33
+ /**
34
+ * Set up event listeners for the atlas panel
35
+ */
36
+ function setupAtlasPanelEvents() {
37
+ const textureTypeButtons = document.querySelectorAll('.texture-type-button');
38
+
39
+ // Check if any button has the active class
40
+ let hasActiveButton = false;
41
+ textureTypeButtons.forEach(button => {
42
+ if (button.classList.contains('active')) {
43
+ hasActiveButton = true;
44
+ }
45
+ });
46
+
47
+ // If no button is active, set the first one as active
48
+ if (!hasActiveButton && textureTypeButtons.length > 0) {
49
+ textureTypeButtons[0].classList.add('active');
50
+ // Update state with the default texture type
51
+ updateState('currentTextureType', textureTypeButtons[0].dataset.textureType);
52
+ }
53
+
54
+ // Set up texture type button handlers
55
+ textureTypeButtons.forEach(button => {
56
+ button.addEventListener('click', () => {
57
+ // Update active state
58
+ textureTypeButtons.forEach(btn => btn.classList.remove('active'));
59
+ button.classList.add('active');
60
+
61
+ // Update current texture type in state
62
+ updateState('currentTextureType', button.dataset.textureType);
63
+
64
+ // Update visualization
65
+ updateAtlasVisualization();
66
+ });
67
+ });
68
+
69
+ // Initialize visualization
70
+ updateAtlasVisualization();
71
+ }
72
+
73
+ /**
74
+ * Update the atlas visualization based on current texture state
75
+ */
76
+ export function updateAtlasVisualization() {
77
+ // Get state to retrieve texture objects
78
+ const state = getState();
79
+
80
+ // Check if we have texture objects
81
+ if (!state.textureObjects) {
82
+ console.warn('No texture objects available for atlas visualization');
83
+ // Show no texture state for the canvas
84
+ const atlasCanvas = document.getElementById('atlas-canvas');
85
+ if (atlasCanvas) {
86
+ showNoTextureState(atlasCanvas);
87
+ }
88
+ return;
89
+ }
90
+
91
+ // Get the current atlas textures
92
+ const baseColorTexture = state.textureObjects.baseColor;
93
+ const ormTexture = state.textureObjects.orm;
94
+ const normalTexture = state.textureObjects.normal;
95
+
96
+ // Get the current texture type from state
97
+ const currentTextureType = state.currentTextureType || 'baseColor';
98
+
99
+ // Get the active texture based on current texture type
100
+ let activeTexture = null;
101
+ if (currentTextureType === 'baseColor') {
102
+ activeTexture = baseColorTexture;
103
+ } else if (currentTextureType === 'orm') {
104
+ activeTexture = ormTexture;
105
+ } else if (currentTextureType === 'normal') {
106
+ activeTexture = normalTexture;
107
+ }
108
+
109
+ // Get the atlas canvas
110
+ const atlasCanvas = document.getElementById('atlas-canvas');
111
+ if (!atlasCanvas) {
112
+ console.warn('Atlas canvas not found');
113
+ return;
114
+ }
115
+
116
+ // Get current UV region from state or use default
117
+ const currentRegion = state.currentUvRegion || { min: [0, 0], max: [1, 1] };
118
+
119
+ // Show the active texture or no texture state
120
+ if (activeTexture) {
121
+ updateCanvasWithTexture(activeTexture, currentRegion);
122
+ } else {
123
+ showNoTextureState(atlasCanvas);
124
+ }
125
+ }
126
+
127
+ /**
128
+ * Update the canvas with the texture
129
+ * @param {THREE.Texture} texture - The texture to display
130
+ * @param {Object} currentRegion - The UV region to highlight
131
+ */
132
+ function updateCanvasWithTexture(texture, currentRegion = { min: [0, 0], max: [1, 1] }) {
133
+ const atlasCanvas = document.getElementById('atlas-canvas');
134
+ const coordsText = document.getElementById('coords-text');
135
+
136
+ if (!atlasCanvas || !texture || !texture.image) return;
137
+
138
+ const ctx = atlasCanvas.getContext('2d');
139
+
140
+ // Set canvas dimensions to match texture
141
+ atlasCanvas.width = texture.image.width;
142
+ atlasCanvas.height = texture.image.height;
143
+
144
+ // Clear canvas
145
+ ctx.clearRect(0, 0, atlasCanvas.width, atlasCanvas.height);
146
+
147
+ // Draw the texture with proper scaling
148
+ try {
149
+ ctx.drawImage(texture.image, 0, 0);
150
+ } catch (error) {
151
+ console.error('Error drawing texture to canvas:', error);
152
+ }
153
+
154
+ // Add overlay grid for UV coordinates
155
+ drawUvGrid(ctx, atlasCanvas.width, atlasCanvas.height);
156
+
157
+ // Draw red highlight to show current region used on the model
158
+ drawHighlightRegion(ctx, currentRegion, atlasCanvas.width, atlasCanvas.height);
159
+
160
+ // Set proper CSS for the canvas
161
+ atlasCanvas.style.width = '100%';
162
+ atlasCanvas.style.height = 'auto';
163
+ atlasCanvas.style.maxHeight = '100%';
164
+ atlasCanvas.style.objectFit = 'contain';
165
+ atlasCanvas.style.display = 'block';
166
+
167
+ // Update coordinates text
168
+ if (coordsText) {
169
+ const isFullTexture = (currentRegion.min[0] === 0 && currentRegion.min[1] === 0 &&
170
+ currentRegion.max[0] === 1 && currentRegion.max[1] === 1);
171
+
172
+ if (isFullTexture) {
173
+ coordsText.textContent = `${getState().currentTextureType}: Full texture (0,0) to (1,1)`;
174
+ } else {
175
+ coordsText.textContent = `${getState().currentTextureType}: (${currentRegion.min[0].toFixed(2)},${currentRegion.min[1].toFixed(2)}) to (${currentRegion.max[0].toFixed(2)},${currentRegion.max[1].toFixed(2)})`;
176
+ }
177
+ }
178
+ }
179
+
180
+ /**
181
+ * Show "No texture loaded" message in the canvas
182
+ * @param {HTMLCanvasElement} atlasCanvas - The canvas element
183
+ */
184
+ function showNoTextureState(atlasCanvas) {
185
+ const coordsText = document.getElementById('coords-text');
186
+ if (!atlasCanvas) return;
187
+
188
+ const ctx = atlasCanvas.getContext('2d');
189
+
190
+ // Use a reasonable size for the empty state
191
+ atlasCanvas.width = 260;
192
+ atlasCanvas.height = 260;
193
+
194
+ // Clear canvas with transparent background
195
+ ctx.clearRect(0, 0, atlasCanvas.width, atlasCanvas.height);
196
+
197
+ // Draw a visible border
198
+ ctx.strokeStyle = '#666';
199
+ ctx.lineWidth = 2;
200
+ ctx.strokeRect(2, 2, atlasCanvas.width - 4, atlasCanvas.height - 4);
201
+
202
+ // Add a subtle background to make text more readable
203
+ ctx.fillStyle = 'rgba(40, 40, 40, 0.3)';
204
+ ctx.fillRect(2, 2, atlasCanvas.width - 4, atlasCanvas.height - 4);
205
+
206
+ // Get current texture type from state
207
+ const currentTextureType = getState().currentTextureType || 'texture';
208
+
209
+ // Draw "No Atlas Data" text
210
+ ctx.fillStyle = '#aaa';
211
+ ctx.font = 'bold 16px monospace';
212
+ ctx.textAlign = 'center';
213
+ ctx.textBaseline = 'middle';
214
+ ctx.fillText(`No ${currentTextureType} Data`, atlasCanvas.width / 2, atlasCanvas.height / 2 - 15);
215
+
216
+ // Set proper CSS for the canvas to maintain aspect ratio and fit in container
217
+ atlasCanvas.style.width = '100%';
218
+ atlasCanvas.style.height = 'auto';
219
+ atlasCanvas.style.maxHeight = '100%';
220
+ atlasCanvas.style.objectFit = 'contain';
221
+ atlasCanvas.style.display = 'block';
222
+ }
223
+
224
+ /**
225
+ * Draw a UV coordinate grid on the canvas
226
+ * @param {CanvasRenderingContext2D} ctx - The canvas context
227
+ * @param {number} width - The canvas width
228
+ * @param {number} height - The canvas height
229
+ */
230
+ function drawUvGrid(ctx, width, height) {
231
+ // Draw grid lines
232
+ ctx.strokeStyle = 'rgba(255, 255, 255, 0.3)';
233
+ ctx.lineWidth = 1;
234
+
235
+ // Draw vertical grid lines
236
+ for (let i = 1; i < 10; i++) {
237
+ const x = width * i / 10;
238
+ ctx.beginPath();
239
+ ctx.moveTo(x, 0);
240
+ ctx.lineTo(x, height);
241
+ ctx.stroke();
242
+ }
243
+
244
+ // Draw horizontal grid lines
245
+ for (let i = 1; i < 10; i++) {
246
+ const y = height * i / 10;
247
+ ctx.beginPath();
248
+ ctx.moveTo(0, y);
249
+ ctx.lineTo(width, y);
250
+ ctx.stroke();
251
+ }
252
+
253
+ // Draw coordinate labels
254
+ ctx.fillStyle = 'white';
255
+ ctx.font = '10px monospace';
256
+
257
+ // 0,0 at bottom left
258
+ ctx.fillText('0,0', 2, height - 2);
259
+
260
+ // 1,0 at bottom right
261
+ ctx.fillText('1,0', width - 20, height - 2);
262
+
263
+ // 0,1 at top left
264
+ ctx.fillText('0,1', 2, 10);
265
+
266
+ // 1,1 at top right
267
+ ctx.fillText('1,1', width - 20, 10);
268
+ }
269
+
270
+ /**
271
+ * Draw a highlight region on the canvas
272
+ * @param {CanvasRenderingContext2D} ctx - The canvas context
273
+ * @param {Object} region - The region to highlight {min: [x, y], max: [x, y]}
274
+ * @param {number} width - The canvas width
275
+ * @param {number} height - The canvas height
276
+ */
277
+ function drawHighlightRegion(ctx, region, width, height) {
278
+ // Draw highlight box
279
+ ctx.strokeStyle = 'red';
280
+ ctx.lineWidth = 2;
281
+ ctx.beginPath();
282
+
283
+ // Calculate rect coordinates (remember Y needs to be flipped)
284
+ const x = width * region.min[0];
285
+ const y = height * (1 - region.max[1]); // Flip Y because canvas coordinates are top-down
286
+ const w = width * (region.max[0] - region.min[0]);
287
+ const h = height * (region.max[1] - region.min[1]);
288
+
289
+ ctx.rect(x, y, w, h);
290
+ ctx.stroke();
291
+
292
+ // Add semi-transparent fill
293
+ ctx.fillStyle = 'rgba(255, 0, 0, 0.1)';
294
+ ctx.fill();
295
+ }
296
+
297
+ /**
298
+ * Update the current UV region in the state
299
+ * @param {Array} min - [x, y] minimum UV coordinates
300
+ * @param {Array} max - [x, y] maximum UV coordinates
301
+ */
302
+ export function updateUvRegion(min, max) {
303
+ const region = { min, max };
304
+ updateState('currentUvRegion', region);
305
+ updateAtlasVisualization();
306
+ }
307
+
308
+ export default {
309
+ initAtlasPanel,
310
+ updateAtlasVisualization,
311
+ updateUvRegion
312
+ };
@@ -0,0 +1,129 @@
1
+ /* Mesh Panel Styles */
2
+
3
+ /* Mesh Visibility Panel Styles */
4
+ #mesh-visibility-container {
5
+ margin-bottom: 12px;
6
+ width: 100%;
7
+ }
8
+
9
+ .subsection-header {
10
+ font-size: 0.95em;
11
+ color: #aaa;
12
+ margin: 0 0 8px 0;
13
+ font-weight: normal;
14
+ }
15
+
16
+ .mesh-groups-container {
17
+ display: flex;
18
+ flex-direction: column;
19
+ gap: 6px;
20
+ }
21
+
22
+ .mesh-group {
23
+ margin-bottom: 8px;
24
+ }
25
+
26
+ .mesh-group-header {
27
+ padding: 2px 0;
28
+ font-size: 0.9em;
29
+ color: #ddd;
30
+ }
31
+
32
+ .mesh-group-name {
33
+ margin-left: 6px;
34
+ }
35
+
36
+ .mesh-group-count {
37
+ font-size: 0.85em;
38
+ color: #777;
39
+ }
40
+
41
+ .mesh-group-collapse {
42
+ padding: 0 4px;
43
+ color: #777;
44
+ }
45
+
46
+ .mesh-items {
47
+ margin-left: 20px;
48
+ margin-top: 4px;
49
+ }
50
+
51
+ .mesh-item {
52
+ display: flex;
53
+ align-items: center;
54
+ padding: 2px 0;
55
+ font-size: 0.85em;
56
+ }
57
+
58
+ .mesh-item:hover {
59
+ background-color: rgba(30, 30, 30, 0.8);
60
+ }
61
+
62
+ .mesh-name {
63
+ margin-left: 6px;
64
+ margin-right: 10px;
65
+ white-space: nowrap;
66
+ overflow: hidden;
67
+ text-overflow: ellipsis;
68
+ max-width: 170px;
69
+ flex-grow: 1;
70
+ color: var(--text-color);
71
+ font-size: 14px;
72
+ }
73
+
74
+ /* HTML Editor Icon */
75
+ .mesh-html-editor-icon {
76
+ color: #28a745;
77
+ cursor: pointer;
78
+ margin-left: 8px;
79
+ font-size: 1.1em;
80
+ display: flex;
81
+ align-items: center;
82
+ }
83
+
84
+ .mesh-html-editor-icon svg {
85
+ width: 14px;
86
+ height: 14px;
87
+ fill: currentColor;
88
+ transition: transform 0.2s ease;
89
+ }
90
+
91
+ .mesh-html-editor-icon:hover svg {
92
+ transform: rotate(20deg);
93
+ }
94
+
95
+ /* Mesh Info Icon */
96
+ .mesh-info-icon {
97
+ color: #6c757d;
98
+ cursor: pointer;
99
+ margin-left: 8px;
100
+ font-size: 1.1em;
101
+ display: flex;
102
+ align-items: center;
103
+ }
104
+
105
+ .mesh-info-icon svg {
106
+ width: 14px;
107
+ height: 14px;
108
+ fill: currentColor;
109
+ }
110
+
111
+ /* Mesh Item Icons Container */
112
+ .mesh-item-icons {
113
+ display: flex;
114
+ align-items: center;
115
+ gap: 4px;
116
+ }
117
+
118
+ .mesh-toggle {
119
+ margin-right: 8px;
120
+ cursor: pointer;
121
+ }
122
+
123
+ /* No Sample Message */
124
+ .no-sample-message {
125
+ text-align: center;
126
+ color: #777;
127
+ font-size: 0.9em;
128
+ font-style: italic;
129
+ }