Skip to content

Image

Drop-in <Image /> replacement with BlurHash placeholder and content-negotiated format.

<AuraImage /> is a Shadcn-registry component you copy into your project. It's a drop-in replacement for <img> that crossfades a BlurHash (or LQIP) placeholder into the full image, eliminating LCP jank.

Because it ships as source — not a binary dependency — you own the file and edit it freely.

Install

npx shadcn@latest add https://auraimage.ai/registry/image.json

This copies one file into src/components/aura/image.tsx. The component depends on blurhash (npm) for client-side hash decoding; shadcn installs it for you.

It reads your CDN base URL from NEXT_PUBLIC_AURA_CDN_URL (set during aura init).

Usage

import { AuraImage } from '@/components/aura/image';

export default function Hero() {
  return (
    <AuraImage
      src='my-app/abc123xyz0-hero'
      alt='Golden Gate Bridge at sunset'
      width={1200}
      height={800}
      priority
    />
  );
}

src is the full CDN path in extension-less projectName/name form. The name returned by upload is exactly the name part — combine it with your project name.

Props

PropTypeDefaultDescription
srcstringrequiredExtension-less projectName/name, e.g. "my-app/abc123xyz0-hero".
altstringrequiredAlt text. Use the generate_alt MCP tool to backfill missing alts.
widthnumberrequiredDisplay width in pixels.
heightnumberrequiredDisplay height in pixels.
prioritybooleanfalseSets loading="eager" and fetchpriority="high". Use for the largest above-the-fold image.
placeholder"blurhash" | "lqip" | "empty""blurhash"Placeholder strategy.
blurhashstringPre-computed hash. When set with placeholder="blurhash", the placeholder decodes locally and the GET /v1/blurhash/… round trip is skipped entirely. Upload returns this string — store it and pass it back.
fluidbooleanfalseFill the parent's width instead of rendering at a fixed pixel size. width / height still select the transform variant and set the box's aspect-ratio, so there's no layout shift either way.
qualitynumber80Compression quality (1–100). Maps to the q URL param.
fit"cover" | "contain" | "face" | "auto""cover"Crop / fit mode. Maps to the fit URL param.
format"auto" | "avif" | "webp" | "jpeg""auto"Output format. Maps to the serve-URL extension; "auto" emits no extension so the CDN negotiates the format.
classNamestringExtra classes merged onto the wrapping <div>.
telemetrybooleanfalseWhen set, reports the page's LCP timing back to AuraImage. Powers the dashboard's per-page LCP chart.

Placeholder strategies

StrategyHow it worksWhen to use
blurhash (default)Fetches GET /v1/blurhash/<projectName>/<name>, decodes the hash on the client, paints it into a canvas, crossfades into the full image. One small, cacheable request per image.Default. Highest fidelity for the bandwidth.
lqipFetches a small, heavily compressed preview (lqip=true transform) before the full image. One extra image request.When you want a sharper, photographic placeholder.
emptyRenders nothing until the full image loads.Small images, or when you have your own skeleton.

If placeholder="blurhash" is set and the blurhash fetch fails (network, malformed hash), the component automatically falls back to lqip — you always get a placeholder.

How it transforms URLs

<AuraImage /> builds the delivery URL from your props, with the transform options in the path segment and src already in project/name form:

${NEXT_PUBLIC_AURA_CDN_URL}/${project}/w=${width},h=${height},q=${quality}/${name}

fit is added to the transform segment only when it isn't the default cover, and the format is expressed by the trailing extension — omitted entirely for format="auto" so the CDN negotiates AVIF/WebP/JPEG per request. When src, width, format, or fit change, the component resets its loaded state so the new variant fades in fresh — no stale frame stays on screen during the swap.

Pick width and height off the ladder

Because width and height are both required, the component always emits w=…,h=… — and the edge rounds each one up to the dimension ladder independently. width={800} height={533} asks for 3:2 but is delivered as a 1024×768 box, which fit="cover" crops to fill.

The delivered image is never smaller than you asked for, so this is a bandwidth and cropping question rather than a quality one. To avoid both, choose a pair that already sits on rungs — 1536×1024, 1024×1024, and 768×512 all pass through untouched. The ladder is 64, 128, 256, 512, 768, 1024, 1536, 2048, 3072, 4096.

See the URL API for the full param reference.