Skip to content

add: opt-in BlurHash placeholder - #8

Merged
lxsmnsyc merged 3 commits into
mainfrom
blurhash-placeholder
Sep 13, 2026
Merged

lxsmnsyc merged 3 commits into
mainfrom
blurhash-placeholder

Conversation

@lxsmnsyc

@lxsmnsyc lxsmnsyc commented Sep 13, 2026

Copy link
Copy Markdown
Member

Summary

Adds a BlurHash preview as an alternative to the inline image preview. It is
off by default, and blurhash is an optional peer dependency that apps install
only when they turn it on.

Changes

  • Set placeholder: { type: "blurhash" } in the plugin to use a BlurHash
    instead of the 20px inline image. The inline image stays the default.
  • There is nothing else to configure. The number of components is picked per
    image from its aspect ratio, about 12 in total. The long side gets more, so
    portraits and landscapes keep even detail. A 4:3 image gets the usual 4 by 3.
  • blurhash is listed as an optional peer dependency. The plugin loads it with a
    dynamic import.
  • The plugin checks for blurhash when the build starts. If it is missing, the
    dev server or build stops with install steps instead of failing on the first
    image.
  • The plugin encodes an upright copy of the image that fits inside 32px, and
    ships the hash with the average color.
  • The generated module imports decode from blurhash only when the option is
    on. The component never imports the package, so apps without it are
    unaffected.
  • The server paints the average color, since decoding needs a canvas. The
    browser decodes the hash into a 32px wide canvas at the image's aspect ratio
    and paints it over that color.
  • The preview is removed once the image loads, the same as the inline image
    preview.
  • Remote images can return { hash, color } from transformURL. The plugin
    adds the decoder for them.

How it was tested

  • pnpm test runs 152 tests across both projects and they pass.
  • Component picking is checked for landscape, 16:9, square, portrait, panorama,
    banner and strip shapes, and counts stay within 1 to 9.
  • Plugin tests confirm the module ships a valid hash, imports the decoder, and
    reports the average color. A portrait gets 3 by 5 components and a 10:1
    banner gets 9 by 1.
  • Plugin tests confirm the default preview and remote images without a hash
    never import blurhash.
  • A plugin test mocks a missing blurhash and checks that the build fails at
    startup with the install message.
  • Encoder tests confirm the base color stored in the hash equals the reported
    average color, the image is reduced to fit inside 32px, and a rotated photo is
    hashed upright.
  • A server rendering test confirms only the average color is painted and the
    decoder is never called.
  • A browser test confirms the hash is decoded at 32 by 18 for a 16:9 image,
    painted before the image loads, and removed once it loads.
  • pnpm build succeeds. dist/vite.js keeps import("blurhash") external, and
    dist/index.jsx does not reference the package.
  • tsc --noEmit reports one pre-existing error in src/vite/fs.ts, unrelated to
    this change.

Notes for review

main was merged in after #7 landed. The BlurHash sample calls .autoOrient(),
like the variants and the inline preview.

🤖 Generated with Claude Code

- Set placeholder: { type: "blurhash" } in the plugin to use a BlurHash instead of the inline image preview.
- blurhash is an optional peer dependency, loaded with a dynamic import and checked when the build starts.
- The generated module imports decode only when the option is on. The component never imports blurhash.
- The server paints the average color. The browser decodes the hash into a small canvas.
- Remote images can return { hash, color } from transformURL.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@socket-security

socket-security Bot commented Sep 13, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedblurhash@​2.0.51001009185100

View full report

@pkg-pr-new

pkg-pr-new Bot commented Sep 13, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/@solidjs/image@8

commit: 9ee0223

lxsmnsyc and others added 2 commits September 13, 2026 22:48
- Pass the configured sizes to getImageSource, so the source uses the largest real width from main.
- Keep the publicDir default from main next to the placeholder resolution.
- Turn the BlurHash sample upright with autoOrient, matching the variants and the inline preview.
- Keep the tests from both sides, and add a test for a rotated photo hash.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- Drop the componentX and componentY options. The whole config is placeholder: { type: "blurhash" }.
- Split a budget of about 12 components by aspect ratio, so the long side gets more and detail stays even.
- A 4:3 image still gets 4 by 3, the usual default.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@lxsmnsyc
lxsmnsyc merged commit f6bdade into main Sep 13, 2026
5 checks passed
@lxsmnsyc
lxsmnsyc deleted the blurhash-placeholder branch September 13, 2026 15:01
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