Photo Mosaic
A hero collage of photos with a few tags, to set the scene for a trip, a dish or a place.
≈ 775 tokens per use (tool 406 · guidance 220 · typical payload 149)How token costs are estimated
Example: Photo Mosaic
Plan a 10-day Pacific Northwest road trip
Your 10-day Pacific Northwest road trip
- 10 days
- Road trip
- Nature + cities
When to use
- Opening a plan or an answer that is visual by nature: a trip, a dish, a place, an event, a venue.
- The agent has 1–5 real photos from a search or tool result.
When not to use
- The agent doesn't have real image URLs. It must never invent or guess them.
- The user wants to browse or pick from many photos. Use a Slide Gallery.
- Each image is an option with its own title. Use Inspiration Cards.
How the agent should use it
- Use it once, at the top of the reply. It sets the scene; the details follow in text or other components.
- Take every image
srcfrom a tool result or the host, never from memory. Only http(s) URLs anddata:image/(png|jpeg|webp|svg+xml)load. - Put the strongest photo first. It becomes the hero.
- Write real alt text that says what each photo shows. It's required.
- Keep tags to a few words each, at most 5, and only facts from the plan ("10 days", "Road trip").
- Lifecycle: photos are a snapshot, so it usually needs none. If
srcvalues are signed URLs that expire, setexpiresAtto their expiry. When the agent replaces the plan, mark the old call superseded (supersededBy).
Layouts
The layout follows the number of photos. The whole mosaic is about 16:9 (aspect: "wide", a little taller on phones when there are three or more photos) or square (aspect: "square").
| Photos | Layout |
|---|---|
| 1 | One wide photo |
| 2 | Side by side |
| 3 | A hero on the left (about 60%) and two stacked on the right |
| 4 | A hero and three: one wide over two small |
| 5 | Two over three |
Interaction
- Enlarge: clicking a photo opens it in a lightbox (a native
<dialog>), with its caption below. Captions appear only there, never on the mosaic. The previous and next buttons and the arrow keys move between photos, and moves are announced politely ("Photo 2 of 5: …"). Escape, Close or a click on the backdrop returns focus to the photo that opened it. - Broken images: a photo that fails to load, or whose
srcisn't allowed, becomes a neutral tile showing its alt text. - Streaming: the three-photo layout shows placeholders from the first token, and photos fill in as they arrive. Photos load lazily.
Installation
npx shadcn@latest add https://your-site.com/r/photo-mosaic.json
Usage
The Photo Mosaic is display-only, so the tool can return immediately:
import { tool } from "ai"
import { photoMosaicTool } from "@/components/genui/photo-mosaic.schema"
const tools = {
[photoMosaicTool.name]: tool({
description: photoMosaicTool.description,
inputSchema: photoMosaicTool.inputSchema,
execute: async () => ({ shown: true }),
}),
}Render it through the Renderer under show_photos, or directly:
<PhotoMosaic
{...part.input}
status={part.state === "input-streaming" ? "streaming" : "ready"}
onResult={track}
/>onResult is optional and for analytics only. It fires each time a photo is enlarged, never locks the mosaic, and the agent doesn't need to answer it:
{ action: "open", index: 0 } // zero-basedWith LangGraph
Push it from a graph node with ui.push({ name: "show_photos", props }, { message }), and render the thread's UI messages with the Renderer.
Schema
| Prop | Type | Notes |
|---|---|---|
title | string? | e.g. "Your 10-day Pacific Northwest road trip" |
aspect | "wide" | "square" | Shape of the whole mosaic. Default "wide" (about 16:9) |
images | { src, alt, caption? }[] | 1–5 photos, the hero first. src is data-bound; caption shows only in the lightbox |
tags | string[]? | Up to 5 short chips, up to 24 characters each |
Host props: status (streaming or ready), onResult and className.