PDFs are vector: bin/pdf.mjs + the button's print route in Chromium, 3× Flate raster in Safari - #17
Merged
Conversation
… the button takes that route in Chromium, Safari's raster is 3× Flate Both exits rasterised: the PDF button painted each slide to a 2× canvas and stored JPEG .92; agents screenshot slides and stitched PNGs with ImageMagick — soft text on every rescale, no links, and the editor's HUD shipped inside a LinkedIn carousel once. - bin/pdf.mjs deck.html [out.pdf]: the deck's own print pipeline (beforeprint → #print) through Chromium's print engine with @page{size:W H px}, zoom 1. One slide-sized page per slide, text stays text, fonts embed, every href is a /Link annotation, HUD hidden by the deck's @media print. Self-gating (exit 1): pages == slides, ratio == W/H, #hud display none under print media, links == linked rows. 367 KB vs 1.6 MB on a seven-card carousel. - The PDF button: Chromium (navigator.userAgentData) injects the px @page + zoom rule and calls print(); afterprint removes it so a plain ⌘P is still the Letter paper path. Safari ignores px @page, so it keeps the in-file rasteriser at 3× with lossless FlateDecode pixels via CompressionStream (JPEG .92 only for a page whose deflate exceeds 6 MB, or an engine without it). Verified in WebKit: 12 pages, 960×540 pt, decodes. - Gate: test/pdf.test.mjs (inspect · pdf.mjs pass · pdf.mjs refuses a visible HUD · button route). editor arrow test hooks getImageData (the Flate path never calls toDataURL). SKILL.md / README / llms.txt: agents make PDFs with bin/pdf.mjs only; screenshot stitching is an anti-pattern. library.html and deck.html rebuilt. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ilds with nspell; a build without it drops the SPELL0 flags and fails the self-hosting gate) Co-Authored-By: Claude Fable 5.1 <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.
What
Both PDF exits rasterised. The PDF button painted each slide to a 2× canvas and stored JPEG .92; agents screenshot slides and stitched PNGs with ImageMagick. Soft text on every rescale, no link annotations, and the editor's HUD shipped inside a LinkedIn carousel once.
bin/pdf.mjs deck.html [out.pdf]drives the deck's own print pipeline (beforeprint→#print) through Chromium's print engine with@page{size:W H px}and zoom 1. One slide-sized page per slide, text stays text, fonts embed, everyhrefis a/Linkannotation, the HUD is hidden by the deck's@media print. Self-gating, exit 1: pages == slides, ratio == W/H,#hudcomputed displaynoneunder print media, link count == linked rows.afterprint, so a plain ⌘P is still the Letter paper path. Safari ignores px@page, so it keeps the in-file rasteriser at 3× with losslessFlateDecodepixels viaCompressionStream(JPEG .92 only for a page whose deflate exceeds 6 MB, or an engine without it).bin/pdf.mjsonly; screenshot stitching is an anti-pattern.decklet-pdfbin. library.html and deck.html rebuilt.Why
A rasterised page blurs on every rescale (LinkedIn's document post, a viewer's zoom), carries no text and no links, and the HUD leak was only ever prevented by a hand-added style override in a per-deck script.
Evidence
Same seven-card 1080×1350 carousel, both ways:
/Linkannotations@media print, gatedWebKit run of the in-file rasteriser: 12 pages, 960×540 pt, all
FlateDecode, page 2 decodes with pdftoppm.Verification
New:
test/pdf.test.mjs(4). Updated: gate's button-route and writer assertions, editor's arrow test hooksgetImageData(the Flate path never callstoDataURL).🤖 Generated with Claude Code