Scene Weaver - Horror
Staged Dread, Not Splatter (and No Gore by Default)
- entity_1_in
- entity_2_in
- entity_3_in
- entity_4_in
- prompt_text
- prompt_json
The Horror half of SceneWeaver runs on the same engine as the fantasy and sci-fi nodes, pointed at a different vocabulary - and it opens with a choice most horror prompt tools won't make: the gore filter starts on No gore.
Leave everything alone and you get something like a scene set in a flooded cellar of a gothic manor, a bog body kneeling in the standing water. Stillness is a situation here. That's the idea - dread staged rather than splattered - and if you want the wet stuff you flip one dropdown.
What's in it
Real horror vocabulary, not horror-flavoured fantasy: the dead (ghouls, vampires, bog bodies, drowned revenants), spirits (banshees, poltergeists, weeping apparitions), cryptids (werewolves, antlered stalkers, living scarecrows), eldritch horrors, mortals (cultists, masked stalkers, plague doctors, survivors), cursed objects (porcelain dolls, spirit boards, cracked mirrors) and haunted places (abandoned farmhouses, ruined chapels, derelict motels). Environments cover graveyards, wilds and rotting piers through to hospital morgues, taxidermy parlours, sewer tunnels and an otherworld bucket that is exactly what it sounds like.
The entity sockets are genre-agnostic, so you can cross the wires on purpose: a fantasy gorgon in a boarded-up church, a sci-fi construct in a haunted chapel. Supported feature, not an accident.
How it works
Same three mechanisms as its siblings, and they explain everything odd the node does.
Coherence at draw time. Fields narrow to what's legal for the kind you picked, and constraints are rules over values - a boarded-up house shows no lit windows, a petrified troll doesn't move. A value you locked beats a rule, and the reasoning for the rule that lost is reported in prompt_json._meta.
A detail budget. Four fully-described entities is about a 400-token prompt, and encoders quietly drop detail across one, so slot 1 is described in full and later slots briefly. Anything cut is written back to None, so prompt_json never promises a detail the image wasn't asked for. Your locks are never cut.
A node-face readout naming the scene you actually rolled, with a rough token count. Every widget says "Random"; this is the only place you see what Random drew.
The node re-runs on every queue by design, so randomize really does re-roll, and a fixed seed reproduces a scene exactly.
The controls that matter
scene_filter-No gore(the default),Any, orGore only.No goreleaves graphic wounds, blood and killing out of the description entirely. A value you lock yourself is always kept, whatever the filter says.entity_count- 1 to 4, and the authority on subject count: slots past it are dropped, slots inside it are filled even when their widgets sayNone. One entity has by far the highest hit rate.set_all_fields- a one-shot bulk action (Randomize all/Clear all) that snaps back toOffand never touches a locked value. Clear everything and lock oneenvironmentto get an empty, haunted room.environment, plus per slot:entity1_kind(which scopes the rest),subkind,scale,condition(rotting, freshly risen, entombed, boarded-up),form,material,primary_color,accent_color,markings,surface_detail,appendages+ count,emitters+ count +emitter_color,armament+ count,sensors+ count,aperture,extras, andentity1_situation- which in this genre is often something very still. Slots 2–4 expose only kind, subkind, scale, condition and situation.relation_1_2and friends, plus the_positionvariants - opt-in, defaultNone, rendered only when both entities exist.context- one more thing in the world for dread and story. Never a lighting instruction.- Four optional
entity_N_insockets for aSCENE_ENTITYpayload.
Outputs: prompt_text goes to your text encoder (and to a Show Text node), prompt_json is structured data - keep it out of the encoder.
Install
Manager: search SceneWeaver. Or:
cd ComfyUI/custom_nodes
git clone https://github.com/EnragedAntelope/comfyui-sceneweaver
Keep the directory named comfyui-sceneweaver, then restart. The pack has no dependencies - standard library only, no requirements.txt, nothing to build - but it wants ComfyUI 0.25.0+ and Python 3.10+. Nodes appear under conditioning/sceneweaver.
Your own monsters and locations go in a user_options.json beside the pack (gitignored, survives updates), in a "horror" section. Tags there drive the filter too: a value tagged conflict_only is what No gore hides.
python scripts/builtin_options.py subkind --kind cryptid --pack horror
Troubleshooting
Flat, lifeless images. The node writes no style on purpose - no lighting, no film stock, no mood - so you supply it. A horror-appropriate prefix through a StringConcatenate in front of prompt_text is the whole fix; the pack leaves how it looks to your checkpoint and LoRAs.
Gore where you didn't want it. Check what you locked. A locked armament or situation beats the filter - intentional, since choosing a value is an explicit statement of intent - but it surprises people who set No gore and then pinned a cleaver.
"I raised entity_count and it ignored my widgets." Slots past the count are dropped whatever they hold, and slots under it are described even if their kind still says None. Set the count first, then fill.
Every scene looks like a paraphrase of the last one. That's an unchanged fixed seed. Put the seed control back on randomize.
prompt_json in your encoder. It's JSON, not prose.
Inputs (61)
| Name | Type | Default | Description |
|---|---|---|---|
| seed | INT | 00–18446744073709550000 | Seed for reproducible scenes. The control below defaults to 'randomize' so every run differs; set it to 'fixed' to reproduce a scene. |
| entity_count | COMBO | 1 | How many subjects the scene has. Slot 1 is described most fully and later slots a little less, because an image has one subject's worth of attention to share out however many things are in it. Raising this reveals that slot's widgets on the node; every slot it reveals is described, never just named. Two is the sweet spot -- three and four work, and read as a crowd. A Scene Entity wired into a slot occupies it whatever this says. How much a slot actually speaks is also capped by what kind of thing it is: a creature or a person carries its whole component list, a station or a wreck only its silhouette, so a slot full of locked widgets can still read shorter than you expect. |
| scene_filter | COMBO | No gore | What random draws may pick. 'No gore' (the default) leaves graphic wounds, blood and killing out of the description entirely; 'Gore only' favours them. A value you lock yourself is always kept. |
| set_all_fields | COMBO | Off | Bulk-edit every descriptive widget below. 'Randomize all' turns each one that says 'None' into 'Random'; 'Clear all' does the reverse. A field you locked to a value is never touched, and the control snaps back to 'Off' as soon as it has run, so it stays a one-shot action rather than a mode. |
| environment | COMBO | Random | Where the scene is: the wilds, a graveyard, the water, a town, a room, underground, or somewhere that should not exist. Scene | Random=randomize, value=lock, None=omit |
| entity1_kind | COMBO | Random | What this entity fundamentally is. Scopes every other field on this slot -- its options and its labels. Set to None to leave the slot empty. Identity | Random=randomize, value=lock, None=omit |
| entity1_subkind | COMBO | Random | The specific type within the kind -- a ghoul, a banshee, a porcelain doll. Identity | Random=randomize, value=lock, None=omit |
| entity1_scale | COMBO | Random | How big it is relative to a person. Identity | Random=randomize, value=lock, None=omit |
| entity1_condition | COMBO | Random | Age, decay and state -- rotting, freshly risen, entombed, boarded-up. Identity | Random=randomize, value=lock, None=omit |
| entity1_form | COMBO | Random | The silhouette: a gait, a build, a body plan, a building's shape. Form & Material | Random=randomize, value=lock, None=omit |
| entity1_material | COMBO | Random | What it is covered in, made of, or wearing. Form & Material | Random=randomize, value=lock, None=omit |
| entity1_primary_color | COMBO | Random | The colour of the thing itself -- skin, robes, wallpaper. Never the lighting. Surface & Colour | Random=randomize, value=lock, None=omit |
| entity1_accent_color | COMBO | Random | A secondary colour: trim, a stain, a sash. Surface & Colour | Random=randomize, value=lock, None=omit |
| entity1_markings | COMBO | Random | Scrawled sigils, stains, burn marks. Carries no readable lettering. Surface & Colour | Random=randomize, value=lock, None=omit |
| entity1_surface_detail | COMBO | Random | Finish and wear at close range -- cracked varnish, grave dirt, wet rot. Surface & Colour | Random=randomize, value=lock, None=omit |
| entity1_appendages | COMBO | Random | What sticks out: antlers, claws, tendrils, a lantern pole, a chimney. Components | Random=randomize, value=lock, None=omit |
| entity1_appendage_count | COMBO | Random | How many. Composed into the appendage phrase. Components | Random=randomize, value=lock, None=omit |
| entity1_emitters | COMBO | Random | What shines with its own light: eyes that catch the dark, a lantern, a cold spectral flame. Components | Random=randomize, value=lock, None=omit |
| entity1_emitter_count | COMBO | Random | How many. Components | Random=randomize, value=lock, None=omit |
| entity1_emitter_color | COMBO | Random | The colour of the unnatural light. Belongs to the subject, not the lighting. Components | Random=randomize, value=lock, None=omit |
| entity1_armament | COMBO | Random | Weapons and implements, carried or grown: a cleaver, a sickle, claws. Components | Random=randomize, value=lock, None=omit |
| entity1_armament_count | COMBO | Random | How many. Components | Random=randomize, value=lock, None=omit |
| entity1_sensors | COMBO | Random | How it watches: eyes, too many eyes, a blank stare. Components | Random=randomize, value=lock, None=omit |
| entity1_sensor_count | COMBO | Random | How many. Components | Random=randomize, value=lock, None=omit |
| entity1_aperture | COMBO | Random | The opening: a mouth, a mask, a door hanging open. Components | Random=randomize, value=lock, None=omit |
| entity1_extras | COMBO | Random | One more distinguishing thing -- a lantern, a satchel, a chain of keys. Components | Random=randomize, value=lock, None=omit |
| entity1_situation | COMBO | Random | What this entity is doing -- often something very still. Scene | Random=randomize, value=lock, None=omit |
| entity2_kind | COMBO | Random | What this entity fundamentally is. Scopes every other field on this slot -- its options and its labels. Set to None to leave the slot empty. Identity | Random=randomize, value=lock, None=omit |
| entity2_subkind | COMBO | Random | The specific type within the kind -- a ghoul, a banshee, a porcelain doll. Identity | Random=randomize, value=lock, None=omit |
| entity2_scale | COMBO | Random | How big it is relative to a person. Identity | Random=randomize, value=lock, None=omit |
| entity2_condition | COMBO | Random | Age, decay and state -- rotting, freshly risen, entombed, boarded-up. Identity | Random=randomize, value=lock, None=omit |
| entity2_situation | COMBO | Random | What this entity is doing -- often something very still. Scene | Random=randomize, value=lock, None=omit |
| entity3_kind | COMBO | Random | What this entity fundamentally is. Scopes every other field on this slot -- its options and its labels. Set to None to leave the slot empty. Identity | Random=randomize, value=lock, None=omit |
| entity3_subkind | COMBO | Random | The specific type within the kind -- a ghoul, a banshee, a porcelain doll. Identity | Random=randomize, value=lock, None=omit |
| entity3_scale | COMBO | Random | How big it is relative to a person. Identity | Random=randomize, value=lock, None=omit |
| entity3_condition | COMBO | Random | Age, decay and state -- rotting, freshly risen, entombed, boarded-up. Identity | Random=randomize, value=lock, None=omit |
| entity3_situation | COMBO | Random | What this entity is doing -- often something very still. Scene | Random=randomize, value=lock, None=omit |
| entity4_kind | COMBO | Random | What this entity fundamentally is. Scopes every other field on this slot -- its options and its labels. Set to None to leave the slot empty. Identity | Random=randomize, value=lock, None=omit |
| entity4_subkind | COMBO | Random | The specific type within the kind -- a ghoul, a banshee, a porcelain doll. Identity | Random=randomize, value=lock, None=omit |
| entity4_scale | COMBO | Random | How big it is relative to a person. Identity | Random=randomize, value=lock, None=omit |
| entity4_condition | COMBO | Random | Age, decay and state -- rotting, freshly risen, entombed, boarded-up. Identity | Random=randomize, value=lock, None=omit |
| entity4_situation | COMBO | Random | What this entity is doing -- often something very still. Scene | Random=randomize, value=lock, None=omit |
| relation_1_2 | COMBO | None | How two slots relate. Rendered only when both entities exist. Opt-in. Relations | Random=randomize, value=lock, None=omit |
| relation_1_3 | COMBO | None | How two slots relate. Rendered only when both entities exist. Opt-in. Relations | Random=randomize, value=lock, None=omit |
| relation_1_4 | COMBO | None | How two slots relate. Rendered only when both entities exist. Opt-in. Relations | Random=randomize, value=lock, None=omit |
| relation_2_3 | COMBO | None | How two slots relate. Rendered only when both entities exist. Opt-in. Relations | Random=randomize, value=lock, None=omit |
| relation_2_4 | COMBO | None | How two slots relate. Rendered only when both entities exist. Opt-in. Relations | Random=randomize, value=lock, None=omit |
| relation_3_4 | COMBO | None | How two slots relate. Rendered only when both entities exist. Opt-in. Relations | Random=randomize, value=lock, None=omit |
| relation_1_2_position | COMBO | None | Where the first entity sits relative to the second. Relations | Random=randomize, value=lock, None=omit |
| relation_1_3_position | COMBO | None | Where the first entity sits relative to the second. Relations | Random=randomize, value=lock, None=omit |
| relation_1_4_position | COMBO | None | Where the first entity sits relative to the second. Relations | Random=randomize, value=lock, None=omit |
| relation_2_3_position | COMBO | None | Where the first entity sits relative to the second. Relations | Random=randomize, value=lock, None=omit |
| relation_2_4_position | COMBO | None | Where the first entity sits relative to the second. Relations | Random=randomize, value=lock, None=omit |
| relation_3_4_position | COMBO | None | Where the first entity sits relative to the second. Relations | Random=randomize, value=lock, None=omit |
| context | COMBO | Random | What else is in the shot besides the subject -- a secondary detail for dread and story. Always a thing in the world, never a lighting instruction. Scene | Random=randomize, value=lock, None=omit |
| staging | COMBO | Random | Where the first subject is in the place -- among the leaning headstones, at the far end of the hall. Said of the place, never of the picture. Scene | Random=randomize, value=lock, None=omit |
| aspect | COMBO | Random | What is happening to the place -- driving rain, fallen leaves, a ransacked room. Weather and state; never the time or the light. Scene | Random=randomize, value=lock, None=omit |
| entity_1_inopt | SCENE_ENTITY | Optional. A Scene Entity wired here describes slot 1, replacing that slot's own descriptive widgets and giving it the top allowance for the scene. It is a promotion, not an exemption: how much the slot speaks is still capped by what kind of thing it is, so a station reads shorter than a creature. A field you locked on the Scene Entity is a choice: it wins over these widgets and over a coherence rule, and the rule's reason is reported in prompt_json._meta. A field the Scene Entity drew at random is a draw: this scene first picks a place that can hold the whole wired subject, and re-draws a drawn field only when no place can -- the node face then names what was re-drawn. What the entity is *doing* stays this node's: situation and relations are never taken from a wired entity. | |
| entity_2_inopt | SCENE_ENTITY | Optional. A Scene Entity wired here describes slot 2, replacing that slot's own descriptive widgets and giving it the top allowance for the scene. It is a promotion, not an exemption: how much the slot speaks is still capped by what kind of thing it is, so a station reads shorter than a creature. A field you locked on the Scene Entity is a choice: it wins over these widgets and over a coherence rule, and the rule's reason is reported in prompt_json._meta. A field the Scene Entity drew at random is a draw: this scene first picks a place that can hold the whole wired subject, and re-draws a drawn field only when no place can -- the node face then names what was re-drawn. What the entity is *doing* stays this node's: situation and relations are never taken from a wired entity. | |
| entity_3_inopt | SCENE_ENTITY | Optional. A Scene Entity wired here describes slot 3, replacing that slot's own descriptive widgets and giving it the top allowance for the scene. It is a promotion, not an exemption: how much the slot speaks is still capped by what kind of thing it is, so a station reads shorter than a creature. A field you locked on the Scene Entity is a choice: it wins over these widgets and over a coherence rule, and the rule's reason is reported in prompt_json._meta. A field the Scene Entity drew at random is a draw: this scene first picks a place that can hold the whole wired subject, and re-draws a drawn field only when no place can -- the node face then names what was re-drawn. What the entity is *doing* stays this node's: situation and relations are never taken from a wired entity. | |
| entity_4_inopt | SCENE_ENTITY | Optional. A Scene Entity wired here describes slot 4, replacing that slot's own descriptive widgets and giving it the top allowance for the scene. It is a promotion, not an exemption: how much the slot speaks is still capped by what kind of thing it is, so a station reads shorter than a creature. A field you locked on the Scene Entity is a choice: it wins over these widgets and over a coherence rule, and the rule's reason is reported in prompt_json._meta. A field the Scene Entity drew at random is a draw: this scene first picks a place that can hold the whole wired subject, and re-draws a drawn field only when no place can -- the node face then names what was re-drawn. What the entity is *doing* stays this node's: situation and relations are never taken from a wired entity. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| prompt_text | STRING | The prompt. Wire this into the text encoder. |
| prompt_json | STRING | Structured scene data for other nodes or logs. Not a prompt: do not wire it into a text encoder. |