Custom Nodes

Create and use your own nodes by placing Python files in the custom nodes folder

Custom Nodes

What are Custom Nodes?

Custom nodes allow you to extend GM_Visual with your own Python code. Unlike built-in nodes (which are part of the repository), custom nodes live in a dedicated folder in your user profile. This means:

Custom Nodes Folder

The default custom nodes directory is created automatically at installation time:

%APPDATA%\GM_Visual\custom_nodes\

On a typical Windows installation this expands to:

C:\Users\<your_username>\AppData\Roaming\GM_Visual\custom_nodes\
Tip: The folder is created the first time you run GM_Visual (or run python install.py). If it is missing, run python install.py repair to recreate it.

Folder Structure

Custom nodes are organised the same way as built-in nodes: a subcategory folder inside the root custom nodes directory, containing one .py file per node:

custom_nodes\
├── demo\
│   ├── __init__.py
│   └── hello_custom_node.py   ← demo node (auto-generated)
├── my_category\
│   ├── __init__.py
│   ├── my_first_node.py
│   └── my_second_node.py
└── __init__.py

Each subfolder of custom_nodes\ becomes a subcategory visible in the Custom nodes section of the Node Library panel.

Finding Custom Nodes in the Node Library

  1. Open GM_Visual and look at the Node Library tab in the right panel.
  2. In the Category dropdown, select Custom nodes.
  3. The subcategories that correspond to your subfolders appear below.
  4. Expand a subcategory to see the available nodes.
  5. Drag a node button onto the canvas — or double-click it — to add it.
Note: The Custom nodes category is always visible, even if the folder is empty.

Creating a Custom Node

Each node file must follow this template. The file name becomes the node identifier.

Minimum template

"""
MyNode - short description.
"""
from core import NodeBase, PinType


class MyNode(NodeBase):
    """One-line description."""

    def __init__(self, node_id: str):
        super().__init__(
            node_type="MyNode",
            name="My Node",
            description="What this node does.",
            version="1.0.0",
            author="Your Name",
            category_tags=["custom"]
        )
        self.node_id = node_id
        self._initialize_pins()

    def _initialize_pins(self) -> None:
        self.add_input_pin("value_in", PinType.FLOAT, description="Input value")
        self.add_output_pin("value_out", PinType.FLOAT, description="Output value")

    def _execute_impl(self) -> None:
        val = self.get_input_value("value_in", default=0.0)
        self.set_output_value("value_out", val * 2.0)

    def get_display_text(self) -> str:
        return "My\nNode"


def create_my_node_node(node_id: str) -> MyNode:
    """Factory function - REQUIRED. Name must be: create_{file_name}_node"""
    return MyNode(node_id=node_id)

Key rules

Available Pin Types

Import PinType from core and use the following constants (defined in src/core/pin_system.py):

Basic types

ConstantValue stringDescription
PinType.INTEGER"int"Integer number
PinType.FLOAT"float"Floating-point number
PinType.STRING"str"Text string
PinType.BOOLEAN"bool"Boolean (True / False)
PinType.ANY"any"Accepts any data type
PinType.NONE"none"No data — trigger / event pin only

Container types

ConstantValue stringDescription
PinType.LIST"list"Generic Python list
PinType.DICT"dict"Generic Python dictionary
PinType.LIST_OF_FLOATS"list_of_floats"List of float values
PinType.LIST_OF_INTS"list_of_ints"List of integer values
PinType.LIST_OF_STRINGS"list_of_strings"List of strings
PinType.LIST_MIXED"list_mixed"List of mixed types

Signal / domain types

ConstantValue stringDescription
PinType.DFTM"dftm"DataFrame Time — time-series signal (GM_modules.Signals)
PinType.DFTB"dftb"DataFrame Table — tabular signal data (GM_modules.Signals)
PinType.MATERIAL"material"Material object (GM_modules.Materials)

Ansys DPF types

ConstantDescription
PinType.ANSYS_DPF_MODELAnsys DPF Model object
PinType.ANSYS_DPF_MESHED_REGIONAnsys DPF Meshed Region object
PinType.ANSYS_DPF_FIELDS_CONTAINERAnsys DPF Fields Container object
PinType.ANSYS_DPF_TIME_SCOPINGAnsys DPF Time Scoping object
PinType.ANSYS_DPF_SCOPINGAnsys DPF Mesh Scoping object
Note: Use PinType.ANY when your node can accept or produce any data type. For most custom nodes, the basic types (INTEGER, FLOAT, STRING, BOOLEAN) and container types (LIST, DICT) are sufficient.

Demo Node

A demo node is automatically generated at:

%APPDATA%\GM_Visual\custom_nodes\demo\hello_custom_node.py

This node outputs the constant string "Hello from Custom Node!" and serves as a working example you can copy and modify.

Troubleshooting

My node does not appear in the library

Error when dropping the node on canvas

custom_nodes folder is missing

Run the repair command from the GM_Visual directory:

python install.py repair
Important: Do not rename or move the demo subfolder. It is recreated automatically during repair if deleted.