Add scene-chain option nodes
This commit is contained in:
@@ -128,6 +128,16 @@ blocking, action, performance, camera, composition, and lighting layers. Use
|
|||||||
`SxCP Hardcore Branch Options`, then render both sides through
|
`SxCP Hardcore Branch Options`, then render both sides through
|
||||||
`SxCP Scene Pair Output`.
|
`SxCP Scene Pair Output`.
|
||||||
|
|
||||||
|
Each layer can stay light on the main chain and take optional side-node inputs:
|
||||||
|
`SxCP Scene Layer Seed Options`, `SxCP Scene Cast Options`,
|
||||||
|
`SxCP Scene Character Options`, `SxCP Scene Wardrobe Options`,
|
||||||
|
`SxCP Scene Location Layout Options`, `SxCP Scene Set Dressing Options`,
|
||||||
|
`SxCP Scene Blocking Options`, `SxCP Scene Action Options`,
|
||||||
|
`SxCP Scene Performance Options`, `SxCP Scene Camera Options`,
|
||||||
|
`SxCP Scene Composition Options`, `SxCP Scene Lighting Options`, and
|
||||||
|
`SxCP Scene Branch Options`. These side nodes are chainable and only override
|
||||||
|
the layer they are connected to.
|
||||||
|
|
||||||
The current v2 output nodes intentionally reuse the existing builder,
|
The current v2 output nodes intentionally reuse the existing builder,
|
||||||
Insta/OF pair, and formatter metadata routes. This keeps old workflows working
|
Insta/OF pair, and formatter metadata routes. This keeps old workflows working
|
||||||
while giving new workflows a cleaner movie-scene structure.
|
while giving new workflows a cleaner movie-scene structure.
|
||||||
|
|||||||
+13
@@ -25,6 +25,19 @@ SXCP_CHARACTER_CAST = "SXCP_CHARACTER_CAST"
|
|||||||
SXCP_CHARACTER_SLOT = "SXCP_CHARACTER_SLOT"
|
SXCP_CHARACTER_SLOT = "SXCP_CHARACTER_SLOT"
|
||||||
SXCP_CHARACTER_PROFILE = "SXCP_CHARACTER_PROFILE"
|
SXCP_CHARACTER_PROFILE = "SXCP_CHARACTER_PROFILE"
|
||||||
SXCP_SCENE = "SXCP_SCENE"
|
SXCP_SCENE = "SXCP_SCENE"
|
||||||
|
SXCP_SCENE_LAYER_SEED = "SXCP_SCENE_LAYER_SEED"
|
||||||
|
SXCP_SCENE_CAST_OPTIONS = "SXCP_SCENE_CAST_OPTIONS"
|
||||||
|
SXCP_SCENE_CHARACTER_OPTIONS = "SXCP_SCENE_CHARACTER_OPTIONS"
|
||||||
|
SXCP_SCENE_WARDROBE_OPTIONS = "SXCP_SCENE_WARDROBE_OPTIONS"
|
||||||
|
SXCP_SCENE_LOCATION_OPTIONS = "SXCP_SCENE_LOCATION_OPTIONS"
|
||||||
|
SXCP_SCENE_SET_OPTIONS = "SXCP_SCENE_SET_OPTIONS"
|
||||||
|
SXCP_SCENE_BLOCKING_OPTIONS = "SXCP_SCENE_BLOCKING_OPTIONS"
|
||||||
|
SXCP_SCENE_ACTION_OPTIONS = "SXCP_SCENE_ACTION_OPTIONS"
|
||||||
|
SXCP_SCENE_PERFORMANCE_OPTIONS = "SXCP_SCENE_PERFORMANCE_OPTIONS"
|
||||||
|
SXCP_SCENE_CAMERA_OPTIONS = "SXCP_SCENE_CAMERA_OPTIONS"
|
||||||
|
SXCP_SCENE_COMPOSITION_OPTIONS = "SXCP_SCENE_COMPOSITION_OPTIONS"
|
||||||
|
SXCP_SCENE_LIGHTING_OPTIONS = "SXCP_SCENE_LIGHTING_OPTIONS"
|
||||||
|
SXCP_SCENE_BRANCH_OPTIONS = "SXCP_SCENE_BRANCH_OPTIONS"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from .node_tooltips import install_input_tooltips as _install_input_tooltips
|
from .node_tooltips import install_input_tooltips as _install_input_tooltips
|
||||||
|
|||||||
@@ -80,6 +80,16 @@ V2 scene-chain display nodes: `SxCP Scene Cast`, `SxCP Scene Character`,
|
|||||||
`SxCP Scene Branch Pair`, `SxCP Softcore Branch Options`, and
|
`SxCP Scene Branch Pair`, `SxCP Softcore Branch Options`, and
|
||||||
`SxCP Hardcore Branch Options`.
|
`SxCP Hardcore Branch Options`.
|
||||||
|
|
||||||
|
V2 scene-chain side option nodes: `SxCP Scene Layer Seed Options`,
|
||||||
|
`SxCP Scene Cast Options`, `SxCP Scene Character Options`,
|
||||||
|
`SxCP Scene Wardrobe Options`, `SxCP Scene Location Layout Options`,
|
||||||
|
`SxCP Scene Set Dressing Options`, `SxCP Scene Blocking Options`,
|
||||||
|
`SxCP Scene Action Options`, `SxCP Scene Performance Options`,
|
||||||
|
`SxCP Scene Camera Options`, `SxCP Scene Composition Options`,
|
||||||
|
`SxCP Scene Lighting Options`, and `SxCP Scene Branch Options`. These nodes
|
||||||
|
feed typed option sockets into the main scene chain so the visible chain can
|
||||||
|
stay organized by movie-scene layer while deeper knobs remain adjacent.
|
||||||
|
|
||||||
Core helper ownership:
|
Core helper ownership:
|
||||||
|
|
||||||
| Python module | What it owns |
|
| Python module | What it owns |
|
||||||
|
|||||||
+1110
-18
File diff suppressed because it is too large
Load Diff
@@ -17,6 +17,10 @@ COMMON_INPUT_TOOLTIPS = {
|
|||||||
"filter_config": "Ethnicity/body filter config. Ethnicity List can feed this too.",
|
"filter_config": "Ethnicity/body filter config. Ethnicity List can feed this too.",
|
||||||
"ethnicity_list": "Optional ethnicity pool. When connected, it overrides the slot or generator ethnicity picker.",
|
"ethnicity_list": "Optional ethnicity pool. When connected, it overrides the slot or generator ethnicity picker.",
|
||||||
"seed_config": "Per-axis seed config. Use Global Seed for full reproducibility, Seed Locker to reroll one axis, or Seed Control for manual axis seeds.",
|
"seed_config": "Per-axis seed config. Use Global Seed for full reproducibility, Seed Locker to reroll one axis, or Seed Control for manual axis seeds.",
|
||||||
|
"layer": "Scene layer affected by this side node. all applies to every compatible scene node that receives the options.",
|
||||||
|
"seed_mode": "follow_global uses the scene seed, fixed uses the seed field, random resolves a fresh seed at queue time, disabled does nothing.",
|
||||||
|
"row_behavior": "same_for_all_rows keeps the option seed as-is; vary_by_row offsets it by row number before writing axis seeds.",
|
||||||
|
"reroll_axis": "Specific generator axis group to reroll. none uses the default axes for the selected scene layer.",
|
||||||
"camera_config": "Camera config consumed only by nodes/options set to from_camera_config.",
|
"camera_config": "Camera config consumed only by nodes/options set to from_camera_config.",
|
||||||
"location_config": "Location config from SxCP Location Pool. It can replace or add to the category scene pool.",
|
"location_config": "Location config from SxCP Location Pool. It can replace or add to the category scene pool.",
|
||||||
"composition_config": "Composition config from SxCP Composition Pool or Location Theme. It can replace or add framing options.",
|
"composition_config": "Composition config from SxCP Composition Pool or Location Theme. It can replace or add framing options.",
|
||||||
@@ -33,6 +37,20 @@ COMMON_INPUT_TOOLTIPS = {
|
|||||||
"scene": "Structured v2 scene context. Chain Scene nodes in order, then connect to Scene Output or Scene Pair Output.",
|
"scene": "Structured v2 scene context. Chain Scene nodes in order, then connect to Scene Output or Scene Pair Output.",
|
||||||
"softcore_scene": "Softcore branch scene from Scene Branch Pair, optionally refined by Softcore Branch Options.",
|
"softcore_scene": "Softcore branch scene from Scene Branch Pair, optionally refined by Softcore Branch Options.",
|
||||||
"hardcore_scene": "Hardcore branch scene from Scene Branch Pair, optionally refined by Hardcore Branch Options.",
|
"hardcore_scene": "Hardcore branch scene from Scene Branch Pair, optionally refined by Hardcore Branch Options.",
|
||||||
|
"options": "Incoming options of the same type. Chain option nodes with combine_mode=add when multiple side knobs should contribute.",
|
||||||
|
"seed_options": "Scene layer seed options. Connect Scene Layer Seed Options to reroll one layer without changing the whole scene.",
|
||||||
|
"cast_options": "Optional cast side-node settings that override the Cast node widgets only when connected.",
|
||||||
|
"character_options": "Optional character side-node settings that override descriptor, presence, and expression controls.",
|
||||||
|
"wardrobe_options": "Optional wardrobe side-node settings for subject-specific clothing, nudity state, and wardrobe prompt text.",
|
||||||
|
"location_options": "Optional location layout settings such as foreground anchors, midground, repetition, and public/private context.",
|
||||||
|
"set_options": "Optional set-dressing settings for props, repeated background, foreground anchors, and sensory details.",
|
||||||
|
"blocking_options": "Optional blocking settings for subject placement, orientation, depth plane, and exact body geography.",
|
||||||
|
"action_options": "Optional action settings for scene kind, action family, category preset, and manual action text.",
|
||||||
|
"performance_options": "Optional performance settings for expression, gaze, hands, body tension, and actor notes.",
|
||||||
|
"camera_options": "Optional camera side-node settings that describe camera source and freeform camera text.",
|
||||||
|
"composition_options": "Optional composition side-node settings for readability target, crop, occlusion, and framing text.",
|
||||||
|
"lighting_options": "Optional lighting side-node settings for source, softness, contrast, color, and time of day.",
|
||||||
|
"branch_options": "Optional branch settings that apply to softcore, hardcore, or both Insta/OF branches.",
|
||||||
"target_formatter": "Intended downstream formatter target. The scene stores this as metadata; use formatter nodes for final rewriting.",
|
"target_formatter": "Intended downstream formatter target. The scene stores this as metadata; use formatter nodes for final rewriting.",
|
||||||
"category_preset": "Category preset this scene should render through when no explicit category config overrides it.",
|
"category_preset": "Category preset this scene should render through when no explicit category config overrides it.",
|
||||||
"central_subject": "Who should be visually central in this scene metadata.",
|
"central_subject": "Who should be visually central in this scene metadata.",
|
||||||
@@ -42,24 +60,43 @@ COMMON_INPUT_TOOLTIPS = {
|
|||||||
"custom_location": "Exact location text for this scene. One line or JSON entry is enough.",
|
"custom_location": "Exact location text for this scene. One line or JSON entry is enough.",
|
||||||
"location_note": "Additional location wording merged into the location pool entry.",
|
"location_note": "Additional location wording merged into the location pool entry.",
|
||||||
"foreground_anchors": "Objects or surfaces that should stay near the camera or lower frame.",
|
"foreground_anchors": "Objects or surfaces that should stay near the camera or lower frame.",
|
||||||
|
"midground_layer": "Readable middle-distance scene elements between the subject and background.",
|
||||||
|
"background_repetition": "Repeated environmental structure that helps the model keep a location coherent across rerolls.",
|
||||||
|
"visibility_level": "How visible or hidden the scene should feel inside the location.",
|
||||||
|
"public_level": "Private, semi-public, or public context for the location layer.",
|
||||||
"repeated_background": "Repeating background structure such as desks, doors, shelves, pillars, or windows.",
|
"repeated_background": "Repeating background structure such as desks, doors, shelves, pillars, or windows.",
|
||||||
"props": "Scene props or set dressing objects that make the location readable.",
|
"props": "Scene props or set dressing objects that make the location readable.",
|
||||||
|
"sensory_details": "Small material/light/surface details that make the set dressing feel specific.",
|
||||||
"set_prompt": "Freeform set-dressing sentence appended to the scene layer.",
|
"set_prompt": "Freeform set-dressing sentence appended to the scene layer.",
|
||||||
"blocking_mode": "Broad body-placement mode. custom lets custom_blocking carry the exact placement.",
|
"blocking_mode": "Broad body-placement mode. custom lets custom_blocking carry the exact placement.",
|
||||||
"subject_placement": "Where the subject or cast sits in the space: foreground, near desk edge, on bed, in aisle, etc.",
|
"subject_placement": "Where the subject or cast sits in the space: foreground, near desk edge, on bed, in aisle, etc.",
|
||||||
"body_relation": "Spatial relationship between participants, separate from the action itself.",
|
"body_relation": "Spatial relationship between participants, separate from the action itself.",
|
||||||
|
"body_orientation": "Front, side, back, three-quarter, or POV-facing body orientation.",
|
||||||
|
"depth_plane": "Whether the subjects sit in foreground, midground, background, or a layered composition.",
|
||||||
|
"distance_note": "Extra spatial distance wording, such as close together, across the table, or partly hidden behind a shelf.",
|
||||||
"custom_blocking": "Exact blocking/positioning sentence for the scene layer.",
|
"custom_blocking": "Exact blocking/positioning sentence for the scene layer.",
|
||||||
"scene_kind": "Regular, softcore, or hardcore intent for this action layer.",
|
"scene_kind": "Regular, softcore, or hardcore intent for this action layer.",
|
||||||
|
"action_family": "Broad action family such as softcore tease, oral, penetration, climax, group, or custom.",
|
||||||
"action_prompt": "Action text stored separately from blocking and camera. Use position pools for hardcore randomization when possible.",
|
"action_prompt": "Action text stored separately from blocking and camera. Use position pools for hardcore randomization when possible.",
|
||||||
|
"gaze": "Where the character looks: camera, partner, down, away, over shoulder, or eyes closed.",
|
||||||
|
"hand_placement": "What hands are doing: relaxed, on body, on partner, holding camera, pulling clothing, or braced.",
|
||||||
|
"body_tension": "Body performance cue: relaxed, posed, arched, braced, or active motion.",
|
||||||
"performance_prompt": "Expression, gaze, hand, and body-performance note stored separately from the action.",
|
"performance_prompt": "Expression, gaze, hand, and body-performance note stored separately from the action.",
|
||||||
|
"camera_source": "Where camera text comes from conceptually: config, qwen orbit, POV, phone, external, or manual.",
|
||||||
|
"preserve_location_layout": "Keep location layout wording compatible with the camera instead of letting camera text replace the space.",
|
||||||
"camera_prompt": "Optional freeform camera note kept as scene metadata. Camera config still controls existing formatter behavior.",
|
"camera_prompt": "Optional freeform camera note kept as scene metadata. Camera config still controls existing formatter behavior.",
|
||||||
"custom_composition": "Exact composition/framing entry to add to the composition pool.",
|
"custom_composition": "Exact composition/framing entry to add to the composition pool.",
|
||||||
|
"readability_target": "What the composition should keep most readable: face, body, action, room, anchor objects, or contact points.",
|
||||||
|
"crop": "Composition crop intent such as full body, three-quarter, close-up, or extreme close-up.",
|
||||||
|
"occlusion": "How much foreground or hidden-sightline occlusion the composition should allow.",
|
||||||
"composition_prompt": "Additional composition wording merged into the composition layer.",
|
"composition_prompt": "Additional composition wording merged into the composition layer.",
|
||||||
"lighting_source": "Main light source family for the scene.",
|
"lighting_source": "Main light source family for the scene.",
|
||||||
"lighting_softness": "Softness of the light: soft, balanced, or hard.",
|
"lighting_softness": "Softness of the light: soft, balanced, or hard.",
|
||||||
"lighting_contrast": "Overall contrast level for the lighting layer.",
|
"lighting_contrast": "Overall contrast level for the lighting layer.",
|
||||||
"color_temperature": "Warm, neutral, cool, or mixed color temperature.",
|
"color_temperature": "Warm, neutral, cool, or mixed color temperature.",
|
||||||
|
"time_of_day": "Optional time-of-day lighting context.",
|
||||||
"custom_lighting": "Exact lighting sentence for the scene layer.",
|
"custom_lighting": "Exact lighting sentence for the scene layer.",
|
||||||
|
"branch_target": "Whether branch options affect both Insta/OF branches, softcore only, or hardcore only.",
|
||||||
"continuity": "How branch outputs share cast/location setup between softcore and hardcore scenes.",
|
"continuity": "How branch outputs share cast/location setup between softcore and hardcore scenes.",
|
||||||
"platform_style": "Instagram/OnlyFans styling bias for Scene Pair Output.",
|
"platform_style": "Instagram/OnlyFans styling bias for Scene Pair Output.",
|
||||||
"softcore_cast": "Whether the softcore branch uses a solo creator or the same cast as the hardcore branch.",
|
"softcore_cast": "Whether the softcore branch uses a solo creator or the same cast as the hardcore branch.",
|
||||||
@@ -126,6 +163,9 @@ COMMON_INPUT_TOOLTIPS = {
|
|||||||
"presence_mode": "Controls whether the character is visible or acts as the male POV participant.",
|
"presence_mode": "Controls whether the character is visible or acts as the male POV participant.",
|
||||||
"softcore_outfit": "Manual softcore outfit text for this character. Prefer Character Clothing for reusable outfit pools.",
|
"softcore_outfit": "Manual softcore outfit text for this character. Prefer Character Clothing for reusable outfit pools.",
|
||||||
"hardcore_clothing": "Manual hardcore exposure text for this character. Use explicit nude states when you do not want clothing words repeated.",
|
"hardcore_clothing": "Manual hardcore exposure text for this character. Use explicit nude states when you do not want clothing words repeated.",
|
||||||
|
"wardrobe_state": "High-level clothing/body-exposure state. explicit_nude avoids conflicting outfit text in hardcore prompts.",
|
||||||
|
"accessories": "Accessories that can remain visible without forcing full outfit wording.",
|
||||||
|
"avoid_clothing_when_nude": "When nude states are selected, avoid reintroducing clothing words that make the image model dress the subject.",
|
||||||
"custom_softcore_outfits": "One custom softcore outfit per line. Used when softcore_source is custom.",
|
"custom_softcore_outfits": "One custom softcore outfit per line. Used when softcore_source is custom.",
|
||||||
"custom_hardcore_clothing": "One custom hardcore clothing/body exposure state per line.",
|
"custom_hardcore_clothing": "One custom hardcore clothing/body exposure state per line.",
|
||||||
"condition": "Loop condition. When false, the loop stops and passes current values through.",
|
"condition": "Loop condition. When false, the loop stops and passes current values through.",
|
||||||
|
|||||||
+86
-5
@@ -8792,6 +8792,19 @@ def smoke_node_insta_registration() -> None:
|
|||||||
|
|
||||||
def smoke_node_scene_chain_registration() -> None:
|
def smoke_node_scene_chain_registration() -> None:
|
||||||
required_nodes = [
|
required_nodes = [
|
||||||
|
"SxCPSceneLayerSeedOptions",
|
||||||
|
"SxCPSceneCastOptions",
|
||||||
|
"SxCPSceneCharacterOptions",
|
||||||
|
"SxCPSceneWardrobeOptions",
|
||||||
|
"SxCPSceneLocationLayoutOptions",
|
||||||
|
"SxCPSceneSetDressingOptions",
|
||||||
|
"SxCPSceneBlockingOptions",
|
||||||
|
"SxCPSceneActionOptions",
|
||||||
|
"SxCPScenePerformanceOptions",
|
||||||
|
"SxCPSceneCameraOptions",
|
||||||
|
"SxCPSceneCompositionOptions",
|
||||||
|
"SxCPSceneLightingOptions",
|
||||||
|
"SxCPSceneBranchOptions",
|
||||||
"SxCPSceneStart",
|
"SxCPSceneStart",
|
||||||
"SxCPSceneCast",
|
"SxCPSceneCast",
|
||||||
"SxCPSceneCharacter",
|
"SxCPSceneCharacter",
|
||||||
@@ -8830,6 +8843,7 @@ def smoke_node_scene_chain_registration() -> None:
|
|||||||
parsed_scene = json.loads(scene)
|
parsed_scene = json.loads(scene)
|
||||||
_expect(parsed_scene.get("schema") == "sxcp_scene_v2", "Scene Start did not emit v2 schema")
|
_expect(parsed_scene.get("schema") == "sxcp_scene_v2", "Scene Start did not emit v2 schema")
|
||||||
|
|
||||||
|
cast_options = nodes["SxCPSceneCastOptions"]().build("replace", "mixed_couple", 1, 1, "woman_a", "none")[0]
|
||||||
scene, _cast_config, _cast_summary, _cast_metadata = nodes["SxCPSceneCast"]().build(
|
scene, _cast_config, _cast_summary, _cast_metadata = nodes["SxCPSceneCast"]().build(
|
||||||
scene,
|
scene,
|
||||||
"mixed_couple",
|
"mixed_couple",
|
||||||
@@ -8837,7 +8851,18 @@ def smoke_node_scene_chain_registration() -> None:
|
|||||||
1,
|
1,
|
||||||
"woman_a",
|
"woman_a",
|
||||||
"none",
|
"none",
|
||||||
|
cast_options=cast_options,
|
||||||
)
|
)
|
||||||
|
character_options = nodes["SxCPSceneCharacterOptions"]().build(
|
||||||
|
"replace",
|
||||||
|
"medium",
|
||||||
|
"visible",
|
||||||
|
"enabled",
|
||||||
|
0.5,
|
||||||
|
-1,
|
||||||
|
-1,
|
||||||
|
"controlled slot performance note",
|
||||||
|
)[0]
|
||||||
scene, character_cast, _slot, _summary, _metadata = nodes["SxCPSceneCharacter"]().build(
|
scene, character_cast, _slot, _summary, _metadata = nodes["SxCPSceneCharacter"]().build(
|
||||||
scene,
|
scene,
|
||||||
True,
|
True,
|
||||||
@@ -8854,6 +8879,7 @@ def smoke_node_scene_chain_registration() -> None:
|
|||||||
"visible",
|
"visible",
|
||||||
-1,
|
-1,
|
||||||
-1,
|
-1,
|
||||||
|
character_options=character_options,
|
||||||
)
|
)
|
||||||
scene, character_cast, _slot, _summary, _metadata = nodes["SxCPSceneCharacter"]().build(
|
scene, character_cast, _slot, _summary, _metadata = nodes["SxCPSceneCharacter"]().build(
|
||||||
scene,
|
scene,
|
||||||
@@ -8872,6 +8898,19 @@ def smoke_node_scene_chain_registration() -> None:
|
|||||||
-1,
|
-1,
|
||||||
-1,
|
-1,
|
||||||
)
|
)
|
||||||
|
wardrobe_seed_options = nodes["SxCPSceneLayerSeedOptions"]().build("wardrobe", "fixed", 9981, "content", "same_for_all_rows", "replace_layer")[0]
|
||||||
|
wardrobe_options = nodes["SxCPSceneWardrobeOptions"]().build(
|
||||||
|
"replace",
|
||||||
|
"woman",
|
||||||
|
"A",
|
||||||
|
"full",
|
||||||
|
"explicit_nude",
|
||||||
|
True,
|
||||||
|
"simple black dress",
|
||||||
|
"",
|
||||||
|
"thin necklace",
|
||||||
|
"",
|
||||||
|
)[0]
|
||||||
scene, character_cast, _wardrobe_summary, _wardrobe_metadata = nodes["SxCPSceneWardrobe"]().build(
|
scene, character_cast, _wardrobe_summary, _wardrobe_metadata = nodes["SxCPSceneWardrobe"]().build(
|
||||||
scene,
|
scene,
|
||||||
True,
|
True,
|
||||||
@@ -8881,12 +8920,24 @@ def smoke_node_scene_chain_registration() -> None:
|
|||||||
"simple black dress",
|
"simple black dress",
|
||||||
"fully nude",
|
"fully nude",
|
||||||
"",
|
"",
|
||||||
|
wardrobe_options=wardrobe_options,
|
||||||
|
seed_options=wardrobe_seed_options,
|
||||||
)
|
)
|
||||||
slots = json.loads(character_cast).get("slots") or []
|
slots = json.loads(character_cast).get("slots") or []
|
||||||
woman_slot = next(slot for slot in slots if slot.get("subject_type") == "woman")
|
woman_slot = next(slot for slot in slots if slot.get("subject_type") == "woman")
|
||||||
_expect(woman_slot.get("softcore_outfit") == "simple black dress", "Scene Wardrobe did not update softcore outfit")
|
_expect(woman_slot.get("softcore_outfit") == "simple black dress", "Scene Wardrobe did not update softcore outfit")
|
||||||
_expect(woman_slot.get("hardcore_clothing") == "fully nude", "Scene Wardrobe did not update hardcore clothing")
|
_expect(woman_slot.get("hardcore_clothing") == "fully nude", "Scene Wardrobe did not update hardcore clothing")
|
||||||
|
_expect(json.loads(scene).get("seed_trace", {}).get("wardrobe", {}).get("seed") == 9981, "Scene Wardrobe seed options did not write seed trace")
|
||||||
|
|
||||||
|
location_options = nodes["SxCPSceneLocationLayoutOptions"]().build(
|
||||||
|
"replace",
|
||||||
|
"mirror edge",
|
||||||
|
"soft curtain layer",
|
||||||
|
"repeating lamp reflections",
|
||||||
|
"private",
|
||||||
|
"private",
|
||||||
|
"warm mirror-room geometry",
|
||||||
|
)[0]
|
||||||
scene = nodes["SxCPSceneLocation"]().build(
|
scene = nodes["SxCPSceneLocation"]().build(
|
||||||
scene,
|
scene,
|
||||||
True,
|
True,
|
||||||
@@ -8894,10 +8945,26 @@ def smoke_node_scene_chain_registration() -> None:
|
|||||||
"custom_only",
|
"custom_only",
|
||||||
"quiet studio room with a large mirror",
|
"quiet studio room with a large mirror",
|
||||||
"",
|
"",
|
||||||
|
location_options=location_options,
|
||||||
)[0]
|
)[0]
|
||||||
scene = nodes["SxCPSceneSetDressing"]().build(scene, True, "mirror edge", "soft curtains", "small lamp", "")[0]
|
set_options = nodes["SxCPSceneSetDressingOptions"]().build("replace", "mirror edge", "soft curtains", "small lamp", "warm fabric texture", "")[0]
|
||||||
scene = nodes["SxCPSceneBlocking"]().build(scene, True, "standing", "woman near mirror", "man behind her", "")[0]
|
scene = nodes["SxCPSceneSetDressing"]().build(scene, True, "mirror edge", "soft curtains", "small lamp", "", set_options=set_options)[0]
|
||||||
scene = nodes["SxCPScenePerformance"]().build(scene, True, "fixed", 0.4, "controlled eye contact")[0]
|
blocking_options = nodes["SxCPSceneBlockingOptions"]().build(
|
||||||
|
"replace",
|
||||||
|
"standing",
|
||||||
|
"woman near mirror",
|
||||||
|
"man behind her",
|
||||||
|
"three_quarter",
|
||||||
|
"foreground",
|
||||||
|
"standing close",
|
||||||
|
"",
|
||||||
|
)[0]
|
||||||
|
scene = nodes["SxCPSceneBlocking"]().build(scene, True, "standing", "woman near mirror", "man behind her", "", blocking_options=blocking_options)[0]
|
||||||
|
action_options = nodes["SxCPSceneActionOptions"]().build("replace", "softcore", "softcore_tease", "no_change", "quiet pose transition")[0]
|
||||||
|
scene = nodes["SxCPSceneAction"]().build(scene, True, "regular", "no_change", "", action_options=action_options)[0]
|
||||||
|
performance_options = nodes["SxCPScenePerformanceOptions"]().build("replace", "enabled", "fixed", 0.4, "camera", "on_body", "posed", "controlled eye contact")[0]
|
||||||
|
scene = nodes["SxCPScenePerformance"]().build(scene, True, "fixed", 0.4, "controlled eye contact", performance_options=performance_options)[0]
|
||||||
|
camera_options = nodes["SxCPSceneCameraOptions"]().build("replace", "from_camera_config", True, "mirror-aware camera note")[0]
|
||||||
scene = nodes["SxCPSceneCamera"]().build(
|
scene = nodes["SxCPSceneCamera"]().build(
|
||||||
scene,
|
scene,
|
||||||
True,
|
True,
|
||||||
@@ -8911,9 +8978,12 @@ def smoke_node_scene_chain_registration() -> None:
|
|||||||
"strong",
|
"strong",
|
||||||
"compact",
|
"compact",
|
||||||
"",
|
"",
|
||||||
|
camera_options=camera_options,
|
||||||
)[0]
|
)[0]
|
||||||
scene = nodes["SxCPSceneComposition"]().build(scene, True, "replace", "no_outfit_check", "mirror-aware three-quarter frame", "")[0]
|
composition_options = nodes["SxCPSceneCompositionOptions"]().build("replace", "body", "three_quarter", "clear", "mirror-aware three-quarter frame")[0]
|
||||||
scene = nodes["SxCPSceneLighting"]().build(scene, True, "practical_lamps", "soft", "medium", "warm", "")[0]
|
scene = nodes["SxCPSceneComposition"]().build(scene, True, "replace", "no_outfit_check", "", "", composition_options=composition_options)[0]
|
||||||
|
lighting_options = nodes["SxCPSceneLightingOptions"]().build("replace", "practical_lamps", "soft", "medium", "warm", "evening", "")[0]
|
||||||
|
scene = nodes["SxCPSceneLighting"]().build(scene, True, "practical_lamps", "soft", "medium", "warm", "", lighting_options=lighting_options)[0]
|
||||||
|
|
||||||
output = nodes["SxCPSceneOutput"]().build(scene)
|
output = nodes["SxCPSceneOutput"]().build(scene)
|
||||||
_expect_text("node_scene_chain.prompt", output[0], 40)
|
_expect_text("node_scene_chain.prompt", output[0], 40)
|
||||||
@@ -8921,10 +8991,14 @@ def smoke_node_scene_chain_registration() -> None:
|
|||||||
row = json.loads(output[3])
|
row = json.loads(output[3])
|
||||||
_expect(row.get("scene_chain", {}).get("schema") == "sxcp_scene_v2", "Scene Output lost scene_chain metadata")
|
_expect(row.get("scene_chain", {}).get("schema") == "sxcp_scene_v2", "Scene Output lost scene_chain metadata")
|
||||||
|
|
||||||
|
branch_options = nodes["SxCPSceneBranchOptions"]().build("replace", "both", "same_creator_same_room", "hybrid", "shared branch note")[0]
|
||||||
|
branch_seed_options = nodes["SxCPSceneLayerSeedOptions"]().build("hardcore_branch", "fixed", 7799, "pose", "same_for_all_rows", "replace_layer")[0]
|
||||||
soft_scene, hard_scene, _branch_summary, _branch_metadata = nodes["SxCPSceneBranchPair"]().build(
|
soft_scene, hard_scene, _branch_summary, _branch_metadata = nodes["SxCPSceneBranchPair"]().build(
|
||||||
scene,
|
scene,
|
||||||
"same_creator_same_room",
|
"same_creator_same_room",
|
||||||
"hybrid",
|
"hybrid",
|
||||||
|
branch_options=branch_options,
|
||||||
|
seed_options=branch_seed_options,
|
||||||
)
|
)
|
||||||
soft_scene = nodes["SxCPSoftcoreBranchOptions"]().build(
|
soft_scene = nodes["SxCPSoftcoreBranchOptions"]().build(
|
||||||
soft_scene,
|
soft_scene,
|
||||||
@@ -8935,6 +9009,7 @@ def smoke_node_scene_chain_registration() -> None:
|
|||||||
"from_camera_config",
|
"from_camera_config",
|
||||||
"compact",
|
"compact",
|
||||||
"",
|
"",
|
||||||
|
branch_options=branch_options,
|
||||||
)[0]
|
)[0]
|
||||||
hard_scene = nodes["SxCPHardcoreBranchOptions"]().build(
|
hard_scene = nodes["SxCPHardcoreBranchOptions"]().build(
|
||||||
hard_scene,
|
hard_scene,
|
||||||
@@ -8949,6 +9024,8 @@ def smoke_node_scene_chain_registration() -> None:
|
|||||||
"compact",
|
"compact",
|
||||||
"balanced",
|
"balanced",
|
||||||
"",
|
"",
|
||||||
|
branch_options=branch_options,
|
||||||
|
seed_options=branch_seed_options,
|
||||||
)[0]
|
)[0]
|
||||||
pair_output = nodes["SxCPScenePairOutput"]().build(soft_scene, hard_scene)
|
pair_output = nodes["SxCPScenePairOutput"]().build(soft_scene, hard_scene)
|
||||||
_expect_text("node_scene_chain.softcore_prompt", pair_output[0], 40)
|
_expect_text("node_scene_chain.softcore_prompt", pair_output[0], 40)
|
||||||
@@ -8957,6 +9034,10 @@ def smoke_node_scene_chain_registration() -> None:
|
|||||||
_expect_pair(pair, "node_scene_chain_pair")
|
_expect_pair(pair, "node_scene_chain_pair")
|
||||||
_expect(pair.get("options", {}).get("hardcore_cast") == "couple", "Scene Pair Output lost hardcore branch options")
|
_expect(pair.get("options", {}).get("hardcore_cast") == "couple", "Scene Pair Output lost hardcore branch options")
|
||||||
_expect("scene_chain" in pair, "Scene Pair Output lost scene_chain metadata")
|
_expect("scene_chain" in pair, "Scene Pair Output lost scene_chain metadata")
|
||||||
|
_expect(
|
||||||
|
pair.get("scene_chain", {}).get("hardcore", {}).get("seed_trace", {}).get("hardcore.hardcore_branch", {}).get("seed") == 7799,
|
||||||
|
"Scene branch seed options did not write hardcore branch seed trace",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def smoke_node_builder_registration() -> None:
|
def smoke_node_builder_registration() -> None:
|
||||||
|
|||||||
Reference in New Issue
Block a user