# Prompt Pool Routing Map This document maps the roads that can lead to prompt text. It intentionally does not duplicate every prompt phrase in the JSON pools. The useful debugging target is usually: which node path selected which pool, which seed axis controlled it, and whether the final wording was still raw builder text or rewritten by a formatter. ## Mental Model There are three layers: 1. Generation layer: selects category, subcategory, item/action, character descriptors, scene, expression, pose, composition, and camera directives. 2. Pair/adapter layer: optionally builds a softcore/hardcore pair, applies continuity, POV handling, camera-aware scene text, and clothing state. 3. Formatter layer: rewrites a metadata row into Krea2 prose, SDXL tags, or a naturalized caption. When a result is wrong, first identify which layer owns the bad text: - Raw builder prompt already wrong: edit `prompt_builder.py` or the relevant `categories/*.json` pool/template. - Raw builder prompt acceptable, Krea2 output wrong: edit `krea_formatter.py`. - Raw builder prompt acceptable, SDXL tags wrong: edit `sdxl_formatter.py`. - Natural caption/training caption wrong: edit `caption_naturalizer.py`. - UI/preview/loop behavior wrong: edit `__init__.py`, `loop_nodes.py`, or `web/*.js`. ## High-Level Routes ```mermaid flowchart TD A[SxCP Prompt Builder] --> B[prompt_builder.build_prompt] C[SxCP Prompt Builder From Configs] --> D[parse config nodes] D --> B E[SxCP Insta/OF Prompt Pair] --> F[prompt_builder.build_insta_of_pair] F --> B B --> R[metadata row + prompt + negative + caption] F --> P[pair metadata: soft row + hard row] R --> K[SxCP Krea2 Formatter] R --> S[SxCP SDXL Formatter] R --> N[SxCP Caption Naturalizer] P --> K P --> S P --> N ``` The config nodes mostly emit JSON. The final builder nodes parse that JSON and call the same core generation functions. ## Main Entry Points | ComfyUI node | Python entry | What it owns | | --- | --- | --- | | `SxCP Prompt Builder` | `build_prompt` | Direct single prompt generation. Can use built-in categories or JSON categories. | | `SxCP Prompt Builder From Configs` | `build_prompt_from_configs` -> `build_prompt` | Same generator, but inputs come from category/cast/profile/filter helper nodes. | | `SxCP Insta/OF Prompt Pair` | `build_insta_of_pair` | Builds a softcore row and hardcore row with shared cast/continuity options. | | `SxCP Krea2 Formatter` | `format_krea2_prompt` | Converts metadata rows or pair metadata into Krea2-friendly prose. | | `SxCP SDXL Formatter` | `format_sdxl_prompt` | Converts metadata rows or pair metadata into SDXL/tag style prompts. | | `SxCP Caption Naturalizer` | `naturalize_caption` | Converts rows into more natural sentence captions. | Core helper ownership: | Python module | What it owns | | --- | --- | | `hardcore_role_graphs.py` | Source role graph construction for hardcore configured-cast rows, including POV-aware interaction geometry. | | `hardcore_role_outercourse.py` | Outercourse role graph wording for boobjob, testicle-sucking, penis-licking, handjob, and footjob geometry. | | `hardcore_action_metadata.py` | Source action-family and position-family metadata used by Krea2, SDXL, and caption routes. | | `scene_camera_adapters.py` | Location-aware camera/scene prose such as coworking lounge camera layout. | | `prompt_hygiene.py` | Generic prompt, caption, and negative-prompt cleanup. | ## Node IO Map Use this when wiring or debugging a workflow. If the formatter can receive `metadata_json`, prefer wiring metadata instead of only prompt text. Metadata is what keeps cast, role graph, POV labels, camera config, and soft/hard pair state recoverable. | Node | Important inputs | Important outputs | | --- | --- | --- | | `SxCP Prompt Builder` | category, subcategory, seed, optional config nodes | `prompt`, `negative_prompt`, `caption`, `metadata_json`, `category`, `subcategory` | | `SxCP Prompt Builder From Configs` | category/cast/profile/filter/config node outputs | Same as `SxCP Prompt Builder` | | `SxCP Insta/OF Prompt Pair` | options, seed_config, character_cast, location/composition/camera, hardcore_position_config | `softcore_prompt`, `hardcore_prompt`, both negatives, both captions, `shared_descriptor`, `metadata_json` | | `SxCP Krea2 Formatter` | `source_text`, optional `metadata_json`, target | `krea_prompt`, both pair prompts if pair metadata exists, negative outputs, method | | `SxCP SDXL Formatter` | `source_text`, optional `metadata_json`, target, style/quality preset | `sdxl_prompt`, both pair prompts if pair metadata exists, negative outputs, method | | `SxCP Caption Naturalizer` | `source_text`, optional `metadata_json` | `natural_caption`, method | ## Practical Recipes These recipes identify the intended road before editing prompt text. | Request | Preferred node route | Critical settings | If wrong, inspect | | --- | --- | --- | --- | | Keep character/location but change only sexual pose | `Global Seed` or fixed seed config -> builder/pair | Keep `person_seed` and `scene_seed` fixed; change `pose_seed` and usually `role_seed`; for hardcore categories check `content_seed_axis` | `sexual_poses.json`, `hardcore_position_config`, `krea_actions.hardcore_action_sentence` | | Generate a specific hardcore oral/blowjob scene | `Hardcore Position Pool` -> `Hardcore Action Filter` -> `Insta/OF Prompt Pair` or `Prompt Builder` | Use `focus=oral_only` or disable non-oral families; keep `allow_oral=true`; constrain position pool to kneeling/standing/oral variants when needed | `sexual_poses.json` oral subcategory/templates, `_apply_hardcore_position_config_to_subcategory`, `krea_actions.hardcore_action_sentence` | | Generate POV oral or POV penetration | `Man Slot` with POV presence -> `character_cast` -> pair/builder -> Krea2 formatter | POV man must be in the cast; use metadata into Krea2; normal camera directive is suppressed by POV | `krea_pov_actions.py`, `krea_pov.py`, `krea_cast.cast_prose` omit-label handling | | Generate porn-scene interaction beats | `Hardcore Position Pool` -> `Hardcore Action Filter` -> pair/builder | Use `focus=interaction_only` for kissing/body worship/transitions/guidance/camera/watching/aftercare, or `focus=manual_only` for fingering/clit/manual stimulation; constrain keys such as `camera_showing`, `wrist_pinning`, `fingering`, `aftercare` | `sexual_poses.json` interaction/manual subcategories, `_role_graph`, `krea_action_context.is_foreplay_text` / `krea_actions.hardcore_action_sentence` | | Same woman, same room, softcore and hardcore outputs | `Character Slot/Profile` -> `Insta/OF Options` -> `Insta/OF Prompt Pair` | `continuity=same_creator_same_room`; set `softcore_cast` as needed; use pair metadata into formatter | `build_insta_of_pair`, `softcore_row`, `hardcore_row`, pair metadata fields | | Same cast in softcore and hardcore | Character slot chain -> `Insta/OF Options` | `softcore_cast=same_as_hardcore`; configure partner slots/outfits if needed | `_insta_of_partner_styling`, character slot clothing, pair Krea branch | | Change only outfit/clothing | Character clothing or category content route | Keep `person_seed`, `scene_seed`, `pose_seed`; change `content_seed`; slot `softcore_outfit` overrides Insta/OF outfit | `SxCP Character Clothing`, `INSTA_OF_SOFTCORE_OUTFITS`, category item templates | | Force a custom location | `SxCP Location Pool` or `SxCP Location Theme` -> builder/pair | `combine_mode=replace` to force; `add` to mix with category scenes | `_scene_pool`, `_apply_location_config_to_legacy_row`, camera scene adapter | | Force a custom frame/composition | `SxCP Composition Pool` or `SxCP Location Theme` -> builder/pair | `combine_mode=replace` to force; `add` to mix | `_composition_pool`, `_apply_composition_config_to_legacy_row`, Krea composition phrase | | Use Qwen/orbit camera geometry | Qwen/orbit node -> camera_config -> builder/pair | For pair, use `softcore_camera_config` and/or `hardcore_camera_config`; set mode from config in options | `_camera_config_with_mode`, `_camera_directive`, `_camera_scene_directive_for_context` | | Use Krea2 for only hard prompt from a pair | Pair `metadata_json` -> Krea2 Formatter | `target=hardcore`, `input_hint=metadata_json` or auto with metadata connected | `_insta_pair_to_krea`, hard row fields | | Convert builder output to SDXL tags | Builder/pair metadata -> SDXL Formatter | Use metadata input; set `target`; select style and quality preset | `_row_core_tags`, `_soft_tags`, `_hard_tags` | | Save/reuse character | Slot/profile nodes -> Profile Save/Load -> slot/builder | Save from the row/profile data you want, not a freshly randomized disconnected route | profile helpers, `web/profile_buttons.js`, profile JSON | ## Seed Axes Seed routing is centralized around `SEED_AXIS_SALTS`, `SEED_AXIS_ALIASES`, and `_axis_rng` in `prompt_builder.py`. | Axis | Controls | | --- | --- | | `category` | Main category selection when random/auto. | | `subcategory` | Subcategory selection. | | `content` | Clothing item, category item, generated outfit, many softcore outfit choices. | | `person` | Character appearance when not fully manual. | | `scene` | Location/scene choice. | | `pose` | Generic pose choice, and for pose-content categories, the hardcore position/action item. | | `role` | Role graph / action choreography for sexual pose categories. Falls back through pose aliases. | | `expression` | Expression choice and expression intensity randomization. | | `composition` | Composition/framing choice. | `SxCP Global Seed`, `SxCP Seed Control`, and `SxCP Seed Locker` all feed `seed_config`. Values below zero mean the row's main seed still drives that axis. Fixed axis seeds allow changing only one road, for example changing `pose`/`role` while keeping person, scene, and category stable. ## Seed Playbook The seed system has two levels: the main row seed and optional per-axis seeds. If an axis seed is negative or absent, the main row seed plus row number drives that axis. If an axis seed is fixed, that axis is reproducible even while other axes change. | Goal | Seed setup | | --- | --- | | Exact full regeneration | Keep main `seed`, `row_number`, `start_index`, and every connected config identical. | | Same person, new pose | Fix `person_seed`; change `pose_seed` and usually `role_seed`. For hardcore pose categories, changing `content_seed` may also matter if the selected category uses content for pose items. | | Same scene, new character | Fix `scene_seed`; change `person_seed`. | | Same action, new framing | Fix `pose_seed`, `role_seed`, and `content_seed`; change `composition_seed` and/or camera config. | | Same outfit, new pose | Fix `content_seed`; change `pose_seed`/`role_seed`. | | Same soft/hard pair but different hardcore action | In pair mode, keep `person_seed`, `scene_seed`, `content_seed` if clothing must stay; change `pose_seed`/`role_seed`. | | Debug expression only | Fix everything except `expression_seed` or expression intensity. | Common trap: `row_number` participates in `_axis_rng`. If two workflows have the same seeds but different `row_number`, they are not expected to match. ## Category Sources There are two category systems. | Source | Files/functions | Notes | | --- | --- | --- | | Built-in legacy generator | `generate_prompt_batches.py`, `_build_direct_builtin_row`, `_build_auto_weighted_row` | Handles legacy `woman`, `man`, `couple`, `group_or_layout`, `auto_weighted`, and `auto_full`. | | JSON category library | `categories/*.json`, `load_category_library`, `_build_custom_row` | Handles expandable categories such as casual clothes, erotic clothes, and hardcore sexual poses. | JSON categories are the scalable system. Add new main categories or subcategories there unless the behavior needs Python logic. ## JSON Category Road ```mermaid flowchart TD A[category/subcategory input] --> B[_find_subcategory] B --> C[item from subcategory.items] C --> D[_compose_item] D --> E[item_templates + axes] B --> F[_scene_pool] B --> G[_expression_pool] B --> H[_pose_pool] B --> I[_composition_pool] E --> J[role graph / item text / axis values] F --> R[scene_text] G --> R H --> R I --> R J --> R[metadata row] ``` Important JSON keys: - `categories`: main category definitions. - `subcategories`: selectable subcategories inside a category. - `items`: item/action entries selected by the content or pose axis. - `item_templates`: templates with axis placeholders. - `axes`: values used to fill `item_templates`. - `scene_pool` / `scene_pools` or direct `scenes`: location road. - `expression_pool` / `expression_pools` or direct `expressions`: expression road. - `composition_pool` / `composition_pools` or direct `compositions`: framing road. - `poses`: category-specific pose fallback. - `prompt_template` / `caption_template`: final prompt assembly for that category. - `inherit_scenes`, `inherit_expressions`, `inherit_compositions`: stop or allow inheritance from category/subcategory/item levels. - `pool_extensions`: patch legacy pools from JSON. Current category/pool files: | File | Main ownership | | --- | --- | | `categories/default_categories.json` | Casual clothes, men/couple casual variants, normal JSON categories. | | `categories/erotic_clothes.json` | Provocative/erotic clothing categories and their scene/expression/composition pools. | | `categories/sexual_poses.json` | Hardcore sexual pose/action categories, role graphs, explicit scene/expression/composition pools. | | `categories/location_pools.json` | Named scene pools and location pool extensions. | | `categories/expression_composition_pools.json` | Named expression pools and composition pools. | ## Pool Ownership Matrix This table is the first stop when the selected content is wrong. | File / pool area | Owns | Selection axis | Formatter risk | | --- | --- | --- | --- | | `default_categories.json` woman casual subcategories | Casual outfit items, casual scenes, casual expressions, casual compositions | `category`, `subcategory`, `content`, `scene`, `expression`, `composition` | Low unless Krea/SDXL needs shorter clothing tags | | `default_categories.json` men casual subcategories | Male casual outfit/items and men-specific casual pools | Same as above | Medium if men are part of a mixed cast and clothing detail is too strong | | `default_categories.json` couple casual subcategories | Couple outfit/action-ish soft poses and couple pools | Same as above | Medium because labels and partner styling can duplicate pair mode | | `erotic_clothes.json` | Provocative/erotic clothing categories and softcore creator scenes | `content`, `scene`, `expression`, `composition` | Medium because nude/implied-nude wording can conflict with clothes | | `sexual_poses.json` foreplay/interaction/manual/oral/outercourse/penetration/etc. | Hardcore action and porn-scene interaction templates, role graphs, axis values, hardcore pool references | `pose` for pose-content route, also `role`; sometimes `content` aliases matter | High because Krea2 rewrites action and POV position text | | `location_pools.json` | Reusable scene pools and legacy scene extensions | `scene` | Medium when a camera-aware adapter changes scene/composition wording | | `expression_composition_pools.json` | Reusable expressions and framing/composition pools | `expression`, `composition` | Medium because formatter may label or suppress expressions | | `generate_prompt_batches.py` legacy pools | Built-in generator clothing, pose, expression, scene, composition lists | Main row seed plus axis config through legacy adapter | Medium because legacy prompt format is field-label heavy | When adding a new pool, choose JSON when the change is pure selectable wording. Choose Python only when selection logic, compatibility filters, camera adaptation, profile behavior, or formatter rewriting must change. ## Pool Resolution ### Scene / Location Scene text is selected by `_scene_pool`. Resolution order: 1. `SxCP Location Pool` / `SxCP Location Theme` with `replace` overrides the category scene pool. 2. Category/subcategory/item direct `scenes` and referenced scene pools are merged, unless inheritance is disabled. 3. `SxCP Location Pool` with `add` appends its entries. 4. Fallback is legacy `g.SCENES` or `g.GROUP_SCENES`. Edit targets: - Add reusable named locations: `categories/location_pools.json`. - Add category-specific locations: the category JSON file. - Add quick workflow-only locations: `SxCP Location Pool` custom locations. - Add themed location packs: `THEMATIC_LOCATION_PRESETS` in `prompt_builder.py`. ### Expression Expression text is selected by `_expression_pool`, then filtered by `_expression_entries_for_intensity`. Resolution order: 1. Category/subcategory/item direct `expressions` and named expression pools. 2. Inheritance can stop at item or subcategory level. 3. Fallback is legacy `g.EXPRESSIONS`. 4. Character slots can override intensity per softcore/hardcore phase. 5. Expression can be disabled globally or per character slot. Edit targets: - General expression pools: `categories/expression_composition_pools.json`. - Hardcore-specific expressions: usually `categories/sexual_poses.json` or named hardcore expression pools. - Character-level expression settings: slot config and `_cast_expression_intensity_override`. - Formatter expression wording: `krea_formatter.py` or `caption_naturalizer.py`. ### Pose / Action Generic pose text is selected by `_pose_pool`. Hardcore sexual pose categories are different: the sexual position/action is an item/template selected by the content route, with `content_seed_axis` set to `pose` for pose-content categories. Edit targets: - Normal pose pools: legacy `g.POSES`, `g.EVOCATIVE_POSES`, or JSON `poses`. - Hardcore positions/actions: `categories/sexual_poses.json`. - Hardcore interaction beats: `categories/sexual_poses.json` subcategories `foreplay_teasing`, `manual_stimulation`, `body_worship_touching`, `clothing_position_transitions`, `dominant_guidance`, `camera_performance`, `group_coordination`, and `aftercare_cleanup`. - Position filtering UI: `build_hardcore_position_pool_json`, `build_hardcore_action_filter_json`, `_apply_hardcore_position_config_to_subcategory`. - Krea2 action rewrite orchestration: `krea_formatter.py`. - Krea2 non-POV position anchors/arrangements: `krea_action_positions.py`. - Krea2 non-climax item/detail cleanup: `krea_action_details.py`. - Krea2 climax role/detail cleanup: `krea_action_climax.py`. - Krea2 non-POV action-family routing: `krea_action_dispatch.py`. - Krea2 non-POV action sentence assembly: `krea_actions.py`. - Krea2 POV position rewrite: `krea_pov_actions.py`. ### Composition Composition text is selected by `_composition_pool`. Resolution order: 1. `SxCP Composition Pool` / `SxCP Location Theme` with `replace` overrides the category composition pool. 2. Category/subcategory/item direct `compositions` and named composition pools are merged. 3. `SxCP Composition Pool` with `add` appends entries. 4. Fallback is legacy `g.COMPOSITIONS` or `g.GROUP_COMPOSITIONS`. Edit targets: - General composition pools: `categories/expression_composition_pools.json`. - Category-specific composition pools: relevant category JSON. - Workflow overrides: `SxCP Composition Pool`. - Camera-aware composition replacements: `_coworking_composition_prompt`. ## Character Route ```mermaid flowchart TD A[Woman/Man/Character Slot chain] --> B[character_cast JSON] C[Profile Load] --> D[character_profile JSON] E[Manual Details / Hair / Body / Age / Eyes / Clothing nodes] --> A B --> F[_parse_character_cast] F --> G[_character_slot_label_map] G --> H[_context_from_character_slot] H --> R[cast descriptors + slot clothing + expression settings] D --> I[_apply_character_profile_to_context] I --> R ``` Important behavior: - Slot chaining labels the closest slot to the final node as `A` for that gender, then upstream slots as `B`, `C`, and so on. - `character_cast` is for multi-character configured casts. `character_profile` is for reusable primary-character details. - `SxCP Character Manual Details` and characteristic pool nodes can feed slots. - `SxCP Character Clothing` can feed `softcore_outfit` and `hardcore_clothing`. - A man slot can be marked as POV. POV men are omitted from visible cast descriptors, and camera wording is adapted to first-person view. Edit targets: - Appearance field generation: `_context_from_character_slot`, `_character_context_for_label`, `_cast_descriptor_entries`. - Profile save/load: `SxCPCharacterProfileSave`, `SxCPCharacterProfileLoad`, profile helpers in `prompt_builder.py`, and `web/profile_buttons.js`. - Hair/body/ethnicity list behavior: characteristic config builders in `prompt_builder.py`. ## Insta/OF Pair Route ```mermaid flowchart TD O[SxCP Insta/OF Options] --> P[build_insta_of_pair] C[character_cast] --> P S[seed_config] --> P L[location_config] --> P M[composition_config] --> P H[hardcore_position_config] --> P P --> A[soft_row via build_prompt] P --> B[hard_row via build_prompt] A --> X[pair metadata] B --> X X --> K[Krea2/SDXL/Naturalizer] ``` Softcore row: - Category comes from `INSTA_OF_SOFTCORE_SUBCATEGORY_BY_LEVEL`. - Outfit comes from character slot `softcore_outfit` if present, otherwise `INSTA_OF_SOFTCORE_OUTFITS`. - Soft pose comes from `INSTA_OF_SOFTCORE_POSES`. - Partner styling comes from `_insta_of_partner_styling` when softcore cast is `same_as_hardcore`. Hardcore row: - Category is always `Hardcore sexual poses`. - Cast count comes from `SxCP Insta/OF Options`. - Position/action/interaction can be constrained by `SxCP Hardcore Position Pool` and `SxCP Hardcore Action Filter`. - Clothing comes from character slot hardcore clothing first, then fallback `hardcore_clothing_continuity`. - Men receive default hardcore clothing if visible and not configured. - POV labels alter action, camera, composition, and visible cast descriptors. Continuity: - `same_creator_same_room` reuses the softcore scene for hardcore. - `same_creator_new_scene` lets hardcore use its own scene. - Shared cast descriptors are stored in pair metadata and consumed by formatters. ## Metadata Field Dictionary The builder outputs JSON metadata because downstream formatters need more than plain prompt text. When debugging, inspect these fields before editing pools. ### Normal Row Metadata | Field | Owner | Consumed by | Meaning | | --- | --- | --- | --- | | `source` | `build_prompt` / row builder | All formatters | Usually `json_category` or `built_in_generator`; tells which route created the row. | | `main_category`, `subcategory` | Category selection | All formatters and debug | Human-readable selected category route. | | `category_slug`, `subcategory_slug` | JSON category normalization | Debug/filtering | Stable-ish machine labels for selected category route. | | `content_seed_axis` | `_build_custom_row` | Debug | Shows whether the item/action was driven by `content` or `pose`. Critical for hardcore pose categories. | | `item` | `_compose_item` or Insta override | Krea/SDXL/Naturalizer | Clothing item, category item, or sexual scene/action text. | | `item_axis_values` | `_compose_item` | Krea hardcore rewrite, SDXL tags | Filled template axes such as position/action/detail values. | | `action_family` | `hardcore_action_metadata.source_hardcore_action_family` | Krea hardcore rewrite, SDXL tags, natural captions, debug | Source-aware formatter semantic family such as `foreplay`, `outercourse`, `oral`, `penetration`, `toy_double`, or `climax`. | | `position_family` | `_hardcore_source_position_family` | Debug/filtering | Source/UI hardcore family selected by subcategory, such as `manual`, `interaction`, `oral`, `anal`, or `climax`. | | `position_key`, `position_keys` | `_hardcore_position_keys` | Debug/future filters | Concrete position tokens inferred from axes and role text, such as `kneeling`, `doggy`, `boobjob`, or `open_thighs`. | | `custom_item`, `item_label` | Category/pair route | Formatters and debug | Label/name for item route. | | `role_graph` | `_role_graph`, POV adapter | Krea/Naturalizer | Choreography/action relationship text after POV adaptation. | | `source_role_graph` | `_role_graph` before POV rewrite | Krea hardcore rewrite | Raw action graph used to infer position and contact. | | `scene_text` | `_scene_pool` or location config | All formatters | Final location text. | | `source_scene_text` | location/body-exposure/camera adapters | Debug/continuity | Previous scene text before an override. | | `location_config` | Location config parser | Debug | Active location pool config, if connected. | | `pose` | `_pose_pool` or category item route | Formatters | Generic pose text. Less important for hardcore action categories than `item`/`role_graph`. | | `expression` | `_expression_pool` and intensity filter | All formatters | Final expression text unless disabled. | | `shared_expression` | Expression selection | Debug | Expression before character-specific expansion. | | `character_expression_text` | Character slot expression route | Krea/Naturalizer | Per-character expression clauses. | | `expression_enabled`, `expression_disabled` | Builder/slot override | All formatters | Hard gate for whether expression text should appear. | | `expression_intensity_source` | Builder/slot override | Debug | Explains whether intensity came from input, random, slot, or disabled state. | | `composition` | `_composition_pool`, POV/camera adapter | All formatters | Final framing phrase. | | `source_composition` | Composition adapter | Krea hardcore rewrite | Previous/raw composition, often better for action inference. | | `composition_config` | Composition config parser | Debug | Active composition pool config, if connected. | | `camera_config` | Camera nodes/parser | Krea/SDXL/debug | Structured camera settings. | | `camera_directive` | `_camera_directive` | Krea/Naturalizer/prompt text | Human camera sentence. Suppressed for POV. | | `camera_scene_directive` | scene-camera adapter | Krea/Naturalizer/prompt text | Location-aware camera layout sentence. | | `subject_type`, `subject_phrase` | Subject/context builder | Formatters | Single/couple/group/configured cast route. | | `women_count`, `men_count`, `person_count` | Cast route | Pair/formatters/debug | Effective cast counts. | | `cast_descriptors`, `cast_descriptor_text` | Character/cast route | Krea/SDXL/Naturalizer | Visible cast descriptors. | | `character_cast_slots` | Character slot chain | POV/camera/formatters | Raw configured slots. | | `character_slot_status`, `character_profile_status` | Character/profile application | Debug | Explains whether slot/profile was applied or skipped. | | `pov_character_labels` | Character slot presence mode | Krea/prompt/camera | Labels omitted from visible cast and rewritten as first-person POV. | | `hardcore_position_config` | Hardcore position/filter nodes | Debug | Active hardcore family/position/action/interaction constraints, including `interaction_only` and `manual_only`. | | `negative_prompt` | Category/pair/default negative route | Formatter output | Base negative text before formatter extras. | | `trigger` | Builder input | Formatter/fallback/debug | Active trigger after fallback to default. | ### Insta/OF Pair Metadata | Field | Owner | Consumed by | Meaning | | --- | --- | --- | --- | | `mode` | `build_insta_of_pair` | Formatters | `Insta/OF` selects pair formatter branches. | | `options` | `SxCP Insta/OF Options` | Formatters/debug | Soft/hard level, cast mode, continuity, camera modes, expression settings. | | `shared_descriptor` | Soft row descriptor | Pair formatters | Primary creator descriptor. | | `shared_cast_descriptors` | Cast descriptor builder | Pair formatters | Full cast descriptor list. | | `softcore_row`, `hardcore_row` | Pair route | Pair formatters | Full normal metadata rows for each side. | | `softcore_prompt`, `hardcore_prompt` | Pair assembly | Direct output/fallback | Raw pair prompts before formatter rewrite. | | `softcore_negative_prompt`, `hardcore_negative_prompt` | Pair assembly | Formatter negatives | Separate negatives for each side. | | `softcore_partner_styling` | `_insta_of_partner_styling` | Krea/SDXL pair branch | Partner softcore clothing and pose when same-cast softcore is enabled. | | `character_hardcore_clothing` | Character slots | Krea pair branch | Explicit per-character hardcore clothing state. | | `default_man_hardcore_clothing` | Pair fallback | Krea pair branch | Auto clothing for visible men without configured clothing. | | `hardcore_clothing_state` | Pair clothing continuity | Krea/SDXL pair branch | Final hard clothing/body exposure sentence before Krea cleanup. | | `hardcore_detail_density` | Insta/OF options | Krea hardcore action rewrite | Controls compact/balanced/dense action detail. | | `softcore_camera_config`, `hardcore_camera_config` | Pair camera route | Krea/SDXL pair branch | Separate camera configs after option mode resolution. | | `softcore_camera_directive`, `hardcore_camera_directive` | Pair camera route | Krea pair branch | Separate plain camera sentences, suppressed for POV. | | `softcore_camera_scene_directive`, `hardcore_camera_scene_directive` | Scene-camera adapter | Krea/Naturalizer pair branch | Separate location-aware camera layout text. | ## Hardcore Position Route `SxCP Hardcore Position Pool` and `SxCP Hardcore Action Filter` both emit `hardcore_position_config`. ```mermaid flowchart TD A[Hardcore Position Pool] --> C[hardcore_position_config] B[Hardcore Action Filter] --> C C --> D[_filter_hardcore_categories_for_position] C --> E[_apply_hardcore_position_config_to_subcategory] E --> F[item_templates / axes in sexual_poses.json] F --> G[role_graph + item + axis_values] G --> H[Krea2 action sentence and POV rewrite] ``` What each part owns: - `sexual_poses.json`: available positions, families, action templates, role graph templates, interaction templates, and action-specific pool references. - `prompt_builder.py`: filters which templates/axes remain available. - `krea_formatter.py`: orchestrates the selected action rewrite into model-readable prose. - `krea_action_positions.py`: resolves non-POV pose anchors, body-arrangement text, duplicate arrangement checks, and action-position phrases. - `krea_action_details.py`: normalizes non-climax item/detail text and dedupes foreplay, outercourse, oral, penetration, toy/double-contact, and anchor details. - `krea_action_climax.py`: rewrites climax role graphs and dedupes aftermath detail/view clauses. - `krea_action_dispatch.py`: normalizes non-POV role graphs, classifies action families, and applies the matching detail cleanup. - `krea_actions.py`: assembles the final non-POV hardcore action sentence. - `krea_pov_actions.py`: rewrites POV variants with first-person geometry. Current broad hardcore families: | Family / focus | Subcategories | | --- | --- | | `penetrative` / `penetration_only` | `penetrative_sex` | | `foreplay` / `foreplay_only` | `foreplay_teasing` | | `interaction` / `interaction_only` | `foreplay_teasing`, `body_worship_touching`, `clothing_position_transitions`, `dominant_guidance`, `camera_performance`, `group_coordination`, `aftercare_cleanup` | | `manual` / `manual_only` | `manual_stimulation` | | `oral` / `oral_only` | `oral_sex` | | `outercourse` / `outercourse_only` | `outercourse_sex`, `manual_stimulation` | | `anal` / `anal_only` | `anal_double_penetration` | | `climax` / `climax_only` | `cumshot_climax` | | `threesome` / `threesome_only` | `threesomes` | | `group` / `group_only` | `group_sex_orgy` | The action filter also has independent gates for toys, double-contact, penetration, foreplay, interaction, manual stimulation, oral, outercourse, anal, and climax. Keep `allow_interaction=true` when using the broader interaction family; keep `allow_manual=true` when manual stimulation should remain possible. `allow_anal=false` blocks anal-sex wording, not ordinary ass-touching interaction phrases such as ass grabbing or body worship. Interaction selector keys include kissing/caressing/undressing, body worship, nipple play, ass grabbing, thigh kissing, hair holding, wrist pinning, dirty talk, position transitions, guided positioning, camera presentation, watching, aftercare, cleanup, fingering, clit rubbing, and mutual masturbation. These keys are still routed through `hardcore_position_config.positions`, so they are controlled by the same `pose`/`role` debug path as other hardcore action keys. If one action keeps recurring, inspect: 1. The enabled position family/action flags. 2. `weight` values in `sexual_poses.json`. 3. Whether the selected subcategory has only a small compatible set after filtering. 4. Whether the formatter collapses several raw actions into the same final wording. ## Camera And Scene Route Camera config nodes: - `SxCP Camera Control`: direct camera settings. - `SxCP Camera Orbit Control`: orbit-like camera settings. - `SxCP Qwen Camera Translator`: converts qwen multi-angle info into `camera_config`. Camera handling: 1. Camera nodes emit `camera_config`. 2. `build_prompt` calls `_apply_camera_config`. 3. `_camera_directive` creates a plain camera sentence unless disabled/off. 4. `_camera_scene_directive_for_context` can add location-aware camera text. 5. POV rows suppress the normal camera directive and use first-person camera wording instead. Current camera-aware scene adapter: - Coworking/business-cafe/office scenes are detected by `_is_coworking_scene`. - Location profile comes from `_coworking_location_profile`. - Direction, distance, and elevation details come from `_coworking_direction_detail`, `_coworking_distance_detail`, and `_coworking_elevation_detail`. - Composition cleanup for coworking outfit-check wording happens in `_coworking_composition_prompt`. Important POV rule: - In POV rows, location anchors must stay behind, beside, or at the frame edges. The foreground belongs to the POV body/hands and visible partner/action. ## Formatter Routes ### Krea2 `format_krea2_prompt` chooses between three roads: - Pair metadata: `_insta_pair_to_krea`. - Normal metadata row: `_normal_row_to_krea`. - Plain text fallback: `_fallback_text_to_krea`. Key Krea2 ownership: - Cast descriptor naturalization: `krea_cast.cast_prose`, `krea_cast.natural_label_text`. - Shared action-family metadata: `hardcore_action_metadata.py`. - Action context and family predicates: `krea_action_context.py`. - Non-POV pose anchors and arrangements: `krea_action_positions.py`. - Non-climax item/detail cleanup: `krea_action_details.py`. - Climax role/detail cleanup: `krea_action_climax.py`. - Non-POV action-family routing: `krea_action_dispatch.py`. - Non-POV hardcore action sentence: `krea_actions.hardcore_action_sentence`. - POV labels, filtering, and camera/composition support: `krea_pov.py`. - Detail clause splitting and density limiting: `krea_detail.py`. - POV hardcore sentence: `krea_pov_actions.pov_action_phrase`. - Clothing state cleanup: `krea_clothing.natural_clothing_state`. - Camera scene preservation: `_camera_scene_phrase`. Krea2 field consumption: | Branch | Reads most from | Key functions | | --- | --- | --- | | Normal single row | `subject_type`, `item`, `pose`, `scene_text`, `expression`, `composition`, `camera_*`, style fields | `_normal_row_to_krea` | | Normal configured cast/hardcore row | `cast_descriptor_text`, `women_count`, `men_count`, `source_role_graph`, `role_graph`, `item`, `item_axis_values`, `source_composition`, `pov_character_labels` | `_normal_row_to_krea`, `krea_actions.hardcore_action_sentence`, `krea_pov_actions.pov_action_phrase` | | Insta/OF pair softcore | `shared_descriptor`, `softcore_row`, `softcore_partner_styling`, options, soft camera fields | `_insta_pair_to_krea` | | Insta/OF pair hardcore | `hardcore_row`, `shared_cast_descriptors`, `hardcore_clothing_state`, `hardcore_detail_density`, hard camera fields, POV labels | `_insta_pair_to_krea`, `krea_actions.hardcore_action_sentence`, `krea_pov_actions.pov_action_phrase`, `krea_clothing.natural_clothing_state` | | Plain text fallback | `source_text` only | `_fallback_text_to_krea` | If metadata is connected and `method` says `text(fallback)`, the formatter did not parse metadata. That is a wiring/input-hint issue, not a prompt pool issue. ### SDXL `format_sdxl_prompt` chooses between: - Pair metadata: `_soft_tags` and `_hard_tags`. - Normal metadata row: `_row_core_tags`. - Plain text fallback: `_fallback_text_to_sdxl`. Use this route for style triggers, weighted tag style, nude weighting, and Pony / SDXL quality/style presets. SDXL field consumption: | Branch | Reads most from | Key functions | | --- | --- | --- | | Normal metadata | cast descriptors, age/body/skin/hair/eyes, `action_family`, `position_family`, `position_keys`, item, role graph, scene, camera config/directive | `_row_core_tags`, `_metadata_family_tags`, `_camera_tags` | | Pair softcore | `softcore_row`, pair partner styling, root soft camera config | `_soft_tags` | | Pair hardcore | `hardcore_row`, `action_family`, `position_family`, `position_keys`, `hardcore_clothing_state`, hard camera fields, hard prompt text | `_hard_tags`, `_metadata_family_tags` | | Text fallback | `source_text`, preserve-trigger setting | `_fallback_text_to_sdxl` | SDXL is the right place for model trigger handling, tag ordering, weight syntax, quality/style preset changes, and nude-weight defaults. Do not solve those in JSON category pools unless the raw builder text is also wrong. ### Naturalizer `naturalize_caption` chooses metadata-specific renderers such as `_configured_cast_from_row`, `_couple_from_row`, and single/group renderers. Use this route when the row metadata is correct but the sentence-style caption is too mechanical or unsuitable for training captions. Naturalizer field consumption: | Branch | Reads most from | Key functions | | --- | --- | --- | | Normal single/couple/group | subject fields, age/body, item, scene, expression, composition, camera scene | `_single_from_row`, `_couple_from_row`, `_group_or_layout_from_row` | | Configured cast/hardcore | `cast_descriptor_text`, `action_family`, `position_family`, `role_graph`, `item`, `scene_text`, expression, composition | `_configured_cast_from_row`, `_metadata_action_label` | | Insta/OF pair | `softcore_row`, `hardcore_row`, pair options and continuity | `_insta_pair_from_row` | | Text fallback | `caption` or `prompt` text | `_text_to_prose` | ### Final Text Hygiene `prompt_hygiene.py` owns route-agnostic final cleanup. It is intentionally small: whitespace, punctuation, empty field labels, adjacent duplicate sentences, repeated trigger prefixes, duplicate comma-list items, and dangling connectors. It is called from: - `prompt_builder.build_prompt` - `prompt_builder.build_insta_of_pair` - `krea_formatter.format_krea2_prompt` - `sdxl_formatter.format_sdxl_prompt` - `caption_naturalizer.naturalize_caption` Do not put semantic fixes in `prompt_hygiene.py`. Sexual action readability, POV geometry, clothing state, Krea prose, SDXL weighting, and training-caption policy still belong to their route-specific owner. ## Utility / Workflow Nodes These do not own prompt pool wording, but they affect execution and review: | Node family | Files | Purpose | | --- | --- | --- | | Loop nodes | `loop_nodes.py`, `web/loop_slots.js` | While/for loop execution and carry values. | | Index switch | `loop_nodes.py`, `web/index_switch_slots.js` | Multi-input to selected output, and selected input to multi-output routing. | | Accumulator | `loop_nodes.py`, `web/accumulator_preview.js` | Stores generated values/images during workflow execution and previews/reorders/deletes them. | | Persistent text preview | `loop_nodes.py`, `web/preview_any_text.js` | Stores any value as text and keeps it after workflow reload. | | SDXL bucket size | `SxCPSDXLBucketSize` in `__init__.py` | Random/fixed SDXL bucket width and height selection. | | Krea2 resolution selector | `SxCPKrea2ResolutionSelector` in `__init__.py` | Krea-compatible width/height and API aspect/resolution helper. | ## Drift Audit Helper The map should be checked when adding nodes, category files, or named pools. Run: ```bash python tools/prompt_map_audit.py ``` The script does not import ComfyUI. It parses the repo and prints: - registered display node names and known return names; - per-JSON category counts; - named scene/expression/composition pool inventory. - JSON reference validation for every `scene_pools`, `expression_pools`, and `composition_pools` reference; - item template validation so `{placeholder}` names resolve to `item_axes`. Use its output to spot doc drift after adding a new node or pool. If a new node or pool appears there but not in this map, update the relevant route table. The script exits nonzero when JSON pool references or item template axes do not resolve. ## Behavioral Smoke Helper Route behavior should be checked when changing prompt generation, pair assembly, formatter metadata parsing, trigger handling, expression disabling, or scene continuity. Run: ```bash python tools/prompt_smoke.py ``` The script does not import ComfyUI. It builds representative metadata rows and pair metadata through the core Python APIs, then verifies: - generated rows keep prompt, negative prompt, scene, composition, action item, and role graph metadata populated; - Krea2, SDXL, and natural caption routes use metadata instead of text fallback; - SDXL and caption trigger handling keeps one trigger; - negative prompts do not duplicate comma-list items; - `SxCP Prompt Builder From Configs`-style wiring preserves category, cast, generation profile, seed lock, camera, location theme, and composition config; - same-room Insta/OF continuity keeps prompt text and `hardcore_row.scene_text` synchronized; - camera-aware coworking scene text survives single-row Krea formatting; - softcore and hardcore pair rows can carry different camera configs without collapsing to the same camera phrase; - POV camera-scene directives suppress normal third-person camera text while preserving first-person spatial layout; - Krea close-interaction routes keep rewritten action wording, avoid raw builder labels, and catch invalid surface joins such as `on against a wall`; - Krea POV penetration routes keep first-person position anchors, suppress normal camera text, and preserve composition punctuation before the style suffix; - POV outercourse routes keep constrained boobjob, testicle-sucking, penis-licking, handjob, and footjob geometry through Krea formatting; - expression-disabled rows do not fall back to generated expression text. - static formatter metadata fixtures keep source-provided action families stable across Krea2 prose, SDXL tags, and natural captions even when raw item text contains distracting wording. ## Editing Cheatsheet | Symptom | First file/function to inspect | | --- | --- | | Wrong main category/subcategory frequency | Category node config, `load_category_library`, category JSON weights. | | Wrong outfit/clothing item | Relevant category JSON, `INSTA_OF_SOFTCORE_OUTFITS`, `SxCP Character Clothing`. | | Nude/clothing state confusing Krea2 | `build_insta_of_pair` clothing state helpers, then `krea_clothing.natural_clothing_state`. | | Wrong location | `categories/location_pools.json`, category `scene_pool`, `_scene_pool`. | | Location good but camera/location layout wrong | `_camera_scene_directive_for_context`, coworking adapter functions. | | Repeated desk/anchor in POV foreground | Coworking direction/distance/elevation helpers. | | Wrong expression intensity | Character slot expression settings, `_expression_entries_for_intensity`, expression pools. | | Expression appears when disabled | `_disable_row_expression`, formatter expression extraction. | | Same hardcore action repeats | Hardcore filter config, `sexual_poses.json` weights, `_apply_hardcore_position_config_to_subcategory`. | | Hardcore interaction beat falls back to penetration/oral | `sexual_poses.json` interaction subcategory, `_role_graph`, and `krea_action_context.is_foreplay_text` / `krea_action_positions.hardcore_pose_anchor`. | | Raw hardcore prompt position is vague | `sexual_poses.json` item templates and role graph templates. | | Krea2 hardcore prompt position is vague | `krea_actions.hardcore_action_sentence` or `krea_pov_actions.py`. | | Man appears described in POV | POV labels, `krea_cast.cast_prose` omit labels, `krea_pov_actions.pov_action_phrase`. | | Camera prompt missing from Krea2 | Row `camera_directive` / `camera_scene_directive`, then Krea `_camera_phrase`. | | Trigger missing in Krea2 fallback | `format_krea2_prompt` preserve-trigger fallback behavior. | | SDXL tags too weak/wrong style | `sdxl_formatter.py` presets and `_row_core_tags` / `_soft_tags` / `_hard_tags`. | | Duplicate punctuation, empty labels, repeated trigger, repeated tag item | `prompt_hygiene.py`, then the route-specific formatter if the repeated content is semantic. | | Bed/sheet/couch or malformed surface wording leaks into hardcore prompts | `hardcore_text_cleanup.py`, then the relevant category pool/template. | | Saved profile does not match liked character | Profile save/load path and whether the saved input is row metadata or regenerated slot config. | | Accumulator preview behavior wrong | `loop_nodes.py` accumulator methods and `web/accumulator_preview.js`. | ## Debug Route Traces Use these traces to narrow a problem in one pass. ### Hardcore action keeps selecting the same family 1. Check metadata `main_category`, `subcategory`, `content_seed_axis`, `action_family`, `position_family`, `position_key`, `hardcore_position_config`, `item`, `role_graph`, and `item_axis_values`. 2. If `hardcore_position_config` disabled most families, the repeated action may be the only compatible pool left. 3. Inspect `categories/sexual_poses.json` for the selected subcategory, `item_templates`, `axes`, and `weight`. 4. If raw `item` differs but Krea output looks identical, inspect `hardcore_action_metadata.py` action-family metadata first, then `krea_action_context.py` family predicates, `krea_action_positions.py` pose anchors/arrangements, `krea_action_details.py` item/detail cleanup, `krea_action_climax.py` climax cleanup, `krea_action_dispatch.py` family routing, and `krea_actions.py` action sentence assembly. ### POV position is spatially wrong 1. Confirm `pov_character_labels` includes the intended man label. 2. Confirm Krea input uses metadata, not plain prompt fallback. 3. Inspect `source_role_graph`, `item`, `source_composition`, and `item_axis_values`. 4. Inspect `krea_pov.py` if the label omission, camera phrase, or POV composition cleanup is wrong. 5. Edit `krea_pov_actions.py` if the first-person body geometry is wrong. 6. Edit `sexual_poses.json` if the raw action lacks enough body-position anchor for any formatter to infer a good POV prompt. ### Camera disappears or becomes too generic 1. Check row `camera_config`, `camera_directive`, and `camera_scene_directive`. 2. If `camera_detail=off` or `camera_mode=disabled`, missing camera text is expected. 3. If POV labels exist, plain `camera_directive` is intentionally suppressed. 4. If a location-aware sentence is missing, inspect `_camera_scene_directive_for_context` and the scene detector for that location family. 5. If raw metadata has camera text but Krea omits it, inspect `_camera_phrase`, `_pair_camera_phrase`, and `_camera_scene_phrase`. ### Nude/clothing wording conflicts 1. Check pair root `hardcore_clothing_state`. 2. Check hard row `item` and `source_role_graph` for access flags. 3. Character slot `hardcore_clothing` overrides pair fallback clothing. 4. For Krea wording, inspect `krea_clothing.natural_clothing_state`. 5. For generation wording, inspect `_insta_of_hardcore_clothing_state`, `_hardcore_row_access_flags`, and `character_hardcore_clothing_values`. ### Softcore contains strange no-contact or bed/action leakage 1. Check whether the prompt came from pair softcore or normal category builder. 2. In pair softcore, inspect `softcore_partner_styling`, `softcore_row.item`, `softcore_row.pose`, and options `softcore_cast`. 3. If the raw soft prompt contains awkward defensive clauses, fix `build_insta_of_pair` soft prompt assembly. 4. If Krea adds the awkwardness, inspect `_insta_pair_to_krea`. ### Location composition mentions irrelevant props 1. Check `scene_text` and `composition` separately. 2. If scene is good and composition is bad, edit composition pools, not location pools. 3. If a scene-camera adapter rewrote composition, inspect `scene_camera_adapters.py`. 4. If the issue comes from `Location Theme`, edit `THEMATIC_LOCATION_PRESETS`. ### Trigger missing after formatting 1. For builder raw prompts, check `trigger` and `prepend_trigger_to_prompt`. 2. For Krea fallback, check `preserve_trigger`; metadata route usually rebuilds prose and does not use prompt text as a raw string. 3. For SDXL, trigger handling belongs to `format_sdxl_prompt` style assembly: `trigger`, `prepend_trigger_to_prompt`, `preserve_trigger`, and style preset. ## Safe Edit Workflow Before changing prompt behavior: 1. Capture one raw builder output and the formatter output. 2. Check metadata JSON for `source`, `main_category`, `subcategory`, `content_seed_axis`, `scene_text`, `item`, `role_graph`, `source_role_graph`, `item_axis_values`, `composition`, `camera_scene_directive`, and `pov_character_labels`. 3. Decide whether the bug is selection, raw wording, camera adaptation, or formatter rewrite. 4. Edit the smallest owning pool/template/function. 5. Re-run a small simulation with fixed person/scene/category seeds and only the target axis varied. The repo may have unrelated dirty files during interactive prompt work. Always stage only the intended files for commits.