Skip to content
Inputs

AI Image

A picture made from a sentence — the frame, the prompt bar, the wait and the picture, wired to whichever model you have.

Walkthrough

1. Basic

One prop. mockGenerate() stands in for a model on this page; in an app, endpoint('/api/image') points it at a route of yours and the rest is the same — the bar, the chips, the spinner while it works, the toolbar.

Describe the picture you want

Type a prompt below, or start from one of these.

<script lang="ts">	import { AiImage, mockGenerate } from 'omaris';</script>​<AiImage	generate={mockGenerate()}	suggestions={[		'A lighthouse at dusk, oil on canvas',		'Isometric city block, pastel',		'A fox in a raincoat, studio photo'	]}	class="max-w-lg"/>

2. States

The wait and the result, side by side. While the model works the frame is its own surface with one spinner in the middle; when the picture has loaded it fades in. The one on the right makes its picture on mount; its regenerate button runs the wait again over it.

Describe the picture you want

Describe the picture you want

<script lang="ts">	import { AiImage, mockGenerate } from 'omaris';</script>​<div class="grid max-w-2xl gap-4 sm:grid-cols-2">	<AiImage		generate={mockGenerate({ delay: 60_000, progress: false, partial: false })}		prompt="A lighthouse at dusk, oil on canvas"		auto		composer="none"		aspect="4:3"	/>	<AiImage		generate={mockGenerate({ delay: [1800, 2600] })}		prompt="A fox in a raincoat, studio photo"		auto		composer="none"		tools={['regenerate']}		aspect="4:3"	/></div>

3. Auto

A picture with nothing to press. A prompt and auto make it on mount and again whenever the prompt changes; no bar, no tools, a wide shape and a ghost frame — a hero image, a product placeholder, a playlist cover.

Describe the picture you want

