catalog/shoot: optional imageScale for a device-pixel page image, motion-safe (fixes #51) - #75
Merged
Merged
Conversation
…ion-safe (fixes jrpool#51) When report.imageScale is a number greater than 1, the catalog browser context runs at that deviceScaleFactor and the catalog captures a second page image at device-pixel scale as images[1], with imageScale times the pixels of the CSS layout in each dimension. Fractional factors (e.g. a device's native 2.625) capture exactly. images[0] keeps its contract: it is always captured at CSS-pixel scale, so the testaro motion rule, which compares its own CSS-scale screenshot against images[0] and fails fast on any dimension mismatch, is unaffected by imageScale. (Capturing images[0] itself at device scale was the originally proposed design; it would have made every motion comparison under imageScale > 1 a guaranteed size-mismatch false positive.) Box IDs remain CSS-pixel by definition (getBoundingClientRect); consumers map them onto images[1] by multiplying the coordinates by imageScale. Omitted, 1, or invalid imageScale keeps behavior identical to before this option existed, including no images[1]. Plumbing: launch() and launchOnce() accept contextOverrides, extra Playwright context options spread after the defaults; shoot() accepts scale ('css' or 'device') passed to page.screenshot. Verified end-to-end on a synthetic page (chromium, 1280x800): imageScale 2 yields images[0] 1280x800 and images[1] 2560x1600; imageScale 2.625 yields images[1] 3360x2100 exactly; with no imageScale, images has one CSS-scale entry as before. Box IDs are CSS-pixel in all cases. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.
Implements #51 with the revised, motion-safe design (see my reply there answering your question about the
motionrule — you were right, and this design removes the coupling entirely).What it does
When
report.imageScaleis a number > 1:deviceScaleFactor: imageScale(via a newcontextOverridespass-through inlaunch()), andimages[0], a second image is captured atscale: 'device'and appended asimages[1]—imageScale× the pixels of the CSS layout in each dimension.images[0]keeps its contract: always CSS-pixel scale, exactly as today. Themotionrule — which compares its own CSS-scale screenshot againstimages[0]and fails fast on any dimension mismatch — is therefore unaffected byimageScale. (The originally proposed single-shot design would have made every motion comparison underimageScale > 1a guaranteed size-mismatch false positive; this is the fix for the problem you spotted.)boxIDs remain CSS-pixel by definition; consumers map them ontoimages[1]by multiplying byimageScale. Omitted,1, or invalid values keep behavior byte-identical to today, including noimages[1].Changes
procs/launch.js:launch()/launchOnce()acceptcontextOverrides— extra Playwright context options spread after the defaults (used here fordeviceScaleFactor; the launch-arg--force-device-scale-factor=1is cleanly overridden by the context option, verified empirically).procs/shoot.js:shoot()acceptsscale('css'default, or'device'), passed topage.screenshot.procs/catalog.js: validatesreport.imageScale, applies the context override, and takes the supplemental device-scale shot when applicable.README.md: documents theimageScalejob property and theimages[1]semantics.Verification
End-to-end
getCatalogruns on a synthetic page (chromium, viewport 1280×800):Box IDs are CSS-pixel in all cases, and the closed-
<details>expansion from #71 is visible in both images (both shots happen after it).One note for completeness: when
imageScalediffers from the emulated device's own DSF,images[0]is a CSS-scale downsample of a higher-DPR render while motion's own shot renders at the test context's DPR — same dimensions, near-identical pixels; pixelmatch's default antialiasing exclusion absorbs the rendering difference. SettingimageScaleto the device'sdeviceScaleFactor(the natural policy suggested in the issue) makes the two rendering pipelines identical.🤖 Generated with Claude Code