Nodes/SceneWeaver/Scene Weaver - Horror
ComfyUI Node

Scene Weaver - Horror

Staged Dread, Not Splatter (and No Gore by Default)

By EnragedAntelope·Created 29 days ago·Updated 2 days ago· 4
Scene Weaver - Horror
  • entity_1_in
  • entity_2_in
  • entity_3_in
  • entity_4_in
  • prompt_text
  • prompt_json
◄seed0►
◄entity_count1►
◄scene_filterNo gore►
◄set_all_fieldsOff►
◄environmentRandom►
◄entity1_kindRandom►
◄entity1_subkindRandom►
◄entity1_scaleRandom►
◄entity1_conditionRandom►
◄entity1_formRandom►
◄entity1_materialRandom►
◄entity1_primary_colorRandom►
◄entity1_accent_colorRandom►
◄entity1_markingsRandom►
◄entity1_surface_detailRandom►
◄entity1_appendagesRandom►
◄entity1_appendage_countRandom►
◄entity1_emittersRandom►
◄entity1_emitter_countRandom►
◄entity1_emitter_colorRandom►
◄entity1_armamentRandom►
◄entity1_armament_countRandom►
◄entity1_sensorsRandom►
◄entity1_sensor_countRandom►
◄entity1_apertureRandom►
◄entity1_extrasRandom►
◄entity1_situationRandom►
◄entity2_kindRandom►
◄entity2_subkindRandom►
◄entity2_scaleRandom►
◄entity2_conditionRandom►
◄entity2_situationRandom►
◄entity3_kindRandom►
◄entity3_subkindRandom►
◄entity3_scaleRandom►
◄entity3_conditionRandom►
◄entity3_situationRandom►
◄entity4_kindRandom►
◄entity4_subkindRandom►
◄entity4_scaleRandom►
◄entity4_conditionRandom►
◄entity4_situationRandom►
◄relation_1_2None►
◄relation_1_3None►
◄relation_1_4None►
◄relation_2_3None►
◄relation_2_4None►
◄relation_3_4None►
◄relation_1_2_positionNone►
◄relation_1_3_positionNone►
◄relation_1_4_positionNone►
◄relation_2_3_positionNone►
◄relation_2_4_positionNone►
◄relation_3_4_positionNone►
◄contextRandom►
◄stagingRandom►
◄aspectRandom►

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, or Gore only. No gore leaves 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 say None. One entity has by far the highest hit rate.
  • set_all_fields - a one-shot bulk action (Randomize all / Clear all) that snaps back to Off and never touches a locked value. Clear everything and lock one environment to 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, and entity1_situation - which in this genre is often something very still. Slots 2–4 expose only kind, subkind, scale, condition and situation.
  • relation_1_2 and friends, plus the _position variants - opt-in, default None, 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_in sockets for a SCENE_ENTITY payload.

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.

Categoryconditioning/sceneweaver

Inputs (61)

