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