5.0 KiB
SOP — Character visual identity and appearance forms
Status: implemented. Covers how a character's avatar and concept (reference) sheet stay the same person, and how one character holds several appearances ("forms") without splitting into several characters or voices.
Single source of truth
- Appearance facts come from the sheet's
physical,clothing,age_estimate,race_species,gender,title,profession,archetype(and the user overridesvisual_appearance,visual_species,visual_costume). Both prompts are built by_character_visual_factsinroutes/conversation.py; the active form is overlaid first (_character_form_sheet, which never lets a form change its ownid/name). image_prompt(portrait) andconcept_art_prompt(reference sheet) are deterministic — built server-side from those facts with fixed camera/lighting/period text. Sheet extraction no longer asks the LLM to writeimage_prompt(it drifted from the concept sheet); the prompt is generated right after extraction bycsAutoGenerateExternalPrompts, and again before any avatar-only or per-form generation. A hand-edited prompt (*_user_edited) is never overwritten.- Only the two prompts describe an appearance.
voice_design_promptand the SillyTavern prompt belong to the character as a whole, so they always live on the base sheet.
Stale detection
_character_identity_fingerprint (server) and _libIdentityFingerprint (browser) hash the same
field list; a test runs the browser code in Node and compares, including list values and non-BMP
characters. The three visual_* overrides are appended only when set, so pairs made before they
existed keep a valid fingerprint. A pair needs review when its prompt version is not current, its
fingerprint is missing or differs, or identity_consistent is false. Regenerating only the
avatar or only the reference image sets identity_consistent = false on an existing pair,
because a lone regeneration produces a new face.
Where the data lives
| base appearance | a form | |
|---|---|---|
| profile image | record image |
form.image |
reference image, version, fingerprint, digests, identity_consistent |
sheet.* |
form.* |
| Physical / Clothing text | sheet.physical/clothing |
form.physical/clothing |
All visual results are written through one function (_libSaveCharacterVisual), which re-reads the
stored record, writes to the active form or the base, and saves. (It used to write the base
reference image to the record root, and the consistent-pair generator kept it in memory only, so a
base pair lost its reference image and metadata on reload.)
GET /api/characters/visual-pair-review checks the base pair and every form that has images, each
against its own metadata and its own fingerprint, and reports form pairs under the form name.
Forms (max 8 per character, enforced in core/validation.py)
Add (starts as a copy of the base Physical/Clothing; only non-empty keys are stored because an empty key would blank the base value when overlaid), rename (unique, ≤160 chars), delete (confirm; the character, its voice and the base look stay), show, and generate matched images for one form or for all forms. Generation rebuilds that form's prompts first (unless hand-edited), saves the pair on that form, then restores whichever appearance was active. Editing Physical/Clothing while a form is active changes only that form.
Image prompt hygiene and the turnaround (1.34.x)
- Setting. Prompts describe the books as The Dark Eye high-fantasy medieval dress (about 900-1300 AD: wool and linen tunics, belted robes, leather, mail where the sheet names it). The earlier "early Renaissance 1420-1500" wording pulled uniforms, coats, hats and boots that read as musketeer/cowboy/wartime.
- Wording. Extracted costume text is rewritten at prompt time (
_period_wording: Uniform, Weste, Hut, Sporen, Jacke, Schal … become surcoat, jerkin, hood, boots, tunic …). Stored sheets are not changed. - Injuries and dirt.
_strip_injury_clausesremoves clauses about blood, wounds, bandages, burns, limping, torn clothes, soot and dirt from appearance, costume and the story moment; the rest of the sentence stays. The portrait baseline asks for clean skin and garments. - Variety. Characters with armour or weapons get an individual garment cut and colour scheme (
_character_design_variation, stable per name; colours the sheet names win) instead of one shared list. - Same person in portrait and sheet. The profile picture is a crop of the full-body identity image. The front, side and rear views are drawn one by one with the edit model using that identity image as the only reference (no pose guides), then stitched into the three-panel image the compositor already crops. The old text-only triptych produced a different face.
- Props get an object-only period sentence, so a tile no longer turns into a portrait of the character.
- Older saved prompts are cleaned the same way at render time. Existing image pairs are unchanged until regenerated.