Components
A drop-in image with a BlurHash placeholder and a drag-and-drop uploader, installed with the shadcn CLI and owned as source in your repo.
Rendering images is <AuraImage />. Accepting them is <AuraUploader />. Neither depends on the other, and both read your CDN base URL from NEXT_PUBLIC_AURA_CDN_URL.
Installing either one copies a single .tsx file into your repo. There is no @auraimage/react package to pin, and no component API you have to wait on us to extend — edit the file, delete half of it, restyle it; it's yours.
AuraImage
<AuraImage />https://cdn.auraimage.ai/my-project/w=1536,h=1024,q=80/demo/0049
A drop-in replacement for <img> that paints a placeholder on mount and crossfades into the full image once it decodes — the box is reserved from the start, so nothing reflows and the LCP element never flashes empty. The three placeholder modes — blurhash, lqip, and empty — trade payload against fidelity; the demo above switches between them live, and the URL under the frame is the exact request the component makes.
Transform options travel in the URL path, so a resize is a different URL rather than a different build. With the default format="auto" the extension is omitted entirely and the edge negotiates AVIF, WebP, or JPEG per request.
The w=1536,h=1024 above is not arbitrary: the edge rounds both dimensions up to a fixed dimension ladder, and those two values sit on it exactly. Ask for w=800,h=533 instead and you'd be served a 1024×768 box — larger than requested, and cropped to a different aspect ratio. Open the network tab and check this one; the URL under the frame is what arrives.
npx shadcn@latest add https://auraimage.ai/registry/image.jsonWrites components/aura/image.tsx, installs blurhash from npm, and pulls in the config module. No Next.js import and no Tailwind requirement.
AuraUploader
<AuraUploader />Drag-and-drop, click-to-browse, and paste-from-clipboard, backed by a multi-file queue: per-row thumbnail and progress bar, cancel and retry, drag-reorder of files still waiting, and a copy-URL pill on each finished row. Uploads run in parallel up to concurrency (default 8).
Bytes go straight from the browser to cdn.auraimage.ai. Your backend only mints a short-lived signature — it never proxies the file. The demo above signs through the shared demo project; in your app you'd pass project="my-app", a pre-computed signature, or your own getSignature function.
npx shadcn@latest add https://auraimage.ai/registry/uploader.jsonWrites components/aura/uploader.tsx and installs lucide-react, @auraimage/sdk, the shadcn cn() helper, and the config module. One command, nothing left to wire.
To see an uploaded image go straight into a transform pipeline, the home page pairs the same uploader with a live playground for width, quality, format, and fit.
Installing
The config module
Both components resolve the CDN origin through @/lib/config.public, which the registry installs alongside them as a dependency. You don't need to create it — but you should know what it is, because it's the one file you'll edit if your setup differs:
export const publicConfig = {
NEXT_PUBLIC_AURA_CDN_URL: (process.env.NEXT_PUBLIC_AURA_CDN_URL ?? '').replace(/\/+$/, '')
};That single field is all either component reads. On a bundler that doesn't expose process.env — Vite, where it's import.meta.env — change this line and both components follow.
From a URL
Every registry item has a stable JSON endpoint. This is the copy-paste form used above and it needs no configuration:
npx shadcn@latest add https://auraimage.ai/registry/image.json
npx shadcn@latest add https://auraimage.ai/registry/uploader.jsonAs a named registry
If you install from AuraImage more than once, register the namespace in your components.json and refer to items by short name:
{
"registries": {
"@aura": "https://auraimage.ai/registry/{name}.json"
}
}npx shadcn@latest add @aura/image @aura/uploaderWhat lands in your repo
| Item | Files written | npm packages installed |
|---|---|---|
image | components/aura/image.tsx, lib/config.public.ts | blurhash |
uploader | components/aura/uploader.tsx, lib/config.public.ts, lib/utils.ts | lucide-react, @auraimage/sdk, clsx, tailwind-merge |
Paths follow your components.json aliases, so the files land wherever the rest of your components live. Installing both items writes lib/config.public.ts once, not twice.
Requirements
- React 18 or newer. Both are client components (
'use client') built on hooks and plain DOM APIs. Neither imports fromnext/*, so they run under Vite or Remix as readily as Next.js — theNEXT_PUBLIC_prefix is a naming convention here, not a framework dependency. NEXT_PUBLIC_AURA_CDN_URLin your environment, read through the config module.aura initwrites it to.env.localalongside your project name and public key; see Getting Started. This is the only thing the installer can't do for you.- Tailwind CSS —
<AuraUploader />only, for its styling.<AuraImage />uses inline styles and passesclassNamestraight through, so it drops into any styling approach.
Why source instead of a package
A CDN component is exactly the kind of code you end up wanting to change: a different placeholder ramp, your own loading skeleton, an extra sizes attribute, a wrapper your design system already has. Shipping it as a dependency means every one of those is a feature request. Shipping it as source means it's a diff.
The tradeoff is upgrades: re-running the add command overwrites the file, so your edits are yours to reconcile. Both components are single files under 500 lines, which is the point — you can read the whole thing before you accept it.