vue-streaming 0.1.4 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +425 -699
  2. package/dist/WebSocketStream.vue_vue_type_script_setup_true_lang-C_F2vNNk.js +1081 -0
  3. package/dist/WebSocketStream.vue_vue_type_script_setup_true_lang-C_F2vNNk.js.map +1 -0
  4. package/dist/WebSocketStream.vue_vue_type_script_setup_true_lang-EzMJEQkx.cjs +2 -0
  5. package/dist/WebSocketStream.vue_vue_type_script_setup_true_lang-EzMJEQkx.cjs.map +1 -0
  6. package/dist/components/index.cjs +2 -0
  7. package/dist/components/index.cjs.map +1 -0
  8. package/dist/components/index.js +15 -0
  9. package/dist/components/index.js.map +1 -0
  10. package/dist/composables/index.cjs +2 -0
  11. package/dist/composables/index.cjs.map +1 -0
  12. package/dist/composables/index.js +15 -0
  13. package/dist/composables/index.js.map +1 -0
  14. package/dist/index.cjs +1 -3
  15. package/dist/index.cjs.map +1 -1
  16. package/dist/index.js +62 -2
  17. package/dist/index.js.map +1 -1
  18. package/dist/types.cjs +2 -0
  19. package/dist/types.cjs.map +1 -0
  20. package/dist/types.js +2 -0
  21. package/dist/types.js.map +1 -0
  22. package/dist/usePointCloud-D0qcpYFY.js +115 -0
  23. package/dist/usePointCloud-D0qcpYFY.js.map +1 -0
  24. package/dist/usePointCloud-D2csBAs8.cjs +2 -0
  25. package/dist/usePointCloud-D2csBAs8.cjs.map +1 -0
  26. package/dist/useWebSocket-7-qar6to.cjs +4 -0
  27. package/dist/useWebSocket-7-qar6to.cjs.map +1 -0
  28. package/dist/useWebSocket-CrE6QkTW.js +1278 -0
  29. package/dist/useWebSocket-CrE6QkTW.js.map +1 -0
  30. package/dist/utils/index.cjs +2 -0
  31. package/dist/utils/index.cjs.map +1 -0
  32. package/dist/utils/index.js +503 -0
  33. package/dist/utils/index.js.map +1 -0
  34. package/dist/vue-streaming.css +1 -0
  35. package/package.json +126 -69
  36. package/dist/index.d.cts +0 -49
  37. package/dist/index.d.ts +0 -49
  38. package/dist/index.global.js +0 -8
  39. package/dist/index.global.js.map +0 -1
