Add files via upload

Updated randomizers, README, init.py
This commit is contained in:
tusharbhutt
2025-06-23 23:28:47 -06:00
committed by GitHub
parent 6a2a20728d
commit 84b4e42a4b
4 changed files with 233 additions and 133 deletions

View File

@@ -85,7 +85,7 @@ NODE_DISPLAY_NAME_MAPPINGS.update(TEXT_SWITCH_NAMES)
NODE_DISPLAY_NAME_MAPPINGS.update(TYPE_CONVERTER_NAMES)
# Version info
__version__ = "0.46"
__version__ = "1.2.0"
print(f"Endless Sea of Stars Custom Nodes v{__version__} loaded successfully!")
print("Nodes available under 'Endless 🌊✨' menu")

View File

@@ -1,6 +1,8 @@
Jun 23/23, V1.2.0: Added the Endless Pandemonium node, a black box that randomly and invisibly changes parameters on you. Put in ability to use 64 or 16 as the minimum steps for the dimensions in the Randomizer nodes, added CFG Guidance outputs for Flux. Fixed typos and added better credits in README. Some bug squishing.
Jun 22/25, V1.1.1: Minor typos and trying to align version numbers
Jun 21/25, V1.00: Blew it all up and started again
Jun 21/25, V1.0.0: Blew it all up and started again
Aug 19/24, V0.41: Fixed Image Saver node so it appears
@@ -61,5 +63,3 @@ Sep 15/23, V0.10: Added Six Input Number Widget, first release to GitHub
Sep 12/23, V0.05: Added Six Input Number String
Sep 08/23, V0.00: Basic Flow for Six Input Text Switch
\

View File

@@ -5,13 +5,13 @@ from .endless_randomizers import (
)
NODE_CLASS_MAPPINGS = {
"Randomzier_Mayhem": EndlessNode_Mayhem,
"Randomzier_Chaos": EndlessNode_Chaos,
# "Randomzier_Pandemonium": EndlessNode_Pandemonium,
"Randomizer_Mayhem": EndlessNode_Mayhem,
"Randomizer_Chaos": EndlessNode_Chaos,
"Randomizer_Pandemonium": EndlessNode_Pandemonium,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"Randomzier_Mayhem": "Mayhem Randomizer",
"Randomzier_Chaos": "Chaos Randomizer",
# "Randomzier_Pandemonium": "Pandemonium Randomizer",
"Randomizer_Mayhem": "Mayhem Randomizer",
"Randomizer_Chaos": "Chaos Randomizer",
"Randomizer_Pandemonium": "Pandemonium Randomizer",
}

View File

