Project structure modeled on ComfyUI-Pixaroma (MIT) with original code: fail-soft module loader in __init__.py, one file per node under nodes/, per-node frontend folders under js/ with shared .mjs utilities, offline validation script, docs, and a smoke-test workflow. Phase 1 placeholder nodes: Text Box, Show Text (with JS frontend), Random Line, Image Dimensions.
3.2 KiB
3.2 KiB
Adding a node
Every node in this pack follows the same recipe. Copy it and you get a node that loads, documents itself, and survives a broken neighbor.
1. Create the node file
nodes/node_my_thing.py — one node (or one tight family of nodes) per file:
"""My Thing (AusBoss) — one-line summary of what it does."""
class AusBossMyThing:
DESCRIPTION = (
"What the node does, written for the tooltip a user reads in the "
"search menu. Mention inputs, outputs, and any gotchas."
)
CATEGORY = "🧰 AusBoss/📝 Text" # or 🖼️ Image — add new groups sparingly
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"text": (
"STRING",
{"default": "", "multiline": True, "tooltip": "..."},
),
# ("INT", {"default": 0, "min": 0, "max": 100, "tooltip": "..."})
# ("FLOAT", {"default": 1.0, "min": 0.0, "max": 10.0, "step": 0.05})
# (["choice_a", "choice_b"], {"default": "choice_a"}) # dropdown
# ("IMAGE", {"tooltip": "..."}) # BHWC float tensor batch
},
"optional": {},
}
RETURN_TYPES = ("STRING",)
RETURN_NAMES = ("text",)
OUTPUT_TOOLTIPS = ("What comes out of this slot.",)
FUNCTION = "run"
def run(self, text):
return (text,) # always a tuple, even for one output
NODE_CLASS_MAPPINGS = {"AusBossMyThing": AusBossMyThing}
NODE_DISPLAY_NAME_MAPPINGS = {"AusBossMyThing": "My Thing (AusBoss)"}
Rules of thumb:
- Class name and mapping key are
AusBoss<Name>— the mapping key is what saved workflows reference, so treat it as permanent once released. - Display name is
<Name> (AusBoss)so searching "ausboss" finds everything. - Shared backend logic goes in
nodes/_<topic>_helpers.py(the underscore prefix keeps it out of the node-file pattern match). - Nodes that display something after a run set
OUTPUT_NODE = Trueand return{"ui": {...}, "result": (...)}— seenode_show_text.py.
2. Register it
Add one line to NODE_MODULES in __init__.py:
NODE_MODULES = [
...
"node_my_thing",
]
That's the whole registration. If the module throws on import, the pack logs it and loads everything else — check the AusBoss banner in the console.
3. (Optional) frontend JS
Only needed for custom widgets, buttons, or displaying run results.
- Entry point:
js/my_thing/index.js—.jsfiles auto-load, one folder per node. - Shared utilities:
js/shared/*.mjs—.mjsfiles do not auto-load, import them from your entry point. - Never overwrite a LiteGraph prototype callback; use
chainCallbackfromjs/shared/index.mjs.js/show_text/index.jsis the working example.
4. Validate
python scripts/validate_nodes.py
Then:
- Restart ComfyUI fully (Python is only read at startup).
- Watch the AusBoss banner — your node count should tick up, no red lines.
- Confirm the class appears in
GET http://127.0.0.1:8188/object_info. - Drop the node in a tiny graph, queue it, check the output.
- If you touched JS, hard-refresh the browser tab (Ctrl+Shift+R).