# ComfyUI Prompt Builder Custom ComfyUI node for building prompts from the existing `generate_prompt_batches.py` generator without writing image batches. The node is registered as: - `prompt_builder / SxCP Prompt Builder` - `prompt_builder / SxCP Seed Control` - `prompt_builder / SxCP Caption Naturalizer` - `prompt_builder / SxCP Insta/OF Options` - `prompt_builder / SxCP Insta/OF Prompt Pair` It outputs: - `prompt` - `negative_prompt` - `caption` - `metadata_json` - `category` - `subcategory` `SxCP Seed Control` outputs `seed_config`, which can be connected to the prompt builder's optional `seed_config` input. `SxCP Caption Naturalizer` rewrites tag-like captions or labeled prompts into more natural language. Connect the prompt builder's `metadata_json` output to `source_text` for the cleanest result. You can also connect `caption` or `prompt`; in that case the node falls back to prompt-label parsing or comma-tag cleanup. Naturalizer controls: - `input_hint`: `auto`, `metadata_json`, or `caption_or_prompt`. - `detail_level`: `concise`, `balanced`, or `dense`. - `style_policy`: `drop_style_tail` removes old fixed style tails; `keep_style_terms` keeps style descriptions in the rewritten text. - `trigger`: defaults to `sxcppnl7`. - `include_trigger`: prepends the trigger as its own sentence. It outputs: - `natural_caption` - `method` `SxCP Insta/OF Prompt Pair` is a special paired-output mode. It creates one shared primary creator descriptor, then returns both a softcore prompt and a hardcore prompt from that same descriptor. This is useful when you want the same person/look/scene continuity but need two different prompt strengths. It outputs: - `softcore_prompt` - `hardcore_prompt` - `softcore_negative_prompt` - `hardcore_negative_prompt` - `softcore_caption` - `hardcore_caption` - `shared_descriptor` - `metadata_json` `SxCP Insta/OF Options` outputs `options_json`, which can be connected to the pair node. Defaults are set so the softcore prompt is solo while the hardcore prompt can include partners. Options: - `softcore_cast`: `solo` or `same_as_hardcore`. - `hardcore_cast`: `use_counts`, `couple`, `threesome`, or `group`. - `hardcore_women_count` and `hardcore_men_count`: used when `hardcore_cast` is `use_counts`. The pair mode always keeps at least one adult woman as the primary creator so the shared descriptor remains valid. - `softcore_level`: `social_tease`, `lingerie_tease`, `implied_nude`, or `explicit_tease`. - `hardcore_level`: `explicit` or `hardcore`. - `platform_style`: `hybrid`, `instagram`, or `onlyfans`. - `continuity`: `same_creator_same_room` keeps the scene/composition aligned; `same_creator_new_scene` keeps the same creator descriptor but lets the hardcore scene use its own setting. ## Built-In Categories The node keeps the original generator controls: - `category`: `auto_weighted`, `woman`, `man`, `couple`, `group_or_layout`, or a custom JSON category. - `clothing`: `full` or `minimal`. - `minimal_clothing_ratio`: `-1` disables mixing; `0.0` to `1.0` mixes minimal/full clothing. - `ethnicity`: `any`, `asian`, `white_asian`. - `poses`: `standard` or `evocative`. - `standard_pose_ratio`: `-1` disables mixing; `0.0` to `1.0` mixes standard/evocative poses. - `backside_bias`: `0.0` to `1.0`, applies to evocative single-subject poses. - `figure`: `curvy`, `balanced`, `bombshell`. - `no_plus_women`: excludes plus-size women. - `no_black`: excludes Black/African-coded women from women-focused pools. `auto_weighted` uses the original batch mix: mostly women, then men, couples, and group/layout rows. Direct categories generate only that selected category. ## Custom Categories Add or edit JSON files in `categories/*.json`. Each file can define new main categories, subcategories, and optional extensions to the built-in pools. Restart or reload ComfyUI after changing JSON so dropdown choices are rebuilt. Included JSON categories: - `Casual clothes` - `Provocative erotic clothes` - `Hardcore sexual poses` Example: ```json { "version": 1, "categories": [ { "name": "Casual clothes", "slug": "casual_clothes", "subject_type": "woman", "item_label": "Clothing", "style": "tasteful adult fashion-editorial coloured-pencil comic illustration", "subcategories": [ { "name": "Streetwear", "slug": "streetwear", "items": [ "oversized hoodie with slim jeans and clean sneakers", "cropped bomber jacket with cargo pants and chunky trainers" ], "scenes": [ { "slug": "city_crosswalk", "prompt": "sunlit city crosswalk with storefront reflections" } ], "poses": [ "standing with one hand in a pocket", "walking forward with a casual runway stride" ] } ] } ] } ``` Custom categories do not need a Python generator. If no `prompt_template` is provided, the node uses a generic composer that selects subject appearance, scene, pose, expression, composition, and a random item from the selected subcategory. For large categories, prefer `item_templates` plus `item_axes` instead of writing every final item by hand: ```json { "name": "Example clothes", "subject_type": "woman", "subcategories": [ { "name": "Lingerie", "item_templates": [ "{color} {fabric} {top} with {bottom} and {stockings}" ], "item_axes": { "color": ["black", "red", "ivory"], "fabric": ["lace", "satin", "transparent mesh"], "top": ["balconette bra", "open-cup bra"], "bottom": ["matching thong", "high-cut g-string"], "stockings": ["thigh-high stockings", "fishnet stockings"] } } ] } ``` The node chooses one template, fills each placeholder from the matching axis, then records the selected axis values in `metadata_json`. Supported `subject_type` values: - `single_any` - `woman` - `man` - `couple` - `group` - `layout` - `scene` - `configured_cast` `configured_cast` uses the node's `women_count` and `men_count` inputs. It adds template fields for `{women_count}`, `{men_count}`, `{person_count}`, `{cast_summary}`, `{scene_kind}`, and `{role_graph}`. This is intended for categories where the same prompt generator should support couples, threesomes, and larger groups. `{role_graph}` is a generated choreography sentence that assigns roles to the cast, such as who penetrates, who receives oral, and who joins from the side. It is currently most useful for `Hardcore sexual poses`. Subcategories, templates, and axis values can declare cast constraints: ```json { "name": "Threesomes", "min_people": 3, "item_axes": { "act": [ { "text": "strap-on penetration and cunnilingus", "cast": "women_only" }, { "text": "male/male oral and anal contact", "cast": "men_only" }, { "text": "front-and-back penetration", "cast": "mixed" } ] } } ``` Supported constraints: - `min_women`, `max_women` - `min_men`, `max_men` - `min_people`, `max_people` - `cast` or `requires`: `women_only`, `men_only`, `mixed`, `has_women`, `has_men`, `solo`, `couple`, `threesome`, `group` If an exact subcategory is not compatible with `women_count` and `men_count`, the node raises a clear error instead of generating an impossible prompt. Use the `subcategory` dropdown to select either `random` or an exact `Main category / Subcategory` path. Exact paths override the `category` dropdown, which is useful because ComfyUI does not provide dependent dropdowns from Python alone. ## Seed Control The main `seed` input is still the default master seed. Connect `SxCP Seed Control` to `seed_config` when you want to lock or vary specific axes. Seed values: - `-1`: follow the main seed. - `0` or higher: override only that axis. Axes: - `category_seed`: custom category selection when `custom_random` is used. - `subcategory_seed`: random subcategory selection. - `content_seed`: generated item content, such as outfit wording. - `person_seed`: appearance/person selection. - `scene_seed`: scene/environment selection. - `pose_seed`: body pose selection. For `Hardcore sexual poses`, this also drives the generated sexual pose content. - `role_seed`: participant choreography for `{role_graph}`. If left at `-1`, it follows `pose_seed`. - `expression_seed`: facial expression selection. - `composition_seed`: camera/composition selection. Example workflow: if the person and scene are right but the pose is wrong, keep `person_seed` and `scene_seed` fixed, then change `pose_seed`. If the cast roles are wrong but the act wording is good, change `role_seed`. If the clothing or sexual act wording is wrong, change `content_seed`; for pose-driven categories, change `pose_seed`. ## Pool Extensions Use `pool_extensions` to add new entries to built-in pools without editing Python: ```json { "pool_extensions": { "women_clothes": ["relaxed high-waist jeans with a fitted ribbed tank top"], "men_clothes": ["clean white T-shirt with relaxed jeans and canvas sneakers"], "poses": ["standing with a relaxed hand-on-hip pose"], "expressions": ["easygoing half-smile"], "scenes": [ { "slug": "city_cafe", "prompt": "quiet city cafe terrace with morning light and small round tables" } ] } } ``` Known extension pools: `women_clothes`, `women_clothes_minimal`, `men_clothes`, `men_clothes_minimal`, `couple_outfits`, `couple_outfits_minimal`, `poses`, `evocative_poses`, `backside_poses`, `expressions`, `compositions`, `props`, `figure_curvy`, `figure_athletic`, `figure_bombshell`, `scenes`, `group_scenes`, `layouts_full`, `layouts_minimal`, `group_compositions`, `group_ages`. ## Templates A category, subcategory, or individual item can provide `prompt_template` and `caption_template`. Templates can use these fields: `{trigger}`, `{main_category}`, `{subcategory}`, `{item}`, `{item_label}`, `{subject}`, `{subject_phrase}`, `{age}`, `{body}`, `{body_phrase}`, `{skin}`, `{hair}`, `{eyes}`, `{figure}`, `{scene}`, `{pose}`, `{expression}`, `{composition}`, `{style}`, `{positive_suffix}`, `{negative_prompt}`, `{women_count}`, `{men_count}`, `{person_count}`, `{cast_summary}`, `{scene_kind}`, `{role_graph}`. If `prepend_trigger_to_prompt` is enabled, the node prepends the trigger to the positive prompt. Disable it for output closer to the original script's `prompt` field.