Files
blog/image-generation-fal.html
T

333 lines
19 KiB
HTML
Raw Normal View History

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Image Generation at Every Price Point with fal.ai — Tinqs Blog</title>
<meta name="description" content="We generate concept art, logos, icons, and trailer frames through a single API proxy. Here's how we pick between 12 models spanning $0.002 to $0.09 per image.">
<meta name="robots" content="index, follow">
<link rel="canonical" href="https://www.tinqs.com/blog/image-generation-fal">
<meta property="og:type" content="article">
<meta property="og:url" content="https://www.tinqs.com/blog/image-generation-fal">
<meta property="og:title" content="Image Generation at Every Price Point with fal.ai">
<meta property="og:description" content="One proxy, 12 models, $0.002 to $0.09 per image. How we pick.">
<meta property="og:image" content="https://www.tinqs.com/img/og-cover.jpg">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Image Generation at Every Price Point with fal.ai">
<meta name="twitter:description" content="One proxy, 12 models, $0.002 to $0.09 per image. How we pick.">
<meta name="twitter:image" content="https://www.tinqs.com/img/og-cover.jpg">
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BlogPosting",
"headline": "Image Generation at Every Price Point with fal.ai",
"datePublished": "2026-05-25",
"author": {
"@type": "Person",
"name": "Ozan Bozkurt"
},
"publisher": {
"@type": "Organization",
"name": "Tinqs Limited",
"url": "https://www.tinqs.com"
},
"description": "We generate concept art, logos, icons, and trailer frames through a single API proxy. Here's how we pick between 12 models spanning $0.002 to $0.09 per image."
}
</script>
<!-- PostHog (EU) -->
<script>
!function(t,e){var o,n,p,r;e.__SV||(window.posthog=e,e._i=[],e.init=function(i,s,a){function g(t,e){var o=e.split(".");2==o.length&&(t=t[o[0]],e=o[1]),t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}}(p=t.createElement("script")).type="text/javascript",p.crossOrigin="anonymous",p.async=!0,p.src=s.api_host.replace(".i.posthog.com","-assets.i.posthog.com")+"/static/array.js",(r=t.getElementsByTagName("script")[0]).parentNode.insertBefore(p,r);var u=e;for(void 0!==a?u=e[a]=[]:a="posthog",u.people=u.people||[],u.toString=function(t){var e="posthog";return"posthog"!==a&&(e+="."+a),t||(e+=" (stub)"),e},u.people.toString=function(){return u.toString(1)+".people (stub)"},o="init capture register register_once register_for_session unregister unregister_for_session getFeatureFlag getFeatureFlagPayload isFeatureEnabled reloadFeatureFlags updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures on onFeatureFlags onSessionId getSurveys getActiveMatchingSurveys renderSurvey canRenderSurvey getNextSurveyStep identify setPersonProperties group resetGroups setPersonPropertiesForFlags resetPersonPropertiesForFlags setGroupPropertiesForFlags resetGroupPropertiesForFlags reset get_distinct_id getGroups get_session_id get_session_replay_url alias set_config startSessionRecording stopSessionRecording sessionRecordingStarted captureException loadToolbar get_property getSessionProperty createPersonProfile opt_in_capturing opt_out_capturing has_opted_in_capturing has_opted_out_capturing clear_opt_in_out_capturing debug".split(" "),n=0;n<o.length;n++)g(u,o[n]);e._i.push([i,s,a])},e.__SV=1)}(document,window.posthog||[]);
posthog.init('phc_teG6p5oxf6poQHPThq5AGKzWQNhw4bHW9arLwWAVXm3f',{api_host:'https://eu.i.posthog.com',ui_host:'https://eu.posthog.com',person_profiles:'identified_only',defaults:'2026-01-30'})
</script>
<link rel="icon" type="image/svg+xml" href="/img/favicon.svg">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;1,300;1,400;1,500;1,600;1,700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="../style.css">
2026-06-02 22:50:20 +01:00
<style>
/* ── Team guide aesthetic: self-contained overrides ── */
/* ── Gradient title (amber → warm gold, hint of blue) ── */
.post__title {
background: linear-gradient(90deg, #c9935a, #f59e0b 40%, #38bdf8);
-webkit-background-clip: text;
background-clip: text;
color: transparent;
font-weight: 800;
}
/* ── Date pill ── */
.post__date {
display: inline-block;
font-family: ui-monospace, 'SF Mono', 'Cascadia Code', Consolas, monospace;
font-size: 0.72rem;
letter-spacing: 0.22em;
text-transform: uppercase;
color: #38bdf8;
border: 1px solid rgba(147, 140, 129, 0.25);
border-radius: 999px;
padding: 4px 14px;
margin-bottom: 16px;
}
/* ── Lead ── */
.post__lead {
color: #9aa7b4;
font-size: 1.08rem;
line-height: 1.7;
}
/* ── H2: left accent bar ── */
.post__body h2 {
font-size: 1.7rem;
margin: 54px 0 6px;
padding-left: 16px;
border-left: 4px solid #c9935a;
}
/* ── H3: purple secondary accent ── */
.post__body h3 {
color: #a855f7;
font-size: 1.18rem;
margin: 30px 0 4px;
}
/* ── Inline code ── */
.post__body code {
font-family: ui-monospace, 'SF Mono', 'Cascadia Code', Consolas, monospace;
font-size: 0.86em;
background: #1c2230;
color: #9fe6c0;
padding: 2px 6px;
border-radius: 5px;
border: 1px solid #2a3340;
}
/* ── Code blocks (dark panel) ── */
.post__body pre {
background: #0a0e14;
border: 1px solid #2a3340;
border-radius: 10px;
padding: 16px 18px;
overflow-x: auto;
margin: 14px 0;
font-family: ui-monospace, 'SF Mono', 'Cascadia Code', Consolas, monospace;
font-size: 0.85rem;
line-height: 1.55;
color: #e6edf3;
}
/* Reset inline-code double-up inside pre */
.post__body pre code {
background: transparent;
padding: 0;
border: none;
font-size: inherit;
color: inherit;
border-radius: 0;
}
/* ── Blockquote callout (ready for future use; build.js does not emit blockquote yet) ── */
.post__body blockquote {
background: rgba(245, 158, 11, 0.08);
border: 1px solid rgba(245, 158, 11, 0.25);
border-left: 4px solid #f59e0b;
border-radius: 0 12px 12px 0;
padding: 16px 18px;
margin: 18px 0;
color: #f4e3c4;
font-size: 0.94rem;
}
/* ── Links ── */
.post__body a {
color: #38bdf8;
}
.post__body a:hover {
color: #a855f7;
}
/* ── Strong ── */
.post__body strong {
color: #f59e0b;
}
/* ── HR ── */
.post__body hr {
border: none;
border-top: 1px solid #2a3340;
margin: 32px 0;
}
/* ── Figures ── */
.post__body figure img {
border-radius: 12px;
border: 1px solid #2a3340;
}
.post__body figcaption {
color: #9aa7b4;
font-size: 0.85rem;
margin-top: 6px;
}
/* ── List spacing ── */
.post__body li {
margin: 4px 0;
}
</style>
</head>
<body>
<!-- NAV -->
<nav class="nav nav--scrolled" id="nav">
<a href="/" class="nav__logo" aria-label="Tinqs home">
<span class="nav__wordmark">TINQS</span>
</a>
<div class="nav__links">
<a href="/#game" class="nav__link">Games</a>
<a href="/#tech" class="nav__link">Technology</a>
<a href="/#about" class="nav__link">About</a>
<a href="/blog/" class="nav__link" style="color: var(--c-accent-l);">Blog</a>
<a href="/#signup" class="nav__link">Contact</a>
<a href="/press" class="nav__link">Press</a>
</div>
<button class="nav__burger" aria-label="Open menu" id="navBurger">
<span></span><span></span><span></span>
</button>
</nav>
<!-- MOBILE MENU -->
<div class="mobile-menu" id="mobileMenu">
<a href="/#game" class="mobile-menu__link">Games</a>
<a href="/#tech" class="mobile-menu__link">Technology</a>
<a href="/#about" class="mobile-menu__link">About</a>
<a href="/blog/" class="mobile-menu__link">Blog</a>
<a href="/#signup" class="mobile-menu__link">Contact</a>
<a href="/press" class="mobile-menu__link">Press</a>
</div>
<!-- POST -->
<article class="post">
<a href="/blog/" class="post__back">&larr; All Posts</a>
<span class="post__date">25 May 2026</span>
<h1 class="post__title">Image Generation at Every Price Point with fal.ai</h1>
<p class="post__lead">We generate every visual asset for Ariki &mdash; concept art, app icons, trailer frames, logo variants, Steam capsules &mdash; through a single inference proxy that routes to fal.ai. No Photoshop. No Midjourney subscription. Just API calls at prices that range from $0.002 to $0.09 per image. Here's how we decide which model gets which job.</p>
<div class="post__body">
<h2>The Setup</h2>
<p>Our <a href="https://tinqs.com" style="color: var(&ndash;c-accent-l);">Tinqs Studio</a> platform includes an inference proxy that sits between agents and model providers. When an agent (or a human in Cursor) says "generate an image," the proxy routes the request to fal.ai, handles authentication, tracks usage per user, and persists the result to S3. The caller doesn't care which model runs &mdash; they describe what they want, and the proxy picks or the caller specifies.</p>
<pre><code>Agent describes what it wants
→ tinqsProxy receives generate_image call
→ Routes to fal.ai with the specified model
→ Image generated, persisted to S3
→ Permanent URL returned to caller</code></pre>
<p>One API key. One billing account. Access to every model fal.ai hosts. That's the pitch of aggregator platforms, and fal.ai delivers on it.</p>
<h2>The Tiers</h2>
<p>Not every image needs the best model. A throwaway mockup doesn't justify $0.09. A final logo doesn't deserve $0.002. We split our usage into four tiers.</p>
<h3>Best Quality &mdash; Final Art</h3>
<p>For images that ship &mdash; hero art, app icons, trailer keyframes, print-ready designs &mdash; we use three models depending on the content:</p>
<p><strong>Flux 2 Pro</strong> ($0.03/megapixel, ~15 seconds). Our default. Best all-round quality for concept art, character illustrations, environment paintings, and anything that doesn't need text. Handles complex prompts with multiple elements well. Rarely fails.</p>
<p><strong>Ideogram v3 Quality</strong> ($0.09, ~12 seconds). The only model that renders text reliably inside images. When we need a poster with a tagline, a sign in a game scene, or a logo with readable letters, this is the only option. The QUALITY tier is expensive but worth it &mdash; text at lower tiers gets blurry.</p>
<p><strong>Recraft v3</strong> ($0.04 raster, $0.08 vector, ~10 seconds). Built for commercial design. Clean lines, consistent style, and the only model on fal.ai that outputs SVG vectors. When we need brand assets, packaging mockups, or anything that might end up in print, Recraft produces work that doesn't need cleanup.</p>
<h3>Mid Tier &mdash; Everyday Work</h3>
<p>For images that are good enough for internal review, social posts, or documentation:</p>
<p><strong>Ideogram v3 Balanced</strong> ($0.06, ~8 seconds). Typography quality between Turbo and Quality. Good for marketing materials where text matters but perfection doesn't.</p>
<p><strong>Seedream v4.5</strong> ($0.04, ~8 seconds). Google's model on fal.ai. Photorealistic scenes and product shots. Different aesthetic from Flux &mdash; slightly more photographic, less painterly.</p>
<p><strong>Flux Dev</strong> ($0.025, ~10 seconds). The open-weight Flux variant. Good quality, and the base for LoRA fine-tuning if you want to train on your own style. We use it when we need custom-trained models later.</p>
<h3>Low Cost &mdash; Drafts and Exploration</h3>
<p>For iteration, A/B testing, and throwing things at the wall:</p>
<p><strong>Flux Schnell</strong> ($0.003/megapixel, ~3 seconds). The workhorse for exploration. When we're figuring out composition, trying different camera angles, or generating 20 variants to pick one direction &mdash; Schnell. A hundred images costs $0.30. You can afford to be wasteful.</p>
<p><strong>SDXL Lightning</strong> (~$0.002, ~2 seconds). The absolute cheapest option. Lower quality than Schnell, but when you need 50 thumbnails to test a layout grid or generate placeholder textures, quality doesn't matter. Two cents for ten images.</p>
<h3>Specialised &mdash; Editing and Post-Processing</h3>
<p>For modifying existing images rather than generating new ones:</p>
<p><strong>Flux Kontext</strong> (~$0.04, ~12 seconds). Context-aware editing. Give it an image and say "change the wood to marble" or "make it sunset lighting." Preserves composition while changing style or material. Useful for quick style transfers without regenerating from scratch.</p>
<p><strong>Nano Banana Edit</strong> ($0.039, ~12 seconds). Image-to-image restyle. We use this for our logo variant pipeline &mdash; take one carved-wood Ariki logo and produce versions in mahogany, pearl, obsidian, coral, gold. It's better than Kontext at preserving fine detail in complex images.</p>
<p><strong>BiRefNet</strong> ($0.001, ~3 seconds). Background removal. Produces clean alpha cutouts from any image. We pair it with every logo and icon generation &mdash; generate with a white background, then cut it out. A dollar gets you a thousand cutouts.</p>
<h2>How We Actually Use Them</h2>
<h3>The Schnell-to-Pro Pipeline</h3>
<p>We never start with the expensive model. Every generation session follows the same pattern:</p>
<p>1. <strong>Explore with Schnell</strong> ($0.003) &mdash; 10-20 variants, different angles, compositions, color palettes. Total: $0.03-0.06.</p>
<p>2. <strong>Pick 2-3 directions.</strong> Human looks at the grid, picks the promising ones.</p>
<p>3. <strong>Refine with Flux 2 Pro</strong> ($0.03) &mdash; regenerate the winners at full quality with refined prompts. Total: $0.06-0.09.</p>
<p>4. <strong>Post-process</strong> &mdash; BiRefNet for background removal ($0.001), maybe Recraft for a vector version ($0.08).</p>
<p>A full session &mdash; from blank canvas to final assets &mdash; costs under $0.20. That's the price of a single Midjourney generation on their Pro plan.</p>
<h3>Logo Variants at Scale</h3>
<p>Our Ariki logo has 18 material variants &mdash; deep mahogany, mother-of-pearl, obsidian, molten lava, bronze with verdigris, tapa cloth, and more. Each one generated with Nano Banana Edit ($0.039) + BiRefNet ($0.001) for transparency. Total cost for 18 variants: <strong>$0.72</strong>. A designer would quote hundreds of dollars and a week of work for the same output.</p>
<h3>Typography That Works</h3>
<p>Every model except Ideogram fails at text. Flux will give you beautiful art with garbled letters. Recraft gets close but isn't consistent. SDXL doesn't try. If the image has words in it, Ideogram v3 is the only answer. We've learned to accept the $0.09 cost for text-heavy images rather than wasting $0.30 on ten failed Flux attempts.</p>
<h2>The Numbers</h2>
<p>Over the past month:</p>
<p>| Category | Images | Total Cost | Avg Cost/Image |</p>
<p>|&mdash;&mdash;&mdash;-|&mdash;&mdash;&ndash;|&mdash;&mdash;&mdash;&ndash;|&mdash;&mdash;&mdash;&mdash;&mdash;-|</p>
<p>| Concept art (flux-2-pro) | ~120 | $3.60 | $0.03 |</p>
<p>| Exploration drafts (schnell) | ~400 | $1.20 | $0.003 |</p>
<p>| Logo variants (nano-banana) | 18 | $0.72 | $0.04 |</p>
<p>| Icons (nano-banana + birefnet) | 30 | $1.20 | $0.04 |</p>
<p>| Typography (ideogram) | ~25 | $1.50 | $0.06 |</p>
<p>| Background removal (birefnet) | ~80 | $0.08 | $0.001 |</p>
<p>| <strong>Total</strong> | <strong>~673</strong> | <strong>$8.30</strong> | <strong>$0.012</strong> |</p>
<p>Six hundred images for eight dollars. The infrastructure to route, authenticate, and persist them costs more than the generation itself.</p>
<h2>What We Learned</h2>
<p><strong>Never iterate on expensive models.</strong> The Schnell-to-Pro pipeline saves 10x. Most of the creative work happens at $0.003/image. The expensive model just polishes the decision you already made.</p>
<p><strong>Typography is a solved problem &mdash; but only on one model.</strong> Stop trying to make Flux render text. Use Ideogram v3 Quality for anything with words. Accept the cost.</p>
<p><strong>Vector output is underrated.</strong> Recraft v3's SVG export means logos and icons scale to any size without artifacts. For anything that might end up on a billboard or a business card, pay the $0.08 for vector.</p>
<p><strong>Background removal is basically free.</strong> At $0.001 per image, there's no reason to ever manually mask anything. Run BiRefNet on everything, keep both versions.</p>
<p><strong>Aggregation beats loyalty.</strong> No single model is best at everything. Flux for art, Ideogram for text, Recraft for design, Nano Banana for edits, BiRefNet for masks. The proxy pattern lets us use the right tool for each job without managing five API keys and five billing accounts.</p>
<hr>
<p><em>Image generation is built into <a href="https://tinqs.com" style="color: var(&ndash;c-accent-l);">Tinqs Studio</a> &mdash; our Gitea-based platform for game teams. Every model above is available through the same inference proxy that handles LLM calls, authenticated with the same Gitea token. We're building <a href="https://arikigame.com" style="color: var(&ndash;c-accent-l);">Ariki</a> with these tools, and every asset in the game touched at least one of them.</em></p>
</div>
<div class="post__author">
<div class="post__author-avatar">OB</div>
<div class="post__author-info">
<span class="post__author-name">Ozan Bozkurt</span><br>
CTO & Developer, Tinqs
</div>
</div>
</article>
<!-- FOOTER -->
<footer class="footer">
<div class="footer__inner">
<span class="footer__wordmark">TINQS</span>
<div class="footer__links">
<a href="/#game">Games</a>
<a href="/#tech">Technology</a>
<a href="/#about">About</a>
<a href="/blog/">Blog</a>
<a href="mailto:hello@tinqs.com">hello@tinqs.com</a>
<a href="/press">Press Kit</a>
</div>
<p class="footer__copy">Tinqs Limited &mdash; London, est. 2020</p>
</div>
</footer>
<script>
const burger = document.getElementById('navBurger');
const mobileMenu = document.getElementById('mobileMenu');
burger.addEventListener('click', () => {
const open = mobileMenu.classList.toggle('mobile-menu--open');
burger.classList.toggle('nav__burger--open', open);
document.body.style.overflow = open ? 'hidden' : '';
});
mobileMenu.querySelectorAll('a').forEach(link => {
link.addEventListener('click', () => {
mobileMenu.classList.remove('mobile-menu--open');
burger.classList.remove('nav__burger--open');
document.body.style.overflow = '';
});
});
</script>
</body>
</html>