DEV Community

visiohex
visiohex

Posted on Fully Autonomous

I built a one-photo Burning Bridges video generator

I built Drake Burning Bridges AI, a small web app that takes one portrait and generates a personal version of the Burning Bridges party scene.

You choose the main character with your photo. I’ve configured the video reference and prompt, so you don’t have to write scene instructions. The output is a 20-second, 720p, landscape MP4 with the supplied soundtrack.

For this post, I wanted to share the implementation choices behind that short upload flow.

Keeping the input small

The studio accepts one portrait. The photo provides the appearance reference for the main subject; the video reference guides the party setting, gestures and camera movement.

I kept the scene and output settings fixed. Users can choose who appears in the foreground, but they can’t cast each guest or change the duration. That limits what you can make, and it gives the upload page a clear job: help you choose a usable photo and understand the expected result.

The server checks file size, image type and dimensions. A file extension or a browser-provided MIME type alone isn’t enough to validate an upload.

The stack

I’m using React and TanStack Start for the app, with Better Auth for authentication. The application runs on Cloudflare Workers. I store task and credit records in D1, and uploaded photos and finished videos in R2.

The app calls an external video generation service. Workers handle the application flow rather than running video inference themselves.

Treating generation as a saved job

A video request needs to survive the user leaving the page. I store the job before processing it and track its progress through these states:

queued → processing → composing → saving → succeeded
Enter fullscreen mode Exit fullscreen mode

The composition step adds the supplied soundtrack. I mark a task as successful after saving the finished video, rather than when the generation provider first reports success.

Users can return to My videos to check an existing task. The browser doesn’t have to stay open for the whole operation.

Handling retries and credits

Each generation uses one credit. I use a request ID to connect a submission to its job. If the same user sends the same request again, the application returns the existing job. Reusing that ID with different input is rejected.

In the database, I connect job creation to the credit debit with a trigger. If the debit can’t complete, the job insert rolls back. I also give failed-job credit returns a unique ledger reference, so processing the same failure again doesn’t add another credit.

The less obvious case is a timeout while submitting to the video provider. The provider might have accepted the job even though my application didn’t receive its response. Submitting a fresh request at that point could create a second paid generation.

I record that submission attempt and keep an uncertain outcome for reconciliation. A confirmed failure returns the credit; a missing response needs more investigation. This leaves some cases requiring support review, but avoids treating an unknown result as permission to submit again.

Setting expectations for the video

AI can change facial details or hands as the person moves. A completed job means the user received a video, not that the model preserved their appearance in every frame.

I’ve included examples so visitors can inspect the intended scene. Those are supplied 480p samples, not evidence of a paid generation through the app. The configured output is 720p.

The site is an independent project with no affiliation with Drake. Users should upload photos they have permission to use, with the subject’s consent.

You can see the project at drakeburningbridgesai.video. I’d welcome feedback on the upload flow, or how you handle uncertain provider responses in apps that charge per task.

Top comments (0)