# 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 Camera Control` - `prompt_builder / SxCP Caption Naturalizer` - `prompt_builder / SxCP Krea2 Formatter` - `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 Camera Control` outputs `camera_config`, which can be connected to the prompt builder or the Insta/OF pair node. It makes camera/framing first-class instead of relying on a weak phrase inside the prompt. Camera controls: - `camera_mode`: `standard`, `handheld_selfie`, `mirror_selfie`, `phone_tripod`, `creator_pov`, `bed_selfie`, `bathroom_mirror`, `phone_flash`, or `action_cam`. - `shot_size`: `auto`, `full_body`, `three_quarter`, `waist_up`, `close_up`, or `extreme_close_up`. - `angle`: `auto`, `eye_level`, `high_angle`, `low_angle`, `overhead`, `side_profile`, `rear_view`, or `mirror_reflection`. - `lens`: `auto`, `smartphone_wide`, `ultra_wide`, `portrait_lens`, `telephoto`, or `macro_detail`. - `distance`: `auto`, `arm_length`, `near_body`, `bedside`, or `room_corner`. - `orientation`: `auto`, `vertical_story`, `square_feed`, or `horizontal`. - `phone_visibility`: `auto`, `phone_visible`, `phone_hidden`, `screen_reflection`, or `ring_light_visible`. - `priority`: `soft_hint`, `strong`, or `locked`. `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. When connected to `SxCP Insta/OF Prompt Pair` metadata, the naturalizer emits a single combined natural caption with the shared descriptor plus separate softcore and hardcore version descriptions. It uses the final selected expression and composition from the generated rows, including any expression pool and intensity settings. 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 Krea2 Formatter` rewrites an existing prompt or `metadata_json` into a Krea2-oriented natural-language paragraph. It is a formatter, not a safety or content downgrade pass: hardcore items, role graphs, sexual pose wording, and camera controls are preserved. Negative prompts stay separate. Important behavior: - Age wording is preserved deliberately. Phrases like `21-year-old adult`, `late 20s adult woman`, and `all participants 21+ and visibly adult` are kept because they help avoid unwanted young-looking outputs. - Trigger words are removed by default because Krea2 prompting generally reads better as natural language. Enable `preserve_trigger` if you still need a LoRA trigger in the positive prompt. - `style_mode`: `preserve` keeps the current generated style text, `photographic` converts the style tail toward creator-photo language, and `minimal` omits most style text. - For Insta/OF paired metadata, the node returns both `krea_softcore_prompt` and `krea_hardcore_prompt`, with separate softcore and hardcore negatives. It outputs: - `krea_prompt` - `negative_prompt` - `krea_softcore_prompt` - `krea_hardcore_prompt` - `softcore_negative_prompt` - `hardcore_negative_prompt` - `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. When the hardcore cast includes partners, pair mode also creates deterministic shared cast descriptors such as `woman A / primary creator` and `man A`. Use `softcore_cast=same_as_hardcore`, `hardcore_cast=couple`, and `continuity=same_creator_same_room` when you want a soft prompt with the same woman, man, and location as the hardcore prompt. 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. It also defaults the camera to handheld selfie framing. For stronger camera control, connect `SxCP Camera Control` to the pair node's optional `camera_config` input. 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`. - `softcore_expression_intensity`: `0.0` is mild/controlled, `0.5` is sensual, `1.0` strongly favors more heated softcore faces. - `hardcore_expression_intensity`: `0.0` is controlled, `0.5` is balanced hardcore, `1.0` strongly favors ahegao-style, drooling, fucked-out, climax, and messy orgasm expressions. - `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. - `softcore_camera_mode`: base camera mode for the softcore output. - `hardcore_camera_mode`: `same_as_softcore` or a separate base camera mode for the hardcore output. ## 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`. - `expression_intensity`: `0.0` favors mild, neutral, controlled expressions; `0.5` favors balanced category expressions; `1.0` strongly favors the most intense expressions available in the selected category. This affects custom JSON categories such as `Provocative erotic clothes` and `Hardcore sexual poses`. - `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. - Optional `camera_config`: connect `SxCP Camera Control` to force selfie, phone, lens, angle, distance, crop, and camera-priority behavior. This applies to custom categories too, including `Hardcore sexual poses`. `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. Reusable banks can be defined with top-level `scene_pools`, `expression_pools`, and `composition_pools` in any `categories/*.json` file. Categories, subcategories, and items can reference them with `scene_pools`, `expression_pools`, and `composition_pools`; referenced pools are merged with any local `scenes`, `expressions`, or `compositions`. This keeps expansion scalable without duplicating the same bedroom, selfie, mirror, creator, expression, camera, or group-sex framing across every subcategory. Set `"inherit_scenes": false`, `"inherit_expressions": false`, or `"inherit_compositions": false` on a subcategory or item when it should use only its own pools instead of also inheriting parent category values. This is useful for narrow subcategories such as group scenes, fetish sets, outdoor-only sets, or any category where generic parent wording would be a bad match. Example: ```json { "expression_pools": { "creator_tease_faces": [ "direct creator-shot eye contact", "heavy-lidded bedroom gaze" ] }, "composition_pools": { "creator_selfie_frames": [ "handheld selfie crop from face to hips", "mirror selfie with phone visible and body framed clearly" ] }, "scene_pools": { "creator_selfie_rooms": [ { "slug": "bedroom_phone_tripod", "prompt": "private creator bedroom with a phone tripod, rumpled bedding, and warm lamps" } ] }, "categories": [ { "name": "Example", "subcategories": [ { "name": "Selfie set", "inherit_scenes": false, "inherit_expressions": false, "inherit_compositions": false, "scene_pools": ["creator_selfie_rooms"], "expression_pools": ["creator_tease_faces"], "composition_pools": ["creator_selfie_frames"], "items": ["simple outfit prompt"] } ] } ] } ``` 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.