Nodes/ComfyUI_StarNodes/⭐ Star Horror Villains Builder
ComfyUI Node

⭐ Star Horror Villains Builder

From Masked Slasher to Cenobite Without Typing a Word

By Starnodes2024·Created 2 years ago·Updated 6 days ago· 120
⭐ Star Horror Villains Builder
    • description
    • villain_sheet
    • system_prompt
    ◄sexnone►
    ◄villain_typenone►
    ◄sizenone►
    ◄facenone►
    ◄hairnone►
    ◄skinnone►
    ◄eyesnone►
    ◄body_buildnone►
    ◄outfitnone►
    ◄weaponnone►
    ◄injuriesnone►
    ◄accessoriesnone►
    ◄auranone►
    ◄expressionnone►
    ◄posenone►
    ◄customnone►
    ◄stylecinematic horror film still►
    ◄age►
    ◄random_agefalse►
    ◄additional►
    ◄seed0►
    ◄random_allfalse►

    Horror is the genre where being vague gets you a guy in a hoodie. Ask for "a scary killer" and you get the same stock silhouette: no mask logic, no weapon, no wrongness in the skin. The specificity is the whole job, and nobody wants to type it at 1am.

    ⭐ Star Horror Villains Builder is the StarNodes answer. Seventeen dropdowns, three string outputs, no model, no VRAM. Pick an archetype, then pick what's wrong with it - the mask, the skin, the eyes, what it's holding - and the node assembles the prompt.

    The mechanism, which is dumber and more useful than it sounds

    Options live in json/star_horror_villains_builder.json: 17 lists (51 villain types in one of them), plus settings and a system_prompt. On load each list becomes a dropdown with none, random and exclude prepended.

    none skips the category, random picks an entry, and exclude skips it and keeps it out when random_all is on - which is the point of three states instead of a checkbox. Set face and weapon to exclude with your choices locked in, flip random_all on, and you'll roll endless villains who all wear the same mask and carry the same blade. That's how you build a cast instead of a grab bag.

    seed controls every pick: 0 re-rolls each queue, a pinned number reproduces the villain. The node reports itself changed on every run (its IS_CHANGED returns a timestamp), so nothing is cached and seed: 0 genuinely re-rolls.

    One bit of actual language handling: entries from the face list get an article with the right vowel rule, so it reads "…with a burlap sack mask", not "…with burlap sack mask". Tiny, and why the sheet output reads like prose instead of tag soup.

    Three outputs, three jobs

    description is the plain comma-separated prompt. villain_sheet specifies a reference layout - two tall full-body panels left (front and back), a 3×2 detail grid right (face/mask front, profile, 45°, chest, pelvis, rear), expanding to 4×2 with close-ups of mask and weapon.

    Then the style clause: "presented in a clinical and scientific way like a forensic case file, with flat, even studio lighting… and enforces absolute consistency in the villain's… appearance across every panel." A deliberate tonal collision - your style, shot like evidence. For a sheet it's the right call: even lighting is what stops a grid drifting into three different monsters, the failure mode anyone who's chased a turnaround knows (character-consistency.md).

    system_prompt is the instruction text you'd feed an LLM to write these sheets itself, think-step-by-step preamble and all. Steal it if you're wiring an Ollama or API node upstream - LLM-assisted prompting went from novelty to default practice over 2025–26, and this saves you writing the system message (prompt-engineering.md).

    What to actually set

    • villain_type - 51 entries, doing more work than the rest combined: killer doll, ventriloquist dummy, cenobite, masked slasher, chainsaw butcher.
    • face - 33 options, because the mask is the character. Burlap sack, scratched hockey mask, mask made of human skin.
    • weapon, injuries, aura - what stops it reading as generic; aura is the one people forget.
    • style - defaults to cinematic horror film still and lands in both outputs; the only dropdown whose default isn't none.
    • age - free text; a number becomes 43 year old, random_age rolls 25–90.

    Install

    Manager → search Starnodes → Install → restart, or:

    cd ComfyUI/custom_nodes
    git clone https://github.com/Starnodes2024/ComfyUI_StarNodes
    cd ComfyUI_StarNodes
    pip install -r requirements.txt
    

    The builder imports nothing beyond the standard library - the pip line is for the pack's other hundred-odd nodes, and install.py runs no installs of its own, so a bare clone still leaves you a working text node.

    On the pack generally: it's a solo-run toolbox that updates constantly. Upside, things get fixed fast. Downside, re-check a workflow built on a StarNodes node after an update.

    Where people get burned

    Editing the JSON does nothing until you restart. Dropdown lists are read at module load. random picks re-read the file every run, so a new mask gets used immediately - you just won't see it in the dropdown yet.

    Broken JSON fails quietly. The loader swallows the exception, prints StarNodes: Could not load star_horror_villains_builder.json, and hands back empty lists. The node still runs; the dropdowns shrink to three options and the prompt comes out nearly blank. Validate first:

    python3 -m json.tool ComfyUI/custom_nodes/ComfyUI_StarNodes/json/star_horror_villains_builder.json > /dev/null
    

    The sheet came out unclothed. There's a single outfit field here, not a wear rule, and if it's none the sheet prompt says plainly that the villain is unclothed in the full-body panels. Set an outfit, or set the field to exclude - the tooltip is honest about which way that cuts.

    random_all overwrote your choices. Intended - that's what exclude is for.

    Category⭐StarNodes/Text And Data

    Inputs (22)

    NameTypeDefaultDescription
    sexCOMBOnone'none' skips this trait, 'random' picks a random entry, 'exclude' keeps it out of the prompt even when random_all is on. Add your own entries in json/star_horror_villains_builder.json (restart ComfyUI to see them in this list, 'random' uses them right away).
    villain_typeCOMBOnone'none' skips this trait, 'random' picks a random entry, 'exclude' keeps it out of the prompt even when random_all is on. Add your own entries in json/star_horror_villains_builder.json (restart ComfyUI to see them in this list, 'random' uses them right away).
    sizeCOMBOnone'none' skips this trait, 'random' picks a random entry, 'exclude' keeps it out of the prompt even when random_all is on. Add your own entries in json/star_horror_villains_builder.json (restart ComfyUI to see them in this list, 'random' uses them right away).
    faceCOMBOnone'none' skips this trait, 'random' picks a random entry, 'exclude' keeps it out of the prompt even when random_all is on. Add your own entries in json/star_horror_villains_builder.json (restart ComfyUI to see them in this list, 'random' uses them right away).
    hairCOMBOnone'none' skips this trait, 'random' picks a random entry, 'exclude' keeps it out of the prompt even when random_all is on. Add your own entries in json/star_horror_villains_builder.json (restart ComfyUI to see them in this list, 'random' uses them right away).
    skinCOMBOnone'none' skips this trait, 'random' picks a random entry, 'exclude' keeps it out of the prompt even when random_all is on. Add your own entries in json/star_horror_villains_builder.json (restart ComfyUI to see them in this list, 'random' uses them right away).
    eyesCOMBOnone'none' skips this trait, 'random' picks a random entry, 'exclude' keeps it out of the prompt even when random_all is on. Add your own entries in json/star_horror_villains_builder.json (restart ComfyUI to see them in this list, 'random' uses them right away).
    body_buildCOMBOnone'none' skips this trait, 'random' picks a random entry, 'exclude' keeps it out of the prompt even when random_all is on. Add your own entries in json/star_horror_villains_builder.json (restart ComfyUI to see them in this list, 'random' uses them right away).
    outfitCOMBOnone'none' skips this trait, 'random' picks a random entry, 'exclude' keeps it out of the prompt even when random_all is on. Add your own entries in json/star_horror_villains_builder.json (restart ComfyUI to see them in this list, 'random' uses them right away).
    weaponCOMBOnone'none' skips this trait, 'random' picks a random entry, 'exclude' keeps it out of the prompt even when random_all is on. Add your own entries in json/star_horror_villains_builder.json (restart ComfyUI to see them in this list, 'random' uses them right away).
    injuriesCOMBOnone'none' skips this trait, 'random' picks a random entry, 'exclude' keeps it out of the prompt even when random_all is on. Add your own entries in json/star_horror_villains_builder.json (restart ComfyUI to see them in this list, 'random' uses them right away).
    accessoriesCOMBOnone'none' skips this trait, 'random' picks a random entry, 'exclude' keeps it out of the prompt even when random_all is on. Add your own entries in json/star_horror_villains_builder.json (restart ComfyUI to see them in this list, 'random' uses them right away).
    auraCOMBOnone'none' skips this trait, 'random' picks a random entry, 'exclude' keeps it out of the prompt even when random_all is on. Add your own entries in json/star_horror_villains_builder.json (restart ComfyUI to see them in this list, 'random' uses them right away).
    expressionCOMBOnone'none' skips this trait, 'random' picks a random entry, 'exclude' keeps it out of the prompt even when random_all is on. Add your own entries in json/star_horror_villains_builder.json (restart ComfyUI to see them in this list, 'random' uses them right away).
    poseCOMBOnone'none' skips this trait, 'random' picks a random entry, 'exclude' keeps it out of the prompt even when random_all is on. Add your own entries in json/star_horror_villains_builder.json (restart ComfyUI to see them in this list, 'random' uses them right away).
    customCOMBOnone'none' skips this trait, 'random' picks a random entry, 'exclude' keeps it out of the prompt even when random_all is on. Add your own entries in json/star_horror_villains_builder.json (restart ComfyUI to see them in this list, 'random' uses them right away).
    styleCOMBOcinematic horror film still'none' skips this trait, 'random' picks a random entry, 'exclude' keeps it out of the prompt even when random_all is on. Add your own entries in json/star_horror_villains_builder.json (restart ComfyUI to see them in this list, 'random' uses them right away).
    ageSTRINGFree text. Empty = skipped. Type 'random' or enable the random_age toggle for a random age (25-90 by default, change age_random_min/max in the json settings). A plain number becomes 'X year old'.
    random_ageBOOLEANfalseIf enabled each run, picks a random age between age_random_min and age_random_max from the json settings and ignores the age text field.
    additionalSTRINGFree text that is appended to the end of the prompt. Empty = skipped.
    seedINT00–18446744073709550000Seed for all 'random' picks. 0 = new random picks every run.
    random_allBOOLEANfalseIf enabled, every category gets a random pick regardless of its widget setting. Categories set to 'exclude' stay out of the prompt.

    Outputs (3)

    NameTypeDescription
    descriptionSTRINGThe plain generated comma-separated description prompt.
    villain_sheetSTRINGThe ready-to-use strict horror villain sheet image prompt for the same villain (multi-panel grid, face/mask and weapon close-up panels). Note: the villain is unclothed unless an outfit is selected or randomized.
    system_promptSTRINGThe system prompt to feed into your LLM so it can write horror villain sheet prompts itself. Editable as 'system_prompt' in json/star_horror_villains_builder.json.