comfyui-node-datatypes について
ComfyUI のカスタムノードを開発する人向けのデータ型リファレンスです。テンソル、モデル、3D ファイル、ウィジェットなどの構造を説明します。
主な機能
- 01画像、マスク、潜在表現の形式
- 02音声、動画、条件付けデータの構造
- 03モデルと 3D 型のリファレンス
- 04ノードウィジェットの型
- 05特殊型と動的型の説明
活用シーン
- 01ノードの入出力形式の確認
- 02ComfyUI の画像や動画データの処理
- 03カスタムノードの型定義
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ jtydhr88/ comfyui-custom-node-skills --skill comfyui-node-datatypesインストール後、Claude Code で/comfyui-node-datatypesを入力して読み込まれたか確認します。
詳細
ComfyUI のデータ型
ComfyUI では、ノードの入力と出力に特定のデータ型を使用します。テンソルの形状とデータ形式を理解することが重要です。
完全な型リファレンス
テンソル/データ型
| 型 | V3 クラス | 形式 | 説明 |
|---|---|---|---|
| IMAGE | io.Image | torch.Tensor [B,H,W,C] float32 0-1 | RGB 画像のバッチ |
| MASK | io.Mask | torch.Tensor [H,W] または [B,H,W] float32 0-1 | グレースケールのマスク |
| LATENT | io.Latent | {"samples": Tensor[B,C,H,W] or [B,C,T,H,W], "noise_mask"?: Tensor, "batch_index"?: list[int], "type"?: str} | 潜在空間(4D 画像/5D 動画) |
| CONDITIONING | io.Conditioning | list[tuple[Tensor, PooledDict]] | プール出力を伴うテキストコンディショニング |
| AUDIO | io.Audio | {"waveform": Tensor[B,C,T], "sample_rate": int} | オーディオデータ |
| VIDEO | io.Video | VideoInput ABC | 動画データ(抽象基底クラス) |
| SIGMAS | io.Sigmas | torch.Tensor 1D、長さは steps+1 | ノイズスケジュール |
| NOISE | io.Noise | generate_noise() を持つオブジェクト | ノイズジェネレーター |
| LORA_MODEL | io.LoraModel | dict[str, torch.Tensor] | LoRA の重み差分 |
| LOSS_MAP | io.LossMap | {"loss": list[torch.Tensor]} | 損失マップ |
| TRACKS | io.Tracks | {"track_path": Tensor, "track_visibility": Tensor} | モーショントラッキングデータ |
| WAN_CAMERA_EMBEDDING | io.WanCameraEmbedding | torch.Tensor | WAN カメラ埋め込み |
| LATENT_OPERATION | io.LatentOperation | Callable[[Tensor], Tensor] | 潜在変換関数 |
| TIMESTEPS_RANGE | io.TimestepsRange | tuple[int, int] | 範囲 0.0-1.0 |
| DICT | io.Dict | dict | 汎用辞書 |
| ARRAY | io.Array | list | 汎用リスト/配列 |
| LAYERS | io.Layers | {"version": int, "canvas"?: (w, h), "layers": list[LayerItem]} | レイヤースタック(v0.31+);LayerItem:image テンソル、type: "raster"、z_index、省略可能な x、y、mask、name、opacity、blend_mode(io.Layers.BlendMode)、visible、flip_h/v、rotation、w、h |
モデル型(不透明で、通常はそのまま受け渡します)
| 型 | V3 クラス | Python 型 |
|---|---|---|
| MODEL | io.Model | ModelPatcher |
| CLIP | io.Clip | CLIP |
| VAE | io.Vae | VAE |
| CONTROL_NET | io.ControlNet | ControlNet |
| CLIP_VISION | io.ClipVision | ClipVisionModel |
| CLIP_VISION_OUTPUT | io.ClipVisionOutput | ClipVisionOutput |
| STYLE_MODEL | io.StyleModel | StyleModel |
| GLIGEN | io.Gligen | ModelPatcher(Gligen をラップ) |
| UPSCALE_MODEL | io.UpscaleModel | ImageModelDescriptor |
| BACKGROUND_REMOVAL | io.BackgroundRemoval | BackgroundRemovalModel(例:BiRefNet) |
| LATENT_UPSCALE_MODEL | io.LatentUpscaleModel | Any |
| SAMPLER | io.Sampler | Sampler |
| GUIDER | io.Guider | CFGGuider |
| HOOKS | io.Hooks | HookGroup |
| HOOK_KEYFRAMES | io.HookKeyframes | HookKeyframeGroup |
| MODEL_PATCH | io.ModelPatch | Any |
| AUDIO_ENCODER | io.AudioEncoder | Any |
| AUDIO_ENCODER_OUTPUT | io.AudioEncoderOutput | Any |
| PHOTOMAKER | io.Photomaker | Any |
| POINT | io.Point | Any |
| FACE_ANALYSIS | io.FaceAnalysis | Any |
| BBOX | io.BBOX | Any |
| SEGS | io.SEGS | Any |
3D タイプ
| タイプ | V3 クラス | Python 型 | 説明 |
|---|---|---|---|
| MESH | io.Mesh | MESH(vertices, faces) | 頂点と面のテンソルを持つ3Dメッシュ |
| VOXEL | io.Voxel | VOXEL(data) | ボクセルデータのテンソル |
| SPLAT | io.Splat | SPLAT | ガウシアンスプラットデータ |
| FILE_3D | io.File3DAny | File3D | サポートされている任意の3D形式 |
| FILE_3D_GLB | io.File3DGLB | File3D | バイナリ glTF |
| FILE_3D_GLTF | io.File3DGLTF | File3D | JSONベースの glTF |
| FILE_3D_FBX | io.File3DFBX | File3D | FBX形式 |
| FILE_3D_OBJ | io.File3DOBJ | File3D | OBJ形式 |
| FILE_3D_STL | io.File3DSTL | File3D | STL形式(3Dプリント用) |
| FILE_3D_USDZ | io.File3DUSDZ | File3D | Apple AR形式 |
| FILE_3D_PLY | io.File3DPLY | File3D | PLY(点群/スプラット) |
| FILE_3D_SPLAT | io.File3DSPLAT | File3D | .splat ガウシアンスプラットファイル |
| FILE_3D_SPZ | io.File3DSPZ | File3D | 圧縮スプラット(.spz) |
| FILE_3D_KSPLAT | io.File3DKSPLAT | File3D | .ksplat 形式 |
| FILE_3D_SPLAT_ANY | io.File3DSplatAny | File3D | 任意のスプラット形式 |
| FILE_3D_POINT_CLOUD_ANY | io.File3DPointCloudAny | File3D | 任意の点群形式 |
| SVG | io.SVG | SVG | 拡大縮小可能なベクターグラフィックス |
| LOAD_3D | io.Load3D | Model3DDict(下記参照) | レンダリングを含む3Dモデル |
| LOAD_3D_ANIMATION | io.Load3DAnimation | Load3D と同じ | アニメーション付き3Dモデル |
| LOAD3D_CAMERA | io.Load3DCamera | CameraInfo(下記参照) | 3Dカメラ情報 |
| LOAD3D_MODEL_INFO | io.Load3DModelInfo | list[Model3DTransform] | モデルごとの変換情報(位置/クォータニオン/スケール) |
Load3D.Model3DDict: {"image": str, "mask": str, "normal": str, "camera_info": CameraInfo, "recording"?: str, "model_3d_info"?: list[Model3DTransform]}
Load3DCamera.CameraInfo(右手系、Y軸上向き、カメラは-Z方向を向きます): 必須キーは position、target、zoom、cameraType('perspective' | 'orthographic')です。オプションキーは quaternion(カメラのワールド回転)、useCustomUp(bool、v0.40以降:ワールドの+Yではなくクォータニオンの上方向を使用)、fov(垂直方向、度数、透視投影のみ)、aspect、near、far、frustum(正投影のみ:{left, right, top, bottom})です。
Load3DModelInfo.Model3DTransform: ワールド空間での {"position": dict, "quaternion": dict, "scale": dict} です。
ウィジェットタイプ(UIコントロールの作成)
| タイプ | V3 クラス | Python 型 | 説明 |
|---|---|---|---|
| INT | io.Int | int | 最小値/最大値/ステップを指定できる整数 |
| FLOAT | io.Float | float | 最小値/最大値/ステップ/丸めを指定できる浮動小数点数 |
| STRING | io.String | str | テキスト(1行/複数行) |
| BOOLEAN | io.Boolean | bool | ラベル付きの切り替え |
| COMBO | io.Combo | str | ドロップダウン選択 |
| COMBO (multi) | io.MultiCombo | list[str] | 複数選択ドロップダウン |
| COLOR | io.Color | str (hex) | カラーピッカー、デフォルトは #ffffff |
| COLORS | io.Colors | list[str] (hex) | カラーパレット(色のリスト) |
| BOUNDING_BOX | io.BoundingBox | {"x": int, "y": int, "width": int, "height": int} | 矩形領域 |
| BOUNDING_BOXES | io.BoundingBoxes | list[{"x", "y", "width", "height", "metadata": dict}] | 複数のラベル付き領域 |
| CURVE | io.Curve | list[tuple[float, float]] | スプライン曲線の点 |
| RANGE | io.Range | RangeInput(最小値/最大値+任意の中間値) | グラデーション表示付きのレベル/範囲エディター |
| IMAGECOMPARE | io.ImageCompare | dict | 画像比較ウィジェット |
| WEBCAM | io.Webcam | str | ウェブカメラ撮影ウィジェット |
| HISTOGRAM | io.Histogram | list[int] | ヒストグラムのビン数 |
| VIDEO_EDIT | io.VideoEdit | {"trim"?: {start_time, duration}, "crop"?: {x, y, width, height}} | 動画のトリミング/クロップエディター(features=["trim","crop"]) |
| RESOLUTION_PREVIEW | io.ResolutionPreview | dict | 名前で他のウィジェットに紐付けられた、リアルタイムの解像度プレビュー |
| COMPOSITOR | io.Compositor | dict (LayerState) | レイヤーエディターの状態、デフォルトは {} |
| CAMERA_INFO_STATE | io.CameraInfoState | dict | カメラエディターの状態(入力のみ) |
特殊な型
| 型 | V3 クラス | 説明 |
|---|---|---|
* (ANY) | io.AnyType | 任意の型に一致します |
| COMFY_MULTITYPED_V3 | io.MultiType | 1 つの入力で複数の特定の型を受け入れます |
| COMFY_MATCHTYPE_V3 | io.MatchType | 入力と出力をまたいで汎用的な型マッチングを行います |
| COMFY_AUTOGROW_V3 | io.Autogrow | 動的に拡張する入力です |
| COMFY_DYNAMICCOMBO_V3 | io.DynamicCombo | オプションごとにサブ入力を表示するコンボです |
| COMFY_DYNAMICSLOT_V3 | io.DynamicSlot | 接続時にサブ入力を表示する接続スロットです(コアノードではまだ使用されていません) |
| COMFY_DYNAMICGROUP_V3 | (internal _DynamicGroup) | 繰り返し表示されるウィジェット行です。エクスポートされず、安定していないため、使用しないでください(v1.57.0 以降、フロントエンドでサポート) |
| FLOW_CONTROL | io.FlowControl | 内部テスト専用 |
| ACCUMULATION | io.Accumulation | 内部テスト専用 |
IMAGE 型
画像は、形状が [B, H, W, C] の torch.Tensor です。
- B = バッチサイズ(単一画像の場合は 1)
- H = ピクセル単位の高さ
- W = ピクセル単位の幅
- C = チャンネル数(RGB の場合は 3、値の範囲は 0.0〜1.0)
import torch
import numpy as np
from PIL import Image as PILImage
class ImageProcessor(io.ComfyNode):
@classmethod
def define_schema(cls):
return io.Schema(
node_id="ImageProcessor",
display_name="Image Processor",
category="image",
inputs=[io.Image.Input("image")],
outputs=[io.Image.Output("IMAGE")],
)
@classmethod
def execute(cls, image):
b, h, w, c = image.shape
result = torch.clamp(image * 1.5, 0.0, 1.0)
return io.NodeOutput(result)
画像の読み込み/保存
from PIL import ImageOps
# Load from file → tensor
def load_image(path):
img = PILImage.open(path)
img = ImageOps.exif_transpose(img) # fix rotation from camera EXIF
if img.mode == "I": # handle 16-bit images
img = img.point(lambda i: i * (1 / 255))
img = img.convert("RGB")
return torch.from_numpy(np.array(img).astype(np.float32) / 255.0).unsqueeze(0)
# Tensor → save to file
def save_image(tensor, path):
if tensor.dim() == 4:
tensor = tensor[0]
PILImage.fromarray(np.clip(255.0 * tensor.cpu().numpy(), 0, 255).astype(np.uint8)).save(path)
# Batch operations
batch = torch.cat([img1, img2], dim=0) # stack into batch
single = image[i] # extract from batch [H,W,C]
single_batch = image.unsqueeze(0) # add batch dim [1,H,W,C]
MASK 型
形状が [H, W] または [B, H, W] で、値が 0.0〜1.0 の torch.Tensor です。
# Invert mask
inverted = 1.0 - mask
# Mask ↔ Image conversion
alpha = mask.unsqueeze(0).unsqueeze(-1) # [1,H,W,1]
gray_mask = 0.299*img[:,:,:,0] + 0.587*img[:,:,:,1] + 0.114*img[:,:,:,2]
image_from_mask = mask.unsqueeze(-1).repeat(1, 1, 1, 3) # [B,H,W,3]
# Ensure batch dim
if mask.dim() == 2:
mask = mask.unsqueeze(0) # [1, H, W]
LATENT 型
型付きキーを持つ辞書です。
class LatentDict(TypedDict):
samples: torch.Tensor # [B, C, H, W] (image) or [B, C, T, H, W] (video) - required
noise_mask: NotRequired[torch.Tensor]
batch_index: NotRequired[list[int]]
type: NotRequired[str] # only for "audio", "hunyuan3dv2"
画像モデル(SD1.5、SDXL、SD3、Flux):4D [B, C, H, W] — SD1.5/SDXL は 4 チャンネル、SD3/Flux は 16 チャンネルです。潜在表現の寸法はピクセル寸法の 1/8 です。
動画モデル(Hunyuan Video、Wan、Cosmos、LTX Video、Mochi):5D [B, C, T, H, W] — T は時間(フレーム)方向の寸法です。
samples = latent["samples"]
# Check dimensionality:
if samples.ndim == 5:
B, C, T, H, W = samples.shape # video latent
else:
B, C, H, W = samples.shape # image latent
# Always preserve extra keys when modifying:
result = latent.copy()
result["samples"] = modified_samples
CONDITIONING 型
list[tuple[Tensor, PooledDict]] — (cond_tensor, metadata_dict) のペアのリストです。
PooledDict には、さまざまなモデル向けの多数の任意キーが含まれます。
class PooledDict(TypedDict):
pooled_output: torch.Tensor
control: NotRequired[ControlNet]
area: NotRequired[tuple[int, ...]]
strength: NotRequired[float] # default 1.0
mask: NotRequired[torch.Tensor]
start_percent: NotRequired[float] # 0.0-1.0
end_percent: NotRequired[float] # 0.0-1.0
guidance: NotRequired[float] # Flux-like models
hooks: NotRequired[HookGroup]
# ... many more model-specific keys (SDXL, SVD, WAN, etc.)
コンディショニングを結合するには、result = cond_a + cond_b とします(リストの連結)。
VIDEO 型
VideoInput は、次のメソッドを持つ抽象基底クラスです。
class VideoInput(ABC):
def get_components(self) -> VideoComponents # images tensor + audio + frame_rate
def save_to(self, path, format=VideoContainer.AUTO, codec=VideoCodec.AUTO, metadata=None,
bit_depth=None, # None keeps native depth
crf=None, # H.264/AV1 CRF; None -> 18 (H.264) / 24 (AV1)
color_space=None, # "sRGB" | "HDR" (BT.2020 HLG) | "HDR PQ"
preset=None) # H.264 encoder preset, e.g. "ultrafast"
def as_trimmed(self, start_time=None, duration=None, strict_duration=False) -> VideoInput | None
def as_cropped(self, x=0, y=0, width=0, height=0) -> VideoInput # clamped, even-aligned; empty/full rect = self
def get_stream_source(self) -> str | BytesIO
def get_dimensions(self) -> tuple[int, int] # (width, height)
def get_duration(self) -> float # seconds
def get_frame_count(self) -> int
def get_frame_rate(self) -> Fraction
def get_container_format(self) -> str
def get_bit_depth(self) -> int # max component bits of the stream, e.g. 8/10/12 (default 8)
def get_color_space(self) -> str # "sRGB" | "HDR" | "HDR PQ" | "auto" (unknown)
高ビット深度と HDR(v0.34 以降)は、エンドツーエンドでサポートされています。ローダーは get_bit_depth()/get_color_space() を返し、保存ノードはそれらを保持します。コーデック:Types.VideoCodec.AUTO/H264/AV1。コンテナ:Types.VideoContainer.AUTO/MP4/MKV/WEBM。
具象実装(from comfy_api.latest import InputImpl 経由):
VideoFromFile(file, *, start_time=0, duration=0, crop=None)— パスまたは BytesIO。crop=(x, y, w, h)VideoFromComponents(components, bit_depth=8, color_space="sRGB")— テンソルから作成VideoFromList(videos, complete_audio=None, codec=AUTO)— 連結(v0.36 以降)
3D 型
File3D
from comfy_api.latest import Types
# File3D wraps a 3D file (disk path or BytesIO stream)
file_3d = Types.File3D(source="/path/to/model.glb", file_format="glb")
file_3d.format # "glb"
file_3d.is_disk_backed # True
file_3d.get_data() # BytesIO
file_3d.get_bytes() # raw bytes
file_3d.save_to("/output/model.glb")
MESH、VOXEL、SPLAT
from comfy_api.latest import Types
mesh = Types.MESH(vertices=torch.tensor(...), faces=torch.tensor(...)) # (B,N,3), (B,M,3)
voxel = Types.VOXEL(data=torch.tensor(...), voxel_colors=None, resolution=None)
splat = Types.SPLAT(...) # gaussian splat data
MESH の任意フィールド(キーワードで渡してください。v0.34 で metallic_roughness が vertex_counts の前に挿入され、位置引数による呼び出しが壊れました):uvs (B,N,2)、vertex_colors (B,N,3|4)、texture (B,H,W,3 baseColor)、metallic_roughness (B,H,W,3;G=roughness、B=metallic)、vertex_counts/face_counts (B,) パディングされたバッチの実際の長さ(両方指定するか、どちらも指定しないでください)、unlit、normals (B,N,3)、tangents (B,N,4)、normal_map、occlusion_in_mr、material (dict)、emissive。
特殊機能を持つウィジェット型
Color
io.Color.Input("color", default="#ff0000", socketless=True)
# Value is a hex string like "#ff0000"
Colors(パレット)
io.Colors.Input("palette", default=["#ff0000", "#00ff00"], socketless=True)
# Value is list[str] of hex colors
BoundingBox
io.BoundingBox.Input("bbox",
default={"x": 0, "y": 0, "width": 512, "height": 512},
socketless=True,
component="my_component", # optional custom UI component
)
# Value is {"x": int, "y": int, "width": int, "height": int}
BoundingBoxes(複数領域)
io.BoundingBoxes.Input("regions", default=[], socketless=True)
# Value is list of {"x": int, "y": int, "width": int, "height": int, "metadata": dict}
Curve
from comfy_api.input import CurveInput
io.Curve.Input("curve",
default=[(0.0, 0.0), (1.0, 1.0)], # linear
socketless=True,
)
# In execute(), normalize the raw value first:
curve = CurveInput.from_raw(curve)
Range(レベルエディター)
from comfy_api.input import RangeInput
io.Range.Input("levels",
default={"min": 0.0, "max": 1.0},
display=None, # widget visualization mode
gradient_stops=None, # gradient background for the slider
show_midpoint=True, # show gamma midpoint handle
midpoint_scale=None,
value_min=0.0, value_max=1.0, # UI bounds
)
# In execute(), normalize with RangeInput.from_raw(value):
# .min_val, .max_val, .midpoint (gamma = -log2(midpoint), 0.5 = linear)
# .to_lut(size) generates a GIMP-style levels lookup table
MultiCombo
io.MultiCombo.Input("tags",
options=["tag1", "tag2", "tag3"],
default=["tag1"],
placeholder="Select tags...",
chip=True, # show as chips
)
# Value is list[str]
Webcam
io.Webcam.Input("webcam_capture")
# Value is str (captured image data)
ImageCompare
io.ImageCompare.Input("comparison", socketless=True)
# Value is dict
カスタム型
# Simple: create inline custom type
MyData = io.Custom("MY_DATA_TYPE")
# Use in inputs/outputs
io.Schema(
inputs=[MyData.Input("data")],
outputs=[MyData.Output("MY_DATA")],
)
上級:@comfytype デコレーター
型ヒントやカスタム Input/Output クラスを使うカスタム型の場合:
from comfy_api.latest._io import comfytype, ComfyTypeIO
@comfytype(io_type="MY_DATA_TYPE")
class MyData(ComfyTypeIO):
Type = dict[str, Any] # type hint for the data
RAM キャッシュのサイズ設定:デフォルトの RAM 圧力キャッシュは、出力内の CPU テンソル(リスト/タプル/辞書の内部も含む)を計測します。不透明なオブジェクトは小さなデフォルト値として扱われます。大きなテンソルを保持するカスタムクラスでは、正しくサイズが計測され、削除されるように def _comfy_cache_tensors(self): return (self.a, self.b) を追加してください(コアの MESH/VOXEL/SPLAT も同様です。v0.35 以降)。
AnyType/ワイルドカード
# Accept any single type (always a connection input, no widget)
io.AnyType.Input("anything")
# Accept specific multiple types
io.MultiType.Input("data", types=[io.Image, io.Mask, io.Latent])
# MultiType with widget override (shows widget for first type)
io.MultiType.Input(
io.Float.Input("value", default=1.0),
types=[io.Float, io.Int],
)
comfy_api.latest からのインポート
from comfy_api.latest import (
ComfyExtension, # extension registration
ComfyAPI, # runtime API (progress, node replacement)
io, # all io types (io.Image, io.Schema, io.ComfyNode, etc.)
ui, # UI output helpers (ui.PreviewImage, ui.SavedImages, etc.)
Input, # Input.Image (ImageInput), Input.Audio, Input.Mask, Input.Latent, Input.Video
InputImpl, # InputImpl.VideoFromFile, .VideoFromComponents, .VideoFromList
Types, # Types.MESH, Types.VOXEL, Types.File3D, Types.VideoCodec, etc.
)
テンソルの安全な取り扱い
テンソルの有無を確認する際は、真偽値による判定ではなく、必ず is not None を使用してください。
# CORRECT
if image is not None:
process(image)
# WRONG — multi-element tensors don't support bool()
if image: # raises RuntimeError
process(image)
# For boolean conditions on tensors, use .all() or .any()
if (mask > 0.5).all():
...
型変換パターン
# IMAGE [B,H,W,C] → MASK [B,H,W]
mask = 0.299 * image[:,:,:,0] + 0.587 * image[:,:,:,1] + 0.114 * image[:,:,:,2]
# MASK [B,H,W] → IMAGE [B,H,W,C]
image = mask.unsqueeze(-1).repeat(1, 1, 1, 3)
# Resize image tensor
import torch.nn.functional as F
resized = F.interpolate(
image.permute(0, 3, 1, 2), # [B,C,H,W] for interpolate
size=(new_h, new_w), mode='bilinear', align_corners=False
).permute(0, 2, 3, 1) # back to [B,H,W,C]
関連項目
comfyui-node-basics- ノードクラスの構造と登録comfyui-node-inputs- 入力設定の詳細(ウィジェットのオプション)comfyui-node-outputs- 出力の型と UI 出力comfyui-node-advanced- MatchType、MultiType、Autogrow、DynamicCombo