@h-rig/cli 0.0.6-alpha.82 → 0.0.6-alpha.83

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 (100) hide show
  1. package/dist/bin/build-rig-binaries.js +40 -8
  2. package/dist/bin/rig.js +2798 -1440
  3. package/dist/src/app/board.js +62 -13
  4. package/dist/src/app-opentui/adapters/command.d.ts +2 -0
  5. package/dist/src/app-opentui/adapters/command.js +329 -0
  6. package/dist/src/app-opentui/adapters/common.js +2 -2
  7. package/dist/src/app-opentui/adapters/doctor.js +63 -14
  8. package/dist/src/app-opentui/adapters/fleet.js +84 -20
  9. package/dist/src/app-opentui/adapters/inbox.js +83 -19
  10. package/dist/src/app-opentui/adapters/init.js +87 -23
  11. package/dist/src/app-opentui/adapters/pi-attach.js +96 -34
  12. package/dist/src/app-opentui/adapters/run-detail.js +83 -19
  13. package/dist/src/app-opentui/adapters/server.js +100 -23
  14. package/dist/src/app-opentui/adapters/tasks.d.ts +11 -0
  15. package/dist/src/app-opentui/adapters/tasks.js +742 -94
  16. package/dist/src/app-opentui/bootstrap.d.ts +1 -6
  17. package/dist/src/app-opentui/bootstrap.js +13769 -12368
  18. package/dist/src/app-opentui/command-pty-host.d.ts +62 -0
  19. package/dist/src/app-opentui/command-pty-host.js +248 -0
  20. package/dist/src/app-opentui/events.js +1 -1
  21. package/dist/src/app-opentui/focus-manager.d.ts +14 -0
  22. package/dist/src/app-opentui/focus-manager.js +24 -0
  23. package/dist/src/app-opentui/index.js +3802 -2882
  24. package/dist/src/app-opentui/intent.js +154 -48
  25. package/dist/src/app-opentui/keymap.d.ts +20 -0
  26. package/dist/src/app-opentui/keymap.js +707 -0
  27. package/dist/src/app-opentui/launch-routing.d.ts +16 -0
  28. package/dist/src/app-opentui/launch-routing.js +55 -0
  29. package/dist/src/app-opentui/layout.js +2 -2
  30. package/dist/src/app-opentui/pi-host-child.js +66 -16
  31. package/dist/src/app-opentui/pi-pty-host.d.ts +9 -0
  32. package/dist/src/app-opentui/pi-pty-host.js +9 -11
  33. package/dist/src/app-opentui/registry.js +3231 -2403
  34. package/dist/src/app-opentui/render/ascii-fleet.d.ts +15 -0
  35. package/dist/src/app-opentui/render/ascii-fleet.js +82 -0
  36. package/dist/src/app-opentui/render/graphics.d.ts +1 -1
  37. package/dist/src/app-opentui/render/graphics.js +131 -16
  38. package/dist/src/app-opentui/render/image-visual-layer-worker.js +408 -957
  39. package/dist/src/app-opentui/render/image-visual-layer.d.ts +18 -10
  40. package/dist/src/app-opentui/render/image-visual-layer.js +386 -356
  41. package/dist/src/app-opentui/render/panel-layout.d.ts +38 -0
  42. package/dist/src/app-opentui/render/panel-layout.js +48 -0
  43. package/dist/src/app-opentui/render/panels.d.ts +2 -0
  44. package/dist/src/app-opentui/render/panels.js +62 -29
  45. package/dist/src/app-opentui/render/preloader.d.ts +10 -0
  46. package/dist/src/app-opentui/render/preloader.js +163 -0
  47. package/dist/src/app-opentui/render/scene.d.ts +3 -0
  48. package/dist/src/app-opentui/render/scene.js +12 -0
  49. package/dist/src/app-opentui/render/text.js +5 -1
  50. package/dist/src/app-opentui/render/type-bar.d.ts +2 -1
  51. package/dist/src/app-opentui/render/type-bar.js +51 -16
  52. package/dist/src/app-opentui/runtime-resources.d.ts +16 -0
  53. package/dist/src/app-opentui/runtime-resources.js +62 -0
  54. package/dist/src/app-opentui/runtime.js +2322 -1513
  55. package/dist/src/app-opentui/scenes/command.d.ts +3 -0
  56. package/dist/src/app-opentui/scenes/command.js +103 -0
  57. package/dist/src/app-opentui/scenes/doctor.d.ts +2 -1
  58. package/dist/src/app-opentui/scenes/doctor.js +53 -14
  59. package/dist/src/app-opentui/scenes/error.js +44 -14
  60. package/dist/src/app-opentui/scenes/fleet.js +40 -21
  61. package/dist/src/app-opentui/scenes/handoff.js +142 -27
  62. package/dist/src/app-opentui/scenes/help.js +63 -48
  63. package/dist/src/app-opentui/scenes/inbox.d.ts +2 -1
  64. package/dist/src/app-opentui/scenes/inbox.js +64 -17
  65. package/dist/src/app-opentui/scenes/init.d.ts +2 -1
  66. package/dist/src/app-opentui/scenes/init.js +62 -21
  67. package/dist/src/app-opentui/scenes/main.d.ts +2 -1
  68. package/dist/src/app-opentui/scenes/main.js +80 -24
  69. package/dist/src/app-opentui/scenes/run-detail.d.ts +2 -1
  70. package/dist/src/app-opentui/scenes/run-detail.js +39 -25
  71. package/dist/src/app-opentui/scenes/server.d.ts +2 -1
  72. package/dist/src/app-opentui/scenes/server.js +71 -20
  73. package/dist/src/app-opentui/scenes/tasks.js +44 -22
  74. package/dist/src/app-opentui/state.js +70 -30
  75. package/dist/src/app-opentui/terminal-capabilities.d.ts +7 -0
  76. package/dist/src/app-opentui/terminal-capabilities.js +15 -0
  77. package/dist/src/app-opentui/types.d.ts +10 -2
  78. package/dist/src/commands/_doctor-checks.js +62 -13
  79. package/dist/src/commands/_operator-view.js +63 -13
  80. package/dist/src/commands/_pi-frontend.js +63 -13
  81. package/dist/src/commands/_preflight.js +64 -14
  82. package/dist/src/commands/_server-client.js +82 -18
  83. package/dist/src/commands/_snapshot-upload.js +62 -13
  84. package/dist/src/commands/connect.js +7 -1
  85. package/dist/src/commands/doctor.js +62 -13
  86. package/dist/src/commands/github.js +144 -23
  87. package/dist/src/commands/inbox.js +62 -13
  88. package/dist/src/commands/init.js +82 -18
  89. package/dist/src/commands/inspect.js +62 -13
  90. package/dist/src/commands/run.js +66 -13
  91. package/dist/src/commands/server.js +69 -14
  92. package/dist/src/commands/setup.js +62 -13
  93. package/dist/src/commands/stats.js +62 -13
  94. package/dist/src/commands/task-run-driver.js +62 -13
  95. package/dist/src/commands/task.js +65 -14
  96. package/dist/src/commands.js +227 -92
  97. package/dist/src/index.js +234 -99
  98. package/package.json +8 -9
  99. package/dist/src/app-opentui/render/image-visual-layer-native-canvas.d.ts +0 -2
  100. package/dist/src/app-opentui/render/image-visual-layer-native-canvas.js +0 -1484
