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.jsonThis 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
| Prop | Type | Default | Description |
|---|---|---|---|
src | string | required | Extension-less projectName/name, e.g. "my-app/abc123xyz0-hero". |
alt | string | required | Alt text. Use the generate_alt MCP tool to backfill missing alts. |
width | number | required | Display width in pixels. |
height | number | required | Display height in pixels. |
priority | boolean | false | Sets loading="eager" and fetchpriority="high". Use for the largest above-the-fold image. |
placeholder | "blurhash" | "lqip" | "empty" | "blurhash" | Placeholder strategy. |
blurhash | string | — | Pre-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. |
fluid | boolean | false | Fill 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. |
quality | number | 80 | Compression 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. |
className | string | — | Extra classes merged onto the wrapping <div>. |
telemetry | boolean | false | When set, reports the page's LCP timing back to AuraImage. Powers the dashboard's per-page LCP chart. |
Placeholder strategies
| Strategy | How it works | When 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. |
lqip | Fetches a small, heavily compressed preview (lqip=true transform) before the full image. One extra image request. | When you want a sharper, photographic placeholder. |
empty | Renders 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.