<script lang="ts">	import { AiImage, mockGenerate } from 'omaris';​	let mood = $state('calm');</script>​<div class="flex max-w-2xl flex-col gap-3">	<AiImage		generate={mockGenerate({ delay: [900, 1600] })}		prompt="Abstract cover art for a {mood} playlist"		auto		composer="none"		tools={[]}		aspect="21:9"		variant="ghost"	/>	<div class="flex flex-wrap gap-2">		{#each ['calm', 'late night', 'sunday morning', 'road trip'] as option (option)}			<button				type="button"				class="h-8 rounded-full border border-border px-3 text-sm text-foreground transition-colors duration-150 ease-standard hover:bg-surface-container-high aria-pressed:border-primary aria-pressed:bg-primary-container aria-pressed:text-primary-container-foreground motion-reduce:transition-none"				aria-pressed={mood === option}				onclick={() => (mood = option)}			>				{option}			</button>		{/each}	</div></div>

4. Grid

Four at once. count tiles the results in the frame; tap one to keep it. history keeps every result on a strip, and viewer opens the one on show full-screen. bind:images is the whole session, newest first.

Describe the picture you want

Type a prompt below, or start from one of these.

<script lang="ts">	import { AiImage, mockGenerate, type AiImageItem } from 'omaris';​	let images = $state<AiImageItem[]>([]);</script>​<AiImage	generate={mockGenerate({ delay: [1200, 2200] })}	count={4}	aspect="4:3"	history	viewer	bind:images	suggestions={['Four takes on a lighthouse', 'Logo ideas for a bakery']}	class="max-w-xl"/>

5. Edit

Editing. attach puts a paperclip in the bar so a person can drop a picture in; the edit tool on a result feeds it back in as the reference for the next prompt. Either way the generator is handed reference — Gemini and OpenAI both take one and change the picture rather than starting over.

Describe the picture you want

Type a prompt below, or start from one of these.

<script lang="ts">	import { AiImage, mockGenerate } from 'omaris';</script>​<AiImage	generate={mockGenerate()}	attach	aspect="3:2"	placeholder="Describe the picture, or attach one and say what should change…"	suggestions={['A red bicycle against a white wall']}	class="max-w-lg"/>

6. Headless

Your own controls. composer="none" takes the bar away; bind:this gives you generate(), cancel(), clear() and download(), and bind:status says where it is. The frame keeps the spinner — offer your own stop, as here, since the frame has none.

Nothing made yet

<script lang="ts">	import { AiImage, Button, Input, Select, mockGenerate, type AiImageStatus } from 'omaris';​	let frame = $state<AiImage | null>(null);	let prompt = $state('A paper boat on a puddle, macro');	let aspect = $state<'1:1' | '16:9' | '9:16'>('16:9');	let status = $state<AiImageStatus>('idle');</script>​<div class="flex max-w-lg flex-col gap-3">	<AiImage bind:this={frame} bind:status generate={mockGenerate()} composer="none" {aspect} />	<form		class="flex flex-wrap items-end gap-2"		onsubmit={(event) => {			event.preventDefault();			void frame?.generate(prompt);		}}	>		<Input label="Prompt" bind:value={prompt} class="min-w-48 flex-1" />		<Select			label="Shape"			bind:value={aspect}			options={[				{ value: '1:1', label: 'Square' },				{ value: '16:9', label: 'Wide' },				{ value: '9:16', label: 'Tall' }			]}			class="w-32"		/>		{#if status === 'generating'}			<Button type="button" variant="tonal" onclick={() => frame?.cancel()}>Stop</Button>		{:else}			<Button type="submit" disabled={!prompt.trim()}>Make it</Button>		{/if}	</form></div>

7. Server

The real wiring. The key stays on the server: endpoint() posts the prompt to a route of yours, and the route makes the picture. With omaris/ai and the Vercel AI SDK the route is two lines, and switching models is switching the import: ``ts // src/routes/api/image/+server.ts import { imageRoute } from 'omaris/ai'; import { google } from '@ai-sdk/google'; // or: import { openai } from '@ai-sdk/openai'; export const POST = imageRoute({ model: google.image('imagen-4.0-generate-001') }); ` Without the SDK, gemini() and openaiImages() from omaris talk to those APIs directly and also take a reference picture to edit: `ts import { gemini } from 'omaris'; import { GEMINI_API_KEY } from '$env/static/private'; const generate = gemini({ apiKey: GEMINI_API_KEY }); export async function POST({ request }) { const images = await generate(await request.json(), { signal: request.signal, progress() {}, partial() {}, status() {} }); return Response.json(images); } ``

Describe the picture you want

Type a prompt below and press Enter.

<script lang="ts">	import { AiImage, endpoint } from 'omaris';</script>​<AiImage generate={endpoint('/api/image')} aspect="16:9" class="max-w-lg" />

8. Overridden

Every part is reachable. classes names the slots, class covers the root and wins last, the copy is plain strings, height replaces the aspect, and the loading snippet replaces the spinner — here with the provider's progress, which the default wait leaves out.

Album art

Say the mood, not the subject.

<script lang="ts">	import { AiImage, Text, mockGenerate } from 'omaris';</script>​<AiImage	generate={mockGenerate({ delay: [2500, 4000] })}	tone="tertiary"	height={220}	title="Album art"	hint="Say the mood, not the subject."	placeholder="Moody, warm, a little grainy…"	generateLabel="Paint"	class="max-w-md"	classes={{		frame: 'rounded-shape-2xl border-2 border-dashed border-tertiary/40',		composer: 'rounded-full bg-tertiary-container/40',		emptyIcon: 'bg-tertiary text-tertiary-foreground'	}}>	{#snippet loading({ progress })}		<div			class="grid size-full place-items-center bg-tertiary-container text-tertiary-container-foreground"		>			<Text variant="label-lg" tabular>{Math.round(progress ?? 0)}%</Text>		</div>	{/snippet}</AiImage>