@@ -1,1484 +0,0 @@
1
- // @bun
2
- // packages/cli/src/app-opentui/render/image-visual-layer-native-canvas.ts
3
- import { mkdirSync, writeFileSync } from "fs";
4
- import { join } from "path";
5
- import { tmpdir } from "os";
6
- import { clearAllCache, createCanvas } from "@napi-rs/canvas";
7
-
8
- // packages/cli/src/app-opentui/render/image-visual-layer.ts
9
- import { Worker } from "worker_threads";
10
- import { deflateSync } from "zlib";
11
- import { allocateImageId, deleteKittyImage, getCapabilities } from "@earendil-works/pi-tui";
12
- var BG = [7, 8, 9, 255];
13
- var PANEL = [16, 17, 21, 184];
14
- var PANEL_HEADER = [16, 17, 21, 190];
15
- var PANEL_LINE = [255, 255, 255, 24];
16
- var LIME = [204, 255, 77, 255];
17
- var LIME_DIM = [169, 214, 63, 255];
18
- var CYAN = [86, 216, 255, 255];
19
- var MAGENTA = [255, 121, 176, 255];
20
- var INK_DIM = [108, 110, 121, 255];
21
- var PNG_SIGNATURE = new Uint8Array([137, 80, 78, 71, 13, 10, 26, 10]);
22
- var CRC_TABLE = makeCrcTable();
23
- var MAX_IMAGE_BYTES = 48 * 1024 * 1024;
24
- var KITTY_CHUNK_SIZE = 4096;
25
- var PANEL_BLUR_SCALE = 5;
26
- var PANEL_MASK_CACHE_LIMIT = 16;
27
- var ZLIB_LEVEL = 1;
28
- var DEFAULT_DRONE_LAYER_SCALE = 0.18;
29
- var DEFAULT_IMAGE_FPS = 24;
30
- var panelMaskCache = new Map;
31
- var BG_WORD = rgbaWord(BG);
32
- function imageTransport() {
33
- const forced = process.env.RIG_OPENTUI_IMAGE_TRANSPORT;
34
- if (forced === "rgba-zlib")
35
- return "rgba-zlib";
36
- return "png";
37
- }
38
- function droneLayerScale() {
39
- const raw = Number.parseFloat(process.env.RIG_OPENTUI_DRONE_SCALE ?? "");
40
- if (Number.isFinite(raw) && raw > 0)
41
- return Math.max(0.15, Math.min(1, raw));
42
- return DEFAULT_DRONE_LAYER_SCALE;
43
- }
44
- function scaledPixelSize(size, scale, layout) {
45
- return {
46
- width: Math.max(layout.width, Math.floor(size.width * scale)),
47
- height: Math.max(layout.height, Math.floor(size.height * scale))
48
- };
49
- }
50
- function imageFps() {
51
- const raw = Number.parseFloat(process.env.RIG_OPENTUI_IMAGE_FPS ?? "");
52
- if (Number.isFinite(raw) && raw > 0)
53
- return Math.max(10, Math.min(60, raw));
54
- return DEFAULT_IMAGE_FPS;
55
- }
56
- function rgbaWord(color) {
57
- return (color[3] << 24 | color[2] << 16 | color[1] << 8 | color[0]) >>> 0;
58
- }
59
- function fillRgba(data, color, word = rgbaWord(color)) {
60
- if (data.byteOffset % 4 === 0 && data.byteLength % 4 === 0) {
61
- new Uint32Array(data.buffer, data.byteOffset, data.byteLength / 4).fill(word);
62
- return;
63
- }
64
- for (let i = 0;i < data.length; i += 4) {
65
- data[i] = color[0];
66
- data[i + 1] = color[1];
67
- data[i + 2] = color[2];
68
- data[i + 3] = color[3];
69
- }
70
- }
71
- function makeCrcTable() {
72
- const table = new Uint32Array(256);
73
- for (let n = 0;n < 256; n += 1) {
74
- let c = n;
75
- for (let k = 0;k < 8; k += 1)
76
- c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;
77
- table[n] = c >>> 0;
78
- }
79
- return table;
80
- }
81
- function crc32(bytes) {
82
- let c = 4294967295;
83
- for (let i = 0;i < bytes.length; i += 1)
84
- c = CRC_TABLE[(c ^ bytes[i]) & 255] ^ c >>> 8;
85
- return (c ^ 4294967295) >>> 0;
86
- }
87
- function chunk(type, data) {
88
- const out = new Uint8Array(12 + data.length);
89
- const view = new DataView(out.buffer);
90
- view.setUint32(0, data.length);
91
- out[4] = type.charCodeAt(0);
92
- out[5] = type.charCodeAt(1);
93
- out[6] = type.charCodeAt(2);
94
- out[7] = type.charCodeAt(3);
95
- out.set(data, 8);
96
- view.setUint32(8 + data.length, crc32(out.subarray(4, 8 + data.length)));
97
- return out;
98
- }
99
- function encodePng(width, height, rgba) {
100
- const ihdr = new Uint8Array(13);
101
- const ihdrView = new DataView(ihdr.buffer);
102
- ihdrView.setUint32(0, width);
103
- ihdrView.setUint32(4, height);
104
- ihdr[8] = 8;
105
- ihdr[9] = 6;
106
- ihdr[10] = 0;
107
- ihdr[11] = 0;
108
- ihdr[12] = 0;
109
- const stride = width * 4;
110
- const raw = new Uint8Array((stride + 1) * height);
111
- for (let y = 0;y < height; y += 1) {
112
- const rawOffset = y * (stride + 1);
113
- raw[rawOffset] = 0;
114
- raw.set(rgba.subarray(y * stride, y * stride + stride), rawOffset + 1);
115
- }
116
- const compressed = deflateSync(raw, { level: ZLIB_LEVEL });
117
- return Buffer.concat([
118
- Buffer.from(PNG_SIGNATURE),
119
- Buffer.from(chunk("IHDR", ihdr)),
120
- Buffer.from(chunk("IDAT", compressed)),
121
- Buffer.from(chunk("IEND", new Uint8Array(0)))
122
- ]);
123
- }
124
- function kittyImageSequence(base64, options) {
125
- const params = [`a=T`, `f=${options.format}`, `q=2`, `C=1`, `c=${options.columns}`, `r=${options.rows}`, `i=${options.imageId}`, `z=${options.zIndex}`];
126
- if (options.format === 32) {
127
- params.push(`s=${options.pixelWidth ?? 1}`, `v=${options.pixelHeight ?? 1}`);
128
- if (options.compressed)
129
- params.push("o=z");
130
- }
131
- if (base64.length <= KITTY_CHUNK_SIZE)
132
- return `\x1B_G${params.join(",")};${base64}\x1B\\`;
133
- const chunks = [];
134
- for (let offset = 0;offset < base64.length; offset += KITTY_CHUNK_SIZE) {
135
- const part = base64.slice(offset, offset + KITTY_CHUNK_SIZE);
136
- const last = offset + KITTY_CHUNK_SIZE >= base64.length;
137
- chunks.push(`\x1B_G${offset === 0 ? `${params.join(",")},` : ""}m=${last ? 0 : 1};${part}\x1B\\`);
138
- }
139
- return chunks.join("");
140
- }
141
- function isModernImageTerminal(protocol) {
142
- return protocol === "kitty";
143
- }
144
- function clampByte(value) {
145
- return Math.max(0, Math.min(255, Math.round(value)));
146
- }
147
- function blendOver(data, index, color, alphaScale = 1) {
148
- const alpha = color[3] / 255 * alphaScale;
149
- const inv = 1 - alpha;
150
- data[index] = clampByte(color[0] * alpha + data[index] * inv);
151
- data[index + 1] = clampByte(color[1] * alpha + data[index + 1] * inv);
152
- data[index + 2] = clampByte(color[2] * alpha + data[index + 2] * inv);
153
- data[index + 3] = 255;
154
- }
155
- function drawDisc(data, width, height, cx, cy, radius, color, alpha = 1) {
156
- const minX = Math.max(0, Math.floor(cx - radius));
157
- const maxX = Math.min(width - 1, Math.ceil(cx + radius));
158
- const minY = Math.max(0, Math.floor(cy - radius));
159
- const maxY = Math.min(height - 1, Math.ceil(cy + radius));
160
- for (let y = minY;y <= maxY; y += 1) {
161
- for (let x = minX;x <= maxX; x += 1) {
162
- const dx = x + 0.5 - cx;
163
- const dy = y + 0.5 - cy;
164
- const d = Math.sqrt(dx * dx + dy * dy);
165
- if (d > radius)
166
- continue;
167
- const edge = Math.max(0, Math.min(1, radius - d));
168
- blendOver(data, (y * width + x) * 4, color, alpha * Math.min(1, 0.35 + edge));
169
- }
170
- }
171
- }
172
- function drawGlow(data, width, height, cx, cy, radius, color, alpha = 0.18) {
173
- const minX = Math.max(0, Math.floor(cx - radius));
174
- const maxX = Math.min(width - 1, Math.ceil(cx + radius));
175
- const minY = Math.max(0, Math.floor(cy - radius));
176
- const maxY = Math.min(height - 1, Math.ceil(cy + radius));
177
- for (let y = minY;y <= maxY; y += 1) {
178
- for (let x = minX;x <= maxX; x += 1) {
179
- const dx = x + 0.5 - cx;
180
- const dy = y + 0.5 - cy;
181
- const d = Math.sqrt(dx * dx + dy * dy);
182
- if (d > radius)
183
- continue;
184
- const falloff = Math.pow(1 - d / Math.max(1, radius), 2.4);
185
- blendOver(data, (y * width + x) * 4, color, alpha * falloff);
186
- }
187
- }
188
- }
189
- function drawLine(data, width, height, x0, y0, x1, y1, color, alpha = 0.5, thickness = 1.4) {
190
- const dx = x1 - x0;
191
- const dy = y1 - y0;
192
- const steps = Math.max(1, Math.ceil(Math.hypot(dx, dy) * 1.2));
193
- for (let i = 0;i <= steps; i += 1) {
194
- const t = i / steps;
195
- drawDisc(data, width, height, x0 + dx * t, y0 + dy * t, thickness, color, alpha);
196
- }
197
- }
198
- function drawDrone(data, width, height, x, y, scale, tick, color) {
199
- const wobble = Math.sin(tick * 0.055) * scale * 0.35;
200
- const cy = y + wobble;
201
- drawGlow(data, width, height, x, cy, scale * 7, color, 0.18);
202
- drawDisc(data, width, height, x, cy, scale * 1.45, color, 0.92);
203
- drawDisc(data, width, height, x, cy, scale * 0.55, [235, 255, 176, 255], 0.85);
204
- const arm = scale * 4.1;
205
- const rotor = scale * 1.6;
206
- const arms = [[-arm, -arm * 0.72], [arm, -arm * 0.72], [-arm, arm * 0.72], [arm, arm * 0.72]];
207
- for (const [dx, dy] of arms) {
208
- drawLine(data, width, height, x, cy, x + dx, cy + dy, color, 0.42, Math.max(1, scale * 0.22));
209
- drawGlow(data, width, height, x + dx, cy + dy, rotor * 2.6, color, 0.1);
210
- drawDisc(data, width, height, x + dx, cy + dy, rotor, color, 0.34 + 0.12 * Math.sin(tick * 0.15));
211
- }
212
- }
213
- function roundRectAlpha(px, py, x, y, w, h, r) {
214
- const rx = Math.max(x + r, Math.min(px, x + w - r));
215
- const ry = Math.max(y + r, Math.min(py, y + h - r));
216
- const dx = px - rx;
217
- const dy = py - ry;
218
- const dist = Math.sqrt(dx * dx + dy * dy);
219
- return Math.max(0, Math.min(1, r + 0.75 - dist));
220
- }
221
- function panelRect(layout, panel, size) {
222
- const cellW = size.width / layout.width;
223
- const cellH = size.height / layout.height;
224
- const leftCells = layout.centerLeft + (panel.left ?? 0);
225
- const topCells = layout.centerTop + panel.top;
226
- const widthCells = panel.width ?? layout.centerWidth;
227
- const heightCells = panel.height;
228
- const left = Math.round(leftCells * cellW);
229
- const top = Math.round(topCells * cellH);
230
- const width = Math.round(widthCells * cellW);
231
- const height = Math.round(heightCells * cellH);
232
- return width > 8 && height > 8 ? { left, top, width, height } : null;
233
- }
234
- function downsampleRegion(data, canvasW, canvasH, rect, scale) {
235
- const w = Math.max(1, Math.ceil(rect.width / scale));
236
- const h = Math.max(1, Math.ceil(rect.height / scale));
237
- const out = new Uint8ClampedArray(w * h * 3);
238
- for (let y = 0;y < h; y += 1) {
239
- for (let x = 0;x < w; x += 1) {
240
- let r = 0, g = 0, b = 0, count = 0;
241
- const sx0 = rect.left + x * scale;
242
- const sy0 = rect.top + y * scale;
243
- for (let yy = 0;yy < scale; yy += 1) {
244
- const sy = sy0 + yy;
245
- if (sy < 0 || sy >= canvasH)
246
- continue;
247
- for (let xx = 0;xx < scale; xx += 1) {
248
- const sx = sx0 + xx;
249
- if (sx < 0 || sx >= canvasW)
250
- continue;
251
- const i = (sy * canvasW + sx) * 4;
252
- r += data[i];
253
- g += data[i + 1];
254
- b += data[i + 2];
255
- count += 1;
256
- }
257
- }
258
- const oi = (y * w + x) * 3;
259
- out[oi] = count ? r / count : BG[0];
260
- out[oi + 1] = count ? g / count : BG[1];
261
- out[oi + 2] = count ? b / count : BG[2];
262
- }
263
- }
264
- return { pixels: out, width: w, height: h };
265
- }
266
- function blurRgb(buffer, width, height, radius) {
267
- const tmp = new Uint8ClampedArray(buffer.length);
268
- const out = new Uint8ClampedArray(buffer.length);
269
- const window = radius * 2 + 1;
270
- for (let y = 0;y < height; y += 1) {
271
- let r = 0, g = 0, b = 0;
272
- for (let x = -radius;x <= radius; x += 1) {
273
- const sx = Math.max(0, Math.min(width - 1, x));
274
- const i = (y * width + sx) * 3;
275
- r += buffer[i];
276
- g += buffer[i + 1];
277
- b += buffer[i + 2];
278
- }
279
- for (let x = 0;x < width; x += 1) {
280
- const oi = (y * width + x) * 3;
281
- tmp[oi] = r / window;
282
- tmp[oi + 1] = g / window;
283
- tmp[oi + 2] = b / window;
284
- const removeX = Math.max(0, x - radius);
285
- const addX = Math.min(width - 1, x + radius + 1);
286
- const ri = (y * width + removeX) * 3;
287
- const ai = (y * width + addX) * 3;
288
- r += tmp.length ? buffer[ai] - buffer[ri] : 0;
289
- g += tmp.length ? buffer[ai + 1] - buffer[ri + 1] : 0;
290
- b += tmp.length ? buffer[ai + 2] - buffer[ri + 2] : 0;
291
- }
292
- }
293
- for (let x = 0;x < width; x += 1) {
294
- let r = 0, g = 0, b = 0;
295
- for (let y = -radius;y <= radius; y += 1) {
296
- const sy = Math.max(0, Math.min(height - 1, y));
297
- const i = (sy * width + x) * 3;
298
- r += tmp[i];
299
- g += tmp[i + 1];
300
- b += tmp[i + 2];
301
- }
302
- for (let y = 0;y < height; y += 1) {
303
- const oi = (y * width + x) * 3;
304
- out[oi] = r / window;
305
- out[oi + 1] = g / window;
306
- out[oi + 2] = b / window;
307
- const removeY = Math.max(0, y - radius);
308
- const addY = Math.min(height - 1, y + radius + 1);
309
- const ri = (removeY * width + x) * 3;
310
- const ai = (addY * width + x) * 3;
311
- r += tmp[ai] - tmp[ri];
312
- g += tmp[ai + 1] - tmp[ri + 1];
313
- b += tmp[ai + 2] - tmp[ri + 2];
314
- }
315
- }
316
- return out;
317
- }
318
- function panelMaskKey(width, height, rect, headerPx, blurScale) {
319
- return `${width}x${height}:${rect.left},${rect.top},${rect.width},${rect.height}:${Math.round(headerPx * 100) / 100}:${blurScale}`;
320
- }
321
- function getPanelMask(width, height, rect, headerPx, blurScale) {
322
- const key = panelMaskKey(width, height, rect, headerPx, blurScale);
323
- const cached = panelMaskCache.get(key);
324
- if (cached)
325
- return cached;
326
- const radius = Math.max(14, Math.min(34, Math.round(Math.min(rect.width, rect.height) * 0.035)));
327
- const sampledWidth = Math.max(1, Math.ceil(rect.width / blurScale));
328
- const sampledHeight = Math.max(1, Math.ceil(rect.height / blurScale));
329
- const x0 = Math.max(0, rect.left);
330
- const y0 = Math.max(0, rect.top);
331
- const x1 = Math.min(width - 1, rect.left + rect.width - 1);
332
- const y1 = Math.min(height - 1, rect.top + rect.height - 1);
333
- const indices = [];
334
- const sampleIndices = [];
335
- const panelAlpha = [];
336
- const edgeAlpha = [];
337
- const headerFlags = [];
338
- const dividerIndices = [];
339
- for (let y = y0;y <= y1; y += 1) {
340
- for (let x = x0;x <= x1; x += 1) {
341
- const a = roundRectAlpha(x + 0.5, y + 0.5, rect.left, rect.top, rect.width, rect.height, radius);
342
- if (a <= 0)
343
- continue;
344
- const edge = roundRectAlpha(x + 0.5, y + 0.5, rect.left + 1.2, rect.top + 1.2, rect.width - 2.4, rect.height - 2.4, Math.max(1, radius - 1.2));
345
- const sx = Math.max(0, Math.min(sampledWidth - 1, Math.floor((x - rect.left) / blurScale)));
346
- const sy = Math.max(0, Math.min(sampledHeight - 1, Math.floor((y - rect.top) / blurScale)));
347
- indices.push((y * width + x) * 4);
348
- sampleIndices.push((sy * sampledWidth + sx) * 3);
349
- panelAlpha.push(a);
350
- edgeAlpha.push(edge < 0.96 ? Math.min(1, (1 - edge) * 0.7) : 0);
351
- headerFlags.push(y < rect.top + headerPx ? 1 : 0);
352
- }
353
- }
354
- const dividerY = Math.round(rect.top + headerPx);
355
- if (dividerY > y0 && dividerY < y1) {
356
- for (let x = x0 + radius;x <= x1 - radius; x += 1) {
357
- dividerIndices.push((dividerY * width + x) * 4);
358
- }
359
- }
360
- const mask = {
361
- key,
362
- indices: Uint32Array.from(indices),
363
- sampleIndices: Uint32Array.from(sampleIndices),
364
- panelAlpha: Float32Array.from(panelAlpha),
365
- edgeAlpha: Float32Array.from(edgeAlpha),
366
- headerFlags: Uint8Array.from(headerFlags),
367
- dividerIndices: Uint32Array.from(dividerIndices)
368
- };
369
- panelMaskCache.set(key, mask);
370
- while (panelMaskCache.size > PANEL_MASK_CACHE_LIMIT) {
371
- const oldest = panelMaskCache.keys().next().value;
372
- if (!oldest)
373
- break;
374
- panelMaskCache.delete(oldest);
375
- }
376
- return mask;
377
- }
378
- function compositePanel(data, width, height, rect, headerPx) {
379
- const blurScale = PANEL_BLUR_SCALE;
380
- const sampled = downsampleRegion(data, width, height, rect, blurScale);
381
- const blurred = blurRgb(sampled.pixels, sampled.width, sampled.height, 4);
382
- const mask = getPanelMask(width, height, rect, headerPx, blurScale);
383
- for (let i = 0;i < mask.indices.length; i += 1) {
384
- const idx = mask.indices[i];
385
- const sampleIdx = mask.sampleIndices[i];
386
- data[idx] = blurred[sampleIdx];
387
- data[idx + 1] = blurred[sampleIdx + 1];
388
- data[idx + 2] = blurred[sampleIdx + 2];
389
- data[idx + 3] = 255;
390
- blendOver(data, idx, mask.headerFlags[i] ? PANEL_HEADER : PANEL, mask.panelAlpha[i]);
391
- const edge = mask.edgeAlpha[i];
392
- if (edge > 0)
393
- blendOver(data, idx, PANEL_LINE, edge);
394
- }
395
- for (let i = 0;i < mask.dividerIndices.length; i += 1) {
396
- blendOver(data, mask.dividerIndices[i], PANEL_LINE, 0.28);
397
- }
398
- }
399
- function visualSceneKind(scene) {
400
- if (scene === "tasks")
401
- return "loop";
402
- if (scene === "help")
403
- return "carrier";
404
- return "dispatch";
405
- }
406
- function seededUnit(seed) {
407
- let value = seed >>> 0;
408
- value = value * 1664525 + 1013904223 >>> 0;
409
- return value / 4294967295;
410
- }
411
- function sceneCore(width, height, kind) {
412
- if (kind === "dispatch")
413
- return { x: width * 0.3, y: height * 0.45 };
414
- if (kind === "carrier")
415
- return { x: width * 0.5, y: height * 0.54 };
416
- return { x: width * 0.09, y: height * 0.56 };
417
- }
418
- function dispatchLane(width, index, count) {
419
- const a = seededUnit(28672 + index * 101);
420
- const b = seededUnit(36864 + index * 131);
421
- const c = seededUnit(45056 + index * 151);
422
- const ang = (-0.9 + 1.8 * (index / Math.max(1, count - 1))) * (Math.PI * 0.5);
423
- return { ang, len: width * (0.32 + a * 0.42), curve: (b - 0.5) * 0.7, phase: c * Math.PI * 2 };
424
- }
425
- function lanePoint(width, height, lane, p, kind = "dispatch") {
426
- const core = sceneCore(width, height, kind);
427
- const dist = lane.len * p;
428
- const bend = Math.sin(p * Math.PI) * lane.curve * Math.min(width, height) * 0.035;
429
- const ux = Math.cos(lane.ang);
430
- const uy = Math.sin(lane.ang);
431
- return { x: core.x + ux * dist + -uy * bend, y: core.y + uy * dist + ux * bend };
432
- }
433
- function drawMarketingRails(data, width, height, kind, tick) {
434
- const ys = kind === "loop" ? [0.18, 0.5, 0.82] : kind === "carrier" ? [0.24, 0.54, 0.82] : [0.18, 0.58, 0.82];
435
- ys.forEach((ratio, index) => {
436
- const y = height * ratio + Math.sin(tick * 0.018 + index) * Math.max(2, height * 0.0025);
437
- const color = index === 2 ? CYAN : index === 1 ? LIME : LIME_DIM;
438
- drawLine(data, width, height, width * 0.06, y, width * 0.94, y + Math.sin(index) * height * 0.002, color, index === 1 ? 0.11 : 0.07, Math.max(0.8, height * 0.0012));
439
- for (let p = (tick * 0.004 + index * 0.21) % 1;p < 1; p += 0.18 + index * 0.02) {
440
- const x = width * (0.06 + 0.88 * p);
441
- drawDisc(data, width, height, x, y, Math.max(1.2, height * (0.0017 + index * 0.0004)), color, 0.24);
442
- drawGlow(data, width, height, x, y, Math.max(5, height * 0.006), color, 0.035);
443
- }
444
- });
445
- }
446
- function drawDispatchScene(data, width, height, tick) {
447
- const core = sceneCore(width, height, "dispatch");
448
- const min = Math.min(width, height);
449
- drawGlow(data, width, height, core.x, core.y, min * 0.085, LIME, 0.12);
450
- drawDisc(data, width, height, core.x, core.y, min * 0.0065, LIME, 0.85);
451
- const laneCount = width < 1000 ? 7 : 12;
452
- const lanes = Array.from({ length: laneCount }, (_, index) => dispatchLane(width, index, laneCount));
453
- lanes.forEach((lane) => {
454
- let prev = lanePoint(width, height, lane, 0);
455
- for (let step = 1;step <= 32; step += 1) {
456
- const next = lanePoint(width, height, lane, step / 32);
457
- drawLine(data, width, height, prev.x, prev.y, next.x, next.y, lane.phase > Math.PI ? CYAN : LIME_DIM, 0.045, Math.max(0.7, min * 0.0009));
458
- prev = next;
459
- }
460
- });
461
- const packets = width < 1000 ? 70 : 150;
462
- for (let i = 0;i < packets; i += 1) {
463
- const lane = lanes[i % lanes.length];
464
- const speed = 0.003 + seededUnit(12288 + i * 17) * 0.009;
465
- const p = (seededUnit(16384 + i * 19) + tick * speed) % 1;
466
- const pt = lanePoint(width, height, lane, p);
467
- const wobble = (seededUnit(20480 + i * 23) - 0.5) * min * 0.012;
468
- const fade = p < 0.1 ? p / 0.1 : p > 0.88 ? (1 - p) / 0.12 : 1;
469
- const color = seededUnit(24576 + i * 29) < 0.22 ? CYAN : LIME_DIM;
470
- const y = pt.y + wobble * Math.sin(p * Math.PI * 2);
471
- drawLine(data, width, height, pt.x - min * 0.012, y - min * 0.002, pt.x, y, color, 0.08 * fade, Math.max(0.7, min * 0.0008));
472
- drawDisc(data, width, height, pt.x, y, Math.max(1.3, min * 0.0022), color, 0.5 * fade);
473
- drawGlow(data, width, height, pt.x, y, Math.max(4, min * 0.008), color, 0.045 * fade);
474
- }
475
- for (let i = 0;i < (width < 1000 ? 4 : 8); i += 1) {
476
- const lane = lanes[i % lanes.length];
477
- const p = (tick * 0.002 + i * 0.13) % 1;
478
- const pt = lanePoint(width, height, lane, p);
479
- drawDrone(data, width, height, pt.x, pt.y + Math.sin(tick * 0.04 + i) * min * 0.004, min * (0.006 + i % 2 * 0.0015), tick + i * 11, i % 3 === 0 ? CYAN : LIME_DIM);
480
- }
481
- }
482
- function drawLoopScene(data, width, height, tick) {
483
- const min = Math.min(width, height);
484
- const y = height * 0.56;
485
- const x0 = width * 0.09;
486
- const x1 = width * 0.91;
487
- drawLine(data, width, height, x0, y, x1, y, LIME_DIM, 0.12, Math.max(0.8, min * 0.001));
488
- const gates = width < 1000 ? 4 : 5;
489
- const active = Math.floor(tick / 16) % gates;
490
- for (let i = 0;i < gates; i += 1) {
491
- const x = x0 + (x1 - x0) * (i / Math.max(1, gates - 1));
492
- const color = i === active ? LIME : i <= active ? LIME_DIM : INK_DIM;
493
- drawLine(data, width, height, x, y - min * 0.05, x, y + min * 0.05, color, i === active ? 0.25 : 0.08, Math.max(0.8, min * 0.001));
494
- drawDisc(data, width, height, x, y, i === active ? min * 0.006 : min * 0.0035, color, i === active ? 0.72 : 0.25);
495
- drawGlow(data, width, height, x, y, i === active ? min * 0.018 : min * 0.01, color, i === active ? 0.1 : 0.035);
496
- }
497
- const packets = width < 1000 ? 36 : 84;
498
- for (let i = 0;i < packets; i += 1) {
499
- const p = (seededUnit(33024 + i * 13) + tick * (0.0022 + seededUnit(33280 + i * 17) * 0.004)) % 1;
500
- const x = x0 + (x1 - x0) * p;
501
- const segment = Math.min(gates - 1, Math.floor(p * gates));
502
- const color = segment < active ? LIME_DIM : segment === active ? CYAN : INK_DIM;
503
- const py = y + (seededUnit(33536 + i * 19) - 0.5) * min * 0.018 * Math.sin(p * Math.PI * 2);
504
- drawLine(data, width, height, x - min * 0.014, py, x, py, color, 0.1, Math.max(0.7, min * 0.0008));
505
- drawDisc(data, width, height, x, py, Math.max(1.2, min * 0.002), color, color === INK_DIM ? 0.22 : 0.58);
506
- }
507
- drawDrone(data, width, height, x0 + (x1 - x0) * (tick * 0.003 % 1), y - min * 0.04, min * 0.0065, tick, LIME_DIM);
508
- drawDrone(data, width, height, x0 + (x1 - x0) * ((tick * 0.002 + 0.5) % 1), y + min * 0.036, min * 0.0055, tick + 40, MAGENTA);
509
- }
510
- function drawCarrierScene(data, width, height, tick) {
511
- const min = Math.min(width, height);
512
- const core = sceneCore(width, height, "carrier");
513
- drawGlow(data, width, height, core.x, core.y, min * 0.075, LIME, 0.12);
514
- drawDisc(data, width, height, core.x, core.y, min * 0.0065, LIME, 0.92);
515
- const nodes = width < 1000 ? 5 : 7;
516
- const rx = width * 0.36;
517
- const ry = height * 0.22;
518
- for (let i = 0;i < nodes; i += 1) {
519
- const a = i / nodes * Math.PI * 2 - Math.PI / 2 + tick * 0.006;
520
- const x = core.x + Math.cos(a) * rx;
521
- const y = core.y + Math.sin(a) * ry;
522
- const color = i % 2 ? CYAN : LIME_DIM;
523
- drawLine(data, width, height, core.x, core.y, x, y, color, 0.055, Math.max(0.7, min * 0.0008));
524
- drawGlow(data, width, height, x, y, min * 0.018, color, 0.055);
525
- drawDisc(data, width, height, x, y, min * 0.0048, color, 0.62);
526
- drawDrone(data, width, height, x, y - min * 0.018, min * 0.005, tick + i * 9, color);
527
- }
528
- const packets = width < 1000 ? 30 : 72;
529
- for (let i = 0;i < packets; i += 1) {
530
- const lane = i % nodes;
531
- const a = lane / nodes * Math.PI * 2 - Math.PI / 2 + tick * 0.006;
532
- const nx = core.x + Math.cos(a) * rx;
533
- const ny = core.y + Math.sin(a) * ry;
534
- const p = (seededUnit(37120 + i * 37) + tick * (0.003 + seededUnit(37376 + i * 43) * 0.009)) % 1;
535
- const x = core.x + (nx - core.x) * p;
536
- const y = core.y + (ny - core.y) * p;
537
- const color = seededUnit(37632 + i * 47) < 0.35 ? CYAN : LIME_DIM;
538
- drawDisc(data, width, height, x, y, Math.max(1.2, min * 0.002), color, 0.48);
539
- drawGlow(data, width, height, x, y, min * 0.008, color, 0.035);
540
- }
541
- }
542
- function drawBackground(data, width, height, tick, scene) {
543
- fillRgba(data, BG, BG_WORD);
544
- const kind = visualSceneKind(scene);
545
- drawGlow(data, width, height, width * 0.82, height * 0.04, Math.min(width, height) * 0.22, LIME, 0.035);
546
- drawGlow(data, width, height, width * 0.12, height * 0.18, Math.min(width, height) * 0.17, CYAN, 0.025);
547
- drawMarketingRails(data, width, height, kind, tick);
548
- if (kind === "loop")
549
- drawLoopScene(data, width, height, tick);
550
- else if (kind === "carrier")
551
- drawCarrierScene(data, width, height, tick);
552
- else
553
- drawDispatchScene(data, width, height, tick);
554
- }
555
- function imageVisualFrameKey(input) {
556
- const width = Math.max(1, Math.floor(input.pixelSize.width));
557
- const height = Math.max(1, Math.floor(input.pixelSize.height));
558
- const layer = "layer" in input ? input.layer ?? "full" : "full";
559
- return `${layer}:${width}x${height}:${input.layout.width}x${input.layout.height}:${input.scene}:${input.tick}:${input.panels.map((panel) => `${panel.id}:${panel.top}:${panel.height}:${panel.width ?? ""}:${panel.left ?? ""}:${panel.headerHeight ?? ""}`).join("|")}`;
560
- }
561
- function encodeKittyFrame(width, height, data, input) {
562
- if (input.transport === "png") {
563
- const png = encodePng(width, height, data);
564
- return kittyImageSequence(png.toString("base64"), { columns: input.layout.width, rows: input.layout.height, imageId: input.imageId, zIndex: input.zIndex, format: 100 });
565
- }
566
- const compressed = deflateSync(data, { level: ZLIB_LEVEL });
567
- return kittyImageSequence(compressed.toString("base64"), {
568
- columns: input.layout.width,
569
- rows: input.layout.height,
570
- imageId: input.imageId,
571
- zIndex: input.zIndex,
572
- format: 32,
573
- pixelWidth: width,
574
- pixelHeight: height,
575
- compressed: true
576
- });
577
- }
578
- function renderImageVisualFrame(input) {
579
- const width = Math.max(1, Math.floor(input.pixelSize.width));
580
- const height = Math.max(1, Math.floor(input.pixelSize.height));
581
- const byteCount = width * height * 4;
582
- if (byteCount > MAX_IMAGE_BYTES)
583
- return null;
584
- const data = new Uint8ClampedArray(byteCount);
585
- drawBackground(data, width, height, input.tick, input.scene);
586
- for (const panel of input.panels) {
587
- if (panel.chrome !== "ad-terminal")
588
- continue;
589
- const rect = panelRect(input.layout, panel, { width, height });
590
- if (!rect)
591
- continue;
592
- const cellH = height / input.layout.height;
593
- const headerPx = Math.max(cellH * 3, (panel.headerHeight ?? 3) * cellH);
594
- compositePanel(data, width, height, rect, headerPx);
595
- }
596
- return { key: imageVisualFrameKey(input), sequence: encodeKittyFrame(width, height, data, input) };
597
- }
598
- function createImageWorker() {
599
- if (process.env.RIG_OPENTUI_IMAGE_WORKER === "0")
600
- return null;
601
- const isTypeScriptRuntime = import.meta.url.endsWith(".ts");
602
- const workerUrl = new URL(isTypeScriptRuntime ? "./image-visual-layer-worker.ts" : "./image-visual-layer-worker.js", import.meta.url);
603
- try {
604
- return new Worker(workerUrl);
605
- } catch {
606
- if (typeof process.versions.bun === "string") {
607
- try {
608
- return new Worker("./src/app-opentui/render/image-visual-layer-worker.ts");
609
- } catch {}
610
- }
611
- return null;
612
- }
613
- }
614
- var RECENT_WRITTEN_LIMIT = 24;
615
- var DEFAULT_PANEL_FPS = 24;
616
- var DEFAULT_PANEL_LAYER_SCALE = 0.22;
617
- var DEFAULT_IMAGE_OUTPUT_BACKLOG_BYTES = 256 * 1024;
618
- var DEFAULT_IMAGE_OUTPUT_BYTES_PER_SECOND = 850 * 1024;
619
- var MIN_BACKGROUND_BUDGET_BYTES = 24 * 1024;
620
- var MIN_PANEL_BUDGET_BYTES = 56 * 1024;
621
- function panelFps() {
622
- const raw = Number.parseFloat(process.env.RIG_OPENTUI_PANEL_FPS ?? "");
623
- if (Number.isFinite(raw) && raw > 0)
624
- return Math.max(4, Math.min(60, raw));
625
- return DEFAULT_PANEL_FPS;
626
- }
627
- function panelLayerScale() {
628
- const raw = Number.parseFloat(process.env.RIG_OPENTUI_PANEL_SCALE ?? "");
629
- if (Number.isFinite(raw) && raw > 0)
630
- return Math.max(0.18, Math.min(1, raw));
631
- return DEFAULT_PANEL_LAYER_SCALE;
632
- }
633
- function imageOutputBacklogBytes() {
634
- const raw = Number.parseInt(process.env.RIG_OPENTUI_IMAGE_BACKLOG_BYTES ?? "", 10);
635
- if (Number.isFinite(raw) && raw > 0)
636
- return Math.max(64 * 1024, Math.min(2 * 1024 * 1024, raw));
637
- return DEFAULT_IMAGE_OUTPUT_BACKLOG_BYTES;
638
- }
639
- function imageOutputBytesPerSecond() {
640
- const raw = Number.parseInt(process.env.RIG_OPENTUI_IMAGE_BYTES_PER_SECOND ?? "", 10);
641
- if (Number.isFinite(raw) && raw > 0)
642
- return Math.max(128 * 1024, Math.min(2 * 1024 * 1024, raw));
643
- return DEFAULT_IMAGE_OUTPUT_BYTES_PER_SECOND;
644
- }
645
- function pendingLayerKey(key) {
646
- return key.split(":", 1)[0] || "full";
647
- }
648
-
649
- class ImageVisualLayer {
650
- imageId = allocateImageId();
651
- panelImageIds = Array.from({ length: 8 }, () => allocateImageId());
652
- panelChromeImageIds = Array.from({ length: 8 }, () => allocateImageId());
653
- stdout;
654
- protocol;
655
- transport = imageTransport();
656
- frameIntervalMs = 1000 / imageFps();
657
- panelIntervalMs = 1000 / panelFps();
658
- maxOutputBacklogBytes = imageOutputBacklogBytes();
659
- outputBytesPerSecond = imageOutputBytesPerSecond();
660
- outputBudgetBytes = imageOutputBytesPerSecond();
661
- lastBudgetAtMs = Date.now();
662
- motionSlot = this.createSlot();
663
- panelSlot = this.createSlot();
664
- chromeSlot = this.createSlot();
665
- pendingFrames = new Map;
666
- recentWrittenKeys = [];
667
- imagesVisible = false;
668
- requestId = 0;
669
- lastMotionFrameIndex = -1;
670
- lastPanelFrameIndex = -1;
671
- lastChromeKey = "";
672
- destroyed = false;
673
- constructor(stdout = process.stdout) {
674
- this.stdout = stdout;
675
- this.protocol = getCapabilities().images;
676
- if (this.enabled) {
677
- this.startWorker(this.motionSlot);
678
- this.startWorker(this.panelSlot);
679
- this.startWorker(this.chromeSlot);
680
- }
681
- }
682
- get enabled() {
683
- return isModernImageTerminal(this.protocol);
684
- }
685
- clear() {
686
- if (this.enabled) {
687
- if (this.imagesVisible)
688
- this.stdout.write([this.imageId, ...this.panelImageIds, ...this.panelChromeImageIds].map((id) => deleteKittyImage(id)).join("") + "\x1B[?25h");
689
- this.imagesVisible = false;
690
- this.pendingFrames.clear();
691
- this.recentWrittenKeys.length = 0;
692
- this.resetSlot(this.motionSlot);
693
- this.resetSlot(this.panelSlot);
694
- this.resetSlot(this.chromeSlot);
695
- this.lastMotionFrameIndex = -1;
696
- this.lastPanelFrameIndex = -1;
697
- this.lastChromeKey = "";
698
- this.outputBudgetBytes = this.outputBytesPerSecond;
699
- this.lastBudgetAtMs = Date.now();
700
- this.motionSlot.clearedThroughRequestId = this.requestId;
701
- this.panelSlot.clearedThroughRequestId = this.requestId;
702
- this.chromeSlot.clearedThroughRequestId = this.requestId;
703
- }
704
- }
705
- destroy() {
706
- if (this.destroyed)
707
- return;
708
- this.clear();
709
- this.destroyed = true;
710
- const workers = [this.motionSlot.worker, this.panelSlot.worker, this.chromeSlot.worker];
711
- this.motionSlot.worker = null;
712
- this.panelSlot.worker = null;
713
- this.chromeSlot.worker = null;
714
- for (const worker of workers)
715
- if (worker)
716
- worker.terminate().catch(() => {
717
- return;
718
- });
719
- }
720
- render(input) {
721
- if (!this.enabled || this.destroyed)
722
- return;
723
- const width = Math.max(1, Math.floor(input.pixelSize.width));
724
- const height = Math.max(1, Math.floor(input.pixelSize.height));
725
- if (width * height * 4 > MAX_IMAGE_BYTES)
726
- return;
727
- if (this.isOutputBackedUp())
728
- return;
729
- this.refillOutputBudget();
730
- const now = Date.now();
731
- const visualTick = Math.floor(now / (1000 / 60));
732
- const useDynamicSplit = Boolean(this.motionSlot.worker && this.panelSlot.worker && this.chromeSlot.worker && this.transport === "png" && process.env.RIG_OPENTUI_DYNAMIC_SPLIT !== "0");
733
- if (!useDynamicSplit) {
734
- const frameIndex = Math.floor(now / this.frameIntervalMs);
735
- if (!input.force && frameIndex === this.lastMotionFrameIndex)
736
- return;
737
- this.scheduleRender(this.motionSlot, { ...input, tick: visualTick, layer: "full" }, this.imageId, -10, input.force);
738
- this.lastMotionFrameIndex = frameIndex;
739
- return;
740
- }
741
- const motionFrameIndex = Math.floor(now / this.frameIntervalMs);
742
- if ((input.force || motionFrameIndex !== this.lastMotionFrameIndex) && this.outputBudgetBytes >= MIN_BACKGROUND_BUDGET_BYTES) {
743
- this.scheduleRender(this.motionSlot, { ...input, pixelSize: scaledPixelSize(input.pixelSize, droneLayerScale(), input.layout), panels: [], tick: visualTick, layer: "background" }, this.imageId, -30, input.force);
744
- this.lastMotionFrameIndex = motionFrameIndex;
745
- }
746
- const panelFrameIndex = Math.floor(now / this.panelIntervalMs);
747
- if ((input.force || panelFrameIndex !== this.lastPanelFrameIndex) && this.outputBudgetBytes >= MIN_PANEL_BUDGET_BYTES) {
748
- this.scheduleRender(this.panelSlot, { ...input, pixelSize: scaledPixelSize(input.pixelSize, panelLayerScale(), input.layout), tick: visualTick, layer: "panel-patches" }, this.imageId, -12, input.force, this.panelImageIds);
749
- this.lastPanelFrameIndex = panelFrameIndex;
750
- }
751
- const chromeInput = { ...input, tick: 0, layer: "panel-chrome" };
752
- const chromeKey = imageVisualFrameKey(chromeInput);
753
- if (input.force || chromeKey !== this.lastChromeKey) {
754
- this.scheduleRender(this.chromeSlot, chromeInput, this.imageId, -8, input.force, this.panelChromeImageIds);
755
- this.lastChromeKey = chromeKey;
756
- }
757
- }
758
- flush() {
759
- if (this.pendingFrames.size === 0)
760
- return false;
761
- this.refillOutputBudget();
762
- if (this.isOutputBackedUp()) {
763
- const chrome = this.pendingFrames.get("panel-chrome");
764
- this.pendingFrames.clear();
765
- if (chrome)
766
- this.pendingFrames.set("panel-chrome", chrome);
767
- return false;
768
- }
769
- const framePriority = (frame) => {
770
- const layer = pendingLayerKey(frame.key);
771
- if (layer === "panel-chrome")
772
- return 0;
773
- if (layer === "background")
774
- return 1;
775
- if (layer === "panel-patches")
776
- return 2;
777
- return 2;
778
- };
779
- const frames = Array.from(this.pendingFrames.values()).sort((a, b) => framePriority(a) - framePriority(b));
780
- const prefix = "\x1B[?25l\x1B7\x1B[s\x1B[H";
781
- const suffix = "\x1B[u\x1B8";
782
- const selected = [];
783
- const retained = new Map;
784
- let sequence = "";
785
- let byteLength = Buffer.byteLength(prefix + suffix);
786
- for (const frame of frames) {
787
- const candidate = sequence + frame.sequence;
788
- const candidateBytes = Buffer.byteLength(prefix + candidate + suffix);
789
- if (candidateBytes <= this.outputBudgetBytes) {
790
- selected.push(frame);
791
- sequence = candidate;
792
- byteLength = candidateBytes;
793
- } else if (pendingLayerKey(frame.key) === "panel-chrome") {
794
- retained.set(pendingLayerKey(frame.key), frame);
795
- }
796
- }
797
- this.pendingFrames.clear();
798
- for (const [layer, frame] of retained)
799
- this.pendingFrames.set(layer, frame);
800
- if (!sequence || selected.length === 0)
801
- return false;
802
- const payload = `${prefix}${sequence}${suffix}`;
803
- for (const frame of selected)
804
- this.markWritten(frame.key);
805
- this.outputBudgetBytes -= byteLength;
806
- this.stdout.cork?.();
807
- const accepted = this.stdout.write(payload);
808
- this.stdout.uncork?.();
809
- this.imagesVisible = true;
810
- return accepted;
811
- }
812
- createSlot() {
813
- return { worker: null, busy: false, queuedRequest: null, inFlightKey: "", queuedKey: "", clearedThroughRequestId: 0 };
814
- }
815
- resetSlot(slot) {
816
- slot.busy = false;
817
- slot.queuedRequest = null;
818
- slot.inFlightKey = "";
819
- slot.queuedKey = "";
820
- }
821
- markWritten(key) {
822
- this.recentWrittenKeys.push(key);
823
- while (this.recentWrittenKeys.length > RECENT_WRITTEN_LIMIT)
824
- this.recentWrittenKeys.shift();
825
- }
826
- refillOutputBudget() {
827
- const now = Date.now();
828
- const elapsedMs = Math.max(0, now - this.lastBudgetAtMs);
829
- this.lastBudgetAtMs = now;
830
- this.outputBudgetBytes = Math.min(this.outputBytesPerSecond, this.outputBudgetBytes + elapsedMs / 1000 * this.outputBytesPerSecond);
831
- }
832
- isOutputBackedUp() {
833
- return Boolean(this.stdout.writableNeedDrain) || this.stdout.writableLength > this.maxOutputBacklogBytes;
834
- }
835
- stageFrame(frame) {
836
- this.pendingFrames.set(pendingLayerKey(frame.key), frame);
837
- }
838
- isKnownKey(slot, key) {
839
- return this.recentWrittenKeys.includes(key) || Array.from(this.pendingFrames.values()).some((frame) => frame.key === key) || key === slot.inFlightKey || key === slot.queuedKey;
840
- }
841
- scheduleRender(slot, input, imageId, zIndex, force, imageIds) {
842
- const key = imageVisualFrameKey(input);
843
- if (!force && this.isKnownKey(slot, key))
844
- return;
845
- const request = {
846
- ...input,
847
- imageId,
848
- ...imageIds ? { imageIds } : {},
849
- zIndex,
850
- transport: this.transport,
851
- requestId: ++this.requestId,
852
- key
853
- };
854
- if (slot.worker) {
855
- this.enqueueWorkerRender(slot, request);
856
- return;
857
- }
858
- this.renderSync(slot, request);
859
- }
860
- startWorker(slot) {
861
- const worker = createImageWorker();
862
- if (!worker)
863
- return;
864
- slot.worker = worker;
865
- worker.on("message", (message) => this.handleWorkerMessage(slot, message));
866
- worker.once("error", () => this.disableWorker(slot));
867
- worker.once("exit", () => this.disableWorker(slot));
868
- }
869
- disableWorker(slot) {
870
- if (this.destroyed)
871
- return;
872
- slot.worker = null;
873
- slot.busy = false;
874
- slot.inFlightKey = "";
875
- const queued = slot.queuedRequest;
876
- slot.queuedRequest = null;
877
- slot.queuedKey = "";
878
- if (queued?.layer === "full")
879
- this.renderSync(slot, queued);
880
- }
881
- enqueueWorkerRender(slot, request) {
882
- if (!slot.worker) {
883
- this.renderSync(slot, request);
884
- return;
885
- }
886
- if (slot.busy) {
887
- slot.queuedRequest = request;
888
- slot.queuedKey = request.key;
889
- return;
890
- }
891
- this.dispatchWorkerRender(slot, request);
892
- }
893
- dispatchWorkerRender(slot, request) {
894
- if (!slot.worker) {
895
- this.renderSync(slot, request);
896
- return;
897
- }
898
- slot.busy = true;
899
- slot.inFlightKey = request.key;
900
- slot.worker.postMessage(request);
901
- }
902
- handleWorkerMessage(slot, message) {
903
- if (this.destroyed || !message || typeof message !== "object")
904
- return;
905
- const response = message;
906
- slot.busy = false;
907
- slot.inFlightKey = "";
908
- if (response.requestId <= slot.clearedThroughRequestId)
909
- return;
910
- if (response.error) {
911
- this.disableWorker(slot);
912
- return;
913
- }
914
- if (response.sequence && !this.isKnownKey(slot, response.key) && (!this.isOutputBackedUp() || pendingLayerKey(response.key) === "panel-chrome")) {
915
- this.stageFrame({ key: response.key, sequence: response.sequence });
916
- }
917
- const next = slot.queuedRequest;
918
- slot.queuedRequest = null;
919
- slot.queuedKey = "";
920
- if (next && !this.isKnownKey(slot, next.key))
921
- this.dispatchWorkerRender(slot, next);
922
- }
923
- renderSync(slot, request) {
924
- const result = renderImageVisualFrame(request);
925
- if (!result || this.isKnownKey(slot, result.key) || this.isOutputBackedUp())
926
- return;
927
- this.stageFrame(result);
928
- }
929
- }
930
-
931
- // packages/cli/src/app-opentui/render/image-visual-layer-native-canvas.ts
932
- var BG2 = [7, 8, 9, 255];
933
- var PANEL2 = [16, 17, 21, 184];
934
- var PANEL_HEADER2 = [16, 17, 21, 190];
935
- var PANEL_LINE2 = [255, 255, 255, 24];
936
- var LIME2 = [204, 255, 77, 255];
937
- var LIME_DIM2 = [169, 214, 63, 255];
938
- var CYAN2 = [86, 216, 255, 255];
939
- var MAGENTA2 = [255, 121, 176, 255];
940
- var INK_DIM2 = [108, 110, 121, 255];
941
- var KITTY_CHUNK_SIZE2 = 4096;
942
- var MAX_IMAGE_BYTES2 = 48 * 1024 * 1024;
943
- var SKIA_CACHE_CLEAR_INTERVAL = 240;
944
- var DEFAULT_DRONE_LAYER_SCALE2 = 0.18;
945
- var DEFAULT_MOTION_DENSITY = 0.42;
946
- var DEFAULT_MOTION_SPEED = 0.55;
947
- var TEMP_GRAPHICS_DIR = join(tmpdir(), "rig-tty-graphics-protocol");
948
- var frameCanvas = null;
949
- var frameCtx = null;
950
- var sceneCanvas = null;
951
- var sceneCtx = null;
952
- var patchCanvas = null;
953
- var patchCtx = null;
954
- var encodedFrames = 0;
955
- function droneLayerScale2() {
956
- const raw = Number.parseFloat(process.env.RIG_OPENTUI_DRONE_SCALE ?? "");
957
- if (Number.isFinite(raw) && raw > 0)
958
- return Math.max(0.15, Math.min(1, raw));
959
- return DEFAULT_DRONE_LAYER_SCALE2;
960
- }
961
- function kittyTransmission() {
962
- return process.env.RIG_OPENTUI_KITTY_TRANSMISSION === "temp-file" ? "temp-file" : "direct";
963
- }
964
- function motionDensity() {
965
- const raw = Number.parseFloat(process.env.RIG_OPENTUI_MOTION_DENSITY ?? "");
966
- if (Number.isFinite(raw) && raw > 0)
967
- return Math.max(0.2, Math.min(1.4, raw));
968
- return DEFAULT_MOTION_DENSITY;
969
- }
970
- function motionSpeed() {
971
- const raw = Number.parseFloat(process.env.RIG_OPENTUI_MOTION_SPEED ?? "");
972
- if (Number.isFinite(raw) && raw > 0)
973
- return Math.max(0.25, Math.min(1.5, raw));
974
- return DEFAULT_MOTION_SPEED;
975
- }
976
- function resetContext(ctx, width, height) {
977
- ctx.reset();
978
- ctx.clearRect(0, 0, width, height);
979
- ctx.imageSmoothingEnabled = true;
980
- ctx.imageSmoothingQuality = "high";
981
- }
982
- function reusableCanvas(width, height) {
983
- if (!frameCanvas || !frameCtx || frameCanvas.width !== width || frameCanvas.height !== height) {
984
- frameCanvas = createCanvas(width, height);
985
- frameCtx = frameCanvas.getContext("2d");
986
- }
987
- resetContext(frameCtx, width, height);
988
- return { canvas: frameCanvas, ctx: frameCtx };
989
- }
990
- function reusableSceneCanvas(width, height) {
991
- if (!sceneCanvas || !sceneCtx || sceneCanvas.width !== width || sceneCanvas.height !== height) {
992
- sceneCanvas = createCanvas(width, height);
993
- sceneCtx = sceneCanvas.getContext("2d");
994
- }
995
- resetContext(sceneCtx, width, height);
996
- return { canvas: sceneCanvas, ctx: sceneCtx };
997
- }
998
- function reusablePatchCanvas(width, height) {
999
- if (!patchCanvas || !patchCtx || patchCanvas.width !== width || patchCanvas.height !== height) {
1000
- patchCanvas = createCanvas(width, height);
1001
- patchCtx = patchCanvas.getContext("2d");
1002
- }
1003
- resetContext(patchCtx, width, height);
1004
- return { canvas: patchCanvas, ctx: patchCtx };
1005
- }
1006
- function css(color, alphaScale = 1) {
1007
- return `rgba(${color[0]},${color[1]},${color[2]},${Math.max(0, Math.min(1, color[3] / 255 * alphaScale))})`;
1008
- }
1009
- function visualSceneKind2(scene) {
1010
- if (scene === "tasks")
1011
- return "loop";
1012
- if (scene === "help")
1013
- return "carrier";
1014
- return "dispatch";
1015
- }
1016
- function seededUnit2(seed) {
1017
- let value = seed >>> 0;
1018
- value = value * 1664525 + 1013904223 >>> 0;
1019
- return value / 4294967295;
1020
- }
1021
- function sceneCore2(width, height, kind) {
1022
- if (kind === "dispatch")
1023
- return { x: width * 0.3, y: height * 0.45 };
1024
- if (kind === "carrier")
1025
- return { x: width * 0.5, y: height * 0.54 };
1026
- return { x: width * 0.09, y: height * 0.56 };
1027
- }
1028
- function dispatchLane2(width, index, count) {
1029
- const a = seededUnit2(28672 + index * 101);
1030
- const b = seededUnit2(36864 + index * 131);
1031
- const c = seededUnit2(45056 + index * 151);
1032
- const ang = (-0.9 + 1.8 * (index / Math.max(1, count - 1))) * (Math.PI * 0.5);
1033
- return { ang, len: width * (0.32 + a * 0.42), curve: (b - 0.5) * 0.7, phase: c * Math.PI * 2 };
1034
- }
1035
- function lanePoint2(width, height, lane, p, kind = "dispatch") {
1036
- const core = sceneCore2(width, height, kind);
1037
- const dist = lane.len * p;
1038
- const bend = Math.sin(p * Math.PI) * lane.curve * Math.min(width, height) * 0.035;
1039
- const ux = Math.cos(lane.ang);
1040
- const uy = Math.sin(lane.ang);
1041
- return { x: core.x + ux * dist + -uy * bend, y: core.y + uy * dist + ux * bend };
1042
- }
1043
- function drawGlow2(ctx, cx, cy, radius, color, alpha = 0.18) {
1044
- if (radius <= 0)
1045
- return;
1046
- const gradient = ctx.createRadialGradient(cx, cy, 0, cx, cy, radius);
1047
- gradient.addColorStop(0, css(color, alpha));
1048
- gradient.addColorStop(0.45, css(color, alpha * 0.28));
1049
- gradient.addColorStop(1, css(color, 0));
1050
- ctx.fillStyle = gradient;
1051
- ctx.beginPath();
1052
- ctx.arc(cx, cy, radius, 0, Math.PI * 2);
1053
- ctx.fill();
1054
- }
1055
- function drawDisc2(ctx, cx, cy, radius, color, alpha = 1) {
1056
- if (radius <= 0)
1057
- return;
1058
- ctx.fillStyle = css(color, alpha);
1059
- ctx.beginPath();
1060
- ctx.arc(cx, cy, radius, 0, Math.PI * 2);
1061
- ctx.fill();
1062
- }
1063
- function drawLine2(ctx, x0, y0, x1, y1, color, alpha = 0.5, thickness = 1.4) {
1064
- ctx.save();
1065
- ctx.strokeStyle = css(color, alpha);
1066
- ctx.lineWidth = thickness * 2;
1067
- ctx.lineCap = "round";
1068
- ctx.lineJoin = "round";
1069
- ctx.beginPath();
1070
- ctx.moveTo(x0, y0);
1071
- ctx.lineTo(x1, y1);
1072
- ctx.stroke();
1073
- ctx.restore();
1074
- }
1075
- function drawDrone2(ctx, x, y, scale, tick, color) {
1076
- const speed = motionSpeed();
1077
- const wobble = Math.sin(tick * 0.055 * speed) * scale * 0.35;
1078
- const cy = y + wobble;
1079
- drawGlow2(ctx, x, cy, scale * 7, color, 0.18);
1080
- drawDisc2(ctx, x, cy, scale * 1.45, color, 0.92);
1081
- drawDisc2(ctx, x, cy, scale * 0.55, [235, 255, 176, 255], 0.85);
1082
- const arm = scale * 4.1;
1083
- const rotor = scale * 1.6;
1084
- const arms = [[-arm, -arm * 0.72], [arm, -arm * 0.72], [-arm, arm * 0.72], [arm, arm * 0.72]];
1085
- for (const [dx, dy] of arms) {
1086
- drawLine2(ctx, x, cy, x + dx, cy + dy, color, 0.42, Math.max(1, scale * 0.22));
1087
- drawGlow2(ctx, x + dx, cy + dy, rotor * 2.6, color, 0.1);
1088
- drawDisc2(ctx, x + dx, cy + dy, rotor, color, 0.34 + 0.12 * Math.sin(tick * 0.15 * speed));
1089
- }
1090
- }
1091
- function drawMarketingRails2(ctx, width, height, kind, tick) {
1092
- const density = motionDensity();
1093
- const speed = motionSpeed();
1094
- const ys = kind === "loop" ? [0.18, 0.5, 0.82] : kind === "carrier" ? [0.24, 0.54, 0.82] : [0.18, 0.58, 0.82];
1095
- ys.forEach((ratio, index) => {
1096
- const y = height * ratio + Math.sin(tick * 0.018 * speed + index) * Math.max(2, height * 0.0025);
1097
- const color = index === 2 ? CYAN2 : index === 1 ? LIME2 : LIME_DIM2;
1098
- drawLine2(ctx, width * 0.06, y, width * 0.94, y + Math.sin(index) * height * 0.002, color, index === 1 ? 0.09 : 0.055, Math.max(0.8, height * 0.0012));
1099
- const spacing = (0.18 + index * 0.02) / density;
1100
- for (let p = (tick * 0.004 * speed + index * 0.21) % 1;p < 1; p += spacing) {
1101
- const x = width * (0.06 + 0.88 * p);
1102
- drawDisc2(ctx, x, y, Math.max(1.2, height * (0.0017 + index * 0.0004)), color, 0.18);
1103
- drawGlow2(ctx, x, y, Math.max(5, height * 0.006), color, 0.026);
1104
- }
1105
- });
1106
- }
1107
- function drawDispatchScene2(ctx, width, height, tick) {
1108
- const density = motionDensity();
1109
- const speed = motionSpeed();
1110
- const core = sceneCore2(width, height, "dispatch");
1111
- const min = Math.min(width, height);
1112
- drawGlow2(ctx, core.x, core.y, min * 0.085, LIME2, 0.12);
1113
- drawDisc2(ctx, core.x, core.y, min * 0.0065, LIME2, 0.85);
1114
- const laneCount = Math.max(4, Math.round((width < 1000 ? 7 : 12) * (0.65 + density * 0.35)));
1115
- const lanes = Array.from({ length: laneCount }, (_, index) => dispatchLane2(width, index, laneCount));
1116
- lanes.forEach((lane) => {
1117
- let prev = lanePoint2(width, height, lane, 0);
1118
- ctx.beginPath();
1119
- ctx.moveTo(prev.x, prev.y);
1120
- for (let step = 1;step <= 32; step += 1) {
1121
- const next = lanePoint2(width, height, lane, step / 32);
1122
- ctx.lineTo(next.x, next.y);
1123
- prev = next;
1124
- }
1125
- ctx.strokeStyle = css(lane.phase > Math.PI ? CYAN2 : LIME_DIM2, 0.045);
1126
- ctx.lineWidth = Math.max(0.7, min * 0.0009) * 2;
1127
- ctx.lineCap = "round";
1128
- ctx.stroke();
1129
- });
1130
- const packets = Math.max(24, Math.round((width < 1000 ? 70 : 150) * density));
1131
- for (let i = 0;i < packets; i += 1) {
1132
- const lane = lanes[i % lanes.length];
1133
- const packetSpeed = (0.003 + seededUnit2(12288 + i * 17) * 0.009) * speed;
1134
- const p = (seededUnit2(16384 + i * 19) + tick * packetSpeed) % 1;
1135
- const pt = lanePoint2(width, height, lane, p);
1136
- const wobble = (seededUnit2(20480 + i * 23) - 0.5) * min * 0.012;
1137
- const fade = p < 0.1 ? p / 0.1 : p > 0.88 ? (1 - p) / 0.12 : 1;
1138
- const color = seededUnit2(24576 + i * 29) < 0.22 ? CYAN2 : LIME_DIM2;
1139
- const y = pt.y + wobble * Math.sin(p * Math.PI * 2);
1140
- drawLine2(ctx, pt.x - min * 0.012, y - min * 0.002, pt.x, y, color, 0.08 * fade, Math.max(0.7, min * 0.0008));
1141
- drawDisc2(ctx, pt.x, y, Math.max(1.3, min * 0.0022), color, 0.5 * fade);
1142
- drawGlow2(ctx, pt.x, y, Math.max(4, min * 0.008), color, 0.045 * fade);
1143
- }
1144
- const droneCount = Math.max(2, Math.round((width < 1000 ? 4 : 8) * density));
1145
- for (let i = 0;i < droneCount; i += 1) {
1146
- const lane = lanes[i % lanes.length];
1147
- const p = (tick * 0.002 * speed + i * 0.13) % 1;
1148
- const pt = lanePoint2(width, height, lane, p);
1149
- drawDrone2(ctx, pt.x, pt.y + Math.sin(tick * 0.04 * speed + i) * min * 0.004, min * (0.006 + i % 2 * 0.0015), tick + i * 11, i % 3 === 0 ? CYAN2 : LIME_DIM2);
1150
- }
1151
- }
1152
- function drawLoopScene2(ctx, width, height, tick) {
1153
- const density = motionDensity();
1154
- const speed = motionSpeed();
1155
- const min = Math.min(width, height);
1156
- const y = height * 0.56;
1157
- const x0 = width * 0.09;
1158
- const x1 = width * 0.91;
1159
- drawLine2(ctx, x0, y, x1, y, LIME_DIM2, 0.12, Math.max(0.8, min * 0.001));
1160
- const gates = width < 1000 ? 4 : 5;
1161
- const active = Math.floor(tick * speed / 20) % gates;
1162
- for (let i = 0;i < gates; i += 1) {
1163
- const x = x0 + (x1 - x0) * (i / Math.max(1, gates - 1));
1164
- const color = i === active ? LIME2 : i <= active ? LIME_DIM2 : INK_DIM2;
1165
- drawLine2(ctx, x, y - min * 0.05, x, y + min * 0.05, color, i === active ? 0.25 : 0.08, Math.max(0.8, min * 0.001));
1166
- drawDisc2(ctx, x, y, i === active ? min * 0.006 : min * 0.0035, color, i === active ? 0.72 : 0.25);
1167
- drawGlow2(ctx, x, y, i === active ? min * 0.018 : min * 0.01, color, i === active ? 0.1 : 0.035);
1168
- }
1169
- const packets = Math.max(16, Math.round((width < 1000 ? 36 : 84) * density));
1170
- for (let i = 0;i < packets; i += 1) {
1171
- const p = (seededUnit2(33024 + i * 13) + tick * (0.0022 + seededUnit2(33280 + i * 17) * 0.004) * speed) % 1;
1172
- const x = x0 + (x1 - x0) * p;
1173
- const segment = Math.min(gates - 1, Math.floor(p * gates));
1174
- const color = segment < active ? LIME_DIM2 : segment === active ? CYAN2 : INK_DIM2;
1175
- const py = y + (seededUnit2(33536 + i * 19) - 0.5) * min * 0.018 * Math.sin(p * Math.PI * 2);
1176
- drawLine2(ctx, x - min * 0.014, py, x, py, color, 0.1, Math.max(0.7, min * 0.0008));
1177
- drawDisc2(ctx, x, py, Math.max(1.2, min * 0.002), color, color === INK_DIM2 ? 0.22 : 0.58);
1178
- }
1179
- drawDrone2(ctx, x0 + (x1 - x0) * (tick * 0.003 * speed % 1), y - min * 0.04, min * 0.0065, tick, LIME_DIM2);
1180
- drawDrone2(ctx, x0 + (x1 - x0) * ((tick * 0.002 * speed + 0.5) % 1), y + min * 0.036, min * 0.0055, tick + 40, MAGENTA2);
1181
- }
1182
- function drawCarrierScene2(ctx, width, height, tick) {
1183
- const density = motionDensity();
1184
- const speed = motionSpeed();
1185
- const min = Math.min(width, height);
1186
- const core = sceneCore2(width, height, "carrier");
1187
- drawGlow2(ctx, core.x, core.y, min * 0.075, LIME2, 0.12);
1188
- drawDisc2(ctx, core.x, core.y, min * 0.0065, LIME2, 0.92);
1189
- const nodes = Math.max(4, Math.round((width < 1000 ? 5 : 7) * (0.75 + density * 0.25)));
1190
- const rx = width * 0.36;
1191
- const ry = height * 0.22;
1192
- for (let i = 0;i < nodes; i += 1) {
1193
- const a = i / nodes * Math.PI * 2 - Math.PI / 2 + tick * 0.006 * speed;
1194
- const x = core.x + Math.cos(a) * rx;
1195
- const y = core.y + Math.sin(a) * ry;
1196
- const color = i % 2 ? CYAN2 : LIME_DIM2;
1197
- drawLine2(ctx, core.x, core.y, x, y, color, 0.055, Math.max(0.7, min * 0.0008));
1198
- drawGlow2(ctx, x, y, min * 0.018, color, 0.055);
1199
- drawDisc2(ctx, x, y, min * 0.0048, color, 0.62);
1200
- drawDrone2(ctx, x, y - min * 0.018, min * 0.005, tick + i * 9, color);
1201
- }
1202
- const packets = Math.max(14, Math.round((width < 1000 ? 30 : 72) * density));
1203
- for (let i = 0;i < packets; i += 1) {
1204
- const lane = i % nodes;
1205
- const a = lane / nodes * Math.PI * 2 - Math.PI / 2 + tick * 0.006 * speed;
1206
- const nx = core.x + Math.cos(a) * rx;
1207
- const ny = core.y + Math.sin(a) * ry;
1208
- const p = (seededUnit2(37120 + i * 37) + tick * (0.003 + seededUnit2(37376 + i * 43) * 0.009) * speed) % 1;
1209
- const x = core.x + (nx - core.x) * p;
1210
- const y = core.y + (ny - core.y) * p;
1211
- const color = seededUnit2(37632 + i * 47) < 0.35 ? CYAN2 : LIME_DIM2;
1212
- drawDisc2(ctx, x, y, Math.max(1.2, min * 0.002), color, 0.48);
1213
- drawGlow2(ctx, x, y, min * 0.008, color, 0.035);
1214
- }
1215
- }
1216
- function drawBackground2(ctx, width, height, tick, scene) {
1217
- ctx.fillStyle = css(BG2);
1218
- ctx.fillRect(0, 0, width, height);
1219
- const kind = visualSceneKind2(scene);
1220
- drawGlow2(ctx, width * 0.82, height * 0.04, Math.min(width, height) * 0.22, LIME2, 0.035);
1221
- drawGlow2(ctx, width * 0.12, height * 0.18, Math.min(width, height) * 0.17, CYAN2, 0.025);
1222
- drawMarketingRails2(ctx, width, height, kind, tick);
1223
- if (kind === "loop")
1224
- drawLoopScene2(ctx, width, height, tick);
1225
- else if (kind === "carrier")
1226
- drawCarrierScene2(ctx, width, height, tick);
1227
- else
1228
- drawDispatchScene2(ctx, width, height, tick);
1229
- }
1230
- function drawScaledDroneLayer(ctx, width, height, tick, scene) {
1231
- const scale = droneLayerScale2();
1232
- if (scale >= 0.99) {
1233
- drawBackground2(ctx, width, height, tick, scene);
1234
- return;
1235
- }
1236
- const sceneWidth = Math.max(1, Math.round(width * scale));
1237
- const sceneHeight = Math.max(1, Math.round(height * scale));
1238
- const { canvas, ctx: sceneCtx2 } = reusableSceneCanvas(sceneWidth, sceneHeight);
1239
- drawBackground2(sceneCtx2, sceneWidth, sceneHeight, tick, scene);
1240
- ctx.save();
1241
- ctx.imageSmoothingEnabled = true;
1242
- ctx.imageSmoothingQuality = "high";
1243
- ctx.drawImage(canvas, 0, 0, sceneWidth, sceneHeight, 0, 0, width, height);
1244
- ctx.restore();
1245
- }
1246
- function panelPlacement(layout, panel, size) {
1247
- const cellW = size.width / layout.width;
1248
- const cellH = size.height / layout.height;
1249
- const leftCells = layout.centerLeft + (panel.left ?? 0);
1250
- const topCells = layout.centerTop + panel.top;
1251
- const widthCells = panel.width ?? layout.centerWidth;
1252
- const heightCells = panel.height;
1253
- const left = Math.round(leftCells * cellW);
1254
- const top = Math.round(topCells * cellH);
1255
- const width = Math.round(widthCells * cellW);
1256
- const height = Math.round(heightCells * cellH);
1257
- return width > 8 && height > 8 ? { left, top, width, height, leftCells, topCells, widthCells, heightCells } : null;
1258
- }
1259
- function panelRect2(layout, panel, size) {
1260
- return panelPlacement(layout, panel, size);
1261
- }
1262
- function clipRoundRect(ctx, rect, radius) {
1263
- ctx.beginPath();
1264
- ctx.roundRect(rect.left, rect.top, rect.width, rect.height, radius);
1265
- ctx.clip();
1266
- }
1267
- function strokeRoundRect(ctx, rect, radius) {
1268
- ctx.beginPath();
1269
- ctx.roundRect(rect.left + 0.75, rect.top + 0.75, rect.width - 1.5, rect.height - 1.5, Math.max(1, radius - 0.75));
1270
- ctx.stroke();
1271
- }
1272
- function compositePanel2(ctx, sourceCanvas, rect, headerPx) {
1273
- const radius = Math.max(14, Math.min(34, Math.round(Math.min(rect.width, rect.height) * 0.035)));
1274
- const { canvas: patch, ctx: patchCtx2 } = reusablePatchCanvas(rect.width, rect.height);
1275
- patchCtx2.drawImage(sourceCanvas, rect.left, rect.top, rect.width, rect.height, 0, 0, rect.width, rect.height);
1276
- ctx.save();
1277
- clipRoundRect(ctx, rect, radius);
1278
- ctx.filter = `blur(${Math.max(10, Math.round(Math.min(rect.width, rect.height) * 0.018))}px)`;
1279
- ctx.drawImage(patch, 0, 0, rect.width, rect.height, rect.left, rect.top, rect.width, rect.height);
1280
- ctx.filter = "none";
1281
- ctx.fillStyle = css(PANEL2);
1282
- ctx.fillRect(rect.left, rect.top, rect.width, rect.height);
1283
- ctx.fillStyle = css(PANEL_HEADER2);
1284
- ctx.fillRect(rect.left, rect.top, rect.width, headerPx);
1285
- ctx.restore();
1286
- ctx.save();
1287
- ctx.strokeStyle = css(PANEL_LINE2, 0.8);
1288
- ctx.lineWidth = 1.5;
1289
- strokeRoundRect(ctx, rect, radius);
1290
- ctx.restore();
1291
- const dividerY = Math.round(rect.top + headerPx);
1292
- if (dividerY > rect.top && dividerY < rect.top + rect.height) {
1293
- drawLine2(ctx, rect.left + radius, dividerY, rect.left + rect.width - radius, dividerY, PANEL_LINE2, 0.28, 0.7);
1294
- }
1295
- }
1296
- function compositePanelPatch(ctx, sourceCanvas, width, height, headerPx) {
1297
- const rect = { left: 0, top: 0, width, height };
1298
- const radius = Math.max(14, Math.min(34, Math.round(Math.min(width, height) * 0.035)));
1299
- ctx.save();
1300
- clipRoundRect(ctx, rect, radius);
1301
- ctx.filter = `blur(${Math.max(10, Math.round(Math.min(width, height) * 0.018))}px)`;
1302
- ctx.drawImage(sourceCanvas, 0, 0, width, height);
1303
- ctx.filter = "none";
1304
- ctx.fillStyle = css(PANEL2);
1305
- ctx.fillRect(0, 0, width, height);
1306
- ctx.fillStyle = css(PANEL_HEADER2);
1307
- ctx.fillRect(0, 0, width, headerPx);
1308
- ctx.restore();
1309
- }
1310
- function compositePanelChromePatch(ctx, width, height, headerPx) {
1311
- const radius = Math.max(14, Math.min(34, Math.round(Math.min(width, height) * 0.035)));
1312
- ctx.clearRect(0, 0, width, height);
1313
- const dividerY = Math.round(headerPx);
1314
- if (dividerY > 0 && dividerY < height)
1315
- drawLine2(ctx, radius, dividerY, width - radius, dividerY, PANEL_LINE2, 0.22, 0.65);
1316
- }
1317
- async function encodePanelPatch(input, placement, imageId, headerPx) {
1318
- const { canvas: sourceCanvas, ctx: sourceCtx } = reusableSceneCanvas(placement.width, placement.height);
1319
- sourceCtx.save();
1320
- sourceCtx.translate(-placement.left, -placement.top);
1321
- drawScaledDroneLayer(sourceCtx, input.pixelSize.width, input.pixelSize.height, input.tick, input.scene);
1322
- sourceCtx.restore();
1323
- const { canvas: patchCanvas2, ctx: patchCtx2 } = reusablePatchCanvas(placement.width, placement.height);
1324
- compositePanelPatch(patchCtx2, sourceCanvas, placement.width, placement.height, headerPx);
1325
- const png = await patchCanvas2.encode("png");
1326
- const sequence = kittyPngFrameSequence(png, { columns: Math.max(1, Math.round(placement.widthCells)), rows: Math.max(1, Math.round(placement.heightCells)), imageId, zIndex: -12 });
1327
- return `\x1B[${Math.max(1, Math.round(placement.topCells) + 1)};${Math.max(1, Math.round(placement.leftCells) + 1)}H${sequence}`;
1328
- }
1329
- async function encodePanelChromePatch(placement, imageId, headerPx) {
1330
- const { canvas: patchCanvas2, ctx: patchCtx2 } = reusablePatchCanvas(placement.width, placement.height);
1331
- compositePanelChromePatch(patchCtx2, placement.width, placement.height, headerPx);
1332
- const png = await patchCanvas2.encode("png");
1333
- const sequence = kittyPngFrameSequence(png, { columns: Math.max(1, Math.round(placement.widthCells)), rows: Math.max(1, Math.round(placement.heightCells)), imageId, zIndex: -8 });
1334
- return `\x1B[${Math.max(1, Math.round(placement.topCells) + 1)};${Math.max(1, Math.round(placement.leftCells) + 1)}H${sequence}`;
1335
- }
1336
- function kittyImageSequence2(base64, options) {
1337
- const params = [`a=T`, `f=100`, `q=2`, `C=1`, `c=${options.columns}`, `r=${options.rows}`, `i=${options.imageId}`, `z=${options.zIndex}`];
1338
- if (base64.length <= KITTY_CHUNK_SIZE2)
1339
- return `\x1B_G${params.join(",")};${base64}\x1B\\`;
1340
- const chunks = [];
1341
- for (let offset = 0;offset < base64.length; offset += KITTY_CHUNK_SIZE2) {
1342
- const part = base64.slice(offset, offset + KITTY_CHUNK_SIZE2);
1343
- const last = offset + KITTY_CHUNK_SIZE2 >= base64.length;
1344
- chunks.push(`\x1B_G${offset === 0 ? `${params.join(",")},` : ""}m=${last ? 0 : 1};${part}\x1B\\`);
1345
- }
1346
- return chunks.join("");
1347
- }
1348
- function kittyTempFileImageSequence(png, options) {
1349
- mkdirSync(TEMP_GRAPHICS_DIR, { recursive: true });
1350
- const path = join(TEMP_GRAPHICS_DIR, `frame-${process.pid}-${Date.now()}-${encodedFrames}.tty-graphics-protocol.png`);
1351
- writeFileSync(path, png);
1352
- const payload = Buffer.from(path).toString("base64");
1353
- const params = [`a=T`, `f=100`, `t=t`, `S=${png.byteLength}`, `q=2`, `C=1`, `c=${options.columns}`, `r=${options.rows}`, `i=${options.imageId}`, `z=${options.zIndex}`];
1354
- return `\x1B_G${params.join(",")};${payload}\x1B\\`;
1355
- }
1356
- function kittyPngFrameSequence(png, options) {
1357
- if (kittyTransmission() === "temp-file")
1358
- return kittyTempFileImageSequence(png, options);
1359
- return kittyImageSequence2(png.toString("base64"), options);
1360
- }
1361
- async function renderNativeCanvasImageVisualFrame(input) {
1362
- if (input.transport !== "png")
1363
- return null;
1364
- const width = Math.max(1, Math.floor(input.pixelSize.width));
1365
- const height = Math.max(1, Math.floor(input.pixelSize.height));
1366
- if (width * height * 4 > MAX_IMAGE_BYTES2)
1367
- return null;
1368
- const layer = input.layer ?? "full";
1369
- if (layer === "split") {
1370
- const backgroundScale = droneLayerScale2();
1371
- const backgroundWidth = Math.max(input.layout.width, Math.round(width * backgroundScale));
1372
- const backgroundHeight = Math.max(input.layout.height, Math.round(height * backgroundScale));
1373
- const { canvas: backgroundCanvas, ctx: backgroundCtx } = reusableCanvas(backgroundWidth, backgroundHeight);
1374
- drawBackground2(backgroundCtx, backgroundWidth, backgroundHeight, input.tick, input.scene);
1375
- const backgroundPng = await backgroundCanvas.encode("png");
1376
- const sequences = [kittyPngFrameSequence(backgroundPng, { columns: input.layout.width, rows: input.layout.height, imageId: input.imageId, zIndex: -30 })];
1377
- let panelIndex = 0;
1378
- for (const panel of input.panels) {
1379
- if (panel.chrome !== "ad-terminal")
1380
- continue;
1381
- const placement = panelPlacement(input.layout, panel, { width, height });
1382
- if (!placement)
1383
- continue;
1384
- const imageId = input.imageIds?.[panelIndex] ?? (input.imageId + 1000 + panelIndex >>> 0 || panelIndex + 1);
1385
- const cellH = height / input.layout.height;
1386
- const headerPx = Math.max(cellH * 3, (panel.headerHeight ?? 3) * cellH);
1387
- sequences.push(await encodePanelPatch(input, placement, imageId, headerPx));
1388
- panelIndex += 1;
1389
- }
1390
- encodedFrames += 1;
1391
- if (encodedFrames % SKIA_CACHE_CLEAR_INTERVAL === 0)
1392
- clearAllCache();
1393
- return {
1394
- key: imageVisualFrameKey(input),
1395
- sequence: sequences.join("")
1396
- };
1397
- }
1398
- if (layer === "panel-patches") {
1399
- const sequences = [];
1400
- let panelIndex = 0;
1401
- for (const panel of input.panels) {
1402
- if (panel.chrome !== "ad-terminal")
1403
- continue;
1404
- const placement = panelPlacement(input.layout, panel, { width, height });
1405
- if (!placement)
1406
- continue;
1407
- const imageId = input.imageIds?.[panelIndex] ?? (input.imageId + 1000 + panelIndex >>> 0 || panelIndex + 1);
1408
- const cellH = height / input.layout.height;
1409
- const headerPx = Math.max(cellH * 3, (panel.headerHeight ?? 3) * cellH);
1410
- sequences.push(await encodePanelPatch(input, placement, imageId, headerPx));
1411
- panelIndex += 1;
1412
- }
1413
- encodedFrames += 1;
1414
- if (encodedFrames % SKIA_CACHE_CLEAR_INTERVAL === 0)
1415
- clearAllCache();
1416
- return {
1417
- key: imageVisualFrameKey(input),
1418
- sequence: sequences.join("")
1419
- };
1420
- }
1421
- if (layer === "panel-chrome") {
1422
- const sequences = [];
1423
- let panelIndex = 0;
1424
- for (const panel of input.panels) {
1425
- if (panel.chrome !== "ad-terminal")
1426
- continue;
1427
- const placement = panelPlacement(input.layout, panel, { width, height });
1428
- if (!placement)
1429
- continue;
1430
- const imageId = input.imageIds?.[panelIndex] ?? (input.imageId + 2000 + panelIndex >>> 0 || panelIndex + 1);
1431
- const cellH = height / input.layout.height;
1432
- const headerPx = Math.max(cellH * 3, (panel.headerHeight ?? 3) * cellH);
1433
- sequences.push(await encodePanelChromePatch(placement, imageId, headerPx));
1434
- panelIndex += 1;
1435
- }
1436
- encodedFrames += 1;
1437
- if (encodedFrames % SKIA_CACHE_CLEAR_INTERVAL === 0)
1438
- clearAllCache();
1439
- return {
1440
- key: imageVisualFrameKey(input),
1441
- sequence: sequences.join("")
1442
- };
1443
- }
1444
- const { canvas, ctx } = reusableCanvas(width, height);
1445
- if (layer === "background") {
1446
- drawBackground2(ctx, width, height, input.tick, input.scene);
1447
- } else if (layer === "panels") {
1448
- const { canvas: sourceCanvas, ctx: sourceCtx } = reusableSceneCanvas(width, height);
1449
- drawScaledDroneLayer(sourceCtx, width, height, input.tick, input.scene);
1450
- for (const panel of input.panels) {
1451
- if (panel.chrome !== "ad-terminal")
1452
- continue;
1453
- const rect = panelRect2(input.layout, panel, { width, height });
1454
- if (!rect)
1455
- continue;
1456
- const cellH = height / input.layout.height;
1457
- const headerPx = Math.max(cellH * 3, (panel.headerHeight ?? 3) * cellH);
1458
- compositePanel2(ctx, sourceCanvas, rect, headerPx);
1459
- }
1460
- } else {
1461
- drawScaledDroneLayer(ctx, width, height, input.tick, input.scene);
1462
- for (const panel of input.panels) {
1463
- if (panel.chrome !== "ad-terminal")
1464
- continue;
1465
- const rect = panelRect2(input.layout, panel, { width, height });
1466
- if (!rect)
1467
- continue;
1468
- const cellH = height / input.layout.height;
1469
- const headerPx = Math.max(cellH * 3, (panel.headerHeight ?? 3) * cellH);
1470
- compositePanel2(ctx, canvas, rect, headerPx);
1471
- }
1472
- }
1473
- const png = await canvas.encode("png");
1474
- encodedFrames += 1;
1475
- if (encodedFrames % SKIA_CACHE_CLEAR_INTERVAL === 0)
1476
- clearAllCache();
1477
- return {
1478
- key: imageVisualFrameKey(input),
1479
- sequence: kittyPngFrameSequence(png, { columns: input.layout.width, rows: input.layout.height, imageId: input.imageId, zIndex: input.zIndex })
1480
- };
1481
- }
1482
- export {
1483
- renderNativeCanvasImageVisualFrame
1484
- };