Repository navigation
Other browsers, captures and designs - #32
Merged
Merged
Conversation
A research note with a phased to-do list: open the page in the browsers installed on this computer (and serve the workspace's changes in Chromium browsers and Firefox), capture it, keep captures and imported designs per workspace, and check the page against a design pixel by pixel, over the live page or on stills. SPEC gets the stories and an M5 milestone, and the README's roadmap drops the two items that shipped.
A menu beside the address bar, in the editor and in the website's own window, lists the browsers found the system's way: Linux launchers (with their icons from the icon theme), apps in the Applications folders on macOS, and the registry's list on Windows. Choosing one opens the page there, with its everyday profile. Settings gets a Browsers section to stop offering one, or to add one by picking its program, and the palette gets an "Open in …" item per browser.
A menu at the toolbar's end keeps captures of the page with the workspace: what it shows, all of it, or one element picked in it (in any frame, cross-site ones too, placed through each frame's owner). Each opens as a tab to zoom into, with the colour of the pixel under the pointer. Designs come in from files, or dropped or pasted on the menu, their scale read from their name or width. Compare with… lays the page out at a design's width and captures it, then shows the two side by side, swiped, faded over each other, or as their difference: how much differs, and each area that does.
"Put over the page" draws a design or capture over the website's top frame: on a canvas from an isolated world, so a strict CSP can't refuse it, kept after reloads, and out of the pointer's way. A bar under the preview's toolbar sets how see-through it is, blends it as a difference, moves it (the arrow keys nudge it), pins it to the page or the viewport, and lays the page out at the design's width, scaled to fit the preview. Captures leave it out.
A Chromium browser found on the computer can now be launched with a profile of the app's own and a debugging port. Every one of its tabs is served the workspace's overrides and rules by the same interception engine as the app's page; a new tab waits until that is set up. Changes to overrides, rules and settings reach those tabs as they are made, and the tabs reload when "Reload page after changes" is on. The browser menu lists each driven browser's tabs: they can be brought to the front, opened in the app or captured into the shots. Letting go of a browser leaves it open. When the app starts again it reconnects to a browser that is still open instead of launching a second one.
"In every browser" (in the shots menu's Capture, and in the palette) captures the whole page in the app and then at the same address in every browser driven with the workspace's changes. Each one is laid out at the app's viewport and density, and captured once it has loaded and been quiet for a moment. The captures are kept as one group. A browser that fails is named in the notice rather than failing the rest. The group's page shows the captures side by side against a baseline: the app's capture, another capture of the group, or a design. Each cell shows the share of pixels that differ, and can show the difference itself. Choosing a cell opens the two in the compare page. The status bar now counts the tabs of other browsers that are served the workspace's changes.
Firefox can now be launched with a profile of the app's own and driven over WebDriver BiDi, like the Chromium browsers over CDP. One interception covers every tab and applies the engine's matching and rules to each paused request: - a block rule fails the request; - an override answers before the request is sent, since Firefox can only replace a body then. The response has its kind's content type, a response override's status, headers and delay, and is readable cross-origin; - the CORS preflight ahead of such a request is allowed; - header and CORS rules edit the upstream response's head. Requests are paused only while an override or a rule is on, and the cache is bypassed then. Tabs are listed and captured, including in "Capture in every browser", and the app reconnects to a Firefox that is still open. The drivers share one interface, a launch path and their tab list. The engine-neutral part of deciding what to do with a request (used by Firefox) now lives in the engine's answering module. The browsers end-to-end test picks the plain "Open in" palette entry by its exact name, now that "with your changes" follows it.
With Firefox installed, the browser menu offers "Your Firefox tabs". Once asked, it lists the tabs open in each Firefox profile, the install's default first, and choosing one loads its address in the app. The search narrows them like the other tabs. The profiles come from profiles.ini, in Firefox's own folder on each system (Linux's Snap and Flatpak included). The tabs are read from the session file Firefox keeps up to date (recovery.jsonlz4, an LZ4 block behind a small header, decoded here), and only http(s) pages are listed. That file is read only after the user asks, and nothing of it leaves the app.
SPEC gains the sections on other browsers (finding and opening them, driving Chromium over CDP and Firefox over WebDriver BiDi, your everyday Firefox's tabs), captures and designs (capturing, the group capture, the compare page) and the design over the page. It also covers their data and storage, source layout, security, tests, stories and milestones. The CHANGELOG's Unreleased section and the README describe what users get, what is kept where, and Firefox's limits. The research doc now says what was built, item by item. It records why WebKit through Playwright (phase 8) isn't built yet, and how to do it.
A design put over the app's page now goes over every tab of the browsers driven with the workspace's changes too, including tabs opened later. It is restyled with it, laid out at its width while that is on, and taken off with it. A capture in those tabs takes it off while it runs. Chromium tabs get the app page's own overlay code over their CDP session. Firefox gets it as preload scripts in a sandbox of every new document, and in each tab's current one. The overlay's script now only draws in a top document. The app's own page ran it in same-site frames' documents too, after a reload, so a design also showed inside them.
With remote debugging turned on for it (chrome://inspect/#remote- debugging, from Chrome 144), a Chromium browser writes its debugging address in its everyday profile. The app finds that address in each Chromium browser's profile folder, on each system and in Snap and Flatpak ones. While the browser runs, its row in the browser menu (and the palette) offers "Use your own … with your changes". The app checks the port only by opening and closing a connection, so Chrome doesn't ask anything for it. Chrome asks you to allow the connection. After that, the app serves the workspace's overrides and rules only in the tabs it opens there; your own tabs are neither listed nor attached. Letting go leaves the browser as it was. The driven browsers now sit in a pool by key, so a browser can be driven with the app's profile and with your own at once. Each lists the installed browser it is, and which profile it uses.
4 tasks done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What and why
Milestone M5 (docs/BROWSERS_RESEARCH.md): check the page you're changing in other browsers, and against designs, pixel by pixel.
Other browsers (SPEC §6.16)
route. The app downloads and unpacks it itself: Playwright's installer forks Node, which the packaged app's fuses refuse.chrome://inspect/#remote-debugging, Chrome 144+). Only the tabs the app opens there are served your changes.Captures and designs (SPEC §6.17, §6.18)
safeStorage.Packaging:
playwright-corebecomes a pinned dependency, left out of the main bundle and shipped in the asar (the package grows from about 26 MB to 39 MB before Electron).Left for later: the console, Network panel and inspector for a tab in another browser (they follow the app's own page only).
How it was tested
Unit:
Integration, real browsers:
End to end, built app:
By hand: an unpacked Linux build (
electron-builder --dir) lists WebKit, downloads a stand-in build and launches it from the asar. A 2880 × 32,766 capture took about 45 s.Not checked for real:
Each is covered by the stand-ins above.
Checklist
feature/…,bugfix/…) intomain, and does one thing (milestone M5: other browsers, captures and designs)npm run typecheck,npm run lint:fsd,npm run lint:structure,npm run lint,npm run lint:unused,npm run lint:duplicates,npm run lint:secrets,npm testandnpm run test:e2epassdocs/SPEC.mddescribes any behaviour this changes[Unreleased]inCHANGELOG.mdGenerated by Claude Code