Files
acorderob-sd-webui-prompt-p…/docs/COOKBOOK.md
T
2026-05-15 11:16:06 +02:00

19 KiB

Cookbook

This cookbook shows some interesting uses of the features available.

Wildcard definition

Grouping

The common use of wildcards is creating multiple of them with simple lists of elements. But this extension supports more interesting ways to group the elements, reducing bloat and improving selection of the wanted elements.

In these examples we assume we want to select colors but we want warm colors to have double weight than cold colors, then have weights for each of them, and we sometimes want to choose only the warm ones, the cold ones, or any of them.

The usual way would be this:

colors_warm:
    - 3::red
    - 2::orange
    - 1::yellow
colors_cold:
    - 2::blue
    - 1::green

And use __colors_warm__ or __colors_cold__, or {2::__colors_warm__|1::__colors_cold__} to get all of them.

The 1 weights are not necessary, it just makes the intent clearer.

Filters

You can add labels to the elements of a wildcard, allowing you to reduce the availability to only a subset of them. This avoids the need to create multiple wildcards of similar elements.

colors:
    - "'warm'6::red"
    - "'warm'4::orange"
    - "'warm'2::yellow"
    - "'cold'2::blue"
    - "'cold'1::green"

And use __colors'warm'__ or __colors'cold'__, or just __colors__ to get all of them.

Labels can be more complex than this. See the syntax document.

Anonymous wildcards

You can also group the elements by using anonymous wildcards, which can also be labeled.

colors:
    - "'warm'2":  # this needs double quotes to include the single quotes as part of the options
        - 3::red
        - 2::orange
        - 1::yellow
    - "'cold'1":
        - 2::blue
        - 1::green

And use __colors'warm'__ or __colors'cold'__, or just __colors__ to get all of them.

This produces almost the same effect as before but is easier to read. The only difference is with the weights when you don't filter, because now it first chooses between the warm and the cold options and then the colors inside the chosen one. This allows you to add simpler weights to the two groups and their elements instead of having to calculate the combined weights.

With simple labels this is probably the best method.

Wildcard inclusion

Another option, but not as clean, is to include wildcards inside other wildcards.

colors_warm:
    - 3::red
    - 2::orange
    - 1::yellow
colors_cold:
    - 2::blue
    - 1::green
colors:
    - "%'warm'2::include colors_warm"
    - "%'cold'1::include colors_cold"

Then use __colors_warm__ or __colors_cold__, or __colors'warm'__ or __colors'cold'__ or __colors__ to get all of them.

Prompt building

You can create a complex set of wildcards that build a full prompt, by using the wildcards along with variables with default values. The variables allow you to choose what parts of the prompt you want to change for specific content, or just leave the defaults. Then, inside the UI, you can use styles (with an appropiate styles node if using ComfyUI) to choose which variables to set. This makes it easy to quickly select what do you want to prompt for.

Wildcards:

style:
    realistic: photograph
    oil: oil painting
    sketch: pencil sketch

subject:
    - "'human'::{man|woman}"
    - "'orc,fantasy'::orc"
    - "'goblin,fantasy'::goblin"

clothes:
    - "'regular'::t-shirt, pants, shoes"
    - "'regular'::swimsuit"
    - "'regular'::uniform"
    - "'regular'::pajamas"
    - "'armor'::metal armor"
    - "'armor'::leather armor"

action:
    - "'passive'::standing"
    - "'passive'::sitting"
    - "'passive'::lying down"
    - "'passive'::crouching"
    - "'active'::running"
    - "'active'::dancing"
    - "'active'::driving"

background:
    home:
        - in the kitchen
        - in the bathroom
        - in the living room
    nature:
        - in a forest
        - in a swamp
        - in a desert
        - in a grotto
        - in the beach
    building:
        - in a cathedral
        - in an office
        - in a store
        - in a castle
        - in a dungeon
    any: "{__background/home__|__background/nature__|__background/building__}"

character:
  - "${style:()}, ${subject:__subject'human'__}, ${clothes:__clothes'regular'__}, ${action:__action'passive'__}, ${background:__background/any__}"

Styles file:

