Prompt Style Presets
A style is a positive *and* a negative, so save them as one thing
- positive
- negative
Every style you actually like is a pair. The lighting tags go in the positive box, and the counterweight - worst quality, blurry, oversaturated or whatever you tuned against them - goes in the negative. Store those in two separate snippet files and you will spend a real amount of your life guessing which negative belonged to which positive.
That's the whole pitch, and it's a better one than it sounds on SDXL-lineage models, where the negative box is still doing work and is still tuned against its positive. On an LLM-encoded model (Z-Image, Anima, Krea 2, ERNIE) the negative box does nothing at all, and a "style preset" is just a saved positive - this node still works, you just leave one half empty.
One warning: the pack has almost no community footprint. A search for its name across the Reddit corpus comes back with nothing. Not a red flag for a utility this small - a few hundred lines of Python, one JS file, MIT, zero dependencies - but there's no tutorial thread. The README and the source are the docs.
How it works
The class is PromptStylePresets with three inputs: positive (multiline STRING), negative (multiline STRING), and seed (INT, with control_after_generate). Outputs are positive and negative, both STRING - wire them into the positive/negative text encoder for your model and nothing else changes.
Both boxes get run through the pack's own dynamic-prompt resolver at queue time, seeded by seed:
{a|b|c} pick one option
{a|0.4::b} weighted option (default 1.0)
{|a|b} an empty option is allowed - emit nothing
{a|{x|y}} groups nest
\{ \| \} escape a literal brace or pipe
An unclosed { is tolerated and closes at the end of the string. The inputs declare dynamicPrompts: False, so core's processor stays out of the way and the node resolves the syntax itself in Python - which is exactly why you get weights and nesting here, since ComfyUI's built-in dynamic prompts only understands bare {a|b|c}. One RNG instance feeds both boxes in order, so a given seed reproduces both picks.
The library lives in user/<user>/prompt_preset_builder/styles.json as folder → name → {positive, negative}, resolved per request through ComfyUI's user manager, so a --multi-user server gives every profile its own file. Saves go through a temp file and keep the previous copy as styles.json.bak.
The toolbar is where the real value is
The folder dropdown, preset dropdown, and the Save / Save as / Load / Apply / Move-Copy / Rename / Delete / Refresh buttons are a DOM widget, not declared inputs - which is why they don't appear in the API schema and why this node looks oddly empty when you drop it in.
- Apply is the one you'll live in. It appends the selected preset to both boxes with a comma, so you can stack styles in sequence before typing your actual subject. An empty side contributes nothing, so no trailing comma, and applying a positive-only style doesn't wipe your negative.
- Load puts the preset back in the boxes for editing. Selecting a name in the dropdown alone does not touch your text.
- Save updates the preset you have selected (it asks before overwriting); Save as forks it under a new folder/name. Move / Copy keeps the name and offers
Keep bothon a collision, saving asname_2. - Refresh matters because the library is a shared file: styles saved in another tab or workflow don't show up until you pull them.
Folders are the organizational unit, and the same name in two folders is two unrelated presets - that's a feature, and it's how you keep one folder per model (krea2, anima), but it will confuse you exactly once. Uncategorized is always there and can't be renamed or deleted.
If you already run the pack's sibling node, Prompt Preset Builder, your data is safe: that one keeps its own presets.json and this node never touches it.
Install
ComfyUI Manager → search Prompt Preset Builder (aiai-r/ComfyUI-PromptPresetBuilder), or:
cd ComfyUI/custom_nodes
git clone https://github.com/aiai-r/ComfyUI-PromptPresetBuilder
Restart ComfyUI, then hard-refresh the browser tab - the pack ships a web/ directory and the toolbar is JS. There is genuinely nothing else: pyproject.toml declares dependencies = [] (aiohttp already comes with the server), and there are no model files to download.
Where people get burned
Sharing a workflow doesn't share your presets. What's embedded in the workflow is the selected folder and name plus the text sitting in the two boxes. Your friend gets your text, not your library. If a style matters, share the text or the styles.json.
A corrupt styles.json locks the whole node. The API validates on read, and if the file is malformed it answers 409 Invalid styles.json; restore it before saving - every save is refused, not just the broken entry. Fix:
cd ComfyUI/user/default/prompt_preset_builder
cp styles.json.bak styles.json # or hand-fix the JSON
Random syntax plus a randomized seed looks like a bug. If control_after_generate is on randomize, {warm|cool} picks a new option every run and your "saved preset" appears to mutate. Pin the seed while iterating.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| positive | STRING | — | |
| negative | STRING | — | |
| seed | INT | 00–18446744073709550000 | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| positive | STRING | — |
| negative | STRING | — |