@kelnishi/satmouse-client 0.10.9 → 0.12.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.
@@ -1,5 +1,5 @@
1
1
  // src/utils/action-map.ts
2
- var FULL_AXES = ["tx", "ty", "tz", "rx", "ry", "rz"];
2
+ var FULL_AXES = ["tx", "ty", "tz", "rx", "ry", "rz", "w"];
3
3
  var DEFAULT_ROUTES = [
4
4
  { source: "tx", target: "tx" },
5
5
  { source: "ty", target: "ty" },
@@ -30,31 +30,38 @@ function readAxis(data, axis) {
30
30
  return data.rotation.y;
31
31
  case "rz":
32
32
  return data.rotation.z;
33
+ case "w":
34
+ return data.w ?? 0;
33
35
  default:
34
36
  return 0;
35
37
  }
36
38
  }
37
- function writeAxis(t, r, axis, value) {
39
+ function writeAxis(acc, axis, value) {
38
40
  const isNeg = axis.endsWith("-");
39
41
  const base = axis.replace(/[+-]$/, "");
40
42
  const sign = isNeg ? -1 : 1;
43
+ if (base === "w") {
44
+ acc.w += value * sign;
45
+ return;
46
+ }
41
47
  const group = base[0];
42
48
  const key = base[1];
43
- if (group === "t") t[key] += value * sign;
44
- else r[key] += value * sign;
49
+ if (group === "t") acc.t[key] += value * sign;
50
+ else acc.r[key] += value * sign;
45
51
  }
46
- function applyRoutes(data, routes, scale = 1) {
47
- const t = { x: 0, y: 0, z: 0 };
48
- const r = { x: 0, y: 0, z: 0 };
52
+ function applyRoutes(data, routes, translateScale = 1, rotateScale = 1, wScale = 1) {
53
+ const acc = { t: { x: 0, y: 0, z: 0 }, r: { x: 0, y: 0, z: 0 }, w: 0 };
49
54
  for (const route of routes) {
50
55
  let value = readAxis(data, route.source);
51
56
  if (route.flip) value = -value;
57
+ const targetBase = route.target.replace(/[+-]$/, "");
58
+ const scale = targetBase === "w" ? wScale : targetBase[0] === "t" ? translateScale : rotateScale;
52
59
  value *= scale;
53
- writeAxis(t, r, route.target, value);
60
+ writeAxis(acc, route.target, value);
54
61
  }
55
- return { translation: t, rotation: r, timestamp: data.timestamp, deviceId: data.deviceId };
62
+ return { translation: acc.t, rotation: acc.r, w: acc.w || void 0, timestamp: data.timestamp, deviceId: data.deviceId };
56
63
  }
57
64
 
58
65
  export { DEFAULT_ROUTES, FULL_AXES, applyRoutes, buildRoutes };
59
- //# sourceMappingURL=chunk-RNM322RZ.js.map
60
- //# sourceMappingURL=chunk-RNM322RZ.js.map
66
+ //# sourceMappingURL=chunk-RE4PNORY.js.map
67
+ //# sourceMappingURL=chunk-RE4PNORY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/action-map.ts"],"names":[],"mappings":"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","file":"chunk-RE4PNORY.js","sourcesContent":["import type { SpatialData } from \"../core/types.js\";\n\n/** Axis identifier — full or half */\nexport type InputAxis =\n | \"tx\" | \"ty\" | \"tz\" | \"rx\" | \"ry\" | \"rz\" | \"w\"\n | \"tx+\" | \"ty+\" | \"tz+\" | \"rx+\" | \"ry+\" | \"rz+\" | \"w+\"\n | \"tx-\" | \"ty-\" | \"tz-\" | \"rx-\" | \"ry-\" | \"rz-\" | \"w-\";\n\n/** The 7 full output axes (6DOF + W) */\nexport const FULL_AXES: InputAxis[] = [\"tx\", \"ty\", \"tz\", \"rx\", \"ry\", \"rz\", \"w\"];\n\n/** A single axis route — reads from source, writes to target */\nexport interface AxisRoute {\n source: InputAxis;\n target: InputAxis;\n /** Negate the value (default: false) */\n flip?: boolean;\n}\n\n/** Default 6DOF passthrough */\nexport const DEFAULT_ROUTES: AxisRoute[] = [\n { source: \"tx\", target: \"tx\" },\n { source: \"ty\", target: \"ty\" },\n { source: \"tz\", target: \"tz\" },\n { source: \"rx\", target: \"rx\" },\n { source: \"ry\", target: \"ry\" },\n { source: \"rz\", target: \"rz\" },\n];\n\n/** Build passthrough routes from a device's axis list. Half-axes target their base axis.\n * Negative half-axes (e.g., \"ty-\") get flip: true. */\nexport function buildRoutes(axes: string[]): AxisRoute[] {\n return axes.map((axis) => {\n const base = axis.replace(/[+-]$/, \"\");\n const flip = axis.endsWith(\"-\");\n return { source: axis as InputAxis, target: base as InputAxis, ...(flip && { flip: true }) };\n });\n}\n\n/** Read a value from SpatialData by axis name. Half-axes read the same as the full axis. */\nfunction readAxis(data: SpatialData, axis: InputAxis): number {\n const base = axis.replace(/[+-]$/, \"\");\n switch (base) {\n case \"tx\": return data.translation.x;\n case \"ty\": return data.translation.y;\n case \"tz\": return data.translation.z;\n case \"rx\": return data.rotation.x;\n case \"ry\": return data.rotation.y;\n case \"rz\": return data.rotation.z;\n case \"w\": return data.w ?? 0;\n default: return 0;\n }\n}\n\n/** Accumulator for applyRoutes */\ninterface RouteAccum {\n t: { x: number; y: number; z: number };\n r: { x: number; y: number; z: number };\n w: number;\n}\n\n/** Write a value to accumulators. Half-axis targets: \"tz+\" adds, \"tz-\" subtracts. */\nfunction writeAxis(acc: RouteAccum, axis: InputAxis, value: number): void {\n const isNeg = axis.endsWith(\"-\");\n const base = axis.replace(/[+-]$/, \"\");\n const sign = isNeg ? -1 : 1;\n if (base === \"w\") { acc.w += value * sign; return; }\n const group = base[0] as \"t\" | \"r\";\n const key = base[1] as \"x\" | \"y\" | \"z\";\n if (group === \"t\") acc.t[key] += value * sign;\n else acc.r[key] += value * sign;\n}\n\n/** Apply routes to SpatialData. Multiple routes targeting the same axis accumulate. */\nexport function applyRoutes(data: SpatialData, routes: AxisRoute[], translateScale = 1, rotateScale = 1, wScale = 1): SpatialData {\n const acc: RouteAccum = { t: { x: 0, y: 0, z: 0 }, r: { x: 0, y: 0, z: 0 }, w: 0 };\n\n for (const route of routes) {\n let value = readAxis(data, route.source);\n if (route.flip) value = -value;\n const targetBase = route.target.replace(/[+-]$/, \"\");\n const scale = targetBase === \"w\" ? wScale : targetBase[0] === \"t\" ? translateScale : rotateScale;\n value *= scale;\n writeAxis(acc, route.target, value);\n }\n\n return { translation: acc.t, rotation: acc.r, w: acc.w || undefined, timestamp: data.timestamp, deviceId: data.deviceId };\n}\n"]}
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  // src/utils/action-map.ts
4
- var FULL_AXES = ["tx", "ty", "tz", "rx", "ry", "rz"];
4
+ var FULL_AXES = ["tx", "ty", "tz", "rx", "ry", "rz", "w"];
5
5
  var DEFAULT_ROUTES = [
6
6
  { source: "tx", target: "tx" },
7
7
  { source: "ty", target: "ty" },
@@ -32,34 +32,41 @@ function readAxis(data, axis) {
32
32
  return data.rotation.y;
33
33
  case "rz":
34
34
  return data.rotation.z;
35
+ case "w":
36
+ return data.w ?? 0;
35
37
  default:
36
38
  return 0;
37
39
  }
38
40
  }
39
- function writeAxis(t, r, axis, value) {
41
+ function writeAxis(acc, axis, value) {
40
42
  const isNeg = axis.endsWith("-");
41
43
  const base = axis.replace(/[+-]$/, "");
42
44
  const sign = isNeg ? -1 : 1;
45
+ if (base === "w") {
46
+ acc.w += value * sign;
47
+ return;
48
+ }
43
49
  const group = base[0];
44
50
  const key = base[1];
45
- if (group === "t") t[key] += value * sign;
46
- else r[key] += value * sign;
51
+ if (group === "t") acc.t[key] += value * sign;
52
+ else acc.r[key] += value * sign;
47
53
  }
48
- function applyRoutes(data, routes, scale = 1) {
49
- const t = { x: 0, y: 0, z: 0 };
50
- const r = { x: 0, y: 0, z: 0 };
54
+ function applyRoutes(data, routes, translateScale = 1, rotateScale = 1, wScale = 1) {
55
+ const acc = { t: { x: 0, y: 0, z: 0 }, r: { x: 0, y: 0, z: 0 }, w: 0 };
51
56
  for (const route of routes) {
52
57
  let value = readAxis(data, route.source);
53
58
  if (route.flip) value = -value;
59
+ const targetBase = route.target.replace(/[+-]$/, "");
60
+ const scale = targetBase === "w" ? wScale : targetBase[0] === "t" ? translateScale : rotateScale;
54
61
  value *= scale;
55
- writeAxis(t, r, route.target, value);
62
+ writeAxis(acc, route.target, value);
56
63
  }
57
- return { translation: t, rotation: r, timestamp: data.timestamp, deviceId: data.deviceId };
64
+ return { translation: acc.t, rotation: acc.r, w: acc.w || void 0, timestamp: data.timestamp, deviceId: data.deviceId };
58
65
  }
59
66
 
60
67
  exports.DEFAULT_ROUTES = DEFAULT_ROUTES;
61
68
  exports.FULL_AXES = FULL_AXES;
62
69
  exports.applyRoutes = applyRoutes;
63
70
  exports.buildRoutes = buildRoutes;
64
- //# sourceMappingURL=chunk-JTG5GEIB.cjs.map
65
- //# sourceMappingURL=chunk-JTG5GEIB.cjs.map
71
+ //# sourceMappingURL=chunk-Y75556IA.cjs.map
72
+ //# sourceMappingURL=chunk-Y75556IA.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/action-map.ts"],"names":[],"mappings":"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","file":"chunk-Y75556IA.cjs","sourcesContent":["import type { SpatialData } from \"../core/types.js\";\n\n/** Axis identifier — full or half */\nexport type InputAxis =\n | \"tx\" | \"ty\" | \"tz\" | \"rx\" | \"ry\" | \"rz\" | \"w\"\n | \"tx+\" | \"ty+\" | \"tz+\" | \"rx+\" | \"ry+\" | \"rz+\" | \"w+\"\n | \"tx-\" | \"ty-\" | \"tz-\" | \"rx-\" | \"ry-\" | \"rz-\" | \"w-\";\n\n/** The 7 full output axes (6DOF + W) */\nexport const FULL_AXES: InputAxis[] = [\"tx\", \"ty\", \"tz\", \"rx\", \"ry\", \"rz\", \"w\"];\n\n/** A single axis route — reads from source, writes to target */\nexport interface AxisRoute {\n source: InputAxis;\n target: InputAxis;\n /** Negate the value (default: false) */\n flip?: boolean;\n}\n\n/** Default 6DOF passthrough */\nexport const DEFAULT_ROUTES: AxisRoute[] = [\n { source: \"tx\", target: \"tx\" },\n { source: \"ty\", target: \"ty\" },\n { source: \"tz\", target: \"tz\" },\n { source: \"rx\", target: \"rx\" },\n { source: \"ry\", target: \"ry\" },\n { source: \"rz\", target: \"rz\" },\n];\n\n/** Build passthrough routes from a device's axis list. Half-axes target their base axis.\n * Negative half-axes (e.g., \"ty-\") get flip: true. */\nexport function buildRoutes(axes: string[]): AxisRoute[] {\n return axes.map((axis) => {\n const base = axis.replace(/[+-]$/, \"\");\n const flip = axis.endsWith(\"-\");\n return { source: axis as InputAxis, target: base as InputAxis, ...(flip && { flip: true }) };\n });\n}\n\n/** Read a value from SpatialData by axis name. Half-axes read the same as the full axis. */\nfunction readAxis(data: SpatialData, axis: InputAxis): number {\n const base = axis.replace(/[+-]$/, \"\");\n switch (base) {\n case \"tx\": return data.translation.x;\n case \"ty\": return data.translation.y;\n case \"tz\": return data.translation.z;\n case \"rx\": return data.rotation.x;\n case \"ry\": return data.rotation.y;\n case \"rz\": return data.rotation.z;\n case \"w\": return data.w ?? 0;\n default: return 0;\n }\n}\n\n/** Accumulator for applyRoutes */\ninterface RouteAccum {\n t: { x: number; y: number; z: number };\n r: { x: number; y: number; z: number };\n w: number;\n}\n\n/** Write a value to accumulators. Half-axis targets: \"tz+\" adds, \"tz-\" subtracts. */\nfunction writeAxis(acc: RouteAccum, axis: InputAxis, value: number): void {\n const isNeg = axis.endsWith(\"-\");\n const base = axis.replace(/[+-]$/, \"\");\n const sign = isNeg ? -1 : 1;\n if (base === \"w\") { acc.w += value * sign; return; }\n const group = base[0] as \"t\" | \"r\";\n const key = base[1] as \"x\" | \"y\" | \"z\";\n if (group === \"t\") acc.t[key] += value * sign;\n else acc.r[key] += value * sign;\n}\n\n/** Apply routes to SpatialData. Multiple routes targeting the same axis accumulate. */\nexport function applyRoutes(data: SpatialData, routes: AxisRoute[], translateScale = 1, rotateScale = 1, wScale = 1): SpatialData {\n const acc: RouteAccum = { t: { x: 0, y: 0, z: 0 }, r: { x: 0, y: 0, z: 0 }, w: 0 };\n\n for (const route of routes) {\n let value = readAxis(data, route.source);\n if (route.flip) value = -value;\n const targetBase = route.target.replace(/[+-]$/, \"\");\n const scale = targetBase === \"w\" ? wScale : targetBase[0] === \"t\" ? translateScale : rotateScale;\n value *= scale;\n writeAxis(acc, route.target, value);\n }\n\n return { translation: acc.t, rotation: acc.r, w: acc.w || undefined, timestamp: data.timestamp, deviceId: data.deviceId };\n}\n"]}
@@ -12,10 +12,12 @@ interface Vec3 {
12
12
  y: number;
13
13
  z: number;
14
14
  }
15
- /** 6DOF spatial input frame — matches spatial-data.schema.json */
15
+ /** 6DOF+W spatial input frame */
16
16
  interface SpatialData {
17
17
  translation: Vec3;
18
18
  rotation: Vec3;
19
+ /** Virtual W axis — application-defined (e.g., zoom, scroll, tool size) */
20
+ w?: number;
19
21
  timestamp: number;
20
22
  /** Source device ID (e.g., "cnx-c635", "hid-054c-5c4") */
21
23
  deviceId?: string;
@@ -42,6 +44,8 @@ interface DeviceInfo {
42
44
  axisLabels?: string[];
43
45
  /** Number of buttons this device provides */
44
46
  buttonCount?: number;
47
+ /** Human-readable labels for buttons (indexed by targetButton) */
48
+ buttonLabels?: string[];
45
49
  }
46
50
  type ConnectionState = "disconnected" | "connecting" | "connected" | "failed";
47
51
  type TransportProtocol = "webtransport" | "websocket" | "none";
@@ -12,10 +12,12 @@ interface Vec3 {
12
12
  y: number;
13
13
  z: number;
14
14
  }
15
- /** 6DOF spatial input frame — matches spatial-data.schema.json */
15
+ /** 6DOF+W spatial input frame */
16
16
  interface SpatialData {
17
17
  translation: Vec3;
18
18
  rotation: Vec3;
19
+ /** Virtual W axis — application-defined (e.g., zoom, scroll, tool size) */
20
+ w?: number;
19
21
  timestamp: number;
20
22
  /** Source device ID (e.g., "cnx-c635", "hid-054c-5c4") */
21
23
  deviceId?: string;
@@ -42,6 +44,8 @@ interface DeviceInfo {
42
44
  axisLabels?: string[];
43
45
  /** Number of buttons this device provides */
44
46
  buttonCount?: number;
47
+ /** Human-readable labels for buttons (indexed by targetButton) */
48
+ buttonLabels?: string[];
45
49
  }
46
50
  type ConnectionState = "disconnected" | "connecting" | "connected" | "failed";
47
51
  type TransportProtocol = "webtransport" | "websocket" | "none";
@@ -1,5 +1,5 @@
1
- import { T as ThingDescription, S as SpatialData, B as ButtonEvent } from '../connection-DQxI5qib.cjs';
2
- export { C as ConnectOptions, a as ConnectionState, D as DeviceInfo, b as SatMouseConnection, c as SatMouseEvents, d as TransportProtocol, e as TypedEmitter, V as Vec3, f as buildSatMouseUri, p as parseSatMouseUri } from '../connection-DQxI5qib.cjs';
1
+ import { T as ThingDescription, S as SpatialData, B as ButtonEvent } from '../connection-C7xJRLzQ.cjs';
2
+ export { C as ConnectOptions, a as ConnectionState, D as DeviceInfo, b as SatMouseConnection, c as SatMouseEvents, d as TransportProtocol, e as TypedEmitter, V as Vec3, f as buildSatMouseUri, p as parseSatMouseUri } from '../connection-C7xJRLzQ.cjs';
3
3
 
4
4
  interface ResolvedEndpoints {
5
5
  webtransport?: {
@@ -1,5 +1,5 @@
1
- import { T as ThingDescription, S as SpatialData, B as ButtonEvent } from '../connection-DQxI5qib.js';
2
- export { C as ConnectOptions, a as ConnectionState, D as DeviceInfo, b as SatMouseConnection, c as SatMouseEvents, d as TransportProtocol, e as TypedEmitter, V as Vec3, f as buildSatMouseUri, p as parseSatMouseUri } from '../connection-DQxI5qib.js';
1
+ import { T as ThingDescription, S as SpatialData, B as ButtonEvent } from '../connection-C7xJRLzQ.js';
2
+ export { C as ConnectOptions, a as ConnectionState, D as DeviceInfo, b as SatMouseConnection, c as SatMouseEvents, d as TransportProtocol, e as TypedEmitter, V as Vec3, f as buildSatMouseUri, p as parseSatMouseUri } from '../connection-C7xJRLzQ.js';
3
3
 
4
4
  interface ResolvedEndpoints {
5
5
  webtransport?: {
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkJTG5GEIB_cjs = require('../chunk-JTG5GEIB.cjs');
3
+ var chunkY75556IA_cjs = require('../chunk-Y75556IA.cjs');
4
4
 
5
5
  // src/elements/registry.ts
6
6
  var globalManager = null;
@@ -161,6 +161,19 @@ var STYLES = `
161
161
  .reset-btn { background: none; border: 1px solid #1a4a8a; border-radius: 3px; color: #7f8c8d;
162
162
  font-size: 11px; padding: 3px 8px; cursor: pointer; margin-top: 4px; }
163
163
  .reset-btn:hover { color: #e0e0e0; border-color: #e74c3c; }
164
+ .btn-section { display: flex; flex-direction: column; gap: 4px; }
165
+ .btn-section-label { color: #7f8c8d; font-weight: 600; font-size: 10px; text-transform: uppercase; letter-spacing: 0.5px; }
166
+ .btn-route { display: flex; gap: 6px; align-items: center; font-size: 11px; }
167
+ .btn-route .btn-idx { color: #7f8c8d; font-family: monospace; min-width: 32px; }
168
+ .btn-route .btn-arrow { color: #7f8c8d; }
169
+ .btn-route .btn-key { color: #3498db; font-family: monospace; }
170
+ .btn-route .btn-remove { cursor: pointer; color: #e74c3c; background: none; border: none;
171
+ font-size: 11px; padding: 0 2px; font-family: inherit; }
172
+ .btn-route .btn-remove:hover { color: #ff6b6b; }
173
+ .btn-add { background: none; border: 1px dashed #1a4a8a; border-radius: 3px; color: #7f8c8d;
174
+ font-size: 11px; padding: 4px 8px; cursor: pointer; font-family: inherit; }
175
+ .btn-add:hover { color: #e0e0e0; border-color: #3498db; }
176
+ .btn-add.listening { color: #f39c12; border-color: #f39c12; border-style: solid; cursor: default; }
164
177
  </style>
165
178
  `;
166
179
  function mapSlider(v) {
@@ -258,7 +271,7 @@ var SatMouseDevices = class extends HTMLElement {
258
271
  label.textContent = device.axisLabels?.[i] ?? deviceAxes[i].toUpperCase();
259
272
  row.appendChild(label);
260
273
  const sel = document.createElement("select");
261
- for (const target of chunkJTG5GEIB_cjs.FULL_AXES) {
274
+ for (const target of chunkY75556IA_cjs.FULL_AXES) {
262
275
  const opt = document.createElement("option");
263
276
  opt.value = target;
264
277
  opt.textContent = target.toUpperCase();
@@ -272,18 +285,93 @@ var SatMouseDevices = class extends HTMLElement {
272
285
  routeGroup.appendChild(row);
273
286
  }
274
287
  controls.appendChild(routeGroup);
275
- const sensRow = document.createElement("div");
276
- sensRow.className = "slider-row";
277
- const currentScale = cfg.scale ?? mgr.config.scale;
278
- sensRow.innerHTML = `<label>Scale</label><input type="range" min="0" max="100" value="${Math.round(unmapSlider(currentScale))}"><span>${currentScale.toFixed(4)}</span>`;
279
- const slider = sensRow.querySelector("input");
280
- const span = sensRow.querySelector("span");
281
- slider.addEventListener("input", () => {
282
- const v = mapSlider(+slider.value);
283
- span.textContent = v.toFixed(4);
284
- mgr.updateDeviceConfig(device.id, { scale: v });
288
+ for (const [label, key, globalKey] of [
289
+ ["Trans", "translateScale", "translateScale"],
290
+ ["Rot", "rotateScale", "rotateScale"],
291
+ ["W", "wScale", "wScale"]
292
+ ]) {
293
+ const row = document.createElement("div");
294
+ row.className = "slider-row";
295
+ const val = cfg[key] ?? mgr.config[globalKey];
296
+ row.innerHTML = `<label>${label}</label><input type="range" min="0" max="100" value="${Math.round(unmapSlider(val))}"><span>${val.toFixed(4)}</span>`;
297
+ const sl = row.querySelector("input");
298
+ const sp = row.querySelector("span");
299
+ sl.addEventListener("input", () => {
300
+ const v = mapSlider(+sl.value);
301
+ sp.textContent = v.toFixed(4);
302
+ mgr.updateDeviceConfig(device.id, { [key]: v });
303
+ });
304
+ controls.appendChild(row);
305
+ }
306
+ const btnSection = document.createElement("div");
307
+ btnSection.className = "btn-section";
308
+ const btnLabel = document.createElement("div");
309
+ btnLabel.className = "btn-section-label";
310
+ btnLabel.textContent = "Button Mappings";
311
+ btnSection.appendChild(btnLabel);
312
+ const buttonRoutes = cfg.buttonRoutes ?? [];
313
+ const labels = device.buttonLabels ?? [];
314
+ for (let i = 0; i < buttonRoutes.length; i++) {
315
+ const route = buttonRoutes[i];
316
+ const btnName = labels[route.button] ?? `Btn ${route.button}`;
317
+ const row = document.createElement("div");
318
+ row.className = "btn-route";
319
+ const idxSpan = document.createElement("span");
320
+ idxSpan.className = "btn-idx";
321
+ idxSpan.textContent = btnName;
322
+ row.appendChild(idxSpan);
323
+ const arrow = document.createElement("span");
324
+ arrow.className = "btn-arrow";
325
+ arrow.textContent = "\u2192";
326
+ row.appendChild(arrow);
327
+ const keySpan = document.createElement("span");
328
+ keySpan.className = "btn-key";
329
+ keySpan.textContent = route.key;
330
+ row.appendChild(keySpan);
331
+ const editBtn = document.createElement("button");
332
+ editBtn.className = "btn-remove";
333
+ editBtn.textContent = "\u270E";
334
+ editBtn.title = "Remap key";
335
+ const routeIdx = i;
336
+ editBtn.addEventListener("click", () => {
337
+ keySpan.textContent = "Press a key...";
338
+ keySpan.style.color = "#f39c12";
339
+ const onKey = (e) => {
340
+ e.preventDefault();
341
+ e.stopPropagation();
342
+ document.removeEventListener("keydown", onKey, true);
343
+ const current = mgr.getDeviceConfig(device.id).buttonRoutes ?? [];
344
+ const updated = current.map(
345
+ (r, j) => j === routeIdx ? { ...r, key: e.key, code: e.code } : r
346
+ );
347
+ mgr.updateDeviceConfig(device.id, { buttonRoutes: updated });
348
+ this.refreshControls(panel, device);
349
+ };
350
+ document.addEventListener("keydown", onKey, true);
351
+ });
352
+ row.appendChild(editBtn);
353
+ const removeBtn = document.createElement("button");
354
+ removeBtn.className = "btn-remove";
355
+ removeBtn.textContent = "\xD7";
356
+ removeBtn.title = "Remove";
357
+ removeBtn.addEventListener("click", () => {
358
+ const current = mgr.getDeviceConfig(device.id).buttonRoutes ?? [];
359
+ const updated = current.filter((_, j) => j !== routeIdx);
360
+ mgr.updateDeviceConfig(device.id, { buttonRoutes: updated });
361
+ this.refreshControls(panel, device);
362
+ });
363
+ row.appendChild(removeBtn);
364
+ btnSection.appendChild(row);
365
+ }
366
+ const addBtn = document.createElement("button");
367
+ addBtn.className = "btn-add";
368
+ addBtn.textContent = "+ Add Button Mapping";
369
+ addBtn.addEventListener("click", () => {
370
+ if (addBtn.classList.contains("listening")) return;
371
+ this.startButtonListen(addBtn, mgr, device, panel);
285
372
  });
286
- controls.appendChild(sensRow);
373
+ btnSection.appendChild(addBtn);
374
+ controls.appendChild(btnSection);
287
375
  const resetBtn = document.createElement("button");
288
376
  resetBtn.className = "reset-btn";
289
377
  resetBtn.textContent = "Restore Defaults";
@@ -303,13 +391,49 @@ var SatMouseDevices = class extends HTMLElement {
303
391
  if (cfg.routes && Array.isArray(cfg.routes)) return cfg.routes;
304
392
  }
305
393
  }
306
- return chunkJTG5GEIB_cjs.buildRoutes(deviceAxes);
394
+ return chunkY75556IA_cjs.buildRoutes(deviceAxes);
307
395
  }
308
396
  updateRoute(deviceId, index, deviceAxes, patch) {
309
397
  const base = this.getRoutes(deviceId, deviceAxes);
310
398
  const updated = base.map((r, j) => j === index ? { ...r, ...patch } : { ...r });
311
399
  this.manager.updateDeviceConfig(deviceId, { routes: updated });
312
400
  }
401
+ startButtonListen(btn, mgr, device, panel) {
402
+ btn.classList.add("listening");
403
+ btn.textContent = "Press a device button...";
404
+ const onButton = (event) => {
405
+ if (!event.pressed) return;
406
+ mgr.off("buttonEvent", onButton);
407
+ const capturedButton = event.button;
408
+ btn.textContent = `Btn ${capturedButton} \u2192 Press a key...`;
409
+ const onKey = (e) => {
410
+ e.preventDefault();
411
+ e.stopPropagation();
412
+ document.removeEventListener("keydown", onKey, true);
413
+ const route = {
414
+ button: capturedButton,
415
+ key: e.key,
416
+ code: e.code
417
+ };
418
+ const current = mgr.getDeviceConfig(device.id).buttonRoutes ?? [];
419
+ const updated = current.filter((r) => r.button !== capturedButton);
420
+ updated.push(route);
421
+ mgr.updateDeviceConfig(device.id, { buttonRoutes: updated });
422
+ this.refreshControls(panel, device);
423
+ };
424
+ document.addEventListener("keydown", onKey, true);
425
+ };
426
+ mgr.on("buttonEvent", onButton);
427
+ const onCancel = (e) => {
428
+ if (e.key === "Escape") {
429
+ mgr.off("buttonEvent", onButton);
430
+ document.removeEventListener("keydown", onCancel, true);
431
+ btn.classList.remove("listening");
432
+ btn.textContent = "+ Add Button Mapping";
433
+ }
434
+ };
435
+ document.addEventListener("keydown", onCancel, true);
436
+ }
313
437
  removeDevice(device) {
314
438
  this.shadowRoot.getElementById(`dev-${device.id}`)?.remove();
315
439
  if (this.container.children.length === 0) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/elements/registry.ts","../../src/elements/satmouse-status.ts","../../src/elements/satmouse-devices.ts","../../src/elements/satmouse-debug.ts"],"names":["FULL_AXES","buildRoutes","TEMPLATE"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { InputManager } from \"../utils/input-manager.js\";\n\n/**\n * Global registry for SatMouse Web Components.\n *\n * Usage:\n * import { registerSatMouse } from \"@kelnishi/satmouse-client/elements\";\n * registerSatMouse(manager);\n * // All <satmouse-*> elements auto-connect to this manager\n */\n\nlet globalManager: InputManager | null = null;\nconst listeners = new Set<(m: InputManager) => void>();\n\nexport function registerSatMouse(manager: InputManager): void {\n globalManager = manager;\n for (const fn of listeners) fn(manager);\n listeners.clear();\n}\n\nexport function getManager(): InputManager | null {\n return globalManager;\n}\n\nexport function onManagerReady(fn: (m: InputManager) => void): void {\n if (globalManager) fn(globalManager);\n else listeners.add(fn);\n}\n\n/** Subscribe to manager availability. Calls fn immediately if already available.\n * Returns an unsubscribe function (for disconnectedCallback). */\nexport function onManager(fn: (m: InputManager) => void): () => void {\n if (globalManager) fn(globalManager);\n else listeners.add(fn);\n return () => listeners.delete(fn);\n}\n","import { onManager } from \"./registry.js\";\nimport type { InputManager } from \"../utils/input-manager.js\";\nimport type { ConnectionState, TransportProtocol } from \"../core/types.js\";\n\nconst TEMPLATE = `\n<style>\n :host { display: inline-flex; align-items: center; gap: 8px; font-family: inherit; font-size: 13px; }\n .dot { width: 8px; height: 8px; border-radius: 50%; background: #e74c3c; transition: background 0.3s; }\n .dot[data-state=\"connected\"] { background: #2ecc71; }\n .dot[data-state=\"connecting\"] { background: #f39c12; }\n .dot[data-state=\"failed\"] { background: #e74c3c; }\n .protocol { color: #7f8c8d; font-size: 11px; text-transform: uppercase; letter-spacing: 1px; }\n .launch { padding: 4px 12px; background: #2980b9; color: #fff; border-radius: 4px; font-size: 11px;\n text-decoration: none; cursor: pointer; border: none; font-family: inherit; display: none; }\n .launch:hover { background: #3498db; }\n\n</style>\n<span class=\"dot\"></span>\n<span class=\"text\">Disconnected</span>\n<span class=\"protocol\"></span>\n<button class=\"launch\">Launch SatMouse</button>\n`;\n\nexport class SatMouseStatus extends HTMLElement {\n private dot!: HTMLElement;\n private text!: HTMLElement;\n private proto!: HTMLElement;\n private launch!: HTMLButtonElement;\n private manager: InputManager | null = null;\n private unsub: (() => void) | null = null;\n private pollTimer: ReturnType<typeof setInterval> | null = null;\n\n private stateHandler = (state: ConnectionState, protocol: TransportProtocol) => this.update(state, protocol);\n\n constructor() {\n super();\n const shadow = this.attachShadow({ mode: \"open\" });\n shadow.innerHTML = TEMPLATE;\n this.dot = shadow.querySelector(\".dot\")!;\n this.text = shadow.querySelector(\".text\")!;\n this.proto = shadow.querySelector(\".protocol\")!;\n this.launch = shadow.querySelector(\".launch\")!;\n\n this.launch.addEventListener(\"click\", () => {\n this.startLaunchFlow();\n });\n }\n\n connectedCallback() {\n this.unsub = onManager((mgr) => this.bind(mgr));\n // Reset button state on remount\n this.stopPoll();\n this.launch.disabled = false;\n this.launch.textContent = \"Launch SatMouse\";\n }\n\n disconnectedCallback() {\n this.stopPoll();\n this.unsub?.();\n this.unbind();\n }\n\n private bind(mgr: InputManager): void {\n this.unbind();\n this.manager = mgr;\n mgr.on(\"stateChange\", this.stateHandler);\n this.update(mgr.state, mgr.protocol);\n }\n\n private unbind(): void {\n this.manager?.off(\"stateChange\", this.stateHandler);\n this.manager = null;\n }\n\n private update(state: ConnectionState, protocol: TransportProtocol): void {\n this.dot.dataset.state = state;\n this.proto.textContent = protocol !== \"none\" ? protocol : \"\";\n\n if (state === \"connected\") {\n this.stopPoll();\n this.showDownload = false;\n this.text.textContent = \"Connected\";\n this.launch.style.display = \"none\";\n } else if (state === \"connecting\") {\n this.text.textContent = \"Connecting...\";\n this.launch.style.display = \"none\";\n } else if (state === \"failed\") {\n this.text.textContent = \"Not running\";\n this.launch.style.display = \"inline-block\";\n this.launch.disabled = false;\n this.launch.textContent = this.showDownload ? \"Download SatMouse\" : \"Launch SatMouse\";\n } else {\n this.text.textContent = \"Disconnected\";\n this.launch.style.display = \"none\";\n }\n }\n\n private showDownload = false;\n\n private startLaunchFlow(): void {\n if (this.showDownload) {\n // Second click — navigate to download page\n window.location.href = \"https://github.com/kelnishi/SatMouse/releases/latest\";\n return;\n }\n\n this.launch.textContent = \"Connecting...\";\n this.launch.disabled = true;\n\n this.manager?.retry();\n window.location.href = \"satmouse://launch\";\n\n let attempts = 0;\n this.stopPoll();\n this.pollTimer = setInterval(() => {\n attempts++;\n if (this.manager?.state === \"connected\") {\n this.stopPoll();\n this.showDownload = false;\n return;\n }\n if (attempts >= 5) {\n this.stopPoll();\n this.showDownload = true;\n this.launch.disabled = false;\n this.launch.textContent = \"Download SatMouse\";\n return;\n }\n this.manager?.retry();\n }, 1500);\n }\n\n private stopPoll(): void {\n if (this.pollTimer) {\n clearInterval(this.pollTimer);\n this.pollTimer = null;\n }\n }\n}\n\ncustomElements.define(\"satmouse-status\", SatMouseStatus);\n","import { onManager } from \"./registry.js\";\nimport type { InputManager } from \"../utils/input-manager.js\";\nimport type { DeviceInfo } from \"../core/types.js\";\nimport type { InputAxis, AxisRoute } from \"../utils/action-map.js\";\nimport { FULL_AXES, buildRoutes, DEFAULT_ROUTES } from \"../utils/action-map.js\";\n\nconst STYLES = `\n<style>\n :host { display: block; font-family: inherit; font-size: 12px; }\n .panel { background: #0f3460; border: 1px solid #1a4a8a; border-radius: 6px; padding: 10px; margin-bottom: 8px; }\n summary { cursor: pointer; font-weight: 600; color: #e0e0e0; font-size: 13px; }\n .type { font-size: 10px; color: #7f8c8d; text-transform: uppercase; margin-left: 6px; }\n .controls { margin-top: 8px; display: flex; flex-direction: column; gap: 6px; }\n .slider-row { display: flex; align-items: center; gap: 6px; }\n .slider-row label { color: #7f8c8d; font-weight: 600; width: 38px; flex-shrink: 0; }\n .slider-row input[type=\"range\"] { flex: 1; min-width: 0; height: 4px; accent-color: #3498db; }\n .slider-row span { color: #7f8c8d; font-family: monospace; font-size: 10px; min-width: 44px; text-align: right; }\n .route-group { display: flex; flex-wrap: wrap; gap: 4px 12px; }\n .route-row { display: flex; gap: 4px; align-items: center; }\n .route-row label { color: #7f8c8d; white-space: nowrap; }\n .route-row select { background: #16213e; color: #e0e0e0; border: 1px solid #1a4a8a; border-radius: 3px;\n font-size: 11px; padding: 1px 4px; }\n .route-row input[type=\"checkbox\"] { accent-color: #e74c3c; margin: 0; }\n .empty { color: #7f8c8d; font-style: italic; }\n .reset-btn { background: none; border: 1px solid #1a4a8a; border-radius: 3px; color: #7f8c8d;\n font-size: 11px; padding: 3px 8px; cursor: pointer; margin-top: 4px; }\n .reset-btn:hover { color: #e0e0e0; border-color: #e74c3c; }\n</style>\n`;\n\nfunction mapSlider(v: number): number { return 0.0001 * Math.pow(500, v / 100); }\nfunction unmapSlider(v: number): number { return (100 * Math.log(v / 0.0001)) / Math.log(500); }\n\nexport class SatMouseDevices extends HTMLElement {\n private manager: InputManager | null = null;\n private container!: HTMLElement;\n\n constructor() {\n super();\n const shadow = this.attachShadow({ mode: \"open\" });\n shadow.innerHTML = STYLES + `<div class=\"container\"><span class=\"empty\">No devices</span></div>`;\n this.container = shadow.querySelector(\".container\")!;\n }\n\n private unsub: (() => void) | null = null;\n\n private deviceStatusHandler = (event: \"connected\" | \"disconnected\", device: DeviceInfo) => {\n if (event === \"connected\") this.addDevice(device);\n else this.removeDevice(device);\n };\n\n private stateHandler = (state: string) => {\n if (state === \"connected\") {\n this.manager?.fetchDeviceInfo().then((devices) => devices.forEach((d) => this.addDevice(d)));\n }\n };\n\n connectedCallback() {\n this.unsub = onManager((mgr) => this.bind(mgr));\n }\n\n disconnectedCallback() {\n this.unsub?.();\n this.unbind();\n this.container.innerHTML = `<span class=\"empty\">No devices</span>`;\n }\n\n private bind(mgr: InputManager): void {\n this.unbind();\n this.manager = mgr;\n mgr.on(\"deviceStatus\", this.deviceStatusHandler);\n mgr.on(\"stateChange\", this.stateHandler);\n if (mgr.state === \"connected\") {\n mgr.fetchDeviceInfo().then((devices) => devices.forEach((d) => this.addDevice(d)));\n }\n }\n\n private unbind(): void {\n if (this.manager) {\n this.manager.off(\"deviceStatus\", this.deviceStatusHandler);\n this.manager.off(\"stateChange\", this.stateHandler);\n this.manager = null;\n }\n }\n\n private addDevice(device: DeviceInfo): void {\n const existing = this.shadowRoot!.getElementById(`dev-${device.id}`);\n if (existing) {\n this.refreshControls(existing as HTMLDetailsElement, device);\n return;\n }\n const empty = this.container.querySelector(\".empty\");\n if (empty) empty.remove();\n\n const panel = document.createElement(\"details\");\n panel.className = \"panel\";\n panel.id = `dev-${device.id}`;\n panel.open = true;\n\n const summary = document.createElement(\"summary\");\n summary.innerHTML = `${device.model ?? device.name}<span class=\"type\">${device.connectionType ?? \"\"}</span>`;\n panel.appendChild(summary);\n\n this.refreshControls(panel, device);\n this.container.appendChild(panel);\n }\n\n private refreshControls(panel: HTMLDetailsElement, device: DeviceInfo): void {\n const old = panel.querySelector(\".controls\");\n if (old) old.remove();\n\n const mgr = this.manager!;\n const cfg = mgr.getDeviceConfig(device.id);\n\n const controls = document.createElement(\"div\");\n controls.className = \"controls\";\n\n // Axis routes — one row per device input: [flip] [label] → [target dropdown] [scale slider]\n const routeGroup = document.createElement(\"div\");\n routeGroup.className = \"route-group\";\n const deviceAxes = device.axes ?? [\"tx\", \"ty\", \"tz\", \"rx\", \"ry\", \"rz\"];\n const routes = this.getRoutes(device.id, deviceAxes);\n\n for (let i = 0; i < deviceAxes.length; i++) {\n const route = routes[i] ?? { source: deviceAxes[i] as InputAxis, target: deviceAxes[i].replace(/[+-]$/, \"\") as InputAxis };\n const row = document.createElement(\"div\");\n row.className = \"route-row\";\n\n // Flip checkbox\n const cb = document.createElement(\"input\");\n cb.type = \"checkbox\";\n cb.checked = route.flip ?? false;\n cb.title = \"Flip\";\n const routeIndex = i;\n cb.addEventListener(\"change\", () => {\n this.updateRoute(device.id, routeIndex, deviceAxes, { flip: cb.checked });\n });\n row.appendChild(cb);\n\n // Label (device input name)\n const label = document.createElement(\"label\");\n label.textContent = device.axisLabels?.[i] ?? deviceAxes[i].toUpperCase();\n row.appendChild(label);\n\n // Target dropdown\n const sel = document.createElement(\"select\");\n for (const target of FULL_AXES) {\n const opt = document.createElement(\"option\");\n opt.value = target;\n opt.textContent = target.toUpperCase();\n if (target === route.target) opt.selected = true;\n sel.appendChild(opt);\n }\n sel.addEventListener(\"change\", () => {\n this.updateRoute(device.id, routeIndex, deviceAxes, { target: sel.value as InputAxis });\n });\n row.appendChild(sel);\n\n routeGroup.appendChild(row);\n }\n controls.appendChild(routeGroup);\n\n // Scale slider\n const sensRow = document.createElement(\"div\");\n sensRow.className = \"slider-row\";\n const currentScale = cfg.scale ?? mgr.config.scale;\n sensRow.innerHTML = `<label>Scale</label>` +\n `<input type=\"range\" min=\"0\" max=\"100\" value=\"${Math.round(unmapSlider(currentScale))}\">` +\n `<span>${currentScale.toFixed(4)}</span>`;\n const slider = sensRow.querySelector(\"input\")! as HTMLInputElement;\n const span = sensRow.querySelector(\"span\")!;\n slider.addEventListener(\"input\", () => {\n const v = mapSlider(+slider.value);\n span.textContent = v.toFixed(4);\n mgr.updateDeviceConfig(device.id, { scale: v });\n });\n controls.appendChild(sensRow);\n\n // Reset button\n const resetBtn = document.createElement(\"button\");\n resetBtn.className = \"reset-btn\";\n resetBtn.textContent = \"Restore Defaults\";\n resetBtn.addEventListener(\"click\", () => {\n mgr.resetDeviceConfig(device.id);\n this.refreshControls(panel, device);\n });\n controls.appendChild(resetBtn);\n\n panel.appendChild(controls);\n }\n\n private getRoutes(deviceId: string, deviceAxes: string[]): AxisRoute[] {\n // Only use saved device config routes — not the global fallback\n const mgr = this.manager!;\n const devCfg = mgr.config.devices[deviceId];\n if (devCfg?.routes && Array.isArray(devCfg.routes)) return devCfg.routes;\n\n // Check pattern matches\n for (const [pattern, cfg] of Object.entries(mgr.config.devices)) {\n if (pattern.endsWith(\"*\") && deviceId.startsWith(pattern.slice(0, -1))) {\n if (cfg.routes && Array.isArray(cfg.routes)) return cfg.routes;\n }\n }\n\n // Build from device axes\n return buildRoutes(deviceAxes);\n }\n\n private updateRoute(deviceId: string, index: number, deviceAxes: string[], patch: Partial<AxisRoute>): void {\n const base = this.getRoutes(deviceId, deviceAxes);\n const updated = base.map((r, j) => j === index ? { ...r, ...patch } : { ...r });\n this.manager!.updateDeviceConfig(deviceId, { routes: updated });\n }\n\n private removeDevice(device: DeviceInfo): void {\n this.shadowRoot!.getElementById(`dev-${device.id}`)?.remove();\n if (this.container.children.length === 0) {\n this.container.innerHTML = `<span class=\"empty\">No devices</span>`;\n }\n }\n}\n\ncustomElements.define(\"satmouse-devices\", SatMouseDevices);\n","import { onManager } from \"./registry.js\";\nimport type { InputManager } from \"../utils/input-manager.js\";\nimport type { SpatialData, ConnectionState, TransportProtocol } from \"../core/types.js\";\n\nconst TEMPLATE = `\n<style>\n :host { display: block; font-family: monospace; font-size: 12px; }\n .row { display: flex; justify-content: space-between; padding: 2px 0; }\n .label { color: #7f8c8d; font-weight: 600; width: 28px; }\n .value { color: #3498db; text-align: right; min-width: 50px; }\n .meta { color: #7f8c8d; font-size: 11px; padding: 2px 0; }\n</style>\n<div class=\"meta\"><span class=\"state\">Disconnected</span> · <span class=\"protocol\"></span> · <span class=\"fps\">0</span> fps</div>\n<div class=\"row\"><span class=\"label\">TX</span><span class=\"value\" id=\"tx\">0</span></div>\n<div class=\"row\"><span class=\"label\">TY</span><span class=\"value\" id=\"ty\">0</span></div>\n<div class=\"row\"><span class=\"label\">TZ</span><span class=\"value\" id=\"tz\">0</span></div>\n<div class=\"row\"><span class=\"label\">RX</span><span class=\"value\" id=\"rx\">0</span></div>\n<div class=\"row\"><span class=\"label\">RY</span><span class=\"value\" id=\"ry\">0</span></div>\n<div class=\"row\"><span class=\"label\">RZ</span><span class=\"value\" id=\"rz\">0</span></div>\n`;\n\nexport class SatMouseDebug extends HTMLElement {\n private els: Record<string, HTMLElement> = {};\n private frameCount = 0;\n private fpsInterval: ReturnType<typeof setInterval> | null = null;\n private manager: InputManager | null = null;\n private unsub: (() => void) | null = null;\n\n private spatialHandler = (data: SpatialData) => {\n this.frameCount++;\n this.els.tx.textContent = String(Math.round(data.translation.x));\n this.els.ty.textContent = String(Math.round(data.translation.y));\n this.els.tz.textContent = String(Math.round(data.translation.z));\n this.els.rx.textContent = String(Math.round(data.rotation.x));\n this.els.ry.textContent = String(Math.round(data.rotation.y));\n this.els.rz.textContent = String(Math.round(data.rotation.z));\n };\n\n private stateHandler = (state: ConnectionState, protocol: TransportProtocol) => {\n this.els.state.textContent = state;\n this.els.protocol.textContent = protocol !== \"none\" ? protocol : \"\";\n };\n\n constructor() {\n super();\n const shadow = this.attachShadow({ mode: \"open\" });\n shadow.innerHTML = TEMPLATE;\n for (const id of [\"tx\", \"ty\", \"tz\", \"rx\", \"ry\", \"rz\"]) {\n this.els[id] = shadow.getElementById(id)!;\n }\n this.els.state = shadow.querySelector(\".state\")!;\n this.els.protocol = shadow.querySelector(\".protocol\")!;\n this.els.fps = shadow.querySelector(\".fps\")!;\n }\n\n connectedCallback() {\n this.unsub = onManager((mgr) => this.bind(mgr));\n this.fpsInterval = setInterval(() => {\n this.els.fps.textContent = String(this.frameCount);\n this.frameCount = 0;\n }, 1000);\n }\n\n disconnectedCallback() {\n this.unsub?.();\n this.unbind();\n if (this.fpsInterval) {\n clearInterval(this.fpsInterval);\n this.fpsInterval = null;\n }\n }\n\n private bind(mgr: InputManager): void {\n this.unbind();\n this.manager = mgr;\n mgr.on(\"rawSpatialData\", this.spatialHandler);\n mgr.on(\"stateChange\", this.stateHandler);\n this.els.state.textContent = mgr.state;\n this.els.protocol.textContent = mgr.protocol !== \"none\" ? mgr.protocol : \"\";\n }\n\n private unbind(): void {\n if (this.manager) {\n this.manager.off(\"rawSpatialData\", this.spatialHandler);\n this.manager.off(\"stateChange\", this.stateHandler);\n this.manager = null;\n }\n }\n}\n\ncustomElements.define(\"satmouse-debug\", SatMouseDebug);\n"]}
1
+ {"version":3,"sources":["../../src/elements/registry.ts","../../src/elements/satmouse-status.ts","../../src/elements/satmouse-devices.ts","../../src/elements/satmouse-debug.ts"],"names":["FULL_AXES","buildRoutes","TEMPLATE"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { InputManager } from \"../utils/input-manager.js\";\n\n/**\n * Global registry for SatMouse Web Components.\n *\n * Usage:\n * import { registerSatMouse } from \"@kelnishi/satmouse-client/elements\";\n * registerSatMouse(manager);\n * // All <satmouse-*> elements auto-connect to this manager\n */\n\nlet globalManager: InputManager | null = null;\nconst listeners = new Set<(m: InputManager) => void>();\n\nexport function registerSatMouse(manager: InputManager): void {\n globalManager = manager;\n for (const fn of listeners) fn(manager);\n listeners.clear();\n}\n\nexport function getManager(): InputManager | null {\n return globalManager;\n}\n\nexport function onManagerReady(fn: (m: InputManager) => void): void {\n if (globalManager) fn(globalManager);\n else listeners.add(fn);\n}\n\n/** Subscribe to manager availability. Calls fn immediately if already available.\n * Returns an unsubscribe function (for disconnectedCallback). */\nexport function onManager(fn: (m: InputManager) => void): () => void {\n if (globalManager) fn(globalManager);\n else listeners.add(fn);\n return () => listeners.delete(fn);\n}\n","import { onManager } from \"./registry.js\";\nimport type { InputManager } from \"../utils/input-manager.js\";\nimport type { ConnectionState, TransportProtocol } from \"../core/types.js\";\n\nconst TEMPLATE = `\n<style>\n :host { display: inline-flex; align-items: center; gap: 8px; font-family: inherit; font-size: 13px; }\n .dot { width: 8px; height: 8px; border-radius: 50%; background: #e74c3c; transition: background 0.3s; }\n .dot[data-state=\"connected\"] { background: #2ecc71; }\n .dot[data-state=\"connecting\"] { background: #f39c12; }\n .dot[data-state=\"failed\"] { background: #e74c3c; }\n .protocol { color: #7f8c8d; font-size: 11px; text-transform: uppercase; letter-spacing: 1px; }\n .launch { padding: 4px 12px; background: #2980b9; color: #fff; border-radius: 4px; font-size: 11px;\n text-decoration: none; cursor: pointer; border: none; font-family: inherit; display: none; }\n .launch:hover { background: #3498db; }\n\n</style>\n<span class=\"dot\"></span>\n<span class=\"text\">Disconnected</span>\n<span class=\"protocol\"></span>\n<button class=\"launch\">Launch SatMouse</button>\n`;\n\nexport class SatMouseStatus extends HTMLElement {\n private dot!: HTMLElement;\n private text!: HTMLElement;\n private proto!: HTMLElement;\n private launch!: HTMLButtonElement;\n private manager: InputManager | null = null;\n private unsub: (() => void) | null = null;\n private pollTimer: ReturnType<typeof setInterval> | null = null;\n\n private stateHandler = (state: ConnectionState, protocol: TransportProtocol) => this.update(state, protocol);\n\n constructor() {\n super();\n const shadow = this.attachShadow({ mode: \"open\" });\n shadow.innerHTML = TEMPLATE;\n this.dot = shadow.querySelector(\".dot\")!;\n this.text = shadow.querySelector(\".text\")!;\n this.proto = shadow.querySelector(\".protocol\")!;\n this.launch = shadow.querySelector(\".launch\")!;\n\n this.launch.addEventListener(\"click\", () => {\n this.startLaunchFlow();\n });\n }\n\n connectedCallback() {\n this.unsub = onManager((mgr) => this.bind(mgr));\n // Reset button state on remount\n this.stopPoll();\n this.launch.disabled = false;\n this.launch.textContent = \"Launch SatMouse\";\n }\n\n disconnectedCallback() {\n this.stopPoll();\n this.unsub?.();\n this.unbind();\n }\n\n private bind(mgr: InputManager): void {\n this.unbind();\n this.manager = mgr;\n mgr.on(\"stateChange\", this.stateHandler);\n this.update(mgr.state, mgr.protocol);\n }\n\n private unbind(): void {\n this.manager?.off(\"stateChange\", this.stateHandler);\n this.manager = null;\n }\n\n private update(state: ConnectionState, protocol: TransportProtocol): void {\n this.dot.dataset.state = state;\n this.proto.textContent = protocol !== \"none\" ? protocol : \"\";\n\n if (state === \"connected\") {\n this.stopPoll();\n this.showDownload = false;\n this.text.textContent = \"Connected\";\n this.launch.style.display = \"none\";\n } else if (state === \"connecting\") {\n this.text.textContent = \"Connecting...\";\n this.launch.style.display = \"none\";\n } else if (state === \"failed\") {\n this.text.textContent = \"Not running\";\n this.launch.style.display = \"inline-block\";\n this.launch.disabled = false;\n this.launch.textContent = this.showDownload ? \"Download SatMouse\" : \"Launch SatMouse\";\n } else {\n this.text.textContent = \"Disconnected\";\n this.launch.style.display = \"none\";\n }\n }\n\n private showDownload = false;\n\n private startLaunchFlow(): void {\n if (this.showDownload) {\n // Second click — navigate to download page\n window.location.href = \"https://github.com/kelnishi/SatMouse/releases/latest\";\n return;\n }\n\n this.launch.textContent = \"Connecting...\";\n this.launch.disabled = true;\n\n this.manager?.retry();\n window.location.href = \"satmouse://launch\";\n\n let attempts = 0;\n this.stopPoll();\n this.pollTimer = setInterval(() => {\n attempts++;\n if (this.manager?.state === \"connected\") {\n this.stopPoll();\n this.showDownload = false;\n return;\n }\n if (attempts >= 5) {\n this.stopPoll();\n this.showDownload = true;\n this.launch.disabled = false;\n this.launch.textContent = \"Download SatMouse\";\n return;\n }\n this.manager?.retry();\n }, 1500);\n }\n\n private stopPoll(): void {\n if (this.pollTimer) {\n clearInterval(this.pollTimer);\n this.pollTimer = null;\n }\n }\n}\n\ncustomElements.define(\"satmouse-status\", SatMouseStatus);\n","import { onManager } from \"./registry.js\";\nimport type { InputManager } from \"../utils/input-manager.js\";\nimport type { DeviceInfo } from \"../core/types.js\";\nimport type { InputAxis, AxisRoute } from \"../utils/action-map.js\";\nimport type { ButtonRoute } from \"../utils/config.js\";\nimport type { ButtonEvent } from \"../core/types.js\";\nimport { FULL_AXES, buildRoutes, DEFAULT_ROUTES } from \"../utils/action-map.js\";\n\nconst STYLES = `\n<style>\n :host { display: block; font-family: inherit; font-size: 12px; }\n .panel { background: #0f3460; border: 1px solid #1a4a8a; border-radius: 6px; padding: 10px; margin-bottom: 8px; }\n summary { cursor: pointer; font-weight: 600; color: #e0e0e0; font-size: 13px; }\n .type { font-size: 10px; color: #7f8c8d; text-transform: uppercase; margin-left: 6px; }\n .controls { margin-top: 8px; display: flex; flex-direction: column; gap: 6px; }\n .slider-row { display: flex; align-items: center; gap: 6px; }\n .slider-row label { color: #7f8c8d; font-weight: 600; width: 38px; flex-shrink: 0; }\n .slider-row input[type=\"range\"] { flex: 1; min-width: 0; height: 4px; accent-color: #3498db; }\n .slider-row span { color: #7f8c8d; font-family: monospace; font-size: 10px; min-width: 44px; text-align: right; }\n .route-group { display: flex; flex-wrap: wrap; gap: 4px 12px; }\n .route-row { display: flex; gap: 4px; align-items: center; }\n .route-row label { color: #7f8c8d; white-space: nowrap; }\n .route-row select { background: #16213e; color: #e0e0e0; border: 1px solid #1a4a8a; border-radius: 3px;\n font-size: 11px; padding: 1px 4px; }\n .route-row input[type=\"checkbox\"] { accent-color: #e74c3c; margin: 0; }\n .empty { color: #7f8c8d; font-style: italic; }\n .reset-btn { background: none; border: 1px solid #1a4a8a; border-radius: 3px; color: #7f8c8d;\n font-size: 11px; padding: 3px 8px; cursor: pointer; margin-top: 4px; }\n .reset-btn:hover { color: #e0e0e0; border-color: #e74c3c; }\n .btn-section { display: flex; flex-direction: column; gap: 4px; }\n .btn-section-label { color: #7f8c8d; font-weight: 600; font-size: 10px; text-transform: uppercase; letter-spacing: 0.5px; }\n .btn-route { display: flex; gap: 6px; align-items: center; font-size: 11px; }\n .btn-route .btn-idx { color: #7f8c8d; font-family: monospace; min-width: 32px; }\n .btn-route .btn-arrow { color: #7f8c8d; }\n .btn-route .btn-key { color: #3498db; font-family: monospace; }\n .btn-route .btn-remove { cursor: pointer; color: #e74c3c; background: none; border: none;\n font-size: 11px; padding: 0 2px; font-family: inherit; }\n .btn-route .btn-remove:hover { color: #ff6b6b; }\n .btn-add { background: none; border: 1px dashed #1a4a8a; border-radius: 3px; color: #7f8c8d;\n font-size: 11px; padding: 4px 8px; cursor: pointer; font-family: inherit; }\n .btn-add:hover { color: #e0e0e0; border-color: #3498db; }\n .btn-add.listening { color: #f39c12; border-color: #f39c12; border-style: solid; cursor: default; }\n</style>\n`;\n\nfunction mapSlider(v: number): number { return 0.0001 * Math.pow(500, v / 100); }\nfunction unmapSlider(v: number): number { return (100 * Math.log(v / 0.0001)) / Math.log(500); }\n\nexport class SatMouseDevices extends HTMLElement {\n private manager: InputManager | null = null;\n private container!: HTMLElement;\n\n constructor() {\n super();\n const shadow = this.attachShadow({ mode: \"open\" });\n shadow.innerHTML = STYLES + `<div class=\"container\"><span class=\"empty\">No devices</span></div>`;\n this.container = shadow.querySelector(\".container\")!;\n }\n\n private unsub: (() => void) | null = null;\n\n private deviceStatusHandler = (event: \"connected\" | \"disconnected\", device: DeviceInfo) => {\n if (event === \"connected\") this.addDevice(device);\n else this.removeDevice(device);\n };\n\n private stateHandler = (state: string) => {\n if (state === \"connected\") {\n this.manager?.fetchDeviceInfo().then((devices) => devices.forEach((d) => this.addDevice(d)));\n }\n };\n\n connectedCallback() {\n this.unsub = onManager((mgr) => this.bind(mgr));\n }\n\n disconnectedCallback() {\n this.unsub?.();\n this.unbind();\n this.container.innerHTML = `<span class=\"empty\">No devices</span>`;\n }\n\n private bind(mgr: InputManager): void {\n this.unbind();\n this.manager = mgr;\n mgr.on(\"deviceStatus\", this.deviceStatusHandler);\n mgr.on(\"stateChange\", this.stateHandler);\n if (mgr.state === \"connected\") {\n mgr.fetchDeviceInfo().then((devices) => devices.forEach((d) => this.addDevice(d)));\n }\n }\n\n private unbind(): void {\n if (this.manager) {\n this.manager.off(\"deviceStatus\", this.deviceStatusHandler);\n this.manager.off(\"stateChange\", this.stateHandler);\n this.manager = null;\n }\n }\n\n private addDevice(device: DeviceInfo): void {\n const existing = this.shadowRoot!.getElementById(`dev-${device.id}`);\n if (existing) {\n this.refreshControls(existing as HTMLDetailsElement, device);\n return;\n }\n const empty = this.container.querySelector(\".empty\");\n if (empty) empty.remove();\n\n const panel = document.createElement(\"details\");\n panel.className = \"panel\";\n panel.id = `dev-${device.id}`;\n panel.open = true;\n\n const summary = document.createElement(\"summary\");\n summary.innerHTML = `${device.model ?? device.name}<span class=\"type\">${device.connectionType ?? \"\"}</span>`;\n panel.appendChild(summary);\n\n this.refreshControls(panel, device);\n this.container.appendChild(panel);\n }\n\n private refreshControls(panel: HTMLDetailsElement, device: DeviceInfo): void {\n const old = panel.querySelector(\".controls\");\n if (old) old.remove();\n\n const mgr = this.manager!;\n const cfg = mgr.getDeviceConfig(device.id);\n\n const controls = document.createElement(\"div\");\n controls.className = \"controls\";\n\n // Axis routes — one row per device input: [flip] [label] → [target dropdown] [scale slider]\n const routeGroup = document.createElement(\"div\");\n routeGroup.className = \"route-group\";\n const deviceAxes = device.axes ?? [\"tx\", \"ty\", \"tz\", \"rx\", \"ry\", \"rz\"];\n const routes = this.getRoutes(device.id, deviceAxes);\n\n for (let i = 0; i < deviceAxes.length; i++) {\n const route = routes[i] ?? { source: deviceAxes[i] as InputAxis, target: deviceAxes[i].replace(/[+-]$/, \"\") as InputAxis };\n const row = document.createElement(\"div\");\n row.className = \"route-row\";\n\n // Flip checkbox\n const cb = document.createElement(\"input\");\n cb.type = \"checkbox\";\n cb.checked = route.flip ?? false;\n cb.title = \"Flip\";\n const routeIndex = i;\n cb.addEventListener(\"change\", () => {\n this.updateRoute(device.id, routeIndex, deviceAxes, { flip: cb.checked });\n });\n row.appendChild(cb);\n\n // Label (device input name)\n const label = document.createElement(\"label\");\n label.textContent = device.axisLabels?.[i] ?? deviceAxes[i].toUpperCase();\n row.appendChild(label);\n\n // Target dropdown\n const sel = document.createElement(\"select\");\n for (const target of FULL_AXES) {\n const opt = document.createElement(\"option\");\n opt.value = target;\n opt.textContent = target.toUpperCase();\n if (target === route.target) opt.selected = true;\n sel.appendChild(opt);\n }\n sel.addEventListener(\"change\", () => {\n this.updateRoute(device.id, routeIndex, deviceAxes, { target: sel.value as InputAxis });\n });\n row.appendChild(sel);\n\n routeGroup.appendChild(row);\n }\n controls.appendChild(routeGroup);\n\n // Scale sliders\n for (const [label, key, globalKey] of [\n [\"Trans\", \"translateScale\", \"translateScale\"],\n [\"Rot\", \"rotateScale\", \"rotateScale\"],\n [\"W\", \"wScale\", \"wScale\"],\n ] as const) {\n const row = document.createElement(\"div\");\n row.className = \"slider-row\";\n const val = (cfg as any)[key] ?? (mgr.config as any)[globalKey];\n row.innerHTML = `<label>${label}</label>` +\n `<input type=\"range\" min=\"0\" max=\"100\" value=\"${Math.round(unmapSlider(val))}\">` +\n `<span>${val.toFixed(4)}</span>`;\n const sl = row.querySelector(\"input\")! as HTMLInputElement;\n const sp = row.querySelector(\"span\")!;\n sl.addEventListener(\"input\", () => {\n const v = mapSlider(+sl.value);\n sp.textContent = v.toFixed(4);\n mgr.updateDeviceConfig(device.id, { [key]: v });\n });\n controls.appendChild(row);\n }\n\n // Button mappings\n const btnSection = document.createElement(\"div\");\n btnSection.className = \"btn-section\";\n const btnLabel = document.createElement(\"div\");\n btnLabel.className = \"btn-section-label\";\n btnLabel.textContent = \"Button Mappings\";\n btnSection.appendChild(btnLabel);\n\n const buttonRoutes: ButtonRoute[] = cfg.buttonRoutes ?? [];\n const labels = device.buttonLabels ?? [];\n for (let i = 0; i < buttonRoutes.length; i++) {\n const route = buttonRoutes[i];\n const btnName = labels[route.button] ?? `Btn ${route.button}`;\n const row = document.createElement(\"div\");\n row.className = \"btn-route\";\n\n const idxSpan = document.createElement(\"span\");\n idxSpan.className = \"btn-idx\";\n idxSpan.textContent = btnName;\n row.appendChild(idxSpan);\n\n const arrow = document.createElement(\"span\");\n arrow.className = \"btn-arrow\";\n arrow.textContent = \"\\u2192\";\n row.appendChild(arrow);\n\n const keySpan = document.createElement(\"span\");\n keySpan.className = \"btn-key\";\n keySpan.textContent = route.key;\n row.appendChild(keySpan);\n\n // Edit — re-listen for a new key\n const editBtn = document.createElement(\"button\");\n editBtn.className = \"btn-remove\";\n editBtn.textContent = \"\\u270E\";\n editBtn.title = \"Remap key\";\n const routeIdx = i;\n editBtn.addEventListener(\"click\", () => {\n keySpan.textContent = \"Press a key...\";\n keySpan.style.color = \"#f39c12\";\n const onKey = (e: KeyboardEvent) => {\n e.preventDefault();\n e.stopPropagation();\n document.removeEventListener(\"keydown\", onKey, true);\n const current = mgr.getDeviceConfig(device.id).buttonRoutes ?? [];\n const updated = current.map((r: ButtonRoute, j: number) =>\n j === routeIdx ? { ...r, key: e.key, code: e.code } : r\n );\n mgr.updateDeviceConfig(device.id, { buttonRoutes: updated });\n this.refreshControls(panel, device);\n };\n document.addEventListener(\"keydown\", onKey, true);\n });\n row.appendChild(editBtn);\n\n // Delete\n const removeBtn = document.createElement(\"button\");\n removeBtn.className = \"btn-remove\";\n removeBtn.textContent = \"\\u00d7\";\n removeBtn.title = \"Remove\";\n removeBtn.addEventListener(\"click\", () => {\n const current = mgr.getDeviceConfig(device.id).buttonRoutes ?? [];\n const updated = current.filter((_: ButtonRoute, j: number) => j !== routeIdx);\n mgr.updateDeviceConfig(device.id, { buttonRoutes: updated });\n this.refreshControls(panel, device);\n });\n row.appendChild(removeBtn);\n btnSection.appendChild(row);\n }\n\n // Add mapping button with listen flow\n const addBtn = document.createElement(\"button\");\n addBtn.className = \"btn-add\";\n addBtn.textContent = \"+ Add Button Mapping\";\n addBtn.addEventListener(\"click\", () => {\n if (addBtn.classList.contains(\"listening\")) return;\n this.startButtonListen(addBtn, mgr, device, panel);\n });\n btnSection.appendChild(addBtn);\n controls.appendChild(btnSection);\n\n // Reset button\n const resetBtn = document.createElement(\"button\");\n resetBtn.className = \"reset-btn\";\n resetBtn.textContent = \"Restore Defaults\";\n resetBtn.addEventListener(\"click\", () => {\n mgr.resetDeviceConfig(device.id);\n this.refreshControls(panel, device);\n });\n controls.appendChild(resetBtn);\n\n panel.appendChild(controls);\n }\n\n private getRoutes(deviceId: string, deviceAxes: string[]): AxisRoute[] {\n // Only use saved device config routes — not the global fallback\n const mgr = this.manager!;\n const devCfg = mgr.config.devices[deviceId];\n if (devCfg?.routes && Array.isArray(devCfg.routes)) return devCfg.routes;\n\n // Check pattern matches\n for (const [pattern, cfg] of Object.entries(mgr.config.devices)) {\n if (pattern.endsWith(\"*\") && deviceId.startsWith(pattern.slice(0, -1))) {\n if (cfg.routes && Array.isArray(cfg.routes)) return cfg.routes;\n }\n }\n\n // Build from device axes\n return buildRoutes(deviceAxes);\n }\n\n private updateRoute(deviceId: string, index: number, deviceAxes: string[], patch: Partial<AxisRoute>): void {\n const base = this.getRoutes(deviceId, deviceAxes);\n const updated = base.map((r, j) => j === index ? { ...r, ...patch } : { ...r });\n this.manager!.updateDeviceConfig(deviceId, { routes: updated });\n }\n\n private startButtonListen(\n btn: HTMLButtonElement,\n mgr: InputManager,\n device: DeviceInfo,\n panel: HTMLDetailsElement,\n ): void {\n btn.classList.add(\"listening\");\n btn.textContent = \"Press a device button...\";\n\n // Step 1: Listen for device button\n const onButton = (event: ButtonEvent) => {\n if (!event.pressed) return; // only on press, not release\n mgr.off(\"buttonEvent\", onButton);\n\n const capturedButton = event.button;\n btn.textContent = `Btn ${capturedButton} \\u2192 Press a key...`;\n\n // Step 2: Listen for keyboard key\n const onKey = (e: KeyboardEvent) => {\n e.preventDefault();\n e.stopPropagation();\n document.removeEventListener(\"keydown\", onKey, true);\n\n const route: ButtonRoute = {\n button: capturedButton,\n key: e.key,\n code: e.code,\n };\n\n const current = mgr.getDeviceConfig(device.id).buttonRoutes ?? [];\n // Replace existing mapping for the same button, or add new\n const updated = current.filter((r: ButtonRoute) => r.button !== capturedButton);\n updated.push(route);\n mgr.updateDeviceConfig(device.id, { buttonRoutes: updated });\n this.refreshControls(panel, device);\n };\n document.addEventListener(\"keydown\", onKey, true);\n };\n mgr.on(\"buttonEvent\", onButton);\n\n // Cancel on Escape (before a button is pressed)\n const onCancel = (e: KeyboardEvent) => {\n if (e.key === \"Escape\") {\n mgr.off(\"buttonEvent\", onButton);\n document.removeEventListener(\"keydown\", onCancel, true);\n btn.classList.remove(\"listening\");\n btn.textContent = \"+ Add Button Mapping\";\n }\n };\n document.addEventListener(\"keydown\", onCancel, true);\n }\n\n private removeDevice(device: DeviceInfo): void {\n this.shadowRoot!.getElementById(`dev-${device.id}`)?.remove();\n if (this.container.children.length === 0) {\n this.container.innerHTML = `<span class=\"empty\">No devices</span>`;\n }\n }\n}\n\ncustomElements.define(\"satmouse-devices\", SatMouseDevices);\n","import { onManager } from \"./registry.js\";\nimport type { InputManager } from \"../utils/input-manager.js\";\nimport type { SpatialData, ConnectionState, TransportProtocol } from \"../core/types.js\";\n\nconst TEMPLATE = `\n<style>\n :host { display: block; font-family: monospace; font-size: 12px; }\n .row { display: flex; justify-content: space-between; padding: 2px 0; }\n .label { color: #7f8c8d; font-weight: 600; width: 28px; }\n .value { color: #3498db; text-align: right; min-width: 50px; }\n .meta { color: #7f8c8d; font-size: 11px; padding: 2px 0; }\n</style>\n<div class=\"meta\"><span class=\"state\">Disconnected</span> · <span class=\"protocol\"></span> · <span class=\"fps\">0</span> fps</div>\n<div class=\"row\"><span class=\"label\">TX</span><span class=\"value\" id=\"tx\">0</span></div>\n<div class=\"row\"><span class=\"label\">TY</span><span class=\"value\" id=\"ty\">0</span></div>\n<div class=\"row\"><span class=\"label\">TZ</span><span class=\"value\" id=\"tz\">0</span></div>\n<div class=\"row\"><span class=\"label\">RX</span><span class=\"value\" id=\"rx\">0</span></div>\n<div class=\"row\"><span class=\"label\">RY</span><span class=\"value\" id=\"ry\">0</span></div>\n<div class=\"row\"><span class=\"label\">RZ</span><span class=\"value\" id=\"rz\">0</span></div>\n`;\n\nexport class SatMouseDebug extends HTMLElement {\n private els: Record<string, HTMLElement> = {};\n private frameCount = 0;\n private fpsInterval: ReturnType<typeof setInterval> | null = null;\n private manager: InputManager | null = null;\n private unsub: (() => void) | null = null;\n\n private spatialHandler = (data: SpatialData) => {\n this.frameCount++;\n this.els.tx.textContent = String(Math.round(data.translation.x));\n this.els.ty.textContent = String(Math.round(data.translation.y));\n this.els.tz.textContent = String(Math.round(data.translation.z));\n this.els.rx.textContent = String(Math.round(data.rotation.x));\n this.els.ry.textContent = String(Math.round(data.rotation.y));\n this.els.rz.textContent = String(Math.round(data.rotation.z));\n };\n\n private stateHandler = (state: ConnectionState, protocol: TransportProtocol) => {\n this.els.state.textContent = state;\n this.els.protocol.textContent = protocol !== \"none\" ? protocol : \"\";\n };\n\n constructor() {\n super();\n const shadow = this.attachShadow({ mode: \"open\" });\n shadow.innerHTML = TEMPLATE;\n for (const id of [\"tx\", \"ty\", \"tz\", \"rx\", \"ry\", \"rz\"]) {\n this.els[id] = shadow.getElementById(id)!;\n }\n this.els.state = shadow.querySelector(\".state\")!;\n this.els.protocol = shadow.querySelector(\".protocol\")!;\n this.els.fps = shadow.querySelector(\".fps\")!;\n }\n\n connectedCallback() {\n this.unsub = onManager((mgr) => this.bind(mgr));\n this.fpsInterval = setInterval(() => {\n this.els.fps.textContent = String(this.frameCount);\n this.frameCount = 0;\n }, 1000);\n }\n\n disconnectedCallback() {\n this.unsub?.();\n this.unbind();\n if (this.fpsInterval) {\n clearInterval(this.fpsInterval);\n this.fpsInterval = null;\n }\n }\n\n private bind(mgr: InputManager): void {\n this.unbind();\n this.manager = mgr;\n mgr.on(\"rawSpatialData\", this.spatialHandler);\n mgr.on(\"stateChange\", this.stateHandler);\n this.els.state.textContent = mgr.state;\n this.els.protocol.textContent = mgr.protocol !== \"none\" ? mgr.protocol : \"\";\n }\n\n private unbind(): void {\n if (this.manager) {\n this.manager.off(\"rawSpatialData\", this.spatialHandler);\n this.manager.off(\"stateChange\", this.stateHandler);\n this.manager = null;\n }\n }\n}\n\ncustomElements.define(\"satmouse-debug\", SatMouseDebug);\n"]}
@@ -1,5 +1,5 @@
1
1
  import { InputManager } from '../utils/index.cjs';
2
- import '../connection-DQxI5qib.cjs';
2
+ import '../connection-C7xJRLzQ.cjs';
3
3
 
4
4
  declare class SatMouseStatus extends HTMLElement {
5
5
  private dot;
@@ -36,6 +36,7 @@ declare class SatMouseDevices extends HTMLElement {
36
36
  private refreshControls;
37
37
  private getRoutes;
38
38
  private updateRoute;
39
+ private startButtonListen;
39
40
  private removeDevice;
40
41
  }
41
42