fix: render iframe layouts at their on-screen resolution - #2728
Open
aron-intframe wants to merge 1 commit into
Open
fix: render iframe layouts at their on-screen resolution#2728aron-intframe wants to merge 1 commit into
aron-intframe wants to merge 1 commit into
Conversation
✅ Deploy Preview for slidev ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
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.
Fixes #2281 (same underlying cause as #1271, which was closed for lack of reproduction).
Root cause
Slidev renders slides at their design size (default
980x552) and fits them to the window withtransform: scale(...)on the slide container. Regular DOM content is re-rasterized by the browser under that scale, so it stays sharp. But iframe content that sizes its own raster from the embedded viewport — canvas apps like Excalidraw, which setcanvas.width = cssSize * devicePixelRatio— renders at the slide's design size and is then bitmap-upscaled by the slide scale. At a 1920x1080 window the scale is ~1.9565, so every canvas pixel is smeared across ~2 screen pixels. That matches the issue screenshots: the shared Excalidraw link is sharp standalone but blurry embedded.Fix
Let the iframe in the
iframe/iframe-left/iframe-rightlayouts lay out at its real on-screen size and counter the slide scale, using the inverse-scale idiom this codebase already uses for.rough-annotationand Monaco's context menu:max(scale, 1)on purpose, so scaled-down views (overview, presenter thumbnails) keep the current behavior.scaleprop keeps its meaning; it now feeds the same formula via--slidev-iframe-scale.Verified with the reproduction from the issue
Loaded the exact Excalidraw link from the issue in
layout: iframe, headless Chromium at 1920x1080 (dpr 1), and measured the blue text region of the drawing in before/after screenshots:Strokes resolve to dark cores again instead of gray smears. Because Excalidraw fits the scene to its viewport, the apparent size of the drawing barely changes — only sharpness does.
I also measured with a local page that mimics Excalidraw's canvas handling (backing store = CSS size x devicePixelRatio) drawing a 1px stripe pattern: before, the pattern is stretched to a ~3.9px period (1px detail cannot survive the upscale); after, the 2px period is preserved pixel-for-pixel, and the embedded render differs from opening the same page directly in the browser by a mean of 2.8/255 per pixel.
The new Cypress spec asserts the iframe's layout width matches its displayed width at a 2x viewport and stays at the design size at 0.5x. Against the previous behavior it fails with
displayed width: expected 600 to be close to 1960 +/- 2.Behavior note (intentional, please review)
When a slide is scaled up, the embedded page now sees its real on-screen viewport (e.g. 1917px at fullscreen 1920) instead of the design-size 980px. Responsive pages lay out the way they would in a standalone browser window of that size — which is what the issue reporter expected — but decks that relied on the old "980px layout blown up ~2x" look will see embedded pages render with more content at a smaller apparent size (the
scaleprop can compensate).One remaining limit: when the fitted slide has a fractional scale/offset (e.g. 1920 window gives scale 1.9565 and a 1.3px centering offset), pixel-aligned 1px patterns lose some contrast to subpixel blending. That is inherent to non-integer compositing and far less visible than the previous 2x upscale.
Ran
pnpm verifylocally (build, typecheck, lint, unit tests all pass) plus the new Cypress spec.