@zenbu-labs/pixel 0.0.14 → 0.0.16
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/index.d.ts +2 -1
- package/dist/index.js +3 -1
- package/dist/react/devtools/controller.d.ts +2 -0
- package/dist/react/devtools/controller.js +13 -0
- package/dist/react/devtools/export-profile.js +15 -1
- package/dist/react/devtools/profiler.js +15 -0
- package/dist/react/devtools/stores.d.ts +4 -1
- package/dist/react/devtools/stores.js +2 -0
- package/dist/react/index.d.ts +19 -4
- package/dist/react/index.js +55 -3
- package/dist/react/native.d.ts +1 -1
- package/dist/react/styles.d.ts +1 -0
- package/dist/react/styles.js +1 -0
- package/dist/react/surface.js +3 -1
- package/dist/root.js +7 -0
- package/dist/scale.js +5 -5
- package/dist/terminal/terminals/ghostty.js +1 -1
- package/dist/web/frame-rate.d.ts +2 -0
- package/dist/web/frame-rate.js +25 -1
- package/dist/web/host.d.ts +1 -0
- package/dist/web/host.js +4 -0
- package/dist/webview.js +1 -0
- package/package.json +5 -5
package/dist/index.d.ts
CHANGED
|
@@ -11,7 +11,8 @@ export type { DevtoolsDock } from "./web/types";
|
|
|
11
11
|
export type { ZoomDirection } from "./web/zoom";
|
|
12
12
|
export type { TerminalTheme } from "./web/session";
|
|
13
13
|
export { QUIT_URL, defaultOpenWindow } from "./web/host";
|
|
14
|
-
export { Box, Text, Input, Image, MarkedText, Path, Markdown, appLog, useTerminalColors, setClipboard, setPointerShape, requestClipboardImage, highlight, diff, parseMarkdown, HIGHLIGHT_CAPTURES, Surface, SurfaceCapture, captureFilmstrip, encodeRecording, } from "./react";
|
|
14
|
+
export { Box, Text, Input, Image, MarkedText, Path, Markdown, appLog, useTerminalColors, setClipboard, setPointerShape, requestClipboardImage, highlight, diff, parseMarkdown, HIGHLIGHT_CAPTURES, Surface, SurfaceCapture, captureFilmstrip, encodeRecording, engineLogs, useStore, } from "./react";
|
|
15
|
+
export type { LogRow, LogBuffer } from "./react";
|
|
15
16
|
export type { BoxProps, TextProps, TextSpan, InputProps, InputGutter, ImageProps, ImageAdvancedProps, MarkedTextProps, MarkRef, PathProps, ShapeStroke, ClickEvent, DragEvent, EventMods, MouseMoveEvent, ScrollEvent, WheelEvent, PointerEvent, PastedImage, PasteSource, CaretInfo, ChangeInfo, ChangeSource, ContainerSelection, SelectionPart, NodeHandle, Color, Edges, InsetEdges, InsetValue, ScrollbarStyle, Style, EngineInfo, EngineKeyEvent, KeyMods, Rgba, TerminalColors, SurfaceFrame, SurfaceTexture, CaptureStats, CaptureFrameMeta, CaptureIndex, MarkdownProps, MarkdownTheme, MarkdownBlock, HighlightSpan, DiffRow, } from "./react";
|
|
16
17
|
export { makeTheme } from "./theme";
|
|
17
18
|
export type { Theme } from "./theme";
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.makeTheme = exports.encodeRecording = exports.captureFilmstrip = exports.SurfaceCapture = exports.Surface = exports.HIGHLIGHT_CAPTURES = exports.parseMarkdown = exports.diff = exports.highlight = exports.requestClipboardImage = exports.setPointerShape = exports.setClipboard = exports.useTerminalColors = exports.appLog = exports.Markdown = exports.Path = exports.MarkedText = exports.Image = exports.Input = exports.Text = exports.Box = exports.defaultOpenWindow = exports.QUIT_URL = exports.DevTools = exports.WebView = exports.listInstances = exports.findOwner = exports.createRoot = void 0;
|
|
3
|
+
exports.makeTheme = exports.useStore = exports.engineLogs = exports.encodeRecording = exports.captureFilmstrip = exports.SurfaceCapture = exports.Surface = exports.HIGHLIGHT_CAPTURES = exports.parseMarkdown = exports.diff = exports.highlight = exports.requestClipboardImage = exports.setPointerShape = exports.setClipboard = exports.useTerminalColors = exports.appLog = exports.Markdown = exports.Path = exports.MarkedText = exports.Image = exports.Input = exports.Text = exports.Box = exports.defaultOpenWindow = exports.QUIT_URL = exports.DevTools = exports.WebView = exports.listInstances = exports.findOwner = exports.createRoot = void 0;
|
|
4
4
|
/// <reference path="../electron/electron.d.ts" preserve="true" />
|
|
5
5
|
var root_1 = require("./root");
|
|
6
6
|
Object.defineProperty(exports, "createRoot", { enumerable: true, get: function () { return root_1.createRoot; } });
|
|
@@ -35,5 +35,7 @@ Object.defineProperty(exports, "Surface", { enumerable: true, get: function () {
|
|
|
35
35
|
Object.defineProperty(exports, "SurfaceCapture", { enumerable: true, get: function () { return react_1.SurfaceCapture; } });
|
|
36
36
|
Object.defineProperty(exports, "captureFilmstrip", { enumerable: true, get: function () { return react_1.captureFilmstrip; } });
|
|
37
37
|
Object.defineProperty(exports, "encodeRecording", { enumerable: true, get: function () { return react_1.encodeRecording; } });
|
|
38
|
+
Object.defineProperty(exports, "engineLogs", { enumerable: true, get: function () { return react_1.engineLogs; } });
|
|
39
|
+
Object.defineProperty(exports, "useStore", { enumerable: true, get: function () { return react_1.useStore; } });
|
|
38
40
|
var theme_1 = require("./theme");
|
|
39
41
|
Object.defineProperty(exports, "makeTheme", { enumerable: true, get: function () { return theme_1.makeTheme; } });
|
|
@@ -13,6 +13,8 @@ export declare function setHighlight(id: number | null, area?: HighlightArea): v
|
|
|
13
13
|
export declare function setPicking(on: boolean): void;
|
|
14
14
|
export declare function toggleExpanded(id: number): void;
|
|
15
15
|
export declare function setCpuThrottle(rate: number): void;
|
|
16
|
+
export declare function setMaxFps(fps: number): void;
|
|
17
|
+
export declare function setHighlightTransmits(on: boolean): void;
|
|
16
18
|
export declare function requestLayout(): void;
|
|
17
19
|
export declare function startRecording(): void;
|
|
18
20
|
export declare function stopRecording(): void;
|
|
@@ -13,6 +13,8 @@ exports.setHighlight = setHighlight;
|
|
|
13
13
|
exports.setPicking = setPicking;
|
|
14
14
|
exports.toggleExpanded = toggleExpanded;
|
|
15
15
|
exports.setCpuThrottle = setCpuThrottle;
|
|
16
|
+
exports.setMaxFps = setMaxFps;
|
|
17
|
+
exports.setHighlightTransmits = setHighlightTransmits;
|
|
16
18
|
exports.requestLayout = requestLayout;
|
|
17
19
|
exports.startRecording = startRecording;
|
|
18
20
|
exports.stopRecording = stopRecording;
|
|
@@ -55,11 +57,14 @@ function openDevtools(selectId) {
|
|
|
55
57
|
stores_1.devtoolsStore.update((s) => ({ ...s, open: true }));
|
|
56
58
|
if (selectId != null)
|
|
57
59
|
selectNode(selectId, true);
|
|
60
|
+
engineOp({ op: "setLogCapture", on: true });
|
|
58
61
|
engineOp({ op: "setSplit", fraction: exports.DEFAULT_SPLIT });
|
|
59
62
|
}
|
|
60
63
|
function closeDevtools() {
|
|
61
64
|
stores_1.devtoolsStore.update((s) => ({ ...s, open: false }));
|
|
62
65
|
setHighlight(null);
|
|
66
|
+
engineOp({ op: "setLogCapture", on: false });
|
|
67
|
+
stores_1.engineLogs.clear();
|
|
63
68
|
engineOp({ op: "setSplit", fraction: null });
|
|
64
69
|
}
|
|
65
70
|
function toggleDevtools() {
|
|
@@ -132,6 +137,14 @@ function setCpuThrottle(rate) {
|
|
|
132
137
|
stores_1.devtoolsStore.update((s) => ({ ...s, cpuRate: rate }));
|
|
133
138
|
engineOp({ op: "setCpuThrottle", rate });
|
|
134
139
|
}
|
|
140
|
+
function setMaxFps(fps) {
|
|
141
|
+
stores_1.devtoolsStore.update((s) => ({ ...s, maxFps: fps }));
|
|
142
|
+
engineOp({ op: "setRender", maxFps: fps });
|
|
143
|
+
}
|
|
144
|
+
function setHighlightTransmits(on) {
|
|
145
|
+
stores_1.devtoolsStore.update((s) => ({ ...s, highlightTransmits: on }));
|
|
146
|
+
engineOp({ op: "setRender", highlightTransmits: on });
|
|
147
|
+
}
|
|
135
148
|
function requestLayout() {
|
|
136
149
|
const b = (0, reconciler_config_1.devtoolsBridge)();
|
|
137
150
|
b.push(reconciler_config_1.APP_VIEW, { op: "queryLayout" });
|
|
@@ -84,7 +84,21 @@ const GLOSSARY = {
|
|
|
84
84
|
aggregates_note: "paint.* spans are per-frame aggregates laid out back-to-back under tree.paint: " +
|
|
85
85
|
"durations and counts are real, start times are not the true instants.",
|
|
86
86
|
counters: "Point samples: 'bytes' = escape-sequence bytes written per frame; 'paint.nodes' / " +
|
|
87
|
-
"'paint.glyphs' = nodes visited / glyphs drawn per paint."
|
|
87
|
+
"'paint.glyphs' = nodes visited / glyphs drawn per paint; 'present.patches' = damaged " +
|
|
88
|
+
"rects sent as separate images that frame, 'present.pixels' = pixels handed to the " +
|
|
89
|
+
"terminal (the whole frame when a full image went out), 'present.whole_frame' = a frame " +
|
|
90
|
+
"that fell back to one full image because too much changed or the patch pool was full. " +
|
|
91
|
+
"Per-stage pixel counts show amplification along the pipeline: 'surface.damage_px' = area " +
|
|
92
|
+
"of the dirty rects the browser reported, 'surface.changed_px' = area that actually changed " +
|
|
93
|
+
"after comparing, 'paint.px' = area repainted in the view, 'compose.px' = area copied into " +
|
|
94
|
+
"the frame, 'present.pixels' = area handed to the terminal. Each should be close to the one " +
|
|
95
|
+
"before it; a jump marks work done on pixels that did not change. 'present.compactions' " +
|
|
96
|
+
"= live patches folded into one image, re-sending their union, to free image ids or " +
|
|
97
|
+
"placements; 'present.absorbed' = a mostly hidden patch deleted as a new one grew over it; " +
|
|
98
|
+
"'present.tiles' = tiles outside the opaque zones re-sent because their pixels changed. " +
|
|
99
|
+
"'cpu.frame_thread_us' / 'cpu.frame_process_us' = CPU time the engine thread / the whole " +
|
|
100
|
+
"process burned during that frame (spans record wall time on one thread and miss worker " +
|
|
101
|
+
"threads and kernel time); 'cpu.convert_thread_us' = the same for one surface compare.",
|
|
88
102
|
cpuThrottle_note: "meta.cpuThrottle > 1 means the engine and JS threads were duty-cycle suspended to " +
|
|
89
103
|
"simulate a CPU that many times slower; durations are inflated accordingly. Throttle " +
|
|
90
104
|
"changes mid-recording appear as 'cpu throttle Nx' interactions.",
|
|
@@ -364,6 +364,21 @@ function ProfilerPanel(props) {
|
|
|
364
364
|
const rates = [1, 2, 4, 10];
|
|
365
365
|
const next = rates[(rates.indexOf(devtools.cpuRate) + 1) % rates.length];
|
|
366
366
|
(0, controller_1.setCpuThrottle)(next);
|
|
367
|
+
} }), (0, jsx_runtime_1.jsx)(ui_1.Button, { rem: rem, label: "outline sends", active: devtools.highlightTransmits, onClick: () => (0, controller_1.setHighlightTransmits)(!devtools.highlightTransmits) }), (0, jsx_runtime_1.jsx)(components_1.Text, { style: { color: theme_1.theme.faint, fontSize: rem * 0.66, wrap: false }, children: "fps" }), (0, jsx_runtime_1.jsx)(components_1.Input, { style: {
|
|
368
|
+
width: rem * 2.6,
|
|
369
|
+
height: rem * 1.3,
|
|
370
|
+
fontSize: rem * 0.7,
|
|
371
|
+
color: theme_1.theme.text,
|
|
372
|
+
font: theme_1.MONO,
|
|
373
|
+
wrap: false,
|
|
374
|
+
padding: { left: rem * 0.3, right: rem * 0.3 },
|
|
375
|
+
border: { width: 1, color: theme_1.theme.border },
|
|
376
|
+
cornerRadius: rem * 0.2,
|
|
377
|
+
}, defaultValue: devtools.maxFps === 0 ? "off" : String(devtools.maxFps), onSubmit: (text) => {
|
|
378
|
+
const value = text.trim().toLowerCase();
|
|
379
|
+
const fps = value === "off" || value === "0" ? 0 : Number(value);
|
|
380
|
+
if (Number.isFinite(fps) && fps >= 0)
|
|
381
|
+
(0, controller_1.setMaxFps)(fps);
|
|
367
382
|
} }), session && !exportedTo && (0, jsx_runtime_1.jsx)(Summary, { session: session, rem: rem }), exportedTo && ((0, jsx_runtime_1.jsx)(components_1.Text, { style: { color: theme_1.theme.ok, fontSize: rem * 0.66, font: theme_1.MONO, wrap: false }, children: exportedTo })), (0, jsx_runtime_1.jsx)(components_1.Box, { style: { flexGrow: 1 } }), (0, jsx_runtime_1.jsx)(components_1.Text, { style: { color: theme_1.theme.faint, fontSize: rem * 0.62, wrap: false }, children: "f=fit" })] }), (0, jsx_runtime_1.jsx)(ui_1.Divider, {}), state.recording ? ((0, jsx_runtime_1.jsx)(ui_1.Empty, { rem: rem, text: "Recording\u2026" })) : state.pendingStop ? ((0, jsx_runtime_1.jsx)(ui_1.Empty, { rem: rem, text: "Waiting for profile\u2026" })) : !session || !viewport ? ((0, jsx_runtime_1.jsx)(ui_1.Empty, { rem: rem, text: "" })) : ((0, jsx_runtime_1.jsxs)(components_1.Box, { style: {
|
|
368
383
|
flexDirection: "column",
|
|
369
384
|
flexGrow: 1,
|
|
@@ -80,13 +80,16 @@ export interface ProfilerState {
|
|
|
80
80
|
export declare const profilerStore: import("./store").Store<ProfilerState>;
|
|
81
81
|
export declare const pendingSpans: TimeSpan[];
|
|
82
82
|
export declare function recordSpan(span: TimeSpan): void;
|
|
83
|
+
export type DevtoolsTab = "elements" | "console" | "profiler";
|
|
83
84
|
export interface DevtoolsState {
|
|
84
85
|
open: boolean;
|
|
85
|
-
tab:
|
|
86
|
+
tab: DevtoolsTab;
|
|
86
87
|
width: number;
|
|
87
88
|
height: number;
|
|
88
89
|
basePx: number;
|
|
89
90
|
cpuRate: number;
|
|
91
|
+
highlightTransmits: boolean;
|
|
92
|
+
maxFps: number;
|
|
90
93
|
background: Rgba | null;
|
|
91
94
|
}
|
|
92
95
|
export declare const devtoolsStore: import("./store").Store<DevtoolsState>;
|
package/dist/react/index.d.ts
CHANGED
|
@@ -4,14 +4,16 @@ import type { EngineInfo, HostOptions, TerminalColors } from "./native";
|
|
|
4
4
|
import { Surface } from "./surface";
|
|
5
5
|
import { closeDevtools, engineOp, openDevtools, requestLayout, toggleDevtools } from "./devtools/controller";
|
|
6
6
|
import type { Rgba } from "./native";
|
|
7
|
-
import { inspectorStore, LayoutSnapshot } from "./devtools/stores";
|
|
7
|
+
import { DevtoolsTab, inspectorStore, LayoutSnapshot } from "./devtools/stores";
|
|
8
8
|
import type { LogLevel } from "./devtools/store";
|
|
9
9
|
declare function appLog(level: LogLevel, target: string, text: string): void;
|
|
10
10
|
export { Box, Text, Input, Image, MarkedText, Path, } from "./components";
|
|
11
11
|
export type { NodeHandle } from "./components";
|
|
12
12
|
export { appLog };
|
|
13
|
-
export { layoutStore, profilerStore } from "./devtools/stores";
|
|
14
|
-
export
|
|
13
|
+
export { layoutStore, profilerStore, engineLogs } from "./devtools/stores";
|
|
14
|
+
export { useStore } from "./devtools/store";
|
|
15
|
+
export type { LogRow, LogBuffer } from "./devtools/store";
|
|
16
|
+
export type { DevtoolsTab, LayoutSnapshot, ProfileSession } from "./devtools/stores";
|
|
15
17
|
export type { BoxProps, TextProps, TextSpan, InputGutter, InputProps, MarkRef, PasteSource, PastedImage, CaretInfo, ChangeInfo, ChangeSource, ImageProps, ImageAdvancedProps, MarkedTextProps, ClickEvent, ContainerSelection, DragEvent, EventMods, MouseMoveEvent, ScrollEvent, SelectionPart, WheelEvent, PointerEvent, ShapeStroke, PathProps, } from "./reconciler-config";
|
|
16
18
|
export type { Color, Edges, InsetEdges, InsetValue, ScrollbarStyle, Style } from "./styles";
|
|
17
19
|
export type { DiffEmphasis, DiffRow, EngineInfo, HighlightSpan, HostOptions, MarkdownBlock, MarkdownCell, MarkdownRow, MarkdownSpan, Rgba, SurfaceShm, TerminalColors, } from "./native";
|
|
@@ -51,6 +53,7 @@ export interface RootOptions {
|
|
|
51
53
|
}) => void;
|
|
52
54
|
onPaste?: (text: string) => void;
|
|
53
55
|
onFocus?: (focused: boolean) => void;
|
|
56
|
+
onVisible?: (visible: boolean) => void;
|
|
54
57
|
onPasteImage?: (image: PastedImage) => void;
|
|
55
58
|
onEngineExit?: (error: string | null) => void;
|
|
56
59
|
onResize?: (size: {
|
|
@@ -73,6 +76,13 @@ export interface RootOptions {
|
|
|
73
76
|
wrapper?: "tmux";
|
|
74
77
|
sessionEnv?: NodeJS.ProcessEnv;
|
|
75
78
|
}
|
|
79
|
+
export interface RenderSettings {
|
|
80
|
+
maxFps?: number;
|
|
81
|
+
frameBudgetMbps?: number;
|
|
82
|
+
highlightTransmits?: boolean;
|
|
83
|
+
compareFrames?: boolean;
|
|
84
|
+
frameEvents?: boolean;
|
|
85
|
+
}
|
|
76
86
|
export interface PixelRoot {
|
|
77
87
|
info: EngineInfo;
|
|
78
88
|
sharedTextures: boolean;
|
|
@@ -82,8 +92,13 @@ export interface PixelRoot {
|
|
|
82
92
|
createSurface(): Surface;
|
|
83
93
|
surfaceStats(): SurfaceStats;
|
|
84
94
|
stop(): void;
|
|
85
|
-
openDevtools(): void;
|
|
95
|
+
openDevtools(tab?: DevtoolsTab): void;
|
|
86
96
|
closeDevtools(): void;
|
|
97
|
+
startProfile(): void;
|
|
98
|
+
stopProfile(): Promise<string | null>;
|
|
99
|
+
setRender(settings: RenderSettings): void;
|
|
100
|
+
setLogFile(path: string | null): void;
|
|
101
|
+
highlightTransmits(): boolean;
|
|
87
102
|
nudgeResize(): void;
|
|
88
103
|
queryLayout(): void;
|
|
89
104
|
setPointerShape(shape: string): void;
|
package/dist/react/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.inspectorStore = exports.engineOp = exports.requestLayout = exports.toggleDevtools = exports.closeDevtools = exports.openDevtools = exports.Markdown = exports.SurfaceCapture = exports.Surface = exports.useTerminalColors = exports.parseMarkdown = exports.highlight = exports.encodeRecording = exports.diff = exports.captureFilmstrip = exports.HIGHLIGHT_CAPTURES = exports.profilerStore = exports.layoutStore = exports.Path = exports.MarkedText = exports.Image = exports.Input = exports.Text = exports.Box = void 0;
|
|
3
|
+
exports.inspectorStore = exports.engineOp = exports.requestLayout = exports.toggleDevtools = exports.closeDevtools = exports.openDevtools = exports.Markdown = exports.SurfaceCapture = exports.Surface = exports.useTerminalColors = exports.parseMarkdown = exports.highlight = exports.encodeRecording = exports.diff = exports.captureFilmstrip = exports.HIGHLIGHT_CAPTURES = exports.useStore = exports.engineLogs = exports.profilerStore = exports.layoutStore = exports.Path = exports.MarkedText = exports.Image = exports.Input = exports.Text = exports.Box = void 0;
|
|
4
4
|
exports.appLog = appLog;
|
|
5
5
|
exports.setKeyCapture = setKeyCapture;
|
|
6
6
|
exports.setPointerShape = setPointerShape;
|
|
@@ -11,6 +11,7 @@ const react_1 = require("react");
|
|
|
11
11
|
const constants_1 = require("react-reconciler/constants");
|
|
12
12
|
const reconciler_config_1 = require("./reconciler-config");
|
|
13
13
|
const surface_1 = require("./surface");
|
|
14
|
+
const frame_rate_1 = require("../web/frame-rate");
|
|
14
15
|
const app_1 = require("./devtools/app");
|
|
15
16
|
const console_capture_1 = require("./devtools/console-capture");
|
|
16
17
|
const controller_1 = require("./devtools/controller");
|
|
@@ -38,6 +39,9 @@ Object.defineProperty(exports, "Path", { enumerable: true, get: function () { re
|
|
|
38
39
|
var stores_2 = require("./devtools/stores");
|
|
39
40
|
Object.defineProperty(exports, "layoutStore", { enumerable: true, get: function () { return stores_2.layoutStore; } });
|
|
40
41
|
Object.defineProperty(exports, "profilerStore", { enumerable: true, get: function () { return stores_2.profilerStore; } });
|
|
42
|
+
Object.defineProperty(exports, "engineLogs", { enumerable: true, get: function () { return stores_2.engineLogs; } });
|
|
43
|
+
var store_1 = require("./devtools/store");
|
|
44
|
+
Object.defineProperty(exports, "useStore", { enumerable: true, get: function () { return store_1.useStore; } });
|
|
41
45
|
var native_1 = require("./native");
|
|
42
46
|
Object.defineProperty(exports, "HIGHLIGHT_CAPTURES", { enumerable: true, get: function () { return native_1.HIGHLIGHT_CAPTURES; } });
|
|
43
47
|
Object.defineProperty(exports, "captureFilmstrip", { enumerable: true, get: function () { return native_1.captureFilmstrip; } });
|
|
@@ -129,7 +133,7 @@ function createRoot(options = {}) {
|
|
|
129
133
|
stores_1.engineLogs.push("error", "react", String(error));
|
|
130
134
|
}, null);
|
|
131
135
|
if (devtoolsEnabled)
|
|
132
|
-
|
|
136
|
+
(0, console_capture_1.installConsoleCapture)();
|
|
133
137
|
const fontIds = new Map();
|
|
134
138
|
const fontRequests = new Map();
|
|
135
139
|
const retargets = [];
|
|
@@ -278,6 +282,8 @@ function createRoot(options = {}) {
|
|
|
278
282
|
if (view === reconciler_config_1.APP_VIEW) {
|
|
279
283
|
info.width = size.width;
|
|
280
284
|
info.height = size.height;
|
|
285
|
+
info.cellWidth = event.cellWidth;
|
|
286
|
+
info.cellHeight = event.cellHeight;
|
|
281
287
|
info.basePx = size.basePx;
|
|
282
288
|
options.onResize?.(size);
|
|
283
289
|
}
|
|
@@ -313,6 +319,9 @@ function createRoot(options = {}) {
|
|
|
313
319
|
case "focus":
|
|
314
320
|
options.onFocus?.(!!event.focused);
|
|
315
321
|
break;
|
|
322
|
+
case "visible":
|
|
323
|
+
options.onVisible?.(!!event.visible);
|
|
324
|
+
break;
|
|
316
325
|
case "devtools":
|
|
317
326
|
enableDevtools();
|
|
318
327
|
(0, controller_1.attachDevtools)(bridge);
|
|
@@ -486,11 +495,54 @@ function createRoot(options = {}) {
|
|
|
486
495
|
process.stdout.off("resize", forwardResize);
|
|
487
496
|
process.off("exit", restore);
|
|
488
497
|
},
|
|
489
|
-
openDevtools() {
|
|
498
|
+
openDevtools(tab) {
|
|
490
499
|
enableDevtools();
|
|
491
500
|
(0, controller_1.attachDevtools)(bridge);
|
|
501
|
+
if (tab)
|
|
502
|
+
stores_1.devtoolsStore.update((s) => ({ ...s, tab }));
|
|
492
503
|
(0, controller_1.openDevtools)();
|
|
493
504
|
},
|
|
505
|
+
startProfile() {
|
|
506
|
+
enableDevtools();
|
|
507
|
+
(0, controller_1.attachDevtools)(bridge);
|
|
508
|
+
(0, controller_1.startRecording)();
|
|
509
|
+
},
|
|
510
|
+
stopProfile() {
|
|
511
|
+
return new Promise((resolve) => {
|
|
512
|
+
const now = stores_1.profilerStore.get();
|
|
513
|
+
if (!now.recording && !now.pendingStop) {
|
|
514
|
+
resolve((0, export_profile_1.exportProfile)());
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
const unsubscribe = stores_1.profilerStore.subscribe(() => {
|
|
518
|
+
const state = stores_1.profilerStore.get();
|
|
519
|
+
if (state.recording || state.pendingStop)
|
|
520
|
+
return;
|
|
521
|
+
unsubscribe();
|
|
522
|
+
resolve((0, export_profile_1.exportProfile)());
|
|
523
|
+
});
|
|
524
|
+
(0, controller_1.stopRecording)();
|
|
525
|
+
});
|
|
526
|
+
},
|
|
527
|
+
setRender(settings) {
|
|
528
|
+
// The browser should not bother producing frames the engine would only drop.
|
|
529
|
+
if (settings.maxFps !== undefined)
|
|
530
|
+
(0, frame_rate_1.requestFrameRate)(settings.maxFps);
|
|
531
|
+
stores_1.devtoolsStore.update((s) => ({
|
|
532
|
+
...s,
|
|
533
|
+
maxFps: settings.maxFps ?? s.maxFps,
|
|
534
|
+
highlightTransmits: settings.highlightTransmits ?? s.highlightTransmits,
|
|
535
|
+
}));
|
|
536
|
+
bridge.push(reconciler_config_1.APP_VIEW, { op: "setRender", ...settings });
|
|
537
|
+
bridge.flush();
|
|
538
|
+
},
|
|
539
|
+
setLogFile(path) {
|
|
540
|
+
bridge.push(reconciler_config_1.APP_VIEW, { op: "setLogFile", path });
|
|
541
|
+
bridge.flush();
|
|
542
|
+
},
|
|
543
|
+
highlightTransmits() {
|
|
544
|
+
return stores_1.devtoolsStore.get().highlightTransmits;
|
|
545
|
+
},
|
|
494
546
|
closeDevtools() {
|
|
495
547
|
if ((0, reconciler_config_1.devtoolsBridge)() === bridge)
|
|
496
548
|
(0, controller_1.closeDevtools)();
|
package/dist/react/native.d.ts
CHANGED
|
@@ -15,7 +15,7 @@ export interface NativeEngine {
|
|
|
15
15
|
info(): string;
|
|
16
16
|
applyOps(ops: string): void;
|
|
17
17
|
updateSurface(id: number, bgra: Buffer, width: number, height: number, damage?: DamageRect): void;
|
|
18
|
-
updateSurfaceTexture?(id: number, handle:
|
|
18
|
+
updateSurfaceTexture?(id: number, handle: number, damageX: number, damageY: number, damageWidth: number, damageHeight: number): void;
|
|
19
19
|
updateSurfaceShm?(id: number, shm: SurfaceShm, damage?: DamageRect, released?: (...args: unknown[]) => void): void;
|
|
20
20
|
removeSurface(id: number): void;
|
|
21
21
|
surfaceStats(): string;
|
package/dist/react/styles.d.ts
CHANGED
package/dist/react/styles.js
CHANGED
|
@@ -70,6 +70,7 @@ function serializeStyle(style) {
|
|
|
70
70
|
wrap: style.wrap,
|
|
71
71
|
ellipsis: style.ellipsis,
|
|
72
72
|
selectable: style.selectable,
|
|
73
|
+
opaque: style.opaque,
|
|
73
74
|
selectionColor: parseColor(style.selectionColor),
|
|
74
75
|
selectionMode: style.selectionMode,
|
|
75
76
|
scrollbar: style.scrollbar && {
|
package/dist/react/surface.js
CHANGED
|
@@ -20,7 +20,9 @@ class Surface {
|
|
|
20
20
|
const submit = this.engine.updateSurfaceTexture;
|
|
21
21
|
if (!submit)
|
|
22
22
|
throw new Error("IOSurface frames are not supported on this platform");
|
|
23
|
-
|
|
23
|
+
const address = frame.ioSurface.readUIntLE(0, 6);
|
|
24
|
+
const d = frame.damage;
|
|
25
|
+
submit.call(this.engine, this.id, address, d?.x ?? 0, d?.y ?? 0, d?.width ?? 0, d?.height ?? 0);
|
|
24
26
|
}
|
|
25
27
|
else if ("shm" in frame) {
|
|
26
28
|
const submit = this.engine.updateSurfaceShm;
|
package/dist/root.js
CHANGED
|
@@ -164,6 +164,7 @@ function createRoot(options = {}) {
|
|
|
164
164
|
options.onFocus?.(focused);
|
|
165
165
|
registry?.handleTerminalFocus(focused);
|
|
166
166
|
},
|
|
167
|
+
onVisible: (visible) => options.onVisible?.(visible),
|
|
167
168
|
onResize: (size) => {
|
|
168
169
|
const ratio = cellZoom.ratio(engineRoot.info);
|
|
169
170
|
if (registry) {
|
|
@@ -337,6 +338,12 @@ function createRoot(options = {}) {
|
|
|
337
338
|
shutdown(code);
|
|
338
339
|
},
|
|
339
340
|
};
|
|
341
|
+
try {
|
|
342
|
+
const hz = electron_1.screen.getPrimaryDisplay().displayFrequency;
|
|
343
|
+
if (hz > 0)
|
|
344
|
+
engineRoot.setRender({ maxFps: hz });
|
|
345
|
+
}
|
|
346
|
+
catch { }
|
|
340
347
|
liveRoots.add(root);
|
|
341
348
|
return root;
|
|
342
349
|
}
|
package/dist/scale.js
CHANGED
|
@@ -14,16 +14,16 @@ function hostDisplayScale(terminal, env) {
|
|
|
14
14
|
class CellZoomFollower {
|
|
15
15
|
last = null;
|
|
16
16
|
ratio(info) {
|
|
17
|
-
const { height, basePx } = info;
|
|
17
|
+
const { height, basePx, cellHeight } = info;
|
|
18
|
+
const rows = cellHeight > 0 ? Math.round(height / cellHeight) : 0;
|
|
18
19
|
const prev = this.last;
|
|
19
|
-
this.last = {
|
|
20
|
-
if (!prev || !prev.basePx || !prev.
|
|
20
|
+
this.last = { rows, basePx };
|
|
21
|
+
if (!prev || !prev.basePx || !prev.rows || !rows)
|
|
21
22
|
return null;
|
|
22
23
|
const ratio = basePx / prev.basePx;
|
|
23
24
|
if (!Number.isFinite(ratio) || ratio <= 0 || Math.abs(ratio - 1) < 0.01)
|
|
24
25
|
return null;
|
|
25
|
-
|
|
26
|
-
if (Math.abs(paneRatio - ratio) < 0.04 * ratio)
|
|
26
|
+
if (rows === prev.rows)
|
|
27
27
|
return null;
|
|
28
28
|
return ratio;
|
|
29
29
|
}
|
|
@@ -17,7 +17,7 @@ const DIRECTION_CODES = {
|
|
|
17
17
|
down: "GSdn",
|
|
18
18
|
up: "GSup",
|
|
19
19
|
};
|
|
20
|
-
const GHOSTTY_BINARY =
|
|
20
|
+
const GHOSTTY_BINARY = /\.app\/Contents\/MacOS\/ghostty(\s|$)/;
|
|
21
21
|
function ghosttyAbove(start, processes) {
|
|
22
22
|
for (let pid = start, hops = 0; hops < 64 && processes.has(pid); hops++) {
|
|
23
23
|
const { parent, command } = processes.get(pid);
|
package/dist/web/frame-rate.d.ts
CHANGED
package/dist/web/frame-rate.js
CHANGED
|
@@ -1,11 +1,35 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.requestFrameRate = requestFrameRate;
|
|
4
|
+
exports.onFrameRateChange = onFrameRateChange;
|
|
3
5
|
exports.frameRate = frameRate;
|
|
4
6
|
const electron_1 = require("electron");
|
|
7
|
+
let requested = 0;
|
|
8
|
+
const listeners = new Set();
|
|
9
|
+
function clamp(fps) {
|
|
10
|
+
return Math.max(1, Math.min(240, Math.round(fps)));
|
|
11
|
+
}
|
|
12
|
+
function requestFrameRate(fps) {
|
|
13
|
+
const next = Number.isFinite(fps) && fps > 0 ? clamp(fps) : 0;
|
|
14
|
+
if (next === requested)
|
|
15
|
+
return;
|
|
16
|
+
requested = next;
|
|
17
|
+
for (const listener of listeners)
|
|
18
|
+
listener();
|
|
19
|
+
}
|
|
20
|
+
function onFrameRateChange(listener) {
|
|
21
|
+
listeners.add(listener);
|
|
22
|
+
return () => {
|
|
23
|
+
listeners.delete(listener);
|
|
24
|
+
};
|
|
25
|
+
}
|
|
5
26
|
function frameRate() {
|
|
6
27
|
const configured = Number(process.env.PIXEL_FPS);
|
|
7
28
|
if (Number.isFinite(configured) && configured > 0) {
|
|
8
|
-
return
|
|
29
|
+
return clamp(configured);
|
|
30
|
+
}
|
|
31
|
+
if (requested > 0) {
|
|
32
|
+
return requested;
|
|
9
33
|
}
|
|
10
34
|
const fastest = Math.max(0, ...electron_1.screen.getAllDisplays().map((display) => display.displayFrequency));
|
|
11
35
|
return fastest > 0 ? Math.min(240, Math.round(fastest)) : 60;
|
package/dist/web/host.d.ts
CHANGED
package/dist/web/host.js
CHANGED
|
@@ -62,6 +62,7 @@ class PageHost {
|
|
|
62
62
|
layout;
|
|
63
63
|
state;
|
|
64
64
|
stopped = false;
|
|
65
|
+
stopWatchingFrameRate;
|
|
65
66
|
contentFocused = false;
|
|
66
67
|
input;
|
|
67
68
|
clipboardRead;
|
|
@@ -133,6 +134,7 @@ class PageHost {
|
|
|
133
134
|
if (this.quitLink(url))
|
|
134
135
|
event.preventDefault();
|
|
135
136
|
});
|
|
137
|
+
this.stopWatchingFrameRate = (0, frame_rate_1.onFrameRateChange)(this.onDisplayChange);
|
|
136
138
|
electron_1.screen.on("display-added", this.onDisplayChange);
|
|
137
139
|
electron_1.screen.on("display-removed", this.onDisplayChange);
|
|
138
140
|
electron_1.screen.on("display-metrics-changed", this.onDisplayChange);
|
|
@@ -424,6 +426,8 @@ class PageHost {
|
|
|
424
426
|
for (const popup of [...this.popups])
|
|
425
427
|
popup.close();
|
|
426
428
|
this.devtools?.close();
|
|
429
|
+
this.stopWatchingFrameRate?.();
|
|
430
|
+
this.stopWatchingFrameRate = undefined;
|
|
427
431
|
electron_1.screen.off("display-added", this.onDisplayChange);
|
|
428
432
|
electron_1.screen.off("display-removed", this.onDisplayChange);
|
|
429
433
|
electron_1.screen.off("display-metrics-changed", this.onDisplayChange);
|
package/dist/webview.js
CHANGED
|
@@ -431,6 +431,7 @@ exports.WebView = (0, react_1.forwardRef)(function WebView(props, ref) {
|
|
|
431
431
|
height: page.height,
|
|
432
432
|
cornerRadius: props.style?.cornerRadius,
|
|
433
433
|
background: theme.bg,
|
|
434
|
+
opaque: !props.browserWindowOptions?.transparent,
|
|
434
435
|
}, onPointer: (event) => {
|
|
435
436
|
if (menuRef.current) {
|
|
436
437
|
if (event.kind === "down")
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zenbu-labs/pixel",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.16",
|
|
4
4
|
"description": "[placeholder copy: Electron apps that render into your terminal pane]",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -58,10 +58,10 @@
|
|
|
58
58
|
"react": "^18.3.1"
|
|
59
59
|
},
|
|
60
60
|
"optionalDependencies": {
|
|
61
|
-
"@zenbu-labs/pixel-native-darwin-arm64": "0.0.
|
|
62
|
-
"@zenbu-labs/pixel-native-darwin-x64": "0.0.
|
|
63
|
-
"@zenbu-labs/pixel-native-linux-arm64": "0.0.
|
|
64
|
-
"@zenbu-labs/pixel-native-linux-x64": "0.0.
|
|
61
|
+
"@zenbu-labs/pixel-native-darwin-arm64": "0.0.16",
|
|
62
|
+
"@zenbu-labs/pixel-native-darwin-x64": "0.0.16",
|
|
63
|
+
"@zenbu-labs/pixel-native-linux-arm64": "0.0.16",
|
|
64
|
+
"@zenbu-labs/pixel-native-linux-x64": "0.0.16"
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
67
67
|
"@types/node": "^22.0.0",
|