@mindexec/cli 0.2.440 → 0.2.442

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 (49) hide show
  1. package/package.json +1 -1
  2. package/remote-fast/osx-arm64/MacScreenCaptureKitH264.swift +339 -0
  3. package/remote-fast/osx-arm64/MacSystemAudioCapture.swift +214 -0
  4. package/remote-fast/osx-arm64/UnixRawCaptureHelper.mjs +80 -0
  5. package/remote-fast/osx-arm64/livedesk-raw-capture-resampler.mjs +73 -0
  6. package/remote-fast/osx-arm64/mindexec-remote-fast.dll +0 -0
  7. package/remote-fast/osx-x64/MacScreenCaptureKitH264.swift +339 -0
  8. package/remote-fast/osx-x64/MacSystemAudioCapture.swift +214 -0
  9. package/remote-fast/osx-x64/UnixRawCaptureHelper.mjs +80 -0
  10. package/remote-fast/osx-x64/livedesk-raw-capture-resampler.mjs +73 -0
  11. package/remote-fast/osx-x64/mindexec-remote-fast.dll +0 -0
  12. package/remote-fast/win-x64/NAudio.Asio.dll +0 -0
  13. package/remote-fast/win-x64/NAudio.Core.dll +0 -0
  14. package/remote-fast/win-x64/NAudio.Midi.dll +0 -0
  15. package/remote-fast/win-x64/NAudio.Wasapi.dll +0 -0
  16. package/remote-fast/win-x64/NAudio.WinForms.dll +0 -0
  17. package/remote-fast/win-x64/NAudio.WinMM.dll +0 -0
  18. package/remote-fast/win-x64/NAudio.dll +0 -0
  19. package/remote-fast/win-x64/SharpGen.Runtime.COM.dll +0 -0
  20. package/remote-fast/win-x64/SharpGen.Runtime.dll +0 -0
  21. package/remote-fast/win-x64/Vortice.DXGI.dll +0 -0
  22. package/remote-fast/win-x64/Vortice.Direct3D11.dll +0 -0
  23. package/remote-fast/win-x64/Vortice.DirectX.dll +0 -0
  24. package/remote-fast/win-x64/Vortice.Mathematics.dll +0 -0
  25. package/remote-fast/win-x64/mindexec-remote-fast.deps.json +238 -0
  26. package/remote-fast/win-x64/mindexec-remote-fast.dll +0 -0
  27. package/remote-fast/win-x64/mindexec-remote-fast.exe +0 -0
  28. package/remote-hub.js +42 -3
  29. package/server.js +22 -6
  30. package/wwwroot/_content/MindExecution.Shared/css/mind-map-overrides.css +49 -0
  31. package/wwwroot/_content/MindExecution.Shared/js/mind-map-core.js +6 -2
  32. package/wwwroot/_content/MindExecution.Shared/js/mind-map-css3d-manager.js +70 -60
  33. package/wwwroot/_content/MindExecution.Shared/js/mind-map-multi-select.js +32 -6
  34. package/wwwroot/_content/MindExecution.Shared/js/mind-map-remote-codecs.js +126 -0
  35. package/wwwroot/_content/MindExecution.Shared/js/mind-map-video-playback-controls.js +95 -0
  36. package/wwwroot/_framework/{MindExecution.Core.808jj176e1.dll → MindExecution.Core.nxjlewduna.dll} +0 -0
  37. package/wwwroot/_framework/{MindExecution.Kernel.75hxk08tt0.dll → MindExecution.Kernel.vrfi63yg9f.dll} +0 -0
  38. package/wwwroot/_framework/{MindExecution.Plugins.Admin.0zkmk8wahq.dll → MindExecution.Plugins.Admin.1rcwhdxl0r.dll} +0 -0
  39. package/wwwroot/_framework/{MindExecution.Plugins.Business.vyw3769hrw.dll → MindExecution.Plugins.Business.rx0eieg51y.dll} +0 -0
  40. package/wwwroot/_framework/{MindExecution.Plugins.Concept.cvmglrxsjb.dll → MindExecution.Plugins.Concept.zzczjzhvk1.dll} +0 -0
  41. package/wwwroot/_framework/{MindExecution.Plugins.Directory.jtw9q1dm9n.dll → MindExecution.Plugins.Directory.bsorcntiwp.dll} +0 -0
  42. package/wwwroot/_framework/{MindExecution.Plugins.PlanMaster.8hmc6ps1ux.dll → MindExecution.Plugins.PlanMaster.i5j9t4f1jf.dll} +0 -0
  43. package/wwwroot/_framework/{MindExecution.Plugins.YouTube.xb9sou9ox0.dll → MindExecution.Plugins.YouTube.1mpn9satft.dll} +0 -0
  44. package/wwwroot/_framework/{MindExecution.Shared.pqab76cjb6.dll → MindExecution.Shared.mpi1gzau9b.dll} +0 -0
  45. package/wwwroot/_framework/{MindExecution.Web.mc24u4bzol.dll → MindExecution.Web.nxykcyxd02.dll} +0 -0
  46. package/wwwroot/_framework/blazor.boot.json +21 -21
  47. package/wwwroot/index.html +3 -1
  48. package/wwwroot/service-worker-assets.js +35 -27
  49. package/wwwroot/service-worker.js +1 -1
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env node
2
+
3
+ import readline from 'node:readline';
4
+ import { convertRgbaToRgb565 } from './livedesk-raw-capture-resampler.mjs';
5
+
6
+ const screenshotModule = await import('node-screenshots');
7
+ const Monitor = screenshotModule.Monitor || screenshotModule.default?.Monitor;
8
+ if (!Monitor?.all) {
9
+ throw new Error('node-screenshots Monitor API is unavailable.');
10
+ }
11
+
12
+ function clampInteger(value, min, max, fallback) {
13
+ const number = Number(value);
14
+ if (!Number.isFinite(number)) return fallback;
15
+ return Math.max(min, Math.min(max, Math.round(number)));
16
+ }
17
+
18
+ function pickMonitor(index) {
19
+ const monitors = Monitor.all();
20
+ if (!monitors.length) {
21
+ throw new Error('No capturable desktop monitor was found.');
22
+ }
23
+ const selectedIndex = clampInteger(index, 0, monitors.length - 1, 0);
24
+ const monitor = monitors[selectedIndex]
25
+ || monitors.find(item => item?.isPrimary?.() === true)
26
+ || monitors[0];
27
+ return { monitor, selectedIndex, monitorCount: monitors.length };
28
+ }
29
+
30
+ function writeResponse(metadata, payload = Buffer.alloc(0)) {
31
+ const header = Buffer.from(JSON.stringify(metadata), 'utf8');
32
+ const prefix = Buffer.allocUnsafe(8);
33
+ prefix.writeUInt32BE(header.length, 0);
34
+ prefix.writeUInt32BE(payload.length, 4);
35
+ process.stdout.write(prefix);
36
+ process.stdout.write(header);
37
+ if (payload.length > 0) process.stdout.write(payload);
38
+ }
39
+
40
+ const input = readline.createInterface({ input: process.stdin, crlfDelay: Infinity });
41
+ for await (const line of input) {
42
+ if (!line.trim()) continue;
43
+ let request;
44
+ try {
45
+ request = JSON.parse(line);
46
+ const id = Number.isSafeInteger(Number(request.id)) ? Number(request.id) : 0;
47
+ const maxWidth = clampInteger(request.maxWidth, 1, 480, 320);
48
+ const maxHeight = clampInteger(request.maxHeight, 1, 270, 180);
49
+ const { monitor, selectedIndex, monitorCount } = pickMonitor(request.monitorIndex);
50
+ const captureStartedAt = performance.now();
51
+ const image = await monitor.captureImage();
52
+ const raw = await image.toRaw(false);
53
+ const captureMs = Math.max(0, performance.now() - captureStartedAt);
54
+ const sourceWidth = Number(image.width || monitor.width?.() || 0);
55
+ const sourceHeight = Number(image.height || monitor.height?.() || 0);
56
+ const convertStartedAt = performance.now();
57
+ const converted = convertRgbaToRgb565(raw, sourceWidth, sourceHeight, maxWidth, maxHeight);
58
+ const convertMs = Math.max(0, performance.now() - convertStartedAt);
59
+ writeResponse({
60
+ ok: true,
61
+ id,
62
+ width: converted.width,
63
+ height: converted.height,
64
+ sourceWidth,
65
+ sourceHeight,
66
+ monitorIndex: selectedIndex,
67
+ monitorCount,
68
+ captureMs: Math.round(captureMs),
69
+ convertMs: Math.round(convertMs),
70
+ resizeFilter: converted.filter
71
+ }, converted.output);
72
+ } catch (error) {
73
+ writeResponse({
74
+ ok: false,
75
+ id: Number.isSafeInteger(Number(request?.id)) ? Number(request.id) : 0,
76
+ error: String(error?.message || error || 'capture failed').slice(0, 1000)
77
+ });
78
+ }
79
+ }
80
+
@@ -0,0 +1,73 @@
1
+ function clampInteger(value, min, max, fallback) {
2
+ const number = Number(value);
3
+ if (!Number.isFinite(number)) return fallback;
4
+ return Math.max(min, Math.min(max, Math.round(number)));
5
+ }
6
+
7
+ function writeRgb565(output, target, red, green, blue) {
8
+ const pixel = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
9
+ output[target] = pixel & 0xff;
10
+ output[target + 1] = pixel >> 8;
11
+ }
12
+
13
+ export function convertRgbaToRgb565(raw, sourceWidthValue, sourceHeightValue, maxWidthValue, maxHeightValue) {
14
+ const sourceWidth = clampInteger(sourceWidthValue, 1, 32_768, 1);
15
+ const sourceHeight = clampInteger(sourceHeightValue, 1, 32_768, 1);
16
+ const maxWidth = clampInteger(maxWidthValue, 1, sourceWidth, sourceWidth);
17
+ const maxHeight = clampInteger(maxHeightValue, 1, sourceHeight, sourceHeight);
18
+ if (raw.length < sourceWidth * sourceHeight * 4) {
19
+ throw new Error(`Raw capture is incomplete: ${raw.length} bytes for ${sourceWidth}x${sourceHeight}.`);
20
+ }
21
+
22
+ const scale = Math.min(1, maxWidth / sourceWidth, maxHeight / sourceHeight);
23
+ const width = Math.max(1, Math.round(sourceWidth * scale));
24
+ const height = Math.max(1, Math.round(sourceHeight * scale));
25
+ const output = Buffer.allocUnsafe(width * height * 2);
26
+
27
+ if (width === sourceWidth && height === sourceHeight) {
28
+ for (let source = 0, target = 0; target < output.length; source += 4, target += 2) {
29
+ writeRgb565(output, target, raw[source], raw[source + 1], raw[source + 2]);
30
+ }
31
+ return { output, width, height, filter: 'none' };
32
+ }
33
+
34
+ const xStarts = new Int32Array(width);
35
+ const xEnds = new Int32Array(width);
36
+ for (let x = 0; x < width; x += 1) {
37
+ xStarts[x] = Math.min(sourceWidth - 1, Math.floor(x * sourceWidth / width));
38
+ xEnds[x] = Math.max(xStarts[x] + 1, Math.min(sourceWidth, Math.floor((x + 1) * sourceWidth / width)));
39
+ }
40
+
41
+ let target = 0;
42
+ for (let y = 0; y < height; y += 1) {
43
+ const sourceY0 = Math.min(sourceHeight - 1, Math.floor(y * sourceHeight / height));
44
+ const sourceY1 = Math.max(sourceY0 + 1, Math.min(sourceHeight, Math.floor((y + 1) * sourceHeight / height)));
45
+ for (let x = 0; x < width; x += 1) {
46
+ let red = 0;
47
+ let green = 0;
48
+ let blue = 0;
49
+ let samples = 0;
50
+ for (let sourceY = sourceY0; sourceY < sourceY1; sourceY += 1) {
51
+ let source = (sourceY * sourceWidth + xStarts[x]) * 4;
52
+ for (let sourceX = xStarts[x]; sourceX < xEnds[x]; sourceX += 1) {
53
+ red += raw[source];
54
+ green += raw[source + 1];
55
+ blue += raw[source + 2];
56
+ samples += 1;
57
+ source += 4;
58
+ }
59
+ }
60
+ writeRgb565(
61
+ output,
62
+ target,
63
+ Math.round(red / samples),
64
+ Math.round(green / samples),
65
+ Math.round(blue / samples)
66
+ );
67
+ target += 2;
68
+ }
69
+ }
70
+
71
+ return { output, width, height, filter: 'box' };
72
+ }
73
+
Binary file
@@ -8,9 +8,156 @@
8
8
  ".NETCoreApp,Version=v9.0": {},
