Skip to content

Commit 7cda5e3

Browse files
sebavanCopilot
andcommitted
fix: captureWorker uses direct postMessage for full-frame capture
The bridge.triggerCapture() path only captured 1 command (viewport) due to a deep interaction between the main-thread Spector spy chain and Worker execution contexts. Fixed captureWorker() to bypass the bridge and send spector:trigger-capture directly to the Worker via worker.postMessage(), with a one-shot message listener for the capture result. This is the same proven approach used by the extension's contentScript.js capture handler. The embedded UI capture menu now also gets full-frame captures (6 commands) when clicking the red capture button on a Worker canvas. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent a4bca89 commit 7cda5e3

4 files changed

Lines changed: 30 additions & 12 deletions

File tree

dist/spector.bundle.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

extensions/spector.bundle.func.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

extensions/spector.bundle.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/spector.ts

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -487,22 +487,40 @@ export class Spector {
487487

488488
/**
489489
* Capture a frame from a Worker's WebGL context.
490-
* @param worker The Worker to capture from
491-
* @param commandCount Number of commands to capture (0 = one frame)
492-
* @param quickCapture Skip visual state capture
493-
* @param fullCapture Full resolution visual state
490+
* Uses direct postMessage to bypass the main-thread spy chain,
491+
* which ensures a full frame is captured.
494492
*/
495493
public captureWorker(
496494
worker: Worker,
497495
commandCount: number = 0,
498496
quickCapture: boolean = false,
499497
fullCapture: boolean = false,
500498
): void {
501-
let bridge = this.workerBridges.get(worker);
502-
if (!bridge) {
503-
bridge = this.spyWorker(worker);
504-
}
505-
bridge.triggerCapture(0, commandCount, quickCapture, fullCapture);
499+
// Ensure bridge exists for UI integration
500+
if (!this.workerBridges.has(worker)) {
501+
this.spyWorker(worker);
502+
}
503+
504+
// Listen for capture result directly on the Worker
505+
// (bypasses the Spector spy chain for reliable full-frame capture)
506+
// tslint:disable-next-line:no-this-assignment
507+
const self = this;
508+
worker.addEventListener("message", function captureHandler(e: MessageEvent) {
509+
if (e.data && e.data.type === "spector:capture-complete") {
510+
worker.removeEventListener("message", captureHandler);
511+
self.triggerCapture(e.data.capture);
512+
}
513+
});
514+
515+
// Send trigger directly to Worker
516+
worker.postMessage({
517+
type: "spector:trigger-capture",
518+
version: 1,
519+
canvasIndex: 0,
520+
commandCount,
521+
quickCapture,
522+
fullCapture,
523+
});
506524
}
507525

508526
private captureFrames(frameCount: number): void {

0 commit comments

Comments
 (0)