@@ -1,12 +1,7 @@
import random
# Safe samplers and schedulers for Flux (example set from your flux matrix)
SAFE_SAMPLERS = [
"DDIM", "Euler", "Euler a", "LMS", "Heun", "DPM2", "DPM2 a", "DPM++ 2S a", "DPM++ 2M", "DPM++ SDE"
]
SAFE_SCHEDULERS = [
"Default", "Scheduler A", "Scheduler B" # Replace with actual safe schedulers if known
]
def ensure_order(a, b):
return (a, b) if a <= b else (b, a)
class EndlessNode_Mayhem:
@classmethod
@@ -17,10 +12,14 @@ class EndlessNode_Mayhem:
"steps_max": ("INT", {"default": 40, "min": 1, "max": 150}),
"cfg_min": ("FLOAT", {"default": 6.0, "min": 1.0, "max": 20.0}),
"cfg_max": ("FLOAT", {"default": 12.0, "min": 1.0, "max": 20.0}),
"height_min": ("INT", {"default": 512, "min": 64, "max": 4096}),
"guidance_min": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 6.0}),
"guidance_max": ("FLOAT", {"default": 3.5, "min": 0.0, "max": 6.0}),
"height_min": ("INT", {"default": 512, "min": 256, "max": 4096}),
"height_max": ("INT", {"default": 768, "min": 256, "max": 4096}),
"width_min": ("INT", {"default": 512, "min": 64, "max": 4096}),
"width_min": ("INT", {"default": 512, "min": 256, "max": 4096}),
"width_max": ("INT", {"default": 768, "min": 256, "max": 4096}),
"flip_dimensions": ("BOOLEAN", {"default": True}),
"divisible_by_64": ("BOOLEAN", {"default": False}),
"seed_min": ("INT", {"default": 0, "min": 0, "max": 2**32 - 1}),
"seed_max": ("INT", {"default": 8675309, "min": 0, "max": 2**32 - 1}),
"seed": ("INT", {
@@ -31,27 +30,50 @@ class EndlessNode_Mayhem:
}
}
RETURN_TYPES = ("INT", "FLOAT", "INT", "INT", "INT")
RETURN_NAMES = ("steps", "cfg_scale", "height", "width", "seed")
FUNCTION = "randomize"
RETURN_TYPES = ("INT", "FLOAT", "FLOAT", "INT", "INT", "INT")
RETURN_NAMES = ("steps", "cfg_scale", "cfg_guidance", "height", "width", "seed")
FUNCTION = "randomize_with_flip"
CATEGORY = "Endless 🌊✨/Randomizers"
def randomize(self, steps_min, steps_max, cfg_min, cfg_max, height_min, height_max, width_min, width_max, seed_min, seed_max, seed):
def randomize_with_flip(self, steps_min, steps_max, cfg_min, cfg_max, guidance_min, guidance_max, height_min, height_max, width_min, width_max, flip_dimensions, divisible_by_64, seed_min, seed_max, seed):
# Use the seed to ensure reproducible randomness
random.seed(seed)
# Ensure dimensions are divisible by 16 and at least 256
height_min = max(256, (height_min // 16) * 16)
height_max = max(256, (height_max // 16) * 16)
width_min = max(256, (width_min // 16) * 16)
width_max = max(256, (width_max // 16) * 16)
# Set divisibility requirement
divisor = 64 if divisible_by_64 else 16
# Min and max sanity checks
steps_min, steps_max = ensure_order(steps_min, steps_max)
cfg_min, cfg_max = ensure_order(cfg_min, cfg_max)
guidance_min, guidance_max = ensure_order(guidance_min, guidance_max)
height_min, height_max = ensure_order(height_min, height_max)
width_min, width_max = ensure_order(width_min, width_max)
seed_min, seed_max = ensure_order(seed_min, seed_max)
# Ensure dimensions are divisible by divisor and at least 256
height_min = max(256, (height_min // divisor) * divisor)
height_max = max(256, (height_max // divisor) * divisor)
width_min = max(256, (width_min // divisor) * divisor)
width_max = max(256, (width_max // divisor) * divisor)
# Random values
steps = random.randint(steps_min, steps_max)
cfg_scale = round(random.uniform(cfg_min, cfg_max), 2)
height = random.randint(height_min // 16, height_max // 16) * 16
width = random.randint(width_min // 16, width_max // 16) * 16
cfg_guidance = round(random.uniform(guidance_min, guidance_max), 2)
# Pick values based on user-defined intent
height = random.randint(height_min // divisor, height_max // divisor) * divisor
width = random.randint(width_min // divisor, width_max // divisor) * divisor
# Flip output if requested
if flip_dimensions and random.random() < 0.5:
width, height = height, width
output_seed = random.randint(seed_min, seed_max)
return (steps, cfg_scale, height, width, output_seed)
return (steps, cfg_scale, cfg_guidance, height, width, output_seed)
class EndlessNode_Chaos:
@classmethod
@@ -62,10 +84,12 @@ class EndlessNode_Chaos:
"steps_max": ("INT", {"default": 40, "min": 1, "max": 150}),
"cfg_min": ("FLOAT", {"default": 6.0, "min": 1.0, "max": 20.0}),
"cfg_max": ("FLOAT", {"default": 12.0, "min": 1.0, "max": 20.0}),
"height_min": ("INT", {"default": 512, "min": 64, "max": 4096}),
"height_max": ("INT", {"default": 768, "min": 64, "max": 4096}),
"width_min": ("INT", {"default": 512, "min": 64, "max": 4096}),
"width_max": ("INT", {"default": 768, "min": 64, "max": 4096}),
"guidance_min": ("FLOAT", {"default": 1.0, "min": 0.0, "max": 6.0}),
"guidance_max": ("FLOAT", {"default": 3.5, "min": 0.0, "max": 6.0}),
"dimension_min": ("INT", {"default": 512, "min": 256, "max": 4096}),
"dimension_max": ("INT", {"default": 1024, "min": 256, "max": 4096}),
"orientation": (["portrait", "landscape", "square", "random"], {"default": "random"}),
"divisible_by_64": ("BOOLEAN", {"default": False}),
"seed_min": ("INT", {"default": 0, "min": 0, "max": 2**32 - 1}),
"seed_max": ("INT", {"default": 8675309, "min": 0, "max": 2**32 - 1}),
"seed": ("INT", {
@@ -76,58 +100,112 @@ class EndlessNode_Chaos:
}
}
RETURN_TYPES = ("INT", "FLOAT", "INT", "INT", "INT")
RETURN_NAMES = ("steps", "cfg_scale", "height", "width", "seed")
FUNCTION = "randomize_with_flip"
RETURN_TYPES = ("INT", "FLOAT", "FLOAT", "INT", "INT", "INT")
RETURN_NAMES = ("steps", "cfg_scale", "cfg_guidance", "height", "width", "seed")
FUNCTION = "randomize_aspect_ratio_chaos"
CATEGORY = "Endless 🌊✨/Randomizers"
def randomize_with_flip(self, steps_min, steps_max, cfg_min, cfg_max, height_min, height_max, width_min, width_max, seed_min, seed_max, seed):
def randomize_aspect_ratio_chaos(self, steps_min, steps_max, cfg_min, cfg_max, guidance_min, guidance_max, dimension_min, dimension_max, orientation, divisible_by_64, seed_min, seed_max, seed):
# Use the seed to ensure reproducible randomness
random.seed(seed)
# Ensure dimensions are divisible by 16 and at least 256
height_min = max(256, (height_min // 16) * 16)
height_max = max(256, (height_max // 16) * 16)
width_min = max(256, (width_min // 16) * 16)
width_max = max(256, (width_max // 16) * 16)
# Set divisibility requirement
divisor = 64 if divisible_by_64 else 16
# Min and max sanity checks
steps_min, steps_max = ensure_order(steps_min, steps_max)
cfg_min, cfg_max = ensure_order(cfg_min, cfg_max)
guidance_min, guidance_max = ensure_order(guidance_min, guidance_max)
dimension_min, dimension_max = ensure_order(dimension_min, dimension_max)
seed_min, seed_max = ensure_order(seed_min, seed_max)
# Ensure min/max dimensions are properly divisible
dimension_min = max(256, (dimension_min // divisor) * divisor)
dimension_max = max(256, (dimension_max // divisor) * divisor)
# Common aspect ratios (width:height)
aspect_ratios = [
(1, 1), # 1:1 Square
(4, 3), # 4:3 Classic
(3, 2), # 3:2 Classic photo
(16, 9), # 16:9 Widescreen
(5, 4), # 5:4
(5, 3), # 5:3
(7, 5), # 7:5
(8, 5), # 8:5
(192, 100), # 1.92:1 Instagram Stories
(21, 9), # 21:9 Ultrawide (2.33:1)
(9, 21), # 9:21 Ultra-tall mobile
(22, 10), # 2.2:1 70mm Cinema
(28, 10), # 2.8:1 Facebook Cover (approx)
(185, 100), # 1.85:1 Cinema
(239, 100), # 2.39:1 Anamorphic
]
# Filter aspect ratios based on orientation
if orientation == "square":
filtered_ratios = [(1, 1)]
elif orientation == "landscape":
filtered_ratios = [(w, h) for w, h in aspect_ratios if w > h]
elif orientation == "portrait":
filtered_ratios = [(h, w) for w, h in aspect_ratios if w > h] # Flip to portrait
filtered_ratios.append((1, 1)) # Include square
else: # random
# Include both orientations for non-square ratios
all_ratios = []
for w, h in aspect_ratios:
all_ratios.append((w, h)) # Landscape
if w != h: # Don't duplicate square
all_ratios.append((h, w)) # Portrait
filtered_ratios = all_ratios
# Find valid dimensions for each aspect ratio
valid_dimensions = []
for aspect_w, aspect_h in filtered_ratios:
# Try different scales to find dimensions within our bounds
for scale in range(1, 100): # Reasonable scale range
width = (aspect_w * scale * divisor) // divisor * divisor
height = (aspect_h * scale * divisor) // divisor * divisor
# Check if dimensions are within bounds
if (dimension_min <= width <= dimension_max and
dimension_min <= height <= dimension_max):
valid_dimensions.append((width, height))
# If we've exceeded max dimension, no point in larger scales
if width > dimension_max or height > dimension_max:
break
# Remove duplicates and ensure we have at least one option
valid_dimensions = list(set(valid_dimensions))
if not valid_dimensions:
# Fallback to square if no valid aspect ratios found
size = (dimension_min // divisor) * divisor
valid_dimensions = [(size, size)]
# Choose random dimensions
width, height = random.choice(valid_dimensions)
# Generate other random values
steps = random.randint(steps_min, steps_max)
cfg_scale = round(random.uniform(cfg_min, cfg_max), 2)
# Randomly flip height and width with 50% chance
if random.random() < 0.5:
height = random.randint(height_min // 16, height_max // 16) * 16
width = random.randint(width_min // 16, width_max // 16) * 16
else:
width = random.randint(height_min // 16, height_max // 16) * 16
height = random.randint(width_min // 16, width_max // 16) * 16
output_seed = random.randint(seed_min, seed_max)
return (steps, cfg_scale, height, width, output_seed)
cfg_guidance = round(random.uniform(guidance_min, guidance_max), 2)
return (steps, cfg_scale, cfg_guidance, height, width, output_seed)
class EndlessNode_Pandemonium:
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"steps_min": ("INT", {"default": 20, "min": 1, "max": 150}),
"steps_max": ("INT", {"default": 40, "min": 1, "max": 150}),
"cfg_min": ("FLOAT", {"default": 6.0, "min": 1.0, "max": 20.0}),
"cfg_max": ("FLOAT", {"default": 12.0, "min": 1.0, "max": 20.0}),
"height_min": ("INT", {"default": 512, "min": 64, "max": 4096}),
"height_max": ("INT", {"default": 768, "min": 64, "max": 4096}),
"width_min": ("INT", {"default": 512, "min": 64, "max": 4096}),
"width_max": ("INT", {"default": 768, "min": 64, "max": 4096}),
"seed_min": ("INT", {"default": 0, "min": 0, "max": 2**32-1}),
"seed_max": ("INT", {"default": 8675309, "min": 0, "max": 2**32 - 1}),
"samplers": ("STRING", {
"multiline": True,
"default": "euler\neuler_ancestral\nheun\nheunpp2\ndpm_2\ndpm_2_ancestral\nlms\ndpm_fast\ndpm_adaptive\ndpmpp_2s_ancestral\ndpmpp_sde\ndpmpp_sde_gpu\ndpmpp_2m\ndpmpp_2m_sde\ndpmpp_2m_sde_gpu\ndpmpp_3m_sde\ndpmpp_3m_sde_gpu\nddpm\nlcm\nddim\nuni_pc\nuni_pc_bh2"
}),
"schedulers": ("STRING", {
"multiline": True,
"default": "normal\nkarras\nexponential\nsgm_uniform\nsimple\nddim_uniform\nbeta"
}),
"divisible_by_64": ("BOOLEAN", {"default": False}),
"seed": ("INT", {
"default": 0,
"min": 0,
@@ -136,38 +214,60 @@ class EndlessNode_Pandemonium:
}
}
RETURN_TYPES = ("INT", "FLOAT", "INT", "INT", "INT", "STRING", "STRING")
RETURN_NAMES = ("steps", "cfg_scale", "height", "width", "seed", "sampler", "scheduler")
FUNCTION = "randomize_all"
RETURN_TYPES = ("INT", "FLOAT", "FLOAT", "INT", "INT", "INT")
RETURN_NAMES = ("steps", "cfg_scale", "cfg_guidance", "height", "width", "seed")
FUNCTION = "randomize_aspect_ratio_mayhem"
CATEGORY = "Endless 🌊✨/Randomizers"
def randomize_all(self, steps_min, steps_max, cfg_min, cfg_max, height_min, height_max, width_min, width_max, seed_min, seed_max, samplers, schedulers, seed):
# Use the seed to ensure reproducible randomness
def randomize_aspect_ratio_mayhem(self, divisible_by_64, seed):
import random
random.seed(seed)
# Ensure dimensions are divisible by 16 and at least 256
height_min = max(256, (height_min // 16) * 16)
height_max = max(256, (height_max // 16) * 16)
width_min = max(256, (width_min // 16) * 16)
width_max = max(256, (width_max // 16) * 16)
# Fixed internal config
dimension_min = 512
dimension_max = 1536
divisor = 64 if divisible_by_64 else 16
steps = random.randint(steps_min, steps_max)
cfg_scale = round(random.uniform(cfg_min, cfg_max), 2)
height = random.randint(height_min // 16, height_max // 16) * 16
width = random.randint(width_min // 16, width_max // 16) * 16
output_seed = random.randint(seed_min, seed_max)
dimension_min = max(256, (dimension_min // divisor) * divisor)
dimension_max = max(256, (dimension_max // divisor) * divisor)
# Parse samplers and schedulers from input strings
sampler_list = [s.strip() for s in samplers.splitlines() if s.strip()]
scheduler_list = [s.strip() for s in schedulers.splitlines() if s.strip()]
# All aspect ratios (landscape + portrait + square)
aspect_ratios = [
(1, 1),
(4, 3), (3, 2),
(16, 9), (9, 16),
(5, 4), (4, 5),
(5, 3), (3, 5),
(7, 5), (5, 7),
(8, 5), (5, 8),
(192, 100), (100, 192),
(21, 9), (9, 21),
(22, 10), (10, 22),
(28, 10), (10, 28),
(185, 100), (100, 185),
(239, 100), (100, 239)
]
# Fallback to defaults if lists are empty
if not sampler_list:
sampler_list = SAFE_SAMPLERS
if not scheduler_list:
scheduler_list = SAFE_SCHEDULERS
valid_dimensions = []
sampler = random.choice(sampler_list)
scheduler = random.choice(scheduler_list)
for aspect_w, aspect_h in aspect_ratios:
for scale in range(1, 100):
width = (aspect_w * scale * divisor) // divisor * divisor
height = (aspect_h * scale * divisor) // divisor * divisor
if dimension_min <= width <= dimension_max and dimension_min <= height <= dimension_max:
valid_dimensions.append((width, height))
if width > dimension_max or height > dimension_max:
break
if not valid_dimensions:
fallback = (dimension_min // divisor) * divisor
valid_dimensions = [(fallback, fallback)]
width, height = random.choice(valid_dimensions)
steps = random.randint(5, 60)
cfg_scale = round(random.uniform(0, 15), 2)
cfg_guidance = round(random.uniform(1, 4), 2)
output_seed = random.randint(0, seed)
return (steps, cfg_scale, cfg_guidance, height, width, output_seed)
return (steps, cfg_scale, height, width, output_seed, sampler, scheduler)