DEV Community

Cover image for An Image-to-Image UI Is a Capability Contract, Not a Prompt Box
EthanCole
EthanCole

Posted on

An Image-to-Image UI Is a Capability Contract, Not a Prompt Box

A prompt box is the visible center of an image-to-image tool, but it is not the product boundary. The boundary is the set of requests the system can accept right now: file type and size, number of source images, selected model, available aspect ratios and resolutions, account state, credit cost, and task availability.

Disclosure: AI was used to structure and edit this article. Product facts and limits were reviewed against the current public UI and documented application evidence.

If those constraints live as scattered if statements and marketing copy, the UI eventually offers combinations the backend cannot execute. The user only discovers the conflict after they have uploaded files and written a prompt. A more reliable design treats capabilities as data and derives the editor from that data.

Model the current capability space

The client needs a compact answer to questions such as: does this mode accept one image or several, which output options are valid, is sign-in required, and can the task be started now?

type Capability = {
  mode: "single" | "fusion";
  sourceImages: { min: number; max: number };
  aspectRatios: string[];
  resolutions: string[];
  requiresAccount: boolean;
  available: boolean;
};
Enter fullscreen mode Exit fullscreen mode

The names are illustrative. The important choice is that the browser renders a projection of the latest server-supported combinations instead of assuming that every model supports every option.

For the reviewed Image to Image Generator workflow, Single Image accepts one reference image and Multi-Image Fusion accepts two to five. The public UI accepts JPEG, PNG, and WebP files up to 24 MB each, and prompts up to 1,000 characters. Model, ratio, resolution, login, credit, and availability details are current capabilities rather than evergreen promises.

Derive validation from the same source

The generate button, helper text, and server payload should agree. A resolver can make the path explainable:

function resolve(cap: Capability, fileCount: number) {
  const validInput = fileCount >= cap.sourceImages.min && fileCount <= cap.sourceImages.max;
  return {
    canGenerate: cap.available && validInput,
    reason: validInput ? null : `Choose ${cap.sourceImages.min}-${cap.sourceImages.max} source images.`,
    requiresAccount: cap.requiresAccount,
  };
}
Enter fullscreen mode Exit fullscreen mode

Server-side validation remains authoritative. Client-side derivation exists so a user can recover before submitting an invalid request. It also prevents a familiar kind of copy drift: a page that advertises a high-resolution or multi-image option that is not available for the selected combination.

Keep configuration state separate from task state

The selected model and uploaded images answer “what is being requested?” Task status answers “what is happening?” Combining them tends to create impossible states such as a finished task that is still uploading, or a failed task that silently removes valid inputs.

idle -> validating -> uploading -> ready
ready -> submitting -> processing -> succeeded | failed
Enter fullscreen mode Exit fullscreen mode

The useful behavior after succeeded is not a reset. It is a review state: inspect the output, download it, or revise the transformation while retaining the input and settings that led to it. A technically completed generation is not a guarantee that the image is fit for a particular campaign, listing, or design.

Design the errors as recovery instructions

“Unable to generate” is an operational message, not useful product guidance. The interface should distinguish an unsupported file, a wrong source-image count, an unavailable resolution, an account gate, and a temporarily unavailable capability. Those are different recovery paths.

This matters especially in image workflows because the user has already made an investment: selected references, decided what should change, and described the result. Preserve that work whenever a request fails. Explain the invalid condition next to the control, then let the user adjust one variable at a time.

The engineering lesson

One editor can support several image-to-image jobs without pretending that all jobs are identical. Keep volatile choices in a capability contract, derive UI state from it, validate again on the server, and make review an explicit stage of the workflow.

The public workflow that prompted these notes is available for context at https://imagetoimagegenerator.io/. The reusable pattern is broader: whenever a UI sits in front of changing provider capabilities, truthful constraints are a better product feature than a larger feature list.

Top comments (0)