@@ -0,0 +1,503 @@
1
+ const A = {
2
+ person: 16711680,
3
+ car: 65280,
4
+ truck: 255,
5
+ bicycle: 16776960,
6
+ motorcycle: 16711935,
7
+ bus: 65535,
8
+ pedestrian: 16737792,
9
+ vehicle: 65280,
10
+ default: 65280
11
+ }, M = {
12
+ 0: 16711680,
13
+ // Person - Red
14
+ 1: 65280,
15
+ // Car - Green
16
+ 2: 255,
17
+ // Truck - Blue
18
+ 3: 16776960,
19
+ // Bicycle - Yellow
20
+ 4: 16711935,
21
+ // Motorcycle - Magenta
22
+ 5: 65535,
23
+ // Bus - Cyan
24
+ 6: 16746496,
25
+ // Train - Orange
26
+ 7: 8978176,
27
+ // Traffic Light - Lime
28
+ 8: 35071,
29
+ // Fire Hydrant - Light Blue
30
+ 9: 16711816,
31
+ // Stop Sign - Pink
32
+ 10: 8913151,
33
+ // Parking Meter - Purple
34
+ 11: 65416,
35
+ // Bench - Teal
36
+ 12: 16777096,
37
+ // Bird - Light Yellow
38
+ 13: 8978431,
39
+ // Cat - Light Cyan
40
+ 14: 16746751,
41
+ // Dog - Light Magenta
42
+ 15: 8947848,
43
+ // Horse - Gray
44
+ 33: 16737792
45
+ // Class 33 - Orange
46
+ }, D = {
47
+ 0: "Person",
48
+ 1: "Car",
49
+ 2: "Truck",
50
+ 3: "Bicycle",
51
+ 4: "Motorcycle",
52
+ 5: "Bus",
53
+ 6: "Train",
54
+ 7: "Traffic Light",
55
+ 8: "Fire Hydrant",
56
+ 9: "Stop Sign",
57
+ 10: "Parking Meter",
58
+ 11: "Bench",
59
+ 12: "Bird",
60
+ 13: "Cat",
61
+ 14: "Dog",
62
+ 15: "Horse",
63
+ 33: "Object"
64
+ };
65
+ let m = { ...A }, x = {
66
+ ...M
67
+ }, p = { ...D };
68
+ function _(e) {
69
+ e.colors && (m = { ...m, ...e.colors }), e.colorsByClassId && (x = { ...x, ...e.colorsByClassId }), e.classLabels && (p = { ...p, ...e.classLabels });
70
+ }
71
+ function T() {
72
+ m = { ...A }, x = { ...M }, p = { ...D };
73
+ }
74
+ function E() {
75
+ return { ...m };
76
+ }
77
+ function N() {
78
+ return { ...x };
79
+ }
80
+ function Y() {
81
+ return { ...p };
82
+ }
83
+ function k(e, n) {
84
+ m[e.toLowerCase()] = n;
85
+ }
86
+ function v(e, n) {
87
+ x[e] = n;
88
+ }
89
+ function X(e, n) {
90
+ p[e] = n;
91
+ }
92
+ function V(e) {
93
+ const n = e.toLowerCase();
94
+ return m[n] ?? m.default;
95
+ }
96
+ function L(e) {
97
+ return x[e] ?? 65280;
98
+ }
99
+ function F(e) {
100
+ return p[e] ?? `Class ${e}`;
101
+ }
102
+ function I(e, n = 0) {
103
+ const i = e[0] ?? 0;
104
+ return {
105
+ id: n,
106
+ label: F(i),
107
+ center: {
108
+ x: e[1] ?? 0,
109
+ y: e[2] ?? 0,
110
+ z: e[3] ?? 0
111
+ },
112
+ dimensions: {
113
+ width: e[4] ?? 1,
114
+ height: e[5] ?? 1,
115
+ depth: e[6] ?? 1
116
+ },
117
+ rotation: {
118
+ x: 0,
119
+ y: e[7] ?? 0,
120
+ z: 0
121
+ },
122
+ confidence: e[8] ?? 1,
123
+ color: L(i)
124
+ };
125
+ }
126
+ function j(e) {
127
+ return e.map((n, i) => I(n, i));
128
+ }
129
+ function H(e) {
130
+ return e.map((n, i) => {
131
+ const t = Math.floor(n[0] ?? i);
132
+ return {
133
+ id: t,
134
+ label: `Person ${t}`,
135
+ center: {
136
+ x: n[1] ?? 0,
137
+ y: n[2] ?? 0,
138
+ z: n[3] ?? 0
139
+ },
140
+ dimensions: {
141
+ width: Math.abs(n[4] ?? 1),
142
+ height: Math.abs(n[5] ?? 1),
143
+ depth: Math.abs(n[6] ?? 1)
144
+ },
145
+ rotation: {
146
+ x: 0,
147
+ y: n[7] ?? 0,
148
+ z: 0
149
+ },
150
+ confidence: n[8] ?? 1,
151
+ color: 65280
152
+ };
153
+ });
154
+ }
155
+ function Z(e) {
156
+ return e.map((n, i) => {
157
+ const t = n, r = t.center || {
158
+ x: t.x || t.centerX || 0,
159
+ y: t.y || t.centerY || 0,
160
+ z: t.z || t.centerZ || 0
161
+ }, o = t.dimensions || t.size || {
162
+ width: t.width || t.w || 1,
163
+ height: t.height || t.h || 1,
164
+ depth: t.depth || t.d || t.length || 1
165
+ }, c = t.rotation || {
166
+ x: t.rotX || t.rx || 0,
167
+ y: t.rotY || t.ry || t.yaw || 0,
168
+ z: t.rotZ || t.rz || 0
169
+ };
170
+ return {
171
+ id: t.id ?? i,
172
+ label: t.label || t.class || t.className,
173
+ center: r,
174
+ dimensions: o,
175
+ rotation: c,
176
+ color: t.color,
177
+ confidence: t.confidence || t.score || t.prob
178
+ };
179
+ });
180
+ }
181
+ function O(e) {
182
+ return {
183
+ id: e.id,
184
+ label: e.label || "unknown",
185
+ confidence: e.confidence || 1,
186
+ boundingBox: {
187
+ x: e.center.x - (e.dimensions.width || 1) / 2,
188
+ y: e.center.y - (e.dimensions.height || 1) / 2,
189
+ width: e.dimensions.width || 1,
190
+ height: e.dimensions.height || 1
191
+ },
192
+ trackId: String(e.id)
193
+ };
194
+ }
195
+ function $(e) {
196
+ return {
197
+ detections: e.map(O),
198
+ timestamp: Date.now()
199
+ };
200
+ }
201
+ function P(e, n) {
202
+ const { center: i, dimensions: t } = e, { center: r, dimensions: o } = n, c = Math.max(i.x - t.width / 2, r.x - o.width / 2), s = Math.max(i.y - t.height / 2, r.y - o.height / 2), a = Math.max(i.z - t.depth / 2, r.z - o.depth / 2), u = Math.min(i.x + t.width / 2, r.x + o.width / 2), y = Math.min(i.y + t.height / 2, r.y + o.height / 2), f = Math.min(i.z + t.depth / 2, r.z + o.depth / 2), l = Math.max(0, u - c), h = Math.max(0, y - s), g = Math.max(0, f - a), d = l * h * g, C = t.width * t.height * t.depth, b = o.width * o.height * o.depth, z = C + b - d;
203
+ return z > 0 ? d / z : 0;
204
+ }
205
+ function J(e, n) {
206
+ return e.filter((i) => (i.confidence ?? 1) >= n);
207
+ }
208
+ function W(e, n = 0.5) {
209
+ if (e.length === 0) return [];
210
+ const i = [...e].sort(
211
+ (o, c) => (c.confidence ?? 1) - (o.confidence ?? 1)
212
+ ), t = [], r = /* @__PURE__ */ new Set();
213
+ for (let o = 0; o < i.length; o++)
214
+ if (!r.has(o)) {
215
+ t.push(i[o]);
216
+ for (let c = o + 1; c < i.length; c++) {
217
+ if (r.has(c)) continue;
218
+ P(i[o], i[c]) >= n && r.add(c);
219
+ }
220
+ }
221
+ return t;
222
+ }
223
+ const B = {
224
+ DRACO: [68, 82, 65, 67, 79],
225
+ // "DRACO"
226
+ BINARY_HEADER: [80, 67, 76, 68],
227
+ // "PCLD"
228
+ PLY: [112, 108, 121],
229
+ // "ply"
230
+ PCD: [35, 32, 46, 80, 67, 68]
231
+ // "# .PCD"
232
+ };
233
+ function G(e) {
234
+ if (typeof e == "string")
235
+ try {
236
+ return JSON.parse(e), "json";
237
+ } catch {
238
+ if (e.startsWith("ply")) return "ply";
239
+ if (e.startsWith("# .PCD")) return "pcd";
240
+ }
241
+ const n = new Uint8Array(
242
+ e instanceof ArrayBuffer ? e : e instanceof Uint8Array ? e.buffer.slice(e.byteOffset, e.byteOffset + e.byteLength) : new TextEncoder().encode(e).buffer
243
+ );
244
+ return w(n, B.DRACO) ? "draco" : w(n, B.BINARY_HEADER) ? "binary-header" : w(n, B.PLY) ? "ply" : w(n, B.PCD) ? "pcd" : n.length % 12 === 0 ? "raw-float32" : n.length % 24 === 0 ? "raw-float32-rgb" : "raw-float32";
245
+ }
246
+ function w(e, n) {
247
+ if (e.length < n.length) return !1;
248
+ for (let i = 0; i < n.length; i++)
249
+ if (e[i] !== n[i]) return !1;
250
+ return !0;
251
+ }
252
+ function q(e) {
253
+ const n = [], i = new Uint8Array(e), t = new DataView(e), r = e.byteLength;
254
+ if (r >= 5 && String.fromCharCode(
255
+ i[0],
256
+ i[1],
257
+ i[2],
258
+ i[3],
259
+ i[4]
260
+ ) === "DRACO")
261
+ return console.warn(
262
+ "[PointCloud] DRACO format detected - requires external decoder"
263
+ ), [];
264
+ if (r >= 4 && String.fromCharCode(i[0], i[1], i[2], i[3]) === "PCLD")
265
+ return R(e);
266
+ let o = 0, c = 0, s = 12;
267
+ if (r >= 4) {
268
+ const a = t.getUint32(0, !0);
269
+ if (a > 0 && a < r / 12 && a < 1e7 && (c = a, o = 4, r >= 8)) {
270
+ const u = t.getUint32(4, !0);
271
+ u === 3 ? (s = 12, o = 8) : u === 4 ? (s = 16, o = 8) : u === 6 && (s = 24, o = 8);
272
+ }
273
+ }
274
+ c === 0 && (r % 16 === 0 ? (s = 16, c = r / 16) : r % 12 === 0 ? (s = 12, c = r / 12) : r % 15 === 0 ? (s = 15, c = r / 15) : (s = 12, c = Math.floor(r / 12)));
275
+ for (let a = 0; a < c && o + s <= r; a++) {
276
+ try {
277
+ const u = t.getFloat32(o, !0), y = t.getFloat32(o + 4, !0), f = t.getFloat32(o + 8, !0);
278
+ if (!Number.isFinite(u) || !Number.isFinite(y) || !Number.isFinite(f) || Math.abs(u) > 1e5 || Math.abs(y) > 1e5 || Math.abs(f) > 1e5) {
279
+ o += s;
280
+ continue;
281
+ }
282
+ const l = { x: u, y, z: f };
283
+ if (s === 16) {
284
+ const h = t.getFloat32(o + 12, !0);
285
+ Number.isFinite(h) && h >= 0 && h <= 1 ? l.intensity = h : (l.r = t.getUint8(o + 12) / 255, l.g = t.getUint8(o + 13) / 255, l.b = t.getUint8(o + 14) / 255);
286
+ } else s === 15 ? (l.r = t.getUint8(o + 12) / 255, l.g = t.getUint8(o + 13) / 255, l.b = t.getUint8(o + 14) / 255) : s === 24 && (l.r = t.getFloat32(o + 12, !0), l.g = t.getFloat32(o + 16, !0), l.b = t.getFloat32(o + 20, !0));
287
+ n.push(l);
288
+ } catch {
289
+ }
290
+ o += s;
291
+ }
292
+ return n;
293
+ }
294
+ function R(e) {
295
+ const n = new Uint8Array(e), i = new DataView(e), t = [], r = i.getUint32(8, !0), o = i.getUint32(12, !0), c = (o & 1) !== 0, s = (o & 2) !== 0;
296
+ let a = 12;
297
+ c && (a += 3), s && (a += 4);
298
+ const u = 16;
299
+ for (let y = 0; y < r; y++) {
300
+ let f = u + y * a;
301
+ const l = i.getFloat32(f, !0), h = i.getFloat32(f + 4, !0), g = i.getFloat32(f + 8, !0);
302
+ if (f += 12, !Number.isFinite(l) || !Number.isFinite(h) || !Number.isFinite(g))
303
+ continue;
304
+ const d = { x: l, y: h, z: g };
305
+ c && (d.r = n[f] / 255, d.g = n[f + 1] / 255, d.b = n[f + 2] / 255, f += 3), s && (d.intensity = i.getFloat32(f, !0)), t.push(d);
306
+ }
307
+ return t;
308
+ }
309
+ function S(e) {
310
+ try {
311
+ const n = JSON.parse(e);
312
+ if (Array.isArray(n)) {
313
+ if (n.length === 0) return [];
314
+ const i = n[0];
315
+ if (Array.isArray(i))
316
+ return n.map((t) => ({
317
+ x: t[0] ?? 0,
318
+ y: t[1] ?? 0,
319
+ z: t[2] ?? 0,
320
+ r: t[3],
321
+ g: t[4],
322
+ b: t[5],
323
+ intensity: t[6]
324
+ }));
325
+ if (typeof i == "object" && i !== null)
326
+ return n.map((t) => ({
327
+ x: t.x ?? t.X ?? 0,
328
+ y: t.y ?? t.Y ?? 0,
329
+ z: t.z ?? t.Z ?? 0,
330
+ r: t.r ?? t.R ?? t.red,
331
+ g: t.g ?? t.G ?? t.green,
332
+ b: t.b ?? t.B ?? t.blue,
333
+ intensity: t.intensity ?? t.i ?? t.I
334
+ }));
335
+ }
336
+ if (n && typeof n == "object") {
337
+ const i = n.points || n.data || n.cloud;
338
+ if (Array.isArray(i))
339
+ return S(JSON.stringify(i));
340
+ }
341
+ return null;
342
+ } catch {
343
+ return null;
344
+ }
345
+ }
346
+ function K(e) {
347
+ if (e.length === 0)
348
+ return {
349
+ min: { x: 0, y: 0, z: 0 },
350
+ max: { x: 0, y: 0, z: 0 }
351
+ };
352
+ let n = 1 / 0, i = -1 / 0, t = 1 / 0, r = -1 / 0, o = 1 / 0, c = -1 / 0;
353
+ for (const s of e)
354
+ s.x < n && (n = s.x), s.x > i && (i = s.x), s.y < t && (t = s.y), s.y > r && (r = s.y), s.z < o && (o = s.z), s.z > c && (c = s.z);
355
+ return {
356
+ min: { x: n, y: t, z: o },
357
+ max: { x: i, y: r, z: c }
358
+ };
359
+ }
360
+ function Q(e, n = 1, i = { x: 0, y: 0, z: 0 }) {
361
+ return n === 1 && i.x === 0 && i.y === 0 && i.z === 0 ? e : e.map((t) => ({
362
+ ...t,
363
+ x: t.x * n + i.x,
364
+ y: t.y * n + i.y,
365
+ z: t.z * n + i.z
366
+ }));
367
+ }
368
+ function tt(e, n) {
369
+ if (n <= 0) return e;
370
+ const i = /* @__PURE__ */ new Map();
371
+ for (const r of e) {
372
+ const o = Math.floor(r.x / n), c = Math.floor(r.y / n), s = Math.floor(r.z / n), a = `${o},${c},${s}`;
373
+ i.has(a) || i.set(a, []), i.get(a).push(r);
374
+ }
375
+ const t = [];
376
+ for (const r of i.values()) {
377
+ const o = { x: 0, y: 0, z: 0 };
378
+ let c = !1, s = 0, a = 0, u = 0, y = 0, f = !1;
379
+ for (const h of r)
380
+ o.x += h.x, o.y += h.y, o.z += h.z, h.r !== void 0 && (c = !0, s += h.r, a += h.g ?? 0, u += h.b ?? 0), h.intensity !== void 0 && (f = !0, y += h.intensity);
381
+ const l = r.length;
382
+ o.x /= l, o.y /= l, o.z /= l, c && (o.r = s / l, o.g = a / l, o.b = u / l), f && (o.intensity = y / l), t.push(o);
383
+ }
384
+ return t;
385
+ }
386
+ function et(e) {
387
+ const n = {
388
+ attempts: 0,
389
+ isReconnecting: !1,
390
+ lastAttempt: null,
391
+ nextAttempt: null
392
+ };
393
+ let i = null;
394
+ const {
395
+ maxAttempts: t,
396
+ delay: r,
397
+ delayMax: o = r * 10,
398
+ backoffMultiplier: c = 1.5,
399
+ onAttempt: s,
400
+ onSuccess: a,
401
+ onFailure: u
402
+ } = e;
403
+ function y() {
404
+ const d = r * Math.pow(c, n.attempts);
405
+ return Math.min(d, o);
406
+ }
407
+ function f(d) {
408
+ if (n.isReconnecting || n.attempts >= t) {
409
+ n.attempts >= t && (u == null || u());
410
+ return;
411
+ }
412
+ n.isReconnecting = !0, n.attempts++, n.lastAttempt = Date.now();
413
+ const C = y();
414
+ n.nextAttempt = Date.now() + C, s == null || s(n.attempts, t), i = setTimeout(async () => {
415
+ try {
416
+ await d() ? (l(), a == null || a()) : (n.isReconnecting = !1, f(d));
417
+ } catch {
418
+ n.isReconnecting = !1, f(d);
419
+ }
420
+ }, C);
421
+ }
422
+ function l() {
423
+ n.attempts = 0, n.isReconnecting = !1, n.lastAttempt = null, n.nextAttempt = null, i && (clearTimeout(i), i = null);
424
+ }
425
+ function h() {
426
+ n.isReconnecting = !1, n.nextAttempt = null, i && (clearTimeout(i), i = null);
427
+ }
428
+ function g() {
429
+ return n.attempts < t;
430
+ }
431
+ return {
432
+ state: n,
433
+ scheduleReconnect: f,
434
+ reset: l,
435
+ cancel: h,
436
+ shouldReconnect: g,
437
+ calculateDelay: y
438
+ };
439
+ }
440
+ function U(e) {
441
+ return new Promise((n) => setTimeout(n, e));
442
+ }
443
+ async function nt(e, n = {}) {
444
+ const {
445
+ maxAttempts: i = 3,
446
+ delay: t = 1e3,
447
+ delayMax: r = 3e4,
448
+ backoffMultiplier: o = 2,
449
+ onAttempt: c
450
+ } = n;
451
+ let s = null;
452
+ for (let a = 1; a <= i; a++)
453
+ try {
454
+ return c == null || c(a), await e();
455
+ } catch (u) {
456
+ if (s = u instanceof Error ? u : new Error(String(u)), a < i) {
457
+ const y = Math.min(
458
+ t * Math.pow(o, a - 1),
459
+ r
460
+ );
461
+ await U(y);
462
+ }
463
+ }
464
+ throw s;
465
+ }
466
+ export {
467
+ m as BBOX_COLORS,
468
+ x as BBOX_COLORS_BY_ID,
469
+ p as CLASS_LABELS,
470
+ A as DEFAULT_BBOX_COLORS,
471
+ M as DEFAULT_BBOX_COLORS_BY_ID,
472
+ D as DEFAULT_CLASS_LABELS,
473
+ O as bbox3DToDetection,
474
+ $ as bboxesToDetectionFrame,
475
+ K as calculateBounds,
476
+ P as calculateIoU3D,
477
+ _ as configureBBox,
478
+ et as createReconnectManager,
479
+ U as delay,
480
+ G as detectPointCloudFormat,
481
+ tt as downsamplePointCloud,
482
+ J as filterByConfidence,
483
+ E as getBBoxColors,
484
+ N as getBBoxColorsByClassId,
485
+ Y as getClassLabels,
486
+ L as getColorForClassId,
487
+ V as getColorForLabel,
488
+ F as getLabelForClassId,
489
+ W as nms3D,
490
+ Z as normalizeBboxes,
491
+ H as parseArrayBboxFormat,
492
+ I as parseArrayBoundingBox,
493
+ j as parseArrayBoundingBoxes,
494
+ q as parsePointCloudBinary,
495
+ S as parsePointCloudJSON,
496
+ T as resetBBoxConfig,
497
+ nt as retryWithBackoff,
498
+ k as setBBoxColor,
499
+ v as setBBoxColorByClassId,
500
+ X as setClassLabel,
501
+ Q as transformPoints
502
+ };
503
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../../src/utils/bbox.ts","../../src/utils/pointcloud.ts","../../src/utils/reconnect.ts"],"sourcesContent":["/**\r\n * Bounding Box utilities\r\n * @module vue-streaming/utils/bbox\r\n */\r\n\r\nimport type { BoundingBox3D, Detection } from \"../types\";\r\n\r\n// =============================================================================\r\n// Configuration Types\r\n// =============================================================================\r\n\r\n/**\r\n * Configuration options for bounding box colors and labels\r\n */\r\nexport interface BBoxConfig {\r\n /** Color palette for different object classes (by name) */\r\n colors?: Record<string, number>;\r\n /** Color palette for different object classes (by class ID) */\r\n colorsByClassId?: Record<number, number>;\r\n /** Class ID to label mapping */\r\n classLabels?: Record<number, string>;\r\n}\r\n\r\n// =============================================================================\r\n// Default Color Palettes\r\n// =============================================================================\r\n\r\n/**\r\n * Default color palette for different object classes (by name)\r\n */\r\nexport const DEFAULT_BBOX_COLORS: Record<string, number> = {\r\n person: 0xff0000,\r\n car: 0x00ff00,\r\n truck: 0x0000ff,\r\n bicycle: 0xffff00,\r\n motorcycle: 0xff00ff,\r\n bus: 0x00ffff,\r\n pedestrian: 0xff6600,\r\n vehicle: 0x00ff00,\r\n default: 0x00ff00,\r\n};\r\n\r\n/**\r\n * Default color palette for different object classes (by class ID)\r\n */\r\nexport const DEFAULT_BBOX_COLORS_BY_ID: Record<number, number> = {\r\n 0: 0xff0000, // Person - Red\r\n 1: 0x00ff00, // Car - Green\r\n 2: 0x0000ff, // Truck - Blue\r\n 3: 0xffff00, // Bicycle - Yellow\r\n 4: 0xff00ff, // Motorcycle - Magenta\r\n 5: 0x00ffff, // Bus - Cyan\r\n 6: 0xff8800, // Train - Orange\r\n 7: 0x88ff00, // Traffic Light - Lime\r\n 8: 0x0088ff, // Fire Hydrant - Light Blue\r\n 9: 0xff0088, // Stop Sign - Pink\r\n 10: 0x8800ff, // Parking Meter - Purple\r\n 11: 0x00ff88, // Bench - Teal\r\n 12: 0xffff88, // Bird - Light Yellow\r\n 13: 0x88ffff, // Cat - Light Cyan\r\n 14: 0xff88ff, // Dog - Light Magenta\r\n 15: 0x888888, // Horse - Gray\r\n 33: 0xff6600, // Class 33 - Orange\r\n};\r\n\r\n/**\r\n * Default class ID to label mapping\r\n */\r\nexport const DEFAULT_CLASS_LABELS: Record<number, string> = {\r\n 0: \"Person\",\r\n 1: \"Car\",\r\n 2: \"Truck\",\r\n 3: \"Bicycle\",\r\n 4: \"Motorcycle\",\r\n 5: \"Bus\",\r\n 6: \"Train\",\r\n 7: \"Traffic Light\",\r\n 8: \"Fire Hydrant\",\r\n 9: \"Stop Sign\",\r\n 10: \"Parking Meter\",\r\n 11: \"Bench\",\r\n 12: \"Bird\",\r\n 13: \"Cat\",\r\n 14: \"Dog\",\r\n 15: \"Horse\",\r\n 33: \"Object\",\r\n};\r\n\r\n// =============================================================================\r\n// Runtime Configuration (Mutable)\r\n// =============================================================================\r\n\r\n/**\r\n * Current runtime color palette for different object classes (by name)\r\n * @deprecated Use `getBBoxColors()` instead for reading, and `configureBBox()` for setting\r\n */\r\nexport let BBOX_COLORS: Record<string, number> = { ...DEFAULT_BBOX_COLORS };\r\n\r\n/**\r\n * Current runtime color palette for different object classes (by class ID)\r\n * @deprecated Use `getBBoxColorsByClassId()` instead for reading, and `configureBBox()` for setting\r\n */\r\nexport let BBOX_COLORS_BY_ID: Record<number, number> = {\r\n ...DEFAULT_BBOX_COLORS_BY_ID,\r\n};\r\n\r\n/**\r\n * Current runtime class ID to label mapping\r\n * @deprecated Use `getClassLabels()` instead for reading, and `configureBBox()` for setting\r\n */\r\nexport let CLASS_LABELS: Record<number, string> = { ...DEFAULT_CLASS_LABELS };\r\n\r\n// =============================================================================\r\n// Configuration Functions\r\n// =============================================================================\r\n\r\n/**\r\n * Configure bounding box colors and labels globally\r\n *\r\n * @param config - Configuration options\r\n * @example\r\n * ```typescript\r\n * import { configureBBox } from 'vue-streaming';\r\n *\r\n * // Override specific colors by label\r\n * configureBBox({\r\n * colors: {\r\n * person: 0x00ffff, // Cyan instead of red\r\n * car: 0xff00ff, // Magenta instead of green\r\n * }\r\n * });\r\n *\r\n * // Override colors by class ID\r\n * configureBBox({\r\n * colorsByClassId: {\r\n * 0: 0x00ffff, // Person - Cyan\r\n * 1: 0xff00ff, // Car - Magenta\r\n * }\r\n * });\r\n *\r\n * // Override class labels\r\n * configureBBox({\r\n * classLabels: {\r\n * 0: \"Human\", // Instead of \"Person\"\r\n * 1: \"Vehicle\", // Instead of \"Car\"\r\n * }\r\n * });\r\n *\r\n * // Configure all at once\r\n * configureBBox({\r\n * colors: { person: 0x00ffff },\r\n * colorsByClassId: { 0: 0x00ffff },\r\n * classLabels: { 0: \"Human\" }\r\n * });\r\n * ```\r\n */\r\nexport function configureBBox(config: BBoxConfig): void {\r\n if (config.colors) {\r\n BBOX_COLORS = { ...BBOX_COLORS, ...config.colors };\r\n }\r\n if (config.colorsByClassId) {\r\n BBOX_COLORS_BY_ID = { ...BBOX_COLORS_BY_ID, ...config.colorsByClassId };\r\n }\r\n if (config.classLabels) {\r\n CLASS_LABELS = { ...CLASS_LABELS, ...config.classLabels };\r\n }\r\n}\r\n\r\n/**\r\n * Reset bounding box configuration to defaults\r\n *\r\n * @example\r\n * ```typescript\r\n * import { resetBBoxConfig } from 'vue-streaming';\r\n *\r\n * // Reset all to defaults\r\n * resetBBoxConfig();\r\n * ```\r\n */\r\nexport function resetBBoxConfig(): void {\r\n BBOX_COLORS = { ...DEFAULT_BBOX_COLORS };\r\n BBOX_COLORS_BY_ID = { ...DEFAULT_BBOX_COLORS_BY_ID };\r\n CLASS_LABELS = { ...DEFAULT_CLASS_LABELS };\r\n}\r\n\r\n/**\r\n * Get current bounding box colors by label\r\n *\r\n * @returns Current color mapping by label name\r\n */\r\nexport function getBBoxColors(): Record<string, number> {\r\n return { ...BBOX_COLORS };\r\n}\r\n\r\n/**\r\n * Get current bounding box colors by class ID\r\n *\r\n * @returns Current color mapping by class ID\r\n */\r\nexport function getBBoxColorsByClassId(): Record<number, number> {\r\n return { ...BBOX_COLORS_BY_ID };\r\n}\r\n\r\n/**\r\n * Get current class labels\r\n *\r\n * @returns Current class label mapping\r\n */\r\nexport function getClassLabels(): Record<number, string> {\r\n return { ...CLASS_LABELS };\r\n}\r\n\r\n/**\r\n * Set a single color for a label\r\n *\r\n * @param label - The label name (e.g., \"person\", \"car\")\r\n * @param color - The color value (hex number, e.g., 0xff0000)\r\n */\r\nexport function setBBoxColor(label: string, color: number): void {\r\n BBOX_COLORS[label.toLowerCase()] = color;\r\n}\r\n\r\n/**\r\n * Set a single color for a class ID\r\n *\r\n * @param classId - The class ID number\r\n * @param color - The color value (hex number, e.g., 0xff0000)\r\n */\r\nexport function setBBoxColorByClassId(classId: number, color: number): void {\r\n BBOX_COLORS_BY_ID[classId] = color;\r\n}\r\n\r\n/**\r\n * Set a single class label\r\n *\r\n * @param classId - The class ID number\r\n * @param label - The label string\r\n */\r\nexport function setClassLabel(classId: number, label: string): void {\r\n CLASS_LABELS[classId] = label;\r\n}\r\n\r\n// =============================================================================\r\n// Color Utilities\r\n// =============================================================================\r\n\r\n/**\r\n * Get color for a specific label\r\n */\r\nexport function getColorForLabel(label: string): number {\r\n const normalizedLabel = label.toLowerCase();\r\n return BBOX_COLORS[normalizedLabel] ?? BBOX_COLORS.default;\r\n}\r\n\r\n/**\r\n * Get color for a specific class ID\r\n */\r\nexport function getColorForClassId(classId: number): number {\r\n return BBOX_COLORS_BY_ID[classId] ?? 0x00ff00;\r\n}\r\n\r\n/**\r\n * Get label for a specific class ID\r\n */\r\nexport function getLabelForClassId(classId: number): string {\r\n return CLASS_LABELS[classId] ?? `Class ${classId}`;\r\n}\r\n\r\n// =============================================================================\r\n// Parsing Utilities\r\n// =============================================================================\r\n\r\n/**\r\n * Parse array-format bounding box data\r\n * Format: [class_id, center_x, center_y, center_z, width, height, depth, rotation_yaw, confidence, ...]\r\n */\r\nexport function parseArrayBoundingBox(\r\n arr: number[],\r\n index: number = 0,\r\n): BoundingBox3D {\r\n const classId = arr[0] ?? 0;\r\n\r\n return {\r\n id: index,\r\n label: getLabelForClassId(classId),\r\n center: {\r\n x: arr[1] ?? 0,\r\n y: arr[2] ?? 0,\r\n z: arr[3] ?? 0,\r\n },\r\n dimensions: {\r\n width: arr[4] ?? 1,\r\n height: arr[5] ?? 1,\r\n depth: arr[6] ?? 1,\r\n },\r\n rotation: {\r\n x: 0,\r\n y: arr[7] ?? 0,\r\n z: 0,\r\n },\r\n confidence: arr[8] ?? 1,\r\n color: getColorForClassId(classId),\r\n };\r\n}\r\n\r\n/**\r\n * Parse array of array-format bounding boxes\r\n */\r\nexport function parseArrayBoundingBoxes(data: number[][]): BoundingBox3D[] {\r\n return data.map((arr, index) => parseArrayBoundingBox(arr, index));\r\n}\r\n\r\n/**\r\n * Parse array-format bounding boxes (person tracking format)\r\n * Format: [[object_id, cx, cy, cz, width, height, depth, rotation_yaw, confidence], ...]\r\n */\r\nexport function parseArrayBboxFormat(data: number[][]): BoundingBox3D[] {\r\n return data.map((arr, index) => {\r\n const personId = Math.floor(arr[0] ?? index);\r\n\r\n return {\r\n id: personId,\r\n label: `Person ${personId}`,\r\n center: {\r\n x: arr[1] ?? 0,\r\n y: arr[2] ?? 0,\r\n z: arr[3] ?? 0,\r\n },\r\n dimensions: {\r\n width: Math.abs(arr[4] ?? 1),\r\n height: Math.abs(arr[5] ?? 1),\r\n depth: Math.abs(arr[6] ?? 1),\r\n },\r\n rotation: {\r\n x: 0,\r\n y: arr[7] ?? 0,\r\n z: 0,\r\n },\r\n confidence: arr[8] ?? 1,\r\n color: 0x00ff00,\r\n };\r\n });\r\n}\r\n\r\n/**\r\n * Normalize various bbox formats to BoundingBox3D\r\n */\r\nexport function normalizeBboxes(bboxes: unknown[]): BoundingBox3D[] {\r\n return bboxes.map((bbox: unknown, index: number) => {\r\n const b = bbox as Record<string, unknown>;\r\n\r\n const center = (b.center as { x: number; y: number; z: number }) || {\r\n x: (b.x as number) || (b.centerX as number) || 0,\r\n y: (b.y as number) || (b.centerY as number) || 0,\r\n z: (b.z as number) || (b.centerZ as number) || 0,\r\n };\r\n\r\n const dimensions = (b.dimensions as {\r\n width: number;\r\n height: number;\r\n depth: number;\r\n }) ||\r\n (b.size as { width: number; height: number; depth: number }) || {\r\n width: (b.width as number) || (b.w as number) || 1,\r\n height: (b.height as number) || (b.h as number) || 1,\r\n depth:\r\n (b.depth as number) || (b.d as number) || (b.length as number) || 1,\r\n };\r\n\r\n const rotation = (b.rotation as { x: number; y: number; z: number }) || {\r\n x: (b.rotX as number) || (b.rx as number) || 0,\r\n y: (b.rotY as number) || (b.ry as number) || (b.yaw as number) || 0,\r\n z: (b.rotZ as number) || (b.rz as number) || 0,\r\n };\r\n\r\n return {\r\n id: (b.id as string | number) ?? index,\r\n label:\r\n (b.label as string) || (b.class as string) || (b.className as string),\r\n center,\r\n dimensions,\r\n rotation,\r\n color: b.color as string | number | undefined,\r\n confidence:\r\n (b.confidence as number) || (b.score as number) || (b.prob as number),\r\n };\r\n });\r\n}\r\n\r\n/**\r\n * Convert BoundingBox3D to Detection (2D projection)\r\n */\r\nexport function bbox3DToDetection(bbox: BoundingBox3D): Detection {\r\n return {\r\n id: bbox.id,\r\n label: bbox.label || \"unknown\",\r\n confidence: bbox.confidence || 1,\r\n boundingBox: {\r\n x: bbox.center.x - (bbox.dimensions.width || 1) / 2,\r\n y: bbox.center.y - (bbox.dimensions.height || 1) / 2,\r\n width: bbox.dimensions.width || 1,\r\n height: bbox.dimensions.height || 1,\r\n },\r\n trackId: String(bbox.id),\r\n };\r\n}\r\n\r\n/**\r\n * Convert array of BoundingBox3D to DetectionFrame\r\n */\r\nexport function bboxesToDetectionFrame(bboxes: BoundingBox3D[]): {\r\n detections: Detection[];\r\n timestamp: number;\r\n} {\r\n return {\r\n detections: bboxes.map(bbox3DToDetection),\r\n timestamp: Date.now(),\r\n };\r\n}\r\n\r\n/**\r\n * Calculate IoU (Intersection over Union) between two 3D bounding boxes\r\n */\r\nexport function calculateIoU3D(\r\n box1: BoundingBox3D,\r\n box2: BoundingBox3D,\r\n): number {\r\n const { center: c1, dimensions: d1 } = box1;\r\n const { center: c2, dimensions: d2 } = box2;\r\n\r\n // Calculate intersection\r\n const x1 = Math.max(c1.x - d1.width / 2, c2.x - d2.width / 2);\r\n const y1 = Math.max(c1.y - d1.height / 2, c2.y - d2.height / 2);\r\n const z1 = Math.max(c1.z - d1.depth / 2, c2.z - d2.depth / 2);\r\n\r\n const x2 = Math.min(c1.x + d1.width / 2, c2.x + d2.width / 2);\r\n const y2 = Math.min(c1.y + d1.height / 2, c2.y + d2.height / 2);\r\n const z2 = Math.min(c1.z + d1.depth / 2, c2.z + d2.depth / 2);\r\n\r\n const intersectionWidth = Math.max(0, x2 - x1);\r\n const intersectionHeight = Math.max(0, y2 - y1);\r\n const intersectionDepth = Math.max(0, z2 - z1);\r\n\r\n const intersectionVolume =\r\n intersectionWidth * intersectionHeight * intersectionDepth;\r\n\r\n // Calculate union\r\n const volume1 = d1.width * d1.height * d1.depth;\r\n const volume2 = d2.width * d2.height * d2.depth;\r\n const unionVolume = volume1 + volume2 - intersectionVolume;\r\n\r\n return unionVolume > 0 ? intersectionVolume / unionVolume : 0;\r\n}\r\n\r\n/**\r\n * Filter bounding boxes by confidence threshold\r\n */\r\nexport function filterByConfidence(\r\n bboxes: BoundingBox3D[],\r\n threshold: number,\r\n): BoundingBox3D[] {\r\n return bboxes.filter((bbox) => (bbox.confidence ?? 1) >= threshold);\r\n}\r\n\r\n/**\r\n * Non-maximum suppression for 3D bounding boxes\r\n */\r\nexport function nms3D(\r\n bboxes: BoundingBox3D[],\r\n iouThreshold: number = 0.5,\r\n): BoundingBox3D[] {\r\n if (bboxes.length === 0) return [];\r\n\r\n // Sort by confidence (descending)\r\n const sorted = [...bboxes].sort(\r\n (a, b) => (b.confidence ?? 1) - (a.confidence ?? 1),\r\n );\r\n const kept: BoundingBox3D[] = [];\r\n const suppressed = new Set<number>();\r\n\r\n for (let i = 0; i < sorted.length; i++) {\r\n if (suppressed.has(i)) continue;\r\n\r\n kept.push(sorted[i]);\r\n\r\n for (let j = i + 1; j < sorted.length; j++) {\r\n if (suppressed.has(j)) continue;\r\n\r\n const iou = calculateIoU3D(sorted[i], sorted[j]);\r\n if (iou >= iouThreshold) {\r\n suppressed.add(j);\r\n }\r\n }\r\n }\r\n\r\n return kept;\r\n}\r\n","/**\r\n * Point Cloud parsing utilities\r\n * @module vue-streaming/utils/pointcloud\r\n */\r\n\r\nimport type { DecodedPointCloud, Point3D, PointCloudFormat } from \"../types\";\r\n\r\n// =============================================================================\r\n// Magic Bytes for Format Detection\r\n// =============================================================================\r\n\r\nconst MAGIC_BYTES = {\r\n DRACO: [0x44, 0x52, 0x41, 0x43, 0x4f], // \"DRACO\"\r\n BINARY_HEADER: [0x50, 0x43, 0x4c, 0x44], // \"PCLD\"\r\n PLY: [0x70, 0x6c, 0x79], // \"ply\"\r\n PCD: [0x23, 0x20, 0x2e, 0x50, 0x43, 0x44], // \"# .PCD\"\r\n};\r\n\r\n/**\r\n * Detect point cloud format from data\r\n */\r\nexport function detectPointCloudFormat(\r\n data: ArrayBuffer | Uint8Array | string,\r\n): PointCloudFormat {\r\n if (typeof data === \"string\") {\r\n try {\r\n JSON.parse(data);\r\n return \"json\";\r\n } catch {\r\n if (data.startsWith(\"ply\")) return \"ply\";\r\n if (data.startsWith(\"# .PCD\")) return \"pcd\";\r\n }\r\n }\r\n\r\n const bytes = new Uint8Array(\r\n data instanceof ArrayBuffer\r\n ? data\r\n : data instanceof Uint8Array\r\n ? data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength)\r\n : new TextEncoder().encode(data).buffer,\r\n );\r\n\r\n if (matchMagicBytes(bytes, MAGIC_BYTES.DRACO)) return \"draco\";\r\n if (matchMagicBytes(bytes, MAGIC_BYTES.BINARY_HEADER)) return \"binary-header\";\r\n if (matchMagicBytes(bytes, MAGIC_BYTES.PLY)) return \"ply\";\r\n if (matchMagicBytes(bytes, MAGIC_BYTES.PCD)) return \"pcd\";\r\n\r\n // Check by size\r\n if (bytes.length % 12 === 0) return \"raw-float32\";\r\n if (bytes.length % 24 === 0) return \"raw-float32-rgb\";\r\n\r\n return \"raw-float32\";\r\n}\r\n\r\nfunction matchMagicBytes(data: Uint8Array, magic: number[]): boolean {\r\n if (data.length < magic.length) return false;\r\n for (let i = 0; i < magic.length; i++) {\r\n if (data[i] !== magic[i]) return false;\r\n }\r\n return true;\r\n}\r\n\r\n/**\r\n * Parse binary point cloud data\r\n */\r\nexport function parsePointCloudBinary(buffer: ArrayBuffer): Point3D[] {\r\n const points: Point3D[] = [];\r\n const bytes = new Uint8Array(buffer);\r\n const dataView = new DataView(buffer);\r\n const byteLength = buffer.byteLength;\r\n\r\n // Check for DRACO format\r\n if (byteLength >= 5) {\r\n const magic = String.fromCharCode(\r\n bytes[0],\r\n bytes[1],\r\n bytes[2],\r\n bytes[3],\r\n bytes[4],\r\n );\r\n if (magic === \"DRACO\") {\r\n console.warn(\r\n \"[PointCloud] DRACO format detected - requires external decoder\",\r\n );\r\n return [];\r\n }\r\n }\r\n\r\n // Check for PCLD header format\r\n if (byteLength >= 4) {\r\n const magic = String.fromCharCode(bytes[0], bytes[1], bytes[2], bytes[3]);\r\n if (magic === \"PCLD\") {\r\n return decodePCLDFormat(buffer);\r\n }\r\n }\r\n\r\n // Detect format based on buffer size\r\n let offset = 0;\r\n let pointCount = 0;\r\n let bytesPerPoint = 12; // Default: XYZ float32\r\n\r\n // Try to read header if present\r\n if (byteLength >= 4) {\r\n const possibleCount = dataView.getUint32(0, true);\r\n if (\r\n possibleCount > 0 &&\r\n possibleCount < byteLength / 12 &&\r\n possibleCount < 10000000\r\n ) {\r\n pointCount = possibleCount;\r\n offset = 4;\r\n\r\n if (byteLength >= 8) {\r\n const formatIndicator = dataView.getUint32(4, true);\r\n if (formatIndicator === 3) {\r\n bytesPerPoint = 12;\r\n offset = 8;\r\n } else if (formatIndicator === 4) {\r\n bytesPerPoint = 16;\r\n offset = 8;\r\n } else if (formatIndicator === 6) {\r\n bytesPerPoint = 24;\r\n offset = 8;\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Calculate based on buffer size if no header\r\n if (pointCount === 0) {\r\n if (byteLength % 16 === 0) {\r\n bytesPerPoint = 16;\r\n pointCount = byteLength / 16;\r\n } else if (byteLength % 12 === 0) {\r\n bytesPerPoint = 12;\r\n pointCount = byteLength / 12;\r\n } else if (byteLength % 15 === 0) {\r\n bytesPerPoint = 15;\r\n pointCount = byteLength / 15;\r\n } else {\r\n bytesPerPoint = 12;\r\n pointCount = Math.floor(byteLength / 12);\r\n }\r\n }\r\n\r\n // Parse points\r\n for (let i = 0; i < pointCount && offset + bytesPerPoint <= byteLength; i++) {\r\n try {\r\n const x = dataView.getFloat32(offset, true);\r\n const y = dataView.getFloat32(offset + 4, true);\r\n const z = dataView.getFloat32(offset + 8, true);\r\n\r\n if (\r\n !Number.isFinite(x) ||\r\n !Number.isFinite(y) ||\r\n !Number.isFinite(z) ||\r\n Math.abs(x) > 100000 ||\r\n Math.abs(y) > 100000 ||\r\n Math.abs(z) > 100000\r\n ) {\r\n offset += bytesPerPoint;\r\n continue;\r\n }\r\n\r\n const point: Point3D = { x, y, z };\r\n\r\n if (bytesPerPoint === 16) {\r\n const extraValue = dataView.getFloat32(offset + 12, true);\r\n if (Number.isFinite(extraValue) && extraValue >= 0 && extraValue <= 1) {\r\n point.intensity = extraValue;\r\n } else {\r\n point.r = dataView.getUint8(offset + 12) / 255;\r\n point.g = dataView.getUint8(offset + 13) / 255;\r\n point.b = dataView.getUint8(offset + 14) / 255;\r\n }\r\n } else if (bytesPerPoint === 15) {\r\n point.r = dataView.getUint8(offset + 12) / 255;\r\n point.g = dataView.getUint8(offset + 13) / 255;\r\n point.b = dataView.getUint8(offset + 14) / 255;\r\n } else if (bytesPerPoint === 24) {\r\n point.r = dataView.getFloat32(offset + 12, true);\r\n point.g = dataView.getFloat32(offset + 16, true);\r\n point.b = dataView.getFloat32(offset + 20, true);\r\n }\r\n\r\n points.push(point);\r\n } catch {\r\n // Skip malformed points\r\n }\r\n\r\n offset += bytesPerPoint;\r\n }\r\n\r\n return points;\r\n}\r\n\r\n/**\r\n * Decode PCLD header format\r\n */\r\nfunction decodePCLDFormat(buffer: ArrayBuffer): Point3D[] {\r\n const bytes = new Uint8Array(buffer);\r\n const view = new DataView(buffer);\r\n const points: Point3D[] = [];\r\n\r\n const numPoints = view.getUint32(8, true);\r\n const flags = view.getUint32(12, true);\r\n\r\n const hasColor = (flags & 0x01) !== 0;\r\n const hasIntensity = (flags & 0x02) !== 0;\r\n\r\n let bytesPerPoint = 12;\r\n if (hasColor) bytesPerPoint += 3;\r\n if (hasIntensity) bytesPerPoint += 4;\r\n\r\n const headerSize = 16;\r\n\r\n for (let i = 0; i < numPoints; i++) {\r\n let offset = headerSize + i * bytesPerPoint;\r\n\r\n const x = view.getFloat32(offset, true);\r\n const y = view.getFloat32(offset + 4, true);\r\n const z = view.getFloat32(offset + 8, true);\r\n offset += 12;\r\n\r\n if (!Number.isFinite(x) || !Number.isFinite(y) || !Number.isFinite(z))\r\n continue;\r\n\r\n const point: Point3D = { x, y, z };\r\n\r\n if (hasColor) {\r\n point.r = bytes[offset] / 255;\r\n point.g = bytes[offset + 1] / 255;\r\n point.b = bytes[offset + 2] / 255;\r\n offset += 3;\r\n }\r\n\r\n if (hasIntensity) {\r\n point.intensity = view.getFloat32(offset, true);\r\n }\r\n\r\n points.push(point);\r\n }\r\n\r\n return points;\r\n}\r\n\r\n/**\r\n * Parse JSON point cloud data\r\n */\r\nexport function parsePointCloudJSON(text: string): Point3D[] | null {\r\n try {\r\n const data = JSON.parse(text);\r\n\r\n if (Array.isArray(data)) {\r\n if (data.length === 0) return [];\r\n\r\n const first = data[0];\r\n\r\n // Array of arrays [[x,y,z], ...]\r\n if (Array.isArray(first)) {\r\n return data.map((arr: number[]) => ({\r\n x: arr[0] ?? 0,\r\n y: arr[1] ?? 0,\r\n z: arr[2] ?? 0,\r\n r: arr[3],\r\n g: arr[4],\r\n b: arr[5],\r\n intensity: arr[6],\r\n }));\r\n }\r\n\r\n // Array of objects [{x,y,z}, ...]\r\n if (typeof first === \"object\" && first !== null) {\r\n return data.map((p: Record<string, number>) => ({\r\n x: p.x ?? p.X ?? 0,\r\n y: p.y ?? p.Y ?? 0,\r\n z: p.z ?? p.Z ?? 0,\r\n r: p.r ?? p.R ?? p.red,\r\n g: p.g ?? p.G ?? p.green,\r\n b: p.b ?? p.B ?? p.blue,\r\n intensity: p.intensity ?? p.i ?? p.I,\r\n }));\r\n }\r\n }\r\n\r\n // Object with points array\r\n if (data && typeof data === \"object\") {\r\n const pointsArray = data.points || data.data || data.cloud;\r\n if (Array.isArray(pointsArray)) {\r\n return parsePointCloudJSON(JSON.stringify(pointsArray));\r\n }\r\n }\r\n\r\n return null;\r\n } catch {\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Calculate bounds for point cloud\r\n */\r\nexport function calculateBounds(\r\n points: Point3D[],\r\n): DecodedPointCloud[\"bounds\"] {\r\n if (points.length === 0) {\r\n return {\r\n min: { x: 0, y: 0, z: 0 },\r\n max: { x: 0, y: 0, z: 0 },\r\n };\r\n }\r\n\r\n let minX = Infinity,\r\n maxX = -Infinity;\r\n let minY = Infinity,\r\n maxY = -Infinity;\r\n let minZ = Infinity,\r\n maxZ = -Infinity;\r\n\r\n for (const p of points) {\r\n if (p.x < minX) minX = p.x;\r\n if (p.x > maxX) maxX = p.x;\r\n if (p.y < minY) minY = p.y;\r\n if (p.y > maxY) maxY = p.y;\r\n if (p.z < minZ) minZ = p.z;\r\n if (p.z > maxZ) maxZ = p.z;\r\n }\r\n\r\n return {\r\n min: { x: minX, y: minY, z: minZ },\r\n max: { x: maxX, y: maxY, z: maxZ },\r\n };\r\n}\r\n\r\n/**\r\n * Transform points with scale and offset\r\n */\r\nexport function transformPoints(\r\n points: Point3D[],\r\n scale: number = 1,\r\n offset: { x: number; y: number; z: number } = { x: 0, y: 0, z: 0 },\r\n): Point3D[] {\r\n if (scale === 1 && offset.x === 0 && offset.y === 0 && offset.z === 0) {\r\n return points;\r\n }\r\n\r\n return points.map((p) => ({\r\n ...p,\r\n x: p.x * scale + offset.x,\r\n y: p.y * scale + offset.y,\r\n z: p.z * scale + offset.z,\r\n }));\r\n}\r\n\r\n/**\r\n * Downsample point cloud using voxel grid\r\n */\r\nexport function downsamplePointCloud(\r\n points: Point3D[],\r\n voxelSize: number,\r\n): Point3D[] {\r\n if (voxelSize <= 0) return points;\r\n\r\n const voxelMap = new Map<string, Point3D[]>();\r\n\r\n for (const point of points) {\r\n const vx = Math.floor(point.x / voxelSize);\r\n const vy = Math.floor(point.y / voxelSize);\r\n const vz = Math.floor(point.z / voxelSize);\r\n const key = `${vx},${vy},${vz}`;\r\n\r\n if (!voxelMap.has(key)) {\r\n voxelMap.set(key, []);\r\n }\r\n voxelMap.get(key)!.push(point);\r\n }\r\n\r\n const result: Point3D[] = [];\r\n\r\n for (const voxelPoints of voxelMap.values()) {\r\n // Average all points in voxel\r\n const avg: Point3D = { x: 0, y: 0, z: 0 };\r\n let hasColor = false;\r\n let r = 0,\r\n g = 0,\r\n b = 0;\r\n let intensity = 0;\r\n let hasIntensity = false;\r\n\r\n for (const p of voxelPoints) {\r\n avg.x += p.x;\r\n avg.y += p.y;\r\n avg.z += p.z;\r\n\r\n if (p.r !== undefined) {\r\n hasColor = true;\r\n r += p.r;\r\n g += p.g ?? 0;\r\n b += p.b ?? 0;\r\n }\r\n\r\n if (p.intensity !== undefined) {\r\n hasIntensity = true;\r\n intensity += p.intensity;\r\n }\r\n }\r\n\r\n const count = voxelPoints.length;\r\n avg.x /= count;\r\n avg.y /= count;\r\n avg.z /= count;\r\n\r\n if (hasColor) {\r\n avg.r = r / count;\r\n avg.g = g / count;\r\n avg.b = b / count;\r\n }\r\n\r\n if (hasIntensity) {\r\n avg.intensity = intensity / count;\r\n }\r\n\r\n result.push(avg);\r\n }\r\n\r\n return result;\r\n}\r\n","/**\r\n * Reconnection utilities\r\n * @module vue-streaming/utils/reconnect\r\n */\r\n\r\nimport type { ReconnectOptions } from \"../types\";\r\n\r\nexport interface ReconnectState {\r\n attempts: number;\r\n isReconnecting: boolean;\r\n lastAttempt: number | null;\r\n nextAttempt: number | null;\r\n}\r\n\r\n/**\r\n * Create a reconnection manager with exponential backoff\r\n */\r\nexport function createReconnectManager(options: ReconnectOptions) {\r\n const state: ReconnectState = {\r\n attempts: 0,\r\n isReconnecting: false,\r\n lastAttempt: null,\r\n nextAttempt: null,\r\n };\r\n\r\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\r\n\r\n const {\r\n maxAttempts,\r\n delay,\r\n delayMax = delay * 10,\r\n backoffMultiplier = 1.5,\r\n onAttempt,\r\n onSuccess,\r\n onFailure,\r\n } = options;\r\n\r\n /**\r\n * Calculate delay with exponential backoff\r\n */\r\n function calculateDelay(): number {\r\n const baseDelay = delay * Math.pow(backoffMultiplier, state.attempts);\r\n return Math.min(baseDelay, delayMax);\r\n }\r\n\r\n /**\r\n * Schedule a reconnection attempt\r\n */\r\n function scheduleReconnect(connectFn: () => Promise<boolean>): void {\r\n if (state.isReconnecting || state.attempts >= maxAttempts) {\r\n if (state.attempts >= maxAttempts) {\r\n onFailure?.();\r\n }\r\n return;\r\n }\r\n\r\n state.isReconnecting = true;\r\n state.attempts++;\r\n state.lastAttempt = Date.now();\r\n\r\n const currentDelay = calculateDelay();\r\n state.nextAttempt = Date.now() + currentDelay;\r\n\r\n onAttempt?.(state.attempts, maxAttempts);\r\n\r\n timeoutId = setTimeout(async () => {\r\n try {\r\n const success = await connectFn();\r\n if (success) {\r\n reset();\r\n onSuccess?.();\r\n } else {\r\n state.isReconnecting = false;\r\n scheduleReconnect(connectFn);\r\n }\r\n } catch {\r\n state.isReconnecting = false;\r\n scheduleReconnect(connectFn);\r\n }\r\n }, currentDelay);\r\n }\r\n\r\n /**\r\n * Reset reconnection state\r\n */\r\n function reset(): void {\r\n state.attempts = 0;\r\n state.isReconnecting = false;\r\n state.lastAttempt = null;\r\n state.nextAttempt = null;\r\n\r\n if (timeoutId) {\r\n clearTimeout(timeoutId);\r\n timeoutId = null;\r\n }\r\n }\r\n\r\n /**\r\n * Cancel pending reconnection\r\n */\r\n function cancel(): void {\r\n state.isReconnecting = false;\r\n state.nextAttempt = null;\r\n\r\n if (timeoutId) {\r\n clearTimeout(timeoutId);\r\n timeoutId = null;\r\n }\r\n }\r\n\r\n /**\r\n * Check if should attempt reconnection\r\n */\r\n function shouldReconnect(): boolean {\r\n return state.attempts < maxAttempts;\r\n }\r\n\r\n return {\r\n state,\r\n scheduleReconnect,\r\n reset,\r\n cancel,\r\n shouldReconnect,\r\n calculateDelay,\r\n };\r\n}\r\n\r\n/**\r\n * Simple delay utility\r\n */\r\nexport function delay(ms: number): Promise<void> {\r\n return new Promise((resolve) => setTimeout(resolve, ms));\r\n}\r\n\r\n/**\r\n * Retry a function with exponential backoff\r\n */\r\nexport async function retryWithBackoff<T>(\r\n fn: () => Promise<T>,\r\n options: {\r\n maxAttempts?: number;\r\n delay?: number;\r\n delayMax?: number;\r\n backoffMultiplier?: number;\r\n onAttempt?: (attempt: number) => void;\r\n } = {},\r\n): Promise<T> {\r\n const {\r\n maxAttempts = 3,\r\n delay: baseDelay = 1000,\r\n delayMax = 30000,\r\n backoffMultiplier = 2,\r\n onAttempt,\r\n } = options;\r\n\r\n let lastError: Error | null = null;\r\n\r\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\r\n try {\r\n onAttempt?.(attempt);\r\n return await fn();\r\n } catch (error) {\r\n lastError = error instanceof Error ? error : new Error(String(error));\r\n\r\n if (attempt < maxAttempts) {\r\n const waitTime = Math.min(\r\n baseDelay * Math.pow(backoffMultiplier, attempt - 1),\r\n delayMax,\r\n );\r\n await delay(waitTime);\r\n }\r\n }\r\n }\r\n\r\n throw lastError;\r\n}\r\n"],"names":["DEFAULT_BBOX_COLORS","DEFAULT_BBOX_COLORS_BY_ID","DEFAULT_CLASS_LABELS","BBOX_COLORS","BBOX_COLORS_BY_ID","CLASS_LABELS","configureBBox","config","resetBBoxConfig","getBBoxColors","getBBoxColorsByClassId","getClassLabels","setBBoxColor","label","color","setBBoxColorByClassId","classId","setClassLabel","getColorForLabel","normalizedLabel","getColorForClassId","getLabelForClassId","parseArrayBoundingBox","arr","index","parseArrayBoundingBoxes","data","parseArrayBboxFormat","personId","normalizeBboxes","bboxes","bbox","b","center","dimensions","rotation","bbox3DToDetection","bboxesToDetectionFrame","calculateIoU3D","box1","box2","c1","d1","c2","d2","x1","y1","z1","x2","y2","z2","intersectionWidth","intersectionHeight","intersectionDepth","intersectionVolume","volume1","volume2","unionVolume","filterByConfidence","threshold","nms3D","iouThreshold","sorted","a","kept","suppressed","i","j","MAGIC_BYTES","detectPointCloudFormat","bytes","matchMagicBytes","magic","parsePointCloudBinary","buffer","points","dataView","byteLength","decodePCLDFormat","offset","pointCount","bytesPerPoint","possibleCount","formatIndicator","x","z","point","extraValue","view","numPoints","flags","hasColor","hasIntensity","headerSize","y","parsePointCloudJSON","text","first","p","pointsArray","calculateBounds","minX","maxX","minY","maxY","minZ","maxZ","transformPoints","scale","downsamplePointCloud","voxelSize","voxelMap","vx","vy","vz","key","result","voxelPoints","avg","r","g","intensity","count","createReconnectManager","options","state","timeoutId","maxAttempts","delay","delayMax","backoffMultiplier","onAttempt","onSuccess","onFailure","calculateDelay","baseDelay","scheduleReconnect","connectFn","currentDelay","reset","cancel","shouldReconnect","ms","resolve","retryWithBackoff","fn","lastError","attempt","error","waitTime"],"mappings":"AA8BO,MAAMA,IAA8C;AAAA,EACzD,QAAQ;AAAA,EACR,KAAK;AAAA,EACL,OAAO;AAAA,EACP,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,KAAK;AAAA,EACL,YAAY;AAAA,EACZ,SAAS;AAAA,EACT,SAAS;AACX,GAKaC,IAAoD;AAAA,EAC/D,GAAG;AAAA;AAAA,EACH,GAAG;AAAA;AAAA,EACH,GAAG;AAAA;AAAA,EACH,GAAG;AAAA;AAAA,EACH,GAAG;AAAA;AAAA,EACH,GAAG;AAAA;AAAA,EACH,GAAG;AAAA;AAAA,EACH,GAAG;AAAA;AAAA,EACH,GAAG;AAAA;AAAA,EACH,GAAG;AAAA;AAAA,EACH,IAAI;AAAA;AAAA,EACJ,IAAI;AAAA;AAAA,EACJ,IAAI;AAAA;AAAA,EACJ,IAAI;AAAA;AAAA,EACJ,IAAI;AAAA;AAAA,EACJ,IAAI;AAAA;AAAA,EACJ,IAAI;AAAA;AACN,GAKaC,IAA+C;AAAA,EAC1D,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,GAAG;AAAA,EACH,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAUO,IAAIC,IAAsC,EAAE,GAAGH,EAAA,GAM3CI,IAA4C;AAAA,EACrD,GAAGH;AACL,GAMWI,IAAuC,EAAE,GAAGH,EAAA;AA8ChD,SAASI,EAAcC,GAA0B;AACtD,EAAIA,EAAO,WACTJ,IAAc,EAAE,GAAGA,GAAa,GAAGI,EAAO,OAAA,IAExCA,EAAO,oBACTH,IAAoB,EAAE,GAAGA,GAAmB,GAAGG,EAAO,gBAAA,IAEpDA,EAAO,gBACTF,IAAe,EAAE,GAAGA,GAAc,GAAGE,EAAO,YAAA;AAEhD;AAaO,SAASC,IAAwB;AACtC,EAAAL,IAAc,EAAE,GAAGH,EAAA,GACnBI,IAAoB,EAAE,GAAGH,EAAA,GACzBI,IAAe,EAAE,GAAGH,EAAA;AACtB;AAOO,SAASO,IAAwC;AACtD,SAAO,EAAE,GAAGN,EAAA;AACd;AAOO,SAASO,IAAiD;AAC/D,SAAO,EAAE,GAAGN,EAAA;AACd;AAOO,SAASO,IAAyC;AACvD,SAAO,EAAE,GAAGN,EAAA;AACd;AAQO,SAASO,EAAaC,GAAeC,GAAqB;AAC/D,EAAAX,EAAYU,EAAM,YAAA,CAAa,IAAIC;AACrC;AAQO,SAASC,EAAsBC,GAAiBF,GAAqB;AAC1E,EAAAV,EAAkBY,CAAO,IAAIF;AAC/B;AAQO,SAASG,EAAcD,GAAiBH,GAAqB;AAClE,EAAAR,EAAaW,CAAO,IAAIH;AAC1B;AASO,SAASK,EAAiBL,GAAuB;AACtD,QAAMM,IAAkBN,EAAM,YAAA;AAC9B,SAAOV,EAAYgB,CAAe,KAAKhB,EAAY;AACrD;AAKO,SAASiB,EAAmBJ,GAAyB;AAC1D,SAAOZ,EAAkBY,CAAO,KAAK;AACvC;AAKO,SAASK,EAAmBL,GAAyB;AAC1D,SAAOX,EAAaW,CAAO,KAAK,SAASA,CAAO;AAClD;AAUO,SAASM,EACdC,GACAC,IAAgB,GACD;AACf,QAAMR,IAAUO,EAAI,CAAC,KAAK;AAE1B,SAAO;AAAA,IACL,IAAIC;AAAA,IACJ,OAAOH,EAAmBL,CAAO;AAAA,IACjC,QAAQ;AAAA,MACN,GAAGO,EAAI,CAAC,KAAK;AAAA,MACb,GAAGA,EAAI,CAAC,KAAK;AAAA,MACb,GAAGA,EAAI,CAAC,KAAK;AAAA,IAAA;AAAA,IAEf,YAAY;AAAA,MACV,OAAOA,EAAI,CAAC,KAAK;AAAA,MACjB,QAAQA,EAAI,CAAC,KAAK;AAAA,MAClB,OAAOA,EAAI,CAAC,KAAK;AAAA,IAAA;AAAA,IAEnB,UAAU;AAAA,MACR,GAAG;AAAA,MACH,GAAGA,EAAI,CAAC,KAAK;AAAA,MACb,GAAG;AAAA,IAAA;AAAA,IAEL,YAAYA,EAAI,CAAC,KAAK;AAAA,IACtB,OAAOH,EAAmBJ,CAAO;AAAA,EAAA;AAErC;AAKO,SAASS,EAAwBC,GAAmC;AACzE,SAAOA,EAAK,IAAI,CAACH,GAAKC,MAAUF,EAAsBC,GAAKC,CAAK,CAAC;AACnE;AAMO,SAASG,EAAqBD,GAAmC;AACtE,SAAOA,EAAK,IAAI,CAACH,GAAKC,MAAU;AAC9B,UAAMI,IAAW,KAAK,MAAML,EAAI,CAAC,KAAKC,CAAK;AAE3C,WAAO;AAAA,MACL,IAAII;AAAA,MACJ,OAAO,UAAUA,CAAQ;AAAA,MACzB,QAAQ;AAAA,QACN,GAAGL,EAAI,CAAC,KAAK;AAAA,QACb,GAAGA,EAAI,CAAC,KAAK;AAAA,QACb,GAAGA,EAAI,CAAC,KAAK;AAAA,MAAA;AAAA,MAEf,YAAY;AAAA,QACV,OAAO,KAAK,IAAIA,EAAI,CAAC,KAAK,CAAC;AAAA,QAC3B,QAAQ,KAAK,IAAIA,EAAI,CAAC,KAAK,CAAC;AAAA,QAC5B,OAAO,KAAK,IAAIA,EAAI,CAAC,KAAK,CAAC;AAAA,MAAA;AAAA,MAE7B,UAAU;AAAA,QACR,GAAG;AAAA,QACH,GAAGA,EAAI,CAAC,KAAK;AAAA,QACb,GAAG;AAAA,MAAA;AAAA,MAEL,YAAYA,EAAI,CAAC,KAAK;AAAA,MACtB,OAAO;AAAA,IAAA;AAAA,EAEX,CAAC;AACH;AAKO,SAASM,EAAgBC,GAAoC;AAClE,SAAOA,EAAO,IAAI,CAACC,GAAeP,MAAkB;AAClD,UAAMQ,IAAID,GAEJE,IAAUD,EAAE,UAAkD;AAAA,MAClE,GAAIA,EAAE,KAAiBA,EAAE,WAAsB;AAAA,MAC/C,GAAIA,EAAE,KAAiBA,EAAE,WAAsB;AAAA,MAC/C,GAAIA,EAAE,KAAiBA,EAAE,WAAsB;AAAA,IAAA,GAG3CE,IAAcF,EAAE,cAKnBA,EAAE,QAA6D;AAAA,MAC9D,OAAQA,EAAE,SAAqBA,EAAE,KAAgB;AAAA,MACjD,QAASA,EAAE,UAAsBA,EAAE,KAAgB;AAAA,MACnD,OACGA,EAAE,SAAqBA,EAAE,KAAiBA,EAAE,UAAqB;AAAA,IAAA,GAGlEG,IAAYH,EAAE,YAAoD;AAAA,MACtE,GAAIA,EAAE,QAAoBA,EAAE,MAAiB;AAAA,MAC7C,GAAIA,EAAE,QAAoBA,EAAE,MAAkBA,EAAE,OAAkB;AAAA,MAClE,GAAIA,EAAE,QAAoBA,EAAE,MAAiB;AAAA,IAAA;AAG/C,WAAO;AAAA,MACL,IAAKA,EAAE,MAA0BR;AAAA,MACjC,OACGQ,EAAE,SAAqBA,EAAE,SAAqBA,EAAE;AAAA,MACnD,QAAAC;AAAA,MACA,YAAAC;AAAA,MACA,UAAAC;AAAA,MACA,OAAOH,EAAE;AAAA,MACT,YACGA,EAAE,cAA0BA,EAAE,SAAqBA,EAAE;AAAA,IAAA;AAAA,EAE5D,CAAC;AACH;AAKO,SAASI,EAAkBL,GAAgC;AAChE,SAAO;AAAA,IACL,IAAIA,EAAK;AAAA,IACT,OAAOA,EAAK,SAAS;AAAA,IACrB,YAAYA,EAAK,cAAc;AAAA,IAC/B,aAAa;AAAA,MACX,GAAGA,EAAK,OAAO,KAAKA,EAAK,WAAW,SAAS,KAAK;AAAA,MAClD,GAAGA,EAAK,OAAO,KAAKA,EAAK,WAAW,UAAU,KAAK;AAAA,MACnD,OAAOA,EAAK,WAAW,SAAS;AAAA,MAChC,QAAQA,EAAK,WAAW,UAAU;AAAA,IAAA;AAAA,IAEpC,SAAS,OAAOA,EAAK,EAAE;AAAA,EAAA;AAE3B;AAKO,SAASM,EAAuBP,GAGrC;AACA,SAAO;AAAA,IACL,YAAYA,EAAO,IAAIM,CAAiB;AAAA,IACxC,WAAW,KAAK,IAAA;AAAA,EAAI;AAExB;AAKO,SAASE,EACdC,GACAC,GACQ;AACR,QAAM,EAAE,QAAQC,GAAI,YAAYC,MAAOH,GACjC,EAAE,QAAQI,GAAI,YAAYC,MAAOJ,GAGjCK,IAAK,KAAK,IAAIJ,EAAG,IAAIC,EAAG,QAAQ,GAAGC,EAAG,IAAIC,EAAG,QAAQ,CAAC,GACtDE,IAAK,KAAK,IAAIL,EAAG,IAAIC,EAAG,SAAS,GAAGC,EAAG,IAAIC,EAAG,SAAS,CAAC,GACxDG,IAAK,KAAK,IAAIN,EAAG,IAAIC,EAAG,QAAQ,GAAGC,EAAG,IAAIC,EAAG,QAAQ,CAAC,GAEtDI,IAAK,KAAK,IAAIP,EAAG,IAAIC,EAAG,QAAQ,GAAGC,EAAG,IAAIC,EAAG,QAAQ,CAAC,GACtDK,IAAK,KAAK,IAAIR,EAAG,IAAIC,EAAG,SAAS,GAAGC,EAAG,IAAIC,EAAG,SAAS,CAAC,GACxDM,IAAK,KAAK,IAAIT,EAAG,IAAIC,EAAG,QAAQ,GAAGC,EAAG,IAAIC,EAAG,QAAQ,CAAC,GAEtDO,IAAoB,KAAK,IAAI,GAAGH,IAAKH,CAAE,GACvCO,IAAqB,KAAK,IAAI,GAAGH,IAAKH,CAAE,GACxCO,IAAoB,KAAK,IAAI,GAAGH,IAAKH,CAAE,GAEvCO,IACJH,IAAoBC,IAAqBC,GAGrCE,IAAUb,EAAG,QAAQA,EAAG,SAASA,EAAG,OACpCc,IAAUZ,EAAG,QAAQA,EAAG,SAASA,EAAG,OACpCa,IAAcF,IAAUC,IAAUF;AAExC,SAAOG,IAAc,IAAIH,IAAqBG,IAAc;AAC9D;AAKO,SAASC,EACd5B,GACA6B,GACiB;AACjB,SAAO7B,EAAO,OAAO,CAACC,OAAUA,EAAK,cAAc,MAAM4B,CAAS;AACpE;AAKO,SAASC,EACd9B,GACA+B,IAAuB,KACN;AACjB,MAAI/B,EAAO,WAAW,EAAG,QAAO,CAAA;AAGhC,QAAMgC,IAAS,CAAC,GAAGhC,CAAM,EAAE;AAAA,IACzB,CAACiC,GAAG/B,OAAOA,EAAE,cAAc,MAAM+B,EAAE,cAAc;AAAA,EAAA,GAE7CC,IAAwB,CAAA,GACxBC,wBAAiB,IAAA;AAEvB,WAASC,IAAI,GAAGA,IAAIJ,EAAO,QAAQI;AACjC,QAAI,CAAAD,EAAW,IAAIC,CAAC,GAEpB;AAAA,MAAAF,EAAK,KAAKF,EAAOI,CAAC,CAAC;AAEnB,eAASC,IAAID,IAAI,GAAGC,IAAIL,EAAO,QAAQK,KAAK;AAC1C,YAAIF,EAAW,IAAIE,CAAC,EAAG;AAGvB,QADY7B,EAAewB,EAAOI,CAAC,GAAGJ,EAAOK,CAAC,CAAC,KACpCN,KACTI,EAAW,IAAIE,CAAC;AAAA,MAEpB;AAAA;AAGF,SAAOH;AACT;ACreA,MAAMI,IAAc;AAAA,EAClB,OAAO,CAAC,IAAM,IAAM,IAAM,IAAM,EAAI;AAAA;AAAA,EACpC,eAAe,CAAC,IAAM,IAAM,IAAM,EAAI;AAAA;AAAA,EACtC,KAAK,CAAC,KAAM,KAAM,GAAI;AAAA;AAAA,EACtB,KAAK,CAAC,IAAM,IAAM,IAAM,IAAM,IAAM,EAAI;AAAA;AAC1C;AAKO,SAASC,EACd3C,GACkB;AAClB,MAAI,OAAOA,KAAS;AAClB,QAAI;AACF,kBAAK,MAAMA,CAAI,GACR;AAAA,IACT,QAAQ;AACN,UAAIA,EAAK,WAAW,KAAK,EAAG,QAAO;AACnC,UAAIA,EAAK,WAAW,QAAQ,EAAG,QAAO;AAAA,IACxC;AAGF,QAAM4C,IAAQ,IAAI;AAAA,IAChB5C,aAAgB,cACZA,IACAA,aAAgB,aACdA,EAAK,OAAO,MAAMA,EAAK,YAAYA,EAAK,aAAaA,EAAK,UAAU,IACpE,IAAI,cAAc,OAAOA,CAAI,EAAE;AAAA,EAAA;AAGvC,SAAI6C,EAAgBD,GAAOF,EAAY,KAAK,IAAU,UAClDG,EAAgBD,GAAOF,EAAY,aAAa,IAAU,kBAC1DG,EAAgBD,GAAOF,EAAY,GAAG,IAAU,QAChDG,EAAgBD,GAAOF,EAAY,GAAG,IAAU,QAGhDE,EAAM,SAAS,OAAO,IAAU,gBAChCA,EAAM,SAAS,OAAO,IAAU,oBAE7B;AACT;AAEA,SAASC,EAAgB7C,GAAkB8C,GAA0B;AACnE,MAAI9C,EAAK,SAAS8C,EAAM,OAAQ,QAAO;AACvC,WAAS,IAAI,GAAG,IAAIA,EAAM,QAAQ;AAChC,QAAI9C,EAAK,CAAC,MAAM8C,EAAM,CAAC,EAAG,QAAO;AAEnC,SAAO;AACT;AAKO,SAASC,EAAsBC,GAAgC;AACpE,QAAMC,IAAoB,CAAA,GACpBL,IAAQ,IAAI,WAAWI,CAAM,GAC7BE,IAAW,IAAI,SAASF,CAAM,GAC9BG,IAAaH,EAAO;AAG1B,MAAIG,KAAc,KACF,OAAO;AAAA,IACnBP,EAAM,CAAC;AAAA,IACPA,EAAM,CAAC;AAAA,IACPA,EAAM,CAAC;AAAA,IACPA,EAAM,CAAC;AAAA,IACPA,EAAM,CAAC;AAAA,EAAA,MAEK;AACZ,mBAAQ;AAAA,MACN;AAAA,IAAA,GAEK,CAAA;AAKX,MAAIO,KAAc,KACF,OAAO,aAAaP,EAAM,CAAC,GAAGA,EAAM,CAAC,GAAGA,EAAM,CAAC,GAAGA,EAAM,CAAC,CAAC,MAC1D;AACZ,WAAOQ,EAAiBJ,CAAM;AAKlC,MAAIK,IAAS,GACTC,IAAa,GACbC,IAAgB;AAGpB,MAAIJ,KAAc,GAAG;AACnB,UAAMK,IAAgBN,EAAS,UAAU,GAAG,EAAI;AAChD,QACEM,IAAgB,KAChBA,IAAgBL,IAAa,MAC7BK,IAAgB,QAEhBF,IAAaE,GACbH,IAAS,GAELF,KAAc,IAAG;AACnB,YAAMM,IAAkBP,EAAS,UAAU,GAAG,EAAI;AAClD,MAAIO,MAAoB,KACtBF,IAAgB,IAChBF,IAAS,KACAI,MAAoB,KAC7BF,IAAgB,IAChBF,IAAS,KACAI,MAAoB,MAC7BF,IAAgB,IAChBF,IAAS;AAAA,IAEb;AAAA,EAEJ;AAGA,EAAIC,MAAe,MACbH,IAAa,OAAO,KACtBI,IAAgB,IAChBD,IAAaH,IAAa,MACjBA,IAAa,OAAO,KAC7BI,IAAgB,IAChBD,IAAaH,IAAa,MACjBA,IAAa,OAAO,KAC7BI,IAAgB,IAChBD,IAAaH,IAAa,OAE1BI,IAAgB,IAChBD,IAAa,KAAK,MAAMH,IAAa,EAAE;AAK3C,WAASX,IAAI,GAAGA,IAAIc,KAAcD,IAASE,KAAiBJ,GAAYX,KAAK;AAC3E,QAAI;AACF,YAAMkB,IAAIR,EAAS,WAAWG,GAAQ,EAAI,GACpC,IAAIH,EAAS,WAAWG,IAAS,GAAG,EAAI,GACxCM,IAAIT,EAAS,WAAWG,IAAS,GAAG,EAAI;AAE9C,UACE,CAAC,OAAO,SAASK,CAAC,KAClB,CAAC,OAAO,SAAS,CAAC,KAClB,CAAC,OAAO,SAASC,CAAC,KAClB,KAAK,IAAID,CAAC,IAAI,OACd,KAAK,IAAI,CAAC,IAAI,OACd,KAAK,IAAIC,CAAC,IAAI,KACd;AACA,QAAAN,KAAUE;AACV;AAAA,MACF;AAEA,YAAMK,IAAiB,EAAE,GAAAF,GAAG,GAAG,GAAAC,EAAA;AAE/B,UAAIJ,MAAkB,IAAI;AACxB,cAAMM,IAAaX,EAAS,WAAWG,IAAS,IAAI,EAAI;AACxD,QAAI,OAAO,SAASQ,CAAU,KAAKA,KAAc,KAAKA,KAAc,IAClED,EAAM,YAAYC,KAElBD,EAAM,IAAIV,EAAS,SAASG,IAAS,EAAE,IAAI,KAC3CO,EAAM,IAAIV,EAAS,SAASG,IAAS,EAAE,IAAI,KAC3CO,EAAM,IAAIV,EAAS,SAASG,IAAS,EAAE,IAAI;AAAA,MAE/C,MAAA,CAAWE,MAAkB,MAC3BK,EAAM,IAAIV,EAAS,SAASG,IAAS,EAAE,IAAI,KAC3CO,EAAM,IAAIV,EAAS,SAASG,IAAS,EAAE,IAAI,KAC3CO,EAAM,IAAIV,EAAS,SAASG,IAAS,EAAE,IAAI,OAClCE,MAAkB,OAC3BK,EAAM,IAAIV,EAAS,WAAWG,IAAS,IAAI,EAAI,GAC/CO,EAAM,IAAIV,EAAS,WAAWG,IAAS,IAAI,EAAI,GAC/CO,EAAM,IAAIV,EAAS,WAAWG,IAAS,IAAI,EAAI;AAGjD,MAAAJ,EAAO,KAAKW,CAAK;AAAA,IACnB,QAAQ;AAAA,IAER;AAEA,IAAAP,KAAUE;AAAA,EACZ;AAEA,SAAON;AACT;AAKA,SAASG,EAAiBJ,GAAgC;AACxD,QAAMJ,IAAQ,IAAI,WAAWI,CAAM,GAC7Bc,IAAO,IAAI,SAASd,CAAM,GAC1BC,IAAoB,CAAA,GAEpBc,IAAYD,EAAK,UAAU,GAAG,EAAI,GAClCE,IAAQF,EAAK,UAAU,IAAI,EAAI,GAE/BG,KAAYD,IAAQ,OAAU,GAC9BE,KAAgBF,IAAQ,OAAU;AAExC,MAAIT,IAAgB;AACpB,EAAIU,MAAUV,KAAiB,IAC3BW,MAAcX,KAAiB;AAEnC,QAAMY,IAAa;AAEnB,WAAS3B,IAAI,GAAGA,IAAIuB,GAAWvB,KAAK;AAClC,QAAIa,IAASc,IAAa3B,IAAIe;AAE9B,UAAMG,IAAII,EAAK,WAAWT,GAAQ,EAAI,GAChCe,IAAIN,EAAK,WAAWT,IAAS,GAAG,EAAI,GACpCM,IAAIG,EAAK,WAAWT,IAAS,GAAG,EAAI;AAG1C,QAFAA,KAAU,IAEN,CAAC,OAAO,SAASK,CAAC,KAAK,CAAC,OAAO,SAASU,CAAC,KAAK,CAAC,OAAO,SAAST,CAAC;AAClE;AAEF,UAAMC,IAAiB,EAAE,GAAAF,GAAG,GAAAU,GAAG,GAAAT,EAAA;AAE/B,IAAIM,MACFL,EAAM,IAAIhB,EAAMS,CAAM,IAAI,KAC1BO,EAAM,IAAIhB,EAAMS,IAAS,CAAC,IAAI,KAC9BO,EAAM,IAAIhB,EAAMS,IAAS,CAAC,IAAI,KAC9BA,KAAU,IAGRa,MACFN,EAAM,YAAYE,EAAK,WAAWT,GAAQ,EAAI,IAGhDJ,EAAO,KAAKW,CAAK;AAAA,EACnB;AAEA,SAAOX;AACT;AAKO,SAASoB,EAAoBC,GAAgC;AAClE,MAAI;AACF,UAAMtE,IAAO,KAAK,MAAMsE,CAAI;AAE5B,QAAI,MAAM,QAAQtE,CAAI,GAAG;AACvB,UAAIA,EAAK,WAAW,EAAG,QAAO,CAAA;AAE9B,YAAMuE,IAAQvE,EAAK,CAAC;AAGpB,UAAI,MAAM,QAAQuE,CAAK;AACrB,eAAOvE,EAAK,IAAI,CAACH,OAAmB;AAAA,UAClC,GAAGA,EAAI,CAAC,KAAK;AAAA,UACb,GAAGA,EAAI,CAAC,KAAK;AAAA,UACb,GAAGA,EAAI,CAAC,KAAK;AAAA,UACb,GAAGA,EAAI,CAAC;AAAA,UACR,GAAGA,EAAI,CAAC;AAAA,UACR,GAAGA,EAAI,CAAC;AAAA,UACR,WAAWA,EAAI,CAAC;AAAA,QAAA,EAChB;AAIJ,UAAI,OAAO0E,KAAU,YAAYA,MAAU;AACzC,eAAOvE,EAAK,IAAI,CAACwE,OAA+B;AAAA,UAC9C,GAAGA,EAAE,KAAKA,EAAE,KAAK;AAAA,UACjB,GAAGA,EAAE,KAAKA,EAAE,KAAK;AAAA,UACjB,GAAGA,EAAE,KAAKA,EAAE,KAAK;AAAA,UACjB,GAAGA,EAAE,KAAKA,EAAE,KAAKA,EAAE;AAAA,UACnB,GAAGA,EAAE,KAAKA,EAAE,KAAKA,EAAE;AAAA,UACnB,GAAGA,EAAE,KAAKA,EAAE,KAAKA,EAAE;AAAA,UACnB,WAAWA,EAAE,aAAaA,EAAE,KAAKA,EAAE;AAAA,QAAA,EACnC;AAAA,IAEN;AAGA,QAAIxE,KAAQ,OAAOA,KAAS,UAAU;AACpC,YAAMyE,IAAczE,EAAK,UAAUA,EAAK,QAAQA,EAAK;AACrD,UAAI,MAAM,QAAQyE,CAAW;AAC3B,eAAOJ,EAAoB,KAAK,UAAUI,CAAW,CAAC;AAAA,IAE1D;AAEA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAKO,SAASC,EACdzB,GAC6B;AAC7B,MAAIA,EAAO,WAAW;AACpB,WAAO;AAAA,MACL,KAAK,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAA;AAAA,MACtB,KAAK,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAA;AAAA,IAAE;AAI5B,MAAI0B,IAAO,OACTC,IAAO,QACLC,IAAO,OACTC,IAAO,QACLC,IAAO,OACTC,IAAO;AAET,aAAWR,KAAKvB;AACd,IAAIuB,EAAE,IAAIG,MAAMA,IAAOH,EAAE,IACrBA,EAAE,IAAII,MAAMA,IAAOJ,EAAE,IACrBA,EAAE,IAAIK,MAAMA,IAAOL,EAAE,IACrBA,EAAE,IAAIM,MAAMA,IAAON,EAAE,IACrBA,EAAE,IAAIO,MAAMA,IAAOP,EAAE,IACrBA,EAAE,IAAIQ,MAAMA,IAAOR,EAAE;AAG3B,SAAO;AAAA,IACL,KAAK,EAAE,GAAGG,GAAM,GAAGE,GAAM,GAAGE,EAAA;AAAA,IAC5B,KAAK,EAAE,GAAGH,GAAM,GAAGE,GAAM,GAAGE,EAAA;AAAA,EAAK;AAErC;AAKO,SAASC,EACdhC,GACAiC,IAAgB,GAChB7B,IAA8C,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAA,GACpD;AACX,SAAI6B,MAAU,KAAK7B,EAAO,MAAM,KAAKA,EAAO,MAAM,KAAKA,EAAO,MAAM,IAC3DJ,IAGFA,EAAO,IAAI,CAACuB,OAAO;AAAA,IACxB,GAAGA;AAAA,IACH,GAAGA,EAAE,IAAIU,IAAQ7B,EAAO;AAAA,IACxB,GAAGmB,EAAE,IAAIU,IAAQ7B,EAAO;AAAA,IACxB,GAAGmB,EAAE,IAAIU,IAAQ7B,EAAO;AAAA,EAAA,EACxB;AACJ;AAKO,SAAS8B,GACdlC,GACAmC,GACW;AACX,MAAIA,KAAa,EAAG,QAAOnC;AAE3B,QAAMoC,wBAAe,IAAA;AAErB,aAAWzB,KAASX,GAAQ;AAC1B,UAAMqC,IAAK,KAAK,MAAM1B,EAAM,IAAIwB,CAAS,GACnCG,IAAK,KAAK,MAAM3B,EAAM,IAAIwB,CAAS,GACnCI,IAAK,KAAK,MAAM5B,EAAM,IAAIwB,CAAS,GACnCK,IAAM,GAAGH,CAAE,IAAIC,CAAE,IAAIC,CAAE;AAE7B,IAAKH,EAAS,IAAII,CAAG,KACnBJ,EAAS,IAAII,GAAK,EAAE,GAEtBJ,EAAS,IAAII,CAAG,EAAG,KAAK7B,CAAK;AAAA,EAC/B;AAEA,QAAM8B,IAAoB,CAAA;AAE1B,aAAWC,KAAeN,EAAS,UAAU;AAE3C,UAAMO,IAAe,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAA;AACtC,QAAI3B,IAAW,IACX4B,IAAI,GACNC,IAAI,GACJxF,IAAI,GACFyF,IAAY,GACZ7B,IAAe;AAEnB,eAAWM,KAAKmB;AACd,MAAAC,EAAI,KAAKpB,EAAE,GACXoB,EAAI,KAAKpB,EAAE,GACXoB,EAAI,KAAKpB,EAAE,GAEPA,EAAE,MAAM,WACVP,IAAW,IACX4B,KAAKrB,EAAE,GACPsB,KAAKtB,EAAE,KAAK,GACZlE,KAAKkE,EAAE,KAAK,IAGVA,EAAE,cAAc,WAClBN,IAAe,IACf6B,KAAavB,EAAE;AAInB,UAAMwB,IAAQL,EAAY;AAC1B,IAAAC,EAAI,KAAKI,GACTJ,EAAI,KAAKI,GACTJ,EAAI,KAAKI,GAEL/B,MACF2B,EAAI,IAAIC,IAAIG,GACZJ,EAAI,IAAIE,IAAIE,GACZJ,EAAI,IAAItF,IAAI0F,IAGV9B,MACF0B,EAAI,YAAYG,IAAYC,IAG9BN,EAAO,KAAKE,CAAG;AAAA,EACjB;AAEA,SAAOF;AACT;ACzZO,SAASO,GAAuBC,GAA2B;AAChE,QAAMC,IAAwB;AAAA,IAC5B,UAAU;AAAA,IACV,gBAAgB;AAAA,IAChB,aAAa;AAAA,IACb,aAAa;AAAA,EAAA;AAGf,MAAIC,IAAkD;AAEtD,QAAM;AAAA,IACJ,aAAAC;AAAA,IACA,OAAAC;AAAAA,IACA,UAAAC,IAAWD,IAAQ;AAAA,IACnB,mBAAAE,IAAoB;AAAA,IACpB,WAAAC;AAAA,IACA,WAAAC;AAAA,IACA,WAAAC;AAAA,EAAA,IACET;AAKJ,WAASU,IAAyB;AAChC,UAAMC,IAAYP,IAAQ,KAAK,IAAIE,GAAmBL,EAAM,QAAQ;AACpE,WAAO,KAAK,IAAIU,GAAWN,CAAQ;AAAA,EACrC;AAKA,WAASO,EAAkBC,GAAyC;AAClE,QAAIZ,EAAM,kBAAkBA,EAAM,YAAYE,GAAa;AACzD,MAAIF,EAAM,YAAYE,MACpBM,KAAA,QAAAA;AAEF;AAAA,IACF;AAEA,IAAAR,EAAM,iBAAiB,IACvBA,EAAM,YACNA,EAAM,cAAc,KAAK,IAAA;AAEzB,UAAMa,IAAeJ,EAAA;AACrB,IAAAT,EAAM,cAAc,KAAK,IAAA,IAAQa,GAEjCP,KAAA,QAAAA,EAAYN,EAAM,UAAUE,IAE5BD,IAAY,WAAW,YAAY;AACjC,UAAI;AAEF,QADgB,MAAMW,EAAA,KAEpBE,EAAA,GACAP,KAAA,QAAAA,QAEAP,EAAM,iBAAiB,IACvBW,EAAkBC,CAAS;AAAA,MAE/B,QAAQ;AACN,QAAAZ,EAAM,iBAAiB,IACvBW,EAAkBC,CAAS;AAAA,MAC7B;AAAA,IACF,GAAGC,CAAY;AAAA,EACjB;AAKA,WAASC,IAAc;AACrB,IAAAd,EAAM,WAAW,GACjBA,EAAM,iBAAiB,IACvBA,EAAM,cAAc,MACpBA,EAAM,cAAc,MAEhBC,MACF,aAAaA,CAAS,GACtBA,IAAY;AAAA,EAEhB;AAKA,WAASc,IAAe;AACtB,IAAAf,EAAM,iBAAiB,IACvBA,EAAM,cAAc,MAEhBC,MACF,aAAaA,CAAS,GACtBA,IAAY;AAAA,EAEhB;AAKA,WAASe,IAA2B;AAClC,WAAOhB,EAAM,WAAWE;AAAA,EAC1B;AAEA,SAAO;AAAA,IACL,OAAAF;AAAA,IACA,mBAAAW;AAAA,IACA,OAAAG;AAAA,IACA,QAAAC;AAAA,IACA,iBAAAC;AAAA,IACA,gBAAAP;AAAA,EAAA;AAEJ;AAKO,SAASN,EAAMc,GAA2B;AAC/C,SAAO,IAAI,QAAQ,CAACC,MAAY,WAAWA,GAASD,CAAE,CAAC;AACzD;AAKA,eAAsBE,GACpBC,GACArB,IAMI,IACQ;AACZ,QAAM;AAAA,IACJ,aAAAG,IAAc;AAAA,IACd,OAAOQ,IAAY;AAAA,IACnB,UAAAN,IAAW;AAAA,IACX,mBAAAC,IAAoB;AAAA,IACpB,WAAAC;AAAA,EAAA,IACEP;AAEJ,MAAIsB,IAA0B;AAE9B,WAASC,IAAU,GAAGA,KAAWpB,GAAaoB;AAC5C,QAAI;AACF,aAAAhB,KAAA,QAAAA,EAAYgB,IACL,MAAMF,EAAA;AAAA,IACf,SAASG,GAAO;AAGd,UAFAF,IAAYE,aAAiB,QAAQA,IAAQ,IAAI,MAAM,OAAOA,CAAK,CAAC,GAEhED,IAAUpB,GAAa;AACzB,cAAMsB,IAAW,KAAK;AAAA,UACpBd,IAAY,KAAK,IAAIL,GAAmBiB,IAAU,CAAC;AAAA,UACnDlB;AAAA,QAAA;AAEF,cAAMD,EAAMqB,CAAQ;AAAA,MACtB;AAAA,IACF;AAGF,QAAMH;AACR;"}
@@ -0,0 +1 @@
1
+ .hls-player[data-v-b04c54da]{display:flex;flex-direction:column;background:#000;border-radius:4px;overflow:hidden}.hls-player__video-container[data-v-b04c54da]{position:relative;width:100%;aspect-ratio:16 / 9}.hls-player__video[data-v-b04c54da]{width:100%;height:100%;object-fit:contain}.hls-player__overlay[data-v-b04c54da]{position:absolute;top:0;left:0;right:0;bottom:0;display:flex;align-items:center;justify-content:center;background:#00000080}.hls-player__overlay--error[data-v-b04c54da]{background:#000c}.hls-player__spinner[data-v-b04c54da]{width:48px;height:48px;border:3px solid rgba(255,255,255,.3);border-top-color:#fff;border-radius:50%;animation:spin-b04c54da 1s linear infinite}@keyframes spin-b04c54da{to{transform:rotate(360deg)}}.hls-player__error[data-v-b04c54da]{color:#f48771;text-align:center;padding:16px}.hls-player__controls[data-v-b04c54da]{display:flex;justify-content:space-between;align-items:center;padding:8px 12px;background:#1e1e1e;color:#ccc;font-size:12px}.hls-player__quality[data-v-b04c54da]{display:flex;align-items:center;gap:8px}.hls-player__quality select[data-v-b04c54da]{padding:4px 8px;background:#3c3c3c;border:none;border-radius:3px;color:#ccc;cursor:pointer}.hls-player__stats[data-v-b04c54da]{display:flex;gap:16px;color:#858585}.pointcloud-viewer[data-v-7f487135]{position:relative;width:100%;height:100%;min-height:300px;background:#1e1e1e;border-radius:4px;overflow:hidden}.pointcloud-viewer__canvas[data-v-7f487135]{width:100%;height:100%}.pointcloud-viewer__overlay[data-v-7f487135]{position:absolute;top:0;left:0;right:0;bottom:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;background:#1e1e1ee6;color:#ccc}.pointcloud-viewer__overlay--error[data-v-7f487135]{color:#f48771}.pointcloud-viewer__overlay small[data-v-7f487135]{color:#858585}.pointcloud-viewer__spinner[data-v-7f487135]{width:32px;height:32px;border:3px solid rgba(255,255,255,.3);border-top-color:#fff;border-radius:50%;animation:spin-7f487135 1s linear infinite}@keyframes spin-7f487135{to{transform:rotate(360deg)}}.pointcloud-viewer__stats[data-v-7f487135]{position:absolute;bottom:8px;left:8px;display:flex;gap:12px;padding:4px 8px;background:#0009;border-radius:3px;color:#ccc;font-size:11px}.stream-viewer[data-v-06dc8d20]{display:flex;flex-direction:column;height:100%;min-height:200px;background:#1e1e1e;border-radius:4px;overflow:hidden;font-family:Consolas,Monaco,monospace;font-size:12px}.stream-viewer__header[data-v-06dc8d20]{display:flex;justify-content:space-between;align-items:center;padding:8px 12px;background:#252526;border-bottom:1px solid #3c3c3c}.stream-viewer__stats[data-v-06dc8d20]{display:flex;gap:16px;color:#858585}.stream-viewer__errors[data-v-06dc8d20]{color:#f48771}.stream-viewer__actions[data-v-06dc8d20]{display:flex;gap:8px}.stream-viewer__btn[data-v-06dc8d20]{padding:4px 8px;background:#3c3c3c;border:none;border-radius:3px;color:#ccc;cursor:pointer;font-size:11px}.stream-viewer__btn[data-v-06dc8d20]:hover{background:#4c4c4c}.stream-viewer__btn--active[data-v-06dc8d20]{background:#0e639c}.stream-viewer__content[data-v-06dc8d20]{flex:1;overflow-y:auto;padding:8px}.stream-viewer__entry[data-v-06dc8d20]{display:flex;gap:8px;padding:2px 0;border-bottom:1px solid #2d2d2d}.stream-viewer__entry--error[data-v-06dc8d20]{background:#f487711a}.stream-viewer__entry--info[data-v-06dc8d20]{color:#4ec9b0}.stream-viewer__timestamp[data-v-06dc8d20]{color:#858585;white-space:nowrap}.stream-viewer__data[data-v-06dc8d20]{margin:0;white-space:pre-wrap;word-break:break-all;color:#d4d4d4}.stream-viewer__empty[data-v-06dc8d20]{display:flex;align-items:center;justify-content:center;height:100%;color:#858585}.webrtc-viewer[data-v-3f83a728]{display:flex;flex-direction:column;height:100%;min-height:200px;background:#1e1e1e;border-radius:4px;overflow:hidden}.webrtc-viewer__header[data-v-3f83a728]{display:flex;justify-content:space-between;align-items:center;padding:8px 12px;background:#252526;border-bottom:1px solid #3c3c3c}.webrtc-viewer__status[data-v-3f83a728]{display:flex;align-items:center;gap:8px;color:#ccc;font-size:12px}.webrtc-viewer__indicator[data-v-3f83a728]{width:8px;height:8px;border-radius:50%}.webrtc-viewer__controls[data-v-3f83a728]{display:flex;gap:8px}.webrtc-viewer__btn[data-v-3f83a728]{padding:4px 12px;border:none;border-radius:3px;font-size:12px;cursor:pointer}.webrtc-viewer__btn--connect[data-v-3f83a728]{background:#0e639c;color:#fff}.webrtc-viewer__btn--connect[data-v-3f83a728]:hover{background:#17b}.webrtc-viewer__btn--disconnect[data-v-3f83a728]{background:#5a5a5a;color:#fff}.webrtc-viewer__btn--disconnect[data-v-3f83a728]:hover{background:#6a6a6a}.webrtc-viewer__content[data-v-3f83a728]{flex:1;display:flex;align-items:center;justify-content:center;min-height:100px}.webrtc-viewer__default[data-v-3f83a728]{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;color:#858585;text-align:center;padding:24px}.webrtc-viewer__placeholder[data-v-3f83a728],.webrtc-viewer__loading[data-v-3f83a728],.webrtc-viewer__info[data-v-3f83a728]{display:flex;flex-direction:column;align-items:center;gap:8px}.webrtc-viewer__error[data-v-3f83a728]{color:#f48771}.webrtc-viewer__spinner[data-v-3f83a728]{width:32px;height:32px;border:3px solid rgba(255,255,255,.3);border-top-color:#fff;border-radius:50%;animation:spin-3f83a728 1s linear infinite}@keyframes spin-3f83a728{to{transform:rotate(360deg)}}.webrtc-viewer__info p[data-v-3f83a728]{margin:4px 0;color:#ccc}.webrtc-viewer__footer[data-v-3f83a728]{display:flex;gap:16px;padding:6px 12px;background:#252526;border-top:1px solid #3c3c3c;color:#858585;font-size:11px}