comfyui-node-inputs について
comfyui-node-inputsは、データソケットとUIコントロールの定義を解説するComfyUIノード開発者向けガイドです。任意入力や遅延評価に加え、数値・選択肢からメディア編集までの入力形式を扱います。
主な機能
- 01データソケットとUIコントロールの定義
- 02数値、テキスト、選択入力の設定
- 03色、領域、カーブ編集機能の利用
- 04任意、非表示、遅延入力の設定
- 05動的な選択肢とファイルアップロード
活用シーン
- 01カスタムノードのパラメーターと接続ソケットの定義
- 02画像、音声、動画のアップロード入力の作成
- 03条件付きノードの入力を必要時のみ評価
- 04領域、カーブ、色の選択機能の追加
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ jtydhr88/ comfyui-custom-node-skills --skill comfyui-node-inputsインストール後、Claude Code で/comfyui-node-inputsを入力して読み込まれたか確認します。
詳細
ComfyUI ノード入力
入力は、ノードが受け取るデータを定義します。ウィジェット入力は UI コントロールを作成し、接続入力はソケットスロットを作成します。
ウィジェット入力の種類
INT
io.Int.Input("seed",
default=0,
min=0,
max=0xffffffffffffffff,
step=1,
control_after_generate=True, # adds increment/decrement/randomize control
display_mode=io.NumberDisplay.number, # "number", "slider", or "gradient_slider"
tooltip="Random seed for generation",
)
NumberDisplay のオプション: io.NumberDisplay.number、io.NumberDisplay.slider、io.NumberDisplay.gradient_slider
ControlAfterGenerate のオプション: True(デフォルトのランダム化)、または io.ControlAfterGenerate.fixed、.increment、.decrement、.randomize。モード値がコントロールの開始モードとして扱われるのは、フロントエンド v1.57.0 以降(#19867)のみです。それ以前のフロントエンドでは、その文字列はコントロールウィジェットの名前として使われていました。
FLOAT
io.Float.Input("strength",
default=1.0,
min=0.0,
max=10.0,
step=0.01,
round=0.001, # rounding precision
display_mode=io.NumberDisplay.slider,
gradient_stops=[{"offset": 0.0, "color": [0, 0, 0]}, {"offset": 1.0, "color": [255, 255, 255]}], # for gradient_slider mode
tooltip="Effect strength",
)
STRING
# Single-line string
io.String.Input("name",
default="",
placeholder="Enter name...",
)
# Multi-line text area
io.String.Input("prompt",
multiline=True,
default="",
placeholder="Enter prompt...",
dynamic_prompts=True, # enable dynamic prompt syntax
)
BOOLEAN
io.Boolean.Input("enabled",
default=True,
label_on="Enabled",
label_off="Disabled",
tooltip="Toggle this feature",
)
COMBO(ドロップダウン)
io.Combo.Input("mode",
options=["option_a", "option_b", "option_c"],
default="option_a",
tooltip="Select processing mode",
control_after_generate=True, # adds increment/decrement/randomize control
)
Enum を使った Combo:
from enum import Enum
class BlendMode(Enum):
NORMAL = "normal"
MULTIPLY = "multiply"
SCREEN = "screen"
io.Combo.Input("blend", options=BlendMode, default=BlendMode.NORMAL)
# Enum values auto-converted to string list
ファイルアップロードを使った Combo:
io.Combo.Input("image_file",
options=[],
upload=io.UploadType.image, # .image, .audio, .video, .model (for generic file upload)
image_folder=io.FolderType.input, # .input, .output, .temp
)
リモートオプションを使った動的な Combo:
io.Combo.Input("model_name",
options=[],
remote=io.RemoteOptions(
route="/internal/models/checkpoints",
refresh_button=True,
control_after_refresh="first", # "first" or "last"
timeout=5000, # ms
max_retries=3,
refresh=60000, # TTL refresh interval in ms
),
)
セキュリティ:Combo/DynamicCombo の値がファイルシステムに渡される場合は、信頼できない値として扱ってください。ファイル名、フォルダー名、パス、形式、拡張子として使う値は、読み込み/保存の境界で再検証してください(folder_paths.get_full_path_or_raise(...)、folder_paths.is_within_directory(base, path)、または固定の許可リストを使用します)。API 経由で options にない値を指定してプロンプトを送信できるためです。
MULTICOMBO(複数選択ドロップダウン)
io.MultiCombo.Input("tags",
options=["tag1", "tag2", "tag3", "tag4"],
default=["tag1"],
placeholder="Select tags...",
chip=True, # display as chips
)
# Value type: list[str]
COLOR(カラーピッカー)
io.Color.Input("color",
default="#ffffff",
socketless=True, # widget only by default
)
# Value type: str (hex color)
COLORS(カラーパレット)
io.Colors.Input("palette",
default=["#ff0000", "#00ff00"],
socketless=True,
)
# Value type: list[str] (hex colors)
BOUNDING_BOX(矩形セレクター)
io.BoundingBox.Input("region",
default={"x": 0, "y": 0, "width": 512, "height": 512},
socketless=True,
component="my_component", # optional custom UI component name
force_input=False,
)
# Value type: {"x": int, "y": int, "width": int, "height": int}
BOUNDING_BOXES(複数領域)
io.BoundingBoxes.Input("regions",
default=[],
socketless=True,
)
# Value type: list of {"x": int, "y": int, "width": int, "height": int, "metadata": dict}
CURVE(スプラインエディター)
io.Curve.Input("curve",
default=[(0.0, 0.0), (1.0, 1.0)], # linear ramp
socketless=True,
)
# Value type: raw curve data; normalize with CurveInput.from_raw(value)
# (from comfy_api.input import CurveInput)
RANGE(レベル/範囲エディター)
io.Range.Input("levels",
default={"min": 0.0, "max": 1.0},
gradient_stops=None, # gradient background for the slider
show_midpoint=True, # gamma midpoint handle
value_min=0.0,
value_max=1.0,
)
# Value type: raw dict; normalize with RangeInput.from_raw(value)
# (from comfy_api.input import RangeInput) -> .min_val, .max_val, .midpoint, .to_lut()
WEBCAM(カメラキャプチャ)
io.Webcam.Input("capture")
# Value type: str
IMAGECOMPARE(比較ウィジェット)
io.ImageCompare.Input("comparison", socketless=True)
# Value type: dict
新しいエディターウィジェット(v0.31–v0.40、対応するフロントエンドが必要)
io.VideoEdit.Input("trim", features=["trim"]) # "trim" and/or "crop" (default both)
# Value: {"trim": {"start_time": float, "duration": float}, "crop": {"x","y","width","height"}}
# apply with video.as_trimmed(...) / video.as_cropped(...); zero width/height = full frame
io.ResolutionPreview.Input("preview", # live preview of a computed size; optional by default
ratio_widget="aspect_ratio", megapixels_widget="megapixels", multiple_widget="multiple")
io.Compositor.Input("compositor") # layer-editor state dict (pairs with io.Layers)
io.CameraInfoState.Input("camera_info_state", optional=True) # camera editor state dict
入力オプション(共通)
io.Image.Input("image",
optional=True, # not required; creates optional input socket
tooltip="Description shown on hover",
lazy=True, # lazy evaluation - only computed when needed
advanced=True, # hidden by default in compact mode
raw_link=True, # receive raw link reference instead of value
)
force_input
ウィジェット入力をウィジェットではなく接続ソケットとして表示します。
io.Float.Input("value",
default=1.0,
force_input=True, # shows as socket, not slider
)
socketless
ウィジェット入力を、入力ソケットなしのウィジェットとしてのみ表示します。
io.String.Input("note",
default="",
socketless=True, # widget only, no connection socket
)
オプション入力
class MyNode(io.ComfyNode):
@classmethod
def define_schema(cls):
return io.Schema(
node_id="MyNode",
display_name="My Node",
category="example",
inputs=[
io.Image.Input("image"), # required
io.Mask.Input("mask", optional=True), # optional
io.Float.Input("blend", default=0.5), # has default widget
],
outputs=[io.Image.Output("IMAGE")],
)
@classmethod
def execute(cls, image, mask=None, blend=0.5):
# Optional inputs default to None when not connected
if mask is not None:
image = image * (1 - blend) + image * mask.unsqueeze(-1) * blend
return io.NodeOutput(image)
非表示入力
非表示入力はユーザー入力ではなく、サーバーから提供される値を受け取ります。
class MyNode(io.ComfyNode):
@classmethod
def define_schema(cls):
return io.Schema(
node_id="MyNode",
display_name="My Node",
category="example",
inputs=[io.String.Input("text")],
outputs=[io.String.Output()],
hidden=[
io.Hidden.unique_id, # node's unique ID
io.Hidden.prompt, # full prompt data
io.Hidden.extra_pnginfo, # PNG metadata dict
io.Hidden.dynprompt, # dynamic prompt object
io.Hidden.auth_token_comfy_org, # auth token
io.Hidden.api_key_comfy_org, # API key
io.Hidden.comfy_usage_source, # prompt source, e.g. "comfyui-frontend"
# io.Hidden.execution_list exists (v0.36+) but is core-internal and
# slated for removal - DO NOT USE
],
)
@classmethod
def execute(cls, text):
# Access hidden values via cls.hidden
node_id = cls.hidden.unique_id
prompt = cls.hidden.prompt
extra = cls.hidden.extra_pnginfo
return io.NodeOutput(f"{text} (node: {node_id})")
遅延評価
遅延入力は実際に必要になるまで評価されないため、計算量を節約できます。
class ConditionalNode(io.ComfyNode):
@classmethod
def define_schema(cls):
return io.Schema(
node_id="ConditionalNode",
display_name="Conditional",
category="logic",
inputs=[
io.Boolean.Input("condition"),
io.Image.Input("if_true", lazy=True),
io.Image.Input("if_false", lazy=True),
],
outputs=[io.Image.Output("IMAGE")],
)
@classmethod
def check_lazy_status(cls, condition, if_true=None, if_false=None):
"""Return list of input names that need evaluation."""
if condition and if_true is None:
return ["if_true"]
if not condition and if_false is None:
return ["if_false"]
return []
@classmethod
def execute(cls, condition, if_true, if_false):
return io.NodeOutput(if_true if condition else if_false)
遅延評価のルール:
- 入力に
lazy=Trueを指定します check_lazy_status()クラスメソッドを実装します- 未評価の入力は
Noneです。接続されていないオプションの遅延入力は kwargs に含まれません。区別するにはセンチネルのデフォルト値(MISSING = object())を使います(comfyui-node-advancedの Switch パターンを参照) - 計算が必要な入力名のリスト、または空のリストを返します
- メソッドは複数回呼び出される場合があります
- Autogrow/DynamicCombo の遅延サブ入力は、ここでは
(value, key)タプルとして渡されます(comfyui-node-advancedを参照)
入力の許容方針(コアポリシー):推奨値や UI の制限を超えている、または結果が悪くなる可能性があるという理由だけで値を拒否しないでください。処理が失敗する場合に限り、値を調整(クランプ/パディング/サイズ変更)してください。セキュリティチェック(パスの包含確認)は引き続き適用されます。
V1 入力形式(レガシーリファレンス)
@classmethod
def INPUT_TYPES(s):
return {
"required": {
"image": ("IMAGE",),
"strength": ("FLOAT", {
"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.01
}),
"mode": (["option_a", "option_b"],),
"text": ("STRING", {"multiline": True, "default": ""}),
},
"optional": {
"mask": ("MASK",),
},
"hidden": {
"unique_id": "UNIQUE_ID",
"prompt": "PROMPT",
"extra_pnginfo": "EXTRA_PNGINFO",
},
}
完全な例:複数入力ノード
class AdvancedImageNode(io.ComfyNode):
@classmethod
def define_schema(cls):
return io.Schema(
node_id="AdvancedImageNode",
display_name="Advanced Image",
category="image/advanced",
description="Demonstrates various input types",
inputs=[
# Required connection input
io.Image.Input("image", tooltip="Input image"),
# Required widget inputs
io.Float.Input("brightness", default=1.0, min=0.0, max=3.0,
step=0.1, display_mode=io.NumberDisplay.slider),
io.Float.Input("contrast", default=1.0, min=0.0, max=3.0, step=0.1),
io.Int.Input("seed", default=0, min=0, max=0xffffffffffffffff,
control_after_generate=True),
io.Combo.Input("blend_mode", options=["normal", "multiply", "screen"]),
io.Boolean.Input("flip_horizontal", default=False),
io.String.Input("label", default="", socketless=True),
# Optional inputs
io.Mask.Input("mask", optional=True),
io.Image.Input("overlay", optional=True),
# Advanced inputs (collapsed by default)
io.Float.Input("gamma", default=1.0, min=0.1, max=3.0, advanced=True),
],
outputs=[
io.Image.Output("IMAGE"),
io.Mask.Output("MASK"),
],
)
@classmethod
def execute(cls, image, brightness, contrast, seed, blend_mode,
flip_horizontal, label, mask=None, overlay=None, gamma=1.0):
result = image * brightness
if flip_horizontal:
result = torch.flip(result, dims=[2])
if mask is not None:
result = result * mask.unsqueeze(-1)
return io.NodeOutput(result, mask if mask is not None else torch.ones(result.shape[:3]))
関連項目
comfyui-node-basics- ノード構造の概要comfyui-node-datatypes- データ型の詳細comfyui-node-advanced- MatchType、Autogrow、DynamicCombocomfyui-node-lifecycle- 遅延評価の詳細