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-sharp and gatsby-transformer-sharp (gatsby-config.js), backed by sharp
gatsby-plugin-image renders 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] in hugo.toml sets only resampleFilter, quality and anchor, 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 and static/ paths, and static/ files are not resources, so those would have to move under assets/ 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 under assets/ 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?
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 resultsOn 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 asrcsetand a fallback. The repo's_headersalso sets caching rules for/*.webp. Committed.webpfiles 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:
layouts/_default/_markup/render-image.html, which emits a plain<img>with the source path untouched<figure><img>blocks in content are passed straight through[imaging]inhugo.tomlsets onlyresampleFilter,qualityandanchor, which nothing currently exercisesContent inventory: 361 PNG, 71 GIF, 47 SVG, plus images under
static/.Options to evaluate
.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.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
static/images move underassets/so Hugo can process them, and what breaks if their public paths change?_headers, or is that Netlify-only?<picture>fallback wanted, or is WebP-only acceptable given current browser support?