π² Scene Character Roller
Roll a whole cast of characters with one node each β no LoRAs required
- character
- components_json
- seed_used
The Scene Character Roller answers the question nobody likes asking in ComfyUI: who the hell is the person in my image? You've built a nice venue, you've picked a mood, and now there's an empty spot in the frame. Drop one of these in, pick an era, and it writes you a complete character - identity, outfit family, palette, face, posture - as one text string.
It's from the Scene Context pack (elliefox-ai/comfyui-scene-generator) by Ellie and Alexander Dutton, a small suite of procedural narrative-context nodes. The key rule: one node, one character. Have three people in your scene? Add three rollers. That's the whole design philosophy - and it's smart given how badly diffusion models merge two described characters into one blob. Since character is pure text, you can chain a roller into a Scene Context Picker or Composer slot, or just wire it into a CLIP Text Encode and forget the rest of the pack exists.
How it rolls
The mechanism is a seeded random walk over tagged banks, and it's refreshingly principled. Draw order is fixed and documented in the code: identity first, then genre, then everything downstream. The age, sex, and race inputs are each either π² random or a firm value; the resolved identity is stated once in an opening phrase ("an older white woman") and then every feature draw is soft-weighted toward it. That's affinity, never a filter - the tooltip puts it bluntly: "the occasional age-mismatched detail is the point." Vocabulary maps through phrase banks, so nothing raw leaks into your prompt.
The consistency slider (default 0.7) is the star. It's the probability that each garment honors one target outfit family pulled from the era's bank. At 1.0 you get head-to-toe coherence - one family, one palette, the full "this is a knight" look. At 0.0 every piece rolls independently - a thrift-store look, which for a drifter or scavenger is exactly what you want. detail flips between low - wide-shot legible: outer layer, face shape, hair, eyes, maybe one mark - and high, a portrait ladder of layers, wear, complexion, and build, sampled never exhaustive.
Three outputs: character (the assembled string), components_json (each piece exposed separately, in case you want to remix), and seed_used - more on that below.
The inputs that actually matter
You can touch everything, but a beginner really sets four things:
- genre - the era. Set a firm genre on every roller if you want a coherent cast; leave it π² and each character rolls its own era (weird, but occasionally delightful).
- consistency - how coherent the outfit is. 0.7 is a good default; push toward 1.0 for heroes, down toward 0.3 for street crowds.
- detail - low for wide shots, high for close-ups/portraits.
- seed - the node is a pure function of its inputs. Change the seed to re-roll, keep it to lock a character.
name is optional but worth knowing: "Abigail" prefixes the whole description and acts as a binding handle that helps the renderer keep details attached to that figure. pose and positioning bake in a stance or a frame-position phrase - the tooltip warns the scene nodes have the same toggles, so if both fire you get doubled placement, and that's on you.
Installing it
Via ComfyUI Manager, search for "comfyui-scene-generator" (pack title: comfyui-scene-generator). Or the manual way:
cd ComfyUI/custom_nodes/
git clone https://github.com/elliefox-ai/comfyui-scene-generator.git
Restart ComfyUI and look for the nodes under SceneGen in the menu. This is the good kind of node pack: zero extra Python dependencies, no models to download, no API keys. All local text logic over JSON banks - install takes seconds and it runs on anything.
Gotchas
The one real trap is the tag law. The pack validates every tag in its data files against tags.json at ComfyUI startup - an unknown tag is a hard startup failure that names the offending venue and stops ComfyUI from booting. By design (it catches data drift), but it means hand-editing the JSON banks and getting a tag wrong fails loudly and non-negotiably. Don't touch the data until you understand the registry.
Second gotcha is the re-roll footgun. The node is deterministic per seed, so ComfyUI's cache treats it like any pure node - change the seed to force a new roll, or you'll get the same character forever. And if you wire seed_used into a sampler, the roller's seed silently controls your whole generation, which is easy to forget when debugging why two runs look identical.
Is this the tool for locked, reusable characters? No - that's what LoRAs and reference/editing models are for. It's for the generative side: casting believable, varied people into scenes without hand-writing forty descriptions. For that, it's quietly excellent - one node per face, and your crowd scene stops looking like one person cloned six times.
Inputs (11)
| Name | Type | Default | Description |
|---|---|---|---|
| genre | COMBO | π² random | π² rolls this character's era independently. For a shared-era cast, set the same firm genre on every roller node (a shared source input is the parked next step). A firm genre binds every draw to that era's families. |
| consistency | FLOAT | 0.700β1 | How much this character honors the genre's substyle, garment by garment. 1 = full coherence: one outfit family head to toe, one palette. 0 = random character style: every piece rolls independently (firm genre keeps the mismatch within the era). Between = mostly-family with wandering pieces. |
| detail | COMBO | low | low = wide-shot legible: identity phrase, outer layer + palette, face shape, hair, eyes, maybe one mark β enough to read at distance without pulling the render into a close-up. high = portrait ladder (layers, wear, face architecture, complexion, build, demeanor), sampled β never the whole list. |
| role | COMBO | any | Genre-agnostic social function. Filters the concept banks; a family with no matching concepts falls back to its full bank. |
| name | STRING | Optional. 'Abigail'. Prefixes the description β a binding handle that helps the renderer cohere details to this specific figure. Blank = no name. | |
| pose | BOOLEAN | false | Bake a posture phrase into the character ('weight sunk into one hip'). Static stance register β no actions. |
| positioning | BOOLEAN | false | Bake a position phrase into the character ('on the near side of the frame'). The scene nodes have the same toggle β if both fire, doubled placement is on you. |
| seed | INT | 420β4294967295 | β |
| age | COMBO | π² random | π² rolls this figure's age, then weights every feature draw toward it (soft affinity β never a filter; the occasional age-mismatched detail is the point). Stated once in the identity phrase: 'an olderβ¦'. Fixed values weight the pools the same way. |
| sex | COMBO | π² random | π² rolls this figure's sex and weights feature draws toward it. Stated once in the identity phrase ('β¦woman' / 'β¦man'). The wardrobe banks stay unisex β sex never gates garments. |
| race | COMBO | π² random | Broad-stroke, descriptive register. π² rolls this figure's race, weights feature draws toward it, and (at detail=high) adds a complexion phrase keyed to it. Dropdown values never enter the string raw β vocabulary maps through phrase banks, stated once. |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| character | STRING | β |
| components_json | STRING | β |
| seed_used | INT | β |