Skip to content

docs: propose how a pdf page loads at level 3 - #1256

Merged
andiwand merged 2 commits into
mainfrom
docs/pdf-level-3
Oct 24, 2026
Merged

andiwand merged 2 commits into
mainfrom
docs/pdf-level-3

Conversation

@andiwand

@andiwand andiwand commented Oct 24, 2026 •

Copy link
Copy Markdown
Member

🤖 Generated with Claude Code

Refs #764.

Summary

This adds decision 7 to docs/design/lazy-loading.md, a proposal for level 3 of a pdf.

Measured on Core_v5.1.pdf (2,985 pages):

step time memory
core: parse 0.5 s
core: whole-document view 4.9 s 761 MB peak
core: one page view 5–37 ms
browser: first frame at level 1 1.8 s, nearly all html parsing 2.0 GB
document.html 127 MB: 5.4 MB head (2.3 MB fonts), 122 MB pages

For a server, the time is in core. For an offline file, core works once and the reader waits for the browser.

  • Option A, the page side: as the sheets do in feat(html): load the later chunks of a sheet on demand #1255. Keep the full pass, so the head has every class and font, and make the later pages scripts that re-render with the kept registries.
    • The page is about 5.5 MB.
    • Core still takes 4.9 s before the page goes out.
    • It is a small change.
  • Option B, a page on its own: render the first page only, and each later page alone. Its cost is in proportion to what the reader sees: about 40 ms for the page.
    • Class names come from a hash of the declaration, so they are the same in every render.
    • Fonts become shared files. Without that, each page carries its fonts, about 0.5 MB per page here. In dual_layer, the default, a font is already the same for every page. Only single_layer must re-encode a font from its whole ToUnicode map.
    • It is a large change to the pdf writer.

The doc recommends B, because the time is in core. A is the smaller step. The browser cost is the same for both.

Review fixes

  • Rebased onto main after the squash of feat(html): load the later chunks of a sheet on demand #1255.
  • The proposal said that the writer re-encodes each font with the code points of the runs it meets. Only single_layer does that. In dual_layer, the default, reencode_to_pua maps every glyph to a private-use code point, so a font file is already the same for every page. Option B is a little smaller for the default mode.
  • The class examples used the prefix x, which the writer does not have. They now use c.

Base automatically changed from feat/sheet-chunks-on-demand to main October 24, 2026 21:58
andiwand and others added 2 commits October 24, 2026 23:58
Measured on `Core_v5.1.pdf` (2985 pages):

- Core renders the whole document in 4.9 s with 761 MB, and one page in
  5 to 37 ms.
- The browser parses the 127 MB page in 1.8 s.

So for a server, the time is in core. Decision 7 weighs two options:

- A: keep the full pass and load the bodies of the later pages.
- B: render each page alone. Class names come from a hash, and fonts
  are shared files with a cmap that is the same for every page.

The recommendation is B.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017QtawyvLP2SCnoBtnVfFed
The proposal said that the writer re-encodes each font with the code
points of the runs it meets. Only `single_layer` does that. In
`dual_layer`, the default, `reencode_to_pua` maps every glyph to a
private-use code point, so a font file does not change from page to page.
Also use `c`, a prefix the writer has, in the class examples.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YHNzLmVv1mFWfPitHASucN
@andiwand
andiwand merged commit 9782ea8 into main Oct 24, 2026
18 checks passed
@andiwand
andiwand deleted the docs/pdf-level-3 branch October 24, 2026 22:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant