Repository navigation
Description
Notes
layer5io/layer5 converts PNG to WebP as part of its build for SEO and performance. This issue is to investigate that mechanism and whether it can be reused here.
What layer5io/layer5 actually does
It is not a standalone conversion script. layer5.io is a Gatsby site, and the conversion is a side effect of its image pipeline:
gatsby-plugin-sharpandgatsby-transformer-sharp(gatsby-config.js), backed bysharpgatsby-plugin-imagerenders the results
On Gatsby 5 the sharp defaults emit ["auto", "webp", "avif"], so each source image is derived into modern formats at build time and rendered as a <picture> with a srcset and a fallback. The repo's _headers also sets caching rules for /*.webp. Committed .webp files in that repo are separate from this, they are source assets that happen to already be WebP.
Why it cannot be lifted directly
This repo is Hugo (0.158 extended), not Gatsby, so none of those plugins apply. The equivalent capability is built into Hugo extended, which can encode WebP directly.
Today this repo does no image processing at all:
- Markdown images go through
layouts/_default/_markup/render-image.html, which emits a plain<img>with the source path untouched - Raw
<figure><img>blocks in content are passed straight through [imaging]inhugo.tomlsets onlyresampleFilter,qualityandanchor, which nothing currently exercises
Content inventory: 361 PNG, 71 GIF, 47 SVG, plus images under static/.
Options to evaluate
- Process at build time in the render hook. Resolve each image as a page or assets resource, call
.Process "webp", and emit<picture>with the original as fallback. Keeps sources as PNG, needs the hook to handle both page-bundle andstatic/paths, andstatic/files are not resources, so those would have to move underassets/to be processable. - Convert the sources and update references. Simple and predictable, no build cost, but it is a large one-time diff and loses the original PNGs.
- Both. Convert sources for new screenshot-heavy content, process the long tail at build time.
Data point
Converting the 15 Kanvas screenshots from #1245 to lossless WebP took them from 1208KB to 719KB, about 41% smaller, decoding pixel for pixel identical. Lossy quality 90 reached 55% but put visible artifacts on UI text, and on 5 of the 15 it was actually larger than lossless, since UI screenshots are flat colour rather than photographic. Whatever mechanism is chosen, screenshots should stay lossless; photographs are the case where lossy pays.
Open questions
- Should
static/images move underassets/so Hugo can process them, and what breaks if their public paths change? - GIFs are 71 files here. Animated WebP is possible but not through Hugo's image processing, so they would need a separate tool or stay as they are.
- Does the deployment path (GitHub Pages) allow setting cache headers similar to layer5's
_headers, or is that Netlify-only? - Is a
<picture>fallback wanted, or is WebP-only acceptable given current browser support?
Activity
Rohit-Solanki1890 commentedon Oct 11, 2026
Hi @hiyach28 @PARTH-TUSSLE 👋
I've gone through this issue and #1259. Since the render-hook pipeline is merged, I'd like to work on one of the gaps listed in the PR description:
Raw
<img>/<figure>tags in content (~35 images)These bypass
render-image.htmlbecause Goldmark never sees them, so they still ship as PNG. The recent Kanvas pages use<figure><img>heavily, so this affects them most.My plan is to add a shortcode that reuses the same processing as the render hook (resolve via the
assets/contentimgmount, encode WebP at q85, emit<picture>with the original as fallback). Then I'd migrate the existing raw tags to it. Before starting, I'd like to confirm two things:I checked the open PRs: only the modal accessibility ones (fix: make image modal keyboard accessible #1260, fix: make image modal keyboard accessible and manage focus #1274) touch the render hook, and none cover raw
<img>tags. Since I'd be extracting shared logic fromrender-image.html, I'll rebase after those land to avoid conflicts.hiyach28 commentedon Oct 14, 2026
Closing this as resolved by #1259: the investigation is done and option 1 (build-time WebP in the render hook, original kept as the
<picture>fallback) is merged.