Skip to Content
AIImage Generation

Image generation

The Create tab generates an image from your prompt, style and aspect ratio. It uses the generate edge function.

Add a style preset to the Create tab in this project. Add it to stylePresets in supabase/functions/_utils/ai.config.json, then redeploy generate.
The Create tab showing a prompt field, style preset chips, aspect ratio chips, a Generate button, and the Pro-required upgrade state below

Change presets, ratios or the model

To changeEditThen
Style presetsstylePresets in ai.config.jsonRedeploy generate
Aspect ratiosaspectRatios in ai.config.jsonRedeploy generate
The modelgenerateModel in ai.config.jsonRedeploy generate

All three are defined in one file, supabase/functions/_utils/ai.config.json, which config.js also reads. The client sends the user’s prompt and the selected style and aspect-ratio IDs. The function looks up the prompt suffixes for those IDs in the shared file. An unknown ID contributes an empty suffix, so redeploy after adding a preset or ratio.

Adding a style preset

Add it to ai.config.json

supabase/functions/_utils/ai.config.json
{ "id": "noir", "label": "Noir", "promptSuffix": ", black and white film noir, hard shadows, high contrast" }

Redeploy

supabase functions deploy generate

Verify

Check that the new chip appears and test it with a prompt. If its suffix seems to have no effect, confirm that the ID matches and that generate was redeployed.

Changing the model

Change the image generation model in this project. Update generateModel in supabase/functions/_utils/ai.config.json, then redeploy generate.

Pick a slug from openrouter.ai/models  whose output modalities include image, then redeploy:

supabase/functions/_utils/ai.config.json
"generateModel": "google/gemini-3.1-flash-image"

Gotchas

Without REVENUECAT_SECRET_KEY, the server cannot confirm Pro status and refuses generation for every user. See Secrets.

Aspect ratios are approximate. The function adds the ratio to the prompt as text; it does not request exact pixel dimensions.

Generations require Pro and do not count toward the monthly chat and scan allowance. See Quota and paywall.

Error codes

CodeHTTPMeaning
invalid_request400The prompt is empty or the request body has the wrong shape.
unauthorized401The Supabase access token is missing or invalid.
pro_required403Not a Pro user, or REVENUECAT_SECRET_KEY is unset.
no_image502The model replied without an image.
provider_not_configured500OPENROUTER_API_KEY isn’t set.
internal_error500An unexpected server or provider error. Check the function logs.

Files

      • create.tsx - Create route
      • CreateScreen.tsx - Create screen
      • generateImage.ts - Request and response types
      • repository.ts - Generation queries
        • StylePresetChips.tsx - Style selection
        • AspectRatioChips.tsx - Ratio selection
        • GenerationResultCard.tsx - Result display
        • generations.ts - Gallery queries and the generate mutation
    • index.ts - Generation handler

How it works

generateImage() accepts prompt, style and aspectRatio strings. It sends a non-streaming request and returns the saved image’s path, its row id, and the prompt, model, style, aspect ratio and creation time. The image bytes are uploaded to Storage rather than returned in the response.

The generations table is owner-scoped by row-level security. Images are stored as paths rather than signed URLs, because signed URLs expire, and get signed again on demand when the gallery renders.

Last updated on