@h-rig/cli 0.0.6-alpha.84 → 0.0.6-alpha.86
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/rig.js +27 -1063
- package/dist/src/app-opentui/bootstrap.js +27 -1063
- package/dist/src/app-opentui/index.js +7 -1024
- package/dist/src/app-opentui/react/App.js +20 -1032
- package/dist/src/app-opentui/react/Backdrop.js +20 -1032
- package/dist/src/app-opentui/react/ChromeHost.js +0 -1039
- package/dist/src/app-opentui/react/launch.js +20 -1032
- package/dist/src/app-opentui/render/constants.d.ts +0 -1
- package/dist/src/app-opentui/render/constants.js +0 -2
- package/dist/src/app-opentui/render/graphics.js +2 -9
- package/dist/src/app-opentui/runtime.js +8 -1025
- package/package.json +8 -8
- package/dist/src/app-opentui/render/image-visual-layer-worker.d.ts +0 -1
- package/dist/src/app-opentui/render/image-visual-layer-worker.js +0 -1084
- package/dist/src/app-opentui/render/image-visual-layer.d.ts +0 -109
- package/dist/src/app-opentui/render/image-visual-layer.js +0 -1068
- package/dist/src/app-opentui/terminal-capabilities.d.ts +0 -7
- package/dist/src/app-opentui/terminal-capabilities.js +0 -15
|
@@ -17330,22 +17330,9 @@ function panelContentRect(layout, panel) {
|
|
|
17330
17330
|
const contentWidth = Math.max(1, width - paddingX * 2 - 1);
|
|
17331
17331
|
return { left, top, width, height, paddingX, paddingY, contentWidth };
|
|
17332
17332
|
}
|
|
17333
|
-
function panelPixelPlacement(layout, panel, size, minPixels = 8) {
|
|
17334
|
-
const cellW = size.width / layout.width;
|
|
17335
|
-
const cellH = size.height / layout.height;
|
|
17336
|
-
const leftCells = layout.centerLeft + (panel.left ?? 0);
|
|
17337
|
-
const topCells = layout.centerTop + panel.top;
|
|
17338
|
-
const widthCells = panel.width ?? layout.centerWidth;
|
|
17339
|
-
const heightCells = panel.height;
|
|
17340
|
-
const left = Math.round(leftCells * cellW);
|
|
17341
|
-
const top = Math.round(topCells * cellH);
|
|
17342
|
-
const width = Math.round(widthCells * cellW);
|
|
17343
|
-
const height = Math.round(heightCells * cellH);
|
|
17344
|
-
return width > minPixels && height > minPixels ? { left, top, width, height, leftCells, topCells, widthCells, heightCells } : null;
|
|
17345
|
-
}
|
|
17346
17333
|
|
|
17347
17334
|
// packages/cli/src/app-opentui/render/constants.ts
|
|
17348
|
-
var LCG_MULTIPLIER = 1664525, LCG_INCREMENT = 1013904223, LCG_DIVISOR = 4294967295, PACKET_CYAN_PROBABILITY = 0.22, LANE_INTERP_STEPS = 32, LANE_LEN_BASE = 0.32, LANE_LEN_SPREAD = 0.42, LANE_CURVE_RANGE = 0.7, PACKET_SPEED_BASE = 0.003, PACKET_SPEED_SPREAD = 0.009, DISPATCH_LANES_COMPACT = 7, DISPATCH_LANES_WIDE = 12, DISPATCH_PACKETS_COMPACT = 70, DISPATCH_PACKETS_WIDE = 150, CARRIER_NODES_COMPACT = 5, CARRIER_NODES_WIDE = 7, LOOP_GATES_COMPACT = 4, LOOP_GATES_WIDE = 5, DISPATCH_DRONES_COMPACT = 4, DISPATCH_DRONES_WIDE = 8, CORE_DISPATCH_X = 0.3, CORE_DISPATCH_Y = 0.45, CORE_CARRIER_X = 0.5, CORE_CARRIER_Y = 0.54, CORE_LOOP_X = 0.09, CORE_LOOP_Y = 0.56, RAIL_YS_LOOP, RAIL_YS_CARRIER, RAIL_YS_DISPATCH, GLOW_FALLOFF_EXP_ASCII = 2.2
|
|
17335
|
+
var LCG_MULTIPLIER = 1664525, LCG_INCREMENT = 1013904223, LCG_DIVISOR = 4294967295, PACKET_CYAN_PROBABILITY = 0.22, LANE_INTERP_STEPS = 32, LANE_LEN_BASE = 0.32, LANE_LEN_SPREAD = 0.42, LANE_CURVE_RANGE = 0.7, PACKET_SPEED_BASE = 0.003, PACKET_SPEED_SPREAD = 0.009, DISPATCH_LANES_COMPACT = 7, DISPATCH_LANES_WIDE = 12, DISPATCH_PACKETS_COMPACT = 70, DISPATCH_PACKETS_WIDE = 150, CARRIER_NODES_COMPACT = 5, CARRIER_NODES_WIDE = 7, LOOP_GATES_COMPACT = 4, LOOP_GATES_WIDE = 5, DISPATCH_DRONES_COMPACT = 4, DISPATCH_DRONES_WIDE = 8, CORE_DISPATCH_X = 0.3, CORE_DISPATCH_Y = 0.45, CORE_CARRIER_X = 0.5, CORE_CARRIER_Y = 0.54, CORE_LOOP_X = 0.09, CORE_LOOP_Y = 0.56, RAIL_YS_LOOP, RAIL_YS_CARRIER, RAIL_YS_DISPATCH, GLOW_FALLOFF_EXP_ASCII = 2.2;
|
|
17349
17336
|
var init_constants = __esm(() => {
|
|
17350
17337
|
RAIL_YS_LOOP = [0.18, 0.5, 0.82];
|
|
17351
17338
|
RAIL_YS_CARRIER = [0.24, 0.54, 0.82];
|
|
@@ -17764,27 +17751,20 @@ function writeCell(layer, x, y, char, fg2, bg) {
|
|
|
17764
17751
|
function drawFullCell(layer, x, y, bg) {
|
|
17765
17752
|
writeCell(layer, x, y, " ", TRANSPARENT, bg);
|
|
17766
17753
|
}
|
|
17767
|
-
function
|
|
17768
|
-
writeCell(layer, x, y, char, fg2, BACKDROP);
|
|
17769
|
-
}
|
|
17770
|
-
function drawRoundedFill(layer, left, top, right, bottom, dividerY) {
|
|
17754
|
+
function drawPanelFill(layer, left, top, right, bottom, dividerY) {
|
|
17771
17755
|
const bgForY = (y) => y < dividerY ? PANEL_HEADER_BG : PANEL_BG;
|
|
17772
17756
|
for (let y = top;y <= bottom; y += 1) {
|
|
17773
17757
|
const bg = bgForY(y);
|
|
17774
17758
|
for (let x = left;x <= right; x += 1)
|
|
17775
17759
|
drawFullCell(layer, x, y, bg);
|
|
17776
17760
|
}
|
|
17777
|
-
drawCornerCut(layer, left, top, "\u2597", PANEL_HEADER_BG);
|
|
17778
|
-
drawCornerCut(layer, right, top, "\u2596", PANEL_HEADER_BG);
|
|
17779
|
-
drawCornerCut(layer, left, bottom, "\u259D", PANEL_BG);
|
|
17780
|
-
drawCornerCut(layer, right, bottom, "\u2598", PANEL_BG);
|
|
17781
17761
|
}
|
|
17782
17762
|
function drawAdTerminalPanel(layer, layout, panel) {
|
|
17783
17763
|
const rect = panelCellRect(layout, panel);
|
|
17784
17764
|
if (!rect)
|
|
17785
17765
|
return;
|
|
17786
17766
|
const { left, top, width, right, bottom, headerHeight, dividerY } = rect;
|
|
17787
|
-
|
|
17767
|
+
drawPanelFill(layer, left, top, right, bottom, dividerY);
|
|
17788
17768
|
if (dividerY > top && dividerY < bottom) {
|
|
17789
17769
|
for (let x = left + 2;x < right - 1; x += 1) {
|
|
17790
17770
|
writeCell(layer, x, dividerY, "\u2500", PANEL_LINE_DIM, PANEL_BG);
|
|
@@ -17892,963 +17872,6 @@ var init_graphics = __esm(() => {
|
|
|
17892
17872
|
];
|
|
17893
17873
|
});
|
|
17894
17874
|
|
|
17895
|
-
// packages/cli/src/app-opentui/terminal-capabilities.ts
|
|
17896
|
-
import { getCapabilities } from "@earendil-works/pi-tui";
|
|
17897
|
-
function getRigTerminalCapabilities() {
|
|
17898
|
-
const imageProtocol = getCapabilities().images;
|
|
17899
|
-
const supportsKittyImages = imageProtocol === "kitty";
|
|
17900
|
-
return {
|
|
17901
|
-
imageProtocol,
|
|
17902
|
-
supportsKittyImages,
|
|
17903
|
-
visualMode: supportsKittyImages ? "kitty-images" : "framebuffer-fallback"
|
|
17904
|
-
};
|
|
17905
|
-
}
|
|
17906
|
-
var init_terminal_capabilities = () => {};
|
|
17907
|
-
|
|
17908
|
-
// packages/cli/src/app-opentui/render/image-visual-layer.ts
|
|
17909
|
-
import { Worker } from "worker_threads";
|
|
17910
|
-
import { deflateSync } from "zlib";
|
|
17911
|
-
import { allocateImageId, deleteKittyImage } from "@earendil-works/pi-tui";
|
|
17912
|
-
function loadBucket(load) {
|
|
17913
|
-
if (!Number.isFinite(load ?? NaN))
|
|
17914
|
-
return 0;
|
|
17915
|
-
return Math.max(0, Math.min(LOAD_BUCKETS, Math.round((load ?? 0) * LOAD_BUCKETS)));
|
|
17916
|
-
}
|
|
17917
|
-
function imageTransport() {
|
|
17918
|
-
const forced = process.env.RIG_OPENTUI_IMAGE_TRANSPORT;
|
|
17919
|
-
if (forced === "rgba-zlib")
|
|
17920
|
-
return "rgba-zlib";
|
|
17921
|
-
return "png";
|
|
17922
|
-
}
|
|
17923
|
-
function imageResolutionScale() {
|
|
17924
|
-
const raw = Number.parseFloat(process.env.RIG_OPENTUI_IMAGE_SCALE ?? "");
|
|
17925
|
-
if (Number.isFinite(raw) && raw > 0)
|
|
17926
|
-
return Math.max(0.25, Math.min(1, raw));
|
|
17927
|
-
return DEFAULT_IMAGE_RESOLUTION_SCALE;
|
|
17928
|
-
}
|
|
17929
|
-
function rgbaWord(color) {
|
|
17930
|
-
return (color[3] << 24 | color[2] << 16 | color[1] << 8 | color[0]) >>> 0;
|
|
17931
|
-
}
|
|
17932
|
-
function fillRgba(data, color, word = rgbaWord(color)) {
|
|
17933
|
-
if (data.byteOffset % 4 === 0 && data.byteLength % 4 === 0) {
|
|
17934
|
-
new Uint32Array(data.buffer, data.byteOffset, data.byteLength / 4).fill(word);
|
|
17935
|
-
return;
|
|
17936
|
-
}
|
|
17937
|
-
for (let i = 0;i < data.length; i += 4) {
|
|
17938
|
-
data[i] = color[0];
|
|
17939
|
-
data[i + 1] = color[1];
|
|
17940
|
-
data[i + 2] = color[2];
|
|
17941
|
-
data[i + 3] = color[3];
|
|
17942
|
-
}
|
|
17943
|
-
}
|
|
17944
|
-
function sceneStaticTick(scene) {
|
|
17945
|
-
let hash = 0;
|
|
17946
|
-
for (let index = 0;index < scene.length; index += 1)
|
|
17947
|
-
hash = hash * 33 + scene.charCodeAt(index) >>> 0;
|
|
17948
|
-
return 11 + hash % 97;
|
|
17949
|
-
}
|
|
17950
|
-
function charColor(char, row, totalRows) {
|
|
17951
|
-
if (char === "@" || char === "$" || char === "o")
|
|
17952
|
-
return LIME;
|
|
17953
|
-
if (char === "%" || char === "!" || char === "/" || char === "\\" || char === "|")
|
|
17954
|
-
return CYAN;
|
|
17955
|
-
if (char === "." || char === "'" || char === "_" || row < 3 || row > totalRows - 4)
|
|
17956
|
-
return INK_DIM;
|
|
17957
|
-
if (char === "-" || char === "=" || char === "(" || char === ")")
|
|
17958
|
-
return LIME_DIM;
|
|
17959
|
-
return MAGENTA;
|
|
17960
|
-
}
|
|
17961
|
-
function fillRectAlpha(data, width, height, left, top, rectWidth, rectHeight, color, alpha) {
|
|
17962
|
-
const x0 = Math.max(0, Math.floor(left));
|
|
17963
|
-
const y0 = Math.max(0, Math.floor(top));
|
|
17964
|
-
const x1 = Math.min(width, Math.ceil(left + rectWidth));
|
|
17965
|
-
const y1 = Math.min(height, Math.ceil(top + rectHeight));
|
|
17966
|
-
for (let y = y0;y < y1; y += 1) {
|
|
17967
|
-
for (let x = x0;x < x1; x += 1)
|
|
17968
|
-
blendOver(data, (y * width + x) * 4, color, alpha);
|
|
17969
|
-
}
|
|
17970
|
-
}
|
|
17971
|
-
function drawAsciiGlyph(data, width, height, x, y, cellWidth, cellHeight, char, color, alpha) {
|
|
17972
|
-
const pattern = ASCII_GLYPHS[char] ?? ASCII_GLYPHS["*"];
|
|
17973
|
-
const glyphWidth = Math.max(1, cellWidth * 0.56);
|
|
17974
|
-
const glyphHeight = Math.max(1, cellHeight * 0.7);
|
|
17975
|
-
const originX = x + (cellWidth - glyphWidth) * 0.5;
|
|
17976
|
-
const originY = y + (cellHeight - glyphHeight) * 0.5;
|
|
17977
|
-
const pixelWidth = Math.max(1, glyphWidth / pattern[0].length);
|
|
17978
|
-
const pixelHeight = Math.max(1, glyphHeight / pattern.length);
|
|
17979
|
-
for (let row = 0;row < pattern.length; row += 1) {
|
|
17980
|
-
const bits = pattern[row];
|
|
17981
|
-
for (let col = 0;col < bits.length; col += 1) {
|
|
17982
|
-
if (bits[col] !== "1")
|
|
17983
|
-
continue;
|
|
17984
|
-
fillRectAlpha(data, width, height, originX + col * pixelWidth, originY + row * pixelHeight, pixelWidth * 0.72, pixelHeight * 0.72, color, alpha);
|
|
17985
|
-
}
|
|
17986
|
-
}
|
|
17987
|
-
}
|
|
17988
|
-
function drawStaticAsciiFleetBackground(data, width, height, scene, layout, load, activeRuns) {
|
|
17989
|
-
const rows = fleetRows(sceneStaticTick(scene), { animate: true });
|
|
17990
|
-
const cellWidth = width / Math.max(1, layout.width);
|
|
17991
|
-
const cellHeight = height / Math.max(1, layout.height);
|
|
17992
|
-
const sideBySide = layout.width >= FLEET_GRID_WIDTH * 1.9;
|
|
17993
|
-
const leftCells = sideBySide ? Math.max(1, Math.floor(layout.width * 0.3 - FLEET_GRID_WIDTH / 2)) : Math.floor((layout.width - FLEET_GRID_WIDTH) / 2);
|
|
17994
|
-
const topCells = Math.floor((layout.height - FLEET_GRID_HEIGHT) / 2);
|
|
17995
|
-
const fleetLeft = leftCells * cellWidth;
|
|
17996
|
-
const fleetTop = topCells * cellHeight;
|
|
17997
|
-
drawGlow2(data, width, height, width * 0.5, height * 0.5, Math.min(width, height) * 0.4, LIME, 0.022 + load * 0.03);
|
|
17998
|
-
drawGlow2(data, width, height, width * 0.18, height * 0.22, Math.min(width, height) * 0.28, CYAN, 0.018 + load * 0.012);
|
|
17999
|
-
drawGlow2(data, width, height, width * 0.82, height * 0.78, Math.min(width, height) * 0.22, MAGENTA, 0.012 + load * 0.008);
|
|
18000
|
-
let droneTotal = 0;
|
|
18001
|
-
for (const line2 of rows)
|
|
18002
|
-
for (const char of line2)
|
|
18003
|
-
if (char === "@" || char === "$" || char === "%")
|
|
18004
|
-
droneTotal += 1;
|
|
18005
|
-
const litTarget = Math.max(0, Math.min(droneTotal, activeRuns));
|
|
18006
|
-
let droneIndex = 0;
|
|
18007
|
-
for (let row = 0;row < rows.length; row += 1) {
|
|
18008
|
-
const line2 = rows[row];
|
|
18009
|
-
for (let col = 0;col < line2.length; col += 1) {
|
|
18010
|
-
const char = line2[col];
|
|
18011
|
-
if (char === " ")
|
|
18012
|
-
continue;
|
|
18013
|
-
const x = fleetLeft + col * cellWidth;
|
|
18014
|
-
const y = fleetTop + row * cellHeight;
|
|
18015
|
-
const color = charColor(char, row, rows.length);
|
|
18016
|
-
const isDrone = char === "@" || char === "$" || char === "%";
|
|
18017
|
-
const lit = isDrone && droneIndex < litTarget;
|
|
18018
|
-
drawAsciiGlyph(data, width, height, x + cellWidth * 0.07, y + cellHeight * 0.05, cellWidth, cellHeight, char, color, lit ? 0.72 : 0.46);
|
|
18019
|
-
if (isDrone) {
|
|
18020
|
-
droneIndex += 1;
|
|
18021
|
-
drawGlow2(data, width, height, x + cellWidth * 0.5, y + cellHeight * 0.5, Math.max(cellWidth, cellHeight) * 0.95, color, lit ? 0.044 : 0.014);
|
|
18022
|
-
}
|
|
18023
|
-
}
|
|
18024
|
-
}
|
|
18025
|
-
}
|
|
18026
|
-
function applyStaticAtmosphere(data, width, height, load) {
|
|
18027
|
-
const cx = width * 0.5;
|
|
18028
|
-
const cy = height * 0.42;
|
|
18029
|
-
const radius = Math.max(width, height) * 0.78;
|
|
18030
|
-
const minVignette = 0.1 - load * 0.02;
|
|
18031
|
-
for (let y = 0;y < height; y += 1) {
|
|
18032
|
-
for (let x = 0;x < width; x += 1) {
|
|
18033
|
-
const distance = Math.hypot(x - cx, y - cy) / radius;
|
|
18034
|
-
const alpha = Math.max(minVignette, Math.min(0.82, 0.12 + Math.pow(distance, 1.65) * 0.62));
|
|
18035
|
-
blendOver(data, (y * width + x) * 4, BG, alpha);
|
|
18036
|
-
}
|
|
18037
|
-
}
|
|
18038
|
-
drawGlow2(data, width, height, width * 0.82, height * 0.04, Math.min(width, height) * 0.2, LIME, 0.024 + load * 0.012);
|
|
18039
|
-
drawGlow2(data, width, height, width * 0.12, height * 0.18, Math.min(width, height) * 0.16, CYAN, 0.018 + load * 0.008);
|
|
18040
|
-
}
|
|
18041
|
-
function makeCrcTable() {
|
|
18042
|
-
const table = new Uint32Array(256);
|
|
18043
|
-
for (let n = 0;n < 256; n += 1) {
|
|
18044
|
-
let c = n;
|
|
18045
|
-
for (let k = 0;k < 8; k += 1)
|
|
18046
|
-
c = c & 1 ? 3988292384 ^ c >>> 1 : c >>> 1;
|
|
18047
|
-
table[n] = c >>> 0;
|
|
18048
|
-
}
|
|
18049
|
-
return table;
|
|
18050
|
-
}
|
|
18051
|
-
function crc32(bytes) {
|
|
18052
|
-
let c = 4294967295;
|
|
18053
|
-
for (let i = 0;i < bytes.length; i += 1)
|
|
18054
|
-
c = CRC_TABLE[(c ^ bytes[i]) & 255] ^ c >>> 8;
|
|
18055
|
-
return (c ^ 4294967295) >>> 0;
|
|
18056
|
-
}
|
|
18057
|
-
function chunk2(type, data) {
|
|
18058
|
-
const out = new Uint8Array(12 + data.length);
|
|
18059
|
-
const view = new DataView(out.buffer);
|
|
18060
|
-
view.setUint32(0, data.length);
|
|
18061
|
-
out[4] = type.charCodeAt(0);
|
|
18062
|
-
out[5] = type.charCodeAt(1);
|
|
18063
|
-
out[6] = type.charCodeAt(2);
|
|
18064
|
-
out[7] = type.charCodeAt(3);
|
|
18065
|
-
out.set(data, 8);
|
|
18066
|
-
view.setUint32(8 + data.length, crc32(out.subarray(4, 8 + data.length)));
|
|
18067
|
-
return out;
|
|
18068
|
-
}
|
|
18069
|
-
function encodePng(width, height, rgba) {
|
|
18070
|
-
const ihdr = new Uint8Array(13);
|
|
18071
|
-
const ihdrView = new DataView(ihdr.buffer);
|
|
18072
|
-
ihdrView.setUint32(0, width);
|
|
18073
|
-
ihdrView.setUint32(4, height);
|
|
18074
|
-
ihdr[8] = 8;
|
|
18075
|
-
ihdr[9] = 6;
|
|
18076
|
-
ihdr[10] = 0;
|
|
18077
|
-
ihdr[11] = 0;
|
|
18078
|
-
ihdr[12] = 0;
|
|
18079
|
-
const stride = width * 4;
|
|
18080
|
-
const raw = new Uint8Array((stride + 1) * height);
|
|
18081
|
-
for (let y = 0;y < height; y += 1) {
|
|
18082
|
-
const rawOffset = y * (stride + 1);
|
|
18083
|
-
raw[rawOffset] = 0;
|
|
18084
|
-
raw.set(rgba.subarray(y * stride, y * stride + stride), rawOffset + 1);
|
|
18085
|
-
}
|
|
18086
|
-
const compressed = deflateSync(raw, { level: ZLIB_LEVEL });
|
|
18087
|
-
return Buffer.concat([
|
|
18088
|
-
Buffer.from(PNG_SIGNATURE),
|
|
18089
|
-
Buffer.from(chunk2("IHDR", ihdr)),
|
|
18090
|
-
Buffer.from(chunk2("IDAT", compressed)),
|
|
18091
|
-
Buffer.from(chunk2("IEND", new Uint8Array(0)))
|
|
18092
|
-
]);
|
|
18093
|
-
}
|
|
18094
|
-
function kittyImageSequence(base64, options) {
|
|
18095
|
-
const params = [`a=T`, `f=${options.format}`, `q=2`, `C=1`, `c=${options.columns}`, `r=${options.rows}`, `i=${options.imageId}`, `z=${options.zIndex}`];
|
|
18096
|
-
if (options.format === 32) {
|
|
18097
|
-
params.push(`s=${options.pixelWidth ?? 1}`, `v=${options.pixelHeight ?? 1}`);
|
|
18098
|
-
if (options.compressed)
|
|
18099
|
-
params.push("o=z");
|
|
18100
|
-
}
|
|
18101
|
-
if (base64.length <= KITTY_CHUNK_SIZE)
|
|
18102
|
-
return `\x1B_G${params.join(",")};${base64}\x1B\\`;
|
|
18103
|
-
const chunks = [];
|
|
18104
|
-
for (let offset = 0;offset < base64.length; offset += KITTY_CHUNK_SIZE) {
|
|
18105
|
-
const part = base64.slice(offset, offset + KITTY_CHUNK_SIZE);
|
|
18106
|
-
const last = offset + KITTY_CHUNK_SIZE >= base64.length;
|
|
18107
|
-
chunks.push(`\x1B_G${offset === 0 ? `${params.join(",")},` : ""}m=${last ? 0 : 1};${part}\x1B\\`);
|
|
18108
|
-
}
|
|
18109
|
-
return chunks.join("");
|
|
18110
|
-
}
|
|
18111
|
-
function clampByte(value) {
|
|
18112
|
-
return Math.max(0, Math.min(255, Math.round(value)));
|
|
18113
|
-
}
|
|
18114
|
-
function blendOver(data, index, color, alphaScale = 1) {
|
|
18115
|
-
const alpha = color[3] / 255 * alphaScale;
|
|
18116
|
-
const inv = 1 - alpha;
|
|
18117
|
-
data[index] = clampByte(color[0] * alpha + data[index] * inv);
|
|
18118
|
-
data[index + 1] = clampByte(color[1] * alpha + data[index + 1] * inv);
|
|
18119
|
-
data[index + 2] = clampByte(color[2] * alpha + data[index + 2] * inv);
|
|
18120
|
-
data[index + 3] = 255;
|
|
18121
|
-
}
|
|
18122
|
-
function drawDisc(data, width, height, cx, cy, radius, color, alpha = 1) {
|
|
18123
|
-
const minX = Math.max(0, Math.floor(cx - radius));
|
|
18124
|
-
const maxX = Math.min(width - 1, Math.ceil(cx + radius));
|
|
18125
|
-
const minY = Math.max(0, Math.floor(cy - radius));
|
|
18126
|
-
const maxY = Math.min(height - 1, Math.ceil(cy + radius));
|
|
18127
|
-
for (let y = minY;y <= maxY; y += 1) {
|
|
18128
|
-
for (let x = minX;x <= maxX; x += 1) {
|
|
18129
|
-
const dx = x + 0.5 - cx;
|
|
18130
|
-
const dy = y + 0.5 - cy;
|
|
18131
|
-
const d = Math.sqrt(dx * dx + dy * dy);
|
|
18132
|
-
if (d > radius)
|
|
18133
|
-
continue;
|
|
18134
|
-
const edge = Math.max(0, Math.min(1, radius - d));
|
|
18135
|
-
blendOver(data, (y * width + x) * 4, color, alpha * Math.min(1, 0.35 + edge));
|
|
18136
|
-
}
|
|
18137
|
-
}
|
|
18138
|
-
}
|
|
18139
|
-
function drawGlow2(data, width, height, cx, cy, radius, color, alpha = 0.18) {
|
|
18140
|
-
const minX = Math.max(0, Math.floor(cx - radius));
|
|
18141
|
-
const maxX = Math.min(width - 1, Math.ceil(cx + radius));
|
|
18142
|
-
const minY = Math.max(0, Math.floor(cy - radius));
|
|
18143
|
-
const maxY = Math.min(height - 1, Math.ceil(cy + radius));
|
|
18144
|
-
for (let y = minY;y <= maxY; y += 1) {
|
|
18145
|
-
for (let x = minX;x <= maxX; x += 1) {
|
|
18146
|
-
const dx = x + 0.5 - cx;
|
|
18147
|
-
const dy = y + 0.5 - cy;
|
|
18148
|
-
const d = Math.sqrt(dx * dx + dy * dy);
|
|
18149
|
-
if (d > radius)
|
|
18150
|
-
continue;
|
|
18151
|
-
const falloff = Math.pow(1 - d / Math.max(1, radius), GLOW_FALLOFF_EXP_IMAGE);
|
|
18152
|
-
blendOver(data, (y * width + x) * 4, color, alpha * falloff);
|
|
18153
|
-
}
|
|
18154
|
-
}
|
|
18155
|
-
}
|
|
18156
|
-
function drawLine2(data, width, height, x0, y0, x1, y1, color, alpha = 0.5, thickness = 1.4) {
|
|
18157
|
-
const dx = x1 - x0;
|
|
18158
|
-
const dy = y1 - y0;
|
|
18159
|
-
const steps = Math.max(1, Math.ceil(Math.hypot(dx, dy) * 1.2));
|
|
18160
|
-
for (let i = 0;i <= steps; i += 1) {
|
|
18161
|
-
const t2 = i / steps;
|
|
18162
|
-
drawDisc(data, width, height, x0 + dx * t2, y0 + dy * t2, thickness, color, alpha);
|
|
18163
|
-
}
|
|
18164
|
-
}
|
|
18165
|
-
function roundRectAlpha(px, py, x, y, w, h, r) {
|
|
18166
|
-
const rx = Math.max(x + r, Math.min(px, x + w - r));
|
|
18167
|
-
const ry = Math.max(y + r, Math.min(py, y + h - r));
|
|
18168
|
-
const dx = px - rx;
|
|
18169
|
-
const dy = py - ry;
|
|
18170
|
-
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
18171
|
-
return Math.max(0, Math.min(1, r + 0.75 - dist));
|
|
18172
|
-
}
|
|
18173
|
-
function panelRect(layout, panel, size) {
|
|
18174
|
-
return panelPixelPlacement(layout, panel, size);
|
|
18175
|
-
}
|
|
18176
|
-
function downsampleRegion(data, canvasW, canvasH, rect, scale) {
|
|
18177
|
-
const w = Math.max(1, Math.ceil(rect.width / scale));
|
|
18178
|
-
const h = Math.max(1, Math.ceil(rect.height / scale));
|
|
18179
|
-
const out = new Uint8ClampedArray(w * h * 3);
|
|
18180
|
-
for (let y = 0;y < h; y += 1) {
|
|
18181
|
-
for (let x = 0;x < w; x += 1) {
|
|
18182
|
-
let r = 0, g = 0, b = 0, count = 0;
|
|
18183
|
-
const sx0 = rect.left + x * scale;
|
|
18184
|
-
const sy0 = rect.top + y * scale;
|
|
18185
|
-
for (let yy = 0;yy < scale; yy += 1) {
|
|
18186
|
-
const sy = sy0 + yy;
|
|
18187
|
-
if (sy < 0 || sy >= canvasH)
|
|
18188
|
-
continue;
|
|
18189
|
-
for (let xx = 0;xx < scale; xx += 1) {
|
|
18190
|
-
const sx = sx0 + xx;
|
|
18191
|
-
if (sx < 0 || sx >= canvasW)
|
|
18192
|
-
continue;
|
|
18193
|
-
const i = (sy * canvasW + sx) * 4;
|
|
18194
|
-
r += data[i];
|
|
18195
|
-
g += data[i + 1];
|
|
18196
|
-
b += data[i + 2];
|
|
18197
|
-
count += 1;
|
|
18198
|
-
}
|
|
18199
|
-
}
|
|
18200
|
-
const oi = (y * w + x) * 3;
|
|
18201
|
-
out[oi] = count ? r / count : BG[0];
|
|
18202
|
-
out[oi + 1] = count ? g / count : BG[1];
|
|
18203
|
-
out[oi + 2] = count ? b / count : BG[2];
|
|
18204
|
-
}
|
|
18205
|
-
}
|
|
18206
|
-
return { pixels: out, width: w, height: h };
|
|
18207
|
-
}
|
|
18208
|
-
function blurRgb(buffer, width, height, radius) {
|
|
18209
|
-
const tmp = new Uint8ClampedArray(buffer.length);
|
|
18210
|
-
const out = new Uint8ClampedArray(buffer.length);
|
|
18211
|
-
const window = radius * 2 + 1;
|
|
18212
|
-
for (let y = 0;y < height; y += 1) {
|
|
18213
|
-
let r = 0, g = 0, b = 0;
|
|
18214
|
-
for (let x = -radius;x <= radius; x += 1) {
|
|
18215
|
-
const sx = Math.max(0, Math.min(width - 1, x));
|
|
18216
|
-
const i = (y * width + sx) * 3;
|
|
18217
|
-
r += buffer[i];
|
|
18218
|
-
g += buffer[i + 1];
|
|
18219
|
-
b += buffer[i + 2];
|
|
18220
|
-
}
|
|
18221
|
-
for (let x = 0;x < width; x += 1) {
|
|
18222
|
-
const oi = (y * width + x) * 3;
|
|
18223
|
-
tmp[oi] = r / window;
|
|
18224
|
-
tmp[oi + 1] = g / window;
|
|
18225
|
-
tmp[oi + 2] = b / window;
|
|
18226
|
-
const removeX = Math.max(0, x - radius);
|
|
18227
|
-
const addX = Math.min(width - 1, x + radius + 1);
|
|
18228
|
-
const ri = (y * width + removeX) * 3;
|
|
18229
|
-
const ai = (y * width + addX) * 3;
|
|
18230
|
-
r += tmp.length ? buffer[ai] - buffer[ri] : 0;
|
|
18231
|
-
g += tmp.length ? buffer[ai + 1] - buffer[ri + 1] : 0;
|
|
18232
|
-
b += tmp.length ? buffer[ai + 2] - buffer[ri + 2] : 0;
|
|
18233
|
-
}
|
|
18234
|
-
}
|
|
18235
|
-
for (let x = 0;x < width; x += 1) {
|
|
18236
|
-
let r = 0, g = 0, b = 0;
|
|
18237
|
-
for (let y = -radius;y <= radius; y += 1) {
|
|
18238
|
-
const sy = Math.max(0, Math.min(height - 1, y));
|
|
18239
|
-
const i = (sy * width + x) * 3;
|
|
18240
|
-
r += tmp[i];
|
|
18241
|
-
g += tmp[i + 1];
|
|
18242
|
-
b += tmp[i + 2];
|
|
18243
|
-
}
|
|
18244
|
-
for (let y = 0;y < height; y += 1) {
|
|
18245
|
-
const oi = (y * width + x) * 3;
|
|
18246
|
-
out[oi] = r / window;
|
|
18247
|
-
out[oi + 1] = g / window;
|
|
18248
|
-
out[oi + 2] = b / window;
|
|
18249
|
-
const removeY = Math.max(0, y - radius);
|
|
18250
|
-
const addY = Math.min(height - 1, y + radius + 1);
|
|
18251
|
-
const ri = (removeY * width + x) * 3;
|
|
18252
|
-
const ai = (addY * width + x) * 3;
|
|
18253
|
-
r += tmp[ai] - tmp[ri];
|
|
18254
|
-
g += tmp[ai + 1] - tmp[ri + 1];
|
|
18255
|
-
b += tmp[ai + 2] - tmp[ri + 2];
|
|
18256
|
-
}
|
|
18257
|
-
}
|
|
18258
|
-
return out;
|
|
18259
|
-
}
|
|
18260
|
-
function panelMaskKey(width, height, rect, headerPx, blurScale) {
|
|
18261
|
-
return `${width}x${height}:${rect.left},${rect.top},${rect.width},${rect.height}:${Math.round(headerPx * 100) / 100}:${blurScale}`;
|
|
18262
|
-
}
|
|
18263
|
-
function getPanelMask(width, height, rect, headerPx, blurScale) {
|
|
18264
|
-
const key = panelMaskKey(width, height, rect, headerPx, blurScale);
|
|
18265
|
-
const cached = panelMaskCache.get(key);
|
|
18266
|
-
if (cached)
|
|
18267
|
-
return cached;
|
|
18268
|
-
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)));
|
|
18269
|
-
const sampledWidth = Math.max(1, Math.ceil(rect.width / blurScale));
|
|
18270
|
-
const sampledHeight = Math.max(1, Math.ceil(rect.height / blurScale));
|
|
18271
|
-
const x0 = Math.max(0, rect.left);
|
|
18272
|
-
const y0 = Math.max(0, rect.top);
|
|
18273
|
-
const x1 = Math.min(width - 1, rect.left + rect.width - 1);
|
|
18274
|
-
const y1 = Math.min(height - 1, rect.top + rect.height - 1);
|
|
18275
|
-
const indices = [];
|
|
18276
|
-
const sampleIndices = [];
|
|
18277
|
-
const panelAlpha = [];
|
|
18278
|
-
const edgeAlpha = [];
|
|
18279
|
-
const headerFlags = [];
|
|
18280
|
-
const dividerIndices = [];
|
|
18281
|
-
for (let y = y0;y <= y1; y += 1) {
|
|
18282
|
-
for (let x = x0;x <= x1; x += 1) {
|
|
18283
|
-
const a = roundRectAlpha(x + 0.5, y + 0.5, rect.left, rect.top, rect.width, rect.height, radius);
|
|
18284
|
-
if (a <= 0)
|
|
18285
|
-
continue;
|
|
18286
|
-
const edge = roundRectAlpha(x + 0.5, y + 0.5, rect.left + 1.2, rect.top + 1.2, rect.width - 2.4, rect.height - 2.4, Math.max(1, radius - 1.2));
|
|
18287
|
-
const sx = Math.max(0, Math.min(sampledWidth - 1, Math.floor((x - rect.left) / blurScale)));
|
|
18288
|
-
const sy = Math.max(0, Math.min(sampledHeight - 1, Math.floor((y - rect.top) / blurScale)));
|
|
18289
|
-
indices.push((y * width + x) * 4);
|
|
18290
|
-
sampleIndices.push((sy * sampledWidth + sx) * 3);
|
|
18291
|
-
panelAlpha.push(a);
|
|
18292
|
-
edgeAlpha.push(edge < 0.96 ? Math.min(1, (1 - edge) * 0.7) : 0);
|
|
18293
|
-
headerFlags.push(y < rect.top + headerPx ? 1 : 0);
|
|
18294
|
-
}
|
|
18295
|
-
}
|
|
18296
|
-
const dividerY = Math.round(rect.top + headerPx);
|
|
18297
|
-
if (dividerY > y0 && dividerY < y1) {
|
|
18298
|
-
for (let x = x0 + radius;x <= x1 - radius; x += 1) {
|
|
18299
|
-
dividerIndices.push((dividerY * width + x) * 4);
|
|
18300
|
-
}
|
|
18301
|
-
}
|
|
18302
|
-
const mask = {
|
|
18303
|
-
key,
|
|
18304
|
-
indices: Uint32Array.from(indices),
|
|
18305
|
-
sampleIndices: Uint32Array.from(sampleIndices),
|
|
18306
|
-
panelAlpha: Float32Array.from(panelAlpha),
|
|
18307
|
-
edgeAlpha: Float32Array.from(edgeAlpha),
|
|
18308
|
-
headerFlags: Uint8Array.from(headerFlags),
|
|
18309
|
-
dividerIndices: Uint32Array.from(dividerIndices)
|
|
18310
|
-
};
|
|
18311
|
-
panelMaskCache.set(key, mask);
|
|
18312
|
-
while (panelMaskCache.size > PANEL_MASK_CACHE_LIMIT) {
|
|
18313
|
-
const oldest = panelMaskCache.keys().next().value;
|
|
18314
|
-
if (!oldest)
|
|
18315
|
-
break;
|
|
18316
|
-
panelMaskCache.delete(oldest);
|
|
18317
|
-
}
|
|
18318
|
-
return mask;
|
|
18319
|
-
}
|
|
18320
|
-
function compositePanel(data, width, height, rect, headerPx) {
|
|
18321
|
-
const blurScale = PANEL_BLUR_SCALE;
|
|
18322
|
-
const sampled = downsampleRegion(data, width, height, rect, blurScale);
|
|
18323
|
-
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)));
|
|
18324
|
-
const blurred = blurRgb(sampled.pixels, sampled.width, sampled.height, blurRadius);
|
|
18325
|
-
const mask = getPanelMask(width, height, rect, headerPx, blurScale);
|
|
18326
|
-
for (let i = 0;i < mask.indices.length; i += 1) {
|
|
18327
|
-
const idx = mask.indices[i];
|
|
18328
|
-
const sampleIdx = mask.sampleIndices[i];
|
|
18329
|
-
data[idx] = blurred[sampleIdx];
|
|
18330
|
-
data[idx + 1] = blurred[sampleIdx + 1];
|
|
18331
|
-
data[idx + 2] = blurred[sampleIdx + 2];
|
|
18332
|
-
data[idx + 3] = 255;
|
|
18333
|
-
blendOver(data, idx, mask.headerFlags[i] ? PANEL_HEADER : PANEL, mask.panelAlpha[i]);
|
|
18334
|
-
const edge = mask.edgeAlpha[i];
|
|
18335
|
-
if (edge > 0)
|
|
18336
|
-
blendOver(data, idx, PANEL_LINE2, edge);
|
|
18337
|
-
}
|
|
18338
|
-
for (let i = 0;i < mask.dividerIndices.length; i += 1) {
|
|
18339
|
-
blendOver(data, mask.dividerIndices[i], PANEL_LINE2, 0.28);
|
|
18340
|
-
}
|
|
18341
|
-
}
|
|
18342
|
-
function drawBigRigWordmark(data, width, height, layout, load) {
|
|
18343
|
-
const sideBySide = layout.width >= FLEET_GRID_WIDTH * 1.9;
|
|
18344
|
-
if (!sideBySide)
|
|
18345
|
-
return;
|
|
18346
|
-
const letters = "RIG";
|
|
18347
|
-
const min = Math.min(width, height);
|
|
18348
|
-
const glyphH = height * 0.42;
|
|
18349
|
-
const glyphW = width * 0.13;
|
|
18350
|
-
const gap = glyphW * 0.3;
|
|
18351
|
-
const totalW = letters.length * glyphW + (letters.length - 1) * gap;
|
|
18352
|
-
const centerX = width * 0.71;
|
|
18353
|
-
const startX = centerX - totalW / 2;
|
|
18354
|
-
const top = (height - glyphH) / 2;
|
|
18355
|
-
const stroke = Math.max(2, min * 0.013);
|
|
18356
|
-
drawGlow2(data, width, height, centerX, top + glyphH / 2, Math.max(glyphW, glyphH) * 0.9, LIME, 0.022 + load * 0.02);
|
|
18357
|
-
const strokeAlpha = 0.1 + load * 0.06;
|
|
18358
|
-
letters.split("").forEach((letter, index) => {
|
|
18359
|
-
const segments = RIG_GLYPH_STROKES[letter];
|
|
18360
|
-
if (!segments)
|
|
18361
|
-
return;
|
|
18362
|
-
const ox = startX + index * (glyphW + gap);
|
|
18363
|
-
for (const [x0, y0, x1, y1] of segments) {
|
|
18364
|
-
drawLine2(data, width, height, ox + x0 * glyphW, top + y0 * glyphH, ox + x1 * glyphW, top + y1 * glyphH, LIME_DIM, strokeAlpha, stroke);
|
|
18365
|
-
}
|
|
18366
|
-
});
|
|
18367
|
-
}
|
|
18368
|
-
function drawBackground(data, width, height, _tick, scene, layout, load, activeRuns) {
|
|
18369
|
-
fillRgba(data, BG, BG_WORD);
|
|
18370
|
-
drawStaticAsciiFleetBackground(data, width, height, scene, layout, load, activeRuns);
|
|
18371
|
-
drawBigRigWordmark(data, width, height, layout, load);
|
|
18372
|
-
applyStaticAtmosphere(data, width, height, load);
|
|
18373
|
-
}
|
|
18374
|
-
function imageVisualFrameKey(input) {
|
|
18375
|
-
const width = Math.max(1, Math.floor(input.pixelSize.width));
|
|
18376
|
-
const height = Math.max(1, Math.floor(input.pixelSize.height));
|
|
18377
|
-
const layer = "layer" in input ? input.layer ?? "full" : "full";
|
|
18378
|
-
const load = loadBucket(input.load);
|
|
18379
|
-
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("|")}`;
|
|
18380
|
-
}
|
|
18381
|
-
function encodeKittyFrame(width, height, data, input) {
|
|
18382
|
-
if (input.transport === "png") {
|
|
18383
|
-
const png = encodePng(width, height, data);
|
|
18384
|
-
return kittyImageSequence(png.toString("base64"), { columns: input.layout.width, rows: input.layout.height, imageId: input.imageId, zIndex: input.zIndex, format: 100 });
|
|
18385
|
-
}
|
|
18386
|
-
const compressed = deflateSync(data, { level: ZLIB_LEVEL });
|
|
18387
|
-
return kittyImageSequence(compressed.toString("base64"), {
|
|
18388
|
-
columns: input.layout.width,
|
|
18389
|
-
rows: input.layout.height,
|
|
18390
|
-
imageId: input.imageId,
|
|
18391
|
-
zIndex: input.zIndex,
|
|
18392
|
-
format: 32,
|
|
18393
|
-
pixelWidth: width,
|
|
18394
|
-
pixelHeight: height,
|
|
18395
|
-
compressed: true
|
|
18396
|
-
});
|
|
18397
|
-
}
|
|
18398
|
-
function cropRgba(data, sourceWidth, rect) {
|
|
18399
|
-
const out = new Uint8ClampedArray(rect.width * rect.height * 4);
|
|
18400
|
-
for (let y = 0;y < rect.height; y += 1) {
|
|
18401
|
-
const sourceStart = ((rect.top + y) * sourceWidth + rect.left) * 4;
|
|
18402
|
-
out.set(data.subarray(sourceStart, sourceStart + rect.width * 4), y * rect.width * 4);
|
|
18403
|
-
}
|
|
18404
|
-
return out;
|
|
18405
|
-
}
|
|
18406
|
-
function encodePanelPatch(data, sourceWidth, placement, imageId, zIndex) {
|
|
18407
|
-
const patch = cropRgba(data, sourceWidth, placement);
|
|
18408
|
-
const png = encodePng(placement.width, placement.height, patch);
|
|
18409
|
-
const sequence = kittyImageSequence(png.toString("base64"), {
|
|
18410
|
-
columns: Math.max(1, Math.round(placement.widthCells)),
|
|
18411
|
-
rows: Math.max(1, Math.round(placement.heightCells)),
|
|
18412
|
-
imageId,
|
|
18413
|
-
zIndex,
|
|
18414
|
-
format: 100
|
|
18415
|
-
});
|
|
18416
|
-
return `\x1B[${Math.max(1, Math.round(placement.topCells) + 1)};${Math.max(1, Math.round(placement.leftCells) + 1)}H${sequence}`;
|
|
18417
|
-
}
|
|
18418
|
-
function renderImageVisualFrame(input) {
|
|
18419
|
-
const width = Math.max(1, Math.floor(input.pixelSize.width));
|
|
18420
|
-
const height = Math.max(1, Math.floor(input.pixelSize.height));
|
|
18421
|
-
const byteCount = width * height * 4;
|
|
18422
|
-
if (byteCount > MAX_IMAGE_BYTES)
|
|
18423
|
-
return null;
|
|
18424
|
-
const layer = input.layer ?? "full";
|
|
18425
|
-
const data = new Uint8ClampedArray(byteCount);
|
|
18426
|
-
const load = loadBucket(input.load) / LOAD_BUCKETS;
|
|
18427
|
-
const activeRuns = Math.max(0, Math.floor(input.activeRuns ?? 0));
|
|
18428
|
-
drawBackground(data, width, height, 0, input.scene, input.layout, load, activeRuns);
|
|
18429
|
-
if (layer === "split") {
|
|
18430
|
-
const sequences = [encodeKittyFrame(width, height, data, input)];
|
|
18431
|
-
let panelIndex = 0;
|
|
18432
|
-
for (const panel of input.panels) {
|
|
18433
|
-
if (panel.chrome !== "ad-terminal")
|
|
18434
|
-
continue;
|
|
18435
|
-
const placement = panelPixelPlacement(input.layout, panel, { width, height });
|
|
18436
|
-
if (!placement)
|
|
18437
|
-
continue;
|
|
18438
|
-
const cellH = height / input.layout.height;
|
|
18439
|
-
const headerPx = Math.max(cellH * 3, (panel.headerHeight ?? 3) * cellH);
|
|
18440
|
-
compositePanel(data, width, height, placement, headerPx);
|
|
18441
|
-
const imageId = input.imageIds?.[panelIndex] ?? (input.imageId + 1000 + panelIndex >>> 0 || panelIndex + 1);
|
|
18442
|
-
sequences.push(encodePanelPatch(data, width, placement, imageId, -12));
|
|
18443
|
-
panelIndex += 1;
|
|
18444
|
-
}
|
|
18445
|
-
return { key: imageVisualFrameKey(input), sequence: sequences.join("") };
|
|
18446
|
-
}
|
|
18447
|
-
if (layer === "panel-chrome")
|
|
18448
|
-
return { key: imageVisualFrameKey(input), sequence: "" };
|
|
18449
|
-
if (layer === "background") {
|
|
18450
|
-
return { key: imageVisualFrameKey(input), sequence: encodeKittyFrame(width, height, data, input) };
|
|
18451
|
-
}
|
|
18452
|
-
if (layer === "panel-patches") {
|
|
18453
|
-
const sequences = [];
|
|
18454
|
-
let panelIndex = 0;
|
|
18455
|
-
for (const panel of input.panels) {
|
|
18456
|
-
if (panel.chrome !== "ad-terminal")
|
|
18457
|
-
continue;
|
|
18458
|
-
const placement = panelPixelPlacement(input.layout, panel, { width, height });
|
|
18459
|
-
if (!placement)
|
|
18460
|
-
continue;
|
|
18461
|
-
const cellH = height / input.layout.height;
|
|
18462
|
-
const headerPx = Math.max(cellH * 3, (panel.headerHeight ?? 3) * cellH);
|
|
18463
|
-
compositePanel(data, width, height, placement, headerPx);
|
|
18464
|
-
const imageId = input.imageIds?.[panelIndex] ?? (input.imageId + 1000 + panelIndex >>> 0 || panelIndex + 1);
|
|
18465
|
-
sequences.push(encodePanelPatch(data, width, placement, imageId, input.zIndex));
|
|
18466
|
-
panelIndex += 1;
|
|
18467
|
-
}
|
|
18468
|
-
return { key: imageVisualFrameKey(input), sequence: sequences.join("") };
|
|
18469
|
-
}
|
|
18470
|
-
for (const panel of input.panels) {
|
|
18471
|
-
if (panel.chrome !== "ad-terminal")
|
|
18472
|
-
continue;
|
|
18473
|
-
const rect = panelRect(input.layout, panel, { width, height });
|
|
18474
|
-
if (!rect)
|
|
18475
|
-
continue;
|
|
18476
|
-
const cellH = height / input.layout.height;
|
|
18477
|
-
const headerPx = Math.max(cellH * 3, (panel.headerHeight ?? 3) * cellH);
|
|
18478
|
-
compositePanel(data, width, height, rect, headerPx);
|
|
18479
|
-
}
|
|
18480
|
-
return { key: imageVisualFrameKey(input), sequence: encodeKittyFrame(width, height, data, input) };
|
|
18481
|
-
}
|
|
18482
|
-
function shouldRenderImagesInline() {
|
|
18483
|
-
return process.env.RIG_OPENTUI_IMAGE_WORKER === "0" || import.meta.url.includes("$bunfs");
|
|
18484
|
-
}
|
|
18485
|
-
function createImageWorker() {
|
|
18486
|
-
if (shouldRenderImagesInline())
|
|
18487
|
-
return null;
|
|
18488
|
-
const isTypeScriptRuntime = import.meta.url.endsWith(".ts");
|
|
18489
|
-
const workerUrl = new URL(isTypeScriptRuntime ? "./image-visual-layer-worker.ts" : "./image-visual-layer-worker.js", import.meta.url);
|
|
18490
|
-
try {
|
|
18491
|
-
return new Worker(workerUrl);
|
|
18492
|
-
} catch {
|
|
18493
|
-
if (typeof process.versions.bun === "string") {
|
|
18494
|
-
try {
|
|
18495
|
-
return new Worker("./src/app-opentui/render/image-visual-layer-worker.ts");
|
|
18496
|
-
} catch {}
|
|
18497
|
-
}
|
|
18498
|
-
return null;
|
|
18499
|
-
}
|
|
18500
|
-
}
|
|
18501
|
-
function imageOutputBacklogBytes() {
|
|
18502
|
-
const raw = Number.parseInt(process.env.RIG_OPENTUI_IMAGE_BACKLOG_BYTES ?? "", 10);
|
|
18503
|
-
if (Number.isFinite(raw) && raw > 0)
|
|
18504
|
-
return Math.max(64 * 1024, Math.min(2 * 1024 * 1024, raw));
|
|
18505
|
-
return DEFAULT_IMAGE_OUTPUT_BACKLOG_BYTES;
|
|
18506
|
-
}
|
|
18507
|
-
function imageOutputBytesPerSecond() {
|
|
18508
|
-
const raw = Number.parseInt(process.env.RIG_OPENTUI_IMAGE_BYTES_PER_SECOND ?? "", 10);
|
|
18509
|
-
if (Number.isFinite(raw) && raw > 0)
|
|
18510
|
-
return Math.max(128 * 1024, Math.min(2 * 1024 * 1024, raw));
|
|
18511
|
-
return DEFAULT_IMAGE_OUTPUT_BYTES_PER_SECOND;
|
|
18512
|
-
}
|
|
18513
|
-
function pendingLayerKey(key) {
|
|
18514
|
-
return key.split(":", 1)[0] || "full";
|
|
18515
|
-
}
|
|
18516
|
-
|
|
18517
|
-
class ImageVisualLayer {
|
|
18518
|
-
imageId = allocateImageId();
|
|
18519
|
-
panelImageIds = Array.from({ length: 8 }, () => allocateImageId());
|
|
18520
|
-
panelChromeImageIds = Array.from({ length: 8 }, () => allocateImageId());
|
|
18521
|
-
stdout;
|
|
18522
|
-
onFrameReady;
|
|
18523
|
-
protocol;
|
|
18524
|
-
transport = imageTransport();
|
|
18525
|
-
maxOutputBacklogBytes = imageOutputBacklogBytes();
|
|
18526
|
-
outputBytesPerSecond = imageOutputBytesPerSecond();
|
|
18527
|
-
outputBudgetBytes = imageOutputBytesPerSecond();
|
|
18528
|
-
lastBudgetAtMs = Date.now();
|
|
18529
|
-
motionSlot = this.createSlot();
|
|
18530
|
-
workersStarted = false;
|
|
18531
|
-
pendingFrames = new Map;
|
|
18532
|
-
recentWrittenKeys = [];
|
|
18533
|
-
imagesVisible = false;
|
|
18534
|
-
flushPaused = false;
|
|
18535
|
-
requestId = 0;
|
|
18536
|
-
lastBackgroundKey = "";
|
|
18537
|
-
fatalWorkerError = null;
|
|
18538
|
-
destroyed = false;
|
|
18539
|
-
constructor(stdout = process.stdout, onFrameReady) {
|
|
18540
|
-
this.stdout = stdout;
|
|
18541
|
-
this.onFrameReady = onFrameReady;
|
|
18542
|
-
this.protocol = getRigTerminalCapabilities().imageProtocol;
|
|
18543
|
-
}
|
|
18544
|
-
get enabled() {
|
|
18545
|
-
return this.protocol === "kitty";
|
|
18546
|
-
}
|
|
18547
|
-
clear() {
|
|
18548
|
-
if (this.enabled) {
|
|
18549
|
-
if (this.imagesVisible)
|
|
18550
|
-
this.stdout.write([this.imageId, ...this.panelImageIds, ...this.panelChromeImageIds].map((id) => deleteKittyImage(id)).join("") + "\x1B[?25h");
|
|
18551
|
-
this.imagesVisible = false;
|
|
18552
|
-
this.pendingFrames.clear();
|
|
18553
|
-
this.recentWrittenKeys.length = 0;
|
|
18554
|
-
this.resetSlot(this.motionSlot);
|
|
18555
|
-
this.lastBackgroundKey = "";
|
|
18556
|
-
this.outputBudgetBytes = this.outputBytesPerSecond;
|
|
18557
|
-
this.lastBudgetAtMs = Date.now();
|
|
18558
|
-
this.motionSlot.clearedThroughRequestId = this.requestId;
|
|
18559
|
-
}
|
|
18560
|
-
}
|
|
18561
|
-
destroy() {
|
|
18562
|
-
if (this.destroyed)
|
|
18563
|
-
return;
|
|
18564
|
-
this.clear();
|
|
18565
|
-
this.destroyed = true;
|
|
18566
|
-
const workers = [this.motionSlot.worker];
|
|
18567
|
-
this.motionSlot.worker = null;
|
|
18568
|
-
for (const worker of workers)
|
|
18569
|
-
if (worker)
|
|
18570
|
-
worker.terminate().catch(() => {
|
|
18571
|
-
return;
|
|
18572
|
-
});
|
|
18573
|
-
}
|
|
18574
|
-
setFlushPaused(paused) {
|
|
18575
|
-
this.flushPaused = paused;
|
|
18576
|
-
}
|
|
18577
|
-
isReady(input) {
|
|
18578
|
-
if (!this.enabled || this.destroyed)
|
|
18579
|
-
return true;
|
|
18580
|
-
this.throwIfFatal();
|
|
18581
|
-
const splitKey = imageVisualFrameKey({ ...input, tick: 0, layer: "split" });
|
|
18582
|
-
return this.recentWrittenKeys.includes(splitKey) || Array.from(this.pendingFrames.values()).some((frame) => frame.key === splitKey);
|
|
18583
|
-
}
|
|
18584
|
-
render(input) {
|
|
18585
|
-
if (!this.enabled || this.destroyed)
|
|
18586
|
-
return;
|
|
18587
|
-
this.throwIfFatal();
|
|
18588
|
-
if (this.transport !== "png")
|
|
18589
|
-
this.failWorker("renderer", new Error("OpenTUI image visuals require PNG transport for static-background rendering."));
|
|
18590
|
-
this.ensureWorkersStarted();
|
|
18591
|
-
const width = Math.max(1, Math.floor(input.pixelSize.width));
|
|
18592
|
-
const height = Math.max(1, Math.floor(input.pixelSize.height));
|
|
18593
|
-
if (width * height * 4 > MAX_IMAGE_BYTES)
|
|
18594
|
-
return;
|
|
18595
|
-
if (this.isOutputBackedUp())
|
|
18596
|
-
return;
|
|
18597
|
-
this.refillOutputBudget();
|
|
18598
|
-
const splitInput = { ...input, tick: 0, layer: "split" };
|
|
18599
|
-
const splitKey = imageVisualFrameKey(splitInput);
|
|
18600
|
-
if (input.force || splitKey !== this.lastBackgroundKey) {
|
|
18601
|
-
this.scheduleRender(this.motionSlot, splitInput, this.imageId, -30, input.force, this.panelImageIds);
|
|
18602
|
-
this.lastBackgroundKey = splitKey;
|
|
18603
|
-
}
|
|
18604
|
-
}
|
|
18605
|
-
flush() {
|
|
18606
|
-
this.throwIfFatal();
|
|
18607
|
-
if (this.flushPaused)
|
|
18608
|
-
return false;
|
|
18609
|
-
if (this.pendingFrames.size === 0)
|
|
18610
|
-
return false;
|
|
18611
|
-
this.refillOutputBudget();
|
|
18612
|
-
if (this.isOutputBackedUp()) {
|
|
18613
|
-
const retainedSplit = this.pendingFrames.get("split");
|
|
18614
|
-
this.pendingFrames.clear();
|
|
18615
|
-
if (retainedSplit)
|
|
18616
|
-
this.pendingFrames.set("split", retainedSplit);
|
|
18617
|
-
return false;
|
|
18618
|
-
}
|
|
18619
|
-
const framePriority = (frame) => {
|
|
18620
|
-
const layer = pendingLayerKey(frame.key);
|
|
18621
|
-
if (layer === "split")
|
|
18622
|
-
return 1;
|
|
18623
|
-
return 4;
|
|
18624
|
-
};
|
|
18625
|
-
const frames = Array.from(this.pendingFrames.values()).sort((a, b) => framePriority(a) - framePriority(b));
|
|
18626
|
-
const prefix = "\x1B[?25l\x1B7\x1B[s\x1B[H";
|
|
18627
|
-
const suffix = "\x1B[u\x1B8";
|
|
18628
|
-
const selected = [];
|
|
18629
|
-
const retained = new Map;
|
|
18630
|
-
let sequence = "";
|
|
18631
|
-
let byteLength = Buffer.byteLength(prefix + suffix);
|
|
18632
|
-
for (const frame of frames) {
|
|
18633
|
-
const candidate = sequence + frame.sequence;
|
|
18634
|
-
const candidateBytes = Buffer.byteLength(prefix + candidate + suffix);
|
|
18635
|
-
const layer = pendingLayerKey(frame.key);
|
|
18636
|
-
const allowOneStaticFrame = selected.length === 0 && layer === "split";
|
|
18637
|
-
if (candidateBytes <= this.outputBudgetBytes || allowOneStaticFrame) {
|
|
18638
|
-
selected.push(frame);
|
|
18639
|
-
sequence = candidate;
|
|
18640
|
-
byteLength = candidateBytes;
|
|
18641
|
-
} else if (layer === "split") {
|
|
18642
|
-
retained.set(layer, frame);
|
|
18643
|
-
}
|
|
18644
|
-
}
|
|
18645
|
-
this.pendingFrames.clear();
|
|
18646
|
-
for (const [layer, frame] of retained)
|
|
18647
|
-
this.pendingFrames.set(layer, frame);
|
|
18648
|
-
if (!sequence || selected.length === 0)
|
|
18649
|
-
return false;
|
|
18650
|
-
const payload = `${prefix}${sequence}${suffix}`;
|
|
18651
|
-
for (const frame of selected)
|
|
18652
|
-
this.markWritten(frame.key);
|
|
18653
|
-
this.outputBudgetBytes -= byteLength;
|
|
18654
|
-
this.stdout.cork?.();
|
|
18655
|
-
const accepted = this.stdout.write(payload);
|
|
18656
|
-
this.stdout.uncork?.();
|
|
18657
|
-
this.imagesVisible = true;
|
|
18658
|
-
return accepted;
|
|
18659
|
-
}
|
|
18660
|
-
createSlot() {
|
|
18661
|
-
return { worker: null, busy: false, queuedRequest: null, inFlightKey: "", queuedKey: "", clearedThroughRequestId: 0, latestRequestId: 0 };
|
|
18662
|
-
}
|
|
18663
|
-
resetSlot(slot) {
|
|
18664
|
-
slot.busy = false;
|
|
18665
|
-
slot.queuedRequest = null;
|
|
18666
|
-
slot.inFlightKey = "";
|
|
18667
|
-
slot.queuedKey = "";
|
|
18668
|
-
}
|
|
18669
|
-
markWritten(key) {
|
|
18670
|
-
this.recentWrittenKeys.push(key);
|
|
18671
|
-
while (this.recentWrittenKeys.length > RECENT_WRITTEN_LIMIT)
|
|
18672
|
-
this.recentWrittenKeys.shift();
|
|
18673
|
-
}
|
|
18674
|
-
refillOutputBudget() {
|
|
18675
|
-
const now = Date.now();
|
|
18676
|
-
const elapsedMs = Math.max(0, now - this.lastBudgetAtMs);
|
|
18677
|
-
this.lastBudgetAtMs = now;
|
|
18678
|
-
this.outputBudgetBytes = Math.min(this.outputBytesPerSecond, this.outputBudgetBytes + elapsedMs / 1000 * this.outputBytesPerSecond);
|
|
18679
|
-
}
|
|
18680
|
-
isOutputBackedUp() {
|
|
18681
|
-
return Boolean(this.stdout.writableNeedDrain) || this.stdout.writableLength > this.maxOutputBacklogBytes;
|
|
18682
|
-
}
|
|
18683
|
-
stageFrame(frame) {
|
|
18684
|
-
this.pendingFrames.set(pendingLayerKey(frame.key), frame);
|
|
18685
|
-
}
|
|
18686
|
-
isKnownKey(slot, key) {
|
|
18687
|
-
return this.recentWrittenKeys.includes(key) || Array.from(this.pendingFrames.values()).some((frame) => frame.key === key) || key === slot.inFlightKey || key === slot.queuedKey;
|
|
18688
|
-
}
|
|
18689
|
-
ensureWorkersStarted() {
|
|
18690
|
-
if (this.workersStarted)
|
|
18691
|
-
return;
|
|
18692
|
-
this.workersStarted = true;
|
|
18693
|
-
this.startWorker(this.motionSlot, "static-visuals");
|
|
18694
|
-
}
|
|
18695
|
-
failWorker(name, error) {
|
|
18696
|
-
const detail = error instanceof Error ? error.message : String(error);
|
|
18697
|
-
this.fatalWorkerError ??= new Error(`OpenTUI image worker ${name} failed: ${detail}`);
|
|
18698
|
-
throw this.fatalWorkerError;
|
|
18699
|
-
}
|
|
18700
|
-
throwIfFatal() {
|
|
18701
|
-
if (this.fatalWorkerError)
|
|
18702
|
-
throw this.fatalWorkerError;
|
|
18703
|
-
}
|
|
18704
|
-
scheduleRender(slot, input, imageId, zIndex, force, imageIds) {
|
|
18705
|
-
this.throwIfFatal();
|
|
18706
|
-
const key = imageVisualFrameKey(input);
|
|
18707
|
-
if (!force && this.isKnownKey(slot, key))
|
|
18708
|
-
return;
|
|
18709
|
-
const request = {
|
|
18710
|
-
...input,
|
|
18711
|
-
imageId,
|
|
18712
|
-
...imageIds ? { imageIds } : {},
|
|
18713
|
-
zIndex,
|
|
18714
|
-
transport: this.transport,
|
|
18715
|
-
requestId: ++this.requestId,
|
|
18716
|
-
key
|
|
18717
|
-
};
|
|
18718
|
-
slot.latestRequestId = request.requestId;
|
|
18719
|
-
if (!slot.worker) {
|
|
18720
|
-
this.renderInline(slot, request);
|
|
18721
|
-
return;
|
|
18722
|
-
}
|
|
18723
|
-
this.enqueueWorkerRender(slot, request);
|
|
18724
|
-
}
|
|
18725
|
-
startWorker(slot, name) {
|
|
18726
|
-
const worker = createImageWorker();
|
|
18727
|
-
if (!worker)
|
|
18728
|
-
return;
|
|
18729
|
-
slot.worker = worker;
|
|
18730
|
-
worker.on("message", (message2) => this.handleWorkerMessage(slot, message2));
|
|
18731
|
-
worker.once("error", (error) => {
|
|
18732
|
-
if (!this.destroyed)
|
|
18733
|
-
this.fatalWorkerError ??= new Error(`OpenTUI image worker ${name} failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
18734
|
-
});
|
|
18735
|
-
worker.once("exit", (code) => {
|
|
18736
|
-
if (!this.destroyed)
|
|
18737
|
-
this.fatalWorkerError ??= new Error(`OpenTUI image worker ${name} exited unexpectedly with code ${code}.`);
|
|
18738
|
-
});
|
|
18739
|
-
}
|
|
18740
|
-
renderInline(slot, request) {
|
|
18741
|
-
try {
|
|
18742
|
-
const result = renderImageVisualFrame(request);
|
|
18743
|
-
if (result?.sequence && !this.isKnownKey(slot, result.key) && (!this.isOutputBackedUp() || pendingLayerKey(result.key) === "split")) {
|
|
18744
|
-
this.stageFrame({ key: result.key, sequence: result.sequence });
|
|
18745
|
-
this.onFrameReady?.();
|
|
18746
|
-
}
|
|
18747
|
-
} catch (error) {
|
|
18748
|
-
this.failWorker(String(request.layer ?? "visual"), error);
|
|
18749
|
-
}
|
|
18750
|
-
}
|
|
18751
|
-
enqueueWorkerRender(slot, request) {
|
|
18752
|
-
this.throwIfFatal();
|
|
18753
|
-
if (slot.busy) {
|
|
18754
|
-
slot.queuedRequest = request;
|
|
18755
|
-
slot.queuedKey = request.key;
|
|
18756
|
-
return;
|
|
18757
|
-
}
|
|
18758
|
-
this.dispatchWorkerRender(slot, request);
|
|
18759
|
-
}
|
|
18760
|
-
dispatchWorkerRender(slot, request) {
|
|
18761
|
-
this.throwIfFatal();
|
|
18762
|
-
if (!slot.worker)
|
|
18763
|
-
this.failWorker(String(request.layer ?? "visual"), new Error("worker is unavailable"));
|
|
18764
|
-
slot.busy = true;
|
|
18765
|
-
slot.inFlightKey = request.key;
|
|
18766
|
-
try {
|
|
18767
|
-
slot.worker.postMessage(request);
|
|
18768
|
-
} catch (error) {
|
|
18769
|
-
this.failWorker(String(request.layer ?? "visual"), error);
|
|
18770
|
-
}
|
|
18771
|
-
}
|
|
18772
|
-
handleWorkerMessage(slot, message2) {
|
|
18773
|
-
if (this.destroyed || !message2 || typeof message2 !== "object")
|
|
18774
|
-
return;
|
|
18775
|
-
const response = message2;
|
|
18776
|
-
slot.busy = false;
|
|
18777
|
-
slot.inFlightKey = "";
|
|
18778
|
-
const isStale = response.requestId <= slot.clearedThroughRequestId || response.requestId < slot.latestRequestId;
|
|
18779
|
-
if (!isStale) {
|
|
18780
|
-
if (response.error)
|
|
18781
|
-
this.failWorker(pendingLayerKey(response.key), new Error(response.error));
|
|
18782
|
-
if (response.sequence && !this.isKnownKey(slot, response.key) && (!this.isOutputBackedUp() || pendingLayerKey(response.key) === "split")) {
|
|
18783
|
-
this.stageFrame({ key: response.key, sequence: response.sequence });
|
|
18784
|
-
this.onFrameReady?.();
|
|
18785
|
-
}
|
|
18786
|
-
}
|
|
18787
|
-
const next = slot.queuedRequest;
|
|
18788
|
-
slot.queuedRequest = null;
|
|
18789
|
-
slot.queuedKey = "";
|
|
18790
|
-
if (next && !this.isKnownKey(slot, next.key))
|
|
18791
|
-
this.dispatchWorkerRender(slot, next);
|
|
18792
|
-
}
|
|
18793
|
-
}
|
|
18794
|
-
function pixelSizeForRenderer(renderer) {
|
|
18795
|
-
const resolution = renderer.resolution;
|
|
18796
|
-
const base = resolution?.width && resolution?.height ? resolution : { width: renderer.width * 12, height: renderer.height * 24 };
|
|
18797
|
-
const scale = imageResolutionScale();
|
|
18798
|
-
return {
|
|
18799
|
-
width: Math.max(renderer.width, Math.floor(base.width * scale)),
|
|
18800
|
-
height: Math.max(renderer.height, Math.floor(base.height * scale))
|
|
18801
|
-
};
|
|
18802
|
-
}
|
|
18803
|
-
function forceModernImageVisuals() {
|
|
18804
|
-
return getRigTerminalCapabilities().supportsKittyImages;
|
|
18805
|
-
}
|
|
18806
|
-
var PANEL_MASK_RADIUS_MIN = 14, PANEL_MASK_RADIUS_MAX = 34, PANEL_MASK_RADIUS_FACTOR = 0.035, PANEL_BLUR_RADIUS_MIN = 8, PANEL_BLUR_RADIUS_MAX = 28, PANEL_BLUR_RADIUS_FACTOR = 0.018, BG, PANEL, PANEL_HEADER, PANEL_LINE2, LIME, LIME_DIM, CYAN, MAGENTA, INK_DIM, PNG_SIGNATURE, CRC_TABLE, MAX_IMAGE_BYTES, KITTY_CHUNK_SIZE = 4096, PANEL_BLUR_SCALE = 1, PANEL_MASK_CACHE_LIMIT = 16, ZLIB_LEVEL = 1, DEFAULT_IMAGE_RESOLUTION_SCALE = 1, LOAD_BUCKETS = 5, panelMaskCache, BG_WORD, ASCII_GLYPHS, RIG_GLYPH_STROKES, RECENT_WRITTEN_LIMIT = 24, DEFAULT_IMAGE_OUTPUT_BACKLOG_BYTES, DEFAULT_IMAGE_OUTPUT_BYTES_PER_SECOND;
|
|
18807
|
-
var init_image_visual_layer = __esm(() => {
|
|
18808
|
-
init_terminal_capabilities();
|
|
18809
|
-
init_ascii_fleet();
|
|
18810
|
-
init_constants();
|
|
18811
|
-
BG = [7, 8, 9, 255];
|
|
18812
|
-
PANEL = [16, 17, 21, 184];
|
|
18813
|
-
PANEL_HEADER = [16, 17, 21, 190];
|
|
18814
|
-
PANEL_LINE2 = [255, 255, 255, 24];
|
|
18815
|
-
LIME = [204, 255, 77, 255];
|
|
18816
|
-
LIME_DIM = [169, 214, 63, 255];
|
|
18817
|
-
CYAN = [86, 216, 255, 255];
|
|
18818
|
-
MAGENTA = [255, 121, 176, 255];
|
|
18819
|
-
INK_DIM = [108, 110, 121, 255];
|
|
18820
|
-
PNG_SIGNATURE = new Uint8Array([137, 80, 78, 71, 13, 10, 26, 10]);
|
|
18821
|
-
CRC_TABLE = makeCrcTable();
|
|
18822
|
-
MAX_IMAGE_BYTES = 48 * 1024 * 1024;
|
|
18823
|
-
panelMaskCache = new Map;
|
|
18824
|
-
BG_WORD = rgbaWord(BG);
|
|
18825
|
-
ASCII_GLYPHS = {
|
|
18826
|
-
".": ["00000", "00000", "00000", "00000", "00000", "00100", "00100"],
|
|
18827
|
-
"'": ["00100", "00100", "00000", "00000", "00000", "00000", "00000"],
|
|
18828
|
-
"-": ["00000", "00000", "00000", "11111", "00000", "00000", "00000"],
|
|
18829
|
-
_: ["00000", "00000", "00000", "00000", "00000", "00000", "11111"],
|
|
18830
|
-
"=": ["00000", "11111", "00000", "00000", "11111", "00000", "00000"],
|
|
18831
|
-
"|": ["00100", "00100", "00100", "00100", "00100", "00100", "00100"],
|
|
18832
|
-
"/": ["00001", "00010", "00010", "00100", "01000", "01000", "10000"],
|
|
18833
|
-
"\\": ["10000", "01000", "01000", "00100", "00010", "00010", "00001"],
|
|
18834
|
-
"(": ["00010", "00100", "01000", "01000", "01000", "00100", "00010"],
|
|
18835
|
-
")": ["01000", "00100", "00010", "00010", "00010", "00100", "01000"],
|
|
18836
|
-
"!": ["00100", "00100", "00100", "00100", "00100", "00000", "00100"],
|
|
18837
|
-
"%": ["11001", "11010", "00100", "01000", "10110", "00110", "00000"],
|
|
18838
|
-
$: ["00100", "11110", "10100", "11110", "00101", "11110", "00100"],
|
|
18839
|
-
"@": ["01110", "10001", "10111", "10101", "10111", "10000", "01111"],
|
|
18840
|
-
o: ["00000", "01110", "10001", "10001", "10001", "01110", "00000"],
|
|
18841
|
-
"*": ["00100", "10101", "01110", "11111", "01110", "10101", "00100"]
|
|
18842
|
-
};
|
|
18843
|
-
RIG_GLYPH_STROKES = {
|
|
18844
|
-
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]],
|
|
18845
|
-
I: [[0.5, 0, 0.5, 1], [0.18, 0, 0.82, 0], [0.18, 1, 0.82, 1]],
|
|
18846
|
-
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]]
|
|
18847
|
-
};
|
|
18848
|
-
DEFAULT_IMAGE_OUTPUT_BACKLOG_BYTES = 256 * 1024;
|
|
18849
|
-
DEFAULT_IMAGE_OUTPUT_BYTES_PER_SECOND = 850 * 1024;
|
|
18850
|
-
});
|
|
18851
|
-
|
|
18852
17875
|
// packages/cli/src/app-opentui/render/text.ts
|
|
18853
17876
|
import { RGBA as RGBA4, TextAttributes as TextAttributes4, TextRenderable } from "@opentui/core";
|
|
18854
17877
|
function selectableMouseHandler(currentLineRef, onLineMouseDown) {
|
|
@@ -20053,7 +19076,7 @@ function __renderSceneForTest(renderer, state, sceneRenderers) {
|
|
|
20053
19076
|
renderer.root.add(navText);
|
|
20054
19077
|
const registry = buildSceneRendererRegistry(sceneRenderers);
|
|
20055
19078
|
const transition = { scene: state.scene, startedAtMs: 0, minUntilMs: 0 };
|
|
20056
|
-
const selectables = renderNow(renderer, null, null,
|
|
19079
|
+
const selectables = renderNow(renderer, null, null, scrollPanels, null, null, navText, textLines, nativeHost, state, registry, transition);
|
|
20057
19080
|
return { selectables, nativeHost };
|
|
20058
19081
|
}
|
|
20059
19082
|
async function launchRigOpenTuiApp(options) {
|
|
@@ -20065,7 +19088,6 @@ async function launchRigOpenTuiApp(options) {
|
|
|
20065
19088
|
const events = createAppEventBus();
|
|
20066
19089
|
let renderer = null;
|
|
20067
19090
|
let graphics = null;
|
|
20068
|
-
let imageVisuals = null;
|
|
20069
19091
|
let preloaderBackdrop = null;
|
|
20070
19092
|
const scrollPanels = [];
|
|
20071
19093
|
let typeBar = null;
|
|
@@ -20093,7 +19115,7 @@ async function launchRigOpenTuiApp(options) {
|
|
|
20093
19115
|
if (!renderer || destroyed)
|
|
20094
19116
|
return;
|
|
20095
19117
|
const currentState = store.getState();
|
|
20096
|
-
renderedSelectableItems = renderNow(renderer, graphics,
|
|
19118
|
+
renderedSelectableItems = renderNow(renderer, graphics, preloaderBackdrop, scrollPanels, typeBar, brandText, navText, textLines, nativeHost, currentState, sceneRendererRegistry, preloaderTransition, scheduleAppRender);
|
|
20097
19119
|
focusManager.restoreTypeBarFocus(typeBar, { hidden: currentState.scene === "handoff" });
|
|
20098
19120
|
maybeRedirectFromUnresolvedScene(currentState);
|
|
20099
19121
|
};
|
|
@@ -20253,18 +19275,8 @@ async function launchRigOpenTuiApp(options) {
|
|
|
20253
19275
|
});
|
|
20254
19276
|
renderer.setTerminalTitle?.("Operator cockpit");
|
|
20255
19277
|
const layout = computeStageLayout(renderer.width, renderer.height);
|
|
20256
|
-
|
|
20257
|
-
|
|
20258
|
-
const flushImageVisuals = async () => {
|
|
20259
|
-
imageVisuals?.flush();
|
|
20260
|
-
};
|
|
20261
|
-
renderer.setFrameCallback(flushImageVisuals);
|
|
20262
|
-
resources.add(() => renderer?.removeFrameCallback(flushImageVisuals));
|
|
20263
|
-
}
|
|
20264
|
-
if (!imageVisuals?.enabled) {
|
|
20265
|
-
graphics = createGraphicsLayer(renderer, layout);
|
|
20266
|
-
renderer.root.add(graphics);
|
|
20267
|
-
}
|
|
19278
|
+
graphics = createGraphicsLayer(renderer, layout);
|
|
19279
|
+
renderer.root.add(graphics);
|
|
20268
19280
|
preloaderBackdrop = new BoxRenderable3(renderer, {
|
|
20269
19281
|
id: "rig-preloader-backdrop",
|
|
20270
19282
|
position: "absolute",
|
|
@@ -20390,7 +19402,6 @@ async function launchRigOpenTuiApp(options) {
|
|
|
20390
19402
|
stopActivePiHost("renderer destroyed");
|
|
20391
19403
|
stopActiveCommandHost("renderer destroyed");
|
|
20392
19404
|
destroyNativeHost(nativeHost);
|
|
20393
|
-
imageVisuals?.destroy();
|
|
20394
19405
|
if (renderTimer)
|
|
20395
19406
|
clearTimeout(renderTimer);
|
|
20396
19407
|
renderTimer = null;
|
|
@@ -20439,14 +19450,13 @@ async function launchRigOpenTuiApp(options) {
|
|
|
20439
19450
|
clearTimeout(renderTimer);
|
|
20440
19451
|
renderTimer = null;
|
|
20441
19452
|
resources.disposeAll();
|
|
20442
|
-
imageVisuals?.destroy();
|
|
20443
19453
|
stopActivePiHost("app shutdown");
|
|
20444
19454
|
stopActiveCommandHost("app shutdown");
|
|
20445
19455
|
if (renderer && !renderer.isDestroyed)
|
|
20446
19456
|
renderer.destroy();
|
|
20447
19457
|
}
|
|
20448
19458
|
}
|
|
20449
|
-
function renderNow(renderer, graphics,
|
|
19459
|
+
function renderNow(renderer, graphics, preloaderBackdrop, scrollPanels, typeBar, brandText, navText, textLines, nativeHost, state, sceneRendererRegistry, preloaderTransition, scheduleRenderAfter) {
|
|
20450
19460
|
const layout = computeStageLayout(renderer.width, renderer.height);
|
|
20451
19461
|
const hideNav = () => {
|
|
20452
19462
|
if (navText)
|
|
@@ -20455,7 +19465,6 @@ function renderNow(renderer, graphics, imageVisuals, preloaderBackdrop, scrollPa
|
|
|
20455
19465
|
if (layout.tooSmall) {
|
|
20456
19466
|
if (graphics)
|
|
20457
19467
|
clearGraphicsLayer(graphics);
|
|
20458
|
-
imageVisuals?.clear();
|
|
20459
19468
|
if (preloaderBackdrop)
|
|
20460
19469
|
preloaderBackdrop.visible = false;
|
|
20461
19470
|
if (brandText)
|
|
@@ -20489,8 +19498,7 @@ function renderNow(renderer, graphics, imageVisuals, preloaderBackdrop, scrollPa
|
|
|
20489
19498
|
preloaderTransition.minUntilMs = now;
|
|
20490
19499
|
const targetFrame = renderState.typeBar.mode === "command" ? commandPaletteFrame(renderState, layout) : rendererForScene(renderState.scene, sceneRendererRegistry)(renderState, layout);
|
|
20491
19500
|
const targetContentLayout = targetFrame.fullScreen ? { ...layout, centerWidth: layout.width, centerLeft: 0, centerTop: 0, centerHeight: Math.min(layout.height, MAX_SCENE_LINES) } : layout;
|
|
20492
|
-
const
|
|
20493
|
-
let targetVisualReady = true;
|
|
19501
|
+
const targetVisualReady = true;
|
|
20494
19502
|
const fleetStats = fleetStatsFromState(state);
|
|
20495
19503
|
const fleetLoad = fleetStats.load;
|
|
20496
19504
|
const fleetActive = fleetStats.active;
|
|
@@ -20500,23 +19508,7 @@ function renderNow(renderer, graphics, imageVisuals, preloaderBackdrop, scrollPa
|
|
|
20500
19508
|
if (renderState.scene === "command") {
|
|
20501
19509
|
getActiveCommandHost()?.resize(Math.max(40, targetContentLayout.centerWidth - 12), Math.max(10, targetContentLayout.centerHeight - 6));
|
|
20502
19510
|
}
|
|
20503
|
-
if (imageVisuals && targetFrame.terminalActive) {
|
|
20504
|
-
imageVisuals.clear();
|
|
20505
|
-
} else if (imageVisuals && !targetFrame.fullScreen && !sceneJustChanged) {
|
|
20506
|
-
const visualInput = {
|
|
20507
|
-
layout: targetContentLayout,
|
|
20508
|
-
pixelSize: pixelSizeForRenderer(renderer),
|
|
20509
|
-
panels: targetPanelsForImages,
|
|
20510
|
-
scene: state.scene,
|
|
20511
|
-
tick: state.tick,
|
|
20512
|
-
load: fleetLoad,
|
|
20513
|
-
activeRuns: fleetActive
|
|
20514
|
-
};
|
|
20515
|
-
imageVisuals.render(visualInput);
|
|
20516
|
-
targetVisualReady = imageVisuals.isReady(visualInput);
|
|
20517
|
-
}
|
|
20518
19511
|
const preloaderActive = sceneJustChanged && !cachedFastPath || isPreloaderActive(preloaderTransition, targetVisualReady, now);
|
|
20519
|
-
imageVisuals?.setFlushPaused(preloaderActive);
|
|
20520
19512
|
const frame = preloaderActive ? renderAsciiPreloaderFrame(renderState.scene, layout, state.tick) : targetFrame;
|
|
20521
19513
|
if (graphics) {
|
|
20522
19514
|
resizeGraphicsLayer(graphics, layout);
|
|
@@ -20615,7 +19607,6 @@ var init_runtime = __esm(() => {
|
|
|
20615
19607
|
init_theme2();
|
|
20616
19608
|
init_graphics();
|
|
20617
19609
|
init_fleet_stats();
|
|
20618
|
-
init_image_visual_layer();
|
|
20619
19610
|
init_text();
|
|
20620
19611
|
init_panels();
|
|
20621
19612
|
init_type_bar();
|
|
@@ -20675,68 +19666,42 @@ function isTerminalScene(scene) {
|
|
|
20675
19666
|
}
|
|
20676
19667
|
function Backdrop(props) {
|
|
20677
19668
|
const renderer = useRenderer();
|
|
20678
|
-
const imageRef = useRef(null);
|
|
20679
19669
|
const graphicsRef = useRef(null);
|
|
20680
19670
|
useEffect(() => {
|
|
20681
|
-
const
|
|
20682
|
-
|
|
20683
|
-
|
|
20684
|
-
|
|
20685
|
-
const layout = computeStageLayout(renderer.width, renderer.height);
|
|
20686
|
-
const graphics = createGraphicsLayer(renderer, layout);
|
|
20687
|
-
renderer.root.add(graphics);
|
|
20688
|
-
graphicsRef.current = graphics;
|
|
20689
|
-
}
|
|
19671
|
+
const layout = computeStageLayout(renderer.width, renderer.height);
|
|
19672
|
+
const graphics = createGraphicsLayer(renderer, layout);
|
|
19673
|
+
renderer.root.add(graphics);
|
|
19674
|
+
graphicsRef.current = graphics;
|
|
20690
19675
|
return () => {
|
|
20691
|
-
|
|
20692
|
-
|
|
20693
|
-
if (graphics) {
|
|
19676
|
+
const g = graphicsRef.current;
|
|
19677
|
+
if (g) {
|
|
20694
19678
|
try {
|
|
20695
|
-
renderer.root.remove(
|
|
19679
|
+
renderer.root.remove(g.id);
|
|
20696
19680
|
} catch {}
|
|
20697
19681
|
}
|
|
20698
|
-
imageRef.current = null;
|
|
20699
19682
|
graphicsRef.current = null;
|
|
20700
19683
|
};
|
|
20701
19684
|
}, [renderer]);
|
|
20702
19685
|
useEffect(() => {
|
|
20703
|
-
const layout = computeStageLayout(renderer.width, renderer.height);
|
|
20704
|
-
const image = imageRef.current;
|
|
20705
19686
|
const graphics = graphicsRef.current;
|
|
19687
|
+
if (!graphics)
|
|
19688
|
+
return;
|
|
19689
|
+
const layout = computeStageLayout(renderer.width, renderer.height);
|
|
20706
19690
|
if (layout.tooSmall) {
|
|
20707
|
-
|
|
20708
|
-
if (graphics)
|
|
20709
|
-
clearGraphicsLayer(graphics);
|
|
19691
|
+
clearGraphicsLayer(graphics);
|
|
20710
19692
|
return;
|
|
20711
19693
|
}
|
|
20712
19694
|
const stats = fleetStatsFromState(props.state);
|
|
20713
|
-
const
|
|
20714
|
-
const animationTick = Math.floor(tick / ANIMATION_SLOWDOWN2);
|
|
19695
|
+
const animationTick = Math.floor(props.state.tick / ANIMATION_SLOWDOWN2);
|
|
20715
19696
|
const panels = (props.frame.panels ?? []).map((panel) => ({ ...panel }));
|
|
20716
19697
|
const terminalActive = props.frame.terminalActive ?? isTerminalScene(props.state.scene);
|
|
20717
19698
|
const fullScreen = Boolean(props.frame.fullScreen);
|
|
20718
|
-
|
|
20719
|
-
|
|
20720
|
-
|
|
20721
|
-
|
|
20722
|
-
|
|
20723
|
-
|
|
20724
|
-
pixelSize: pixelSizeForRenderer(renderer),
|
|
20725
|
-
panels,
|
|
20726
|
-
scene: props.state.scene,
|
|
20727
|
-
tick,
|
|
20728
|
-
load: stats.load,
|
|
20729
|
-
activeRuns: stats.active
|
|
20730
|
-
});
|
|
20731
|
-
}
|
|
20732
|
-
} else if (graphics) {
|
|
20733
|
-
resizeGraphicsLayer(graphics, layout);
|
|
20734
|
-
if (terminalActive || fullScreen) {
|
|
20735
|
-
clearGraphicsLayer(graphics);
|
|
20736
|
-
} else {
|
|
20737
|
-
drawAmbientField(graphics, layout, animationTick, props.state.scene, stats.load, stats.active);
|
|
20738
|
-
drawPanelChrome(graphics, layout, panels);
|
|
20739
|
-
}
|
|
19699
|
+
resizeGraphicsLayer(graphics, layout);
|
|
19700
|
+
if (terminalActive || fullScreen) {
|
|
19701
|
+
clearGraphicsLayer(graphics);
|
|
19702
|
+
} else {
|
|
19703
|
+
drawAmbientField(graphics, layout, animationTick, props.state.scene, stats.load, stats.active);
|
|
19704
|
+
drawPanelChrome(graphics, layout, panels);
|
|
20740
19705
|
}
|
|
20741
19706
|
});
|
|
20742
19707
|
return null;
|
|
@@ -20744,7 +19709,6 @@ function Backdrop(props) {
|
|
|
20744
19709
|
var ANIMATION_SLOWDOWN2 = 1;
|
|
20745
19710
|
var init_Backdrop = __esm(() => {
|
|
20746
19711
|
init_graphics();
|
|
20747
|
-
init_image_visual_layer();
|
|
20748
19712
|
init_fleet_stats();
|
|
20749
19713
|
});
|
|
20750
19714
|
|