NameTypeDefaultDescription
seedINT00–18446744073709550000Seed for reproducible scenes. The control below defaults to 'randomize' so every run differs; set it to 'fixed' to reproduce a scene.
entity_countCOMBO1How 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_filterCOMBONo goreWhat 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_fieldsCOMBOOffBulk-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.
environmentCOMBORandomWhere 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_kindCOMBORandomWhat 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_subkindCOMBORandomThe specific type within the kind -- a ghoul, a banshee, a porcelain doll. Identity | Random=randomize, value=lock, None=omit
entity1_scaleCOMBORandomHow big it is relative to a person. Identity | Random=randomize, value=lock, None=omit
entity1_conditionCOMBORandomAge, decay and state -- rotting, freshly risen, entombed, boarded-up. Identity | Random=randomize, value=lock, None=omit
entity1_formCOMBORandomThe silhouette: a gait, a build, a body plan, a building's shape. Form & Material | Random=randomize, value=lock, None=omit
entity1_materialCOMBORandomWhat it is covered in, made of, or wearing. Form & Material | Random=randomize, value=lock, None=omit
entity1_primary_colorCOMBORandomThe colour of the thing itself -- skin, robes, wallpaper. Never the lighting. Surface & Colour | Random=randomize, value=lock, None=omit
entity1_accent_colorCOMBORandomA secondary colour: trim, a stain, a sash. Surface & Colour | Random=randomize, value=lock, None=omit
entity1_markingsCOMBORandomScrawled sigils, stains, burn marks. Carries no readable lettering. Surface & Colour | Random=randomize, value=lock, None=omit
entity1_surface_detailCOMBORandomFinish and wear at close range -- cracked varnish, grave dirt, wet rot. Surface & Colour | Random=randomize, value=lock, None=omit
entity1_appendagesCOMBORandomWhat sticks out: antlers, claws, tendrils, a lantern pole, a chimney. Components | Random=randomize, value=lock, None=omit
entity1_appendage_countCOMBORandomHow many. Composed into the appendage phrase. Components | Random=randomize, value=lock, None=omit
entity1_emittersCOMBORandomWhat 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_countCOMBORandomHow many. Components | Random=randomize, value=lock, None=omit
entity1_emitter_colorCOMBORandomThe colour of the unnatural light. Belongs to the subject, not the lighting. Components | Random=randomize, value=lock, None=omit
entity1_armamentCOMBORandomWeapons and implements, carried or grown: a cleaver, a sickle, claws. Components | Random=randomize, value=lock, None=omit
entity1_armament_countCOMBORandomHow many. Components | Random=randomize, value=lock, None=omit
entity1_sensorsCOMBORandomHow it watches: eyes, too many eyes, a blank stare. Components | Random=randomize, value=lock, None=omit
entity1_sensor_countCOMBORandomHow many. Components | Random=randomize, value=lock, None=omit
entity1_apertureCOMBORandomThe opening: a mouth, a mask, a door hanging open. Components | Random=randomize, value=lock, None=omit
entity1_extrasCOMBORandomOne more distinguishing thing -- a lantern, a satchel, a chain of keys. Components | Random=randomize, value=lock, None=omit
entity1_situationCOMBORandomWhat this entity is doing -- often something very still. Scene | Random=randomize, value=lock, None=omit
entity2_kindCOMBORandomWhat 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_subkindCOMBORandomThe specific type within the kind -- a ghoul, a banshee, a porcelain doll. Identity | Random=randomize, value=lock, None=omit
entity2_scaleCOMBORandomHow big it is relative to a person. Identity | Random=randomize, value=lock, None=omit
entity2_conditionCOMBORandomAge, decay and state -- rotting, freshly risen, entombed, boarded-up. Identity | Random=randomize, value=lock, None=omit
entity2_situationCOMBORandomWhat this entity is doing -- often something very still. Scene | Random=randomize, value=lock, None=omit
entity3_kindCOMBORandomWhat 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_subkindCOMBORandomThe specific type within the kind -- a ghoul, a banshee, a porcelain doll. Identity | Random=randomize, value=lock, None=omit
entity3_scaleCOMBORandomHow big it is relative to a person. Identity | Random=randomize, value=lock, None=omit
entity3_conditionCOMBORandomAge, decay and state -- rotting, freshly risen, entombed, boarded-up. Identity | Random=randomize, value=lock, None=omit
entity3_situationCOMBORandomWhat this entity is doing -- often something very still. Scene | Random=randomize, value=lock, None=omit
entity4_kindCOMBORandomWhat 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_subkindCOMBORandomThe specific type within the kind -- a ghoul, a banshee, a porcelain doll. Identity | Random=randomize, value=lock, None=omit
entity4_scaleCOMBORandomHow big it is relative to a person. Identity | Random=randomize, value=lock, None=omit
entity4_conditionCOMBORandomAge, decay and state -- rotting, freshly risen, entombed, boarded-up. Identity | Random=randomize, value=lock, None=omit
entity4_situationCOMBORandomWhat this entity is doing -- often something very still. Scene | Random=randomize, value=lock, None=omit
relation_1_2COMBONoneHow two slots relate. Rendered only when both entities exist. Opt-in. Relations | Random=randomize, value=lock, None=omit
relation_1_3COMBONoneHow two slots relate. Rendered only when both entities exist. Opt-in. Relations | Random=randomize, value=lock, None=omit
relation_1_4COMBONoneHow two slots relate. Rendered only when both entities exist. Opt-in. Relations | Random=randomize, value=lock, None=omit
relation_2_3COMBONoneHow two slots relate. Rendered only when both entities exist. Opt-in. Relations | Random=randomize, value=lock, None=omit
relation_2_4COMBONoneHow two slots relate. Rendered only when both entities exist. Opt-in. Relations | Random=randomize, value=lock, None=omit
relation_3_4COMBONoneHow two slots relate. Rendered only when both entities exist. Opt-in. Relations | Random=randomize, value=lock, None=omit
relation_1_2_positionCOMBONoneWhere the first entity sits relative to the second. Relations | Random=randomize, value=lock, None=omit
relation_1_3_positionCOMBONoneWhere the first entity sits relative to the second. Relations | Random=randomize, value=lock, None=omit
relation_1_4_positionCOMBONoneWhere the first entity sits relative to the second. Relations | Random=randomize, value=lock, None=omit
relation_2_3_positionCOMBONoneWhere the first entity sits relative to the second. Relations | Random=randomize, value=lock, None=omit
relation_2_4_positionCOMBONoneWhere the first entity sits relative to the second. Relations | Random=randomize, value=lock, None=omit
relation_3_4_positionCOMBONoneWhere the first entity sits relative to the second. Relations | Random=randomize, value=lock, None=omit
contextCOMBORandomWhat 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
stagingCOMBORandomWhere 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
aspectCOMBORandomWhat 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_inoptSCENE_ENTITYOptional. 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_inoptSCENE_ENTITYOptional. 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_inoptSCENE_ENTITYOptional. 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_inoptSCENE_ENTITYOptional. 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)

NameTypeDescription
prompt_textSTRINGThe prompt. Wire this into the text encoder.
prompt_jsonSTRINGStructured scene data for other nodes or logs. Not a prompt: do not wire it into a text encoder.