learnCharacters
@Element vs @Image: how each engine on the shelf addresses a character in a prompt
The reference-token rules for Kling, Seedance 2.5, Seedance 2.0 and Veo — and the one function our studio uses to generate the right token for each engine.
by reeldouble · October 25, 2026 · 7 min read
Every blog that explains Kling's @Element syntax stops at Kling. Every guide that explains Seedance's @Image syntax stops at Seedance. Nobody writes a single page that tells you how to address a character on all four of the engines that take references, because nobody is running all four. Our studio does, and the file that decides which token the prompt gets is a seven-line function.
Here is that function's answer, by engine, with the real caps.
The function our studio uses
The token a prompt should name a character by is model-dependent, and the file that mints it is lib/models.ts:
export function refToken(model: ModelKey, index: number): string {
const n = index + 1;
if (model === "kling_o3") return `@Element${n}`;
if (model === "veo_31_fast") return `image ${n}`;
return `@Image${n}`;
}
Three branches, five engines. Kling gets @Element1, @Element2, up to @Element5. Veo gets plain words — image 1, image 2, image 3. Everything else (Seedance 2.5, Seedance 2.0, Seedance 2.0 Fast) gets @Image1 indexed by position in the image list. That is the whole addressing contract, and every refusal, every quote and every prompt-rewrite path in the studio reads from it.
Kling O3 Pro — @Element1 … @Element5
Kling binds a character to an element, which is a reference package rather than a single image. An element is a frontal photo plus up to one or more optional angle references for the same subject. The engine encodes that identity once and holds it through the shot: through pans, dollies, whips, cut-arounds, close-ups and two-shots.
The addressing in the prompt is literal: @Element1 walks into frame from the left, stops at the counter, turns to camera. @Element2 is behind the counter, mid-task. The engine resolves @Element1 to the person inside element one and @Element2 to the person inside element two. There is no need to describe their faces again in the prompt body — the body is for staging and performance, not identity.
The cap is five elements per render on O3 Pro, proven by press on 2026-10-06. Vendor pages still say four; five pass the schema, five render, five are billed. The studio's refusal line uses that number: name six characters on a Kling render and the UI's text under Render asks you to drop one, or offers the roomier engine.
Seedance 2.5 — @Image1 … @Image30
Seedance addresses a reference by its position in the image list, as @Image1, @Image2, and so on. No frontal/angle distinction here — every image is a flat reference, and the prompt has to tell the model what each one is for. That is the one trap in the Seedance 2.5 prompt flow: upload three images and say "use these references" and the model has to guess which one is the face, which is the wardrobe, and which is the location. Half the time it guesses wrong.
The fix is one line per reference:
@Image1 defines Maya's face, hair and age only.
@Image2 defines Maya's green jacket and silver watch.
@Image3 defines the counter, the window and the warm morning light.
Each @ImageN is a role, not an identity. The engine lifts the face from one, the clothes from the second, the environment from the third, and composes.
The cap is thirty images per render on Seedance 2.5. That is the number Segmind's probe answered on 2026-10-02 ("Up to 30 reference images allowed, got 31"). The studio uses that header for a crowd scene with multiple named characters, each with a few angle photos — thirty slots is enough room for ten characters at three images apiece, or three characters at ten.
If several of the images show the same subject from different angles, the prompt has to say so. Otherwise Seedance will treat four images of one coffee maker as four different coffee makers and composite them into one frame. The rule in our studio's prompt scaffold: @Image1, @Image2 and @Image3 show the same subject from front, side and rear. The scene contains one <subject> only.
Seedance 2.0 and 2.0 Fast — @Image1 … @Image9
Same syntax as 2.5 but a smaller list. The cap on 2.0 and 2.0 Fast is nine images per render, probed the same day with the same method ("List should have at most 9 items"). The prompt flow is the same — one line per reference, roles made explicit, same-subject angles grouped — but the budget is tighter: nine is enough for three characters at three references apiece, or one character and a handful of locations.
The upside of the smaller list is speed. 2.0 Fast at 25 credits a second (480p) is the cheapest voiced row on the shelf, and the nine-image ceiling is a hint that this engine wants shorter prompts and tighter scenes rather than a thirty-slot epic.
Veo 3.1 Fast — image 1, image 2, image 3
Veo has no addressing syntax at all. Google ships ingredients-to-video on 3.1 and 3.1 Fast, accepts up to three images, and refers to them in the prompt as plain words — image 1, image 2, image 3. There is no @ prefix, no index, no reserved token. Which is why our refToken returns a space-separated string here, not an @-tagged one.
The three images are, in order:
- Image 1 — the main subject (person, product or character), front-facing.
- Image 2 — a secondary subject or the environment.
- Image 3 — a style or wardrobe reference.
Three slots is the ceiling, and a reference render on Veo is pinned to eight seconds whatever the slider shows — that is the one difference from Veo's text-to-video mode, where the length is a free toggle (4, 6 or 8). The pin is in the catalogue as refSeconds: 8 and the studio quotes eight seconds for a reference generation regardless of what you asked, because that is the length the provider renders and bills.
The decision rule, as a table
| if you need | the engine | the token | the cap |
|---|---|---|---|
| 1–5 characters, identity holds through moves, 720p | Kling O3 Pro | @ElementN | 5 elements |
| 6–30 references, mixed faces + wardrobe + location, up to 30s | Seedance 2.5 | @ImageN | 30 images |
| 1–9 references, up to 15s, cheap voiced output | Seedance 2.0 or 2.0 Fast | @ImageN | 9 images |
| 1–3 references, 8s, native audio | Veo 3.1 Fast | image N (plain words) | 3 images |
The pattern a prompt reads cleanly: upload the images, name them in the prompt by the token the engine takes, say what each reference is for in one line.
Why the function is where the truth lives
The specific failure this function exists to prevent is a prompt rewritten the wrong way between engines. A prompt that says @Element1 and gets routed through Seedance renders a shot with no character — the engine does not resolve @Element to anything and treats the token as literal text. A prompt that says @Image1 on Veo renders a shot with "@Image1" baked into the generation as graffiti on a wall. The token is the contract between the prompt and the model, and the only way to get it right across five engines is to call one function.
Which is why the studio's prompt scaffold calls refToken(model, i) for every character the user tags, every time. If you move a scene from Kling to Seedance 2.5, the scaffold rewrites @Element1 to @Image1 on the way over. If you move the same scene to Veo, it rewrites to image 1 with the space. The user never has to remember which syntax is which — the file does, and the file's answer is the one that reaches the model.
The practical consequence: a reference-sheet workflow built once holds across the four engines that take references, with the token swap handled at render time. That is the thing the one-engine blogs on this query cannot write about, because none of them run four engines on one shelf.
What this looks like in a real prompt
A two-character café scene on Seedance 2.5, 720p, 20 seconds, four references (two faces, two outfits):
@Image1 defines Maya — face, hair, mid-20s only.
@Image2 defines Dev — face, hair, mid-20s only.
@Image3 defines Maya's cream linen jacket and tan tote.
@Image4 defines Dev's navy sweatshirt and silver chain.
Open on Maya mid-counter, left of frame, pouring coffee into a white
cup. Camera dollies slowly right past her shoulder to reveal Dev at the
window seat looking up from a book, raising his cup slightly in a wave.
Warm morning light from the right. Soft room tone, no dialogue.
The same scene on Kling O3 Pro, with Maya and Dev as elements:
@Element1 is mid-counter, left of frame, pouring coffee into a white cup.
@Element2 is at the window seat, looking up from a book, raising his cup
slightly in a wave. Camera dollies right past @Element1's shoulder to reveal
@Element2. Warm morning light from the right.
Shorter prompt, same scene, same identity. That is what an element earns the user over a flat image list: the character identity does not need re-describing in the prompt body.
The one function. Four engines. One scaffold that calls the function. That is how our prompts come out right regardless of which row the render card is pointing at.
FAQ
What is the difference between @Element and @Image in an AI video prompt?
Kling O3 Pro addresses a character as an element, written @Element1 to @Element5, where each element is a reference package that holds identity through the shot. Seedance addresses references by their position in the image list, written @Image1, @Image2 and so on, and each image is a flat reference whose role the prompt must state.
How many reference images can I use on Kling, Seedance and Veo?
Kling O3 Pro takes five elements per render, Seedance 2.5 takes thirty images, Seedance 2.0 and 2.0 Fast take nine, and Veo 3.1 Fast takes three. ReelDouble prints these caps and refuses a render that names more characters than the engine holds.
How do I reference images in a Veo 3.1 prompt?
Veo has no addressing syntax. It accepts up to three images and refers to them in plain words as image 1, image 2 and image 3, with no @ prefix. A reference render on Veo is pinned to eight seconds whatever the length slider shows.
Why does my Seedance render mix up which reference is the face?
If you upload several images and only say "use these references", Seedance has to guess which one is the face, the wardrobe or the location. Write one line per reference stating its role, and say so when several images show the same subject from different angles.
What happens if I use the wrong reference token for an engine?
A prompt that says @Element1 on Seedance renders a shot with no character, and @Image1 on Veo can come out as literal text in the frame. ReelDouble's prompt scaffold rewrites the token automatically when you move a scene between engines, so you never have to remember which syntax goes where.


