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