Inspiration
The video was working perfectly and I couldn't hear a word.
She's in a kitchen. Grey sweatshirt with a coffee stain on it, freckles, hair tied back badly. She leans toward the phone, gets to the number, and stops — that small involuntary pause of someone who still can't believe it. Behind her, takeaway menus on the fridge. Everything in the frame is right.
There is no sound. Under her runs a music bed, correctly mixed, correctly ducked, at exactly the level the specification asks for. I measured it instead of arguing with myself about it: \( -42 \) dBFS. The renderer was muting every clip, on one line, with a comment explaining why — an assumption that had been true for a year and had quietly stopped being true.
Two months earlier I had killed a project called Casanova. It was an agent that would run your dating profiles for you. I put up a site and a waiting list, and a stranger found it and took it apart in the comments: illegal, he said, and no woman is going to trust an AI to pick her partner. My first honest reaction was delight, because someone I had never met had read every word closely enough to get properly angry about it. Then I did the research he pushed me into and found the real problem, which was not his argument at all. It was liveness checks. Film yourself touching your nose, right now. An agent that hits one has to phone a stranger and ask them to open an unfamiliar browser session on the account it could get banned from. Trust dies at that exact moment.
I shut it down. It cost me nothing except the belief that a good product finds its own customers.
That belief is expensive to lose and it is the reason this exists. An app pays a creator €2,000 for one video. The video gets 4,000 views. Nobody involved can say in advance whether the next one will do ten times better or ten times worse, and there is no mechanism to find out except to pay again. The economics of short-form only close at volume, and volume needs people — writers, performers, editors, somebody to post at 18:30 every day for six months. So almost nobody does it, and the ones who do it well are agencies charging accordingly.
I wanted to know whether the whole loop could run with nobody in it. Not a video generator. A creator that wakes up.
Why me
I should explain why a sixteen-year-old is building a marketing product, because the answer is also why it looks the way it does.
When GPT-3 came out I had just finished learning HTML and CSS. I looked at it — it couldn't really code and couldn't really do anything except talk — and I concluded the race was already over, and I stopped learning to program. Everyone tells you that you have to learn to code. I went and learned marketing, persuasion and storytelling instead. I still don't know whether that was clever or lazy.
What I do know is that it left me with exactly one skill and no way to use it at scale. I can write a hook. I spent five months on a treatise about it: twenty-five volumes, Campbell and Vogler, Syd Field's plot points, the Pixar spine, the neurochemistry of why a story holds attention when a fact doesn't. And one person who can write a hook is still one person. You cannot be ten creators. You cannot post at 07:00 on a Tuesday from ten different faces with ten different reasons for being there.
So the thing I built is the thing that turns that one skill into a fleet.
The other reason is the one I have already been taught the hard way. Earlier this year I wanted an internship at Google, so I walked to their Paris office and started talking to people going in and out, which made them uncomfortable and made them leave quickly. Security explained, kindly, that this was not how it worked, and that the letter had to be in before six. It was five. I wrote the whole cover letter on my phone on the train with the cold going down my throat, and arrived at 18:20, twenty minutes late, and the guard let me in anyway and flattened my crumpled CV out with his palm before he filed it.
Two days, no answer. So I went back. Somebody walked out, saw me talking to the guard, came over to find out what was going on, listened to the whole thing, and took me inside. First visitor badge of my life. The internship turned out to be open only to employees' family members, so I never had a chance, and I came out with a badge, a day inside Google, and a fact I now trust: the second visit is a different visit.
That sentence is the product. A fleet that posts once and stops has learned nothing. A fleet that comes back tomorrow with what yesterday taught it is a different fleet.
What it does
Ten synthetic creators run on your own YouTube channels. Each one has a face, a room, a way of speaking, a strategy, and a memory.
At 07:00 each agent wakes up on its own — Cloud Scheduler, not a person — and works through its day. It reads what it learned yesterday. It looks at what its last videos actually did at 2h, 24h and 72h. It picks a shape it has not just used, because two videos with the same length, the same speech mode and the same on-screen text look identical to somebody scrolling, whatever their scripts say. It writes a situation rather than an advert — someone gets a message they can't answer, someone is up too late finishing something they shouldn't have had to do — and the product arrives once, late, in passing. It draws the whole thing as a storyboard, films it, cuts it, checks it, posts it. Then it writes down what it learned, with the numbers in it.
Every post is scored on rates, never absolutes, because a channel with more subscribers would otherwise always win and the fleet would stop learning anything about the creative:
$$S = 1.8\,W_{3s} + 4.5\,\mathrm{CR}_{100} + 5.0\,\frac{\text{shares}}{\text{views}} + 3.5\,\frac{\text{saves}}{\text{views}}$$
Below threshold three times, a format is dropped. Above it, doubled. The channel's posterior over formats updates and tomorrow's choice is drawn from it — mostly exploiting what works, deliberately exploring what hasn't been tried.
There is a hard stop, and it is not in the prompt. No number reaches a video unless it appears in the brand's own published material. Two videos were blocked this week for inventing one.
How we built it
Six Google models, all through Vertex AI, each doing the one thing it is best at. Gemini 3.7 Flash runs the agent loop across 51 tools and also serves as the vision judge that inspects every frame before it is animated. Gemini 3 Pro Image (Nano Banana 2) builds a seven-photograph character sheet, then one storyboard panel per shot. Gemini Omni Flash animates an approved panel with the dialogue rendered in sync inside the clip. Lyria 002 scores it. Chirp 3 HD narrates where the scenario calls for it. Speech-to-Text reads the word timings back off the generated audio.
It runs on Cloud Run, against Cloud SQL, woken by Cloud Scheduler, with finished media copied to Cloud Storage because the container's filesystem lives in memory and disappears minutes after the daily run ends. Cloud Build and Artifact Registry handle the image; one shell script is the entire deployment.
The craft is deliberately not the model's job. A model asked to write a video prompt writes adjective salad — cinematic, beautiful, 8k — and adjective salad produces exactly the plastic look that gets a UGC account dismissed in half a second. So shots are compiled from closed, typed vocabularies: framing, motivated light, sensor behaviour, performance direction. The model supplies only what genuinely requires judgement — who is in the shot, what happens, what is said. The agent chooses which video exists today and why. That is the part no procedure can do for it.
The storyboard is the one idea I would keep if I had to throw the rest away. The image model is far better than the video model at composition, at detail, and above all at holding a face. Asking the video model to invent the framing and animate it gets both jobs done at the quality of the weaker one. So the frame is decided in stills: a panel per shot, each conditioned on the character's own photographs and on the panel before it, so the room and the clothes and the light carry over as pixels rather than as adjectives. A vision pass then rejects any panel with the wrong face, a fabricated interface, or burnt-in text. Only approved panels are animated.
I wrote all of it with an AI, one to two hours a day, mostly at night. What I contributed was the precision of what I asked for and the shape of the system: what runs on a timer, what is allowed to fail, and what is not. My debugging method is crude and beats everything clever I tried — open a completely new conversation, hand it the code cold, ask it to find every bug. There are always more.
Challenges we ran into
The agent could not exist, and it was a protocol bug. Gemini 3.x attaches a thought signature to every function call and refuses the next request if it is missing. My runtime was rebuilding the model's turn from {name, args}, dropping the signature, so every tool-using run died at step two with a 400. It also requires the responses for a turn to come back as one user turn with exactly as many parts as the turn had calls. Two protocol details, and until both were right there was no agent — only a pipeline wearing a prompt.
Imagen does not exist on this account. Five published model ids, five 404s. And the Gemini image models refuse the predict endpoint that the SDK's generateImages() calls, with FAILED_PRECONDITION. So no character reference image had ever been generated. The sheet was full of placeholders, the video model got no references, and every shot invented a new face. The fix was generateContent with image output — which is also what makes reference images an input, which is the only reason the storyboard exists at all.
The videos kept lying. A shot directed as "an insert on the screen" came back with a fabricated Shopify dashboard. Another with a fake Instagram analytics grid. A selfie came back with an entire iPhone camera app painted over the image, mode tabs reading FENTO VIDEO MATEO PHOTO FORMOTO. The negative prompt already said "no text overlay" — the model simply did not classify a user interface as text. The negative list is a bug log now, not a wish list: every entry names something actually seen in a rejected frame.
A seed that was too big. 3041694504 exceeds a signed 32-bit integer, Vertex refuses it, and it killed every storyboard panel of a run while the clips generated and billed normally. The video shipped with no panels and I only found out by reading the assets in the database.
Cloud Run withdraws the CPU when the request returns. Renders were fire-and-forget — correct for a long-lived server, fatal here. A render left running does not fail. It freezes, at whatever percent it reached, for ever. Three runs sat at 0% while I looked for a bug in the renderer that was not there. The CLI had always awaited the render queue, which is precisely why rendering worked on my laptop and had never once worked in the cloud.
And the silence. Fixing the muted renderer only revealed the next thing: Omni's clip audio stops when the speech stops, so a shot held past its last word fell to \( -90 \) dBFS. Seven seconds of it in a seventeen-second video. Not quiet — absent. There is a synthesised room tone under everything now, about \( -46 \) dBFS, crossfaded so it loops without a seam. It is inaudible as a sound and audible as the absence of a hole.
Accomplishments that we're proud of
The run I keep going back to is 54 steps long. The agent read its memory, chose a shape, produced the video, ran the timeline check, saw the warnings — opening silence, a stretch with no visual break — and fixed them itself. Added a sound effect. Applied three effects. Re-checked until the issue list was empty. Rendered. Scheduled the post with a reason about a lunchtime scroll window. Wrote what it learned.
Nobody told it to do the middle part. That is the whole difference between an agent and a pipeline, and it is in the trace.
The rest, measured rather than claimed: a 22-second video at 1080×1920 and 60fps with audible sync dialogue and word-level captions, produced end to end on Cloud Run in 623 seconds; 22 scenarios across 16 distinct shapes; six Google models; a character who is recognisably the same person across every shot of a video for the first time; the vision judge catching a fabricated interface before it cost a clip.
And the honest one, because I would rather say it than let it be inferred: zero videos have been published. Publishing is implemented and tested in dry run, and the switch has not been thrown. The decision engine has never seen a real retention curve. Everything above is the machine working; none of it is yet the market answering.
What we learned
Move every rejection to the cheapest stage that can catch it. Let \( c_i \) be the cost of a rejection at stage \( i \) and \( p_i \) the probability of catching a given defect there. Expected waste is
$$\mathbb{E}[\text{waste}] = \sum_i p_i\, c_i$$
and the entire game is shifting probability mass leftward, toward small \( c_i \). An invented figure caught by quality control costs a whole video. Caught at write time it costs one model call. A wrong frame caught after generation costs about €0.60 and forty seconds; caught as a storyboard panel it costs about €0.13 and three. Roughly five to one in money, thirteen to one in time. That ratio is why the storyboard exists. It is not a documentation step — it is where the failure rate is supposed to live.
A creative step that fails quietly is worse than one that fails loudly. My scene writer swallowed every error into a convincing template fallback. The videos still shipped. Nobody noticed the model had stopped writing for days.
Green is not proof. Typecheck passed on every commit of a system that had never produced a watchable video. I only learned what was actually wrong by extracting frames and measuring decibels — by looking at the output instead of at the process reporting on itself.
And the one I did not expect. I stopped learning to code because I decided a model would do it better than me. Three years later I built a system whose central design decision is taking work away from the model — closed vocabularies instead of free prompts, rules in code instead of in instructions, facts behind functions instead of pasted into context. The bet I made at thirteen was right about capability and wrong about where the value sits. It sits in knowing precisely what to ask for.
What's next for OttoUGC
Throw the publishing switch. One channel, one video, one real retention curve — the number that turns the decision engine from tested into true.
Then multi-tenant onboarding, and the paid amplification loop for the videos the grid marks as outliers, which is where the economics actually close.
And the flywheel the thing is named for. There is a brand called ottougc in the database and it runs on the same code path as any customer. When it starts posting, the showcase on the landing page stops being a portfolio and becomes a proof: if it stopped working, that page would have nothing left to show.
I killed Casanova because I believed a good product would find its own customers. This is the machine I built after finding out it won't.
The woman in the kitchen has a voice now.
Built With
- chirp-3-hd
- cloud-build
- cloud-run
- cloud-scheduler
- cloud-sql
- cloud-storage
- docker
- drizzle-orm
- gemini-3-pro-image
- gemini-3.7-flash
- gemini-omni-flash
- google-genai-sdk
- lyria
- next.js
- node.js
- postgresql
- react
- remotion
- speech-to-text
- tailwindcss
- typescript
- vertex-ai
- youtube-analytics-api
- youtube-data-api
- zod
Log in or sign up for Devpost to join the conversation.