@60fps/ui-image v0.0.1

Image

Describe an image once. Get the srcset, sizes and <source> tags the browser needs to download the right file for every screen.

Any backend

You write the URL your CDN or CMS expects. No adapters.

Resizes if needed

No image service? sharp does it: at build time or on request.

Any framework

Returns plain data for React, Vue, Astro, or plain HTML.

Installation#

No dependencies. Add sharp only if the library should resize images itself (project files, sharp).

Quick start#

  1. Point to the image

    Put {width} where your server expects the size. Give the original size so nothing is upscaled and the layout doesn't jump.

  2. Say how wide it's displayed

    The browser picks a file before the page is laid out, so it needs to know the display width. That's sizes.

  3. Render it

Result:

Set defaults once for the whole project:

How it works#

A phone downloads a small file and a 4K screen downloads a large one, from the same HTML. Try it: change the preset, sizes, or resize the window.

Formats
Edit the URL
Candidates
    Generated HTML

    Where do your images come from?#

    For a choice of files, something has to produce each size. Find your case and follow its recipe:

    URL template

    Your image service already resizes. Write its URL with tokens where the values go. The library fills them in for each width and format.

    Tokens: {width}, {height}, {format}, {quality}, {name|default}. All tokens →

    Image proxy

    The URLs are plain (photo.jpg, no size in them), but your host resizes on the fly. Set a proxy: a template where {src} is the original URL.

    Project files

    Images live in your code (src/assets). Add ?responsive to the import, and the Vite plugin makes every size with sharp. The dev server generates them on the fly. The build writes them as hashed files.

    Per image: ./hero.jpg?widths=400;800&formats=webp&responsive. For types, add /// <reference types="@60fps/ui-image/client" />.

    Resize with sharp

    Plain URLs, and no image service at all. sharp does the resizing, in one of two ways:

    At build or render time

    Static sites, SSR. Files are written to a folder.

    On request

    Any page, even rendered in the browser. Like Astro's /_image.

    The endpoint only reads files inside roots, and remote hosts must be listed in domains. It isn't an open proxy.

    Astro

    Astro already resizes with its own getImage. Hand it the work:

    Sizes & breakpoints#

    Describe sizes per breakpoint, with the same numbers as your CSS. The library writes the media queries in the right order.

    Breakpoints are Tailwind's by default. Use your own:

    A wrong sizes costs you

    Too big and the browser downloads too much. Too small and the image is blurry. Try both in the demo.

    Art direction#

    A different crop per screen size, not just a different resolution. Each entry becomes a <source media> with its own width and height.

    Good to know#

    • Above the fold? Use priority for the hero image:
    • Shrinking the window doesn't switch to a smaller file. Browsers keep the bigger image they already have. Test small sizes with a fresh reload.
    • Only list formats your server can make. The browser picks a <source> by type, and doesn't fall back if that file fails. (Public wsrv.nl has no AVIF, for example.)
    • Changed the Vite plugin config? Restart the dev server or Storybook: plugins are only read at startup.
    • Built in: never upscales, skips variants with a different crop, and sets width/height so the layout doesn't shift.
    Next API reference Every option, token and function →