Skip to content

Cut image payload 70% with WebP and lazy loading; add copy buttons and anchors - #29

Merged
tdhopper merged 5 commits into
add-hvplotfrom
perf-ux
Aug 5, 2026
Merged

Cut image payload 70% with WebP and lazy loading; add copy buttons and anchors#29
tdhopper merged 5 commits into
add-hvplotfrom
perf-ux

Conversation

@tdhopper

@tdhopper tdhopper commented Aug 5, 2026

Copy link
Copy Markdown
Owner

TL;DR

The page ships 101 plot images; this cuts their payload 70% (8.54 MB → 2.58 MB) by converting render.py's output to WebP q85, and lazy-loads all but the first image with width/height attributes so cards don't reflow while streaming. Also: copy-to-clipboard buttons on every code panel, working anchor links, and fixed social-preview metadata.

Stacked on #26 (add-hvplot).

Files to review (3):

File Why
templates/t_index.html (start here) lazy/async images with dimensions, copy buttons + inline JS, anchors, OG/twitter/canonical meta.
render.py image_from_cell writes WebP via Pillow (quality 85); MD5 naming kept so unchanged plots keep URLs.
web/css/custom.css .copy-btn styling matched to the dark code panel.

Reviewer notes

  • Two latent bugs fixed in passing: the heading anchor used a Font Awesome icon but the site never loads Font Awesome (it rendered as nothing — replaced with a muted #), and the template called $.bigfoot() with no bigfoot library loaded, throwing a TypeError on every page load. Console is now clean, verified headless.
  • Copy buttons are one delegated listener, navigator.clipboard with a "Press ⌘C" fallback; verified all 101 buttons resolve their code block with zero misses.
  • og:image was plain-http and pointed at a nonexistent cover.png; now https banner.png with alt text and twitter:card.
  • Render time grows 0.3 s → 6.8 s from WebP encoding, noise next to the ~4 min notebook execution.

Plots are exported at ~1500x1500, and the page now ships 100+ of them.
Re-encoding the notebook's PNG output as quality-85 WebP cuts the image
payload from 8.5 MB to 2.6 MB with no visible loss. Filenames keep the
MD5-of-base64 scheme so unchanged plots keep their URLs.

image_from_cell now also returns the pixel dimensions, which the template
uses to reserve layout space.
Every plot image but the first one now loads lazily and decodes off the
main thread, so a visit only fetches what the reader scrolls to. The
width/height attributes come from the rendered image, which keeps the
cards from collapsing and reflowing as images arrive. Also adds alt text,
which the images never had.
The whole point of the site is lifting a snippet into your own notebook,
which until now meant selecting the pygments markup by hand. One
delegated click handler covers all 101 panels and falls back to a
"Press ⌘C" hint where the clipboard API is unavailable.

Also drops the $.bigfoot() call: the library was never loaded, so it threw
on every page load.
The heading already carried a deep link, but it was a Font Awesome icon
and Font Awesome is not loaded, so it rendered as nothing. A muted # after
the title is visible without competing with the heading.
og:image pointed at a cover.png over plain http, so previews were
insecure-mixed-content at best. It now points at the banner over https,
with the large-image Twitter card, matching twitter:* tags, a canonical
URL, and a description that names the libraries the page actually covers.
@tdhopper
tdhopper marked this pull request as ready for review August 5, 2026 11:48
@tdhopper
tdhopper merged commit 7198f02 into add-hvplot Aug 5, 2026
1 check passed
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