Developer Docs
Build Nodes. Ship Pipelines.
The complete API reference for extending Vibrante-Node. From custom BaseNode classes to the Houdini bridge, action-list pattern, and headless execution.
custom_node.py
python
1from src.nodes.base import BaseNode23class My_Node(BaseNode):4 name = "my_node"56 def __init__(self):7 super().__init__()8 # [AUTO-GENERATED-PORTS-START]9 self.add_input("file_path", "string", widget_type="text")10 self.add_input("scale", "float", widget_type="float", default=1.0)11 self.add_output("result", "any")12 # [AUTO-GENERATED-PORTS-END]1314 async def execute(self, inputs):15 path = inputs.get("file_path", "")16 scale = inputs.get("scale", 1.0)17 # your logic here — async-safe18 return {"result": path, "exec_out": True}1920def register_node():21 return My_Node
BaseNode
Custom Node
Every node inherits BaseNode. super().__init__() adds exec_in/exec_out automatically. Only add your custom ports in the AUTO block.
Key Rules
- super().__init__() adds exec_in/exec_out — do NOT add them again
- Only add custom ports inside the AUTO block
- Always return {"exec_out": True} in execute()
- register_node() must return the class, not an instance
Houdini Bridge
Full Bridge API Reference
All 18 methods available on the HouBridge singleton. Every call goes over TCP JSON-RPC to your live Houdini session.
Method
Returns
Description
bridge.ping(){"status": "ok", "version": "..."}Check connection to Houdini
bridge.create_node(parent, type, name){"path": "/obj/geo1", ...}Create a Houdini node
bridge.delete_node(path){"deleted": "/obj/geo1"}Delete a node by path
bridge.set_parm(node, parm, value){"set": True}Set a single parameter
bridge.set_parms(node, parms_dict){"set": True, "count": N}Set multiple parameters at once
bridge.get_parm(node, parm){"value": <current>}Read a parameter value
bridge.connect_nodes(from, to, out=0, in=0){"connected": True}Wire two nodes together
bridge.cook_node(path, force=False){"cooked": True}Cook a node network
bridge.run_code(code){"result": <value>}Execute Python code inside Houdini
bridge.node_info(path){"path", "type", "category", "children", ...}Get detailed node info
bridge.children(path)[{"name", "type", "path"}, ...]List child nodes
bridge.node_exists(path){"exists": bool}Check if a node path exists
bridge.set_display_flag(path, on=True){"set": True}Set display flag on a SOP
bridge.save_hip(path=""){"saved": "/path/to.hip"}Save the Houdini scene
bridge.scene_info(){"hip_file", "fps", "frame", "frame_range", ...}Get scene metadata
bridge.set_expression(node, parm, expr, lang){"set": True}Set HScript or Python expression
bridge.set_frame(frame){"frame": N}Jump to a specific frame
bridge.layout_children(path){"done": True}Auto-layout child nodes
Import:
from src.utils.hou_bridge import get_bridge. Never import hou directly. Never call hou_bridge.get_hou() — that function does not exist.Node Format
The .json Node Schema
Every node is defined by a single JSON file. Drop it in nodes/ — no plugin system, no registration, no restart required.
Port Types
stringtextText input widgetfloatfloatNumeric float widgetintintNumeric integer widgetboolcheckboxCheckbox widgetlistnullList/array dataanynullGeneric exec/data portExec Pins (white squares)
Set use_exec: true to add exec flow. Always include exec_in and exec_out in the JSON arrays. In Python, super().__init__() adds them automatically — do not add them manually.
Categories
HoudiniMayaBlenderPrismLogicMathStringFile I/OCustom
Common Mistakes to Avoid
hou.node("/obj").createNode(...)bridge.create_node("/obj", ...)result = bridge.create_node(...); result.path()result = bridge.create_node(...); path = result["path"]Adding exec_in/exec_out manuallysuper().__init__() adds them automaticallyAdding ports twice (in AUTO block + below)Add each port exactly once