pagevera

How it works

The technical side of PageVera: how a save works, what Chrome’s PDF engine can and can’t do, and how to run the tests.

The save pipeline

The extension attaches Chrome’s debugger to the tab and calls the DevTools command Page.printToPDF. That is the same PDF engine as Print → Save as PDF, without the dialog. In that engine:

The quality gains come from preparing the page first:

  1. Find every frame on the page, including cross-origin iframes such as embedded course players (SCORM, Articulate Rise) and document viewers, and run the same preparation inside each one.
  2. Remove popups and scroll locks, and switch lazy-loading images and iframes to load right away.
  3. Optionally scroll to the end, inside embedded frames first and then the page, waiting for network requests to settle after each step.
  4. Remove the chosen navigation, footer and popups, in each frame and on the page. Convert sticky and fixed elements so they print once instead of repeating. Let fixed-height panels and inner scroll areas grow so their whole content prints.
  5. Lay out carousels so every slide prints. A carousel keeps the slides it isn’t showing beside the current one (cut off by its box), stacked under it, or hidden. The extension finds the row of alike slides where at least one is out of view, wraps them into rows one after another in slide order, leaves out the copies that looping carousels add at both ends, and hides the arrows, dots and counters. The forced styles live in a stylesheet with !important, so autoplay timers and resize handlers can’t move the slides back.
  6. Grow each embedded frame to its full content height, innermost first. If the content sits in a full-window dialog (a course or document player), print that dialog on its own and leave out the page behind it, with the lesson starting at the top of page 1.
  7. Chrome prints an embedded frame as one picture cut at every page break. Since the page height is known, the extension moves any image or text block that would straddle a break down to the next page inside the frame first.
  8. Pin every responsive image to its largest candidate and wait until all images and fonts have loaded.
  9. In print, vh units are measured against the paper height, which would make a full-screen hero section as tall as the whole PDF. The extension briefly emulates a viewport as tall as the paper, finds every style that changes, and pins it to its on-screen value.
  10. Print, then undo every change to the page and restore your scroll position.

Limitations

Development

Requirements: Node 22, Python 3 with Pillow and numpy, and poppler (brew install poppler) for the PDF checks.

npm install          # playwright-core, used only by the tests
npm run fixtures     # generate test images (already committed)
npm run icons        # redraw the icons
node tools/make_screenshots.mjs   # redraw the README images from docs/demo/article.html
npm test             # unit tests + end-to-end tests
npm run package      # zip only the files the extension needs

The end-to-end tests launch Chrome for Testing with the unpacked extension (branded Chrome ignores --load-extension). By default they use the Playwright build at ~/Library/Caches/ms-playwright/chromium-1243. Set CHROME_PATH to use another Chrome for Testing binary.

node tests/run-one.mjs <fixture.html | URL> '{"layout":"paged"}' [--headed] [--out file.pdf] saves one page and prints the job report, embedded fonts and embedded image sizes.

Code layout: