Images
A landing page can carry up to nine images: a hero, up to six feature icons, a CTA background, and a dedicated OG share card. You can AI-generate them or upload your own.
Image slots
| Slot | Aspect | Size | Source |
|---|---|---|---|
| Hero | 16:9 | 2K (~1920×1080) | AI or upload |
| Feature icons (×2–6) | 1:1 | 1K (~1024×1024) | AI-generated during initial flow |
| CTA background | 16:9 | 2K | AI or upload |
| OG share card | 16:9 | 2K | AI-generated during initial flow |
Gemini Nano Banana
We use Google's Gemini 2.5 Flash Image (codename "Nano Banana") for every AI image. The SDK's imageConfig lets us pin the aspect ratio and render size per slot, and we reinforce the same intent in the prompt text. Style-consistent across multiple images thanks to Nano Banana's strength at preserving accent color and composition.
Batch generation
During the signup / new-page wizard, once the AI text finishes, we kick off all missing images in parallel via /api/landing-pages/[id]/enrich-images. Hero, feature icons, CTA background, and OG card all run concurrently so total image generation takes roughly the slowest single call, not the sum. Partial failures don't block - whatever succeeds gets written.
WebP transcoding
Whatever the AI returns (PNG today) gets re-encoded as WebP at quality 82 before storage. User uploads pass through the same pipeline. The result is dramatically smaller files with no visible quality loss - better LCP and lower bandwidth.
Uploading your own image
Every image slot that supports AI generation also supports upload:
- Open the landing page editor.
- Find the hero or CTA section.
- Click ⬆ Upload.
- Pick a JPEG, PNG, WebP, or GIF from your computer.
- It gets compressed to WebP (max 1920px, ≤450 KB) before upload.
- Hit Save to persist and recompile.
Dedupe + limits
Every AI-generation prompt is hashed - identical prompts under the same page reuse the cached WebP object. Hard cap: 30 images per user per day across all AI paths; upload doesn't count.
Fallback
If the Gemini call errors or times out (>10 s), the slot falls back to an Unsplash image matched to the prompt keywords so your page still has a visual. Worth re-generating once later if you want a brand-matched image.
How images ship to the visitor
- Stored in R2 at
landing-images/{userId}/{pageId}/{slot}-{hash}.webp. - Served by
/api/images/[...key]withCache-Control: max-age=31536000, immutable. - Hero is preloaded via
<link rel="preload">before the HTML parse finishes - huge LCP win. - Below-the-fold images are
loading="lazy". - Intrinsic width/height attrs keep cumulative layout shift at zero.