Skip to content
FLORA DocsGo to app

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.

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.run_cost.toFixed(2)} × ${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.run_id, '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.error_message);
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);
#!/usr/bin/env bash
set -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 '.run_id' -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 ;;
esac
done
flora techniques:runs retrieve \
--technique-id thumbnail-v3 \
--run-id "$RUN_ID" \
--jq '.outputs[].url' -r

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>
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');
  • Aspect ratio: many Techniques accept aspect_ratio as 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.outputs shape after retrieve — if it returns a single output, run the Technique N times in parallel instead.
  • Pre-check the cost with retrieve before kicking off — total = run_cost × count in USD (or run_cost × N runs for 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.