name,prompt,negative_prompt
"Nothing","",""
"Style: realistic","${style=__style/realistic__}",""
"Style: oil","${style=__style/oil__}",""
"Style: sketch","${style=__style/sketch__}",""
"Subject: human","${subject=__subject'human'__}",""
"Subject: orc","${subject=__subject'orc'__}",""
"Subject: goblin","${subject=__subject'goblin'__}",""
"Subject: fantasy","${subject=__subject'fantasy'__}",""
"Subject: any","${subject=__subject__}",""
"Clothes: regular","${clothes=__clothes'regular'__}",""
"Clothes: armor","${clothes=__clothes'armor'__}",""
"Clothes: any","${clothes=__clothes__}",""
"Action: passive","${action=__action'passive'__}",""
"Action: active","${action=__action'active'__}",""
"Action: any","${action=__action__}",""
"Background: home","${background=__background/home__}",""
"Background: nature","${background=__background/nature__}",""
"Background: building","${background=__background/building__}",""
"Background: any","${background=__background/any__}",""
"Character","__character__",""

You first select the styles that set the variables that you are interested in changing from the default, and you end with the main wildcard that uses them to build the prompt.

Tip

The order of the variables don't usually matter because they are only evaluated when echoed to the prompt. This allows you to use variables inside wildcards that are inside other variables, and only at the end they will be evaluated.

Sample style selections:

Sample 1:

  • "Style: oil"
  • "Subject human"
  • "Clothes: regular"
  • "Background: home"
  • "Character"

This would create this prompt:

${style=__style/oil__}, ${subject=__subject'human'__}, ${clothes=__clothes'regular'__}, ${background=__background/home__}, __character__

Sample 2:

  • "Subject: fantasy"
  • "Clothes: armor"
  • "Action: active"
  • "Background: nature"
  • "Character"

This would create this prompt:

${subject=__subject'fantasy'__}, ${clothes=__clothes'armor'__}, ${action=__action'active'__}, ${background=__background/nature__}, __character__

Using variables for detailer prompts

This only applies to ComfyUI, because the variables cannot be used in the ADetailer prompts of the A1111 UIs.

You can put parts of the prompt to be set into variables, and then extract this variables from the output and use them in the prompts of the detailer nodes.

For example, imagine you have this prompt:

Cyberpunk woman with ${head:long red hair mohawk, green eyes, and neon makeup} riding a futuristic motorcycle

That will create a variable head with the head description and insert it in that position in the prompt. That variable can then be extracted with the "ACB PPP Select Variable" node and used as input for the detailer for the head, thus avoiding prompt clutter that does not apply.

Conditional content based on model

The _is_* system variables let you write a single prompt that adapts automatically to the loaded model. This is especially useful for LoRAs that exist in different versions for different model families.

beautiful woman in a garden
<ppp:if _is_sd1><lora:woman_detail_sd1:0.8> detailed face<ppp:elif _is_sdxl><lora:woman_detail_xl:0.9> detailed face<ppp:elif _is_flux><lora:woman_detail_flux:1.0> detailed face<ppp:/if>

Only one branch ends up in the final prompt. You can also nest if commands inside wildcards to gate certain choices:

poses:
    - "'standing'::standing upright"
    - "'sitting'::sitting on a bench"
    - "'dynamic,sdxl'if _is_sdxl::dynamic action pose"
    - "'dynamic,flux'if _is_flux::powerful dynamic pose, motion blur"

The last two entries are only available when their respective model is loaded.

ExtraNetworks mappings

When you have the same LoRA in multiple versions (one per model family), you can create a mapping so the correct one is picked automatically without rewriting your prompt for each model.

Mapping file (enmappings/my_loras.yaml):

lora:
  my_character:
    - condition: "_is_sd1"
      name: "my_character_sd1"
      parameters: "0.8"
      triggers: ["my_char_trigger"]
    - condition: "_is_sdxl"
      name: "my_character_xl"
      parameters: "0.9"
      triggers: ["my_char_trigger", "detailed"]
    - condition: "_is_flux"
      name: "my_character_flux"
      parameters: "1.0"
      triggers: ["my_char_trigger"]

Prompt usage:

a portrait of <ppp:ext $lora my_character>extra trigger<ppp:/ext>

The extension picks the mapping whose condition matches the loaded model, builds the correct <lora:...:...> tag, prepends the triggers from the mapping, and appends the inline triggers. If no condition matches (e.g. an unsupported model) nothing is added.

