commit 97ebe8f8deb654a708779bbbf17d58987adf2ef7 Author: diSty Date: Fri Mar 8 11:19:13 2024 +0200 first commit diff --git a/FrameMaker.py b/FrameMaker.py new file mode 100644 index 0000000..c2d015b --- /dev/null +++ b/FrameMaker.py @@ -0,0 +1,384 @@ +import numpy as np +import torch +from PIL import Image + +# FrameMaker 0.1.0 by diSty + +class FrameMaker: + @classmethod + def INPUT_TYPES(cls): + return { + 'required': { + 'subject_image': ('IMAGE',), + 'frame_count': ('INT', {'default': 4}), + "invert_alpha": (['true','false'], {"default": 'false'}), + "movement_presets": (movement,{"default": 'left to center',}), + 'movement_presets_distance': ('INT', {'default': 50, 'min': -10000, 'max': 10000}), + "movement_direction": (['None','front', 'back'],{"default": 'back',}), + 'x_pos_start': ('INT', {'default': 0, 'min': -10000, 'max': 10000}), + 'x_pos_end': ('INT', {'default': 0, 'min': -10000, 'max': 10000}), + 'y_pos_start': ('INT', {'default': 0, 'min': -10000, 'max': 10000}), + 'y_pos_end': ('INT', {'default': 0, 'min': -10000, 'max': 10000}), + 'scale_start': ('FLOAT', {'default': 1, 'min': 0.05, 'step': 0.05, 'max': 10}), + 'scale_end': ('FLOAT', {'default': 1, 'min': 0.05, 'step': 0.05, 'max': 10}), + "scale_anchor_point": (['center','top center', 'bottom center', 'top left', 'top right', 'bottom left', 'bottom right'],), + }, + "optional": { + "subject_alpha": ("MASK",), + 'bg1': ('IMAGE',), + 'bg2': ('IMAGE',), + 'bg3': ('IMAGE',), + 'bg4': ('IMAGE',), + 'frames': ('IMAGE',), + "resize_frame_input": (['true','false'], {"default": 'true'}), + 'frame_input_width': ('INT', {'default': 768, 'min': 16,'step': 16, 'max': 8192}), + 'frame_input_height': ('INT', {'default': 768, 'min': 16,'step': 16, 'max': 8192}), + "resize_frame_output": (['true','false'], {"default": 'false'}), + 'frame_output_width': ('INT', {'default': 512, 'min': 16,'step': 16, 'max': 8192}), + 'frame_output_height': ('INT', {'default': 512, 'min': 16,'step': 16, 'max': 8192}), + "invert_order": (['true','false'], {"default": 'false'}), + # "limit_frames": (['true','false'], {"default": 'false'}), + # 'limit_frames_count': ('INT', {'default': 4, 'min': 1,'step': 1, 'max': 10000}), + # 'limit_frames_index': ('INT', {'default': 1, 'min': 1,'step': 1, 'max': 10000}), + } + } + + RETURN_TYPES = ('IMAGE','IMAGE','INT', 'INT', 'INT',) + RETURN_NAMES = ('frames','subject_image', 'width', 'height','frame_count',) + FUNCTION = 'process_frames' + CATEGORY = '🅓 diSty/FrameMaker' + + def process_frames(self, subject_image, frame_count,invert_alpha,movement_presets,movement_presets_distance,movement_direction, + x_pos_start, x_pos_end, y_pos_start, y_pos_end, scale_start, scale_end, scale_anchor_point, + subject_alpha=None,bg1=None, bg2=None, bg3=None, bg4=None,frames=None,width=0, height=0,resize_frame_input=0, frame_input_width=0, + frame_input_height=0,resize_frame_output=None, frame_output_width=0,frame_output_height=0,invert_order='false' + # , **kwargs + ): + + if subject_alpha is not None: + if invert_alpha == 'true': + subject_alpha = 1.0 - subject_alpha + subject_image = join_image_with_alpha(subject_image, subject_alpha) + + foreground_image_pil = tensor2pil(subject_image) + backgrounds = [bg1, bg2, bg3, bg4] + backgrounds = [b for b in backgrounds if b is not None] + + if frames is not None: + backgrounds = [] + for i in range(frames.shape[0]): + frame_tensor = frames[i] + backgrounds.append(frame_tensor) + + if resize_frame_input == 'true': + foreground_image_pil = foreground_image_pil.resize((frame_input_width, frame_input_height), Image.Resampling.LANCZOS) + width = frame_input_width + height = frame_input_height + + resized_backgrounds_pil = [] + for bg_tensor in backgrounds: + bg_pil = tensor2pil(bg_tensor) + resized_bg_pil = bg_pil.resize((frame_input_width, frame_input_height), Image.Resampling.LANCZOS) + resized_backgrounds_pil.append(resized_bg_pil) + + movement_map = movement_map_f(movement_presets_distance) + + if movement_presets != 'None' and movement_presets in movement_map: + preset = movement_map[movement_presets] + x_pos_start = preset['x_start'] + x_pos_end = preset['x_end'] + y_pos_start = preset['y_start'] + y_pos_end = preset['y_end'] + + x_pos_start_pix = x_pos_start * foreground_image_pil.width / 100 + x_pos_end_pix = x_pos_end * foreground_image_pil.width / 100 + y_pos_start_pix = y_pos_start * foreground_image_pil.height / 100 + y_pos_end_pix = y_pos_end * foreground_image_pil.height / 100 + + if movement_direction != 'None': + if movement_direction == 'front': + scale_start = .3 + scale_end = 1.3 + if movement_direction == 'back': + scale_start = 1.3 + scale_end = .3 + + x_step = (x_pos_end_pix - x_pos_start_pix) / (frame_count - 1) + y_step = (y_pos_end_pix - y_pos_start_pix) / (frame_count - 1) + scale_step = (scale_end - scale_start) / (frame_count - 1) + + result_images = [] + for frame in range(frame_count): + if resize_frame_input == 'true': + background_image_pil = resized_backgrounds_pil[frame % len(resized_backgrounds_pil)] + else: + background_image_pil = tensor2pil(backgrounds[frame % len(backgrounds)]) + + scale = scale_start + frame * scale_step + scaled_width = int(foreground_image_pil.width * scale) + scaled_height = int(foreground_image_pil.height * scale) + + foreground_resized = foreground_image_pil.resize((scaled_width, scaled_height), Image.Resampling.LANCZOS) + + x_pos = x_pos_start_pix + frame * x_step + y_pos = y_pos_start_pix + frame * y_step + + width_diff = (scaled_width - foreground_image_pil.width) + height_diff = (scaled_height - foreground_image_pil.height) + + if 'center' in scale_anchor_point.lower(): + x_pos -= width_diff // 2 + if scale_anchor_point.lower() == 'center': + y_pos -= height_diff // 2 + elif 'bottom' in scale_anchor_point.lower(): + y_pos -= height_diff + if 'right' in scale_anchor_point.lower(): + x_pos -= width_diff + frame_image = background_image_pil.copy() + if foreground_resized.mode != 'RGBA': + foreground_resized = foreground_resized.convert('RGBA') + + frame_image.paste(foreground_resized, (int(x_pos), int(y_pos)), foreground_resized) + + if resize_frame_output == 'true': + frame_image = frame_image.resize((frame_output_width, frame_output_height), Image.Resampling.LANCZOS) + width = frame_output_width + height = frame_output_height + result_images.append(pil2tensor(frame_image)) + + batch = torch.cat(result_images, dim=0) + if invert_order == 'true': + batch = batch.flip(dims=[0]) + + return (batch,) + (subject_image,) + (width,) + (height,) + (frame_count,) + +class FrameMakerBatch: + @classmethod + def INPUT_TYPES(cls): + return { + 'required': { + 'frames': ('IMAGE',), + 'subject_image': ('IMAGE',), + 'frame_count': ('INT', {'default': 4}), + "invert_alpha": (['true','false'], {"default": 'false'}), + "movement_presets": (movement,{"default": 'left to center',}), + 'movement_presets_distance': ('INT', {'default': 50, 'min': -10000, 'max': 10000}), + "movement_direction": (['None','front', 'back'],{"default": 'back',}), + 'x_pos_start': ('INT', {'default': 0, 'min': -10000, 'max': 10000}), + 'x_pos_end': ('INT', {'default': 0, 'min': -10000, 'max': 10000}), + 'y_pos_start': ('INT', {'default': 0, 'min': -10000, 'max': 10000}), + 'y_pos_end': ('INT', {'default': 0, 'min': -10000, 'max': 10000}), + 'scale_start': ('FLOAT', {'default': 1, 'min': 0.05, 'step': 0.05, 'max': 10}), + 'scale_end': ('FLOAT', {'default': 1, 'min': 0.05, 'step': 0.05, 'max': 10}), + "scale_anchor_point": (['center','top center', 'bottom center', 'top left', 'top right', 'bottom left', 'bottom right'],), + }, + "optional": { + "subject_alpha": ("MASK",), + "resize_frame_input": (['true','false'], {"default": 'true'}), + 'frame_input_width': ('INT', {'default': 768, 'min': 16,'step': 16, 'max': 8192}), + 'frame_input_height': ('INT', {'default': 768, 'min': 16,'step': 16, 'max': 8192}), + "resize_frame_output": (['true','false'], {"default": 'false'}), + 'frame_output_width': ('INT', {'default': 512, 'min': 16,'step': 16, 'max': 8192}), + 'frame_output_height': ('INT', {'default': 512, 'min': 16,'step': 16, 'max': 8192}), + "invert_order": (['true','false'], {"default": 'false'}), + } + } + + RETURN_TYPES = ('IMAGE','IMAGE','INT', 'INT', 'INT',) + RETURN_NAMES = ('frames','subject_image', 'width', 'height','frame_count',) + FUNCTION = 'process_frames' + CATEGORY = '🅓 diSty/FrameMaker' + + def process_frames(self,frames,subject_image, frame_count,invert_alpha,movement_presets,movement_presets_distance,movement_direction, + x_pos_start, x_pos_end, y_pos_start, y_pos_end, scale_start, scale_end, scale_anchor_point, + subject_alpha=None,width=0, height=0,resize_frame_input=0, frame_input_width=0, + frame_input_height=0,resize_frame_output=None, frame_output_width=0,frame_output_height=0,invert_order='false'): + + + if subject_alpha is not None: + if invert_alpha == 'true': + subject_alpha = 1.0 - subject_alpha + subject_image = join_image_with_alpha(subject_image, subject_alpha) + + foreground_image_pil = tensor2pil(subject_image) + + if frames is not None: + backgrounds = [] + for i in range(frames.shape[0]): + frame_tensor = frames[i] + backgrounds.append(frame_tensor) + + if resize_frame_input == 'true': + foreground_image_pil = foreground_image_pil.resize((frame_input_width, frame_input_height), Image.Resampling.LANCZOS) + width = frame_input_width + height = frame_input_height + + resized_backgrounds_pil = [] + for bg_tensor in backgrounds: + bg_pil = tensor2pil(bg_tensor) + resized_bg_pil = bg_pil.resize((frame_input_width, frame_input_height), Image.Resampling.LANCZOS) + resized_backgrounds_pil.append(resized_bg_pil) + + movement_map = movement_map_f(movement_presets_distance) + + if movement_presets != 'None' and movement_presets in movement_map: + preset = movement_map[movement_presets] + x_pos_start = preset['x_start'] + x_pos_end = preset['x_end'] + y_pos_start = preset['y_start'] + y_pos_end = preset['y_end'] + + + x_pos_start_pix = x_pos_start * foreground_image_pil.width / 100 + x_pos_end_pix = x_pos_end * foreground_image_pil.width / 100 + y_pos_start_pix = y_pos_start * foreground_image_pil.height / 100 + y_pos_end_pix = y_pos_end * foreground_image_pil.height / 100 + + if movement_direction != 'None': + if movement_direction == 'front': + scale_start = .3 + scale_end = 1.3 + if movement_direction == 'back': + scale_start = 1.3 + scale_end = .3 + + x_step = (x_pos_end_pix - x_pos_start_pix) / (frame_count - 1) + y_step = (y_pos_end_pix - y_pos_start_pix) / (frame_count - 1) + scale_step = (scale_end - scale_start) / (frame_count - 1) + + result_images = [] + for frame in range(frame_count): + if resize_frame_input == 'true': + background_image_pil = resized_backgrounds_pil[frame % len(resized_backgrounds_pil)] + else: + background_image_pil = tensor2pil(backgrounds[frame % len(backgrounds)]) + + scale = scale_start + frame * scale_step + scaled_width = int(foreground_image_pil.width * scale) + scaled_height = int(foreground_image_pil.height * scale) + + foreground_resized = foreground_image_pil.resize((scaled_width, scaled_height), Image.Resampling.LANCZOS) + + x_pos = x_pos_start_pix + frame * x_step + y_pos = y_pos_start_pix + frame * y_step + + width_diff = (scaled_width - foreground_image_pil.width) + height_diff = (scaled_height - foreground_image_pil.height) + + if 'center' in scale_anchor_point.lower(): + x_pos -= width_diff // 2 + + if scale_anchor_point.lower() == 'center': + y_pos -= height_diff // 2 + elif 'bottom' in scale_anchor_point.lower(): + y_pos -= height_diff + if 'right' in scale_anchor_point.lower(): + x_pos -= width_diff + frame_image = background_image_pil.copy() + if foreground_resized.mode != 'RGBA': + foreground_resized = foreground_resized.convert('RGBA') + + frame_image.paste(foreground_resized, (int(x_pos), int(y_pos)), foreground_resized) + + if resize_frame_output == 'true': + frame_image = frame_image.resize((frame_output_width, frame_output_height), Image.Resampling.LANCZOS) + width = frame_output_width + height = frame_output_height + result_images.append(pil2tensor(frame_image)) + + batch = torch.cat(result_images, dim=0) + if invert_order == 'true': + batch = batch.flip(dims=[0]) + + return (batch,) + (subject_image,) + (width,) + (height,) + (frame_count,) + +NODE_CLASS_MAPPINGS = { + "FrameMaker": FrameMaker, + "FrameMakerBatch": FrameMakerBatch +} + +NODE_DISPLAY_NAME_MAPPINGS = { + "FrameMaker": f"🅓 Frame Maker ", + "FrameMakerBatch": f"🅓 Frame Maker Batch" +} + +def tensor2pil(image): + return Image.fromarray(np.clip(255. * image.cpu().numpy().squeeze(), 0, 255).astype(np.uint8)) + +def pil2tensor(image): + return torch.from_numpy(np.array(image).astype(np.float32) / 255.0).unsqueeze(0) + +def resize_mask(mask, shape): + return torch.nn.functional.interpolate(mask.reshape((-1, 1, mask.shape[-2], mask.shape[-1])), size=(shape[0], shape[1]), mode="bilinear").squeeze(1) + +def join_image_with_alpha(image: torch.Tensor, alpha: torch.Tensor): + batch_size = min(len(image), len(alpha)) + out_images = [] + + alpha = 1.0 - resize_mask(alpha, image.shape[1:]) + for i in range(batch_size): + out_images.append(torch.cat((image[i][:,:,:3], alpha[i].unsqueeze(2)), dim=2)) + + result = (torch.stack(out_images)) + return result + +def movement_map_f(movement_presets_distance): + movement_map = { + 'left to center': {'x_start': -movement_presets_distance, 'x_end': 0, 'y_start': 0, 'y_end': 0}, + 'right to center': {'x_start': movement_presets_distance, 'x_end': 0, 'y_start': 0, 'y_end': 0}, + 'center to left': {'x_start': 0, 'x_end': -movement_presets_distance, 'y_start': 0, 'y_end': 0}, + 'center to right': {'x_start': 0, 'x_end': movement_presets_distance, 'y_start': 0, 'y_end': 0}, + 'left to right': {'x_start': -movement_presets_distance, 'x_end': movement_presets_distance, 'y_start': 0, 'y_end': 0}, + 'right to left': {'x_start': movement_presets_distance, 'x_end': -movement_presets_distance, 'y_start': 0, 'y_end': 0}, + 'top to center': {'x_start': 0, 'x_end': 0, 'y_start': -movement_presets_distance, 'y_end': 0}, + 'bottom to center': {'x_start': 0, 'x_end': 0, 'y_start': movement_presets_distance, 'y_end': 0}, + 'center to top': {'x_start': 0, 'x_end': 0, 'y_start': 0, 'y_end': -movement_presets_distance}, + 'center to bottom': {'x_start': 0, 'x_end': 0, 'y_start': 0, 'y_end': movement_presets_distance}, + 'top to bottom': {'x_start': 0, 'x_end': 0, 'y_start': -movement_presets_distance, 'y_end': movement_presets_distance}, + 'bottom to top': {'x_start': 0, 'x_end': 0, 'y_start': movement_presets_distance, 'y_end': -movement_presets_distance}, + 'top left to center': {'x_start': -movement_presets_distance, 'x_end': 0, 'y_start': -movement_presets_distance, 'y_end': 0}, + 'top right to center': {'x_start': movement_presets_distance, 'x_end': 0, 'y_start': -movement_presets_distance, 'y_end': 0}, + 'bottom left to center': {'x_start': -movement_presets_distance, 'x_end': 0, 'y_start': movement_presets_distance, 'y_end': 0}, + 'bottom right to center': {'x_start': movement_presets_distance, 'x_end': 0, 'y_start': movement_presets_distance, 'y_end': 0}, + 'center to top left': {'x_start': 0, 'x_end': -movement_presets_distance, 'y_start': 0, 'y_end': -movement_presets_distance}, + 'center to top right': {'x_start': 0, 'x_end': movement_presets_distance, 'y_start': 0, 'y_end': -movement_presets_distance}, + 'center to bottom left': {'x_start': 0, 'x_end': -movement_presets_distance, 'y_start': 0, 'y_end': movement_presets_distance}, + 'center to bottom right': {'x_start': 0, 'x_end': movement_presets_distance, 'y_start': 0, 'y_end': movement_presets_distance}, + 'top left to bottom right': {'x_start': -movement_presets_distance, 'x_end': movement_presets_distance, 'y_start': -movement_presets_distance, 'y_end': movement_presets_distance}, + 'bottom right to top left': {'x_start': movement_presets_distance, 'x_end': -movement_presets_distance, 'y_start': movement_presets_distance, 'y_end': -movement_presets_distance}, + 'top right to bottom left': {'x_start': movement_presets_distance, 'x_end': -movement_presets_distance, 'y_start': -movement_presets_distance, 'y_end': movement_presets_distance}, + 'bottom left to top right': {'x_start': -movement_presets_distance, 'x_end': movement_presets_distance, 'y_start': movement_presets_distance, 'y_end': -movement_presets_distance}, + } + + return movement_map + +movement = ['None', +'left to center', +'right to center', +'center to left', +'center to right', +'left to right', +'right to left', + +'top to center', +'bottom to center', +'top to bottom', +'bottom to top', +'center to top', +'center to bottom', + +'top left to center', +'top right to center', +'bottom left to center', +'bottom right to center', + +'center to top left', +'center to top right', +'center to bottom left', +'center to bottom right', + +'top left to bottom right', +'bottom right to top left', +'top right to bottom left', +'bottom left to top right' +] diff --git a/README.md b/README.md new file mode 100644 index 0000000..6bc6168 --- /dev/null +++ b/README.md @@ -0,0 +1,158 @@ + + + + +
+
+ +[![](media/svg/patreon.svg)](https://www.patreon.com/distyx) + + + +

ComfyUI Frame Maker

+

Add control and cool effects into your animation.

+

Don't forget to leave a star.

+ + +

+ Report Bug +

+
+ + + + +
+ Table of Contents +
    +
  1. + About The Project +
  2. +
  3. Requirements
  4. +
  5. Contact
  6. +
  7. My Other Projects
  8. + +
+
+ + +## About The Project + +### This node creates a sequence of frames by moving and scaling a subject image over a background image. + + +## Basic frame maker workflow + + + +## Basic batch frame maker workflow + + + +## layerdiffusion frame maker workflow + + + +## frame maker + splash workflow (soon) + + + + +

(back to top)

+ + +## Requirements + - [CompfyUI](https://github.com/comfyanonymous/ComfyUI) + + ### Recommended + - [ComfyUI-Manager](https://github.com/ltdrdata/ComfyUI-Manager) + +

(back to top)

+ + + + +## Install + + ``` +cd custom_nodes +git clone https://github.com/diStyApps/ComfyUI_FrameMaker.git +``` + + +

(back to top)

+ + + +## Contact + +distty@gmail.com + + +

(back to top)

+ + +## My Other Projects + +[SEAIT](https://github.com/diStyApps/seait) + +[VisionCrafter](https://github.com/diStyApps/VisionCrafter) + +[FaceSwapSuite](https://github.com/diStyApps/FaceSwapSuite) + +[VisualClipPicker](https://github.com/diStyApps/VisualClipPicker) + +[Stable-Diffusion-Pickle-Scanner-GUI](https://github.com/diStyApps/Stable-Diffusion-Pickle-Scanner-GUI) + +[Safe-and-Stable-Ckpt2Safetensors-Conversion-Tool-GUI](https://github.com/diStyApps/Safe-and-Stable-Ckpt2Safetensors-Conversion-Tool-GUI) + + +

(back to top)

+ + + + +[contributors-shield]: https://img.shields.io/github/contributors/othneildrew/Best-README-Template.svg?style=for-the-badge +[contributors-url]: https://github.com/othneildrew/Best-README-Template/graphs/contributors +[forks-shield]: https://img.shields.io/github/forks/othneildrew/Best-README-Template.svg?style=for-the-badge +[forks-url]: https://github.com/othneildrew/Best-README-Template/network/members +[stars-shield]: https://img.shields.io/github/stars/othneildrew/Best-README-Template.svg?style=for-the-badge +[stars-url]: https://github.com/othneildrew/Best-README-Template/stargazers +[issues-shield]: https://img.shields.io/github/issues/othneildrew/Best-README-Template.svg?style=for-the-badge +[issues-url]: https://github.com/othneildrew/Best-README-Template/issues +[license-shield]: https://img.shields.io/github/license/othneildrew/Best-README-Template.svg?style=for-the-badge +[license-url]: https://github.com/othneildrew/Best-README-Template/blob/master/LICENSE.txt +[linkedin-shield]: https://img.shields.io/badge/-LinkedIn-black.svg?style=for-the-badge&logo=linkedin&colorB=555 +[linkedin-url]: https://linkedin.com/in/othneildrew +[product-screenshot]: images/screenshot.png +[Next.js]: https://img.shields.io/badge/next.js-000000?style=for-the-badge&logo=nextdotjs&logoColor=white +[Next-url]: https://nextjs.org/ +[React.js]: https://img.shields.io/badge/React-20232A?style=for-the-badge&logo=react&logoColor=61DAFB +[React-url]: https://reactjs.org/ +[Vue.js]: https://img.shields.io/badge/Vue.js-35495E?style=for-the-badge&logo=vuedotjs&logoColor=4FC08D +[Vue-url]: https://vuejs.org/ +[Angular.io]: https://img.shields.io/badge/Angular-DD0031?style=for-the-badge&logo=angular&logoColor=white +[Angular-url]: https://angular.io/ +[Svelte.dev]: https://img.shields.io/badge/Svelte-4A4A55?style=for-the-badge&logo=svelte&logoColor=FF3E00 +[Svelte-url]: https://svelte.dev/ +[Laravel.com]: https://img.shields.io/badge/Laravel-FF2D20?style=for-the-badge&logo=laravel&logoColor=white +[Laravel-url]: https://laravel.com +[Bootstrap.com]: https://img.shields.io/badge/Bootstrap-563D7C?style=for-the-badge&logo=bootstrap&logoColor=white +[Bootstrap-url]: https://getbootstrap.com +[JQuery.com]: https://img.shields.io/badge/jQuery-0769AD?style=for-the-badge&logo=jquery&logoColor=white +[JQuery-url]: https://jquery.com + + + diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..e952a40 --- /dev/null +++ b/__init__.py @@ -0,0 +1,6 @@ +from .FrameMaker import NODE_CLASS_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS +WEB_DIRECTORY = "js" + +CC_VERSION = 2.0 + +__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS', 'CC_VERSION'] \ No newline at end of file diff --git a/js/appearance.js b/js/appearance.js new file mode 100644 index 0000000..da96417 --- /dev/null +++ b/js/appearance.js @@ -0,0 +1,66 @@ +import { app } from "../../scripts/app.js"; + +const COLOR_THEMES = { + red: { nodeColor: "#332222", nodeBgColor: "#553333" }, + green: { nodeColor: "#223322", nodeBgColor: "#335533" }, + blue: { nodeColor: "#222233", nodeBgColor: "#333355" }, + pale_blue: { nodeColor: "#2a363b", nodeBgColor: "#3f5159" }, + cyan: { nodeColor: "#223333", nodeBgColor: "#335555" }, + purple: { nodeColor: "#332233", nodeBgColor: "#553355" }, + yellow: { nodeColor: "#443322", nodeBgColor: "#665533" }, + // purple_custom: { nodeColor: "#7345b0" , nodeBgColor: "#482b6e" }, + purple_custom: { nodeColor: "#111111" , nodeBgColor: "#482b6e" }, + + none: { nodeColor: null, nodeBgColor: null } // no color +}; + +const NODE_COLORS = { + "FrameMaker": "purple_custom", + "FrameMakerBatch": "purple_custom", + + + }; + +function shuffleArray(array) { + for (let i = array.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [array[i], array[j]] = [array[j], array[i]]; // Swap elements + } +} + +let colorKeys = Object.keys(COLOR_THEMES).filter(key => key !== "none"); +shuffleArray(colorKeys); // Shuffle the color themes initially + +function setNodeColors(node, theme) { + if (!theme) {return;} + node.shape = "box"; + if(theme.nodeColor && theme.nodeBgColor) { + node.color = theme.nodeColor; + node.bgcolor = theme.nodeBgColor; + } +} + +const ext = { + name: "disty.appearance", + + nodeCreated(node) { + const nclass = node.comfyClass; + if (NODE_COLORS.hasOwnProperty(nclass)) { + let colorKey = NODE_COLORS[nclass]; + + if (colorKey === "random") { + // Check for a valid color key before popping + if (colorKeys.length === 0 || !COLOR_THEMES[colorKeys[colorKeys.length - 1]]) { + colorKeys = Object.keys(COLOR_THEMES).filter(key => key !== "none"); + shuffleArray(colorKeys); + } + colorKey = colorKeys.pop(); + } + + const theme = COLOR_THEMES[colorKey]; + setNodeColors(node, theme); + } + } +}; + +app.registerExtension(ext); diff --git a/media/preview/frame_maker_1.gif b/media/preview/frame_maker_1.gif new file mode 100644 index 0000000..934f6c4 Binary files /dev/null and b/media/preview/frame_maker_1.gif differ diff --git a/media/preview/frame_maker_2.gif b/media/preview/frame_maker_2.gif new file mode 100644 index 0000000..39dfe4a Binary files /dev/null and b/media/preview/frame_maker_2.gif differ diff --git a/media/preview/frame_maker_3.gif b/media/preview/frame_maker_3.gif new file mode 100644 index 0000000..14649ba Binary files /dev/null and b/media/preview/frame_maker_3.gif differ diff --git a/workflows/frame_maker_basic.json b/workflows/frame_maker_basic.json new file mode 100644 index 0000000..57ff32c --- /dev/null +++ b/workflows/frame_maker_basic.json @@ -0,0 +1,271 @@ +{ + "last_node_id": 16, + "last_link_id": 28, + "nodes": [ + { + "id": 2, + "type": "LoadImage", + "pos": [ + 120, + 70 + ], + "size": [ + 240, + 310 + ], + "flags": {}, + "order": 0, + "mode": 0, + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 1 + ], + "shape": 3 + }, + { + "name": "MASK", + "type": "MASK", + "links": [ + 2 + ], + "shape": 3, + "slot_index": 1 + } + ], + "properties": { + "Node name for S&R": "LoadImage" + }, + "widgets_values": [ + "ComfyUI_13306_.png", + "image" + ], + "shape": 1 + }, + { + "id": 4, + "type": "LoadImage", + "pos": [ + 110, + 430 + ], + "size": { + "0": 250, + "1": 350 + }, + "flags": {}, + "order": 1, + "mode": 0, + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 4 + ], + "shape": 3, + "slot_index": 0 + }, + { + "name": "MASK", + "type": "MASK", + "links": [], + "shape": 3, + "slot_index": 1 + } + ], + "properties": { + "Node name for S&R": "LoadImage" + }, + "widgets_values": [ + "gm_forest_00008_.png", + "image" + ], + "shape": 1 + }, + { + "id": 1, + "type": "FrameMaker", + "pos": [ + 400, + 70 + ], + "size": { + "0": 342.5999755859375, + "1": 610 + }, + "flags": {}, + "order": 2, + "mode": 0, + "inputs": [ + { + "name": "subject_image", + "type": "IMAGE", + "link": 1, + "slot_index": 0 + }, + { + "name": "subject_alpha", + "type": "MASK", + "link": 2 + }, + { + "name": "bg1", + "type": "IMAGE", + "link": 4, + "slot_index": 2 + }, + { + "name": "bg2", + "type": "IMAGE", + "link": null + }, + { + "name": "bg3", + "type": "IMAGE", + "link": null + }, + { + "name": "bg4", + "type": "IMAGE", + "link": null + }, + { + "name": "frames", + "type": "IMAGE", + "link": null + } + ], + "outputs": [ + { + "name": "frames", + "type": "IMAGE", + "links": [ + 28 + ], + "shape": 3, + "slot_index": 0 + }, + { + "name": "subject_image", + "type": "IMAGE", + "links": [], + "shape": 3, + "slot_index": 1 + }, + { + "name": "width", + "type": "INT", + "links": null, + "shape": 3 + }, + { + "name": "height", + "type": "INT", + "links": null, + "shape": 3 + }, + { + "name": "frame_count", + "type": "INT", + "links": [], + "shape": 3, + "slot_index": 4 + } + ], + "properties": { + "Node name for S&R": "FrameMaker" + }, + "widgets_values": [ + 4, + "false", + "center to right", + 50, + "front", + 0, + 0, + 0, + 0, + 1, + 1, + "center", + "true", + 768, + 768, + "false", + 512, + 512, + "false" + ], + "color": "#111111", + "bgcolor": "#482b6e", + "shape": 1 + }, + { + "id": 16, + "type": "PreviewImage", + "pos": [ + 780, + 70 + ], + "size": { + "0": 590, + "1": 610 + }, + "flags": {}, + "order": 3, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 28 + } + ], + "properties": { + "Node name for S&R": "PreviewImage" + }, + "shape": 1 + } + ], + "links": [ + [ + 1, + 2, + 0, + 1, + 0, + "IMAGE" + ], + [ + 2, + 2, + 1, + 1, + 1, + "MASK" + ], + [ + 4, + 4, + 0, + 1, + 2, + "IMAGE" + ], + [ + 28, + 1, + 0, + 16, + 0, + "IMAGE" + ] + ], + "groups": [], + "config": {}, + "extra": {}, + "version": 0.4 +} \ No newline at end of file diff --git a/workflows/frame_maker_basic.png b/workflows/frame_maker_basic.png new file mode 100644 index 0000000..9e0ce5a Binary files /dev/null and b/workflows/frame_maker_basic.png differ diff --git a/workflows/frame_maker_batch.json b/workflows/frame_maker_batch.json new file mode 100644 index 0000000..292055b --- /dev/null +++ b/workflows/frame_maker_batch.json @@ -0,0 +1,768 @@ +{ + "last_node_id": 15, + "last_link_id": 27, + "nodes": [ + { + "id": 2, + "type": "LoadImage", + "pos": [ + 20, + 60 + ], + "size": [ + 320, + 310 + ], + "flags": {}, + "order": 0, + "mode": 0, + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 1 + ], + "shape": 3 + }, + { + "name": "MASK", + "type": "MASK", + "links": [ + 2 + ], + "shape": 3, + "slot_index": 1 + } + ], + "properties": { + "Node name for S&R": "LoadImage" + }, + "widgets_values": [ + "ComfyUI_13306_.png", + "image" + ], + "shape": 1 + }, + { + "id": 10, + "type": "FrameMakerBatch", + "pos": [ + 740, + 70 + ], + "size": [ + 350, + 590 + ], + "flags": {}, + "order": 3, + "mode": 0, + "inputs": [ + { + "name": "frames", + "type": "IMAGE", + "link": 8, + "slot_index": 0 + }, + { + "name": "subject_image", + "type": "IMAGE", + "link": 9 + }, + { + "name": "subject_alpha", + "type": "MASK", + "link": null + }, + { + "name": "frame_count", + "type": "INT", + "link": 11, + "widget": { + "name": "frame_count" + } + } + ], + "outputs": [ + { + "name": "frames", + "type": "IMAGE", + "links": [ + 15 + ], + "shape": 3, + "slot_index": 0 + }, + { + "name": "subject_image", + "type": "IMAGE", + "links": [ + 16 + ], + "shape": 3, + "slot_index": 1 + }, + { + "name": "width", + "type": "INT", + "links": null, + "shape": 3 + }, + { + "name": "height", + "type": "INT", + "links": null, + "shape": 3 + }, + { + "name": "frame_count", + "type": "INT", + "links": [ + 17 + ], + "shape": 3, + "slot_index": 4 + } + ], + "properties": { + "Node name for S&R": "FrameMakerBatch" + }, + "widgets_values": [ + 4, + "false", + "top right to bottom left", + 50, + "front", + 0, + 0, + 0, + 0, + 1, + 1, + "center", + "true", + 768, + 768, + "false", + 512, + 512, + "false" + ], + "color": "#111111", + "bgcolor": "#482b6e", + "shape": 1 + }, + { + "id": 1, + "type": "FrameMaker", + "pos": [ + 370, + 60 + ], + "size": { + "0": 342.5999755859375, + "1": 610 + }, + "flags": {}, + "order": 2, + "mode": 0, + "inputs": [ + { + "name": "subject_image", + "type": "IMAGE", + "link": 1, + "slot_index": 0 + }, + { + "name": "subject_alpha", + "type": "MASK", + "link": 2 + }, + { + "name": "bg1", + "type": "IMAGE", + "link": 4, + "slot_index": 2 + }, + { + "name": "bg2", + "type": "IMAGE", + "link": null + }, + { + "name": "bg3", + "type": "IMAGE", + "link": null + }, + { + "name": "bg4", + "type": "IMAGE", + "link": null + }, + { + "name": "frames", + "type": "IMAGE", + "link": null + } + ], + "outputs": [ + { + "name": "frames", + "type": "IMAGE", + "links": [ + 8 + ], + "shape": 3, + "slot_index": 0 + }, + { + "name": "subject_image", + "type": "IMAGE", + "links": [ + 9 + ], + "shape": 3, + "slot_index": 1 + }, + { + "name": "width", + "type": "INT", + "links": null, + "shape": 3 + }, + { + "name": "height", + "type": "INT", + "links": null, + "shape": 3 + }, + { + "name": "frame_count", + "type": "INT", + "links": [ + 11 + ], + "shape": 3, + "slot_index": 4 + } + ], + "properties": { + "Node name for S&R": "FrameMaker" + }, + "widgets_values": [ + 16, + "false", + "left to center", + 50, + "front", + 0, + 0, + 0, + 0, + 1, + 1, + "center", + "true", + 768, + 768, + "false", + 512, + 512, + "false" + ], + "color": "#111111", + "bgcolor": "#482b6e", + "shape": 1 + }, + { + "id": 11, + "type": "FrameMakerBatch", + "pos": [ + 1110, + 70 + ], + "size": { + "0": 350, + "1": 590 + }, + "flags": {}, + "order": 4, + "mode": 0, + "inputs": [ + { + "name": "frames", + "type": "IMAGE", + "link": 15, + "slot_index": 0 + }, + { + "name": "subject_image", + "type": "IMAGE", + "link": 16 + }, + { + "name": "subject_alpha", + "type": "MASK", + "link": null + }, + { + "name": "frame_count", + "type": "INT", + "link": 17, + "widget": { + "name": "frame_count" + } + } + ], + "outputs": [ + { + "name": "frames", + "type": "IMAGE", + "links": [ + 22 + ], + "shape": 3, + "slot_index": 0 + }, + { + "name": "subject_image", + "type": "IMAGE", + "links": [ + 23 + ], + "shape": 3, + "slot_index": 1 + }, + { + "name": "width", + "type": "INT", + "links": null, + "shape": 3 + }, + { + "name": "height", + "type": "INT", + "links": [], + "shape": 3, + "slot_index": 3 + }, + { + "name": "frame_count", + "type": "INT", + "links": [ + 25 + ], + "shape": 3, + "slot_index": 4 + } + ], + "properties": { + "Node name for S&R": "FrameMakerBatch" + }, + "widgets_values": [ + 4, + "false", + "center to right", + 50, + "back", + 0, + 0, + 0, + 0, + 1, + 1, + "center", + "true", + 768, + 768, + "false", + 512, + 512, + "false" + ], + "color": "#111111", + "bgcolor": "#482b6e", + "shape": 1 + }, + { + "id": 12, + "type": "FrameMakerBatch", + "pos": [ + 1480, + 70 + ], + "size": { + "0": 350, + "1": 590 + }, + "flags": {}, + "order": 5, + "mode": 0, + "inputs": [ + { + "name": "frames", + "type": "IMAGE", + "link": 22, + "slot_index": 0 + }, + { + "name": "subject_image", + "type": "IMAGE", + "link": 23 + }, + { + "name": "subject_alpha", + "type": "MASK", + "link": null + }, + { + "name": "frame_count", + "type": "INT", + "link": 25, + "widget": { + "name": "frame_count" + } + } + ], + "outputs": [ + { + "name": "frames", + "type": "IMAGE", + "links": [ + 21 + ], + "shape": 3, + "slot_index": 0 + }, + { + "name": "subject_image", + "type": "IMAGE", + "links": null, + "shape": 3 + }, + { + "name": "width", + "type": "INT", + "links": null, + "shape": 3 + }, + { + "name": "height", + "type": "INT", + "links": null, + "shape": 3 + }, + { + "name": "frame_count", + "type": "INT", + "links": null, + "shape": 3 + } + ], + "properties": { + "Node name for S&R": "FrameMakerBatch" + }, + "widgets_values": [ + 4, + "false", + "bottom left to center", + 50, + "front", + 0, + 0, + 0, + 0, + 1, + 1, + "center", + "true", + 768, + 768, + "false", + 512, + 512, + "false" + ], + "color": "#111111", + "bgcolor": "#482b6e", + "shape": 1 + }, + { + "id": 6, + "type": "RIFE VFI", + "pos": [ + 1850, + 70 + ], + "size": { + "0": 319.9336853027344, + "1": 309.7534484863281 + }, + "flags": { + "collapsed": true + }, + "order": 6, + "mode": 0, + "inputs": [ + { + "name": "frames", + "type": "IMAGE", + "link": 21 + }, + { + "name": "optional_interpolation_states", + "type": "INTERPOLATION_STATES", + "link": null + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 27 + ], + "shape": 3, + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "RIFE VFI" + }, + "widgets_values": [ + "rife47.pth", + 10, + 2, + true, + true, + 1 + ], + "shape": 1 + }, + { + "id": 4, + "type": "LoadImage", + "pos": [ + 20, + 420 + ], + "size": [ + 320, + 410 + ], + "flags": {}, + "order": 1, + "mode": 0, + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 4 + ], + "shape": 3, + "slot_index": 0 + }, + { + "name": "MASK", + "type": "MASK", + "links": [], + "shape": 3, + "slot_index": 1 + } + ], + "properties": { + "Node name for S&R": "LoadImage" + }, + "widgets_values": [ + "gm_forest_00008_.png", + "image" + ], + "shape": 1 + }, + { + "id": 15, + "type": "VHS_VideoCombine", + "pos": [ + 1850, + 110 + ], + "size": [ + 530, + 810 + ], + "flags": {}, + "order": 7, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 27 + }, + { + "name": "audio", + "type": "VHS_AUDIO", + "link": null + }, + { + "name": "batch_manager", + "type": "VHS_BatchManager", + "link": null + } + ], + "outputs": [ + { + "name": "Filenames", + "type": "VHS_FILENAMES", + "links": null, + "shape": 3 + } + ], + "properties": { + "Node name for S&R": "VHS_VideoCombine" + }, + "widgets_values": { + "frame_rate": 32, + "loop_count": 0, + "filename_prefix": "AnimateDiff", + "format": "video/h264-mp4", + "pix_fmt": "yuv420p", + "crf": 19, + "save_metadata": true, + "pingpong": false, + "save_output": true, + "videopreview": { + "hidden": false, + "paused": false, + "params": { + "filename": "AnimateDiff_00002.mp4", + "subfolder": "", + "type": "output", + "format": "video/h264-mp4" + } + } + }, + "shape": 1 + } + ], + "links": [ + [ + 1, + 2, + 0, + 1, + 0, + "IMAGE" + ], + [ + 2, + 2, + 1, + 1, + 1, + "MASK" + ], + [ + 4, + 4, + 0, + 1, + 2, + "IMAGE" + ], + [ + 8, + 1, + 0, + 10, + 0, + "IMAGE" + ], + [ + 9, + 1, + 1, + 10, + 1, + "IMAGE" + ], + [ + 11, + 1, + 4, + 10, + 3, + "INT" + ], + [ + 15, + 10, + 0, + 11, + 0, + "IMAGE" + ], + [ + 16, + 10, + 1, + 11, + 1, + "IMAGE" + ], + [ + 17, + 10, + 4, + 11, + 3, + "INT" + ], + [ + 21, + 12, + 0, + 6, + 0, + "IMAGE" + ], + [ + 22, + 11, + 0, + 12, + 0, + "IMAGE" + ], + [ + 23, + 11, + 1, + 12, + 1, + "IMAGE" + ], + [ + 25, + 11, + 4, + 12, + 3, + "INT" + ], + [ + 27, + 6, + 0, + 15, + 0, + "IMAGE" + ] + ], + "groups": [], + "config": {}, + "extra": {}, + "version": 0.4 +} \ No newline at end of file diff --git a/workflows/frame_maker_batch.png b/workflows/frame_maker_batch.png new file mode 100644 index 0000000..ef43d76 Binary files /dev/null and b/workflows/frame_maker_batch.png differ diff --git a/workflows/frame_maker_layerdiffusion.json b/workflows/frame_maker_layerdiffusion.json new file mode 100644 index 0000000..6dc6070 --- /dev/null +++ b/workflows/frame_maker_layerdiffusion.json @@ -0,0 +1,1049 @@ +{ + "last_node_id": 56, + "last_link_id": 95, + "nodes": [ + { + "id": 13, + "type": "LayeredDiffusionApply", + "pos": [ + 10, + 350 + ], + "size": { + "0": 327.8314208984375, + "1": 106.42147827148438 + }, + "flags": {}, + "order": 2, + "mode": 0, + "inputs": [ + { + "name": "model", + "type": "MODEL", + "link": 18 + } + ], + "outputs": [ + { + "name": "MODEL", + "type": "MODEL", + "links": [ + 19 + ], + "shape": 3, + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "LayeredDiffusionApply" + }, + "widgets_values": [ + "Conv Injection", + 1 + ], + "shape": 1 + }, + { + "id": 5, + "type": "EmptyLatentImage", + "pos": [ + 10, + 190 + ], + "size": { + "0": 330, + "1": 110 + }, + "flags": {}, + "order": 0, + "mode": 0, + "outputs": [ + { + "name": "LATENT", + "type": "LATENT", + "links": [ + 2, + 87 + ], + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "EmptyLatentImage" + }, + "widgets_values": [ + 1024, + 1024, + 1 + ], + "shape": 1 + }, + { + "id": 14, + "type": "VAEDecode", + "pos": [ + 1140, + 40 + ], + "size": { + "0": 210, + "1": 46 + }, + "flags": { + "collapsed": true + }, + "order": 8, + "mode": 0, + "inputs": [ + { + "name": "samples", + "type": "LATENT", + "link": 21 + }, + { + "name": "vae", + "type": "VAE", + "link": 22, + "slot_index": 1 + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 24 + ], + "shape": 3, + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "VAEDecode" + }, + "shape": 1 + }, + { + "id": 34, + "type": "RIFE VFI", + "pos": [ + 1720, + 130 + ], + "size": { + "0": 319.9336853027344, + "1": 309.7534484863281 + }, + "flags": { + "collapsed": true + }, + "order": 14, + "mode": 0, + "inputs": [ + { + "name": "frames", + "type": "IMAGE", + "link": 92 + }, + { + "name": "optional_interpolation_states", + "type": "INTERPOLATION_STATES", + "link": null + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 86 + ], + "shape": 3, + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "RIFE VFI" + }, + "widgets_values": [ + "rife47.pth", + 10, + 2, + true, + true, + 0.5 + ], + "shape": 1 + }, + { + "id": 6, + "type": "CLIPTextEncode", + "pos": [ + 370, + 40 + ], + "size": { + "0": 422.84503173828125, + "1": 164.31304931640625 + }, + "flags": {}, + "order": 3, + "mode": 0, + "inputs": [ + { + "name": "clip", + "type": "CLIP", + "link": 3 + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 4 + ], + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "CLIPTextEncode" + }, + "widgets_values": [ + "a cartoon dolphin jumping out of the water" + ], + "color": "#232", + "bgcolor": "#353", + "shape": 1 + }, + { + "id": 41, + "type": "PreviewImage", + "pos": [ + 1140, + 420 + ], + "size": { + "0": 200, + "1": 250 + }, + "flags": {}, + "order": 11, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 58 + } + ], + "properties": { + "Node name for S&R": "PreviewImage" + }, + "shape": 1 + }, + { + "id": 55, + "type": "PreviewImage", + "pos": [ + 1140, + 80 + ], + "size": { + "0": 200, + "1": 250 + }, + "flags": {}, + "order": 12, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 91 + } + ], + "properties": { + "Node name for S&R": "PreviewImage" + }, + "shape": 1 + }, + { + "id": 35, + "type": "VHS_VideoCombine", + "pos": [ + 1720, + 170 + ], + "size": [ + 290, + 570 + ], + "flags": {}, + "order": 16, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 86 + }, + { + "name": "audio", + "type": "VHS_AUDIO", + "link": null + }, + { + "name": "batch_manager", + "type": "VHS_BatchManager", + "link": null + } + ], + "outputs": [ + { + "name": "Filenames", + "type": "VHS_FILENAMES", + "links": null, + "shape": 3 + } + ], + "properties": { + "Node name for S&R": "VHS_VideoCombine" + }, + "widgets_values": { + "frame_rate": 32, + "loop_count": 0, + "filename_prefix": "AnimateDiff", + "format": "video/h264-mp4", + "pix_fmt": "yuv420p", + "crf": 19, + "save_metadata": true, + "pingpong": false, + "save_output": true, + "videopreview": { + "hidden": false, + "paused": false, + "params": { + "filename": "AnimateDiff_00031.mp4", + "subfolder": "", + "type": "output", + "format": "video/h264-mp4" + } + } + }, + "shape": 1 + }, + { + "id": 32, + "type": "PreviewImage", + "pos": [ + 2020, + 130 + ], + "size": { + "0": 360, + "1": 370 + }, + "flags": {}, + "order": 15, + "mode": 0, + "inputs": [ + { + "name": "images", + "type": "IMAGE", + "link": 94 + } + ], + "properties": { + "Node name for S&R": "PreviewImage" + }, + "shape": 1 + }, + { + "id": 15, + "type": "LayeredDiffusionDecode", + "pos": [ + 1360, + 40 + ], + "size": { + "0": 210, + "1": 46 + }, + "flags": { + "collapsed": false + }, + "order": 10, + "mode": 0, + "inputs": [ + { + "name": "samples", + "type": "LATENT", + "link": 23 + }, + { + "name": "images", + "type": "IMAGE", + "link": 24 + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 43, + 91 + ], + "shape": 3, + "slot_index": 0 + }, + { + "name": "MASK", + "type": "MASK", + "links": [ + 44 + ], + "shape": 3, + "slot_index": 1 + } + ], + "properties": { + "Node name for S&R": "LayeredDiffusionDecode" + }, + "shape": 1 + }, + { + "id": 31, + "type": "FrameMaker", + "pos": [ + 1360, + 130 + ], + "size": { + "0": 342.5999755859375, + "1": 610 + }, + "flags": {}, + "order": 13, + "mode": 0, + "inputs": [ + { + "name": "subject_image", + "type": "IMAGE", + "link": 43 + }, + { + "name": "subject_alpha", + "type": "MASK", + "link": 44 + }, + { + "name": "bg1", + "type": "IMAGE", + "link": 88, + "slot_index": 2 + }, + { + "name": "bg2", + "type": "IMAGE", + "link": null + }, + { + "name": "bg3", + "type": "IMAGE", + "link": null + }, + { + "name": "bg4", + "type": "IMAGE", + "link": null + }, + { + "name": "frames", + "type": "IMAGE", + "link": null + } + ], + "outputs": [ + { + "name": "frames", + "type": "IMAGE", + "links": [ + 92, + 94 + ], + "shape": 3, + "slot_index": 0 + }, + { + "name": "subject_image", + "type": "IMAGE", + "links": null, + "shape": 3 + }, + { + "name": "width", + "type": "INT", + "links": null, + "shape": 3 + }, + { + "name": "height", + "type": "INT", + "links": null, + "shape": 3 + }, + { + "name": "frame_count", + "type": "INT", + "links": [], + "shape": 3, + "slot_index": 4 + } + ], + "properties": { + "Node name for S&R": "FrameMaker" + }, + "widgets_values": [ + 16, + "true", + "bottom to center", + 50, + "front", + 0, + 0, + 0, + 0, + 1, + 1, + "center", + "true", + 768, + 768, + "false", + 512, + 512, + "false" + ], + "color": "#111111", + "bgcolor": "#482b6e", + "shape": 1 + }, + { + "id": 4, + "type": "CheckpointLoaderSimple", + "pos": [ + 10, + 40 + ], + "size": { + "0": 330, + "1": 100 + }, + "flags": {}, + "order": 1, + "mode": 0, + "outputs": [ + { + "name": "MODEL", + "type": "MODEL", + "links": [ + 18, + 61 + ], + "slot_index": 0 + }, + { + "name": "CLIP", + "type": "CLIP", + "links": [ + 3, + 5, + 60 + ], + "slot_index": 1 + }, + { + "name": "VAE", + "type": "VAE", + "links": [ + 22, + 57 + ], + "slot_index": 2 + } + ], + "properties": { + "Node name for S&R": "CheckpointLoaderSimple" + }, + "widgets_values": [ + "checkpoints_e\\juggernautXL_v7Rundiffusion.safetensors" + ], + "shape": 1 + }, + { + "id": 7, + "type": "CLIPTextEncode", + "pos": [ + 370, + 470 + ], + "size": { + "0": 425.27801513671875, + "1": 180.6060791015625 + }, + "flags": {}, + "order": 4, + "mode": 0, + "inputs": [ + { + "name": "clip", + "type": "CLIP", + "link": 5 + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 6, + 51 + ], + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "CLIPTextEncode" + }, + "widgets_values": [ + "text, watermark" + ], + "color": "#322", + "bgcolor": "#533", + "shape": 1 + }, + { + "id": 42, + "type": "CLIPTextEncode", + "pos": [ + 370, + 250 + ], + "size": { + "0": 422.84503173828125, + "1": 164.31304931640625 + }, + "flags": {}, + "order": 5, + "mode": 0, + "inputs": [ + { + "name": "clip", + "type": "CLIP", + "link": 60 + } + ], + "outputs": [ + { + "name": "CONDITIONING", + "type": "CONDITIONING", + "links": [ + 59 + ], + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "CLIPTextEncode" + }, + "widgets_values": [ + "a (cartoon:1.3) signal tropical resort island masterpiece epic, simple, ocean" + ], + "color": "#232", + "bgcolor": "#353", + "shape": 1 + }, + { + "id": 3, + "type": "KSampler", + "pos": [ + 810, + 40 + ], + "size": { + "0": 320, + "1": 270 + }, + "flags": {}, + "order": 6, + "mode": 0, + "inputs": [ + { + "name": "model", + "type": "MODEL", + "link": 19 + }, + { + "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": [ + 21, + 23 + ], + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "KSampler" + }, + "widgets_values": [ + 999325912211320, + "fixed", + 20, + 8, + "euler", + "normal", + 1 + ], + "shape": 1 + }, + { + "id": 38, + "type": "KSampler", + "pos": [ + 810, + 380 + ], + "size": { + "0": 320, + "1": 270 + }, + "flags": {}, + "order": 7, + "mode": 0, + "inputs": [ + { + "name": "model", + "type": "MODEL", + "link": 61 + }, + { + "name": "positive", + "type": "CONDITIONING", + "link": 59 + }, + { + "name": "negative", + "type": "CONDITIONING", + "link": 51 + }, + { + "name": "latent_image", + "type": "LATENT", + "link": 87 + } + ], + "outputs": [ + { + "name": "LATENT", + "type": "LATENT", + "links": [ + 56 + ], + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "KSampler" + }, + "widgets_values": [ + 999325912211320, + "fixed", + 25, + 6.7, + "dpmpp_2m_sde_gpu", + "karras", + 1 + ], + "shape": 1 + }, + { + "id": 40, + "type": "VAEDecode", + "pos": [ + 1140, + 380 + ], + "size": { + "0": 210, + "1": 46 + }, + "flags": { + "collapsed": true + }, + "order": 9, + "mode": 0, + "inputs": [ + { + "name": "samples", + "type": "LATENT", + "link": 56 + }, + { + "name": "vae", + "type": "VAE", + "link": 57 + } + ], + "outputs": [ + { + "name": "IMAGE", + "type": "IMAGE", + "links": [ + 58, + 88 + ], + "shape": 3, + "slot_index": 0 + } + ], + "properties": { + "Node name for S&R": "VAEDecode" + }, + "shape": 1 + } + ], + "links": [ + [ + 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" + ], + [ + 18, + 4, + 0, + 13, + 0, + "MODEL" + ], + [ + 19, + 13, + 0, + 3, + 0, + "MODEL" + ], + [ + 21, + 3, + 0, + 14, + 0, + "LATENT" + ], + [ + 22, + 4, + 2, + 14, + 1, + "VAE" + ], + [ + 23, + 3, + 0, + 15, + 0, + "LATENT" + ], + [ + 24, + 14, + 0, + 15, + 1, + "IMAGE" + ], + [ + 43, + 15, + 0, + 31, + 0, + "IMAGE" + ], + [ + 44, + 15, + 1, + 31, + 1, + "MASK" + ], + [ + 51, + 7, + 0, + 38, + 2, + "CONDITIONING" + ], + [ + 56, + 38, + 0, + 40, + 0, + "LATENT" + ], + [ + 57, + 4, + 2, + 40, + 1, + "VAE" + ], + [ + 58, + 40, + 0, + 41, + 0, + "IMAGE" + ], + [ + 59, + 42, + 0, + 38, + 1, + "CONDITIONING" + ], + [ + 60, + 4, + 1, + 42, + 0, + "CLIP" + ], + [ + 61, + 4, + 0, + 38, + 0, + "MODEL" + ], + [ + 86, + 34, + 0, + 35, + 0, + "IMAGE" + ], + [ + 87, + 5, + 0, + 38, + 3, + "LATENT" + ], + [ + 88, + 40, + 0, + 31, + 2, + "IMAGE" + ], + [ + 91, + 15, + 0, + 55, + 0, + "IMAGE" + ], + [ + 92, + 31, + 0, + 34, + 0, + "IMAGE" + ], + [ + 94, + 31, + 0, + 32, + 0, + "IMAGE" + ] + ], + "groups": [], + "config": {}, + "extra": {}, + "version": 0.4 +} \ No newline at end of file diff --git a/workflows/frame_maker_layerdiffusion.png b/workflows/frame_maker_layerdiffusion.png new file mode 100644 index 0000000..c1c5ea8 Binary files /dev/null and b/workflows/frame_maker_layerdiffusion.png differ