Live Nov 18 · Cohort 3Nov 18, 19:00 MSK — free hands-on AI agents live workshop · Live Cohort 3 starts Nov 23Join Nov 18 Live →Cohort 3 (Nov 23)
ReleaseAPI / Product · ActionableHabr AI→ original

A Consistent Character in the Gemini API: An 18-Frame Test Shows a Bare Prompt Makes Clothing Drift

An image generator has no memory between requests, so a "persistent character" is a discipline the client has to enforce: a fixed text passport for the hero and reference images in every request. The author ran 18 generations of a two-character scene across three prompt variants. The faces never changed, but with the bare prompt, clothing and accessories drifted from the reference and text showed up in the background.

AI-processed from Habr AI; edited by Hamidun News
A Consistent Character in the Gemini API: An 18-Frame Test Shows a Bare Prompt Makes Clothing Drift
Source: Habr AI. Collage: Hamidun News.
Listen to article
Article Fact Sheet & Key Figures
ParameterDetails
Primary sourceHabr AI ↗
Editor-in-Chief
Key metric #1Store the hero's passport in code and paste it into every prompt unedited
Key metric #2Number the images and list distinguishing features: 6 of 6 takes with no errors
Check the series on a contact sheetthe eye misses a dark jacket in a single frame

If you make videos or ads with the same characters, the main pain is familiar: by the third frame the heroine no longer looks like herself, and two people in one scene suddenly swap faces or clothes. A Habr author worked out how to handle this through the Gemini API and tested the techniques with a small measurement.

Why the face drifts

The generator has no memory between requests. Each call builds the frame from scratch from the text and the attached images. So character consistency has to be enforced on the client side.

The author proposes four elements:

  • Passport: a fixed text block describing the character's appearance, pasted into every prompt byte for byte. It holds only what never changes: age, hair, eyes, distinguishing features. Do not put a smile or clothing in it, or the smile will show up in every frame.
  • Reference: a front-facing portrait on a gray background, even lighting, neutral expression. It goes into every request as a reference image.
  • Views: front, three-quarter, profile, back. Each view is generated in a separate request with the reference as input. When the author asked for all four views in a single image, the model turned the head to the left and the feet to the right.
  • Review of every frame by eye at full size.

Technically it is simple: in generateContent, images go in as inlineData in the same parts array as the text. The order of the parts is the order of the images that the prompt refers to. It is better to set the aspect ratio with the imageConfig.aspectRatio parameter: a line in the prompt remains a hint, while the parameter is enforced.

The test: two characters in frame

The author used gemini-3.1-flash-image and two pairs of characters: a woman and a man, and two clearly different women. There were three prompt variants, three takes per pair, 18 generations in total:

  1. Bare: "these two meet in a café", with no roles and no distinguishing features.
  2. With roles: who sits, who stands, who is on the left. No image numbering.
  3. With numbering: "Image 1 is the woman: …", "Image 2 is the man: …", features described in words, and a direct ban on mixing up the faces.

The faces never swapped, and nobody sat with their back to the camera. The difference was in the details. In the bare prompt, in one take out of three, the heroine appeared in a dark jacket and a gold bracelet that are not on the reference, and she looked older. In another take, the text "EVENING SPECIALS" appeared on a board in the café. The variant with roles kept faces and clothing correct in 6 takes out of 6, but in two takes there were signs in the background even though the prompt said no text. The numbered variant produced 6 out of 6 with no errors and no text.

The main takeaway: the risk of a bare prompt is not swapped faces but drift of clothing and accessories away from the reference. Three takes per variant is a small sample, and you cannot use it to claim "N percent fewer errors". The comparison is also imperfect: the time of day differs across the bare prompts, and no text appeared only in the prompts with roles. The author did not test two similar-looking characters, such as brunettes in suits.

Video and Omni

For video, the author uses gemini-omni-1.1-flash through the Interactions API. Image roles are set with tags directly in the text: <FIRST_FRAME> for the first frame and <IMAGE_REF_n> for the character references. The working order is: first build and check a frame with both characters, then pass it as the first frame and add the references as references.

The model decides for itself where everyone ends up. Given the request "sits down across from her", the character sat next to her, because he was standing to the side. If the arrangement matters, you need a first frame in which the characters are already seated, so the video only has to supply the action.

gemini-omni-1.2-flash has been available since November 5, and from December 3 requests to 1.1 will be redirected to it. In it, duration became a parameter (from 3 to 15 seconds), and a second of 720p dropped in price from $0.10 to $0.07. But in one test the first-frame and last-frame tags did not work. A direct phrase at the start of the prompt helped: "The video starts exactly on the first image and ends exactly on the second image". The variant with a single FIRST_FRAME and IMAGE_REF was not tested on 1.2.

What to do in practice

  • Keep the hero's passport as a constant in code, not as text written anew each time.
  • For scenes with two characters, number the images and list distinguishing features. It costs a couple of lines and makes the prompt unambiguous.
  • Do not trust no text: check the background. In an ad, a sign behind the character will show up first.
  • Stitch the takes into a contact sheet and zoom in on suspicious frames. The author noticed the jacket and bracelet only when they sat next to clean takes.

On cost, a 1K image costs about $0.067, the whole 18-frame test about $1.21, and a 6-second clip on Omni 1.1 came to $0.63.

Story

Key Questions Answered

Why the face drifts?

The generator has no memory between requests. Each call builds the frame from scratch from the text and the attached images. So character consistency has to be enforced on the client side. The author proposes four elements: Passport: a fixed text block describing the character's appearance, pasted into every prompt byte for byte. It holds only what never changes: age, hair, eyes, distinguishing features. Do not put a smile or clothing in it, or the smile will show up in every frame.

What are the key details on The test: two characters in frame?

The author used gemini-3.1-flash-image and two pairs of characters: a woman and a man, and two clearly different women. There were three prompt variants, three takes per pair, 18 generations in total: Bare: "these two meet in a café", with no roles and no distinguishing features. With roles: who sits, who stands, who is on the left. No image numbering. With numbering: "Image 1 is the woman: …", "Image 2 is the man: …", features described in words, and a direct ban on mixing up the faces.

What are the key details on Video and Omni?

For video, the author uses gemini-omni-1.1-flash through the Interactions API. Image roles are set with tags directly in the text: <FIRST_FRAME> for the first frame and <IMAGE_REF_n> for the character references. The working order is: first build and check a frame with both characters, then pass it as the first frame and add the references as references. The model decides for itself where everyone ends up.

ZK
Zhemal Khamidun — CPO at Alpina Digital, product manager of AlpinaGPT. Building AI products since 2019. Hamidun News is a pet project that grew into a production aggregator with 6,000+ readers.
✦ Unified AI Workspace · Nomad

Test Frontier LLMs & Autonomous Agents in One Workspace

Run Claude Opus 5.5, GPT-6, Gemini 3.1, and DeepSeek side-by-side in Nomad AI (nomadnet.ai) — unified model routing, deep research, and multimodal workflows under one subscription.

Try Nomad AI →Launch Nomad Agent
What do you think?
Loading comments…