From 593be209a45a8a306c26de550e240a363de405a7 Mon Sep 17 00:00:00 2001 From: Christian Byrne Date: Sun, 15 Mar 2026 16:18:04 -0700 Subject: [PATCH] feat: add essentials_category to nodes and blueprints for Essentials tab (#12573) * feat: add essentials_category to nodes and blueprints for Essentials tab Add ESSENTIALS_CATEGORY or essentials_category to 12 node classes and all 36 blueprint JSONs. Update SubgraphEntry TypedDict and subgraph_manager to extract and pass through the field. Fixes COM-15221 Amp-Thread-ID: https://ampcode.com/threads/T-019c83de-f7ab-7779-a451-0ba5940b56a9 * fix: import NotRequired from typing_extensions for Python 3.10 compat * refactor: keep only node class ESSENTIALS_CATEGORY, remove blueprint/subgraph changes Frontend will own blueprint categorization separately. * fix: remove essentials_category from CreateVideo (not in spec) --------- Co-authored-by: guill --- comfy_api_nodes/nodes_kling.py | 1 + comfy_api_nodes/nodes_recraft.py | 1 + comfy_extras/nodes_audio.py | 2 ++ comfy_extras/nodes_image_compare.py | 1 + comfy_extras/nodes_images.py | 1 + comfy_extras/nodes_post_processing.py | 1 + nodes.py | 3 +++ 7 files changed, 10 insertions(+) diff --git a/comfy_api_nodes/nodes_kling.py b/comfy_api_nodes/nodes_kling.py index 8963c335d..9a37ccc53 100644 --- a/comfy_api_nodes/nodes_kling.py +++ b/comfy_api_nodes/nodes_kling.py @@ -1459,6 +1459,7 @@ class OmniProEditVideoNode(IO.ComfyNode): node_id="KlingOmniProEditVideoNode", display_name="Kling 3.0 Omni Edit Video", category="api node/video/Kling", + essentials_category="Video Generation", description="Edit an existing video with the latest model from Kling.", inputs=[ IO.Combo.Input("model_name", options=["kling-v3-omni", "kling-video-o1"]), diff --git a/comfy_api_nodes/nodes_recraft.py b/comfy_api_nodes/nodes_recraft.py index 4d1d508fa..c60cfbc4a 100644 --- a/comfy_api_nodes/nodes_recraft.py +++ b/comfy_api_nodes/nodes_recraft.py @@ -833,6 +833,7 @@ class RecraftVectorizeImageNode(IO.ComfyNode): node_id="RecraftVectorizeImageNode", display_name="Recraft Vectorize Image", category="api node/image/Recraft", + essentials_category="Image Tools", description="Generates SVG synchronously from an input image.", inputs=[ IO.Image.Input("image"), diff --git a/comfy_extras/nodes_audio.py b/comfy_extras/nodes_audio.py index 5d8d9bf6f..a395392d8 100644 --- a/comfy_extras/nodes_audio.py +++ b/comfy_extras/nodes_audio.py @@ -19,6 +19,7 @@ class EmptyLatentAudio(IO.ComfyNode): node_id="EmptyLatentAudio", display_name="Empty Latent Audio", category="latent/audio", + essentials_category="Audio", inputs=[ IO.Float.Input("seconds", default=47.6, min=1.0, max=1000.0, step=0.1), IO.Int.Input( @@ -185,6 +186,7 @@ class SaveAudioMP3(IO.ComfyNode): search_aliases=["export mp3"], display_name="Save Audio (MP3)", category="audio", + essentials_category="Audio", inputs=[ IO.Audio.Input("audio"), IO.String.Input("filename_prefix", default="audio/ComfyUI"), diff --git a/comfy_extras/nodes_image_compare.py b/comfy_extras/nodes_image_compare.py index 8e9f809e6..3d943be67 100644 --- a/comfy_extras/nodes_image_compare.py +++ b/comfy_extras/nodes_image_compare.py @@ -14,6 +14,7 @@ class ImageCompare(IO.ComfyNode): display_name="Image Compare", description="Compares two images side by side with a slider.", category="image", + essentials_category="Image Tools", is_experimental=True, is_output_node=True, inputs=[ diff --git a/comfy_extras/nodes_images.py b/comfy_extras/nodes_images.py index 4c57bb5cb..a8223cf8b 100644 --- a/comfy_extras/nodes_images.py +++ b/comfy_extras/nodes_images.py @@ -58,6 +58,7 @@ class ImageCropV2(IO.ComfyNode): search_aliases=["trim"], display_name="Image Crop", category="image/transform", + essentials_category="Image Tools", inputs=[ IO.Image.Input("image"), IO.BoundingBox.Input("crop_region", component="ImageCrop"), diff --git a/comfy_extras/nodes_post_processing.py b/comfy_extras/nodes_post_processing.py index 4a0f7141a..06626f9dd 100644 --- a/comfy_extras/nodes_post_processing.py +++ b/comfy_extras/nodes_post_processing.py @@ -21,6 +21,7 @@ class Blend(io.ComfyNode): node_id="ImageBlend", display_name="Image Blend", category="image/postprocessing", + essentials_category="Image Tools", inputs=[ io.Image.Input("image1"), io.Image.Input("image2"), diff --git a/nodes.py b/nodes.py index dd9298b18..03dcc9d4a 100644 --- a/nodes.py +++ b/nodes.py @@ -81,6 +81,7 @@ class CLIPTextEncode(ComfyNodeABC): class ConditioningCombine: + ESSENTIALS_CATEGORY = "Image Generation" @classmethod def INPUT_TYPES(s): return {"required": {"conditioning_1": ("CONDITIONING", ), "conditioning_2": ("CONDITIONING", )}} @@ -1778,6 +1779,7 @@ class LoadImage: return True class LoadImageMask: + ESSENTIALS_CATEGORY = "Image Tools" SEARCH_ALIASES = ["import mask", "alpha mask", "channel mask"] _color_channels = ["alpha", "red", "green", "blue"] @@ -1886,6 +1888,7 @@ class ImageScale: return (s,) class ImageScaleBy: + ESSENTIALS_CATEGORY = "Image Tools" upscale_methods = ["nearest-exact", "bilinear", "area", "bicubic", "lanczos"] @classmethod