9
9
  ".NETCoreApp,Version=v9.0/win-x64": {
10
10
  "mindexec-remote-fast/1.0.0": {
11
+ "dependencies": {
12
+ "NAudio": "2.2.1",
13
+ "Vortice.Direct3D11": "3.8.3"
14
+ },
11
15
  "runtime": {
12
16
  "mindexec-remote-fast.dll": {}
13
17
  }
18
+ },
19
+ "NAudio/2.2.1": {
20
+ "dependencies": {
21
+ "NAudio.Asio": "2.2.1",
22
+ "NAudio.Core": "2.2.1",
23
+ "NAudio.Midi": "2.2.1",
24
+ "NAudio.Wasapi": "2.2.1",
25
+ "NAudio.WinForms": "2.2.1",
26
+ "NAudio.WinMM": "2.2.1"
27
+ },
28
+ "runtime": {
29
+ "lib/net6.0-windows7.0/NAudio.dll": {
30
+ "assemblyVersion": "2.2.1.0",
31
+ "fileVersion": "2.2.1.0"
32
+ }
33
+ }
34
+ },
35
+ "NAudio.Asio/2.2.1": {
36
+ "dependencies": {
37
+ "NAudio.Core": "2.2.1"
38
+ },
39
+ "runtime": {
40
+ "lib/netstandard2.0/NAudio.Asio.dll": {
41
+ "assemblyVersion": "2.2.1.0",
42
+ "fileVersion": "2.2.1.0"
43
+ }
44
+ }
45
+ },
46
+ "NAudio.Core/2.2.1": {
47
+ "runtime": {
48
+ "lib/netstandard2.0/NAudio.Core.dll": {
49
+ "assemblyVersion": "2.2.1.0",
50
+ "fileVersion": "2.2.1.0"
51
+ }
52
+ }
53
+ },
54
+ "NAudio.Midi/2.2.1": {
55
+ "dependencies": {
56
+ "NAudio.Core": "2.2.1"
57
+ },
58
+ "runtime": {
59
+ "lib/netstandard2.0/NAudio.Midi.dll": {
60
+ "assemblyVersion": "2.2.1.0",
61
+ "fileVersion": "2.2.1.0"
62
+ }
63
+ }
64
+ },
65
+ "NAudio.Wasapi/2.2.1": {
66
+ "dependencies": {
67
+ "NAudio.Core": "2.2.1"
68
+ },
69
+ "runtime": {
70
+ "lib/netstandard2.0/NAudio.Wasapi.dll": {
71
+ "assemblyVersion": "2.2.1.0",
72
+ "fileVersion": "2.2.1.0"
73
+ }
74
+ }
75
+ },
76
+ "NAudio.WinForms/2.2.1": {
77
+ "dependencies": {
78
+ "NAudio.WinMM": "2.2.1"
79
+ },
80
+ "runtime": {
81
+ "lib/netcoreapp3.1/NAudio.WinForms.dll": {
82
+ "assemblyVersion": "2.2.1.0",
83
+ "fileVersion": "2.2.1.0"
84
+ }
85
+ }
86
+ },
87
+ "NAudio.WinMM/2.2.1": {
88
+ "dependencies": {
89
+ "NAudio.Core": "2.2.1"
90
+ },
91
+ "runtime": {
92
+ "lib/netstandard2.0/NAudio.WinMM.dll": {
93
+ "assemblyVersion": "2.2.1.0",
94
+ "fileVersion": "2.2.1.0"
95
+ }
96
+ }
97
+ },
98
+ "SharpGen.Runtime/2.4.2-beta": {
99
+ "runtime": {
100
+ "lib/net9.0/SharpGen.Runtime.dll": {
101
+ "assemblyVersion": "2.4.2.0",
102
+ "fileVersion": "2.4.2.0"
103
+ }
104
+ }
105
+ },
106
+ "SharpGen.Runtime.COM/2.4.2-beta": {
107
+ "dependencies": {
108
+ "SharpGen.Runtime": "2.4.2-beta"
109
+ },
110
+ "runtime": {
111
+ "lib/net9.0/SharpGen.Runtime.COM.dll": {
112
+ "assemblyVersion": "2.4.2.0",
113
+ "fileVersion": "2.4.2.0"
114
+ }
115
+ }
116
+ },
117
+ "Vortice.Direct3D11/3.8.3": {
118
+ "dependencies": {
119
+ "SharpGen.Runtime": "2.4.2-beta",
120
+ "Vortice.DXGI": "3.8.3"
121
+ },
122
+ "runtime": {
123
+ "lib/net9.0/Vortice.Direct3D11.dll": {
124
+ "assemblyVersion": "3.8.3.0",
125
+ "fileVersion": "3.8.3.0"
126
+ }
127
+ }
128
+ },
129
+ "Vortice.DirectX/3.8.3": {
130
+ "dependencies": {
131
+ "SharpGen.Runtime": "2.4.2-beta",
132
+ "SharpGen.Runtime.COM": "2.4.2-beta",
133
+ "Vortice.Mathematics": "2.1.0"
134
+ },
135
+ "runtime": {
136
+ "lib/net9.0/Vortice.DirectX.dll": {
137
+ "assemblyVersion": "3.8.3.0",
138
+ "fileVersion": "3.8.3.0"
139
+ }
140
+ }
141
+ },
142
+ "Vortice.DXGI/3.8.3": {
143
+ "dependencies": {
144
+ "SharpGen.Runtime": "2.4.2-beta",
145
+ "Vortice.DirectX": "3.8.3"
146
+ },
147
+ "runtime": {
148
+ "lib/net9.0/Vortice.DXGI.dll": {
149
+ "assemblyVersion": "3.8.3.0",
150
+ "fileVersion": "3.8.3.0"
151
+ }
152
+ }
153
+ },
154
+ "Vortice.Mathematics/2.1.0": {
155
+ "runtime": {
156
+ "lib/net9.0/Vortice.Mathematics.dll": {
157
+ "assemblyVersion": "2.1.0.0",
158
+ "fileVersion": "2.1.0.0"
159
+ }
160
+ }
14
161
  }
15
162
  }
16
163
  },
@@ -19,6 +166,97 @@
19
166
  "type": "project",
20
167
  "serviceable": false,
21
168
  "sha512": ""
169
+ },
170
+ "NAudio/2.2.1": {
171
+ "type": "package",
172
+ "serviceable": true,
173
+ "sha512": "sha512-c0DzwiyyklM0TP39Y7RObwO3QkWecgM6H60ikiEnsV/aEAJPbj5MFCLaD8BSfKuZe0HGuh9GRGWWlJmSxDc9MA==",
174
+ "path": "naudio/2.2.1",
175
+ "hashPath": "naudio.2.2.1.nupkg.sha512"
176
+ },
177
+ "NAudio.Asio/2.2.1": {
178
+ "type": "package",
179
+ "serviceable": true,
180
+ "sha512": "sha512-hQglyOT5iT3XuGpBP8ZG0+aoqwRfidHjTNehpoWwX0g6KJEgtH2VaqM2nuJ2mheKZa/IBqB4YQTZVvrIapzfOA==",
181
+ "path": "naudio.asio/2.2.1",
182
+ "hashPath": "naudio.asio.2.2.1.nupkg.sha512"
183
+ },
184
+ "NAudio.Core/2.2.1": {
185
+ "type": "package",
186
+ "serviceable": true,
187
+ "sha512": "sha512-GgkdP6K/7FqXFo7uHvoqGZTJvW4z8g2IffhOO4JHaLzKCdDOUEzVKtveoZkCuUX8eV2HAINqi7VFqlFndrnz/g==",
188
+ "path": "naudio.core/2.2.1",
189
+ "hashPath": "naudio.core.2.2.1.nupkg.sha512"
190
+ },
191
+ "NAudio.Midi/2.2.1": {
192
+ "type": "package",
193
+ "serviceable": true,
194
+ "sha512": "sha512-6r23ylGo5aeP02WFXsPquz0T0hFJWyh+7t++tz19tc3Kr38NHm+Z9j+FiAv+xkH8tZqXJqus9Q8p6u7bidIgbw==",
195
+ "path": "naudio.midi/2.2.1",
196
+ "hashPath": "naudio.midi.2.2.1.nupkg.sha512"
197
+ },
198
+ "NAudio.Wasapi/2.2.1": {
199
+ "type": "package",
200
+ "serviceable": true,
201
+ "sha512": "sha512-lFfXoqacZZe0WqNChJgGYI+XV/n/61LzPHT3C1CJp4khoxeo2sziyX5wzNYWeCMNbsWxFvT3b3iXeY1UYjBhZw==",
202
+ "path": "naudio.wasapi/2.2.1",
203
+ "hashPath": "naudio.wasapi.2.2.1.nupkg.sha512"
204
+ },
205
+ "NAudio.WinForms/2.2.1": {
206
+ "type": "package",
207
+ "serviceable": true,
208
+ "sha512": "sha512-DlDkewY1myY0A+3NrYRJD+MZhZV0yy1mNF6dckB27IQ9XCs/My5Ip8BZcoSHOsaPSe2GAjvoaDnk6N9w8xTv7w==",
209
+ "path": "naudio.winforms/2.2.1",
210
+ "hashPath": "naudio.winforms.2.2.1.nupkg.sha512"
211
+ },
212
+ "NAudio.WinMM/2.2.1": {
213
+ "type": "package",
214
+ "serviceable": true,
215
+ "sha512": "sha512-xFHRFwH4x6aq3IxRbewvO33ugJRvZFEOfO62i7uQJRUNW2cnu6BeBTHUS0JD5KBucZbHZaYqxQG8dwZ47ezQuQ==",
216
+ "path": "naudio.winmm/2.2.1",
217
+ "hashPath": "naudio.winmm.2.2.1.nupkg.sha512"
218
+ },
219
+ "SharpGen.Runtime/2.4.2-beta": {
220
+ "type": "package",
221
+ "serviceable": true,
222
+ "sha512": "sha512-niTtWAUov1F7wZGAlVeEvW+Tnqvg5yTmhI7rxmYu2Utoyu2TbC9tWWpUpMs0PQg5lu5svoYpCAztNjxCqMFP/w==",
223
+ "path": "sharpgen.runtime/2.4.2-beta",
224
+ "hashPath": "sharpgen.runtime.2.4.2-beta.nupkg.sha512"
225
+ },
226
+ "SharpGen.Runtime.COM/2.4.2-beta": {
227
+ "type": "package",
228
+ "serviceable": true,
229
+ "sha512": "sha512-9lxDFMiepqo3lJQzMSjECCIONeCc2f3Drokgj6HtrTLZcJSftNgcLbD6/iXYj2iphkwgrZb1oLsDOZxoFZkawQ==",
230
+ "path": "sharpgen.runtime.com/2.4.2-beta",
231
+ "hashPath": "sharpgen.runtime.com.2.4.2-beta.nupkg.sha512"
232
+ },
233
+ "Vortice.Direct3D11/3.8.3": {
234
+ "type": "package",
235
+ "serviceable": true,
236
+ "sha512": "sha512-JgFUswu2mgrSwcd0KRF2AnfeE5VbMEgcicmxPD1g2yXyomPIHbnX3wldBNHPOzzD0URC1WJ/pO1ymfi3imZwvg==",
237
+ "path": "vortice.direct3d11/3.8.3",
238
+ "hashPath": "vortice.direct3d11.3.8.3.nupkg.sha512"
239
+ },
240
+ "Vortice.DirectX/3.8.3": {
241
+ "type": "package",
242
+ "serviceable": true,
243
+ "sha512": "sha512-nKwSavv0w5rDF7prSefqAVPDcTyqrfZxKFMVfttiXPfm62VdA/1d+b3PhCZpW4xO7jXczXDwjQdWgD1zGsvM8w==",
244
+ "path": "vortice.directx/3.8.3",
245
+ "hashPath": "vortice.directx.3.8.3.nupkg.sha512"
246
+ },
247
+ "Vortice.DXGI/3.8.3": {
248
+ "type": "package",
249
+ "serviceable": true,
250
+ "sha512": "sha512-MbAUnTeQ6WD99ctAdrj5CQO2I7oaax0Kt2eVdWSUj0bYP9Ed0726+s7dIHe4+tqhpmINW/dcPt0mNtc72o+E0w==",
251
+ "path": "vortice.dxgi/3.8.3",
252
+ "hashPath": "vortice.dxgi.3.8.3.nupkg.sha512"
253
+ },
254
+ "Vortice.Mathematics/2.1.0": {
255
+ "type": "package",
256
+ "serviceable": true,
257
+ "sha512": "sha512-KK+SjNSuKdP+zbavekubi+vaeb1Jo4k87ZF6CMkVWjr6RjJwc8peVtmgzXXDIMy4ZC3ZISyk3llY3q65ISOkBQ==",
258
+ "path": "vortice.mathematics/2.1.0",
259
+ "hashPath": "vortice.mathematics.2.1.0.nupkg.sha512"
22
260
  }
