Generate a grid
Run a Technique with N outputs and render them as a grid.
The most common FLORA API workflow: take a brief, run a Technique, get back multiple variants. The “3×3 grid” is the canonical shape.
What you’ll build: a script that runs thumbnail-v3 with a brief and returns 9 image URLs.
TypeScript
Section titled “TypeScript”import Flora from '@flora-ai/flora';
const client = new Flora({ apiKey: process.env.FLORA_API_KEY });
async function generateGrid(brief: string, count = 9) { const technique = await client.techniques.retrieve('thumbnail-v3'); console.log(`Cost per output: ${technique.runCost} credits × ${count}`);
const run = await client.techniques.runs.create('thumbnail-v3', { inputs: [ { id: 'prompt', type: 'text', value: brief }, { id: 'count', type: 'text', value: String(count) }, ], mode: 'async', });
return pollUntilDone(run.runId, 'thumbnail-v3');}
async function pollUntilDone(runId: string, slug: string) { while (true) { const result = await client.techniques.runs.retrieve(runId, { techniqueId: slug }); if (result.status === 'completed') return result.outputs.map((o: any) => o.url); if (result.status === 'failed') throw new Error(result.errorMessage); await new Promise((r) => setTimeout(r, 2000)); }}
const urls = await generateGrid( 'Smart living, simple. Audience 25-40, design-conscious. Warm minimalism, soft shadows. No clip-art, no gradients.');
console.log(urls);package main
import ( "context" "fmt" "log" "os" "time"
"github.com/florafauna-ai/flora-go" "github.com/florafauna-ai/flora-go/option")
func generateGrid(ctx context.Context, c *flora.Client, brief string, count int) ([]string, error) { run, err := c.Techniques.Runs.New(ctx, "thumbnail-v3", flora.TechniqueRunNewParams{ Inputs: []flora.TechniqueRunNewParamsInput{ {ID: "prompt", Type: "text", Value: brief}, {ID: "count", Type: "text", Value: fmt.Sprint(count)}, }, Mode: flora.TechniqueRunNewParamsModeAsync, }) if err != nil { return nil, err }
for { result, err := c.Techniques.Runs.Get(ctx, run.RunID, flora.TechniqueRunGetParams{ TechniqueID: "thumbnail-v3", }) if err != nil { return nil, err } switch result.Status { case "completed": urls := make([]string, 0, len(result.Outputs)) for _, o := range result.Outputs { urls = append(urls, o.URL) } return urls, nil case "failed": return nil, fmt.Errorf("run failed: %s", result.ErrorMessage) } time.Sleep(2 * time.Second) }}
func main() { ctx := context.Background() client := flora.NewClient(option.WithAPIKey(os.Getenv("FLORA_API_KEY")))
urls, err := generateGrid(ctx, client, "Smart living, simple. Warm minimalism.", 9) if err != nil { log.Fatal(err) } for _, u := range urls { fmt.Println(u) }}#!/usr/bin/env bashset -euo pipefail
BRIEF="Smart living, simple. Warm minimalism."COUNT=9
RUN_ID=$(flora techniques:runs create \ --technique-id thumbnail-v3 \ --input "{id: prompt, type: text, value: '$BRIEF'}" \ --input "{id: count, type: text, value: '$COUNT'}" \ --mode async \ --jq '.runId' -r)
while true; do STATUS=$(flora techniques:runs retrieve \ --technique-id thumbnail-v3 \ --run-id "$RUN_ID" \ --jq '.status' -r)
case "$STATUS" in completed) break ;; failed) echo "run failed"; exit 1 ;; *) sleep 2 ;; esacdone
flora techniques:runs retrieve \ --technique-id thumbnail-v3 \ --run-id "$RUN_ID" \ --jq '.outputs[].url' -rDisplay the grid
Section titled “Display the grid”In a Node/browser app, render the URLs as an HTML grid:
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: '8px' }}> {urls.map((url) => ( <img key={url} src={url} alt="" loading="lazy" /> ))}</div>Save the grid as files
Section titled “Save the grid as files”import fs from 'node:fs/promises';import path from 'node:path';
async function downloadAll(urls: string[], dir: string) { await fs.mkdir(dir, { recursive: true }); await Promise.all( urls.map(async (url, i) => { const res = await fetch(url); const buf = Buffer.from(await res.arrayBuffer()); await fs.writeFile(path.join(dir, `tile_${i}.png`), buf); }) );}
await downloadAll(urls, './out/q3-grid');Variations
Section titled “Variations”- Aspect ratio: many Techniques accept
aspect_ratioas an input. Add{ id: 'aspect_ratio', type: 'text', value: '1:1' }. - Reference image: pass an image URL as a Technique input — see Iterate on outputs.
- Different counts: not all Techniques support N>1. Check
technique.outputsshape afterretrieve— if it returns a single output, run the Technique N times in parallel instead.
- Pre-check the cost with
retrievebefore kicking off — cost =runCost × count(orrunCost × N runsfor serial calls). - Output URLs are long-lived but not permanent. Download anything you need to keep.
- For batches >10, switch to a batch pattern with idempotency keys.
Related
Section titled “Related”- Iterate on outputs — re-run with chosen outputs as references.
- Upload an asset — use your own image as a Technique input.
- Batch from a CSV — many runs across structured input.