Repository navigation
feat: share comparison snapshots, fit and resize panels, rating prompt - #91
Merged
Merged
Conversation
Count successful Send All actions in chrome.storage.local. After 20 sends the comparison page shows a banner linking to the store reviews page. Rate and Don't ask again stop the prompt; Later snoozes it for 50 sends.
Chrome writes _metadata into the unpacked repo while a test loads it, so a concurrent copy could fail with ENOENT when the directory disappeared.
Add a pure module that lays out the prompt strip, the captured panels and the optional Panelize watermark on a canvas, plus a tab capture helper built on getDisplayMedia with preferCurrentTab. Chrome asks the user to share the tab, so no extension permission is needed, and a capture handle confirms the stream shows this tab before it is cropped.
A Share button captures the panels, adds the last prompt and a "Compared with Panelize" strip, and opens a preview that warns about sidebars and avatars before the image is copied or downloaded as PNG. Everything stays on the device. A new setting turns the watermark off.
Sends one prompt in temporary chat to ChatGPT, Claude, Gemini and DeepSeek on the live profile, then takes, downloads and copies a snapshot. Runs only with PANELIZE_LIVE_SEND=1 and stores evidence under artifacts/share-snapshot/live.
The focus restore after loading, sending or starting a new chat pulled focus back to the prompt box even while a dialog was open, so typing into a dialog field right after sending went to the prompt box instead.
…shots Provider frames answer PREPARE, SCROLL and RESTORE messages from the page that embeds them: align the latest message matching the prompt under the provider header, report the visible conversation without sticky headers and the composer, scroll it step by step and put it back afterwards.
- The toolbar icon, its shortcut and the context menu on the Panelize tab take a snapshot of that tab with captureVisibleTab, without Chrome's tab sharing dialog. The Share button tries the same first and falls back to getDisplayMedia, with a hint naming the shortcut. - Snapshots follow the theme: layout A (light) and B (dark). The title is editable and prefilled with the prompt; the watermark setting drops the brand row, keeping the headline and frame. - "Full answers" scrolls every panel in lock-step, captures one screen per step and stitches each conversation without sticky headers, the composer or overlap, up to 8000 px with a note when truncated. Progress shows over the input bar and can be cancelled. - After the capture the dialog focuses its first button, and the mode button that started a capture once it is enabled again.
Chrome keeps the registered service worker of an unpacked extension while its version is unchanged, so the live profile ran an old background script. The live copy now gets a fresh fourth version part.
Scroll-to-bottom buttons and edge fades stay pinned over the conversation, so they repeated on every stitched screen. Full-answer captures now hide them with visibility (keeping layout) and drop edge masks, re-checking after every scroll, and put the original inline styles back on restore.
A header's backdrop without pointer events was never hit when checking which bars cover the conversation, so its fade repeated at the top of every screen. Layers of a covering bar now count with it. Overlay scrollbars, which show up after every scroll, are hidden while stitching.
Claude shows a usage notice as a plain card above the input, inside a transparent dock stuck to the bottom of the conversation. It repeated on every stitched screen. While stitching, hide what sits next to the input's ancestors inside the pinned composer and overlaps the clip. Also let the e2e polls on the preview height retry while a newer preview replaces the one being decoded.
Sends a long prompt to a live comparison, then snapshots it silently from the toolbar icon in both layouts and both modes, and saves the images, the dialog on desktop and at 390 px, and what each panel reported. PANELIZE_SHARE_PROVIDERS leaves providers out, e.g. one near a usage limit.
…es and the cursor out Full answers now aligns every panel to the prompt, then the latest user turn, then the top, and puts each scroll position back afterwards. Mid-content sticky headings and table headers are un-stuck, gradient pseudo-element fades and overlay scrollbars are hidden, and the pointer is hidden in every frame. The current view hides floating controls, fades and composer notices too, while keeping the composer.
The share dialog opens in Full answers by default and then in the mode picked last, kept in chrome.storage.local. When a snapshot needs Chrome's tab sharing, the stream is kept paused at a low frame rate between snapshots, so Chrome asks once per page. It is released on Stop, when the track ends or when the page goes away, and the dialog says the tab is being shared. The stream asks for no cursor.
Asking for a capture larger than the tab made Chrome raise the tab's device pixel ratio, and every later constraint change re-laid it out, which clamped virtual lists such as DeepSeek's. Cap the capture at the tab's own device pixels, and when restoring follow a short virtual range until it grows back to the remembered position or end.
Tab capture sends a frame only when the page changes, so waiting for two frame callbacks could time out and take a frame from before the latest scroll, repeating one screen and dropping the next in Full answers. Flip a nearly transparent pixel to make Chrome send a frame, and take the first one whose capture time is after the request; fail rather than use an old frame.
Each screen's place and height were rounded on their own, so at a fractional scale a screen could end one pixel before or after the next began. The gap showed the cell's fill color, a dark line across Gemini's code blocks. Round where each screen starts and ends instead, in the crop from the frame and in the stitched image.
Put a solid panelize.dev pill with a Free Chrome extension caption on the brand row of both layouts, and move the provider names and date into one subline under the headline so light and dark show the same details. The subline wraps once on narrow captures and stays without the watermark.
…t out Panels cut by the grid's horizontal scroll were captured as slivers and listed in the subline. Snapshots now take the panels fully on screen, crop to them, and a note names the open providers left out. A window narrower than one column still captures its most visible panel. Co-Authored-By: Claude <noreply@anthropic.com>
…s to resize Some provider pages (Kimi, Zhipu and others) hold a pixel min-width, so narrow panels such as 1x12 cut off their right side. - Provider frames report the width their layout needs; a panel narrower than that lays the page out at that width and scales it down to fit (down to 0.4), so media queries and fixed elements keep working and share snapshots match what is on screen. - Handles between columns resize panels by dragging or arrow keys; widths are remembered per layout and double-click resets them.
"Long answers truncated — showing the first 13 screens" did not say which answer was cut or what a screen is. The capture now reports the panels whose answer did not fit the image, and the note names them.
Chrome draws the pointer into shared-tab frames for 2s after it moves or clicks, regardless of the page's CSS cursor, so stitched full-answer snapshots showed one pointer per screen. While tab sharing captures, a transparent shield covers the panels and each frame waits until the pointer near them has been still past Chrome's idle timeout, asking the user to hold the mouse still.
The toolbar icon e2e tests click the action through the CDP method Extensions.triggerAction, which the Chrome 145 bundled with Playwright 1.58 lacks; CI failed with "'Extensions.triggerAction' wasn't found".
The page measured only what reached past its viewport, so once laid out at the width it needs it reported 0, the panel shrank it back and it asked again: the fit flickered and, when slow, stayed off.
A heading in an answer that repeats the prompt verbatim could win the match and start the Full answers capture partway down the answer. Matches inside a marked user turn now rank first.
captureVisibleTab takes whatever tab is in front of the window, so switching tabs mid-capture could stitch another tab into the snapshot. The source now checks before and after every frame that its own tab is still the active one (and was not hidden meanwhile), stops with a message asking to keep the tab in front, and does not fall back to tab sharing.
Full answers planned the image height of a page scaled down to fit its panel in the page's own CSS pixels, so a long answer was cut well before the image was full. The budget is now planned in on-screen pixels and the cap converted back to the page's. Stitched screens of such pages also start between rows; rounding to the nearest row picked up the page header's edge and left a line at every seam. Screens are now cropped to rows wholly inside them.
A page that stopped answering partway (e.g. its session expired) was kept as captured so far but reported as cut to fit the image, or not at all. It is now listed separately and named in the dialog and the image note.
The layout check covered the window and the grid only, so dragging a panel divider during a silent capture kept cropping later screens with the old panel boxes and stitched parts of one panel into its neighbour. Panel and frame boxes are now part of the check, so the capture starts over as it does when the window is resized.
A page that answered a scroll request but stayed where it was (e.g. while putting back its own position) ended its Full answers capture as if it had reached the end, with no note. It is now asked once more, and if it still does not move it is named as not captured to the end. The note now says that, which also fits a page that stopped answering.
A page that scrolled past the requested position left a blank hole in its stitched answer and still counted as complete. Only a screen that joins up with what is covered is used; otherwise the page is asked again, then it is named as stopped partway with the part that joins up.
… prompt A page that kept scrolling back to its bottom after the alignment retry was still stitched from there, so Full answers showed only the end of the answer as if complete. The preparation now reports that it could not align, and the panel is shown as on screen and named as current view only.
Download and Copy used the last rendered image, so a title cleared or changed just before exporting was shared as it was. Both now wait for the pending render; Copy hands the clipboard a promise so the click still counts.
Signed-in Qwen (Global) puts a 60px rail of icons beside a scrolling content box that holds the app. The box did not start at the left edge, so it was not taken for the app shell and its min-width was never seen: the page was cut off instead of scaled to fit its panel.
A conversation inside a box scrolled sideways reaches under the side rail next to it, so every stitched screen repeated part of the rail.
A panel frame that has not started loading has an empty URL, which made new URL() throw and failed the focus protection tests now and then.
Merged
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.
Summary
Adds shareable comparison snapshots, panels that fit wide provider pages and can be resized by dragging, and a Chrome Web Store rating prompt.
Share a snapshot of the comparison
captureVisibleTabwhen the activeTab grant is present.getDisplayMedia). The shared tab is kept between snapshots so Chrome asks only once, and the dialog shows a shortcut tip.Panels
Rating prompt
Other
Validation
npx vitest run).npx playwright test tests/e2e).