23
261
  }
24
262
  }
package/remote-hub.js CHANGED
@@ -60,6 +60,28 @@ const REMOTE_FRAME_MODE_PROFILES = Object.freeze({
60
60
  modeVersion: 1,
61
61
  implemented: true
62
62
  }),
63
+ 'mode3-h264-hw': Object.freeze({
64
+ mode: 'mode3-h264-hw',
65
+ label: 'Mode 3 H.264 Control',
66
+ transport: 'ws-binary',
67
+ encoding: 'video',
68
+ codec: 'h264',
69
+ compression: 'video/h264',
70
+ profile: 'mode3-h264-hardware-v1',
71
+ modeVersion: 3,
72
+ implemented: true
73
+ }),
74
+ 'mode4-h264-atlas': Object.freeze({
75
+ mode: 'mode4-h264-atlas',
76
+ label: 'Mode 4 H.264 Atlas Wall',
77
+ transport: 'ws-binary',
78
+ encoding: 'video',
79
+ codec: 'h264',
80
+ compression: 'video/h264',
81
+ profile: 'mode4-h264-atlas-v1',
82
+ modeVersion: 4,
83
+ implemented: true
84
+ }),
63
85
  'video-codec': Object.freeze({
64
86
  mode: 'video-codec',
65
87
  label: 'Video Codec Stream',
@@ -81,6 +103,12 @@ const REMOTE_FRAME_MODE_ALIASES = new Map([
81
103
  ['remotequality', 'remote-quality'],
82
104
  ['remote_quality', 'remote-quality'],
83
105
  ['remote-quality', 'remote-quality'],
106
+ ['mode3-h264', 'mode3-h264-hw'],
107
+ ['mode3-h264-hw', 'mode3-h264-hw'],
108
+ ['h264', 'mode3-h264-hw'],
109
+ ['mode4', 'mode4-h264-atlas'],
110
+ ['mode4-h264-atlas', 'mode4-h264-atlas'],
111
+ ['atlas', 'mode4-h264-atlas'],
84
112
  ['thumb', 'thumbnail'],
85
113
  ['thumbnail', 'thumbnail'],
86
114
  ['video', 'video-codec'],
@@ -443,6 +471,9 @@ function normalizeRemoteInputEvent(value = {}) {
443
471
  code: safeString(input.code || input.Code, 80),
444
472
  text: safeText(input.text || input.Text, 256),
445
473
  repeat: input.repeat === true || input.Repeat === true,
474
+ inputSeq: Number.isFinite(Number(input.inputSeq ?? input.InputSeq)) ? Math.max(0, Math.floor(Number(input.inputSeq ?? input.InputSeq))) : 0,
475
+ requestAck: input.requestAck === true || input.RequestAck === true,
476
+ fireAndForget: input.fireAndForget === true || input.FireAndForget === true,
446
477
  controlLeaseId: safeString(input.controlLeaseId || input.ControlLeaseId, 128),
447
478
  issuedAt: safeString(input.issuedAt || input.IssuedAt, 80)
448
479
  };
@@ -1399,7 +1430,7 @@ export function createRemoteHub(options = {}) {
1399
1430
  transferProtocol: descriptor.transferProtocol,
1400
1431
  transferProtocolVersion: descriptor.transferProtocolVersion,
1401
1432
  handshake: descriptor.handshake,
1402
- fps: clampNumber(options.fps, 1, 24, mode === 'remote-fast' ? 20 : 1),
1433
+ fps: clampNumber(options.fps, 1, 30, mode === 'remote-fast' ? 20 : 1),
1403
1434
  capturedAt: now,
1404
1435
  receivedAt: now,
1405
1436
  byteLength: 68,
@@ -2416,6 +2447,14 @@ export function createRemoteHub(options = {}) {
2416
2447
  transferProtocolVersion: transfer.transferProtocolVersion,
2417
2448
  handshake: transfer.handshake,
2418
2449
  fps: Number.isFinite(Number(message.fps)) ? Number(message.fps) : device.activeLiveStream.fps,
2450
+ streamPurpose: safeString(message.streamPurpose, 32),
2451
+ monitorIndex: Number.isFinite(Number(message.monitorIndex)) ? Number(message.monitorIndex) : 0,
2452
+ h264Format: safeString(message.h264Format, 24),
2453
+ isKeyFrame: message.isKeyFrame === true,
2454
+ chunkType: safeString(message.chunkType, 24),
2455
+ timestampUs: Number.isFinite(Number(message.timestampUs)) ? Number(message.timestampUs) : 0,
2456
+ durationUs: Number.isFinite(Number(message.durationUs)) ? Number(message.durationUs) : 0,
2457
+ streamFrameSeq: Number.isFinite(Number(message.streamFrameSeq)) ? Number(message.streamFrameSeq) : frameSeq,
2419
2458
  capturedAt,
2420
2459
  receivedAt: device.lastSeenAt,
2421
2460
  byteLength,
@@ -3221,7 +3260,7 @@ export function createRemoteHub(options = {}) {
3221
3260
 
3222
3261
  const now = new Date().toISOString();
3223
3262
  const streamId = safeString(options.streamId, 128) || `live-${Date.now()}`;
3224
- const fps = clampNumber(options.fps, 1, 24, 20);
3263
+ const fps = clampNumber(options.fps, 1, 30, 20);
3225
3264
  const commandId = safeString(options.commandId, 128) || crypto.randomUUID();
3226
3265
  const transfer = buildRemoteFrameTransferDescriptor(options.mode || DEFAULT_REMOTE_FRAME_MODE);
3227
3266
  device.counters.commandsSent += 1;
@@ -3275,7 +3314,7 @@ export function createRemoteHub(options = {}) {
3275
3314
 
3276
3315
  const now = new Date().toISOString();
3277
3316
  const streamId = safeString(options.streamId, 128) || `live-${Date.now()}`;
3278
- const fps = clampNumber(options.fps, 1, 24, 12);
3317
+ const fps = clampNumber(options.fps, 1, 30, 20);
3279
3318
  const commandId = safeString(options.commandId, 128) || crypto.randomUUID();
3280
3319
  const transfer = buildRemoteFrameTransferDescriptor(options.mode || DEFAULT_REMOTE_FRAME_MODE);
3281
3320
  const result = sendCommand(deviceId, {
package/server.js CHANGED
@@ -2454,7 +2454,7 @@ const remoteInputWsDiagnostics = {
2454
2454
  lastError: ''
2455
2455
  };
2456
2456
  const REMOTE_FRAME_WS_AUTO_START_LIMIT = 120;
2457
- const REMOTE_FRAME_WS_DEFAULT_FPS = 12;
2457
+ const REMOTE_FRAME_WS_DEFAULT_FPS = 20;
2458
2458
  const REMOTE_FRAME_WS_DEFAULT_MAX_WIDTH = 960;
2459
2459
  const REMOTE_FRAME_WS_DEFAULT_MAX_HEIGHT = 540;
2460
2460
  const REMOTE_FRAME_WS_DEFAULT_QUALITY = 60;
@@ -2563,7 +2563,10 @@ function updateRemoteFrameClientSubscription(ws, payload = {}) {
2563
2563
  timestamp: ws.remoteFrameSubscriptionUpdatedAt,
2564
2564
  deviceIds,
2565
2565
  mode: deviceIds.length > 0 ? 'selected-devices' : 'all-devices',
2566
- autoStartLive: ws.remoteFrameAutoStartLive === true
2566
+ autoStartLive: ws.remoteFrameAutoStartLive === true,
2567
+ streamPurpose: ws.remoteFrameAutoStartOptions.streamPurpose,
2568
+ fps: ws.remoteFrameAutoStartOptions.fps,
2569
+ frameMode: ws.remoteFrameAutoStartOptions.frameMode
2567
2570
  });
2568
2571
  maybeAutoStartRemoteFrameLiveStreams(ws, deviceIds);
2569
2572
  }
@@ -2579,13 +2582,16 @@ function clampRemoteFrameWsNumber(value, min, max, fallback) {
2579
2582
 
2580
2583
  function normalizeRemoteFrameWsLiveOptions(payload = {}) {
2581
2584
  const mode = String(payload.frameMode || payload.mode || 'remote-fast').trim() || 'remote-fast';
2585
+ const streamPurpose = String(payload.streamPurpose || '').trim().toLowerCase();
2586
+ const defaultFps = streamPurpose === 'control' || mode === 'mode3-h264-hw' ? 30 : REMOTE_FRAME_WS_DEFAULT_FPS;
2582
2587
  return {
2583
- fps: clampRemoteFrameWsNumber(payload.fps, 1, 24, REMOTE_FRAME_WS_DEFAULT_FPS),
2588
+ fps: clampRemoteFrameWsNumber(payload.fps, 1, 30, defaultFps),
2584
2589
  maxWidth: clampRemoteFrameWsNumber(payload.maxWidth, 320, 2560, REMOTE_FRAME_WS_DEFAULT_MAX_WIDTH),
2585
2590
  maxHeight: clampRemoteFrameWsNumber(payload.maxHeight, 180, 1440, REMOTE_FRAME_WS_DEFAULT_MAX_HEIGHT),
2586
2591
  quality: clampRemoteFrameWsNumber(payload.quality, 20, 95, REMOTE_FRAME_WS_DEFAULT_QUALITY),
2587
2592
  mode,
2588
- frameMode: mode
2593
+ frameMode: mode,
2594
+ streamPurpose: streamPurpose || (mode === 'mode3-h264-hw' ? 'control' : 'wall')
2589
2595
  };
2590
2596
  }
2591
2597
 
@@ -2716,7 +2722,17 @@ function buildRemoteFrameBinaryPacket(frameEvent) {
2716
2722
  transport: frame.transport || '',
2717
2723
  contentHash: frame.contentHash || '',
2718
2724
  captureMs: Number(frame.captureMs || 0) || 0,
2719
- sameContentStreak: Number(frame.sameContentStreak || 0) || 0
2725
+ sameContentStreak: Number(frame.sameContentStreak || 0) || 0,
2726
+ streamPurpose: frame.streamPurpose || '',
2727
+ monitorIndex: Number.isFinite(Number(frame.monitorIndex)) ? Number(frame.monitorIndex) : 0,
2728
+ codec: frame.codec || '',
2729
+ h264Format: frame.h264Format || '',
2730
+ isKeyFrame: frame.isKeyFrame === true,
2731
+ chunkType: frame.chunkType || '',
2732
+ timestampUs: Number.isFinite(Number(frame.timestampUs)) ? Number(frame.timestampUs) : 0,
2733
+ durationUs: Number.isFinite(Number(frame.durationUs)) ? Number(frame.durationUs) : 0,
2734
+ streamFrameSeq: Number.isFinite(Number(frame.streamFrameSeq)) ? Number(frame.streamFrameSeq) : 0,
2735
+ commandId: frame.commandId || ''
2720
2736
  };
2721
2737
  const metaBuffer = Buffer.from(JSON.stringify(metadata), 'utf8');
2722
2738
  const header = Buffer.allocUnsafe(4);
@@ -12805,7 +12821,7 @@ app.get('/api/remote/devices/:deviceId/live/frame', (req, res) => {
12805
12821
  app.post('/api/remote/devices/:deviceId/live/start', (req, res) => {
12806
12822
  res.json(remoteHub.startLiveStream(req.params.deviceId, {
12807
12823
  streamId: req.body?.streamId,
12808
- mode: req.body?.mode,
12824
+ mode: req.body?.frameMode || req.body?.mode || 'mode3-h264-hw',
12809
12825
  fps: req.body?.fps,
12810
12826
  maxWidth: req.body?.maxWidth,
12811
12827
  maxHeight: req.body?.maxHeight,
@@ -3697,6 +3697,55 @@ html body .css3d-resolution-wrapper:not(.lod-low).node-type-embed.selected-media
3697
3697
  0 0 0 1px rgba(var(--node-selection-glow-rgb-soft), 0.12) !important;
3698
3698
  }
3699
3699
 
3700
+ /* Selected video playback is an explicit compact action; native controls stay off. */
3701
+ .mind-map-video-playback-control {
3702
+ position: absolute;
3703
+ left: 50%;
3704
+ bottom: 10px;
3705
+ z-index: 8;
3706
+ display: none;
3707
+ align-items: center;
3708
+ gap: 6px;
3709
+ min-height: 28px;
3710
+ padding: 5px 10px;
3711
+ border: 1px solid rgba(255, 255, 255, 0.34);
3712
+ border-radius: 999px;
3713
+ background: rgba(15, 23, 42, 0.82);
3714
+ color: #f8fafc;
3715
+ box-shadow: 0 4px 14px rgba(15, 23, 42, 0.24);
3716
+ font: 600 12px/1 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
3717
+ letter-spacing: 0.01em;
3718
+ pointer-events: auto;
3719
+ cursor: pointer;
3720
+ transform: translateX(-50%);
3721
+ backdrop-filter: blur(8px);
3722
+ }
3723
+
3724
+ .mind-map-video-playback-control__icon {
3725
+ display: inline-flex;
3726
+ min-width: 10px;
3727
+ align-items: center;
3728
+ justify-content: center;
3729
+ font-size: 10px;
3730
+ }
3731
+
3732
+ .css3d-resolution-wrapper.node-type-video.selected .mind-map-video-playback-control,
3733
+ .css3d-resolution-wrapper.node-type-video.selected-media-safe .mind-map-video-playback-control {
3734
+ display: inline-flex;
3735
+ }
3736
+
3737
+ .css3d-resolution-wrapper.node-type-video.lod-low:not(.selected):not(.selected-media-safe) .mind-map-video-playback-control {
3738
+ display: none !important;
3739
+ }
3740
+
3741
+ .mind-map-video-playback-control:hover,
3742
+ .mind-map-video-playback-control:focus-visible {
3743
+ background: rgba(15, 23, 42, 0.94);
3744
+ border-color: rgba(255, 255, 255, 0.62);
3745
+ outline: 2px solid rgba(96, 165, 250, 0.85);
3746
+ outline-offset: 2px;
3747
+ }
3748
+
3700
3749
  html body .css3d-resolution-wrapper:not(.lod-low) > .map-node-bubble.selected,
3701
3750
  html body .css3d-resolution-wrapper:not(.lod-low) > .map-node-note.selected,
3702
3751
  html body .css3d-resolution-wrapper:not(.lod-low) > .map-node-note:focus-within,