DEV Community

Cover image for Building Picturesque AI: one studio, 50+ models, and the plumbing nobody wants to maintain
Picturesque AI
Picturesque AI

Posted on

Building Picturesque AI: one studio, 50+ models, and the plumbing nobody wants to maintain

One creative studio for images, video, music, audio, editing, upscaling, and motion control. 50+ models, one credit balance.

This is mostly about how we built it and what went wrong along the way.

The problem (from a dev perspective)
The models are good now. That's not really the issue anymore.

The issue is everything around them. Different providers, different UIs, different billing. No shared history across modalities. No easy way to go from "generate image" to "animate it" to "add music" to "upscale" without opening four tabs.

We wanted one place where you could actually finish something.

What the product is
Picturesque has a few main pieces:

Studio - tabs for image, video, audio, edit, motion control

Projects + Explore - save your work, browse what other people made

Workflows - node canvas where you chain models together and run the pipeline in one go

Director - an agent that plans multi-step creative work, quotes credits, and runs generations for you

The studio covers a lot on its own. 4K images, cinematic video with audio, Suno music, ElevenLabs TTS, Topaz upscaling, motion control, talking avatars. The annoying engineering showed up once we tried to make all of that feel like one product instead of a folder of integrations.

Stack (kept boring on purpose)
Frontend is React, TypeScript, Vite, React Router. Backend is Node + Express. Socket.IO for real-time updates. Supabase for Postgres and auth. S3-compatible storage for outputs and uploads.

For the actual model calls we built a service layer that normalizes inputs, maps our internal model IDs to provider APIs, and handles retries/errors in one place. Media stuff runs through FFmpeg and Sharp.

Nothing fancy. When you're wiring up dozens of models with different schemas and pricing rules, you don't want your infra adding more chaos.

We also refactored the backend out of a single 7,700-line server.js into routes + services. Painful refactor. Would do it again immediately.

The unglamorous part: 50 models, one UI
Every model has opinions.

Kling wants duration, aspect ratio, sometimes start/end frames. Veo has quality tiers. Suno has like five different modes. Topaz pricing changes based on resolution and scale.

What we ended up with:

One frontend config (models.ts and friends) for capabilities, slugs, SEO, pricing display
One backend pricing layer that calculates credit cost before deducting
One generation flow per modality with model-specific validation shoved into the service layer
One history table so everything shows up in the same grid
The mapping layer is boring work. It's also the product. Without it you're just linking people to other people's tools.

Real-time updates
Generations take anywhere from a few seconds to a few minutes. Browser polling felt wrong.

Rough flow:

User clicks generate
Backend creates the task, deducts credits, writes a pending history row
A background workflow polls the provider until it's done
Output gets uploaded to S3, DB gets updated, webhook fires
Backend pushes a generation-update over Socket.IO
Frontend updates the card in place
Works fine until it doesn't. Reconnects, duplicate events, socket firing before the DB write lands. We ended up doing silent history refetches after completion to paper over the race conditions. Not elegant. Works.

Director
At some point we realized a generation UI isn't enough for a chunk of our users. Marketers don't care about picking Kling vs Veo. They want a TikTok ad.

Director is the agent layer. You say what you want ("5-slide carousel for my skincare brand") and it breaks it into steps, estimates credits, runs the generations.

Three modes:

auto - just go
plan - show me the credit breakdown first
ask - approve each generation
There's also brand memory, specialist agents, social connectors, scheduled posting. Still iterating on all of it.

Building an agent on top of an existing studio is weird. It needs to know what models exist, what they cost, what inputs they take, what's already in your history. The agent and the studio share the same generation code. That coupling is intentional.

Workflows
For people who want pipelines but don't want to click through tabs manually.

Node editor on an infinite canvas. Wire image β†’ video β†’ audio nodes together, run the whole thing. Built with XYFlow.

Studio tabs = "I know what I want" Workflows = "I want to chain this" Director = "just do it for me"

Same backend, three entry points.

Stuff we learned the hard way
People compare credits, not just output quality. "How many Kling videos do I get for $30?" is a real question. We added a billing comparison table with approximate outputs per plan. People actually use it.

Free tier is a product decision. 15 credits/day across all models, no card. Lets people try Nano Banana Pro or Kling before paying. Costs us compute. Seems worth it.

Refund on failure or you lose trust immediately. If credits get deducted and the provider fails, that's it, user's gone. We had a bug early on where credits would deduct and the API would throw after. Added emergency refund logic in every catch block.

New models never stop shipping. Keeping the config layer up to date is basically a permanent side job now.

Still working on
Better team collaboration on projects
Director social posting integrations
More workflow templates
Not falling behind on model releases (lol)
If you're building something similar
Abstract providers early. Model IDs, pricing, input schemas. Even if you only have one provider today.
Async delivery should be first-class. Webhooks + background workers beat client polling.
One wallet, one history. Users shouldn't have to think about where their stuff lives.
Build for different skill levels. Manual controls, pipelines, and agent automation are different users.
Refund on failure. Seriously.
Try it
Live at aipicturesque.com. 15 free credits a day, all models.

If you're working on something in this space, curious how other people are handling the model sprawl problem. Drop a comment.

React, Node, Supabase, Socket.IO, and not enough documentation

Top comments (0)