For a browser-based starting point, Photogenerator.ai brings image and video creation into one workspace.
AI video interfaces often look simple: upload an asset, enter a prompt, click generate. The hard part is not the button. It is defining a contract for what the input controls, what the prompt controls, and what the reviewer is expected to accept.
This post is an interface-level design memo. It does not infer a vendor's source code, backend, model routing, or production guarantees.
An image-to-video workflow usually contains at least three different intents:
These intents should not be hidden behind one vague “generate video” action. Even when the implementation shares a backend, the UI can name the distinction so the user chooses the correct mental model.
The following type is a proposal for discussing UI behavior, not an observed implementation:
type GenerationState =
| { kind: "empty" }
| { kind: "ready"; references: number; prompt: string }
| { kind: "generating"; requestId: string }
| { kind: "review"; requestId: string; assetUrl?: string }
| { kind: "failed"; message: string };
The useful design question is what information survives each transition. A failed request should not erase the uploaded reference or the prompt. A review state should expose enough context to compare the result with the original brief.
On the public video page for Text With Reference, the visible workflow describes combining text prompts with image, video, or audio references. That suggests a role-based input model: each uploaded item should be understandable as a reference, not merely as an unnamed attachment.
For a frontend implementation, test these cases:
The product page is evidence of the visible interaction and copy, not evidence of the internal request schema. A production integration still needs an official API contract.
When the user has a start frame and an intended end frame, the UI should make the pair visible together. A single upload control can hide an important error: the user may think they selected an endpoint when they actually selected a general reference.
The Frame to Video option is a useful product example for this distinction. An implementation checklist could ask:
Generation is not the same as acceptance. For product clips, review should cover object shape, label legibility, lighting continuity, motion direction, and intended placement. For portraits, add expression, eye line, and identity continuity. For illustrations, check whether the requested style survives movement.
Avoid claiming a fixed quality score or latency unless it is measured under a defined model, input, and date. A public UI can show a workflow; it cannot establish a benchmark.
Selectors below are illustrative. They are not claimed to match the public page's DOM:
test("keeps the prompt after a failed generation", async ({ page }) => {
await page.getByRole("textbox", { name: /prompt/i }).fill("slow camera push");
await page.getByRole("button", { name: /create video/i }).click();
await expect(page.getByRole("textbox", { name: /prompt/i })).toHaveValue("slow camera push");
});
The key assertion is not the selector. It is the contract that user intent remains recoverable when generation is asynchronous or fails.
The strongest AI video UX is not the one with the most controls. It is the one that makes intent, state, and review criteria visible. Treat references as typed inputs, treat frame endpoints as a separate job, and test recovery paths as carefully as the happy path. Those principles apply across providers and models.