Identity Forge
One queue, a brand-new person every time — ComfyUI's Identity Forge, explained
- prompt_text
- prompt_json
You know the loop. You sit in ComfyUI trying to describe a person, type "young woman, auburn hair, green eyes," and get a face that's suspiciously close to every other face you generated this week. Or you batch for variety and half the outputs are the same person in a slightly different outfit. Identity Forge is the node that breaks that loop: it's a character generator built out of dropdowns. Pick the traits you care about, leave the rest on Random, and every queue hands you a new, internally consistent person described in clean prose you can wire straight into CLIP Text Encode.
That's the whole pitch, and it earns it. The dropdowns run to roughly seventy fields across Demographics, Body, Face, Hair, Makeup, Jewelry & Nails, Clothing, and Setting & Shot - enough granularity that you can lock "redhead, freckled, 25, librarian-ish" and let everything else roll. But the real trick is what happens between the roll and the output.
Why it doesn't produce prompt soup
If you've come from the wildcard world ({brown|blonde|black} hair), you know the failure mode: nothing stops a randomizer from rolling a buzz cut and braids, or a handbag with gym gear, or an Irish subject in ebony skin. Identity Forge's answer is a constraint engine that resolves those clashes after the fact. A buzz cut never gets a braid, "no makeup" clears every cosmetic, an athletic outfit drops the handbag. The priority order is the part worth internalizing: a rule never overrides a field you locked. It logs an [IdentityForge] notice and keeps your value. So "lock what you care about, let the rest roll" isn't a tagline, it's the mechanism.
One more design choice to know about: gender is a hard gate, not a coherence rule. Point a masculine preset at a Female node and it never produces a beard - the engine drops the incompatible value and re-rolls it inside the female pool. gender: Any resolves to a coherent man or woman per seed, so you never get a beard sitting next to a feminine bust.
The inputs that actually matter
seed- the control below defaults to randomize, so every run is a new person. Flip it to fixed and the same character comes back exactly. That's your reproducibility story, and it works.gender+wardrobe-gender: Anyrolls a coherent man OR woman per run. Addwardrobe: Anyand you unlock genuinely mixed-gender output. Want a man in feminine clothes without the mixed pools?wardrobe: Feminine.accessory_density- drop it toMinimalorNonefor clean portraits without hand-locking two dozen fields.location_setting-Studio / solid backdropforces a plain, easily maskable background (grey, white, black, chroma-key green) plus clean studio light. Your inpaint-friendly backgrounds come from here.set_all_fields-All to Noneblanks every field still on Random, so only the ones you lock appear. Ideal for a character-only description you want to splice into a scene you write yourself.
The scene fields deserve their own warning because people trip on them. The location is what stands: if it rolls an indoor spot, the lighting adapts to it - you never get a spice-market stall lit by "dappled sunlight through forest canopy." Most locations are interiors, which is why random daylight is deliberately rare. Set location_setting: Outdoor when you want sunny golden-hour looks, or lock a light like harsh desert sun and the location re-rolls to fit it.
Outputs
The node emits two things: prompt_text (STRING) - the natural-language paragraph you connect to CLIP Text Encode - and prompt_json (STRING), the same character as structured JSON nested by group, with a small _meta block. The JSON is what you feed to the pack's own Vault Save node, or use however you like.
Install
Zero dependencies, fully offline - no LLM, no API keys, no model downloads. requirements.txt is a comment saying exactly that.
cd ComfyUI/custom_nodes
git clone https://github.com/EnragedAntelope/comfyui-identity-forge
Then restart ComfyUI. Or use ComfyUI Manager and search "Identity Forge". One catch: the pack is built on ComfyUI's V3 API (comfy_api.latest) and needs ComfyUI 0.25.0 or newer - if it doesn't load after install, update ComfyUI first.
Troubleshooting
The one issue the maintainer documents: after a pack update you can hit a NoneType error or a blank/missing widget on a saved graph. The node's fields are built when it's created, so an old node holds stale widgets. Delete and re-add the node (or recreate it) and it clears - reselect any locked values afterward. Worth knowing that locking a field on a cosplay character you then chain upstream will respect it; the node closest to Identity Forge wins where presets overlap.
Honest caveat before you go: this generates text, and the checkpoint renders the person. It won't give you the same face across fifty renders - that's LoRA/adapter territory, and Identity Forge is a complement to it, not a replacement. Use it to roll OCs until one clicks, then build consistency around that. For its actual job - fast, varied, coherent people for portraits, crowds, or just staring at fresh faces - it's hard to beat.
Inputs (78)
| Name | Type | Default | Description |
|---|---|---|---|
| seed | INT | 00–18446744073709550000 | Seed for reproducible randomization. The control below defaults to 'randomize' so every run differs; set it to 'fixed' to reproduce a character. |
| gender | COMBO | Any | Steers gender-specific presentation and pronouns: 'Male' keeps the random fill masculine (no makeup, polish, feminine jewellery or hairstyles), 'Female' allows them. 'Any' rolls a coherent man OR woman each run (set wardrobe to 'Any' to instead unlock every mixed-gender combination). Locked / archetype / cosplayer values are always respected; 'Any' defers to a connected archetype's gender. |
| wardrobe | COMBO | Match gender | Which outfit wardrobe to draw from -- and how the character presents. 'Match gender' keeps outfits typical for the chosen gender; 'Feminine' / 'Masculine' force a wardrobe (e.g. a man in feminine outfits). 'Any' mixes outfits -- and, when gender is also 'Any', unlocks fully mixed-gender features too. On a man, 'Feminine' / 'Any' also lift the masculine defaults for jewellery, nails and makeup so a full femme look is reachable. 'Auto (preset)' defers to a wired character's own saved wardrobe (use it when recalling a vault save made with 'Any'). |
| size_scale | COMBO | Auto | Force an unrealistic body scale on an otherwise ordinary person -- a doll-sized office worker, a fifty-foot commuter. 'Auto' (the default) says nothing about scale and is NEVER chosen at random, so this control only ever does something when you pick a tier yourself -- it cannot affect normal randomized output. A tier replaces the height description in the opening sentence, and overrides a connected Cosplayer's own scale, so you can make any character giant or tiny. |
| hair_color_scope | COMBO | Natural only | Defaults to realistic hair colours; choose 'Full spectrum' to allow fantasy shades (pink, blue, ...). 'Auto (preset)' defers to a wired character's own saved scope (use it when recalling a vault save made with 'Full spectrum'). |
| accessory_density | COMBO | Balanced | How often random characters carry bags / jewellery / accessories. 'Balanced' keeps it tasteful, 'None' strips them, 'Maximal' decks everyone out. (Fields you lock are unaffected.) |
| location_setting | COMBO | Any indoor/outdoor | Restrict the random location. 'Any indoor/outdoor' (default) picks any real scene but never a studio. 'Studio / solid backdrop' forces a plain, easily-maskable background (grey, white, black, or chroma-key green screen) and a clean studio light. A locked location overrides this. |
| set_all_fields | COMBO | Off | Quick reset for the fields below. 'All to None' omits every field left on 'Random', so only the fields you lock to a specific value appear in the output. A wired costume and the character's signature look (hair, eyes, physique) are kept. Handy for tweaking a cosplay: blank the random-person noise, then enable just the fields you want. |
| age | COMBO | Random | Apparent age in years. Demographics · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| ethnicity | COMBO | Random | Also nudges skin tone toward a plausible range; locking skin tone overrides that. Demographics · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| skin_tone | COMBO | Random | Overall skin colour. A costume that colours the whole body replaces this. Body · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| body_type | COMBO | Random | Overall build and proportions. Muscle definition is separate - see fitness_level. Body · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| height | COMBO | Random | Relative height. To force an unrealistic scale (doll-sized, fifty feet tall), use the size_scale control near the top instead. Body · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| bust | COMBO | Random | Chest size and shape. Renders as 'chest' on a male subject. Body · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| waist | COMBO | Random | Waist width relative to the rest of the figure. Body · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| hips | COMBO | Random | Hip width relative to the rest of the figure. Body · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| face_shape | COMBO | Random | Overall shape of the face - oval, square, heart. Face · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| forehead | COMBO | Random | Forehead height and brow ridge. Face · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| cheekbones | COMBO | Random | How high and prominent the cheekbones sit. Face · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| eyebrows | COMBO | Random | Natural brow shape and thickness. Grooming and product are eyebrow_makeup. Face · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| eye_color | COMBO | Random | Iris colour. A cosplay character with non-human eyes overrides this. Face · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| eye_shape | COMBO | Random | Eye shape and set - almond, hooded, deep-set. Face · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| nose | COMBO | Random | Nose shape and bridge. Face · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| lips | COMBO | Random | Lip shape and fullness. Colour and finish are lips_makeup. Face · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| smile_type | COMBO | Random | What the mouth is doing - closed, toothy, smirking. Face · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| jawline | COMBO | Random | Jaw width and definition. Face · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| chin | COMBO | Random | Chin shape and projection. Face · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| complexion | COMBO | Random | Skin quality and undertone - rosy, sallow, weathered. Face · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| skin_details | COMBO | Random | Moles, beauty marks, scars and other distinguishing marks. Face · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| freckles_density | COMBO | Random | How heavily freckled the skin is. Face · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| hair_color | COMBO | Random | Limited to realistic shades unless the hair_color_scope control is set to 'Full spectrum'. Hair · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| hair_length | COMBO | Random | Hair length. Styles that need more length are automatically excluded on short cuts. Hair · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| hair_texture | COMBO | Random | Curl pattern and body - straight, wavy, coily, fine. Hair · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| hair_style | COMBO | Random | How the hair is worn. Styles needing gatherable length are dropped automatically on a pixie or a buzz cut, and the short barbered crops only appear on short hair. Hair · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| facial_hair | COMBO | Random | Beard and moustache. Randomized only on male subjects. Hair · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| hair_accessory | COMBO | Random | Headband, clip, scarf in the hair. Dropped automatically when a costume is supplied. Hair · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| makeup_style | COMBO | Random | The overall makeup look. Set it to 'no makeup' and every other Makeup field clears automatically; male subjects default to bare-faced. Makeup · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| eyebrow_makeup | COMBO | Random | Brow grooming and product. Natural brow shape is the eyebrows field. Makeup · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| eye_makeup | COMBO | Random | Eyeshadow colour and finish. Makeup · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| eyeliner | COMBO | Random | Liner style and weight. Makeup · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| lashes | COMBO | Random | Mascara or falsies. Makeup · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| contour | COMBO | Random | Sculpting on the cheeks, nose and jaw. Makeup · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| highlight | COMBO | Random | Where the skin catches the light. Makeup · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| blush | COMBO | Random | Cheek colour and placement. Makeup · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| lips_makeup | COMBO | Random | Lip colour and finish. Lip shape is the lips field. Makeup · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| skin_finish | COMBO | Random | How the base reads - matte, dewy, glass. Makeup · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| earrings | COMBO | Random | Ear jewellery. Name earrings in a costume only if you also lock this field, or you get two sets. Jewelry & Nails · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| necklace | COMBO | Random | Neck jewellery. Same caution as earrings if a costume already describes one. Jewelry & Nails · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| other_jewelry | COMBO | Random | Brooches, anklets, body chains and the like. Jewelry & Nails · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| piercings | COMBO | Random | Piercings other than earlobes. Jewelry & Nails · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| nails | COMBO | Random | Nail length, shape and polish. Jewelry & Nails · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| outfit_style | COMBO | Random | How dressed up, and for what occasion. Subculture and era themes live on the Archetype node instead. Clothing · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| bag | COMBO | Random | Bag carried. Dropped automatically when a costume is supplied. Clothing · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| accessories | COMBO | Random | Hats, glasses, gloves, belts and scarves. Dropped automatically when a costume is supplied, and gloves suppress nail polish and rings. Clothing · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| expression | COMBO | Random | The face the subject is pulling. Dropped automatically behind a full mask or helmet, unless you lock it. Setting & Shot · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| location | COMBO | Random | Where the shot happens, including named world landmarks. Narrow it with the location_setting control; a value locked here overrides that control. Setting & Shot · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| lighting | COMBO | Random | Quality and source of the light. Automatically kept coherent with whether the location is indoors or out. Set to 'None' if a downstream rendering pack owns this axis. Setting & Shot · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| shot_type | COMBO | Random | The camera only - distance, height, angle and lens. Never scene content. Setting & Shot · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| shoulder_width | COMBO | Random | Shoulder breadth relative to the hips. Body · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| neck_length | COMBO | Random | Neck length and thickness. Body · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| posture | COMBO | Random | How the subject carries themselves - upright, slouched, confident. Body · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| fitness_level | COMBO | Random | How conditioned the body looks, from sedentary to muscular. This is where muscle lives, not body_type. Body · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| hair_part | COMBO | Random | Where the hair is parted. Cleared automatically on a bald or buzzed head. Hair · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| hair_highlights | COMBO | Random | Colour worked through the hair - balayage, streaks, frosted tips. Hair · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| rings | COMBO | Random | Finger rings. Jewelry & Nails · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| bracelet | COMBO | Random | Wrist jewellery. Jewelry & Nails · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| watch_type | COMBO | Random | Wristwatch. Dropped automatically when a costume is supplied, so no smartwatch on a samurai. Jewelry & Nails · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| footwear | COMBO | Random | Shoes. Voiced with the generated outfit, so locking this actually changes the shoes. Narrowed to what the chosen outfit_style plausibly wears; a supplied costume overrides it. Clothing · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| clothing_color | COMBO | Random | Dominant palette of the outfit, voiced as an adjective in front of the garment ("a jewel-toned satin slip gown"). Yields to a garment that names its own colour. Clothing · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| clothing_pattern | COMBO | Random | Print or weave of the outfit. Yields to a garment that names its own (a denim or sequined piece), and a monochrome palette rules out multi-colour prints. Clothing · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| season | COMBO | Random | Time of year, which colours the setting and wardrobe. Setting & Shot · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| mood | COMBO | Random | Overall emotional tone of the image. Set to 'None' if a downstream rendering pack owns this axis. Setting & Shot · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| pose | COMBO | Random | What the body is doing. A pose needing something the subject lacks is dropped: hair or pockets to reach for, a free hand when a prop is held, a seat at giant scale. A lock wins. Setting & Shot · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| composition | COMBO | Random | Where the subject sits within the frame - layout, not camera position. Kept coherent with shot_type. Setting & Shot · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| tattoos | COMBO | Random | Body ink - style and how much of it. Deliberately uncommon at random, and scaled by the accessory density control. Where it sits is tattoo_placement. Body · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| legwear | COMBO | Random | Tights, stockings or socks. Only rendered when the outfit actually shows leg, so it never appears under trousers. Feminine wardrobe only. Clothing · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| tattoo_placement | COMBO | Random | Where the tattoo sits. Placements the clothing would hide are dropped automatically - no forearm ink under long sleeves, no thigh ink under a skirt-less outfit or opaque tights. Body · 'Random' = randomize, a value = lock, 'None' = omit from the output. |
| archetype_jsonopt | STRING | Connect an IdentityForgeArchetype, IdentityForgeCosplayer or IdentityForgeCreature here (chain several via their 'upstream' inputs). Its fields seed the character; explicit non-'Random' widgets still override it. Leave unconnected (or use 'None') for no override. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| prompt_text | STRING | — |
| prompt_json | STRING | — |