Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
4400b28
Add background preview capture and picture-in-picture support
juliusmarminge Jul 23, 2026
82601c4
Merge origin/main into background preview automation
juliusmarminge Jul 23, 2026
43c84dc
Fix preview lifecycle review findings
juliusmarminge Jul 23, 2026
6678c48
fix(web): serialize desktop tab lifecycle
juliusmarminge Jul 23, 2026
3a37abc
fix(desktop): make PiP initialization cancellable
juliusmarminge Jul 23, 2026
12d14b5
fix(desktop): coordinate PiP session readiness
juliusmarminge Jul 23, 2026
235155d
fix(desktop): publish PiP readiness atomically
juliusmarminge Jul 23, 2026
06ad094
Merge origin/main into background preview automation
juliusmarminge Jul 23, 2026
43f1bc6
fix(preview): harden capture lifecycle
juliusmarminge Jul 23, 2026
65dbe94
fix(recording): lock dimensions before encoding
juliusmarminge Jul 23, 2026
7b046af
fix(recording): require stable startup frames
juliusmarminge Jul 24, 2026
b792005
Merge origin/main into background preview automation
juliusmarminge Jul 24, 2026
117d097
feat(preview): add thread-scoped floating browser
juliusmarminge Jul 24, 2026
c102de8
Merge origin/main into background preview automation
juliusmarminge Jul 24, 2026
5029e1d
fix(preview): harden floating preview recovery
juliusmarminge Jul 24, 2026
3505d31
fix(preview): harden capture and tab lifecycle races
juliusmarminge Jul 24, 2026
a272ca9
fix(preview): serialize teardown ownership
juliusmarminge Jul 24, 2026
606bf3d
fix(preview): isolate tab lifecycle generations
juliusmarminge Jul 24, 2026
d43a965
fix(auth): isolate loopback server sessions
juliusmarminge Jul 24, 2026
51ac943
test(auth): use configured session cookie
juliusmarminge Jul 24, 2026
9bf0e07
fix(auth): isolate wildcard dev sessions
juliusmarminge Jul 24, 2026
a9731c1
fix(preview): preserve viewport in resizable PiP
juliusmarminge Jul 24, 2026
8ad8ea1
Merge remote-tracking branch 'origin/main' into t3code/background-pre…
juliusmarminge Jul 24, 2026
3ff68d5
fix(preview): harden background lifecycle
juliusmarminge Jul 24, 2026
83703e7
fix(preview): close remaining capture races
juliusmarminge Jul 24, 2026
3435b33
fix(preview): compact and scale PiP surfaces
juliusmarminge Jul 24, 2026
75f8378
fix(preview): reset native PiP aspect lock
juliusmarminge Jul 24, 2026
3f818cc
fix(preview): open inline player by default
juliusmarminge Jul 24, 2026
ac1bf91
fix(preview): preserve viewport in inline player
juliusmarminge Jul 24, 2026
a691655
fix(preview): clear fitted surface state
juliusmarminge Jul 24, 2026
bfc1e68
Merge origin/main into background preview automation
juliusmarminge Jul 27, 2026
00462f4
fix(preview): harden capture and PiP races
juliusmarminge Jul 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/desktop/src/electron/ElectronWindow.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ describe("ElectronWindow", () => {
webPreferences: {
preload: "/tmp/preload.js",
partition: "persist:t3code-preview-test",
backgroundThrottling: null,
sandbox: true,
contextIsolation: true,
nodeIntegration: false,
Expand Down
2 changes: 2 additions & 0 deletions apps/desktop/src/electron/ElectronWindow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const ElectronWindowCreateOptions = Schema.Struct({
webPreferences: Schema.Struct({
preload: Schema.NullOr(Schema.String),
partition: Schema.NullOr(Schema.String),
backgroundThrottling: Schema.NullOr(Schema.Boolean),
sandbox: Schema.NullOr(Schema.Boolean),
contextIsolation: Schema.NullOr(Schema.Boolean),
nodeIntegration: Schema.NullOr(Schema.Boolean),
Expand Down Expand Up @@ -179,6 +180,7 @@ export const make = Effect.gen(function* () {
webPreferences: {
preload: webPreferences?.preload ?? null,
partition: webPreferences?.partition ?? null,
backgroundThrottling: webPreferences?.backgroundThrottling ?? null,
sandbox: webPreferences?.sandbox ?? null,
contextIsolation: webPreferences?.contextIsolation ?? null,
nodeIntegration: webPreferences?.nodeIntegration ?? null,
Expand Down
3 changes: 3 additions & 0 deletions apps/desktop/src/ipc/channels.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ export const PREVIEW_CANCEL_PICK_ELEMENT_CHANNEL = "desktop:preview-cancel-pick-
export const PREVIEW_CAPTURE_SCREENSHOT_CHANNEL = "desktop:preview-capture-screenshot";
export const PREVIEW_REVEAL_ARTIFACT_CHANNEL = "desktop:preview-reveal-artifact";
export const PREVIEW_COPY_ARTIFACT_CHANNEL = "desktop:preview-copy-artifact";
export const PREVIEW_PICTURE_IN_PICTURE_OPEN_CHANNEL = "desktop:preview-pip-open";
export const PREVIEW_PICTURE_IN_PICTURE_CLOSE_CHANNEL = "desktop:preview-pip-close";
export const PREVIEW_PICTURE_IN_PICTURE_FRAME_CHANNEL = "desktop:preview-pip-frame";
export const PREVIEW_AUTOMATION_STATUS_CHANNEL = "desktop:preview-automation-status";
export const PREVIEW_AUTOMATION_SNAPSHOT_CHANNEL = "desktop:preview-automation-snapshot";
export const PREVIEW_AUTOMATION_CLICK_CHANNEL = "desktop:preview-automation-click";
Expand Down
12 changes: 12 additions & 0 deletions apps/desktop/src/ipc/methods/preview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,16 @@ export const stopRecording = tabMethod(
"desktop.ipc.preview.stopRecording",
(manager, tabId) => manager.stopRecording(tabId),
);
export const openPictureInPicture = tabMethod(
IpcChannels.PREVIEW_PICTURE_IN_PICTURE_OPEN_CHANNEL,
"desktop.ipc.preview.openPictureInPicture",
(manager, tabId) => manager.openPictureInPicture(tabId),
);
export const closePictureInPicture = tabMethod(
IpcChannels.PREVIEW_PICTURE_IN_PICTURE_CLOSE_CHANNEL,
"desktop.ipc.preview.closePictureInPicture",
(manager, tabId) => manager.closePictureInPicture(tabId),
);

export const clearCookies = DesktopIpc.makeIpcMethod({
channel: IpcChannels.PREVIEW_CLEAR_COOKIES_CHANNEL,
Expand Down Expand Up @@ -367,6 +377,8 @@ export const methods = [
captureScreenshot,
revealArtifact,
copyArtifactToClipboard,
openPictureInPicture,
closePictureInPicture,
automationStatus,
automationSnapshot,
automationClick,
Expand Down
6 changes: 6 additions & 0 deletions apps/desktop/src/preload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,12 @@ contextBridge.exposeInMainWorld("desktopBridge", {
ipcRenderer.invoke(IpcChannels.PREVIEW_REVEAL_ARTIFACT_CHANNEL, { path }),
copyArtifactToClipboard: (path) =>
ipcRenderer.invoke(IpcChannels.PREVIEW_COPY_ARTIFACT_CHANNEL, { path }),
pictureInPicture: {
open: (tabId) =>
ipcRenderer.invoke(IpcChannels.PREVIEW_PICTURE_IN_PICTURE_OPEN_CHANNEL, { tabId }),
close: (tabId) =>
ipcRenderer.invoke(IpcChannels.PREVIEW_PICTURE_IN_PICTURE_CLOSE_CHANNEL, { tabId }),
},
recording: {
startScreencast: (tabId) =>
ipcRenderer.invoke(IpcChannels.PREVIEW_RECORDING_START_CHANNEL, { tabId }),
Expand Down
17 changes: 17 additions & 0 deletions apps/desktop/src/preview-pip-preload.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// @effect-diagnostics globalDate:off - This isolated Electron preload does not run inside an Effect runtime.
import type { DesktopPreviewRecordingFrame } from "@t3tools/contracts";
import { contextBridge, ipcRenderer } from "electron";

import { PREVIEW_PICTURE_IN_PICTURE_FRAME_CHANNEL } from "./ipc/channels.ts";

contextBridge.exposeInMainWorld("previewPictureInPicture", {
onFrame: (listener: (frame: DesktopPreviewRecordingFrame) => void) => {
const wrappedListener = (_event: Electron.IpcRendererEvent, frame: unknown) => {
if (typeof frame !== "object" || frame === null) return;
listener(frame as DesktopPreviewRecordingFrame);
};
ipcRenderer.on(PREVIEW_PICTURE_IN_PICTURE_FRAME_CHANNEL, wrappedListener);
return () =>
ipcRenderer.removeListener(PREVIEW_PICTURE_IN_PICTURE_FRAME_CHANNEL, wrappedListener);
},
});
Loading
Loading