shubeydoo commited on
Commit
af80dcc
·
1 Parent(s): 330a6da

Liquid AI LFM2.5-VL-1.6B-WebGPU Demo

Browse files
Files changed (17) hide show
  1. .gitattributes +2 -34
  2. .gitignore +3 -0
  3. Dockerfile +37 -0
  4. README.md +24 -5
  5. assets/liquid-ai.svg +1 -0
  6. config.js +3 -0
  7. index.html +782 -0
  8. infer.js +3 -0
  9. main.js +3 -0
  10. package-lock.json +1994 -0
  11. package.json +18 -0
  12. styles.css +1103 -0
  13. ui.js +3 -0
  14. vite.config.js +3 -0
  15. vl-model.js +3 -0
  16. vl-processor.js +3 -0
  17. webgpu-inference.js +3 -0
.gitattributes CHANGED
@@ -1,35 +1,3 @@
1
- *.7z filter=lfs diff=lfs merge=lfs -text
2
- *.arrow filter=lfs diff=lfs merge=lfs -text
3
- *.bin filter=lfs diff=lfs merge=lfs -text
4
- *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ckpt filter=lfs diff=lfs merge=lfs -text
6
- *.ftz filter=lfs diff=lfs merge=lfs -text
7
- *.gz filter=lfs diff=lfs merge=lfs -text
8
- *.h5 filter=lfs diff=lfs merge=lfs -text
9
- *.joblib filter=lfs diff=lfs merge=lfs -text
10
- *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
- *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
- *.model filter=lfs diff=lfs merge=lfs -text
13
- *.msgpack filter=lfs diff=lfs merge=lfs -text
14
- *.npy filter=lfs diff=lfs merge=lfs -text
15
- *.npz filter=lfs diff=lfs merge=lfs -text
16
- *.onnx filter=lfs diff=lfs merge=lfs -text
17
- *.ot filter=lfs diff=lfs merge=lfs -text
18
- *.parquet filter=lfs diff=lfs merge=lfs -text
19
- *.pb filter=lfs diff=lfs merge=lfs -text
20
- *.pickle filter=lfs diff=lfs merge=lfs -text
21
- *.pkl filter=lfs diff=lfs merge=lfs -text
22
- *.pt filter=lfs diff=lfs merge=lfs -text
23
- *.pth filter=lfs diff=lfs merge=lfs -text
24
- *.rar filter=lfs diff=lfs merge=lfs -text
25
- *.safetensors filter=lfs diff=lfs merge=lfs -text
26
- saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
- *.tar.* filter=lfs diff=lfs merge=lfs -text
28
- *.tar filter=lfs diff=lfs merge=lfs -text
29
- *.tflite filter=lfs diff=lfs merge=lfs -text
30
- *.tgz filter=lfs diff=lfs merge=lfs -text
31
  *.wasm filter=lfs diff=lfs merge=lfs -text
32
- *.xz filter=lfs diff=lfs merge=lfs -text
33
- *.zip filter=lfs diff=lfs merge=lfs -text
34
- *.zst filter=lfs diff=lfs merge=lfs -text
35
- *tfevents* filter=lfs diff=lfs merge=lfs -text
 
1
+ *.js filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  *.wasm filter=lfs diff=lfs merge=lfs -text
3
+ *.jpg filter=lfs diff=lfs merge=lfs -text
 
 
 
.gitignore ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ dist/
2
+ node_modules/
3
+ *.DS_Store
Dockerfile ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Build stage
2
+ FROM node:20-alpine AS builder
3
+
4
+ WORKDIR /app
5
+ COPY package*.json ./
6
+ RUN npm install
7
+ COPY . .
8
+ RUN npm run build
9
+
10
+ # Production stage
11
+ FROM nginx:alpine
12
+
13
+ # Copy files
14
+ COPY --from=builder /app/dist /usr/share/nginx/html/
15
+
16
+ # Custom nginx config with COEP/COOP/CORP headers
17
+ RUN echo 'server { \
18
+ listen 7860; \
19
+ location / { \
20
+ root /usr/share/nginx/html; \
21
+ index index.html; \
22
+ try_files $uri $uri/ /index.html; \
23
+ add_header Cross-Origin-Opener-Policy same-origin; \
24
+ add_header Cross-Origin-Embedder-Policy require-corp; \
25
+ add_header Cross-Origin-Resource-Policy cross-origin; \
26
+ add_header Cache-Control "no-cache, no-store, must-revalidate"; \
27
+ } \
28
+ location ~* \.(js|css|wasm)$ { \
29
+ root /usr/share/nginx/html; \
30
+ add_header Cross-Origin-Opener-Policy same-origin; \
31
+ add_header Cross-Origin-Embedder-Policy require-corp; \
32
+ add_header Cross-Origin-Resource-Policy cross-origin; \
33
+ add_header Cache-Control "no-cache, must-revalidate"; \
34
+ } \
35
+ }' > /etc/nginx/conf.d/default.conf
36
+
37
+ EXPOSE 7860
README.md CHANGED
@@ -1,10 +1,29 @@
1
  ---
2
- title: LFM2.5 VL 1.6B WebGPU
3
- emoji: 👁
4
- colorFrom: blue
5
- colorTo: gray
6
  sdk: docker
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: LFM2.5-VL-1.6B WebGPU
3
+ emoji: 🧠
4
+ colorFrom: purple
5
+ colorTo: blue
6
  sdk: docker
7
  pinned: false
8
+ models:
9
+ - LiquidAI/LFM2.5-VL-1.6B
10
  ---
11
 
