The companion product feature your audience will pay for second-most (after memory) is images of her. Doing this well is a craft.
The use cases
- Hero portraits. Marketing, app icon, social.
- Expression set. For the avatar layer (→ ch. 25).
- Selfies. In-conversation images "of her" — the killer monetisation feature.
- Worldbuilding imagery. Settings, vignettes, the canon's atlas.
- Merch source art. Print, stickers, figures.
Why this register: the science of the look
Before the consistency machinery, the prior question most builders skip: why the stylised 2.5D anime register, and not photoreal? The honest answer isn't taste — it's two converging mechanisms (→ ch. 02 §7.4).
- Supernormal stimuli. Anime design exaggerates the cues of youth, health, and feminine dimorphism past anything in nature — large eyes and neoteny (Lorenz's Kindchenschema, the baby-schema that pulls caregiving and reads as cute), clear skin, an exaggerated waist-to-hip ratio, vivid hair. A supernormal stimulus (Tinbergen) triggers a stronger instinctive response than the realistic version, which is the visual half of why stylised characters out-pull photoreal ones for this audience, and why the appearance pathway is the male sexual on-ramp the demand-side data describes (→ ch. 06, five layers; Leshner et al. 2026). This is not an argument for maxing every cue to grotesque — past a point it reads as parody — but it is why "make her more real" is the wrong instinct.
- The uncanny valley. Photoreal raises the expectation of human perfection and then fails it: the closer to real, the more a small wrongness (dead eyes, off micro-expression, a hair-physics glitch) reads as corpse-like rather than charming. Stylisation sidesteps the valley entirely — a drawn character has no realism contract to violate, so minor render errors stay inside the style instead of breaking it. (This is also the avatar-rig lesson: stylised faces hold expression consistency where photoreal ones shatter it, → ch. 25.)
Together these are the design rationale the locked register encodes: a register deliberately unreal, tuned to exceed the natural stimulus on the cues that matter while staying clear of the valley. The rest of this chapter is how to render that register consistently.
The consistency problem
Naively generating "an anime girl" 100 times gives you 100 different anime girls. The companion-product requirement is the same anime girl, 1000 times, in varied poses/scenes. As of 2026 there are two complementary ways to get it, and a serious pipeline uses both:
- Train a character LoRA — durable identity. A low-rank adapter trained on 30–60 curated images of the hero, on a current base (recipe below). Best fidelity, fully portable, yours forever — but it costs a curation + training pass.
- Reference-driven editing — no training. Hand a model one example image plus a prompt — "her, in the rain, looking back" — and it holds her identity while changing scene, pose, and lighting. Instruction-following edit models are now good enough to carry a character across scenes with no per-character training at all (detailed just below — it's the most-asked question for this chapter).
In practice you bootstrap with the editing models to nail a canonical look fast, then graduate the hero to a LoRA once you have an on-model face to train from.
Reference-driven consistency (the editing models)
These take your original example and re-render her to a new prompt while holding identity — exactly the "same character, change the scene" problem. The 2026 open options, in rough order of fidelity:
- FLUX.1 Kontext [dev] (Black Forest Labs, open weights) — the character-consistency reference for instruction editing. Background swaps, pose/outfit changes, scene moves with strong identity preservation, all from a single reference. Runs in ComfyUI.
- Qwen-Image 2.0 (Alibaba, Feb 2026, ~7B — down from the 20B predecessor while scoring higher; native 2K, unified generation and editing in one model, GGUF builds fit 16 GB comfortably). It took #1 on AI Arena in both text-to-image and image editing, which makes it the current open editing reference and far lighter to run than the model it replaces. The older Qwen-Image-Edit (2511) (~20B, dual semantic-plus-appearance architecture) is still a fine edit-only option if you already run it — very good at holding face/proportions/clothing on subtle, incremental edits, though large transformations drift.
- FLUX.2 [dev] (open weights, ~32B — heavy: ~32 GB quantized, slow on consumer GPUs). Accepts up to 10 reference images in one generation for multi-shot identity/style/prop consistency — overkill for a single waifu, decisive for a recurring cast or signature objects. The new FLUX.2 [klein] (~4B, Apache-2.0, step-distilled to sub-0.5 s at 4 steps) is the low-VRAM/fast sibling — far weaker at multi-ref identity, but the one to reach for when speed matters more than holding a hard character lock.
- IP-Adapter (training-free, any SDXL/Flux base) — the lightweight option. Feed one or more reference images to steer an ordinary generation toward her look. Lower fidelity than Kontext/Qwen-Edit, but instant, free, and the natural building block inside a ComfyUI graph.
- Closed / hosted. Google's Nano Banana Pro (the Gemini image editor) now holds a decisive lead on single-shot identity-preserving edits and multi-image fusion; ByteDance Seedream 5.0 / 5.0 Lite (Feb 2026) is a strong rival — native 2K/4K in ~2–3 s, "deep-thinking" layout reasoning and optional live web-search, with edits that leave untouched regions alone; and Riverflow (Sourceful, reachable via OpenRouter) is another hosted editor in the same class. You won't ship a closed dependency in a user-owned product, but these are exactly the tools you reach for to bootstrap the LoRA dataset (the one-time reference-editing pass in the recipe below) — fidelity matters more than openness for that throwaway step. Test a few, and use whichever one holds your character best to build the set.
Decision rule: IP-Adapter for quick free steering; Kontext / Qwen-Edit when identity must really hold through a scene change; a LoRA for the canonical hero you'll render thousands of times.
Tooling
- ComfyUI. Open, modular, the power-user default — every model below ships ComfyUI graphs first. (A1111 is the older alternative, still used but increasingly behind.)
- Base generators (2026). Z-Image Turbo (Alibaba Tongyi, 6B, Apache-2.0) — ~2–3 s/image on a 4090 at 8 steps, runs in 6–16 GB VRAM; the best speed/quality balance for a solo creator's iteration loop. Qwen-Image 2.0 (Feb 2026, ~7B, native 2K, unified gen+edit) — top-tier prompt adherence and the best in-image text, broad styles including anime, and light enough to run locally. FLUX.2 — top controllability (HEX colours, JSON-structured prompts) and doubles as an editor; [dev] is heavy (~32 GB quantized, slow), [klein] (4B, Apache-2.0) is the fast low-VRAM variant. AnimagineXL 4.0 (Jan 2026), NoobAI-XL / Illustrious (and the community WAI-Illustrious daily-driver merge), and SDXL + anime LoRAs — the anime-native path; 2026's reality is several specialised branches rather than one winner, but together they carry by far the deepest community LoRA ecosystem. Note the branches are diverging on architecture: Animagine/Illustrious/NoobAI remain SDXL, while Pony V7 moved to the AuraFlow backbone — a cleaner base but a separate, smaller LoRA ecosystem, so "Pony" is no longer a drop-in SDXL sibling. For completeness at the top end, HunyuanImage 3.0 (Tencent, 80B-MoE, the largest open image model, autoregressive multimodal) exists but is impractical here — ~24 GB VRAM even quantized to INT4, hundreds of GB at full precision — so it's a frontier reference, not a companion-runtime option.
- Editing / consistency models. FLUX.1 Kontext, Qwen-Image-Edit, FLUX.2, IP-Adapter (see Reference-driven consistency above).
- Hosted inference. Replicate, Fal, Modal — run any of these pipelines without owning the GPU. Fast to ship.
- NovelAI. Closed, but still a strong reference point for anime character consistency.
Build it behind a backend seam
Don't hard-wire any one of the tools above into your runtime. Image
generation is the part of a companion product you will most want to
change: hosted today because it ships fast, local tomorrow once
you own a GPU, a different local model the moment you need the
intimate register a hosted endpoint refuses. So put generation behind a
single narrow interface — a generate / edit
seam every provider implements — and pick the provider from config. This
is the model-agnostic-runtime discipline (→ ch. 07) applied to images,
and it is how the reference implementation is built: one
ImageBackend with mock / hosted-API / ComfyUI /
local-diffusers implementations, swappable live, so the rest of
the runtime never knows or cares which pixels came from where. The seam
is also what makes the intimate register a backend decision, not
an engine policy (→ ch. 11): the same prompt routes to a hosted
model that refuses it or a local uncensored one that doesn't, and
nothing else in the stack changes. One image-specific caveat there —
censored flagships (Qwen-Image) don't merely refuse, they
sanitise; and because a low-denoise refine can only repaint
what the base already drew, you cannot add explicit anatomy back after
the fact. The intimate base has to come from an uncensored model in the
first place.
The seam pays off a second way: it makes multi-model pipelines cheap to try — use one model for what it's best at, hand off to another. The textbook version is a two-stage refine: a model with strong composition and prompt-adherence (a big DiT like Qwen-Image) lays down pose, scene, and lighting, then a low-denoise img2img pass on your register model (the anime SDXL that owns the 2.5D surface) repaints it on-register. We built and evaluated this and decided against it as the default. The quality lift was real but marginal once the face detailer (above) and a well-tuned single-model path were in place, and it cost on the order of 25× the render time — minutes per image — plus a looser identity from the hand-off and a warmer skin tone to fight. It stays in the reference implementation as an opt-in for the occasional hero still; the everyday default is one uncensored SDXL + the character LoRA, which is fast and good enough. Concretely, the reference implementation defaults to BSS Equinox (a 2.5D semi-realistic checkpoint in the Illustrious SDXL lineage, pulled from Civitai — the main community hub for SDXL fine-tunes and LoRAs). It earns the default on four counts: its 2.5D semi-realistic surface lands almost exactly on the locked register, so prompts need little fighting; the Illustrious lineage has by far the deepest community LoRA and tooling ecosystem, and the hero LoRA is trained natively on it so her face holds tightest; it's uncensored, which is what makes the intimate register a backend choice rather than a wall (→ ch. 11); and it renders an 832×1216 image in about a minute on a 16 GB GPU, fast enough for an iteration loop. None of that is sacred — it's one key in a model registry, swappable from config — but it's a worked example of which model, and why, rather than a hand-wave at "an anime SDXL." The general lesson outlasts this one pipeline: a clean backend seam lets you try a fancier path and back it out without touching the runtime.
Character LoRA recipe
The core of consistency (the same character, a thousand times). The hard part for a new character is the chicken-and-egg: a LoRA needs a varied set of on-model images, but the whole reason you want the LoRA is that you don't have one yet. You bootstrap out of it with the editing models. The pipeline that actually works, from a single frame:
- Pick one canon frame. Generate a batch in the locked register and choose the single best as the identity anchor — the "who." (We used the same model that made the brand art.)
- Synthesise the dataset by reference-editing. Feed
that one frame back in as a reference with new prompts — "same
character, now in a sunny kitchen in a sweater" — to get ~15–30
images of her across varied outfits, scenes, and framings, at full
quality. Quality and consistency beat count: 15 great,
on-model images train a better LoRA than 40 mediocre ones.
(Bootstrapping instead from a cheap IP-Adapter pass bakes that adapter's
lower fidelity into everything downstream — garbage in, garbage out.)
The reference implementation scripts this against a hosted edit model
picked at the command line —
build_lora_dataset_openrouter.py --model …(any OpenRouter image-edit model; default riverflow). There's no universal best editor for holding a character: test two or three on a small batch and build the full set with whichever stays most on-model. - Force diversity, or the LoRA overfits the pose. Reference-editing from one frame silently copies the source's head tilt and expression — a scenes-only set teaches the LoRA one tilt + one smile and it then resists every other angle/expression. Deliberately generate a batch that changes head angle and expression (look up/down, 3/4 profile, laughing, surprised, neutral), and rotate across 2–3 different anchor frames so pose varies at the source too. (Reference-editors soften strong negative affect like crying/anger; expect good positive/neutral range and lean on the base model at inference for extremes.)
- Caption the variable content, not the
identity. Each image: a unique trigger token
(
yuri_v2) + what changes (outfit, scene, expression) — never her face/hair/ears. You want the trigger to carry identity and the descriptive words to stay steerable. - Curate, then train a low-rank adapter on a current base — SDXL for the deepest anime LoRA ecosystem (and it trains comfortably on a 16 GB GPU: bf16, 8-bit Adam, gradient checkpointing, unet-only, ~1400 steps), or Flux / Z-Image for newer quality (→ ch. 20 for the shared low-rank-adapter idea and how the image recipe differs from a text tune).
- Wire it as the default and generate normally. Prepend the trigger; fuse the LoRA into the base. Now any prompt renders her in any scene/pose/outfit with no adapter fighting the prompt — consistency becomes a property of the model, not a per-render hack. Add ControlNet for explicit pose control when you need it.
Two tuning gotchas show up the moment you use it for real, both about over-imposing identity. First, don't bake the default outfit into the fixed identity prompt. If your always-prepended identity text reads "…in her signature black techwear," that sentence overrides every prompt and wardrobe choice downstream — ask for a summer dress and you still get the suit. Keep the fixed identity to the unchanging parts (face, ears, hair, signature marks) and make the signature outfit a default wardrobe option, not a hard-coded clause, so the prompt stays in charge of clothing. Second, tune the LoRA weight as a dial, not a constant: too high (≈1.0) and the trained look — including whatever she usually wore in the training set — bulldozes the prompt; too low and her identity drifts. ~0.7 is a sensible starting point, but the right value is per-base, not universal: on our daily-driver SDXL her face drifted at 0.7 and we settled at 0.9, so treat it as a dial — raise it if she stops looking like herself, lower it for more wardrobe latitude. Third, the LoRA is bound to the base it learned on. It transfers across a model lineage (e.g. the Illustrious SDXL family) well enough to load and render her — but her face quietly drifts on a base it wasn't trained on: body, skin and hair hold, the identity loosens into a generic version of her. So if you change your daily-driver base, retrain the LoRA on it (same dataset, same config, only the base swapped) and keep the base and its matching LoRA paired — a mismatched pair still renders "someone like her," not her.
Two more gotchas show up at generation time, not training.
First, on a semi-realistic base, realism tags backfire.
Words like photorealistic, 8k, realistic skin pull a
2.5D-capable model all the way to photoreal and straight off-register —
the opposite of what they read like they'd do. Lead instead with the
booru quality tags those anime bases were actually trained on
(masterpiece, best quality, very aesthetic), pick an
ancestral sampler (euler a), and let the prose pin the look; add realism
words only if you want to slide toward photoreal. Second,
SDXL's text encoder truncates at 77 tokens. A rich
register + identity + scene prompt silently loses everything past the
cutoff — so the carefully-locked identity tail just never reaches the
model — unless you encode it with a long-prompt helper (the reference
implementation uses sd_embed). A prompt that "mysteriously
ignores half of what you asked for" on SDXL is almost always this.
One failure that a better LoRA cannot fix deserves its own
note, because the instinct is to reach for more training data and that
is the wrong tool. In a full-body or overhead shot the face is
small, and a latent diffusion model works at one-eighth
resolution — so a distant face lands on a handful of latent pixels, far
too few to resolve two eyes with pupils and catchlights. The eyes come
out soft, asymmetric, or malformed. This is a resolution
problem, not an identity one: the model knows who she is, it
simply has no pixels to draw her eyes with, and no amount of retraining
or negative-prompting adds pixels that were never sampled. The fix is
post-hoc face restoration (the technique ADetailer
popularised): detect the face, crop it out, upscale that crop to full
resolution, re-render just the crop with the same fused LoRA so
identity carries, then feather it back into the frame. The face now gets
a full-resolution budget instead of a thumbnail's worth, and the eyes
resolve. It costs one short extra img2img pass per starved face and only
fires on faces below a size threshold — a face that already fills the
frame has enough pixels and is left alone. The reference implementation
ships this as an on-by-default face_detailer in the
diffusers backend (RetinaFace detection via facexlib). It
also ships the complementary hi-res fix — upscale the finished
frame and run a second low-denoise pass over the whole image, so global
detail (skin, hair, fabric) renders at a resolution the base pass never
had. The two stack: the hi-res fix lifts the whole image's crispness,
the detailer surgically rescues small faces (it runs second, on the
already-enlarged image). Both roughly double render time, so they are
the quality path you toggle off when you want fast on-demand
renders.
This is the same parameter-efficient adapter idea as text LoRA (→ ch.
20), applied to the image model. A complete, runnable version of this
exact pipeline — single-frame bootstrap, the diversity batch, the 16 GB
training config, and the LoRA wired in as the default generator — ships
in the reference implementation
(reference-implementations/image-forge/lora/TRAINING.md).
Holding identity across renders and rigs
The consistency problem above is "the same character a thousand times" within the generated images. The harder, often-skipped version is consistency across media: the generated selfie and the rigged avatar (→ ch. 25) have to read as the same person, not cousins. This breaks constantly because the two are built by different processes — the selfie comes from the LoRA, the Live2D/VRM body from a commission or a VRoid tune — and nobody checks them against each other until a user sees both side by side.
The discipline is a single source of truth: the hero portrait + character LoRA is the canonical face (→ ch. 25, avatar-as-brand), and every other render is built to match it, not the other way round.
- Rig toward the LoRA. Commission the Live2D art or tune the VRoid/VRM model to match the hero portrait's proportions, palette, and signature details (the locked register is the shared spec). Hand the artist the LoRA's outputs, not a vibe. (AI rigging can now bootstrap this — single-image → VRM is fairly mature, image → Live2D is research-stage — but an AI rig drifts off the canonical face harder than a briefed artist does, so it makes the round-trip check below matter more, not less. → ch. 25 for the tools and state of the art.)
- Validate by round-trip. Render the rig's neutral pose, then feed it through the LoRA / IP-Adapter and compare to a native LoRA generation. If they diverge, the rig drifted from canon — fix the rig, not the prompt.
- One expression vocabulary. Generate the ~28-expression set off the hero (LoRA + ControlNet) and use it as the shared reference for both the Live2D rig's expressions and the VRM blendshape mapping (→ ch. 25), so "happy" looks like the same happy across 2D art, 3D body, and selfie.
A one-person asset workflow
The whole pipeline a solo creator actually runs, start to identity-locked:
- Generate a hero portrait (Z-Image/Flux/SDXL, or refine one with Kontext/Qwen-Edit), hand-pick the most on-model.
- Bootstrap ~15–30 varied references from it by reference-editing (force angle/expression diversity); train the character LoRA.
- Generate the expression set off the LoRA (the shared vocabulary).
- Build the rig (Live2D commission or VRoid/VRM) toward steps 1–3; round-trip validate.
- Reuse the LoRA + expression set for selfies, marketing, and merch.
One person, one source of truth, every surface recognisably her — which is the entire point of locking the register (→ ch. 03 property 1, ch. 06).
Selfie prompts that don't collapse
The failure mode is every "selfie" resolving to the same five poses/framings. Fixes: maintain a prompt-template library with varied settings (the sanctuary, a window, outdoors), framings (close, mid, candid), and activities tied to canon (→ ch. 10), and rotate them; vary lighting and time-of-day to match conversation state (→ ch. 28 ambient state); and use ControlNet poses from a reference set so composition varies independently of identity.
Worldbuilding atlas
Beyond the character, render the canon (→ ch. 10) — the Sprawl, the sanctuary, key locations — into a consistent visual atlas. This deepens the world, feeds marketing and lore drops (→ ch. 38), and gives the persona scenery to reference. Lock the environment register the same way you lock the character (consistent palette, recurring motifs: rain, warm interiors).
Provenance and watermarking
For outbound generated images you can attach traceable provenance: C2PA / content credentials metadata, plus visible or invisible watermarking. For a hosted operator this is part of the duty of care (→ ch. 22), and it protects you by making your outputs distinguishable in disputes. In an open-source, user-owned build it's a sensible default to ship, not a control you can enforce downstream — which is why this chapter takes no enforcement posture on what gets generated.
Keep this distinct from a second, inward-facing kind of provenance: a reproducibility log. Outbound provenance is about what travels with a file you send (and your opsec posture is usually to strip it). The reproducibility log is the opposite — a private record, kept next to your outputs, of exactly how each image was made: backend, model (which checkpoint, which LoRA and at what weight, or which remote API), the full prompt and negative, seed, sampler, and dimensions. You want this the first time a user says "make another like that one" or you need to re-roll a render six months later, and it's the raw material for the A/B comparison below. Cheap to implement — a JSON sidecar per image plus an appended ledger line — and worth wiring in from day one; the reference implementation logs both for every backend.
A/B testing generations
Image quality and appeal are testable (→ ch. 23): generate variants (different LoRA checkpoints, prompts, samplers) and compare pairwise — on identity fidelity (is it unmistakably her?), on-register, and aesthetic appeal — rather than absolute scoring. The preference data also tells you which checkpoints to keep.