Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d1b774d7ce | ||
|
|
b4c965b1a5 | ||
|
|
b94ba237a1 | ||
|
|
a7d498a081 | ||
|
|
8fe532f2f7 | ||
|
|
4d67a6b4cc | ||
|
|
1ac972f912 | ||
|
|
aa26f4aae2 | ||
|
|
b78501d4e2 | ||
|
|
acdcb0032b | ||
|
|
ed31d7dd82 | ||
|
|
4ab36b4470 | ||
|
|
a22a2e9023 | ||
|
|
489c526404 | ||
|
|
c51e71aaf4 | ||
|
|
bd2cc15447 | ||
|
|
d71cb04f88 | ||
|
|
035b2c3003 | ||
|
|
dc9bb0ad48 | ||
|
|
5feda0fbab |
@@ -0,0 +1,24 @@
|
||||
name: Publish to Comfy registry
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- master
|
||||
paths:
|
||||
- "pyproject.toml"
|
||||
|
||||
jobs:
|
||||
publish-node:
|
||||
name: Publish Custom Node to registry
|
||||
runs-on: ubuntu-latest
|
||||
# if this is a forked repository. Skipping the workflow.
|
||||
if: github.event.repository.fork == false
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
- name: Publish Custom Node
|
||||
uses: Comfy-Org/publish-node-action@main
|
||||
with:
|
||||
## Add your own personal access token to your Github Repository secrets and reference it here.
|
||||
personal_access_token: ${{ secrets.REGISTRY_ACCESS_TOKEN }}
|
||||
@@ -83,6 +83,7 @@ coverage.xml
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
test.py
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024 taches-ai
|
||||
Copyright (c) 2024 Taches
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -1,108 +1,51 @@
|
||||
# ComfyUI Scene Composer
|
||||
|
||||
A collection of [ComfyUI](https://github.com/comfyanonymous/ComfyUI) nodes to create scenes with random procedural generation.
|
||||
|
||||

|
||||
|
||||
## Installation
|
||||
|
||||
Clone this repo in `custom_nodes`, in your ComfyUI folder.
|
||||
### Via ComfyUI
|
||||
|
||||
If you have [ComfyUI Manager](https://github.com/ltdrdata/ComfyUI-Manager) installed, you can simply import [`workflow.json`](workflow.json) or [`workflow.png`](workflow.png) in ComfyUI and click on "Install Missing Nodes".
|
||||
|
||||
Alternatively, you can install it via the [Comfy Registry](https://registry.comfy.org/publishers/taches/nodes/comfyui-scene-composer) using the [CLI](https://docs.comfy.org/comfy-cli/getting-started#install-cli).
|
||||
|
||||
```shell
|
||||
$ comfy node registry-install comfyui-scene-composer
|
||||
```
|
||||
|
||||
### Manually
|
||||
|
||||
Clone this repo in `custom_nodes` situated in your ComfyUI install folder.
|
||||
|
||||
```shell
|
||||
$ git clone https://github.com/taches/comfyui-scene-composer
|
||||
$ pip install -r requirements.txt
|
||||
```
|
||||
|
||||
## Nodes
|
||||
|
||||
### Scene
|
||||
|
||||
The Scene node generates a procedural random prompt as a string. The prompt follows the following structure:
|
||||
|
||||
| Component | Description |
|
||||
| --------------- | ------------------------------------------------------------- |
|
||||
| **C**omposition | The layout of the scene, cameras, number of protagonists, etc |
|
||||
| **A**ctions | Activites done by the character/protagonist(s) |
|
||||
| **C**haracter | Main character, focusing on body type and faces, etc |
|
||||
| **C**lothes | Include casual clothes, uniforms, swimsuits, underwear, etc |
|
||||
| **E**nvironment | The setting, including background, weather, time of day, etc |
|
||||
|
||||
You can define some aspects of the scene directly in the node. If you want to have more control over what's generated, you can override these components by passing a string as input. This work particularly well with the node components, which are explained just below.
|
||||
|
||||
### Components
|
||||
|
||||
Node components also generate a procedural random prompt as a string. It can be used to have better control over the generation of each concept. You can then pass it to the Scene node or even us it as standalone.
|
||||
|
||||
### Seed
|
||||
|
||||
Each node has its own seed. This way, you can alter the generation of each component independently without changing the whole scene. The scene seed is just there as a fallback if a component is not set in the optional input.
|
||||
|
||||
## Config files
|
||||
|
||||
You can configure components and other related concepts using the TOML files situated in the `config` folder.
|
||||
|
||||
Strings will output the chain of tags as it is. Lists will randomly take one tag
|
||||
|
||||
```toml
|
||||
tags = "foo, bar" # -> foo, bar
|
||||
tags = ["foo", "bar"] # -> bar
|
||||
```
|
||||
|
||||
### Weighted lists
|
||||
|
||||
You can change the distribution by assigning a `?weight` next to the tag. By default, every tag has a weight of 1.
|
||||
|
||||
```toml
|
||||
tags = ["foo?2", "bar", "baz"]
|
||||
```
|
||||
|
||||
In this example, `foo` has a 50% chance to be chosen over `bar` or `baz`. This is because its weight is 2x the sum of all weights:
|
||||
|
||||
$\cfrac{\text{foo}}{\text{foo+bar+baz}} = \cfrac{2}{2+1+1}=0.5$
|
||||
|
||||
You can of course add fractions to the weights to make it _less_ likely to be chosen.
|
||||
|
||||
```toml
|
||||
tags = ["foo?0.5", "bar", "baz"]
|
||||
```
|
||||
|
||||
In this example, `foo` has a 20% chance to be chosen over `bar` or `baz`.
|
||||
|
||||
### Probabilities and repetitions
|
||||
|
||||
Some notations inside config files allow to alter the generation:
|
||||
|
||||
- `probability` define how likely the group of tags will be retained
|
||||
- `repeat` define how many tags should be taken from a list with the key
|
||||
|
||||
You can do so by moving the string/list into a dictionary with the `tags` key.
|
||||
|
||||
```toml
|
||||
# Before
|
||||
[group]
|
||||
items = ["foo", "bar", "baz"]
|
||||
|
||||
# After
|
||||
[group.items]
|
||||
probability = 0.75
|
||||
repeat = 2
|
||||
tags = ["foo", "bar", "baz"]
|
||||
```
|
||||
|
||||
In this example, there is a 25% chance to ignore the tags. If it's not the case, 2 tags will be chosen from the list.
|
||||
## Usage
|
||||
|
||||
> [!NOTE]
|
||||
> You can also determine a range of tags to take from the list.<br>
|
||||
> For example: `repeat = [2,4]` will take between 2 and 4 tags
|
||||
> This is a basic guide to get you started. For more detailed information, please refer to the [wiki](https://github.com/mousse-taches/comfyui-scene-composer/wiki)
|
||||
|
||||
### Nested lists
|
||||
Add the `🎞️ Scene` node to your workflow. The output will be a prompt formatted as a string.
|
||||
You can directly pass it to a conditioning node and connect it to your sampler.
|
||||
|
||||
You can define a `list` that includes the name of nested elements. This way, you can set what concept is randomly chosen and how likely.
|
||||
The other nodes are scene components. You can use it as an optional input for the `🎞️ Scene` node, or directly as standalone.
|
||||
|
||||
```toml
|
||||
[group]
|
||||
list = ["foo:2", "bar"]
|
||||
foo = ["tag1", "tag2", "tag3"]
|
||||
bar = ["tag4", "tag5", "tag6"]
|
||||
baz = ["tag7", "tag8", "tag9"]
|
||||
```
|
||||
| Component nodes | Description |
|
||||
| --------------- | ------------------------------------------------------------- |
|
||||
| 📹 Composition | The layout of the scene, cameras, number of protagonists, etc |
|
||||
| 🎬 Action | Activities done by the character/protagonist(s) |
|
||||
| 👤 Character | Main character, focusing on body type and faces, etc |
|
||||
| 👕 Clothes | Include casual clothes, uniforms, swimsuits, underwear, etc |
|
||||
| ⛅️ Environment | The setting, including background, weather, time of day, etc |
|
||||
|
||||
In this example, `foo` tags are more likely to be chosen than `bar` tags. `baz` is not included in the `list` and will never be chosen.
|
||||
### Config files
|
||||
|
||||
You can customize the prompt generation for components by editing the corresponding TOML file in the `config` folder. Keep it mind that the config will be replace by the default when there's an update, so you might want to keep a backup.
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
||||
|
||||
+6
-6
@@ -1,9 +1,9 @@
|
||||
from .src.scene import Scene
|
||||
from .src.components.composition import Composition
|
||||
from .src.components.action import Action
|
||||
from .src.components.character.character import Character
|
||||
from .src.components.clothes import Clothes
|
||||
from .src.components.environment import Environment
|
||||
from .py.scene import Scene
|
||||
from .py.components.composition import Composition
|
||||
from .py.components.action import Action
|
||||
from .py.components.character.character import Character
|
||||
from .py.components.clothes import Clothes
|
||||
from .py.components.environment import Environment
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"🎞️ Scene": Scene,
|
||||
|
||||
+2
-2
@@ -9,8 +9,8 @@ insertions = ["vaginal", "anal"]
|
||||
|
||||
# Male
|
||||
hide_male = false
|
||||
penis_sizes = ["small?0.5", "", "large", "huge?0.5"]
|
||||
testicles_sizes = ["small?0.5", "", "large", "huge?0.5"]
|
||||
penis_sizes = ["small[0.5]", "", "large", "huge[0.5]"]
|
||||
testicles_sizes = ["small[0.5]", "", "large", "huge[0.5]"]
|
||||
|
||||
# Intensity (float number)
|
||||
sweat = 1.0
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# BODY
|
||||
[body.colors]
|
||||
probability = 0.4
|
||||
list = ["standard_colors", "special_colors?0.5"]
|
||||
standard_colors = ["dark?1.5", "pale"]
|
||||
list = ["standard_colors", "special_colors[0.5]"]
|
||||
standard_colors = ["dark[1.5]", "pale"]
|
||||
special_colors = ["black", "red", "green", "blue", "purple", "pink"]
|
||||
|
||||
[body.types]
|
||||
@@ -15,8 +15,8 @@ tags = [
|
||||
"muscular",
|
||||
"curvy",
|
||||
"plump",
|
||||
"chubby?0.2",
|
||||
"fat?0.1",
|
||||
"chubby[0.2]",
|
||||
"fat[0.1]",
|
||||
]
|
||||
|
||||
[body.breasts]
|
||||
@@ -25,7 +25,7 @@ sizes = [
|
||||
"small breasts",
|
||||
"medium breasts",
|
||||
"large breasts",
|
||||
"huge breasts?0.5",
|
||||
"huge breasts[0.5]",
|
||||
]
|
||||
|
||||
[body.breasts.nipples]
|
||||
@@ -36,7 +36,7 @@ tags = ["dark", "puffy"]
|
||||
[body.extras]
|
||||
probability = 0.75
|
||||
repeat = [1, 3]
|
||||
tags = ["freckles?2", "tattoos", "piercings", "scars?0.2"]
|
||||
tags = ["freckles[2]", "tattoos", "piercings", "scars[0.2]"]
|
||||
|
||||
# HAIR
|
||||
[hair]
|
||||
@@ -49,7 +49,7 @@ styles = ["ponytail", "bun", "braid", "pigtails"]
|
||||
appearances = ["curly", "straight", "wavy"]
|
||||
|
||||
[hair.colors]
|
||||
list = ["standard_colors", "special_colors?0.5"]
|
||||
list = ["standard_colors", "special_colors[0.5]"]
|
||||
standard_colors = ["black", "brown", "blonde", "ginger"]
|
||||
special_colors = [
|
||||
"red",
|
||||
@@ -65,7 +65,7 @@ special_colors = [
|
||||
|
||||
# EYES & EYEWEAR
|
||||
[eyes.colors]
|
||||
list = ["standard_colors", "special_colors?0.8"]
|
||||
list = ["standard_colors", "special_colors[0.8]"]
|
||||
standard_colors = ["black", "brown", "blue", "green"]
|
||||
special_colors = ["red", "yellow", "orange", "pink", "purple", "grey", "white"]
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
# State: how clothed the character is
|
||||
states = ["clothed", "underwear?0.3", "nude?0.1"]
|
||||
states = ["clothed", "underwear[0.3]", "nude[0.1]"]
|
||||
|
||||
# Types: if clothed, what type of clothing
|
||||
types = ["casual", "dress", "swimsuit", "uniform"]
|
||||
|
||||
+3
-3
@@ -102,9 +102,9 @@ function filterInputList(node, actWidget, actTypeWidget) {
|
||||
toggleWidget(node, actWidget, actTypeWidget.value !== "random");
|
||||
|
||||
// Filter the act list based on the selected act_type
|
||||
actWidget.options.values = actWidget.options.values
|
||||
.filter(act => act.startsWith(`${actTypeWidget.value}_`) || act == "random")
|
||||
.map(act => act.replace(`${actTypeWidget.value}_`, ""));
|
||||
actWidget.options.values = actWidget.options.values.filter(
|
||||
act => act.startsWith(`${actTypeWidget.value}_`) || act == "random"
|
||||
);
|
||||
|
||||
// Set the value to the first act in the list
|
||||
actWidget.value = actWidget.options.values[0];
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
import argparse
|
||||
import random
|
||||
from src.scene import Scene
|
||||
|
||||
|
||||
def main(seed, nsfw):
|
||||
|
||||
if not seed:
|
||||
seed = random.randint(0, 0xffffffffffffffff)
|
||||
|
||||
scene = Scene()
|
||||
scene.components["action"]["default"].INPUT_TYPES()
|
||||
output = scene.build_prompt(seed)
|
||||
|
||||
print(f"SEED: {seed}")
|
||||
print(f"TAGS: {output}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
parser = argparse.ArgumentParser(description="Simulate a scene")
|
||||
|
||||
parser.add_argument(
|
||||
"--seed", "-s",
|
||||
type=int,
|
||||
default=0,
|
||||
help="Seed for the node"
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--nsfw", "-n",
|
||||
type=bool,
|
||||
default=False,
|
||||
help="Whether the scene is NSFW"
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
main(args.seed, args.nsfw)
|
||||
@@ -69,7 +69,8 @@ class Action(Node):
|
||||
|
||||
gesture = self.select_tags(
|
||||
tags=data["gestures"],
|
||||
selected=gesture
|
||||
selected=gesture,
|
||||
seed=self.seed+1
|
||||
)
|
||||
|
||||
prompt = f"{position}, {gesture}"
|
||||
@@ -87,7 +88,8 @@ class Action(Node):
|
||||
|
||||
act = self.select_tags(
|
||||
tags=data["acts"][act_type],
|
||||
selected=act
|
||||
selected=act,
|
||||
seed=self.seed+1
|
||||
)
|
||||
|
||||
settings = self.apply_settings(data["settings"])
|
||||
@@ -4,19 +4,16 @@ from ..node import Node
|
||||
class Clothes(Node):
|
||||
|
||||
def __init__(self, seed=0, state="random", type="random"):
|
||||
super().__init__(seed, data_file="clothes.toml")
|
||||
self.state = state
|
||||
self.type = type
|
||||
super().__init__(seed, data_file="clothes.toml")
|
||||
|
||||
def build_prompt(self, seed):
|
||||
self.seed = seed
|
||||
prompt = ""
|
||||
|
||||
if self.state == "random":
|
||||
self.state = self.select_tags(self.data["states"])
|
||||
|
||||
if self.type == "random":
|
||||
self.type = self.select_tags(self.data["types"])
|
||||
self.state = self.select_tags(self.data["states"], selected=self.state)
|
||||
self.type = self.select_tags(self.data["types"], selected=self.type)
|
||||
|
||||
match self.state:
|
||||
case "clothed":
|
||||
@@ -37,13 +37,16 @@ class Node:
|
||||
def build_prompt(self):
|
||||
pass
|
||||
|
||||
def select_tags(self, tags, p=1, n=1, selected="random", recursive=True):
|
||||
def select_tags(self, tags, p=1, n=1,
|
||||
selected="random", recursive=True, seed=None):
|
||||
"""Return n tags from a string, list or dict
|
||||
p: probability of selecting the tags
|
||||
n: number of tags to select
|
||||
selected: fallback tag to select if not random
|
||||
recursive: go deeper randomly to select last children tags"""
|
||||
rng = np.random.default_rng(self.seed)
|
||||
if seed is None:
|
||||
seed = self.seed
|
||||
rng = np.random.default_rng(seed)
|
||||
|
||||
if selected != "random":
|
||||
return selected
|
||||
@@ -99,12 +102,14 @@ class Node:
|
||||
def parse_tag_distribution(tags):
|
||||
"""Choose tags randomly according to defined weights
|
||||
If none are defined, tag weight is 1
|
||||
Example: "foo?1.5, bar?0.5" -> 75% chance of foo, 25% chance of bar"""
|
||||
Example: "foo[1.5], bar[0.5]" -> 75% chance of foo, 25% chance of bar
|
||||
"""
|
||||
tag_names = []
|
||||
weights = []
|
||||
for tag in tags:
|
||||
if '?' in tag:
|
||||
tag_name, weight = tag.split('?')
|
||||
if '[' in tag and ']' in tag:
|
||||
tag_name, weight = tag.split('[')
|
||||
weight = weight.rstrip(']')
|
||||
tag_names.append(tag_name)
|
||||
weights.append(float(weight))
|
||||
else:
|
||||
@@ -127,8 +132,13 @@ class Node:
|
||||
@staticmethod
|
||||
def build_inputs_list(data):
|
||||
"""Build a list with a random option"""
|
||||
data = [tag.split('?')[0] for tag in data]
|
||||
inputs_list = ["random"] + data
|
||||
|
||||
inputs_list = ["random"]
|
||||
|
||||
for tag in data:
|
||||
if '[' in tag and ']' in tag:
|
||||
tag = tag.split('[')[0]
|
||||
inputs_list.append(tag)
|
||||
|
||||
return inputs_list
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
from .node import Node
|
||||
from .components.composition import Composition
|
||||
# from .components.action.action import Action
|
||||
from .components.action import Action
|
||||
from .components.character.character import Character
|
||||
from .components.clothes import Clothes
|
||||
@@ -22,7 +21,7 @@ class Scene(Node):
|
||||
},
|
||||
"action": {
|
||||
"default": Action(),
|
||||
"nsfw": True,
|
||||
"nsfw": False,
|
||||
"position": "random",
|
||||
"gesture": "random",
|
||||
"act_type": "random",
|
||||
@@ -63,6 +62,7 @@ class Scene(Node):
|
||||
return inputs
|
||||
|
||||
def build_prompt(self, seed, **kwargs):
|
||||
self.seed = seed
|
||||
components = self.components
|
||||
prompt = []
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
[project]
|
||||
name = "comfyui-scene-composer"
|
||||
description = "A collection of nodes to facilitate the creation of scenes in ComfyUI."
|
||||
version = "0.1.1"
|
||||
license = { file = "LICENSE" }
|
||||
dependencies = ["numpy==2.1.2", "PyYAML==6.0.2", "toml==0.10.2"]
|
||||
|
||||
[project.urls]
|
||||
Repository = "https://github.com/taches-ai/comfyui-scene-composer"
|
||||
# Used by Comfy Registry https://comfyregistry.org
|
||||
|
||||
[tool.comfy]
|
||||
PublisherId = "taches"
|
||||
DisplayName = "Scene Composer"
|
||||
Icon = ""
|
||||
+758
@@ -0,0 +1,758 @@
|
||||
{
|
||||
"last_node_id": 21,
|
||||
"last_link_id": 17,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 12,
|
||||
"type": "📹 Composition",
|
||||
"pos": {
|
||||
"0": 26,
|
||||
"1": 66
|
||||
},
|
||||
"size": {
|
||||
"0": 263,
|
||||
"1": 196
|
||||
},
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "STRING",
|
||||
"type": "STRING",
|
||||
"links": [
|
||||
10
|
||||
],
|
||||
"shape": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "📹 Composition"
|
||||
},
|
||||
"widgets_values": [
|
||||
"score_9, score_8_up, score_7_up, source_anime",
|
||||
"1girl",
|
||||
"random",
|
||||
"random",
|
||||
0,
|
||||
"fixed"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 19,
|
||||
"type": "🎬 Action",
|
||||
"pos": {
|
||||
"0": 30,
|
||||
"1": 314
|
||||
},
|
||||
"size": {
|
||||
"0": 261,
|
||||
"1": 154
|
||||
},
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "STRING",
|
||||
"type": "STRING",
|
||||
"links": [
|
||||
17
|
||||
],
|
||||
"shape": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "🎬 Action"
|
||||
},
|
||||
"widgets_values": [
|
||||
false,
|
||||
"random",
|
||||
"random",
|
||||
"intercourses",
|
||||
"random",
|
||||
0,
|
||||
"fixed"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 13,
|
||||
"type": "👕 Clothes",
|
||||
"pos": {
|
||||
"0": 30,
|
||||
"1": 650
|
||||
},
|
||||
"size": {
|
||||
"0": 263,
|
||||
"1": 82
|
||||
},
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "STRING",
|
||||
"type": "STRING",
|
||||
"links": [
|
||||
13
|
||||
],
|
||||
"slot_index": 0,
|
||||
"shape": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "👕 Clothes"
|
||||
},
|
||||
"widgets_values": [
|
||||
0,
|
||||
"fixed"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"type": "⛅️ Environment",
|
||||
"pos": {
|
||||
"0": 30,
|
||||
"1": 780
|
||||
},
|
||||
"size": {
|
||||
"0": 261,
|
||||
"1": 82
|
||||
},
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "STRING",
|
||||
"type": "STRING",
|
||||
"links": [
|
||||
14
|
||||
],
|
||||
"slot_index": 0,
|
||||
"shape": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "⛅️ Environment"
|
||||
},
|
||||
"widgets_values": [
|
||||
0,
|
||||
"fixed"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"type": "KSampler",
|
||||
"pos": {
|
||||
"0": 931,
|
||||
"1": 418
|
||||
},
|
||||
"size": {
|
||||
"0": 267,
|
||||
"1": 262
|
||||
},
|
||||
"flags": {},
|
||||
"order": 12,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "model",
|
||||
"type": "MODEL",
|
||||
"link": 1
|
||||
},
|
||||
{
|
||||
"name": "positive",
|
||||
"type": "CONDITIONING",
|
||||
"link": 4
|
||||
},
|
||||
{
|
||||
"name": "negative",
|
||||
"type": "CONDITIONING",
|
||||
"link": 6
|
||||
},
|
||||
{
|
||||
"name": "latent_image",
|
||||
"type": "LATENT",
|
||||
"link": 2
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"links": [
|
||||
7
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "KSampler"
|
||||
},
|
||||
"widgets_values": [
|
||||
0,
|
||||
"fixed",
|
||||
25,
|
||||
7,
|
||||
"euler",
|
||||
"normal",
|
||||
0.9500000000000001
|
||||
],
|
||||
"color": "#223",
|
||||
"bgcolor": "#335"
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"type": "VAEDecode",
|
||||
"pos": {
|
||||
"0": 1211,
|
||||
"1": 360
|
||||
},
|
||||
"size": {
|
||||
"0": 210,
|
||||
"1": 46
|
||||
},
|
||||
"flags": {
|
||||
"collapsed": true
|
||||
},
|
||||
"order": 13,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "samples",
|
||||
"type": "LATENT",
|
||||
"link": 7
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": 8
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"links": [
|
||||
9
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VAEDecode"
|
||||
},
|
||||
"color": "#233",
|
||||
"bgcolor": "#355"
|
||||
},
|
||||
{
|
||||
"id": 20,
|
||||
"type": "Note",
|
||||
"pos": {
|
||||
"0": 366,
|
||||
"1": 62
|
||||
},
|
||||
"size": [
|
||||
366,
|
||||
205
|
||||
],
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [],
|
||||
"title": "📖 README",
|
||||
"properties": {},
|
||||
"widgets_values": [
|
||||
"Here's a simple workflow to test the Scene Composer custom nodes.\n\nJust queue a prompt: the 🎞️ Scene will be able to randomly generate an image for you!\n\nHere, optional components are connected to the 🎞️ Scene. That let you have more control over the generation of the scene.\n\nFor example, just change the seed of the 👤 Character. The whole scene stay the same, but the character has changed."
|
||||
],
|
||||
"color": "#432",
|
||||
"bgcolor": "#653"
|
||||
},
|
||||
{
|
||||
"id": 21,
|
||||
"type": "Note",
|
||||
"pos": {
|
||||
"0": 763,
|
||||
"1": 61
|
||||
},
|
||||
"size": [
|
||||
458,
|
||||
208
|
||||
],
|
||||
"flags": {},
|
||||
"order": 5,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [],
|
||||
"title": "🔗 Links",
|
||||
"properties": {},
|
||||
"widgets_values": [
|
||||
"For more info, check out these links:\n\nSource code: https://github.com/mus-taches/comfyui-scene-composer\nWiki: https://github.com/mus-taches/comfyui-scene-composer/wiki\nRoadmap: https://github.com/users/mousse-taches/projects/2/"
|
||||
],
|
||||
"color": "#222",
|
||||
"bgcolor": "#000"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"type": "EmptyLatentImage",
|
||||
"pos": {
|
||||
"0": 681,
|
||||
"1": 699
|
||||
},
|
||||
"size": {
|
||||
"0": 210,
|
||||
"1": 106
|
||||
},
|
||||
"flags": {},
|
||||
"order": 6,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"links": [
|
||||
2
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "EmptyLatentImage"
|
||||
},
|
||||
"widgets_values": [
|
||||
1024,
|
||||
1024,
|
||||
1
|
||||
],
|
||||
"color": "#323",
|
||||
"bgcolor": "#535"
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": {
|
||||
"0": 685,
|
||||
"1": 533
|
||||
},
|
||||
"size": {
|
||||
"0": 210,
|
||||
"1": 117
|
||||
},
|
||||
"flags": {},
|
||||
"order": 9,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 5
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"links": [
|
||||
6
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"title": "Negative",
|
||||
"properties": {
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
"score_6, score_5, score_4"
|
||||
],
|
||||
"color": "#322",
|
||||
"bgcolor": "#533"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": {
|
||||
"0": 791,
|
||||
"1": 490
|
||||
},
|
||||
"size": {
|
||||
"0": 210,
|
||||
"1": 54
|
||||
},
|
||||
"flags": {
|
||||
"collapsed": true
|
||||
},
|
||||
"order": 11,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 3
|
||||
},
|
||||
{
|
||||
"name": "text",
|
||||
"type": "STRING",
|
||||
"link": 15,
|
||||
"widget": {
|
||||
"name": "text"
|
||||
}
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"links": [
|
||||
4
|
||||
],
|
||||
"slot_index": 0
|
||||
}
|
||||
],
|
||||
"title": "Positive",
|
||||
"properties": {
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
"beautiful scenery nature glass bottle landscape, , purple galaxy bottle,"
|
||||
],
|
||||
"color": "#232",
|
||||
"bgcolor": "#353"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"type": "CheckpointLoaderSimple",
|
||||
"pos": {
|
||||
"0": 365,
|
||||
"1": 313
|
||||
},
|
||||
"size": [
|
||||
312,
|
||||
98
|
||||
],
|
||||
"flags": {},
|
||||
"order": 7,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "MODEL",
|
||||
"type": "MODEL",
|
||||
"links": [
|
||||
1
|
||||
],
|
||||
"slot_index": 0
|
||||
},
|
||||
{
|
||||
"name": "CLIP",
|
||||
"type": "CLIP",
|
||||
"links": [
|
||||
3,
|
||||
5
|
||||
],
|
||||
"slot_index": 1
|
||||
},
|
||||
{
|
||||
"name": "VAE",
|
||||
"type": "VAE",
|
||||
"links": [
|
||||
8
|
||||
],
|
||||
"slot_index": 2
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CheckpointLoaderSimple"
|
||||
},
|
||||
"widgets_values": [
|
||||
"tponyai.safetensors"
|
||||
],
|
||||
"color": "#332922",
|
||||
"bgcolor": "#593930"
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"type": "🎞️ Scene",
|
||||
"pos": {
|
||||
"0": 363,
|
||||
"1": 462
|
||||
},
|
||||
"size": [
|
||||
274,
|
||||
162
|
||||
],
|
||||
"flags": {},
|
||||
"order": 10,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "composition",
|
||||
"type": "STRING",
|
||||
"link": 10,
|
||||
"widget": {
|
||||
"name": "composition"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "action",
|
||||
"type": "STRING",
|
||||
"link": 17,
|
||||
"widget": {
|
||||
"name": "action"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "character",
|
||||
"type": "STRING",
|
||||
"link": 12,
|
||||
"widget": {
|
||||
"name": "character"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "clothes",
|
||||
"type": "STRING",
|
||||
"link": 13,
|
||||
"widget": {
|
||||
"name": "clothes"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "environment",
|
||||
"type": "STRING",
|
||||
"link": 14,
|
||||
"widget": {
|
||||
"name": "environment"
|
||||
}
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "STRING",
|
||||
"type": "STRING",
|
||||
"links": [
|
||||
15
|
||||
],
|
||||
"slot_index": 0,
|
||||
"shape": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "🎞️ Scene"
|
||||
},
|
||||
"widgets_values": [
|
||||
1,
|
||||
"fixed",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"type": "SaveImage",
|
||||
"pos": {
|
||||
"0": 1231,
|
||||
"1": 408
|
||||
},
|
||||
"size": {
|
||||
"0": 428.97259521484375,
|
||||
"1": 496.5888366699219
|
||||
},
|
||||
"flags": {},
|
||||
"order": 14,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 9
|
||||
}
|
||||
],
|
||||
"outputs": [],
|
||||
"properties": {},
|
||||
"widgets_values": [
|
||||
"ComfyUI"
|
||||
],
|
||||
"color": "#233",
|
||||
"bgcolor": "#355"
|
||||
},
|
||||
{
|
||||
"id": 15,
|
||||
"type": "👤 Character",
|
||||
"pos": {
|
||||
"0": 30,
|
||||
"1": 520
|
||||
},
|
||||
"size": {
|
||||
"0": 262,
|
||||
"1": 82
|
||||
},
|
||||
"flags": {},
|
||||
"order": 8,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "STRING",
|
||||
"type": "STRING",
|
||||
"links": [
|
||||
12
|
||||
],
|
||||
"slot_index": 0,
|
||||
"shape": 3
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "👤 Character"
|
||||
},
|
||||
"widgets_values": [
|
||||
0,
|
||||
"fixed"
|
||||
]
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[
|
||||
1,
|
||||
4,
|
||||
0,
|
||||
3,
|
||||
0,
|
||||
"MODEL"
|
||||
],
|
||||
[
|
||||
2,
|
||||
5,
|
||||
0,
|
||||
3,
|
||||
3,
|
||||
"LATENT"
|
||||
],
|
||||
[
|
||||
3,
|
||||
4,
|
||||
1,
|
||||
6,
|
||||
0,
|
||||
"CLIP"
|
||||
],
|
||||
[
|
||||
4,
|
||||
6,
|
||||
0,
|
||||
3,
|
||||
1,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
5,
|
||||
4,
|
||||
1,
|
||||
7,
|
||||
0,
|
||||
"CLIP"
|
||||
],
|
||||
[
|
||||
6,
|
||||
7,
|
||||
0,
|
||||
3,
|
||||
2,
|
||||
"CONDITIONING"
|
||||
],
|
||||
[
|
||||
7,
|
||||
3,
|
||||
0,
|
||||
8,
|
||||
0,
|
||||
"LATENT"
|
||||
],
|
||||
[
|
||||
8,
|
||||
4,
|
||||
2,
|
||||
8,
|
||||
1,
|
||||
"VAE"
|
||||
],
|
||||
[
|
||||
9,
|
||||
8,
|
||||
0,
|
||||
9,
|
||||
0,
|
||||
"IMAGE"
|
||||
],
|
||||
[
|
||||
10,
|
||||
12,
|
||||
0,
|
||||
11,
|
||||
0,
|
||||
"STRING"
|
||||
],
|
||||
[
|
||||
12,
|
||||
15,
|
||||
0,
|
||||
11,
|
||||
2,
|
||||
"STRING"
|
||||
],
|
||||
[
|
||||
13,
|
||||
13,
|
||||
0,
|
||||
11,
|
||||
3,
|
||||
"STRING"
|
||||
],
|
||||
[
|
||||
14,
|
||||
10,
|
||||
0,
|
||||
11,
|
||||
4,
|
||||
"STRING"
|
||||
],
|
||||
[
|
||||
15,
|
||||
11,
|
||||
0,
|
||||
6,
|
||||
1,
|
||||
"STRING"
|
||||
],
|
||||
[
|
||||
17,
|
||||
19,
|
||||
0,
|
||||
11,
|
||||
1,
|
||||
"STRING"
|
||||
]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {
|
||||
"ds": {
|
||||
"scale": 1,
|
||||
"offset": [
|
||||
0,
|
||||
1
|
||||
]
|
||||
}
|
||||
},
|
||||
"version": 0.4
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 322 KiB |
Reference in New Issue
Block a user