12
+ # LFM2.5-VL-1.6B WebGPU Demo
13
+
14
+ In-browser vision-language inference with LFM2.5-VL-1.6B, powered by ONNX Runtime and WebGPU.
15
+
16
+ Everything runs entirely in your browser with WebGPU acceleration - no data is sent to a server.
17
+
18
+ ## Features
19
+
20
+ - **Live Webcam Captioning**: Stream from your webcam with real-time AI-generated captions
21
+ - **Multiple Quantization Options**: Choose between Q4/Q4 (~1.5 GB), Q4/FP16 (~2.3 GB), or FP16/FP16 (~3.2 GB)
22
+ - **Browser Caching**: Models are cached locally after first download for faster subsequent loads
23
+ - **Adjustable Resolution**: Configure capture resolution (256-512px) for performance tuning
24
+
25
+ ## Requirements
26
+
27
+ - WebGPU-enabled browser (Chrome 113+, Edge 113+)
28
+ - ~2-4 GB memory depending on quantization choice
29
+ - Webcam access for live captioning
assets/liquid-ai.svg ADDED
config.js ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:bd2306a48827e15ff7bc863ecdace25937f2074524ef97f3a7f156b1acde7f40
3
+ size 1825
index.html ADDED
@@ -0,0 +1,782 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>LFM2.5 VL 1B Demo</title>
7
+ <link rel="preconnect" href="https://fonts.googleapis.com">
8
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
+ <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
10
+ <link rel="stylesheet" href="styles.css">
11
+ </head>
12
+ <body>
13
+ <!-- Loading Screen -->
14
+ <div id="loading-screen" class="loading-screen">
15
+ <!-- Animated Background Canvas -->
16
+ <canvas id="loading-canvas" class="loading-canvas"></canvas>
17
+
18
+ <!-- Vignette Overlay -->
19
+ <div class="loading-vignette"></div>
20
+
21
+ <!-- Main Content -->
22
+ <div class="loading-content">
23
+ <div class="loading-header" style="display: flex; justify-content: center; align-items: center;">
24
+ <img
25
+ src="assets/liquid-ai.svg"
26
+ alt="Liquid AI"
27
+ class="loading-logo"
28
+ style="
29
+ width: min(16vw, 128px);
30
+ height: min(16vw, 128px);
31
+ max-width: 40vw;
32
+ max-height: 40vw;
33
+ min-width: 64px;
34
+ min-height: 64px;
35
+ object-fit: contain;
36
+ transition: width 0.2s, height 0.2s;
37
+ ">
38
+ </div>
39
+
40
+ <div class="loading-title-section">
41
+ <h1 class="loading-title">LFM2.5-VL-1.6B WebGPU</h1>
42
+ <p class="loading-subtitle">Vision-Language Model in Your Browser</p>
43
+ </div>
44
+
45
+ <div class="loading-description">
46
+ <p>This demo showcases in-browser vision-language inference with LFM2.5-VL-1.6B, powered by ONNX Runtime and WebGPU.</p>
47
+ <p>Everything runs entirely in your browser with WebGPU acceleration, meaning no data is sent to a server.</p>
48
+ </div>
49
+
50
+ <div class="loading-action-section">
51
+ <button id="loading-explore-btn" class="loading-explore-button">
52
+ <span id="loading-btn-text">Explore</span>
53
+ <span id="loading-spinner" class="loading-spinner hidden"></span>
54
+ <span id="loading-progress-text" class="loading-progress-text hidden"></span>
55
+ </button>
56
+ </div>
57
+
58
+ <div id="loading-error" class="loading-error hidden">
59
+ <p id="loading-error-text"></p>
60
+ <button id="loading-retry-btn" class="loading-retry-button">Retry</button>
61
+ </div>
62
+ </div>
63
+ </div>
64
+
65
+ <div class="app-layout">
66
+ <!-- Top Navigation -->
67
+ <div class="top-nav">
68
+ <div class="nav-left">
69
+ <img src="assets/liquid-ai.svg" alt="Liquid AI" class="nav-logo-img">
70
+ <a href="https://www.liquid.ai" target="_blank" rel="noopener noreferrer" class="nav-logo-link">Liquid</a>
71
+ </div>
72
+ <div class="nav-center">
73
+ <span class="nav-title">LFM2.5-VL-1.6B</span>
74
+ <span class="nav-subtitle">Stream from your webcam with real-time captions,powered by your own hardware with WebGPU!</span>
75
+ </div>
76
+ </div>
77
+
78
+ <!-- Main Content Area -->
79
+ <div class="container">
80
+ <!-- Live Caption Mode -->
81
+ <div id="live-caption-mode" class="mode-container active">
82
+ <div class="live-caption-content">
83
+ <div class="live-caption-video-section">
84
+ <div class="live-caption-video-container">
85
+ <video id="live-caption-video" autoplay></video>
86
+ <!-- Capture Overlay (on video) -->
87
+ <div class="capture-overlay">
88
+ <button id="start-live-caption-btn" class="control-btn primary">Start</button>
89
+ <div class="overlay-field">
90
+ <label class="overlay-label">Input:</label>
91
+ <select id="live-caption-resolution-select" class="control-select">
92
+ <option value="256">256px</option>
93
+ <option value="384" selected>384px</option>
94
+ <option value="448">448px</option>
95
+ <option value="512">512px</option>
96
+ </select>
97
+ </div>
98
+ <div class="capture-status">
99
+ <span class="status-indicator" id="live-status-indicator"></span>
100
+ <span class="status-text" id="live-status-text">Idle</span>
101
+ </div>
102
+ </div>
103
+ </div>
104
+ <div class="controls-bar">
105
+ <!-- Status Row -->
106
+ <div class="controls-row status-row">
107
+ <span class="model-status" id="model-status"></span>
108
+ <!-- Progress Bar (shown during loading) -->
109
+ <div class="progress-bar-row" id="loading-progress" style="display: none;">
110
+ <div class="progress-fill" id="progress-fill" style="width: 0%"></div>
111
+ </div>
112
+ </div>
113
+ <!-- Controls Row -->
114
+ <div class="controls-row">
115
+ <div class="control-group model-group">
116
+ <label class="control-label">Select quantization:</label>
117
+ <select id="model-select" class="control-select model-select">
118
+ <!-- Options populated from config.js -->
119
+ </select>
120
+ <button class="control-btn" id="reload-model-btn" title="Load Model">Load</button>
121
+ </div>
122
+ <div class="control-group cache-group">
123
+ <span class="cache-info" id="cache-info">0 MB</span>
124
+ <button class="control-btn small" id="clear-cache-btn" disabled title="Clear Cache">Clear</button>
125
+ </div>
126
+ </div>
127
+ </div>
128
+ </div>
129
+ <div class="live-caption-text-section">
130
+ <h3 class="caption-section-title">Captions</h3>
131
+ <div class="latest-caption" id="latest-caption">Start capturing to see live captions...</div>
132
+ <div class="caption-history" id="caption-history"></div>
133
+ </div>
134
+ </div>
135
+ </div>
136
+
137
+ </div>
138
+ </div>
139
+
140
+ <script>
141
+ // ============================================
142
+ // LOADING SCREEN
143
+ // ============================================
144
+
145
+ let loadingScreenVisible = true;
146
+ let loadingCanvas = null;
147
+ let loadingCtx = null;
148
+ let loadingDots = [];
149
+ let loadingAnimationId = null;
150
+
151
+ function initLoadingScreen() {
152
+ // Initialize canvas animation
153
+ loadingCanvas = document.getElementById('loading-canvas');
154
+ if (!loadingCanvas) return;
155
+
156
+ loadingCtx = loadingCanvas.getContext('2d');
157
+ setupLoadingCanvas();
158
+ animateLoadingCanvas();
159
+
160
+ // Set up event listeners
161
+ setupLoadingScreenListeners();
162
+
163
+ // Handle window resize
164
+ window.addEventListener('resize', setupLoadingCanvas);
165
+ }
166
+
167
+ function setupLoadingCanvas() {
168
+ if (!loadingCanvas || !loadingCtx) return;
169
+
170
+ loadingCanvas.width = window.innerWidth;
171
+ loadingCanvas.height = window.innerHeight;
172
+
173
+ // Create dots
174
+ loadingDots = [];
175
+ const numDots = Math.floor((loadingCanvas.width * loadingCanvas.height) / 15000);
176
+ for (let i = 0; i < numDots; i++) {
177
+ loadingDots.push({
178
+ x: Math.random() * loadingCanvas.width,
179
+ y: Math.random() * loadingCanvas.height,
180
+ radius: Math.random() * 1.5 + 0.5,
181
+ speed: Math.random() * 0.5 + 0.1,
182
+ opacity: Math.random() * 0.5 + 0.2,
183
+ blur: Math.random() > 0.7 ? Math.random() * 2 + 1 : 0
184
+ });
185
+ }
186
+ }
187
+
188
+ function animateLoadingCanvas() {
189
+ if (!loadingCtx || !loadingCanvas) return;
190
+
191
+ loadingCtx.clearRect(0, 0, loadingCanvas.width, loadingCanvas.height);
192
+
193
+ loadingDots.forEach(dot => {
194
+ // Update position
195
+ dot.y += dot.speed;
196
+ if (dot.y > loadingCanvas.height) {
197
+ dot.y = 0 - dot.radius;
198
+ dot.x = Math.random() * loadingCanvas.width;
199
+ }
200
+
201
+ // Draw dot
202
+ loadingCtx.beginPath();
203
+ loadingCtx.arc(dot.x, dot.y, dot.radius, 0, Math.PI * 2);
204
+ loadingCtx.fillStyle = `rgba(255, 255, 255, ${dot.opacity})`;
205
+ if (dot.blur > 0) {
206
+ loadingCtx.filter = `blur(${dot.blur}px)`;
207
+ }
208
+ loadingCtx.fill();
209
+ loadingCtx.filter = 'none';
210
+ });
211
+
212
+ loadingAnimationId = requestAnimationFrame(animateLoadingCanvas);
213
+ }
214
+
215
+ function setupLoadingScreenListeners() {
216
+ // Explore button
217
+ const exploreBtn = document.getElementById('loading-explore-btn');
218
+ if (exploreBtn) {
219
+ exploreBtn.addEventListener('click', handleLoadingScreenLoad);
220
+ }
221
+
222
+ // Retry button
223
+ const retryBtn = document.getElementById('loading-retry-btn');
224
+ if (retryBtn) {
225
+ retryBtn.addEventListener('click', handleLoadingScreenLoad);
226
+ }
227
+ }
228
+
229
+ async function handleLoadingScreenLoad() {
230
+ const exploreBtn = document.getElementById('loading-explore-btn');
231
+
232
+ if (!exploreBtn) return;
233
+
234
+ // Simply hide the loading screen - user can load model manually via the input field
235
+ hideLoadingScreen();
236
+ }
237
+
238
+ function hideLoadingScreen() {
239
+ const screen = document.getElementById('loading-screen');
240
+ if (screen) {
241
+ screen.classList.add('hidden');
242
+ loadingScreenVisible = false;
243
+
244
+ // Stop canvas animation
245
+ if (loadingAnimationId) {
246
+ cancelAnimationFrame(loadingAnimationId);
247
+ loadingAnimationId = null;
248
+ }
249
+
250
+ // Clear any URL hash from old bookmarks/links
251
+ if (window.location.hash) {
252
+ history.replaceState(null, '', window.location.pathname);
253
+ }
254
+ }
255
+ }
256
+
257
+ function showLoadingScreen() {
258
+ const screen = document.getElementById('loading-screen');
259
+ if (screen) {
260
+ screen.classList.remove('hidden');
261
+ loadingScreenVisible = true;
262
+
263
+ // Restart canvas animation if needed
264
+ if (!loadingAnimationId && loadingCanvas) {
265
+ animateLoadingCanvas();
266
+ }
267
+ }
268
+ }
269
+
270
+ function isMobileDevice() {
271
+ return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)
272
+ || (navigator.maxTouchPoints > 0 && window.innerWidth < 1024);
273
+ }
274
+
275
+ function showMobileWarning() {
276
+ if (!isMobileDevice()) return;
277
+
278
+ const warningDiv = document.createElement('div');
279
+ warningDiv.className = 'mobile-warning';
280
+ warningDiv.innerHTML = `
281
+ <div class="mobile-warning-title">
282
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
283
+ <path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"></path>
284
+ <line x1="12" y1="9" x2="12" y2="13"></line>
285
+ <line x1="12" y1="17" x2="12.01" y2="17"></line>
286
+ </svg>
287
+ Mobile Device Detected
288
+ </div>
289
+ <p>This demo requires a desktop browser. Mobile browsers have memory limits smaller than the model size.</p>
290
+ <p>Please visit this page on a desktop computer.</p>
291
+ `;
292
+
293
+ const actionSection = document.querySelector('.loading-action-section');
294
+ if (actionSection) {
295
+ actionSection.parentNode.insertBefore(warningDiv, actionSection);
296
+ }
297
+
298
+ const btnText = document.getElementById('loading-btn-text');
299
+ if (btnText) {
300
+ btnText.textContent = 'Try Anyway';
301
+ }
302
+ }
303
+
304
+ function isSafariDesktop() {
305
+ const ua = navigator.userAgent;
306
+ // Safari has "Safari" in UA but Chrome/Edge also include it
307
+ // True Safari doesn't have "Chrome" or "Chromium" in UA
308
+ const isSafari = /Safari/.test(ua) && !/Chrome|Chromium/.test(ua);
309
+ // Exclude iOS (iPhone, iPad, iPod)
310
+ const isIOS = /iPhone|iPad|iPod/.test(ua);
311
+ return isSafari && !isIOS;
312
+ }
313
+
314
+ function showSafariWarning() {
315
+ if (!isSafariDesktop()) return;
316
+
317
+ // Add Safari class to body for CSS targeting
318
+ document.body.classList.add('is-safari');
319
+
320
+ const warningDiv = document.createElement('div');
321
+ warningDiv.className = 'safari-warning';
322
+ warningDiv.innerHTML = `
323
+ <div class="safari-warning-title">
324
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
325
+ <circle cx="12" cy="12" r="10"></circle>
326
+ <line x1="12" y1="8" x2="12" y2="12"></line>
327
+ <line x1="12" y1="16" x2="12.01" y2="16"></line>
328
+ </svg>
329
+ Safari requires WebGPU to be explicitly enabled
330
+ </div>
331
+ <p>WebGPU must be manually enabled in Safari. Go to <strong>Safari → Settings → Feature Flags </strong> and enable <strong>WebGPU</strong>.</p>
332
+ <p><a href="https://webkit.org/blog/14879/webgpu-now-available-for-testing-in-safari-technology-preview/" target="_blank" rel="noopener noreferrer">Learn more about WebGPU in Safari</a></p>
333
+ `;
334
+
335
+ const actionSection = document.querySelector('.loading-action-section');
336
+ if (actionSection) {
337
+ actionSection.parentNode.insertBefore(warningDiv, actionSection);
338
+ }
339
+ }
340
+
341
+ // Initialize loading screen on page load
342
+ if (document.readyState === 'loading') {
343
+ document.addEventListener('DOMContentLoaded', () => {
344
+ initLoadingScreen();
345
+ showMobileWarning();
346
+ showSafariWarning();
347
+ });
348
+ } else {
349
+ initLoadingScreen();
350
+ showMobileWarning();
351
+ showSafariWarning();
352
+ }
353
+
354
+ // ============================================
355
+ // GENERATION CONFIG
356
+ // ============================================
357
+
358
+ const generationConfig = {
359
+ max_new_tokens: 128
360
+ };
361
+
362
+ function getModeConfig() {
363
+ return {
364
+ max_new_tokens: generationConfig.max_new_tokens
365
+ };
366
+ }
367
+
368
+ // Make getModeConfig available globally for main.js
369
+ window.getModeConfig = getModeConfig;
370
+
371
+ // ============================================
372
+ // LIVE CAPTION MODE
373
+ // ============================================
374
+
375
+ let liveCaptionStream = null;
376
+ let isCapturing = false;
377
+ let captureLoopRunning = false;
378
+
379
+
380
+ async function startLiveCaption() {
381
+ try {
382
+ const video = document.getElementById('live-caption-video');
383
+ const statusIndicator = document.getElementById('live-status-indicator');
384
+ const statusText = document.getElementById('live-status-text');
385
+ const startBtn = document.getElementById('start-live-caption-btn');
386
+
387
+ // Get webcam stream
388
+ liveCaptionStream = await navigator.mediaDevices.getUserMedia({
389
+ video: { width: 1024, height: 1024 }
390
+ });
391
+ video.srcObject = liveCaptionStream;
392
+
393
+ // Wait for video to actually start playing before capturing
394
+ await new Promise((resolve) => {
395
+ video.onloadeddata = () => {
396
+ video.play();
397
+ resolve();
398
+ };
399
+ // If already loaded, resolve immediately
400
+ if (video.readyState >= 2) {
401
+ video.play();
402
+ resolve();
403
+ }
404
+ });
405
+
406
+ // Wait for camera to warm up (avoid black first frame)
407
+ await new Promise(resolve => setTimeout(resolve, 500));
408
+
409
+ // Update UI
410
+ isCapturing = true;
411
+ statusIndicator.classList.add('active');
412
+ statusText.textContent = 'Capturing';
413
+ startBtn.textContent = 'Stop';
414
+ startBtn.classList.add('stop');
415
+
416
+ // Hide the initial placeholder text
417
+ const latestCaption = document.getElementById('latest-caption');
418
+ if (latestCaption) {
419
+ latestCaption.style.display = 'none';
420
+ }
421
+
422
+ // Start capture loop (waits for each generation to complete)
423
+ captureLoop();
424
+
425
+ } catch (error) {
426
+ console.error('Error starting live caption:', error);
427
+ alert('Could not access webcam. Please check permissions.');
428
+ }
429
+ }
430
+
431
+ function stopLiveCaption() {
432
+ const video = document.getElementById('live-caption-video');
433
+ const statusIndicator = document.getElementById('live-status-indicator');
434
+ const statusText = document.getElementById('live-status-text');
435
+ const startBtn = document.getElementById('start-live-caption-btn');
436
+
437
+ // Setting isCapturing to false stops the capture loop
438
+ isCapturing = false;
439
+
440
+ if (liveCaptionStream) {
441
+ liveCaptionStream.getTracks().forEach(track => track.stop());
442
+ liveCaptionStream = null;
443
+ }
444
+
445
+ if (video) {
446
+ video.srcObject = null;
447
+ }
448
+
449
+ if (statusIndicator) statusIndicator.classList.remove('active');
450
+ if (statusText) statusText.textContent = 'Idle';
451
+ if (startBtn) {
452
+ startBtn.textContent = 'Start';
453
+ startBtn.classList.remove('stop');
454
+ }
455
+ }
456
+
457
+ // Expose globally so main.js can stop capture before loading new model
458
+ window.stopLiveCaption = stopLiveCaption;
459
+
460
+ /**
461
+ * Async capture loop - waits for each generation to complete before starting next
462
+ */
463
+ async function captureLoop() {
464
+ if (!isCapturing || captureLoopRunning) return;
465
+ captureLoopRunning = true;
466
+
467
+ while (isCapturing) {
468
+ await captureLiveCaptionFrame();
469
+ }
470
+
471
+ captureLoopRunning = false;
472
+ }
473
+
474
+ async function captureLiveCaptionFrame() {
475
+ if (!isCapturing) return;
476
+
477
+ const video = document.getElementById('live-caption-video');
478
+ const statusText = document.getElementById('live-status-text');
479
+
480
+ // Get resolution from dropdown
481
+ const resolutionSelect = document.getElementById('live-caption-resolution-select');
482
+ const resolution = parseInt(resolutionSelect?.value || '384', 10);
483
+
484
+ // Create canvas and capture frame
485
+ const canvas = document.createElement('canvas');
486
+ canvas.width = resolution;
487
+ canvas.height = resolution;
488
+ const ctx = canvas.getContext('2d');
489
+ ctx.drawImage(video, 0, 0, resolution, resolution);
490
+
491
+ // Use DataURL - browser's native JPEG encoding is faster than JS ImageData handling
492
+ const dataURL = canvas.toDataURL('image/jpeg', 0.8);
493
+
494
+ try {
495
+ const config = getModeConfig();
496
+
497
+ // Wait for webgpuInit to be available
498
+ if (!window.webgpuInit) {
499
+ await new Promise((resolve, reject) => {
500
+ if (window.webgpuInit) {
501
+ resolve();
502
+ } else {
503
+ const timeout = setTimeout(() => {
504
+ reject(new Error('WebGPU system initialization timeout'));
505
+ }, 10000);
506
+ window.addEventListener('webgpu-ready', () => {
507
+ clearTimeout(timeout);
508
+ resolve();
509
+ }, { once: true });
510
+ }
511
+ });
512
+ }
513
+
514
+ if (!window.webgpuInit.isModelLoaded()) {
515
+ if (statusText) statusText.textContent = 'Model not loaded';
516
+ return;
517
+ }
518
+
519
+ // Build message
520
+ const messages = [{
521
+ role: 'user',
522
+ content: [
523
+ { type: 'image', value: dataURL },
524
+ { type: 'text', value: 'Describe what you see in one sentence.' }
525
+ ]
526
+ }];
527
+
528
+ const response = await window.webgpuInit.generate(messages, {
529
+ maxNewTokens: config.max_new_tokens
530
+ });
531
+
532
+ updateLiveCaption(response);
533
+
534
+ } catch (error) {
535
+ console.error('Error generating caption:', error);
536
+ if (statusText) statusText.textContent = 'Error';
537
+ }
538
+ }
539
+
540
+ function updateLiveCaption(caption) {
541
+ // Skip empty or whitespace-only captions (happens when model is busy)
542
+ if (!caption || !caption.trim()) {
543
+ return;
544
+ }
545
+
546
+ const captionHistory = document.getElementById('caption-history');
547
+
548
+ // Remove 'latest' class from all existing items
549
+ const existingItems = captionHistory.querySelectorAll('.caption-history-item');
550
+ existingItems.forEach(item => item.classList.remove('latest'));
551
+
552
+ // Add to history at the top (most recent first)
553
+ const timestamp = new Date().toLocaleTimeString();
554
+ const historyItem = document.createElement('div');
555
+ historyItem.className = 'caption-history-item latest';
556
+ historyItem.innerHTML = `
557
+ <span class="caption-timestamp">${timestamp}</span>
558
+ <span class="caption-text">${caption.trim()}</span>
559
+ `;
560
+ captionHistory.prepend(historyItem);
561
+
562
+ // Keep only the last 7 items, remove oldest from bottom
563
+ while (captionHistory.children.length > 7) {
564
+ captionHistory.removeChild(captionHistory.lastChild);
565
+ }
566
+
567
+ // Apply fading effect: newest (first) is fully visible, older ones fade
568
+ const items = captionHistory.children;
569
+ for (let i = 0; i < items.length; i++) {
570
+ // First item is 1.0, then fade to 0.1 for older items
571
+ const opacity = Math.max(0.1, 1.0 - (i * 0.2));
572
+ items[i].style.opacity = opacity;
573
+ }
574
+ }
575
+
576
+ // Model state storage - don't restore from localStorage since model needs to be reloaded each session
577
+ let CURRENT_MODEL = '';
578
+
579
+ function formatModelName(modelId) {
580
+ // Convert "LFM2.5-VL-1.6B-merge-linear-Q4-FP16" to "LFM2.5-VL-1.6B Q4/FP16"
581
+ if (!modelId || modelId === 'Loading...') return modelId;
582
+ // Remove "merge-linear-" or similar internal identifiers
583
+ let clean = modelId.replace(/-merge-linear/g, '').replace(/-91\d+/g, '');
584
+ // Convert trailing "Q4-FP16" to "Q4/FP16"
585
+ clean = clean.replace(/-(Q4|FP16)-(Q4|FP16)$/, ' $1/$2');
586
+ return clean;
587
+ }
588
+
589
+ function updateModelStatus(modelId = null) {
590
+ const statusEl = document.getElementById('model-status');
591
+ if (statusEl) {
592
+ if (modelId) {
593
+ CURRENT_MODEL = modelId;
594
+ localStorage.setItem('CURRENT_MODEL', modelId);
595
+ statusEl.textContent = formatModelName(modelId);
596
+ statusEl.style.color = 'var(--text-primary)';
597
+ } else {
598
+ CURRENT_MODEL = '';
599
+ localStorage.removeItem('CURRENT_MODEL');
600
+ statusEl.textContent = 'No model loaded';
601
+ statusEl.style.color = 'var(--text-secondary)';
602
+ }
603
+ }
604
+ }
605
+
606
+ async function loadSelectedModel(modelId) {
607
+ const modelSelect = document.getElementById('model-select');
608
+ const reloadBtn = document.getElementById('reload-model-btn');
609
+
610
+ // Show loading state
611
+ if (modelSelect) {
612
+ modelSelect.disabled = true;
613
+ }
614
+
615
+ if (reloadBtn) {
616
+ reloadBtn.disabled = true;
617
+ reloadBtn.style.opacity = '0.6';
618
+ reloadBtn.style.cursor = 'not-allowed';
619
+ }
620
+
621
+ // Update status to loading
622
+ updateModelStatus('Loading...');
623
+
624
+ try {
625
+ // Wait for webgpuInit to be available
626
+ if (!window.webgpuInit) {
627
+ await new Promise((resolve, reject) => {
628
+ if (window.webgpuInit) {
629
+ resolve();
630
+ } else {
631
+ const timeout = setTimeout(() => {
632
+ reject(new Error('WebGPU system initialization timeout. Please refresh the page.'));
633
+ }, 10000);
634
+ window.addEventListener('webgpu-ready', () => {
635
+ clearTimeout(timeout);
636
+ resolve();
637
+ }, { once: true });
638
+ }
639
+ });
640
+ }
641
+
642
+ await window.webgpuInit.handleLoadModel();
643
+
644
+ // Store current model (status already updated by handleLoadModel)
645
+ CURRENT_MODEL = modelId;
646
+ localStorage.setItem('CURRENT_MODEL', CURRENT_MODEL);
647
+
648
+ // Enable buttons when model loads
649
+ if (window.webgpuInit && window.webgpuInit.updateButtonStates) {
650
+ window.webgpuInit.updateButtonStates(true);
651
+ }
652
+ } catch (error) {
653
+ updateModelStatus(null);
654
+ alert(`Error loading model: ${error.message}`);
655
+ console.error('Error loading model:', error);
656
+ } finally {
657
+ // Restore UI state
658
+ if (modelSelect) {
659
+ modelSelect.disabled = false;
660
+ }
661
+
662
+ if (reloadBtn) {
663
+ reloadBtn.disabled = false;
664
+ reloadBtn.style.opacity = '1';
665
+ reloadBtn.style.cursor = 'pointer';
666
+ }
667
+ }
668
+ }
669
+
670
+ // Inference via WebGPU
671
+ async function generate(messages, options = {}) {
672
+ const config = getModeConfig();
673
+
674
+ // Wait for webgpuInit to be available
675
+ if (!window.webgpuInit) {
676
+ // Wait for webgpu-ready event
677
+ await new Promise((resolve, reject) => {
678
+ if (window.webgpuInit) {
679
+ resolve();
680
+ } else {
681
+ const timeout = setTimeout(() => {
682
+ reject(new Error('WebGPU system initialization timeout. Please refresh the page.'));
683
+ }, 10000);
684
+ window.addEventListener('webgpu-ready', () => {
685
+ clearTimeout(timeout);
686
+ resolve();
687
+ }, { once: true });
688
+ }
689
+ });
690
+ }
691
+
692
+ if (!window.webgpuInit.isModelLoaded()) {
693
+ throw new Error('Model not loaded. Please load a model first.');
694
+ }
695
+
696
+ try {
697
+ // Generate using WebGPU with streaming support
698
+ const response = await window.webgpuInit.generate(messages, {
699
+ maxNewTokens: config.max_new_tokens,
700
+ onToken: options.onToken || ((token) => {
701
+ // Default: do nothing if no callback provided
702
+ return false;
703
+ })
704
+ });
705
+
706
+ return response;
707
+ } catch (error) {
708
+ console.error('Error calling WebGPU inference:', error);
709
+ throw error;
710
+ }
711
+ }
712
+
713
+ // Initialize
714
+ function init() {
715
+ setupModeEventListeners();
716
+
717
+ // Clear any URL hash from old bookmarks/links
718
+ if (window.location.hash) {
719
+ history.replaceState(null, '', window.location.pathname);
720
+ }
721
+ }
722
+
723
+ function setupModeEventListeners() {
724
+ const reloadModelBtn = document.getElementById('reload-model-btn');
725
+ if (reloadModelBtn) {
726
+ reloadModelBtn.addEventListener('click', () => {
727
+ const modelSelect = document.getElementById('model-select');
728
+ const selectedModelId = modelSelect?.value;
729
+ if (!selectedModelId) {
730
+ alert('Please select a model first.');
731
+ return;
732
+ }
733
+ loadSelectedModel(selectedModelId);
734
+ });
735
+ }
736
+
737
+ // Live Caption controls
738
+ const liveCaptionBtn = document.getElementById('start-live-caption-btn');
739
+ if (liveCaptionBtn) {
740
+ liveCaptionBtn.addEventListener('click', () => {
741
+ if (isCapturing) {
742
+ stopLiveCaption();
743
+ } else {
744
+ startLiveCaption();
745
+ }
746
+ });
747
+ }
748
+
749
+ // Model selector dropdown
750
+ const modelSelect = document.getElementById('model-select');
751
+ if (modelSelect) {
752
+ // Restore last selected model if saved
753
+ const savedModelId = localStorage.getItem('SELECTED_MODEL_ID');
754
+ if (savedModelId && modelSelect.querySelector(`option[value="${savedModelId}"]`)) {
755
+ modelSelect.value = savedModelId;
756
+ }
757
+
758
+ // Initialize model status display
759
+ if (CURRENT_MODEL) {
760
+ updateModelStatus(CURRENT_MODEL);
761
+ } else {
762
+ updateModelStatus(null);
763
+ }
764
+
765
+ // Save selection on change
766
+ modelSelect.addEventListener('change', (e) => {
767
+ localStorage.setItem('SELECTED_MODEL_ID', e.target.value);
768
+ });
769
+ }
770
+ }
771
+
772
+ if (document.readyState === 'loading') {
773
+ document.addEventListener('DOMContentLoaded', init);
774
+ } else {
775
+ init();
776
+ }
777
+ </script>
778
+
779
+ <!-- Load main.js module -->
780
+ <script type="module" src="./main.js"></script>
781
+ </body>
782
+ </html>
infer.js ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b32bd00a2507849fb21631c3f2ac920343aba358169d249133d78ea0b600b959
3
+ size 1884
main.js ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:61b718313a1fb429ed95c09992f66732edfde1149ab0f4d9c53c809a2e10d565
3
+ size 5998
package-lock.json ADDED
@@ -0,0 +1,1994 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "lfm25-vl-webgpu",
3
+ "version": "1.0.0",
4
+ "lockfileVersion": 3,
5
+ "requires": true,
6
+ "packages": {
7
+ "": {
8
+ "name": "lfm25-vl-webgpu",
9
+ "version": "1.0.0",
10
+ "dependencies": {
11
+ "@huggingface/transformers": "^3.7.1",
12
+ "onnxruntime-web": "^1.23.2"
13
+ },
14
+ "devDependencies": {
15
+ "vite": "^5.4.0"
16
+ }
17
+ },
18
+ "node_modules/@emnapi/runtime": {
19
+ "version": "1.8.1",
20
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.8.1.tgz",
21
+ "integrity": "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==",
22
+ "license": "MIT",
23
+ "optional": true,
24
+ "dependencies": {
25
+ "tslib": "^2.4.0"
26
+ }
27
+ },
28
+ "node_modules/@esbuild/aix-ppc64": {
29
+ "version": "0.21.5",
30
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
31
+ "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==",
32
+ "cpu": [
33
+ "ppc64"
34
+ ],
35
+ "dev": true,
36
+ "license": "MIT",
37
+ "optional": true,
38
+ "os": [
39
+ "aix"
40
+ ],
41
+ "engines": {
42
+ "node": ">=12"
43
+ }
44
+ },
45
+ "node_modules/@esbuild/android-arm": {
46
+ "version": "0.21.5",
47
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz",
48
+ "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==",
49
+ "cpu": [
50
+ "arm"
51
+ ],
52
+ "dev": true,
53
+ "license": "MIT",
54
+ "optional": true,
55
+ "os": [
56
+ "android"
57
+ ],
58
+ "engines": {
59
+ "node": ">=12"
60
+ }
61
+ },
62
+ "node_modules/@esbuild/android-arm64": {
63
+ "version": "0.21.5",
64
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz",
65
+ "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==",
66
+ "cpu": [
67
+ "arm64"
68
+ ],
69
+ "dev": true,
70
+ "license": "MIT",
71
+ "optional": true,
72
+ "os": [
73
+ "android"
74
+ ],
75
+ "engines": {
76
+ "node": ">=12"
77
+ }
78
+ },
79
+ "node_modules/@esbuild/android-x64": {
80
+ "version": "0.21.5",
81
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz",
82
+ "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==",
83
+ "cpu": [
84
+ "x64"
85
+ ],
86
+ "dev": true,
87
+ "license": "MIT",
88
+ "optional": true,
89
+ "os": [
90
+ "android"
91
+ ],
92
+ "engines": {
93
+ "node": ">=12"
94
+ }
95
+ },
96
+ "node_modules/@esbuild/darwin-arm64": {
97
+ "version": "0.21.5",
98
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz",
99
+ "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==",
100
+ "cpu": [
101
+ "arm64"
102
+ ],
103
+ "dev": true,
104
+ "license": "MIT",
105
+ "optional": true,
106
+ "os": [
107
+ "darwin"
108
+ ],
109
+ "engines": {
110
+ "node": ">=12"
111
+ }
112
+ },
113
+ "node_modules/@esbuild/darwin-x64": {
114
+ "version": "0.21.5",
115
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz",
116
+ "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==",
117
+ "cpu": [
118
+ "x64"
119
+ ],
120
+ "dev": true,
121
+ "license": "MIT",
122
+ "optional": true,
123
+ "os": [
124
+ "darwin"
125
+ ],
126
+ "engines": {
127
+ "node": ">=12"
128
+ }
129
+ },
130
+ "node_modules/@esbuild/freebsd-arm64": {
131
+ "version": "0.21.5",
132
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz",
133
+ "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==",
134
+ "cpu": [
135
+ "arm64"
136
+ ],
137
+ "dev": true,
138
+ "license": "MIT",
139
+ "optional": true,
140
+ "os": [
141
+ "freebsd"
142
+ ],
143
+ "engines": {
144
+ "node": ">=12"
145
+ }
146
+ },
147
+ "node_modules/@esbuild/freebsd-x64": {
148
+ "version": "0.21.5",
149
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz",
150
+ "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==",
151
+ "cpu": [
152
+ "x64"
153
+ ],
154
+ "dev": true,
155
+ "license": "MIT",
156
+ "optional": true,
157
+ "os": [
158
+ "freebsd"
159
+ ],
160
+ "engines": {
161
+ "node": ">=12"
162
+ }
163
+ },
164
+ "node_modules/@esbuild/linux-arm": {
165
+ "version": "0.21.5",
166
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz",
167
+ "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==",
168
+ "cpu": [
169
+ "arm"
170
+ ],
171
+ "dev": true,
172
+ "license": "MIT",
173
+ "optional": true,
174
+ "os": [
175
+ "linux"
176
+ ],
177
+ "engines": {
178
+ "node": ">=12"
179
+ }
180
+ },
181
+ "node_modules/@esbuild/linux-arm64": {
182
+ "version": "0.21.5",
183
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz",
184
+ "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==",
185
+ "cpu": [
186
+ "arm64"
187
+ ],
188
+ "dev": true,
189
+ "license": "MIT",
190
+ "optional": true,
191
+ "os": [
192
+ "linux"
193
+ ],
194
+ "engines": {
195
+ "node": ">=12"
196
+ }
197
+ },
198
+ "node_modules/@esbuild/linux-ia32": {
199
+ "version": "0.21.5",
200
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz",
201
+ "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==",
202
+ "cpu": [
203
+ "ia32"
204
+ ],
205
+ "dev": true,
206
+ "license": "MIT",
207
+ "optional": true,
208
+ "os": [
209
+ "linux"
210
+ ],
211
+ "engines": {
212
+ "node": ">=12"
213
+ }
214
+ },
215
+ "node_modules/@esbuild/linux-loong64": {
216
+ "version": "0.21.5",
217
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz",
218
+ "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==",
219
+ "cpu": [
220
+ "loong64"
221
+ ],
222
+ "dev": true,
223
+ "license": "MIT",
224
+ "optional": true,
225
+ "os": [
226
+ "linux"
227
+ ],
228
+ "engines": {
229
+ "node": ">=12"
230
+ }
231
+ },
232
+ "node_modules/@esbuild/linux-mips64el": {
233
+ "version": "0.21.5",
234
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz",
235
+ "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==",
236
+ "cpu": [
237
+ "mips64el"
238
+ ],
239
+ "dev": true,
240
+ "license": "MIT",
241
+ "optional": true,
242
+ "os": [
243
+ "linux"
244
+ ],
245
+ "engines": {
246
+ "node": ">=12"
247
+ }
248
+ },
249
+ "node_modules/@esbuild/linux-ppc64": {
250
+ "version": "0.21.5",
251
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz",
252
+ "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==",
253
+ "cpu": [
254
+ "ppc64"
255
+ ],
256
+ "dev": true,
257
+ "license": "MIT",
258
+ "optional": true,
259
+ "os": [
260
+ "linux"
261
+ ],
262
+ "engines": {
263
+ "node": ">=12"
264
+ }
265
+ },
266
+ "node_modules/@esbuild/linux-riscv64": {
267
+ "version": "0.21.5",
268
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz",
269
+ "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==",
270
+ "cpu": [
271
+ "riscv64"
272
+ ],
273
+ "dev": true,
274
+ "license": "MIT",
275
+ "optional": true,
276
+ "os": [
277
+ "linux"
278
+ ],
279
+ "engines": {
280
+ "node": ">=12"
281
+ }
282
+ },
283
+ "node_modules/@esbuild/linux-s390x": {
284
+ "version": "0.21.5",
285
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz",
286
+ "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==",
287
+ "cpu": [
288
+ "s390x"
289
+ ],
290
+ "dev": true,
291
+ "license": "MIT",
292
+ "optional": true,
293
+ "os": [
294
+ "linux"
295
+ ],
296
+ "engines": {
297
+ "node": ">=12"
298
+ }
299
+ },
300
+ "node_modules/@esbuild/linux-x64": {
301
+ "version": "0.21.5",
302
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz",
303
+ "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==",
304
+ "cpu": [
305
+ "x64"
306
+ ],
307
+ "dev": true,
308
+ "license": "MIT",
309
+ "optional": true,
310
+ "os": [
311
+ "linux"
312
+ ],
313
+ "engines": {
314
+ "node": ">=12"
315
+ }
316
+ },
317
+ "node_modules/@esbuild/netbsd-x64": {
318
+ "version": "0.21.5",
319
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
320
+ "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==",
321
+ "cpu": [
322
+ "x64"
323
+ ],
324
+ "dev": true,
325
+ "license": "MIT",
326
+ "optional": true,
327
+ "os": [
328
+ "netbsd"
329
+ ],
330
+ "engines": {
331
+ "node": ">=12"
332
+ }
333
+ },
334
+ "node_modules/@esbuild/openbsd-x64": {
335
+ "version": "0.21.5",
336
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
337
+ "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==",
338
+ "cpu": [
339
+ "x64"
340
+ ],
341
+ "dev": true,
342
+ "license": "MIT",
343
+ "optional": true,
344
+ "os": [
345
+ "openbsd"
346
+ ],
347
+ "engines": {
348
+ "node": ">=12"
349
+ }
350
+ },
351
+ "node_modules/@esbuild/sunos-x64": {
352
+ "version": "0.21.5",
353
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
354
+ "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
355
+ "cpu": [
356
+ "x64"
357
+ ],
358
+ "dev": true,
359
+ "license": "MIT",
360
+ "optional": true,
361
+ "os": [
362
+ "sunos"
363
+ ],
364
+ "engines": {
365
+ "node": ">=12"
366
+ }
367
+ },
368
+ "node_modules/@esbuild/win32-arm64": {
369
+ "version": "0.21.5",
370
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
371
+ "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
372
+ "cpu": [
373
+ "arm64"
374
+ ],
375
+ "dev": true,
376
+ "license": "MIT",
377
+ "optional": true,
378
+ "os": [
379
+ "win32"
380
+ ],
381
+ "engines": {
382
+ "node": ">=12"
383
+ }
384
+ },
385
+ "node_modules/@esbuild/win32-ia32": {
386
+ "version": "0.21.5",
387
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
388
+ "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
389
+ "cpu": [
390
+ "ia32"
391
+ ],
392
+ "dev": true,
393
+ "license": "MIT",
394
+ "optional": true,
395
+ "os": [
396
+ "win32"
397
+ ],
398
+ "engines": {
399
+ "node": ">=12"
400
+ }
401
+ },
402
+ "node_modules/@esbuild/win32-x64": {
403
+ "version": "0.21.5",
404
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
405
+ "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
406
+ "cpu": [
407
+ "x64"
408
+ ],
409
+ "dev": true,
410
+ "license": "MIT",
411
+ "optional": true,
412
+ "os": [
413
+ "win32"
414
+ ],
415
+ "engines": {
416
+ "node": ">=12"
417
+ }
418
+ },
419
+ "node_modules/@huggingface/jinja": {
420
+ "version": "0.5.3",
421
+ "resolved": "https://registry.npmjs.org/@huggingface/jinja/-/jinja-0.5.3.tgz",
422
+ "integrity": "sha512-asqfZ4GQS0hD876Uw4qiUb7Tr/V5Q+JZuo2L+BtdrD4U40QU58nIRq3ZSgAzJgT874VLjhGVacaYfrdpXtEvtA==",
423
+ "license": "MIT",
424
+ "engines": {
425
+ "node": ">=18"
426
+ }
427
+ },
428
+ "node_modules/@huggingface/transformers": {
429
+ "version": "3.8.1",
430
+ "resolved": "https://registry.npmjs.org/@huggingface/transformers/-/transformers-3.8.1.tgz",
431
+ "integrity": "sha512-tsTk4zVjImqdqjS8/AOZg2yNLd1z9S5v+7oUPpXaasDRwEDhB+xnglK1k5cad26lL5/ZIaeREgWWy0bs9y9pPA==",
432
+ "license": "Apache-2.0",
433
+ "dependencies": {
434
+ "@huggingface/jinja": "^0.5.3",
435
+ "onnxruntime-node": "1.21.0",
436
+ "onnxruntime-web": "1.22.0-dev.20250409-89f8206ba4",
437
+ "sharp": "^0.34.1"
438
+ }
439
+ },
440
+ "node_modules/@huggingface/transformers/node_modules/onnxruntime-common": {
441
+ "version": "1.22.0-dev.20250409-89f8206ba4",
442
+ "resolved": "https://registry.npmjs.org/onnxruntime-common/-/onnxruntime-common-1.22.0-dev.20250409-89f8206ba4.tgz",
443
+ "integrity": "sha512-vDJMkfCfb0b1A836rgHj+ORuZf4B4+cc2bASQtpeoJLueuFc5DuYwjIZUBrSvx/fO5IrLjLz+oTrB3pcGlhovQ==",
444
+ "license": "MIT"
445
+ },
446
+ "node_modules/@huggingface/transformers/node_modules/onnxruntime-web": {
447
+ "version": "1.22.0-dev.20250409-89f8206ba4",
448
+ "resolved": "https://registry.npmjs.org/onnxruntime-web/-/onnxruntime-web-1.22.0-dev.20250409-89f8206ba4.tgz",
449
+ "integrity": "sha512-0uS76OPgH0hWCPrFKlL8kYVV7ckM7t/36HfbgoFw6Nd0CZVVbQC4PkrR8mBX8LtNUFZO25IQBqV2Hx2ho3FlbQ==",
450
+ "license": "MIT",
451
+ "dependencies": {
452
+ "flatbuffers": "^25.1.24",
453
+ "guid-typescript": "^1.0.9",
454
+ "long": "^5.2.3",
455
+ "onnxruntime-common": "1.22.0-dev.20250409-89f8206ba4",
456
+ "platform": "^1.3.6",
457
+ "protobufjs": "^7.2.4"
458
+ }
459
+ },
460
+ "node_modules/@img/colour": {
461
+ "version": "1.0.0",
462
+ "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.0.0.tgz",
463
+ "integrity": "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==",
464
+ "license": "MIT",
465
+ "engines": {
466
+ "node": ">=18"
467
+ }
468
+ },
469
+ "node_modules/@img/sharp-darwin-arm64": {
470
+ "version": "0.34.5",
471
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz",
472
+ "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==",
473
+ "cpu": [
474
+ "arm64"
475
+ ],
476
+ "license": "Apache-2.0",
477
+ "optional": true,
478
+ "os": [
479
+ "darwin"
480
+ ],
481
+ "engines": {
482
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
483
+ },
484
+ "funding": {
485
+ "url": "https://opencollective.com/libvips"
486
+ },
487
+ "optionalDependencies": {
488
+ "@img/sharp-libvips-darwin-arm64": "1.2.4"
489
+ }
490
+ },
491
+ "node_modules/@img/sharp-darwin-x64": {
492
+ "version": "0.34.5",
493
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz",
494
+ "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==",
495
+ "cpu": [
496
+ "x64"
497
+ ],
498
+ "license": "Apache-2.0",
499
+ "optional": true,
500
+ "os": [
501
+ "darwin"
502
+ ],
503
+ "engines": {
504
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
505
+ },
506
+ "funding": {
507
+ "url": "https://opencollective.com/libvips"
508
+ },
509
+ "optionalDependencies": {
510
+ "@img/sharp-libvips-darwin-x64": "1.2.4"
511
+ }
512
+ },
513
+ "node_modules/@img/sharp-libvips-darwin-arm64": {
514
+ "version": "1.2.4",
515
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz",
516
+ "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==",
517
+ "cpu": [
518
+ "arm64"
519
+ ],
520
+ "license": "LGPL-3.0-or-later",
521
+ "optional": true,
522
+ "os": [
523
+ "darwin"
524
+ ],
525
+ "funding": {
526
+ "url": "https://opencollective.com/libvips"
527
+ }
528
+ },
529
+ "node_modules/@img/sharp-libvips-darwin-x64": {
530
+ "version": "1.2.4",
531
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz",
532
+ "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==",
533
+ "cpu": [
534
+ "x64"
535
+ ],
536
+ "license": "LGPL-3.0-or-later",
537
+ "optional": true,
538
+ "os": [
539
+ "darwin"
540
+ ],
541
+ "funding": {
542
+ "url": "https://opencollective.com/libvips"
543
+ }
544
+ },
545
+ "node_modules/@img/sharp-libvips-linux-arm": {
546
+ "version": "1.2.4",
547
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz",
548
+ "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==",
549
+ "cpu": [
550
+ "arm"
551
+ ],
552
+ "license": "LGPL-3.0-or-later",
553
+ "optional": true,
554
+ "os": [
555
+ "linux"
556
+ ],
557
+ "funding": {
558
+ "url": "https://opencollective.com/libvips"
559
+ }
560
+ },
561
+ "node_modules/@img/sharp-libvips-linux-arm64": {
562
+ "version": "1.2.4",
563
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz",
564
+ "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==",
565
+ "cpu": [
566
+ "arm64"
567
+ ],
568
+ "license": "LGPL-3.0-or-later",
569
+ "optional": true,
570
+ "os": [
571
+ "linux"
572
+ ],
573
+ "funding": {
574
+ "url": "https://opencollective.com/libvips"
575
+ }
576
+ },
577
+ "node_modules/@img/sharp-libvips-linux-ppc64": {
578
+ "version": "1.2.4",
579
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz",
580
+ "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==",
581
+ "cpu": [
582
+ "ppc64"
583
+ ],
584
+ "license": "LGPL-3.0-or-later",
585
+ "optional": true,
586
+ "os": [
587
+ "linux"
588
+ ],
589
+ "funding": {
590
+ "url": "https://opencollective.com/libvips"
591
+ }
592
+ },
593
+ "node_modules/@img/sharp-libvips-linux-riscv64": {
594
+ "version": "1.2.4",
595
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz",
596
+ "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==",
597
+ "cpu": [
598
+ "riscv64"
599
+ ],
600
+ "license": "LGPL-3.0-or-later",
601
+ "optional": true,
602
+ "os": [
603
+ "linux"
604
+ ],
605
+ "funding": {
606
+ "url": "https://opencollective.com/libvips"
607
+ }
608
+ },
609
+ "node_modules/@img/sharp-libvips-linux-s390x": {
610
+ "version": "1.2.4",
611
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz",
612
+ "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==",
613
+ "cpu": [
614
+ "s390x"
615
+ ],
616
+ "license": "LGPL-3.0-or-later",
617
+ "optional": true,
618
+ "os": [
619
+ "linux"
620
+ ],
621
+ "funding": {
622
+ "url": "https://opencollective.com/libvips"
623
+ }
624
+ },
625
+ "node_modules/@img/sharp-libvips-linux-x64": {
626
+ "version": "1.2.4",
627
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz",
628
+ "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==",
629
+ "cpu": [
630
+ "x64"
631
+ ],
632
+ "license": "LGPL-3.0-or-later",
633
+ "optional": true,
634
+ "os": [
635
+ "linux"
636
+ ],
637
+ "funding": {
638
+ "url": "https://opencollective.com/libvips"
639
+ }
640
+ },
641
+ "node_modules/@img/sharp-libvips-linuxmusl-arm64": {
642
+ "version": "1.2.4",
643
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz",
644
+ "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==",
645
+ "cpu": [
646
+ "arm64"
647
+ ],
648
+ "license": "LGPL-3.0-or-later",
649
+ "optional": true,
650
+ "os": [
651
+ "linux"
652
+ ],
653
+ "funding": {
654
+ "url": "https://opencollective.com/libvips"
655
+ }
656
+ },
657
+ "node_modules/@img/sharp-libvips-linuxmusl-x64": {
658
+ "version": "1.2.4",
659
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz",
660
+ "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==",
661
+ "cpu": [
662
+ "x64"
663
+ ],
664
+ "license": "LGPL-3.0-or-later",
665
+ "optional": true,
666
+ "os": [
667
+ "linux"
668
+ ],
669
+ "funding": {
670
+ "url": "https://opencollective.com/libvips"
671
+ }
672
+ },
673
+ "node_modules/@img/sharp-linux-arm": {
674
+ "version": "0.34.5",
675
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz",
676
+ "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==",
677
+ "cpu": [
678
+ "arm"
679
+ ],
680
+ "license": "Apache-2.0",
681
+ "optional": true,
682
+ "os": [
683
+ "linux"
684
+ ],
685
+ "engines": {
686
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
687
+ },
688
+ "funding": {
689
+ "url": "https://opencollective.com/libvips"
690
+ },
691
+ "optionalDependencies": {
692
+ "@img/sharp-libvips-linux-arm": "1.2.4"
693
+ }
694
+ },
695
+ "node_modules/@img/sharp-linux-arm64": {
696
+ "version": "0.34.5",
697
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz",
698
+ "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==",
699
+ "cpu": [
700
+ "arm64"
701
+ ],
702
+ "license": "Apache-2.0",
703
+ "optional": true,
704
+ "os": [
705
+ "linux"
706
+ ],
707
+ "engines": {
708
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
709
+ },
710
+ "funding": {
711
+ "url": "https://opencollective.com/libvips"
712
+ },
713
+ "optionalDependencies": {
714
+ "@img/sharp-libvips-linux-arm64": "1.2.4"
715
+ }
716
+ },
717
+ "node_modules/@img/sharp-linux-ppc64": {
718
+ "version": "0.34.5",
719
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz",
720
+ "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==",
721
+ "cpu": [
722
+ "ppc64"
723
+ ],
724
+ "license": "Apache-2.0",
725
+ "optional": true,
726
+ "os": [
727
+ "linux"
728
+ ],
729
+ "engines": {
730
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
731
+ },
732
+ "funding": {
733
+ "url": "https://opencollective.com/libvips"
734
+ },
735
+ "optionalDependencies": {
736
+ "@img/sharp-libvips-linux-ppc64": "1.2.4"
737
+ }
738
+ },
739
+ "node_modules/@img/sharp-linux-riscv64": {
740
+ "version": "0.34.5",
741
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz",
742
+ "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==",
743
+ "cpu": [
744
+ "riscv64"
745
+ ],
746
+ "license": "Apache-2.0",
747
+ "optional": true,
748
+ "os": [
749
+ "linux"
750
+ ],
751
+ "engines": {
752
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
753
+ },
754
+ "funding": {
755
+ "url": "https://opencollective.com/libvips"
756
+ },
757
+ "optionalDependencies": {
758
+ "@img/sharp-libvips-linux-riscv64": "1.2.4"
759
+ }
760
+ },
761
+ "node_modules/@img/sharp-linux-s390x": {
762
+ "version": "0.34.5",
763
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz",
764
+ "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==",
765
+ "cpu": [
766
+ "s390x"
767
+ ],
768
+ "license": "Apache-2.0",
769
+ "optional": true,
770
+ "os": [
771
+ "linux"
772
+ ],
773
+ "engines": {
774
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
775
+ },
776
+ "funding": {
777
+ "url": "https://opencollective.com/libvips"
778
+ },
779
+ "optionalDependencies": {
780
+ "@img/sharp-libvips-linux-s390x": "1.2.4"
781
+ }
782
+ },
783
+ "node_modules/@img/sharp-linux-x64": {
784
+ "version": "0.34.5",
785
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz",
786
+ "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==",
787
+ "cpu": [
788
+ "x64"
789
+ ],
790
+ "license": "Apache-2.0",
791
+ "optional": true,
792
+ "os": [
793
+ "linux"
794
+ ],
795
+ "engines": {
796
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
797
+ },
798
+ "funding": {
799
+ "url": "https://opencollective.com/libvips"
800
+ },
801
+ "optionalDependencies": {
802
+ "@img/sharp-libvips-linux-x64": "1.2.4"
803
+ }
804
+ },
805
+ "node_modules/@img/sharp-linuxmusl-arm64": {
806
+ "version": "0.34.5",
807
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz",
808
+ "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==",
809
+ "cpu": [
810
+ "arm64"
811
+ ],
812
+ "license": "Apache-2.0",
813
+ "optional": true,
814
+ "os": [
815
+ "linux"
816
+ ],
817
+ "engines": {
818
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
819
+ },
820
+ "funding": {
821
+ "url": "https://opencollective.com/libvips"
822
+ },
823
+ "optionalDependencies": {
824
+ "@img/sharp-libvips-linuxmusl-arm64": "1.2.4"
825
+ }
826
+ },
827
+ "node_modules/@img/sharp-linuxmusl-x64": {
828
+ "version": "0.34.5",
829
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz",
830
+ "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==",
831
+ "cpu": [
832
+ "x64"
833
+ ],
834
+ "license": "Apache-2.0",
835
+ "optional": true,
836
+ "os": [
837
+ "linux"
838
+ ],
839
+ "engines": {
840
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
841
+ },
842
+ "funding": {
843
+ "url": "https://opencollective.com/libvips"
844
+ },
845
+ "optionalDependencies": {
846
+ "@img/sharp-libvips-linuxmusl-x64": "1.2.4"
847
+ }
848
+ },
849
+ "node_modules/@img/sharp-wasm32": {
850
+ "version": "0.34.5",
851
+ "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz",
852
+ "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==",
853
+ "cpu": [
854
+ "wasm32"
855
+ ],
856
+ "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
857
+ "optional": true,
858
+ "dependencies": {
859
+ "@emnapi/runtime": "^1.7.0"
860
+ },
861
+ "engines": {
862
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
863
+ },
864
+ "funding": {
865
+ "url": "https://opencollective.com/libvips"
866
+ }
867
+ },
868
+ "node_modules/@img/sharp-win32-arm64": {
869
+ "version": "0.34.5",
870
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz",
871
+ "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==",
872
+ "cpu": [
873
+ "arm64"
874
+ ],
875
+ "license": "Apache-2.0 AND LGPL-3.0-or-later",
876
+ "optional": true,
877
+ "os": [
878
+ "win32"
879
+ ],
880
+ "engines": {
881
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
882
+ },
883
+ "funding": {
884
+ "url": "https://opencollective.com/libvips"
885
+ }
886
+ },
887
+ "node_modules/@img/sharp-win32-ia32": {
888
+ "version": "0.34.5",
889
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz",
890
+ "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==",
891
+ "cpu": [
892
+ "ia32"
893
+ ],
894
+ "license": "Apache-2.0 AND LGPL-3.0-or-later",
895
+ "optional": true,
896
+ "os": [
897
+ "win32"
898
+ ],
899
+ "engines": {
900
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
901
+ },
902
+ "funding": {
903
+ "url": "https://opencollective.com/libvips"
904
+ }
905
+ },
906
+ "node_modules/@img/sharp-win32-x64": {
907
+ "version": "0.34.5",
908
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz",
909
+ "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==",
910
+ "cpu": [
911
+ "x64"
912
+ ],
913
+ "license": "Apache-2.0 AND LGPL-3.0-or-later",
914
+ "optional": true,
915
+ "os": [
916
+ "win32"
917
+ ],
918
+ "engines": {
919
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
920
+ },
921
+ "funding": {
922
+ "url": "https://opencollective.com/libvips"
923
+ }
924
+ },
925
+ "node_modules/@isaacs/fs-minipass": {
926
+ "version": "4.0.1",
927
+ "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz",
928
+ "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==",
929
+ "license": "ISC",
930
+ "dependencies": {
931
+ "minipass": "^7.0.4"
932
+ },
933
+ "engines": {
934
+ "node": ">=18.0.0"
935
+ }
936
+ },
937
+ "node_modules/@protobufjs/aspromise": {
938
+ "version": "1.1.2",
939
+ "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
940
+ "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==",
941
+ "license": "BSD-3-Clause"
942
+ },
943
+ "node_modules/@protobufjs/base64": {
944
+ "version": "1.1.2",
945
+ "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz",
946
+ "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==",
947
+ "license": "BSD-3-Clause"
948
+ },
949
+ "node_modules/@protobufjs/codegen": {
950
+ "version": "2.0.4",
951
+ "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz",
952
+ "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==",
953
+ "license": "BSD-3-Clause"
954
+ },
955
+ "node_modules/@protobufjs/eventemitter": {
956
+ "version": "1.1.0",
957
+ "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz",
958
+ "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==",
959
+ "license": "BSD-3-Clause"
960
+ },
961
+ "node_modules/@protobufjs/fetch": {
962
+ "version": "1.1.0",
963
+ "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz",
964
+ "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==",
965
+ "license": "BSD-3-Clause",
966
+ "dependencies": {
967
+ "@protobufjs/aspromise": "^1.1.1",
968
+ "@protobufjs/inquire": "^1.1.0"
969
+ }
970
+ },
971
+ "node_modules/@protobufjs/float": {
972
+ "version": "1.0.2",
973
+ "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz",
974
+ "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==",
975
+ "license": "BSD-3-Clause"
976
+ },
977
+ "node_modules/@protobufjs/inquire": {
978
+ "version": "1.1.0",
979
+ "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz",
980
+ "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==",
981
+ "license": "BSD-3-Clause"
982
+ },
983
+ "node_modules/@protobufjs/path": {
984
+ "version": "1.1.2",
985
+ "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz",
986
+ "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==",
987
+ "license": "BSD-3-Clause"
988
+ },
989
+ "node_modules/@protobufjs/pool": {
990
+ "version": "1.1.0",
991
+ "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz",
992
+ "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==",
993
+ "license": "BSD-3-Clause"
994
+ },
995
+ "node_modules/@protobufjs/utf8": {
996
+ "version": "1.1.0",
997
+ "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz",
998
+ "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==",
999
+ "license": "BSD-3-Clause"
1000
+ },
1001
+ "node_modules/@rollup/rollup-android-arm-eabi": {
1002
+ "version": "4.54.0",
1003
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.54.0.tgz",
1004
+ "integrity": "sha512-OywsdRHrFvCdvsewAInDKCNyR3laPA2mc9bRYJ6LBp5IyvF3fvXbbNR0bSzHlZVFtn6E0xw2oZlyjg4rKCVcng==",
1005
+ "cpu": [
1006
+ "arm"
1007
+ ],
1008
+ "dev": true,
1009
+ "license": "MIT",
1010
+ "optional": true,
1011
+ "os": [
1012
+ "android"
1013
+ ]
1014
+ },
1015
+ "node_modules/@rollup/rollup-android-arm64": {
1016
+ "version": "4.54.0",
1017
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.54.0.tgz",
1018
+ "integrity": "sha512-Skx39Uv+u7H224Af+bDgNinitlmHyQX1K/atIA32JP3JQw6hVODX5tkbi2zof/E69M1qH2UoN3Xdxgs90mmNYw==",
1019
+ "cpu": [
1020
+ "arm64"
1021
+ ],
1022
+ "dev": true,
1023
+ "license": "MIT",
1024
+ "optional": true,
1025
+ "os": [
1026
+ "android"
1027
+ ]
1028
+ },
1029
+ "node_modules/@rollup/rollup-darwin-arm64": {
1030
+ "version": "4.54.0",
1031
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.54.0.tgz",
1032
+ "integrity": "sha512-k43D4qta/+6Fq+nCDhhv9yP2HdeKeP56QrUUTW7E6PhZP1US6NDqpJj4MY0jBHlJivVJD5P8NxrjuobZBJTCRw==",
1033
+ "cpu": [
1034
+ "arm64"
1035
+ ],
1036
+ "dev": true,
1037
+ "license": "MIT",
1038
+ "optional": true,
1039
+ "os": [
1040
+ "darwin"
1041
+ ]
1042
+ },
1043
+ "node_modules/@rollup/rollup-darwin-x64": {
1044
+ "version": "4.54.0",
1045
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.54.0.tgz",
1046
+ "integrity": "sha512-cOo7biqwkpawslEfox5Vs8/qj83M/aZCSSNIWpVzfU2CYHa2G3P1UN5WF01RdTHSgCkri7XOlTdtk17BezlV3A==",
1047
+ "cpu": [
1048
+ "x64"
1049
+ ],
1050
+ "dev": true,
1051
+ "license": "MIT",
1052
+ "optional": true,
1053
+ "os": [
1054
+ "darwin"
1055
+ ]
1056
+ },
1057
+ "node_modules/@rollup/rollup-freebsd-arm64": {
1058
+ "version": "4.54.0",
1059
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.54.0.tgz",
1060
+ "integrity": "sha512-miSvuFkmvFbgJ1BevMa4CPCFt5MPGw094knM64W9I0giUIMMmRYcGW/JWZDriaw/k1kOBtsWh1z6nIFV1vPNtA==",
1061
+ "cpu": [
1062
+ "arm64"
1063
+ ],
1064
+ "dev": true,
1065
+ "license": "MIT",
1066
+ "optional": true,
1067
+ "os": [
1068
+ "freebsd"
1069
+ ]
1070
+ },
1071
+ "node_modules/@rollup/rollup-freebsd-x64": {
1072
+ "version": "4.54.0",
1073
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.54.0.tgz",
1074
+ "integrity": "sha512-KGXIs55+b/ZfZsq9aR026tmr/+7tq6VG6MsnrvF4H8VhwflTIuYh+LFUlIsRdQSgrgmtM3fVATzEAj4hBQlaqQ==",
1075
+ "cpu": [
1076
+ "x64"
1077
+ ],
1078
+ "dev": true,
1079
+ "license": "MIT",
1080
+ "optional": true,
1081
+ "os": [
1082
+ "freebsd"
1083
+ ]
1084
+ },
1085
+ "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
1086
+ "version": "4.54.0",
1087
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.54.0.tgz",
1088
+ "integrity": "sha512-EHMUcDwhtdRGlXZsGSIuXSYwD5kOT9NVnx9sqzYiwAc91wfYOE1g1djOEDseZJKKqtHAHGwnGPQu3kytmfaXLQ==",
1089
+ "cpu": [
1090
+ "arm"
1091
+ ],
1092
+ "dev": true,
1093
+ "license": "MIT",
1094
+ "optional": true,
1095
+ "os": [
1096
+ "linux"
1097
+ ]
1098
+ },
1099
+ "node_modules/@rollup/rollup-linux-arm-musleabihf": {
1100
+ "version": "4.54.0",
1101
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.54.0.tgz",
1102
+ "integrity": "sha512-+pBrqEjaakN2ySv5RVrj/qLytYhPKEUwk+e3SFU5jTLHIcAtqh2rLrd/OkbNuHJpsBgxsD8ccJt5ga/SeG0JmA==",
1103
+ "cpu": [
1104
+ "arm"
1105
+ ],
1106
+ "dev": true,
1107
+ "license": "MIT",
1108
+ "optional": true,
1109
+ "os": [
1110
+ "linux"
1111
+ ]
1112
+ },
1113
+ "node_modules/@rollup/rollup-linux-arm64-gnu": {
1114
+ "version": "4.54.0",
1115
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.54.0.tgz",
1116
+ "integrity": "sha512-NSqc7rE9wuUaRBsBp5ckQ5CVz5aIRKCwsoa6WMF7G01sX3/qHUw/z4pv+D+ahL1EIKy6Enpcnz1RY8pf7bjwng==",
1117
+ "cpu": [
1118
+ "arm64"
1119
+ ],
1120
+ "dev": true,
1121
+ "license": "MIT",
1122
+ "optional": true,
1123
+ "os": [
1124
+ "linux"
1125
+ ]
1126
+ },
1127
+ "node_modules/@rollup/rollup-linux-arm64-musl": {
1128
+ "version": "4.54.0",
1129
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.54.0.tgz",
1130
+ "integrity": "sha512-gr5vDbg3Bakga5kbdpqx81m2n9IX8M6gIMlQQIXiLTNeQW6CucvuInJ91EuCJ/JYvc+rcLLsDFcfAD1K7fMofg==",
1131
+ "cpu": [
1132
+ "arm64"
1133
+ ],
1134
+ "dev": true,
1135
+ "license": "MIT",
1136
+ "optional": true,
1137
+ "os": [
1138
+ "linux"
1139
+ ]
1140
+ },
1141
+ "node_modules/@rollup/rollup-linux-loong64-gnu": {
1142
+ "version": "4.54.0",
1143
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.54.0.tgz",
1144
+ "integrity": "sha512-gsrtB1NA3ZYj2vq0Rzkylo9ylCtW/PhpLEivlgWe0bpgtX5+9j9EZa0wtZiCjgu6zmSeZWyI/e2YRX1URozpIw==",
1145
+ "cpu": [
1146
+ "loong64"
1147
+ ],
1148
+ "dev": true,
1149
+ "license": "MIT",
1150
+ "optional": true,
1151
+ "os": [
1152
+ "linux"
1153
+ ]
1154
+ },
1155
+ "node_modules/@rollup/rollup-linux-ppc64-gnu": {
1156
+ "version": "4.54.0",
1157
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.54.0.tgz",
1158
+ "integrity": "sha512-y3qNOfTBStmFNq+t4s7Tmc9hW2ENtPg8FeUD/VShI7rKxNW7O4fFeaYbMsd3tpFlIg1Q8IapFgy7Q9i2BqeBvA==",
1159
+ "cpu": [
1160
+ "ppc64"
1161
+ ],
1162
+ "dev": true,
1163
+ "license": "MIT",
1164
+ "optional": true,
1165
+ "os": [
1166
+ "linux"
1167
+ ]
1168
+ },
1169
+ "node_modules/@rollup/rollup-linux-riscv64-gnu": {
1170
+ "version": "4.54.0",
1171
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.54.0.tgz",
1172
+ "integrity": "sha512-89sepv7h2lIVPsFma8iwmccN7Yjjtgz0Rj/Ou6fEqg3HDhpCa+Et+YSufy27i6b0Wav69Qv4WBNl3Rs6pwhebQ==",
1173
+ "cpu": [
1174
+ "riscv64"
1175
+ ],
1176
+ "dev": true,
1177
+ "license": "MIT",
1178
+ "optional": true,
1179
+ "os": [
1180
+ "linux"
1181
+ ]
1182
+ },
1183
+ "node_modules/@rollup/rollup-linux-riscv64-musl": {
1184
+ "version": "4.54.0",
1185
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.54.0.tgz",
1186
+ "integrity": "sha512-ZcU77ieh0M2Q8Ur7D5X7KvK+UxbXeDHwiOt/CPSBTI1fBmeDMivW0dPkdqkT4rOgDjrDDBUed9x4EgraIKoR2A==",
1187
+ "cpu": [
1188
+ "riscv64"
1189
+ ],
1190
+ "dev": true,
1191
+ "license": "MIT",
1192
+ "optional": true,
1193
+ "os": [
1194
+ "linux"
1195
+ ]
1196
+ },
1197
+ "node_modules/@rollup/rollup-linux-s390x-gnu": {
1198
+ "version": "4.54.0",
1199
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.54.0.tgz",
1200
+ "integrity": "sha512-2AdWy5RdDF5+4YfG/YesGDDtbyJlC9LHmL6rZw6FurBJ5n4vFGupsOBGfwMRjBYH7qRQowT8D/U4LoSvVwOhSQ==",
1201
+ "cpu": [
1202
+ "s390x"
1203
+ ],
1204
+ "dev": true,
1205
+ "license": "MIT",
1206
+ "optional": true,
1207
+ "os": [
1208
+ "linux"
1209
+ ]
1210
+ },
1211
+ "node_modules/@rollup/rollup-linux-x64-gnu": {
1212
+ "version": "4.54.0",
1213
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.54.0.tgz",
1214
+ "integrity": "sha512-WGt5J8Ij/rvyqpFexxk3ffKqqbLf9AqrTBbWDk7ApGUzaIs6V+s2s84kAxklFwmMF/vBNGrVdYgbblCOFFezMQ==",
1215
+ "cpu": [
1216
+ "x64"
1217
+ ],
1218
+ "dev": true,
1219
+ "license": "MIT",
1220
+ "optional": true,
1221
+ "os": [
1222
+ "linux"
1223
+ ]
1224
+ },
1225
+ "node_modules/@rollup/rollup-linux-x64-musl": {
1226
+ "version": "4.54.0",
1227
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.54.0.tgz",
1228
+ "integrity": "sha512-JzQmb38ATzHjxlPHuTH6tE7ojnMKM2kYNzt44LO/jJi8BpceEC8QuXYA908n8r3CNuG/B3BV8VR3Hi1rYtmPiw==",
1229
+ "cpu": [
1230
+ "x64"
1231
+ ],
1232
+ "dev": true,
1233
+ "license": "MIT",
1234
+ "optional": true,
1235
+ "os": [
1236
+ "linux"
1237
+ ]
1238
+ },
1239
+ "node_modules/@rollup/rollup-openharmony-arm64": {
1240
+ "version": "4.54.0",
1241
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.54.0.tgz",
1242
+ "integrity": "sha512-huT3fd0iC7jigGh7n3q/+lfPcXxBi+om/Rs3yiFxjvSxbSB6aohDFXbWvlspaqjeOh+hx7DDHS+5Es5qRkWkZg==",
1243
+ "cpu": [
1244
+ "arm64"
1245
+ ],
1246
+ "dev": true,
1247
+ "license": "MIT",
1248
+ "optional": true,
1249
+ "os": [
1250
+ "openharmony"
1251
+ ]
1252
+ },
1253
+ "node_modules/@rollup/rollup-win32-arm64-msvc": {
1254
+ "version": "4.54.0",
1255
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.54.0.tgz",
1256
+ "integrity": "sha512-c2V0W1bsKIKfbLMBu/WGBz6Yci8nJ/ZJdheE0EwB73N3MvHYKiKGs3mVilX4Gs70eGeDaMqEob25Tw2Gb9Nqyw==",
1257
+ "cpu": [
1258
+ "arm64"
1259
+ ],
1260
+ "dev": true,
1261
+ "license": "MIT",
1262
+ "optional": true,
1263
+ "os": [
1264
+ "win32"
1265
+ ]
1266
+ },
1267
+ "node_modules/@rollup/rollup-win32-ia32-msvc": {
1268
+ "version": "4.54.0",
1269
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.54.0.tgz",
1270
+ "integrity": "sha512-woEHgqQqDCkAzrDhvDipnSirm5vxUXtSKDYTVpZG3nUdW/VVB5VdCYA2iReSj/u3yCZzXID4kuKG7OynPnB3WQ==",
1271
+ "cpu": [
1272
+ "ia32"
1273
+ ],
1274
+ "dev": true,
1275
+ "license": "MIT",
1276
+ "optional": true,
1277
+ "os": [
1278
+ "win32"
1279
+ ]
1280
+ },
1281
+ "node_modules/@rollup/rollup-win32-x64-gnu": {
1282
+ "version": "4.54.0",
1283
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.54.0.tgz",
1284
+ "integrity": "sha512-dzAc53LOuFvHwbCEOS0rPbXp6SIhAf2txMP5p6mGyOXXw5mWY8NGGbPMPrs4P1WItkfApDathBj/NzMLUZ9rtQ==",
1285
+ "cpu": [
1286
+ "x64"
1287
+ ],
1288
+ "dev": true,
1289
+ "license": "MIT",
1290
+ "optional": true,
1291
+ "os": [
1292
+ "win32"
1293
+ ]
1294
+ },
1295
+ "node_modules/@rollup/rollup-win32-x64-msvc": {
1296
+ "version": "4.54.0",
1297
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.54.0.tgz",
1298
+ "integrity": "sha512-hYT5d3YNdSh3mbCU1gwQyPgQd3T2ne0A3KG8KSBdav5TiBg6eInVmV+TeR5uHufiIgSFg0XsOWGW5/RhNcSvPg==",
1299
+ "cpu": [
1300
+ "x64"
1301
+ ],
1302
+ "dev": true,
1303
+ "license": "MIT",
1304
+ "optional": true,
1305
+ "os": [
1306
+ "win32"
1307
+ ]
1308
+ },
1309
+ "node_modules/@types/estree": {
1310
+ "version": "1.0.8",
1311
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
1312
+ "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
1313
+ "dev": true,
1314
+ "license": "MIT"
1315
+ },
1316
+ "node_modules/@types/node": {
1317
+ "version": "25.0.3",
1318
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.3.tgz",
1319
+ "integrity": "sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA==",
1320
+ "license": "MIT",
1321
+ "dependencies": {
1322
+ "undici-types": "~7.16.0"
1323
+ }
1324
+ },
1325
+ "node_modules/boolean": {
1326
+ "version": "3.2.0",
1327
+ "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz",
1328
+ "integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==",
1329
+ "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.",
1330
+ "license": "MIT"
1331
+ },
1332
+ "node_modules/chownr": {
1333
+ "version": "3.0.0",
1334
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz",
1335
+ "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==",
1336
+ "license": "BlueOak-1.0.0",
1337
+ "engines": {
1338
+ "node": ">=18"
1339
+ }
1340
+ },
1341
+ "node_modules/define-data-property": {
1342
+ "version": "1.1.4",
1343
+ "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
1344
+ "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
1345
+ "license": "MIT",
1346
+ "dependencies": {
1347
+ "es-define-property": "^1.0.0",
1348
+ "es-errors": "^1.3.0",
1349
+ "gopd": "^1.0.1"
1350
+ },
1351
+ "engines": {
1352
+ "node": ">= 0.4"
1353
+ },
1354
+ "funding": {
1355
+ "url": "https://github.com/sponsors/ljharb"
1356
+ }
1357
+ },
1358
+ "node_modules/define-properties": {
1359
+ "version": "1.2.1",
1360
+ "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
1361
+ "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
1362
+ "license": "MIT",
1363
+ "dependencies": {
1364
+ "define-data-property": "^1.0.1",
1365
+ "has-property-descriptors": "^1.0.0",
1366
+ "object-keys": "^1.1.1"
1367
+ },
1368
+ "engines": {
1369
+ "node": ">= 0.4"
1370
+ },
1371
+ "funding": {
1372
+ "url": "https://github.com/sponsors/ljharb"
1373
+ }
1374
+ },
1375
+ "node_modules/detect-libc": {
1376
+ "version": "2.1.2",
1377
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz",
1378
+ "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
1379
+ "license": "Apache-2.0",
1380
+ "engines": {
1381
+ "node": ">=8"
1382
+ }
1383
+ },
1384
+ "node_modules/detect-node": {
1385
+ "version": "2.1.0",
1386
+ "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz",
1387
+ "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==",
1388
+ "license": "MIT"
1389
+ },
1390
+ "node_modules/es-define-property": {
1391
+ "version": "1.0.1",
1392
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
1393
+ "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
1394
+ "license": "MIT",
1395
+ "engines": {
1396
+ "node": ">= 0.4"
1397
+ }
1398
+ },
1399
+ "node_modules/es-errors": {
1400
+ "version": "1.3.0",
1401
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
1402
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
1403
+ "license": "MIT",
1404
+ "engines": {
1405
+ "node": ">= 0.4"
1406
+ }
1407
+ },
1408
+ "node_modules/es6-error": {
1409
+ "version": "4.1.1",
1410
+ "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz",
1411
+ "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==",
1412
+ "license": "MIT"
1413
+ },
1414
+ "node_modules/esbuild": {
1415
+ "version": "0.21.5",
1416
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
1417
+ "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
1418
+ "dev": true,
1419
+ "hasInstallScript": true,
1420
+ "license": "MIT",
1421
+ "bin": {
1422
+ "esbuild": "bin/esbuild"
1423
+ },
1424
+ "engines": {
1425
+ "node": ">=12"
1426
+ },
1427
+ "optionalDependencies": {
1428
+ "@esbuild/aix-ppc64": "0.21.5",
1429
+ "@esbuild/android-arm": "0.21.5",
1430
+ "@esbuild/android-arm64": "0.21.5",
1431
+ "@esbuild/android-x64": "0.21.5",
1432
+ "@esbuild/darwin-arm64": "0.21.5",
1433
+ "@esbuild/darwin-x64": "0.21.5",
1434
+ "@esbuild/freebsd-arm64": "0.21.5",
1435
+ "@esbuild/freebsd-x64": "0.21.5",
1436
+ "@esbuild/linux-arm": "0.21.5",
1437
+ "@esbuild/linux-arm64": "0.21.5",
1438
+ "@esbuild/linux-ia32": "0.21.5",
1439
+ "@esbuild/linux-loong64": "0.21.5",
1440
+ "@esbuild/linux-mips64el": "0.21.5",
1441
+ "@esbuild/linux-ppc64": "0.21.5",
1442
+ "@esbuild/linux-riscv64": "0.21.5",
1443
+ "@esbuild/linux-s390x": "0.21.5",
1444
+ "@esbuild/linux-x64": "0.21.5",
1445
+ "@esbuild/netbsd-x64": "0.21.5",
1446
+ "@esbuild/openbsd-x64": "0.21.5",
1447
+ "@esbuild/sunos-x64": "0.21.5",
1448
+ "@esbuild/win32-arm64": "0.21.5",
1449
+ "@esbuild/win32-ia32": "0.21.5",
1450
+ "@esbuild/win32-x64": "0.21.5"
1451
+ }
1452
+ },
1453
+ "node_modules/escape-string-regexp": {
1454
+ "version": "4.0.0",
1455
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
1456
+ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
1457
+ "license": "MIT",
1458
+ "engines": {
1459
+ "node": ">=10"
1460
+ },
1461
+ "funding": {
1462
+ "url": "https://github.com/sponsors/sindresorhus"
1463
+ }
1464
+ },
1465
+ "node_modules/flatbuffers": {
1466
+ "version": "25.9.23",
1467
+ "resolved": "https://registry.npmjs.org/flatbuffers/-/flatbuffers-25.9.23.tgz",
1468
+ "integrity": "sha512-MI1qs7Lo4Syw0EOzUl0xjs2lsoeqFku44KpngfIduHBYvzm8h2+7K8YMQh1JtVVVrUvhLpNwqVi4DERegUJhPQ==",
1469
+ "license": "Apache-2.0"
1470
+ },
1471
+ "node_modules/fsevents": {
1472
+ "version": "2.3.3",
1473
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
1474
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
1475
+ "dev": true,
1476
+ "hasInstallScript": true,
1477
+ "license": "MIT",
1478
+ "optional": true,
1479
+ "os": [
1480
+ "darwin"
1481
+ ],
1482
+ "engines": {
1483
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
1484
+ }
1485
+ },
1486
+ "node_modules/global-agent": {
1487
+ "version": "3.0.0",
1488
+ "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-3.0.0.tgz",
1489
+ "integrity": "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==",
1490
+ "license": "BSD-3-Clause",
1491
+ "dependencies": {
1492
+ "boolean": "^3.0.1",
1493
+ "es6-error": "^4.1.1",
1494
+ "matcher": "^3.0.0",
1495
+ "roarr": "^2.15.3",
1496
+ "semver": "^7.3.2",
1497
+ "serialize-error": "^7.0.1"
1498
+ },
1499
+ "engines": {
1500
+ "node": ">=10.0"
1501
+ }
1502
+ },
1503
+ "node_modules/globalthis": {
1504
+ "version": "1.0.4",
1505
+ "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz",
1506
+ "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
1507
+ "license": "MIT",
1508
+ "dependencies": {
1509
+ "define-properties": "^1.2.1",
1510
+ "gopd": "^1.0.1"
1511
+ },
1512
+ "engines": {
1513
+ "node": ">= 0.4"
1514
+ },
1515
+ "funding": {
1516
+ "url": "https://github.com/sponsors/ljharb"
1517
+ }
1518
+ },
1519
+ "node_modules/gopd": {
1520
+ "version": "1.2.0",
1521
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
1522
+ "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
1523
+ "license": "MIT",
1524
+ "engines": {
1525
+ "node": ">= 0.4"
1526
+ },
1527
+ "funding": {
1528
+ "url": "https://github.com/sponsors/ljharb"
1529
+ }
1530
+ },
1531
+ "node_modules/guid-typescript": {
1532
+ "version": "1.0.9",
1533
+ "resolved": "https://registry.npmjs.org/guid-typescript/-/guid-typescript-1.0.9.tgz",
1534
+ "integrity": "sha512-Y8T4vYhEfwJOTbouREvG+3XDsjr8E3kIr7uf+JZ0BYloFsttiHU0WfvANVsR7TxNUJa/WpCnw/Ino/p+DeBhBQ==",
1535
+ "license": "ISC"
1536
+ },
1537
+ "node_modules/has-property-descriptors": {
1538
+ "version": "1.0.2",
1539
+ "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
1540
+ "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
1541
+ "license": "MIT",
1542
+ "dependencies": {
1543
+ "es-define-property": "^1.0.0"
1544
+ },
1545
+ "funding": {
1546
+ "url": "https://github.com/sponsors/ljharb"
1547
+ }
1548
+ },
1549
+ "node_modules/json-stringify-safe": {
1550
+ "version": "5.0.1",
1551
+ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
1552
+ "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==",
1553
+ "license": "ISC"
1554
+ },
1555
+ "node_modules/long": {
1556
+ "version": "5.3.2",
1557
+ "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz",
1558
+ "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==",
1559
+ "license": "Apache-2.0"
1560
+ },
1561
+ "node_modules/matcher": {
1562
+ "version": "3.0.0",
1563
+ "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz",
1564
+ "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==",
1565
+ "license": "MIT",
1566
+ "dependencies": {
1567
+ "escape-string-regexp": "^4.0.0"
1568
+ },
1569
+ "engines": {
1570
+ "node": ">=10"
1571
+ }
1572
+ },
1573
+ "node_modules/minipass": {
1574
+ "version": "7.1.2",
1575
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
1576
+ "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
1577
+ "license": "ISC",
1578
+ "engines": {
1579
+ "node": ">=16 || 14 >=14.17"
1580
+ }
1581
+ },
1582
+ "node_modules/minizlib": {
1583
+ "version": "3.1.0",
1584
+ "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz",
1585
+ "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==",
1586
+ "license": "MIT",
1587
+ "dependencies": {
1588
+ "minipass": "^7.1.2"
1589
+ },
1590
+ "engines": {
1591
+ "node": ">= 18"
1592
+ }
1593
+ },
1594
+ "node_modules/nanoid": {
1595
+ "version": "3.3.11",
1596
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
1597
+ "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
1598
+ "dev": true,
1599
+ "funding": [
1600
+ {
1601
+ "type": "github",
1602
+ "url": "https://github.com/sponsors/ai"
1603
+ }
1604
+ ],
1605
+ "license": "MIT",
1606
+ "bin": {
1607
+ "nanoid": "bin/nanoid.cjs"
1608
+ },
1609
+ "engines": {
1610
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
1611
+ }
1612
+ },
1613
+ "node_modules/object-keys": {
1614
+ "version": "1.1.1",
1615
+ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
1616
+ "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
1617
+ "license": "MIT",
1618
+ "engines": {
1619
+ "node": ">= 0.4"
1620
+ }
1621
+ },
1622
+ "node_modules/onnxruntime-common": {
1623
+ "version": "1.21.0",
1624
+ "resolved": "https://registry.npmjs.org/onnxruntime-common/-/onnxruntime-common-1.21.0.tgz",
1625
+ "integrity": "sha512-Q632iLLrtCAVOTO65dh2+mNbQir/QNTVBG3h/QdZBpns7mZ0RYbLRBgGABPbpU9351AgYy7SJf1WaeVwMrBFPQ==",
1626
+ "license": "MIT"
1627
+ },
1628
+ "node_modules/onnxruntime-node": {
1629
+ "version": "1.21.0",
1630
+ "resolved": "https://registry.npmjs.org/onnxruntime-node/-/onnxruntime-node-1.21.0.tgz",
1631
+ "integrity": "sha512-NeaCX6WW2L8cRCSqy3bInlo5ojjQqu2fD3D+9W5qb5irwxhEyWKXeH2vZ8W9r6VxaMPUan+4/7NDwZMtouZxEw==",
1632
+ "hasInstallScript": true,
1633
+ "license": "MIT",
1634
+ "os": [
1635
+ "win32",
1636
+ "darwin",
1637
+ "linux"
1638
+ ],
1639
+ "dependencies": {
1640
+ "global-agent": "^3.0.0",
1641
+ "onnxruntime-common": "1.21.0",
1642
+ "tar": "^7.0.1"
1643
+ }
1644
+ },
1645
+ "node_modules/onnxruntime-web": {
1646
+ "version": "1.23.2",
1647
+ "resolved": "https://registry.npmjs.org/onnxruntime-web/-/onnxruntime-web-1.23.2.tgz",
1648
+ "integrity": "sha512-T09JUtMn+CZLk3mFwqiH0lgQf+4S7+oYHHtk6uhaYAAJI95bTcKi5bOOZYwORXfS/RLZCjDDEXGWIuOCAFlEjg==",
1649
+ "license": "MIT",
1650
+ "dependencies": {
1651
+ "flatbuffers": "^25.1.24",
1652
+ "guid-typescript": "^1.0.9",
1653
+ "long": "^5.2.3",
1654
+ "onnxruntime-common": "1.23.2",
1655
+ "platform": "^1.3.6",
1656
+ "protobufjs": "^7.2.4"
1657
+ }
1658
+ },
1659
+ "node_modules/onnxruntime-web/node_modules/onnxruntime-common": {
1660
+ "version": "1.23.2",
1661
+ "resolved": "https://registry.npmjs.org/onnxruntime-common/-/onnxruntime-common-1.23.2.tgz",
1662
+ "integrity": "sha512-5LFsC9Dukzp2WV6kNHYLNzp8sT6V02IubLCbzw2Xd6X5GOlr65gAX6xiJwyi2URJol/s71gaQLC5F2C25AAR2w==",
1663
+ "license": "MIT"
1664
+ },
1665
+ "node_modules/picocolors": {
1666
+ "version": "1.1.1",
1667
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
1668
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
1669
+ "dev": true,
1670
+ "license": "ISC"
1671
+ },
1672
+ "node_modules/platform": {
1673
+ "version": "1.3.6",
1674
+ "resolved": "https://registry.npmjs.org/platform/-/platform-1.3.6.tgz",
1675
+ "integrity": "sha512-fnWVljUchTro6RiCFvCXBbNhJc2NijN7oIQxbwsyL0buWJPG85v81ehlHI9fXrJsMNgTofEoWIQeClKpgxFLrg==",
1676
+ "license": "MIT"
1677
+ },
1678
+ "node_modules/postcss": {
1679
+ "version": "8.5.6",
1680
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
1681
+ "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
1682
+ "dev": true,
1683
+ "funding": [
1684
+ {
1685
+ "type": "opencollective",
1686
+ "url": "https://opencollective.com/postcss/"
1687
+ },
1688
+ {
1689
+ "type": "tidelift",
1690
+ "url": "https://tidelift.com/funding/github/npm/postcss"
1691
+ },
1692
+ {
1693
+ "type": "github",
1694
+ "url": "https://github.com/sponsors/ai"
1695
+ }
1696
+ ],
1697
+ "license": "MIT",
1698
+ "dependencies": {
1699
+ "nanoid": "^3.3.11",
1700
+ "picocolors": "^1.1.1",
1701
+ "source-map-js": "^1.2.1"
1702
+ },
1703
+ "engines": {
1704
+ "node": "^10 || ^12 || >=14"
1705
+ }
1706
+ },
1707
+ "node_modules/protobufjs": {
1708
+ "version": "7.5.4",
1709
+ "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.4.tgz",
1710
+ "integrity": "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==",
1711
+ "hasInstallScript": true,
1712
+ "license": "BSD-3-Clause",
1713
+ "dependencies": {
1714
+ "@protobufjs/aspromise": "^1.1.2",
1715
+ "@protobufjs/base64": "^1.1.2",
1716
+ "@protobufjs/codegen": "^2.0.4",
1717
+ "@protobufjs/eventemitter": "^1.1.0",
1718
+ "@protobufjs/fetch": "^1.1.0",
1719
+ "@protobufjs/float": "^1.0.2",
1720
+ "@protobufjs/inquire": "^1.1.0",
1721
+ "@protobufjs/path": "^1.1.2",
1722
+ "@protobufjs/pool": "^1.1.0",
1723
+ "@protobufjs/utf8": "^1.1.0",
1724
+ "@types/node": ">=13.7.0",
1725
+ "long": "^5.0.0"
1726
+ },
1727
+ "engines": {
1728
+ "node": ">=12.0.0"
1729
+ }
1730
+ },
1731
+ "node_modules/roarr": {
1732
+ "version": "2.15.4",
1733
+ "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz",
1734
+ "integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==",
1735
+ "license": "BSD-3-Clause",
1736
+ "dependencies": {
1737
+ "boolean": "^3.0.1",
1738
+ "detect-node": "^2.0.4",
1739
+ "globalthis": "^1.0.1",
1740
+ "json-stringify-safe": "^5.0.1",
1741
+ "semver-compare": "^1.0.0",
1742
+ "sprintf-js": "^1.1.2"
1743
+ },
1744
+ "engines": {
1745
+ "node": ">=8.0"
1746
+ }
1747
+ },
1748
+ "node_modules/rollup": {
1749
+ "version": "4.54.0",
1750
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.54.0.tgz",
1751
+ "integrity": "sha512-3nk8Y3a9Ea8szgKhinMlGMhGMw89mqule3KWczxhIzqudyHdCIOHw8WJlj/r329fACjKLEh13ZSk7oE22kyeIw==",
1752
+ "dev": true,
1753
+ "license": "MIT",
1754
+ "dependencies": {
1755
+ "@types/estree": "1.0.8"
1756
+ },
1757
+ "bin": {
1758
+ "rollup": "dist/bin/rollup"
1759
+ },
1760
+ "engines": {
1761
+ "node": ">=18.0.0",
1762
+ "npm": ">=8.0.0"
1763
+ },
1764
+ "optionalDependencies": {
1765
+ "@rollup/rollup-android-arm-eabi": "4.54.0",
1766
+ "@rollup/rollup-android-arm64": "4.54.0",
1767
+ "@rollup/rollup-darwin-arm64": "4.54.0",
1768
+ "@rollup/rollup-darwin-x64": "4.54.0",
1769
+ "@rollup/rollup-freebsd-arm64": "4.54.0",
1770
+ "@rollup/rollup-freebsd-x64": "4.54.0",
1771
+ "@rollup/rollup-linux-arm-gnueabihf": "4.54.0",
1772
+ "@rollup/rollup-linux-arm-musleabihf": "4.54.0",
1773
+ "@rollup/rollup-linux-arm64-gnu": "4.54.0",
1774
+ "@rollup/rollup-linux-arm64-musl": "4.54.0",
1775
+ "@rollup/rollup-linux-loong64-gnu": "4.54.0",
1776
+ "@rollup/rollup-linux-ppc64-gnu": "4.54.0",
1777
+ "@rollup/rollup-linux-riscv64-gnu": "4.54.0",
1778
+ "@rollup/rollup-linux-riscv64-musl": "4.54.0",
1779
+ "@rollup/rollup-linux-s390x-gnu": "4.54.0",
1780
+ "@rollup/rollup-linux-x64-gnu": "4.54.0",
1781
+ "@rollup/rollup-linux-x64-musl": "4.54.0",
1782
+ "@rollup/rollup-openharmony-arm64": "4.54.0",
1783
+ "@rollup/rollup-win32-arm64-msvc": "4.54.0",
1784
+ "@rollup/rollup-win32-ia32-msvc": "4.54.0",
1785
+ "@rollup/rollup-win32-x64-gnu": "4.54.0",
1786
+ "@rollup/rollup-win32-x64-msvc": "4.54.0",
1787
+ "fsevents": "~2.3.2"
1788
+ }
1789
+ },
1790
+ "node_modules/semver": {
1791
+ "version": "7.7.3",
1792
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz",
1793
+ "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==",
1794
+ "license": "ISC",
1795
+ "bin": {
1796
+ "semver": "bin/semver.js"
1797
+ },
1798
+ "engines": {
1799
+ "node": ">=10"
1800
+ }
1801
+ },
1802
+ "node_modules/semver-compare": {
1803
+ "version": "1.0.0",
1804
+ "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz",
1805
+ "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==",
1806
+ "license": "MIT"
1807
+ },
1808
+ "node_modules/serialize-error": {
1809
+ "version": "7.0.1",
1810
+ "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz",
1811
+ "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==",
1812
+ "license": "MIT",
1813
+ "dependencies": {
1814
+ "type-fest": "^0.13.1"
1815
+ },
1816
+ "engines": {
1817
+ "node": ">=10"
1818
+ },
1819
+ "funding": {
1820
+ "url": "https://github.com/sponsors/sindresorhus"
1821
+ }
1822
+ },
1823
+ "node_modules/sharp": {
1824
+ "version": "0.34.5",
1825
+ "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz",
1826
+ "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==",
1827
+ "hasInstallScript": true,
1828
+ "license": "Apache-2.0",
1829
+ "dependencies": {
1830
+ "@img/colour": "^1.0.0",
1831
+ "detect-libc": "^2.1.2",
1832
+ "semver": "^7.7.3"
1833
+ },
1834
+ "engines": {
1835
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
1836
+ },
1837
+ "funding": {
1838
+ "url": "https://opencollective.com/libvips"
1839
+ },
1840
+ "optionalDependencies": {
1841
+ "@img/sharp-darwin-arm64": "0.34.5",
1842
+ "@img/sharp-darwin-x64": "0.34.5",
1843
+ "@img/sharp-libvips-darwin-arm64": "1.2.4",
1844
+ "@img/sharp-libvips-darwin-x64": "1.2.4",
1845
+ "@img/sharp-libvips-linux-arm": "1.2.4",
1846
+ "@img/sharp-libvips-linux-arm64": "1.2.4",
1847
+ "@img/sharp-libvips-linux-ppc64": "1.2.4",
1848
+ "@img/sharp-libvips-linux-riscv64": "1.2.4",
1849
+ "@img/sharp-libvips-linux-s390x": "1.2.4",
1850
+ "@img/sharp-libvips-linux-x64": "1.2.4",
1851
+ "@img/sharp-libvips-linuxmusl-arm64": "1.2.4",
1852
+ "@img/sharp-libvips-linuxmusl-x64": "1.2.4",
1853
+ "@img/sharp-linux-arm": "0.34.5",
1854
+ "@img/sharp-linux-arm64": "0.34.5",
1855
+ "@img/sharp-linux-ppc64": "0.34.5",
1856
+ "@img/sharp-linux-riscv64": "0.34.5",
1857
+ "@img/sharp-linux-s390x": "0.34.5",
1858
+ "@img/sharp-linux-x64": "0.34.5",
1859
+ "@img/sharp-linuxmusl-arm64": "0.34.5",
1860
+ "@img/sharp-linuxmusl-x64": "0.34.5",
1861
+ "@img/sharp-wasm32": "0.34.5",
1862
+ "@img/sharp-win32-arm64": "0.34.5",
1863
+ "@img/sharp-win32-ia32": "0.34.5",
1864
+ "@img/sharp-win32-x64": "0.34.5"
1865
+ }
1866
+ },
1867
+ "node_modules/source-map-js": {
1868
+ "version": "1.2.1",
1869
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
1870
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
1871
+ "dev": true,
1872
+ "license": "BSD-3-Clause",
1873
+ "engines": {
1874
+ "node": ">=0.10.0"
1875
+ }
1876
+ },
1877
+ "node_modules/sprintf-js": {
1878
+ "version": "1.1.3",
1879
+ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
1880
+ "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==",
1881
+ "license": "BSD-3-Clause"
1882
+ },
1883
+ "node_modules/tar": {
1884
+ "version": "7.5.2",
1885
+ "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.2.tgz",
1886
+ "integrity": "sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg==",
1887
+ "license": "BlueOak-1.0.0",
1888
+ "dependencies": {
1889
+ "@isaacs/fs-minipass": "^4.0.0",
1890
+ "chownr": "^3.0.0",
1891
+ "minipass": "^7.1.2",
1892
+ "minizlib": "^3.1.0",
1893
+ "yallist": "^5.0.0"
1894
+ },
1895
+ "engines": {
1896
+ "node": ">=18"
1897
+ }
1898
+ },
1899
+ "node_modules/tslib": {
1900
+ "version": "2.8.1",
1901
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
1902
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
1903
+ "license": "0BSD",
1904
+ "optional": true
1905
+ },
1906
+ "node_modules/type-fest": {
1907
+ "version": "0.13.1",
1908
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz",
1909
+ "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==",
1910
+ "license": "(MIT OR CC0-1.0)",
1911
+ "engines": {
1912
+ "node": ">=10"
1913
+ },
1914
+ "funding": {
1915
+ "url": "https://github.com/sponsors/sindresorhus"
1916
+ }
1917
+ },
1918
+ "node_modules/undici-types": {
1919
+ "version": "7.16.0",
1920
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
1921
+ "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==",
1922
+ "license": "MIT"
1923
+ },
1924
+ "node_modules/vite": {
1925
+ "version": "5.4.21",
1926
+ "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz",
1927
+ "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==",
1928
+ "dev": true,
1929
+ "license": "MIT",
1930
+ "dependencies": {
1931
+ "esbuild": "^0.21.3",
1932
+ "postcss": "^8.4.43",
1933
+ "rollup": "^4.20.0"
1934
+ },
1935
+ "bin": {
1936
+ "vite": "bin/vite.js"
1937
+ },
1938
+ "engines": {
1939
+ "node": "^18.0.0 || >=20.0.0"
1940
+ },
1941
+ "funding": {
1942
+ "url": "https://github.com/vitejs/vite?sponsor=1"
1943
+ },
1944
+ "optionalDependencies": {
1945
+ "fsevents": "~2.3.3"
1946
+ },
1947
+ "peerDependencies": {
1948
+ "@types/node": "^18.0.0 || >=20.0.0",
1949
+ "less": "*",
1950
+ "lightningcss": "^1.21.0",
1951
+ "sass": "*",
1952
+ "sass-embedded": "*",
1953
+ "stylus": "*",
1954
+ "sugarss": "*",
1955
+ "terser": "^5.4.0"
1956
+ },
1957
+ "peerDependenciesMeta": {
1958
+ "@types/node": {
1959
+ "optional": true
1960
+ },
1961
+ "less": {
1962
+ "optional": true
1963
+ },
1964
+ "lightningcss": {
1965
+ "optional": true
1966
+ },
1967
+ "sass": {
1968
+ "optional": true
1969
+ },
1970
+ "sass-embedded": {
1971
+ "optional": true
1972
+ },
1973
+ "stylus": {
1974
+ "optional": true
1975
+ },
1976
+ "sugarss": {
1977
+ "optional": true
1978
+ },
1979
+ "terser": {
1980
+ "optional": true
1981
+ }
1982
+ }
1983
+ },
1984
+ "node_modules/yallist": {
1985
+ "version": "5.0.0",
1986
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
1987
+ "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==",
1988
+ "license": "BlueOak-1.0.0",
1989
+ "engines": {
1990
+ "node": ">=18"
1991
+ }
1992
+ }
1993
+ }
1994
+ }
package.json ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "name": "lfm25-vl-webgpu",
3
+ "version": "1.0.0",
4
+ "description": "LFM2.5-VL Vision-Language Demo with WebGPU",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "vite build",
9
+ "preview": "vite preview"
10
+ },
11
+ "dependencies": {
12
+ "@huggingface/transformers": "^3.7.1",
13
+ "onnxruntime-web": "^1.23.2"
14
+ },
15
+ "devDependencies": {
16
+ "vite": "^5.4.0"
17
+ }
18
+ }
styles.css ADDED
@@ -0,0 +1,1103 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Brand color system for VLM Demo */
2
+
3
+ :root {
4
+ /* Base brand colors */
5
+ --white: rgb(255, 255, 255);
6
+ --black: rgb(0, 0, 0);
7
+ --light-purple: rgb(205, 130, 240);
8
+ --purple: rgb(85, 5, 75);
9
+ --orange: rgb(255, 95, 30);
10
+
11
+ /* Alpha variations */
12
+ --white-70: rgba(255, 255, 255, 0.7);
13
+ --white-50: rgba(255, 255, 255, 0.5);
14
+ --white-30: rgba(255, 255, 255, 0.3);
15
+ --white-10: rgba(255, 255, 255, 0.1);
16
+
17
+ --black-70: rgba(0, 0, 0, 0.7);
18
+ --black-50: rgba(0, 0, 0, 0.5);
19
+ --black-30: rgba(0, 0, 0, 0.3);
20
+ --black-10: rgba(0, 0, 0, 0.1);
21
+
22
+ --light-purple-70: rgba(205, 130, 240, 0.7);
23
+ --light-purple-50: rgba(205, 130, 240, 0.5);
24
+ --light-purple-30: rgba(205, 130, 240, 0.3);
25
+ --light-purple-10: rgba(205, 130, 240, 0.1);
26
+
27
+ --purple-70: rgba(85, 5, 75, 0.7);
28
+ --purple-50: rgba(85, 5, 75, 0.5);
29
+ --purple-30: rgba(85, 5, 75, 0.3);
30
+ --purple-10: rgba(85, 5, 75, 0.1);
31
+
32
+ --orange-70: rgba(255, 95, 30, 0.7);
33
+ --orange-50: rgba(255, 95, 30, 0.5);
34
+ --orange-30: rgba(255, 95, 30, 0.3);
35
+ --orange-10: rgba(255, 95, 30, 0.1);
36
+
37
+ /* Border style controls - change these to customize all dividers */
38
+ --border-style: solid; /* Options: solid, dashed, dotted */
39
+ /* --border-width: 1px; */
40
+ --border-width: 2px;
41
+
42
+ --dash-length: 5px; /* Only applies when border-style is dashed */
43
+
44
+ /* Semantic color assignments */
45
+ --bg-primary: var(--black);
46
+ --bg-secondary: var(--black-70);
47
+ --bg-tertiary: var(--black-50);
48
+ --text-primary: var(--white);
49
+ --text-secondary: var(--white-70);
50
+ /* --border-color: var(--white-30); */
51
+ --border-color: var(--light-purple-30);
52
+ --accent-primary: var(--purple);
53
+ --accent-secondary: var(--light-purple);
54
+ --accent-hover: var(--light-purple);
55
+ --message-user-bg: var(--purple);
56
+ --message-assistant-bg: var(--black-70);
57
+ --input-bg: var(--black-30);
58
+ --input-border: var(--light-purple-30);
59
+ --input-focus: var(--light-purple);
60
+ }
61
+
62
+ * {
63
+ box-sizing: border-box;
64
+ margin: 0;
65
+ padding: 0;
66
+ }
67
+
68
+ body {
69
+ font-family: 'Söhne', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
70
+ background-color: var(--bg-primary);
71
+ color: var(--text-primary);
72
+ padding: 0;
73
+ margin: 0;
74
+ min-height: 100vh;
75
+ }
76
+
77
+ .app-layout {
78
+ display: flex;
79
+ flex-direction: column;
80
+ height: 100vh;
81
+ overflow: hidden;
82
+ }
83
+
84
+ /* Top Navigation Bar */
85
+ .top-nav {
86
+ position: relative;
87
+ display: flex;
88
+ align-items: center;
89
+ justify-content: space-between;
90
+ background-color: var(--bg-secondary);
91
+ border-bottom: var(--border-width) var(--border-style) var(--border-color);
92
+ padding: 24px 24px;
93
+ }
94
+
95
+ .nav-left {
96
+ display: flex;
97
+ align-items: baseline;
98
+ gap: 12px;
99
+ z-index: 1;
100
+ }
101
+
102
+ .nav-center {
103
+ position: absolute;
104
+ left: 50%;
105
+ transform: translateX(-50%);
106
+ display: flex;
107
+ flex-direction: column;
108
+ align-items: center;
109
+ gap: 2px;
110
+ }
111
+
112
+ .nav-title {
113
+ font-size: 22px;
114
+ font-weight: 600;
115
+ color: var(--text-primary);
116
+ }
117
+
118
+ .nav-subtitle {
119
+ font-size: 16px;
120
+ color: var(--text-secondary);
121
+ text-align: center;
122
+ }
123
+
124
+ .nav-logo-img {
125
+ height: 24px;
126
+ width: auto;
127
+ }
128
+
129
+ .nav-logo-link {
130
+ font-size: 28px;
131
+ font-weight: 600;
132
+ color: var(--text-primary);
133
+ text-decoration: none;
134
+ transition: color 0.2s ease;
135
+ display: inline-block;
136
+ line-height: 1;
137
+ }
138
+
139
+ .nav-logo-link:hover {
140
+ color: var(--light-purple);
141
+ }
142
+
143
+ .model-status {
144
+ font-size: 18px;
145
+ font-weight: 500;
146
+ color: var(--text-secondary);
147
+ }
148
+
149
+ .loading-progress {
150
+ width: 100%;
151
+ max-width: 300px;
152
+ margin: 8px 0;
153
+ }
154
+
155
+ .progress-bar {
156
+ width: 100%;
157
+ height: 6px;
158
+ background: var(--white-10);
159
+ border-radius: 3px;
160
+ overflow: hidden;
161
+ }
162
+
163
+ .progress-fill {
164
+ height: 100%;
165
+ background: linear-gradient(90deg, var(--light-purple), var(--orange));
166
+ border-radius: 3px;
167
+ transition: width 0.3s ease;
168
+ }
169
+
170
+ .progress-text {
171
+ font-size: 12px;
172
+ color: var(--text-secondary);
173
+ margin-top: 4px;
174
+ text-align: center;
175
+ }
176
+
177
+ .model-input-wrapper {
178
+ display: flex;
179
+ align-items: center;
180
+ gap: 8px;
181
+ width: 100%;
182
+ }
183
+
184
+ .model-input {
185
+ flex: 1;
186
+ padding: 6px 12px;
187
+ background-color: var(--input-bg);
188
+ border: 1px solid var(--input-border);
189
+ border-radius: 6px;
190
+ font-size: 13px;
191
+ color: var(--text-primary);
192
+ font-family: inherit;
193
+ min-width: 0;
194
+ }
195
+
196
+ select.model-input {
197
+ cursor: pointer;
198
+ appearance: none;
199
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23888' d='M6 8L2 4h8z'/%3E%3C/svg%3E");
200
+ background-repeat: no-repeat;
201
+ background-position: right 10px center;
202
+ padding-right: 30px;
203
+ }
204
+
205
+ select.model-input option {
206
+ background-color: var(--bg-primary);
207
+ color: var(--text-primary);
208
+ }
209
+
210
+ .model-input:focus {
211
+ outline: none;
212
+ border-color: var(--input-focus);
213
+ box-shadow: 0 0 0 3px var(--light-purple-10);
214
+ }
215
+
216
+ .model-input:disabled {
217
+ opacity: 0.6;
218
+ cursor: not-allowed;
219
+ }
220
+
221
+ .cache-info {
222
+ font-size: 12px;
223
+ color: var(--text-secondary);
224
+ white-space: nowrap;
225
+ }
226
+
227
+ .container {
228
+ flex: 1;
229
+ background-color: var(--bg-primary);
230
+ display: flex;
231
+ flex-direction: column;
232
+ overflow: hidden;
233
+ min-height: 0;
234
+ }
235
+
236
+ .mode-container {
237
+ display: none;
238
+ flex-direction: column;
239
+ height: 100%;
240
+ overflow: hidden;
241
+ }
242
+
243
+ .mode-container.active {
244
+ display: flex;
245
+ }
246
+
247
+ /* Live Caption Mode Styles */
248
+ #live-caption-mode.active {
249
+ display: flex;
250
+ flex-direction: column;
251
+ width: 100%;
252
+ height: 100%;
253
+ padding: 32px;
254
+ gap: 24px;
255
+ background-color: var(--bg-primary);
256
+ }
257
+
258
+ .live-caption-content {
259
+ flex: 1;
260
+ display: flex;
261
+ gap: 24px;
262
+ min-height: 0;
263
+ }
264
+
265
+ .live-caption-video-section {
266
+ flex: 2;
267
+ display: flex;
268
+ flex-direction: column;
269
+ justify-content: space-between;
270
+ gap: 16px;
271
+ min-width: 0;
272
+ }
273
+
274
+ /* Safari: aspect-ratio on container causes incorrect width calculation */
275
+ .is-safari .live-caption-video-container {
276
+ aspect-ratio: auto;
277
+ width: 100%;
278
+ }
279
+
280
+
281
+ .live-caption-video-container {
282
+ position: relative;
283
+ aspect-ratio: 1;
284
+ height: 100%;
285
+ max-height: calc(100vh - 220px);
286
+ border: 2px solid var(--light-purple-30);
287
+ border-radius: 12px;
288
+ background-color: var(--black-50);
289
+ overflow: hidden;
290
+ display: flex;
291
+ align-items: center;
292
+ justify-content: center;
293
+ }
294
+
295
+ #live-caption-video {
296
+ width: 100%;
297
+ height: 100%;
298
+ object-fit: contain;
299
+ background-color: var(--black);
300
+ transform: scaleX(-1); /* Mirror the video horizontally */
301
+ }
302
+
303
+ /* Capture Overlay (on video) */
304
+ .capture-overlay {
305
+ position: absolute;
306
+ top: 12px;
307
+ right: 12px;
308
+ display: flex;
309
+ flex-direction: column;
310
+ align-items: flex-end;
311
+ gap: 8px;
312
+ padding: 10px 12px;
313
+ background: rgba(0, 0, 0, 0.6);
314
+ backdrop-filter: blur(8px);
315
+ border-radius: 8px;
316
+ z-index: 10;
317
+ min-width: 100px;
318
+ }
319
+
320
+ .capture-overlay .control-btn {
321
+ padding: 8px 16px;
322
+ font-size: 14px;
323
+ width: 100%;
324
+ }
325
+
326
+ .capture-overlay .control-select {
327
+ padding: 6px 10px;
328
+ padding-right: 24px;
329
+ font-size: 14px;
330
+ background-position: right 6px center;
331
+ }
332
+
333
+ .overlay-field {
334
+ display: flex;
335
+ align-items: center;
336
+ gap: 8px;
337
+ }
338
+
339
+ .overlay-label {
340
+ font-size: 14px;
341
+ color: var(--white-70);
342
+ white-space: nowrap;
343
+ }
344
+
345
+ .capture-status {
346
+ display: flex;
347
+ align-items: center;
348
+ justify-content: center;
349
+ gap: 6px;
350
+ }
351
+
352
+ .capture-overlay .status-text {
353
+ font-size: 14px;
354
+ color: var(--white-70);
355
+ }
356
+
357
+ /* Controls Bar */
358
+ .controls-bar {
359
+ display: flex;
360
+ flex-direction: column;
361
+ gap: 10px;
362
+ padding: 12px 16px;
363
+ background-color: var(--black-50);
364
+ border: 1px solid var(--light-purple-30);
365
+ border-radius: 12px;
366
+ }
367
+
368
+ .controls-row {
369
+ display: flex;
370
+ align-items: center;
371
+ justify-content: space-between;
372
+ gap: 16px;
373
+ flex-wrap: wrap;
374
+ }
375
+
376
+ .controls-row.status-row {
377
+ gap: 12px;
378
+ }
379
+
380
+ .control-group {
381
+ display: flex;
382
+ align-items: center;
383
+ gap: 8px;
384
+ }
385
+
386
+ .control-label {
387
+ font-size: 13px;
388
+ color: var(--text-secondary);
389
+ white-space: nowrap;
390
+ }
391
+
392
+ .control-btn {
393
+ padding: 8px 16px;
394
+ background-color: var(--light-purple-30);
395
+ border: 1px solid var(--light-purple-50);
396
+ border-radius: 6px;
397
+ color: var(--text-primary);
398
+ font-size: 13px;
399
+ font-weight: 500;
400
+ cursor: pointer;
401
+ transition: all 0.2s ease;
402
+ white-space: nowrap;
403
+ }
404
+
405
+ .control-btn:hover:not(:disabled) {
406
+ background-color: var(--light-purple-50);
407
+ border-color: var(--light-purple);
408
+ }
409
+
410
+ .control-btn:disabled {
411
+ opacity: 0.5;
412
+ cursor: not-allowed;
413
+ }
414
+
415
+ .control-btn.primary {
416
+ background: linear-gradient(135deg, var(--purple) 0%, var(--light-purple) 100%);
417
+ border: none;
418
+ color: white;
419
+ padding: 8px 20px;
420
+ }
421
+
422
+ .control-btn.primary:hover:not(:disabled) {
423
+ transform: translateY(-1px);
424
+ box-shadow: 0 4px 12px var(--purple-50);
425
+ }
426
+
427
+ .control-btn.primary.stop {
428
+ background: linear-gradient(135deg, var(--orange) 0%, var(--orange-70) 100%);
429
+ }
430
+
431
+ .control-btn.small {
432
+ padding: 6px 12px;
433
+ font-size: 12px;
434
+ }
435
+
436
+ .control-select {
437
+ padding: 8px 12px;
438
+ padding-right: 28px;
439
+ background-color: var(--input-bg);
440
+ border: 1px solid var(--input-border);
441
+ border-radius: 6px;
442
+ color: var(--text-primary);
443
+ font-size: 13px;
444
+ cursor: pointer;
445
+ appearance: none;
446
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%23888' d='M6 8L2 4h8z'/%3E%3C/svg%3E");
447
+ background-repeat: no-repeat;
448
+ background-position: right 8px center;
449
+ }
450
+
451
+ .control-select:focus {
452
+ outline: none;
453
+ border-color: var(--input-focus);
454
+ }
455
+
456
+ .control-select option {
457
+ background-color: var(--bg-primary);
458
+ color: var(--text-primary);
459
+ }
460
+
461
+ .control-select.model-select {
462
+ min-width: 140px;
463
+ }
464
+
465
+ .status-text {
466
+ font-size: 13px;
467
+ color: var(--text-secondary);
468
+ min-width: 40px;
469
+ }
470
+
471
+ /* Progress Bar (inline in status row) */
472
+ .progress-bar-row {
473
+ flex: 1;
474
+ max-width: 200px;
475
+ height: 4px;
476
+ background: var(--white-10);
477
+ border-radius: 2px;
478
+ overflow: hidden;
479
+ }
480
+
481
+ .progress-bar-row .progress-fill {
482
+ height: 100%;
483
+ background: linear-gradient(90deg, var(--light-purple), var(--orange));
484
+ border-radius: 2px;
485
+ transition: width 0.3s ease;
486
+ }
487
+
488
+ /* Indeterminate progress animation for large downloads */
489
+ .progress-bar-row.indeterminate .progress-fill {
490
+ width: 30% !important;
491
+ animation: indeterminate 1.5s ease-in-out infinite;
492
+ }
493
+
494
+ @keyframes indeterminate {
495
+ 0% { transform: translateX(-100%); }
496
+ 100% { transform: translateX(400%); }
497
+ }
498
+
499
+ .status-indicator {
500
+ width: 10px;
501
+ height: 10px;
502
+ border-radius: 50%;
503
+ background-color: var(--text-secondary);
504
+ }
505
+
506
+ .status-indicator.active {
507
+ background-color: var(--light-purple);
508
+ box-shadow: 0 0 8px var(--light-purple);
509
+ animation: pulse 2s infinite;
510
+ }
511
+
512
+ @keyframes pulse {
513
+ 0%, 100% {
514
+ opacity: 1;
515
+ }
516
+ 50% {
517
+ opacity: 0.5;
518
+ }
519
+ }
520
+
521
+ .live-caption-text-section {
522
+ flex: 1;
523
+ display: flex;
524
+ flex-direction: column;
525
+ gap: 16px;
526
+ min-width: 0;
527
+ padding: 20px;
528
+ background-color: var(--black-50);
529
+ border: 1px solid var(--light-purple-30);
530
+ border-radius: 12px;
531
+ }
532
+
533
+ .caption-section-title {
534
+ font-size: 22px;
535
+ font-weight: 600;
536
+ color: var(--text-primary);
537
+ padding-bottom: 12px;
538
+ border-bottom: 1px solid var(--light-purple-30);
539
+ }
540
+
541
+ .latest-caption {
542
+ font-size: 20px;
543
+ font-weight: 500;
544
+ color: var(--white);
545
+ line-height: 1.4;
546
+ padding: 12px;
547
+ background-color: var(--black-30);
548
+ border-radius: 8px;
549
+ border-left: 3px solid var(--light-purple);
550
+ }
551
+
552
+ .caption-history {
553
+ flex: 1;
554
+ display: flex;
555
+ flex-direction: column;
556
+ gap: 8px;
557
+ overflow-y: auto;
558
+ }
559
+
560
+ .caption-history-item {
561
+ display: flex;
562
+ gap: 12px;
563
+ padding: 12px 16px;
564
+ background-color: var(--black-30);
565
+ border-radius: 8px;
566
+ border: 1px solid var(--light-purple-30);
567
+ border-left: 3px solid transparent;
568
+ transition: opacity 0.3s ease, border-color 0.3s ease;
569
+ }
570
+
571
+ .caption-history-item.latest {
572
+ border-left-color: var(--light-purple);
573
+ background-color: var(--black-50);
574
+ }
575
+
576
+ .caption-timestamp {
577
+ font-size: 11px;
578
+ color: var(--text-secondary);
579
+ flex-shrink: 0;
580
+ font-family: 'JetBrains Mono', monospace;
581
+ opacity: 0.7;
582
+ }
583
+
584
+ .caption-text {
585
+ font-size: 14px;
586
+ color: var(--text-primary);
587
+ line-height: 1.4;
588
+ }
589
+
590
+ /* Responsive Design */
591
+ @media (max-width: 1024px) {
592
+ .live-caption-content {
593
+ flex-direction: column;
594
+ }
595
+
596
+ .live-caption-video-section,
597
+ .live-caption-text-section {
598
+ flex: none;
599
+ width: 100%;
600
+ }
601
+
602
+ .live-caption-text-section {
603
+ max-height: 300px;
604
+ }
605
+ }
606
+
607
+ @media (max-width: 768px) {
608
+ .top-nav {
609
+ flex-direction: column;
610
+ align-items: flex-start;
611
+ gap: 16px;
612
+ padding: 12px 16px;
613
+ }
614
+
615
+ .nav-left,
616
+ .nav-center {
617
+ width: 100%;
618
+ }
619
+
620
+ .nav-center {
621
+ position: static;
622
+ transform: none;
623
+ align-items: flex-start;
624
+ }
625
+
626
+ .nav-subtitle {
627
+ text-align: left;
628
+ font-size: 14px;
629
+ }
630
+
631
+ .model-status {
632
+ max-width: 100%;
633
+ }
634
+
635
+ .model-input-wrapper {
636
+ width: 100%;
637
+ }
638
+
639
+ #live-caption-mode.active {
640
+ padding: 16px;
641
+ gap: 16px;
642
+ }
643
+
644
+ .live-caption-video-container {
645
+ min-height: 200px;
646
+ }
647
+
648
+ .live-caption-text-section {
649
+ padding: 16px;
650
+ }
651
+
652
+ .latest-caption {
653
+ font-size: 20px;
654
+ padding: 12px;
655
+ }
656
+
657
+ /* Controls bar mobile layout */
658
+ .controls-bar {
659
+ padding: 12px;
660
+ }
661
+
662
+ .controls-row {
663
+ flex-direction: column;
664
+ align-items: stretch;
665
+ gap: 12px;
666
+ }
667
+
668
+ .control-group {
669
+ flex-wrap: wrap;
670
+ width: 100%;
671
+ }
672
+
673
+ .control-group.model-group {
674
+ flex-direction: column;
675
+ align-items: stretch;
676
+ gap: 10px;
677
+ }
678
+
679
+ .control-group.model-group .control-label {
680
+ margin-bottom: 4px;
681
+ }
682
+
683
+ .control-group.model-group .control-select {
684
+ width: 100%;
685
+ min-width: auto;
686
+ }
687
+
688
+ .control-group.model-group .control-btn {
689
+ width: 100%;
690
+ padding: 12px 16px;
691
+ }
692
+
693
+ .control-group.cache-group {
694
+ flex-direction: row;
695
+ justify-content: space-between;
696
+ align-items: center;
697
+ }
698
+
699
+ /* Allow scrolling on mobile */
700
+ .app-layout {
701
+ overflow-y: auto;
702
+ overflow-x: hidden;
703
+ }
704
+
705
+ .container {
706
+ overflow-y: auto;
707
+ overflow-x: hidden;
708
+ }
709
+
710
+ #live-caption-mode.active {
711
+ overflow-y: auto;
712
+ min-height: auto;
713
+ height: auto;
714
+ }
715
+
716
+ .live-caption-content {
717
+ min-height: auto;
718
+ }
719
+
720
+ .live-caption-video-section {
721
+ flex-shrink: 0;
722
+ }
723
+ }
724
+
725
+
726
+ /* Smooth transitions */
727
+ .mode-container {
728
+ transition: opacity 0.2s ease;
729
+ }
730
+
731
+ /* Scrollbar styling for webkit browsers */
732
+ .caption-history::-webkit-scrollbar {
733
+ width: 6px;
734
+ }
735
+
736
+ .caption-history::-webkit-scrollbar-track {
737
+ background: var(--black-30);
738
+ }
739
+
740
+ .caption-history::-webkit-scrollbar-thumb {
741
+ background: var(--light-purple-50);
742
+ border-radius: 3px;
743
+ }
744
+
745
+ .caption-history::-webkit-scrollbar-thumb:hover {
746
+ background: var(--light-purple);
747
+ }
748
+
749
+ /* Loading states */
750
+ @keyframes shimmer {
751
+ 0% {
752
+ background-position: -1000px 0;
753
+ }
754
+ 100% {
755
+ background-position: 1000px 0;
756
+ }
757
+ }
758
+
759
+ .loading {
760
+ background: linear-gradient(
761
+ 90deg,
762
+ var(--bg-tertiary) 0%,
763
+ var(--bg-secondary) 50%,
764
+ var(--bg-tertiary) 100%
765
+ );
766
+ background-size: 1000px 100%;
767
+ animation: shimmer 2s infinite;
768
+ }
769
+
770
+ /* Focus visible for accessibility */
771
+ button:focus-visible,
772
+ input:focus-visible {
773
+ outline: 2px solid var(--light-purple);
774
+ outline-offset: 2px;
775
+ }
776
+
777
+ /* Ensure proper text rendering */
778
+ body {
779
+ -webkit-font-smoothing: antialiased;
780
+ -moz-osx-font-smoothing: grayscale;
781
+ text-rendering: optimizeLegibility;
782
+ }
783
+
784
+
785
+ /* High contrast improvements */
786
+ @media (prefers-contrast: high) {
787
+ button:not(:disabled) {
788
+ border: 2px solid var(--light-purple);
789
+ }
790
+ }
791
+
792
+ /* ===================================
793
+ LOADING SCREEN / WELCOME PAGE
794
+ =================================== */
795
+
796
+ .loading-screen {
797
+ position: fixed;
798
+ top: 0;
799
+ left: 0;
800
+ width: 100%;
801
+ height: 100%;
802
+ background-color: var(--black);
803
+ z-index: 10000;
804
+ display: flex;
805
+ align-items: center;
806
+ justify-content: center;
807
+ overflow-y: auto;
808
+ overflow-x: hidden;
809
+ }
810
+
811
+ .loading-screen.hidden {
812
+ display: none;
813
+ }
814
+
815
+ .loading-canvas {
816
+ position: absolute;
817
+ top: 0;
818
+ left: 0;
819
+ width: 100%;
820
+ height: 100%;
821
+ z-index: 1;
822
+ }
823
+
824
+ .loading-vignette {
825
+ position: absolute;
826
+ top: 0;
827
+ left: 0;
828
+ width: 100%;
829
+ height: 100%;
830
+ background: radial-gradient(ellipse at center, transparent 0%, rgba(0, 0, 0, 0.7) 100%);
831
+ z-index: 2;
832
+ }
833
+
834
+ .loading-content {
835
+ position: relative;
836
+ z-index: 3;
837
+ display: flex;
838
+ flex-direction: column;
839
+ align-items: center;
840
+ justify-content: center;
841
+ padding: 2rem;
842
+ max-width: 800px;
843
+ width: 100%;
844
+ text-align: center;
845
+ color: var(--white);
846
+ margin: auto;
847
+ }
848
+
849
+ .loading-header {
850
+ margin-bottom: 2rem;
851
+ }
852
+
853
+ .loading-logo {
854
+ height: 60px;
855
+ width: auto;
856
+ margin-bottom: 1rem;
857
+ }
858
+
859
+ .loading-title-section {
860
+ margin-bottom: 2rem;
861
+ }
862
+
863
+ .loading-title {
864
+ font-size: 2.5rem;
865
+ font-weight: 700;
866
+ color: var(--white);
867
+ margin: 0 0 0.5rem 0;
868
+ text-shadow: 0 2px 8px rgba(0, 0, 0, 0.5);
869
+ }
870
+
871
+ .loading-subtitle {
872
+ font-size: 1.25rem;
873
+ color: var(--white-70);
874
+ margin: 0;
875
+ font-weight: 400;
876
+ }
877
+
878
+ .loading-description {
879
+ margin-bottom: 3rem;
880
+ max-width: 600px;
881
+ }
882
+
883
+ .loading-description p {
884
+ font-size: 1rem;
885
+ color: var(--white-70);
886
+ line-height: 1.6;
887
+ margin: 0 0 1rem 0;
888
+ }
889
+
890
+ .loading-description p:last-child {
891
+ margin-bottom: 0;
892
+ }
893
+
894
+ .loading-action-section {
895
+ margin-bottom: 2rem;
896
+ }
897
+
898
+ .loading-explore-button {
899
+ padding: 16px 48px;
900
+ background: linear-gradient(135deg, var(--purple) 0%, var(--light-purple) 100%);
901
+ color: var(--white);
902
+ border: none;
903
+ border-radius: 12px;
904
+ font-size: 1.125rem;
905
+ font-weight: 600;
906
+ cursor: pointer;
907
+ transition: all 0.3s ease;
908
+ box-shadow: 0 4px 16px var(--purple-50);
909
+ display: inline-flex;
910
+ align-items: center;
911
+ gap: 12px;
912
+ min-width: 200px;
913
+ justify-content: center;
914
+ }
915
+
916
+ .loading-explore-button:hover:not(:disabled) {
917
+ transform: translateY(-2px);
918
+ box-shadow: 0 6px 24px var(--purple-70);
919
+ background: linear-gradient(135deg, var(--light-purple) 0%, var(--purple) 100%);
920
+ }
921
+
922
+ .loading-explore-button:active:not(:disabled) {
923
+ transform: translateY(0);
924
+ }
925
+
926
+ .loading-explore-button:disabled {
927
+ opacity: 0.7;
928
+ cursor: not-allowed;
929
+ }
930
+
931
+ .loading-spinner {
932
+ display: inline-block;
933
+ width: 20px;
934
+ height: 20px;
935
+ border: 3px solid var(--white-30);
936
+ border-top-color: var(--white);
937
+ border-radius: 50%;
938
+ animation: spin 0.8s linear infinite;
939
+ }
940
+
941
+ @keyframes spin {
942
+ to {
943
+ transform: rotate(360deg);
944
+ }
945
+ }
946
+
947
+ .loading-progress-text {
948
+ font-size: 0.875rem;
949
+ color: var(--white-70);
950
+ font-weight: 500;
951
+ }
952
+
953
+ .loading-error {
954
+ margin-top: 2rem;
955
+ padding: 1.5rem;
956
+ background-color: var(--black-70);
957
+ border: 1px solid var(--orange-50);
958
+ border-radius: 8px;
959
+ max-width: 500px;
960
+ }
961
+
962
+ .loading-error p {
963
+ color: var(--orange);
964
+ margin: 0 0 1rem 0;
965
+ font-size: 0.95rem;
966
+ }
967
+
968
+ .loading-retry-button {
969
+ padding: 10px 24px;
970
+ background-color: var(--orange);
971
+ color: var(--white);
972
+ border: none;
973
+ border-radius: 8px;
974
+ font-size: 0.95rem;
975
+ font-weight: 500;
976
+ cursor: pointer;
977
+ transition: all 0.2s ease;
978
+ }
979
+
980
+ .loading-retry-button:hover {
981
+ background-color: var(--orange-70);
982
+ transform: translateY(-1px);
983
+ }
984
+
985
+ .hidden {
986
+ display: none !important;
987
+ }
988
+
989
+ @media (max-width: 768px) {
990
+ .loading-screen {
991
+ align-items: flex-start;
992
+ }
993
+
994
+ .loading-content {
995
+ padding: 2rem 1.5rem;
996
+ min-height: 100%;
997
+ justify-content: flex-start;
998
+ padding-top: 3rem;
999
+ }
1000
+
1001
+ .loading-title {
1002
+ font-size: 1.75rem;
1003
+ }
1004
+
1005
+ .loading-subtitle {
1006
+ font-size: 1rem;
1007
+ }
1008
+
1009
+ .loading-description p {
1010
+ font-size: 0.9rem;
1011
+ }
1012
+
1013
+ .loading-explore-button {
1014
+ padding: 14px 36px;
1015
+ font-size: 1rem;
1016
+ min-width: 180px;
1017
+ }
1018
+ }
1019
+
1020
+ /* Mobile Warning */
1021
+ .mobile-warning {
1022
+ margin-bottom: 1.5rem;
1023
+ padding: 1rem 1.5rem;
1024
+ background-color: rgba(255, 95, 30, 0.15);
1025
+ border: 1px solid var(--orange-50);
1026
+ border-radius: 8px;
1027
+ max-width: 400px;
1028
+ }
1029
+
1030
+ .mobile-warning-title {
1031
+ color: var(--orange);
1032
+ font-weight: 600;
1033
+ font-size: 1rem;
1034
+ margin-bottom: 0.5rem;
1035
+ text-align: center;
1036
+ display: flex;
1037
+ align-items: center;
1038
+ justify-content: center;
1039
+ gap: 6px;
1040
+ }
1041
+
1042
+ .mobile-warning-title svg {
1043
+ flex-shrink: 0;
1044
+ }
1045
+
1046
+ .mobile-warning p {
1047
+ color: var(--white-70);
1048
+ font-size: 0.85rem;
1049
+ line-height: 1.5;
1050
+ margin: 0 0 0.5rem 0;
1051
+ text-align: center;
1052
+ }
1053
+
1054
+ .mobile-warning p:last-child {
1055
+ margin-bottom: 0;
1056
+ }
1057
+
1058
+ /* Safari Warning */
1059
+ .safari-warning {
1060
+ margin-bottom: 1.5rem;
1061
+ padding: 1rem 1.5rem;
1062
+ background-color: rgba(205, 130, 240, 0.15);
1063
+ border: 1px solid var(--light-purple-50);
1064
+ border-radius: 8px;
1065
+ max-width: 500px;
1066
+ }
1067
+
1068
+ .safari-warning-title {
1069
+ color: var(--light-purple);
1070
+ font-weight: 600;
1071
+ font-size: 1rem;
1072
+ margin-bottom: 0.5rem;
1073
+ text-align: center;
1074
+ display: flex;
1075
+ align-items: center;
1076
+ justify-content: center;
1077
+ gap: 6px;
1078
+ }
1079
+
1080
+ .safari-warning-title svg {
1081
+ flex-shrink: 0;
1082
+ }
1083
+
1084
+ .safari-warning p {
1085
+ color: var(--white-70);
1086
+ font-size: 0.85rem;
1087
+ line-height: 1.5;
1088
+ margin: 0 0 0.5rem 0;
1089
+ text-align: center;
1090
+ }
1091
+
1092
+ .safari-warning p:last-child {
1093
+ margin-bottom: 0;
1094
+ }
1095
+
1096
+ .safari-warning a {
1097
+ color: var(--light-purple);
1098
+ text-decoration: underline;
1099
+ }
1100
+
1101
+ .safari-warning a:hover {
1102
+ color: var(--white);
1103
+ }
ui.js ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c51742028d2f86e9e4a5b1f28e6c07a9589dfd22ef8ba08505695a8cfa1fcfcc
3
+ size 7591
vite.config.js ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1b3cfac5b51113cc6f1b2b80b439645cda2a20c128f687f78f6c33c744796b93
3
+ size 569
vl-model.js ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ea7ac06f1056d904b7534c5a03880ca2e152400716494fb9fc3e641b3533ea8b
3
+ size 32726
vl-processor.js ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:48efd9747db48eeee8ef08ae8403460e55e6fb20c68d12111715ac39d5604707
3
+ size 18706
webgpu-inference.js ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0ea584d80f1d877ce1fa6af3bc084191b12c15f84fd580fc8fef646c27970beb
3
+ size 4882