You can also specify a weight multiplier directly in the command - if both the command weight and the mapping parameters are numbers, they are multiplied:

<ppp:ext $lora my_character 0.75/>

Send-to-negative with attention modifiers

When a send-to-negative command sits inside an attention modifier, the weight is carried over to the negative prompt.

(red apple<ppp:stn>round shape<ppp:/stn>:1.4)

Result in the negative: (round shape:1.4) - the surrounding weight is applied.

(red apple<ppp:stn>[round shape]<ppp:/stn>:1.4)
(red [apple<ppp:stn>round shape<ppp:/stn>]:1.4)

For both cases, the result in the negative is: (round shape:1.26) - the weight is merged, if merge attention is enabled.

Array variables

Arrays let you collect several values and then use them together, which is useful when you want to pick a random set of attributes and later echo them as a formatted list.

Example - picking random accessories:

${accessories[]=*__accessories__}
a woman wearing ${accessories[&', ']}

The wildcard __accessories__ is expanded into an array, then echoed as a comma-separated string.

Example - building a list of a fixed size from separate wildcards:

${colors[]=*__colors__}
${colors[]+=*__materials__}
abstract composition of ${colors[&' and ']}

Initializing from a literal list:

${seasons[]=*('spring', 'summer', 'autumn', 'winter')}
seasonal scene: ${seasons[&', ']}

Conditional filtering inside wildcards

You can attach an if condition directly to a choice inside a wildcard, making the choice invisible unless the condition is true. This lets a single wildcard file serve all model families without duplication.

lora_styles:
    - "'painterly'::painterly style, oil paint"
    - "'anime'if _is_sd1 or _is_sdxl::anime style, flat shading"
    - "'photorealistic'if _is_sdxl or _is_flux::photorealistic, hyper detailed"
    - "'concept'if _is_flux::concept art, cinematic lighting"

When loaded with SD 1, only painterly and anime are available. When loaded with Flux, only painterly, photorealistic, and concept are.

You can combine conditions with and, or, and not, and reference any user or system variable:

effects:
    - "bokeh, shallow depth of field"
    - "long exposure, motion blur"
    - "'hdr'if _is_sdxl or _is_flux::HDR, high dynamic range"
    - "'film'if quality ne 'draft'::film grain, subtle noise"

setwcdeffilter for dynamic routing

setwcdeffilter sets a default filter on a wildcard before it is referenced anywhere in the prompt. This avoids having to repeat a filter at every call site when you want to pre-select a subset of choices.

A typical use case is a style variable that narrows what a downstream wildcard will pick:

<ppp:setwcdeffilter 'clothing' 'armor'/>
A warrior ${subject} wearing __clothing__

Whatever label filter you pass becomes the default for that wildcard for the rest of the current generation.

You can use globbing to apply the filter to a whole family of wildcards:

<ppp:setwcdeffilter 'items/*' 'rare'/>

This pre-filters every wildcard under items/ to only rare-labelled choices. To remove a previously set default filter:

<ppp:setwcdeffilter 'items/*'/>

A practical workflow combining this with variables and styles:

name,prompt,negative_prompt
"Gear: armor","<ppp:setwcdeffilter 'clothing' 'armor'/>",""
"Gear: casual","<ppp:setwcdeffilter 'clothing' 'casual'/>",""
"Character","__character__",""

Select a "Gear" style first and then "Character" - the wildcard inside character will automatically use the pre-filtered clothing choices.

Globbing wildcards

Instead of referencing a single wildcard file, you can use glob patterns to merge choices from multiple files into one pool. This is handy when you split a large collection into smaller themed files.

File layout:

wildcards/
  characters/
    humans.yaml
    orcs.yaml
    elves.yaml

Each file is a regular YAML wildcard. Reference them all at once:

__characters/*__

This merges all choices from humans.yaml, orcs.yaml, and elves.yaml into a single pool and picks one.

Note that the globbing works on the wildcard key, not the file structure. So if those files contain multiple wildcards, all of them will be merged.

You can apply parameters to the glob call just like a regular wildcard:

__2$$ / $$characters/*__

Selects 2 choices from the merged pool, separated by " / ".

You can also apply a filter to narrow from within the merged pool:

__characters/*'fantasy'__

Only choices labelled fantasy across all matched files are eligible.

Note: if no parameters are specified in the glob call, the parameters from the first matching file that defines them (sorted by key) are used. To avoid that, specify parameters explicitly in the call.

Prefix/suffix or container on wildcard parameters

Using the object format for wildcard parameters you can set a prefix and/or suffix, or a container, that wraps the result. This is cleaner than repeating the wrapper in each choice.

In this example, without prefix/suffix, every choice needs to repeat the attention modifier:

qualities:
    - "(ultra detailed:1.3)"
    - "(highly detailed:1.3)"
    - "(intricate details:1.3)"

With object-format parameters and a prefix/suffix:

qualities:
    - { prefix: "(", suffix: ":1.3)" }  # parameters line
    - "ultra detailed"
    - "highly detailed"
    - "intricate details"

The prefix and suffix are added around the wildcard's result. They can themselves contain constructs.

Another way is with the container property, which does the same in a slightly more flexible way:

qualities:
    - { container: "(${__choices[]}:1.3)" }  # parameters line
    - "ultra detailed"
    - "highly detailed"
    - "intricate details"

ifundefined / ?= for safe defaults

When building multi-style workflows you often want a variable to have a sensible default that can be overridden by an earlier style, but only if it hasn't already been set. The ifundefined modifier (?=) is designed for this.

${quality?=__qualities__}, ${style?=photograph}, ${subject?=__subject__}

If a "Quality: ultra" style already ran ${quality=ultra detailed, 8k} earlier in the pipeline, the ?= here does nothing. If no quality style was chosen, it picks a random value from __qualities__ as the fallback.

This is more robust than relying on the order of styles. But if you need a specific default for different instances use instead the default value when echoing the variable.

Styles file example:

name,prompt,negative_prompt
"Quality: draft","${quality=draft quality}",""
"Quality: high","${quality=ultra detailed, 8k}",""
"Style: photo","${style=photograph}",""
"Style: painting","${style=oil painting}",""
"Character","${quality?=__qualities__}, ${style?=photograph}, __subject__",""

If the user selects "Quality: high" and "Character", quality is ultra detailed, 8k. If they select only "Character", quality falls back to a random value from __qualities__.

You can also use evaluate ifundefined (?=!) to resolve the wildcard immediately rather than lazily:

${quality?=!__qualities__}

Choosing the model from the prompt

In ComfyUI, you can leave the model and modelname inputs disconnected and set the _modelinfo system variable (or _modelfullname and _modelclass) at the start of the prompt (maybe through a wildcard or a choice construct). Then extract the _modelfullname output variable using the Select Variable node and use its value to actually load that model.

You can also set and extract user variables for other ksampler inputs, like sampler, scheduler, steps, cfg and latent size. The numeric ones will need to be transformed from string to int/float using some other node.

Debugging tips

When something isn't generating as expected, the debug setting is your first tool. Enable it in the extension settings; it will log all system variables at generation time, which tells you exactly what values are available for your conditions.

Finding the right system variable for an unsupported model:

If you load a model that isn't matched by any _is_* variable, check _modelclass in the debug log. Use it directly in a condition while you wait for official support:

<ppp:if _modelclass eq 'StableDiffusionXLPipeline'>content for new model<ppp:/if>

Inspecting variable values mid-prompt:

Insert a temporary echo to see what a variable resolves to:

[DEBUG style=${style}] ${style:photograph}, detailed portrait

Remove the bracketed part once you're satisfied.

Checking which choices are available after filtering:

If a wildcard seems to produce unexpected results, temporarily use a fixed positional filter to verify specific choices:

__mywildcard'0'__   # always picks the first choice
__mywildcard'1'__   # always picks the second choice

This confirms the order and content of choices before relying on label filters.

Common pitfalls:

  • A % choice in a YAML array must be quoted, otherwise YAML treats % as invalid syntax.
  • Variables set with ${var=value} are lazy - they are not evaluated until echoed. Use ${var=!__wildcard__} (with !) for immediate evaluation if the value should only be resolved once (as in, you want the same value to be echoed later multiple times).
  • Wildcards cannot be used inside extranetwork tags (because some LoRA names contain double underscores). Put the entire <lora:...> tag inside a wildcard choice instead, or use the ext command.