Conventions#
Every Visual Script node follows shared attribute, serialization, naming, and title conventions. Matching them makes custom nodes discoverable by editor search, the help window, and Registry publishing.
Attributes#
Attributes on the class supply everything the editor needs to present a node.
Identity#
| Attribute | Supplies |
|---|---|
[Title("…")] |
The display name. |
[Description("…")] |
One or two sentences on what it does. |
[Category("Path/To/Node")] |
Where it sits in the dropdown, using / as a separator. |
[Image(typeof(IconX), ColorTheme.Type.Y)] |
The icon and its tint. An optional third argument adds a badge. |
[Category] also determines the search path, so you can find Debug/Log Text by typing either word.
Documentation#
| Attribute | Supplies |
|---|---|
[Parameter("Name", "Description")] |
One per configurable field. Repeatable. |
[Keywords("…", "…")] |
Extra search terms. Repeatable. |
[Note("…")] |
A caveat shown in the help window. Repeatable. |
[Dependency("Name", "url")] |
Something the node needs. Repeatable. |
[Version(1, 0, 0)] |
The node's own version. |
[Documentation("url")] |
A link to external documentation. |
[MadeWithAI] |
Declares the node was AI-generated. |
These attributes populate the in-editor help window, search index, and Registry listing. Complete attributes keep the node's documentation beside its configuration.
One behavior needs one description
Write [Description] and [Parameter] before the body. If one description can't name the behavior directly, split the node into smaller operations.
Layout#
| Attribute | Effect |
|---|---|
[Inline("m_Field")] |
Draws a field inline with the title. |
[NestInnerList("m_Field")] |
Draws a nested Conditions list. |
[NestOuterList("m_Field")] |
Draws a nested Instructions list at the outer indentation. |
[Color(ColorName.X)] |
Tints the node's title text. |
Signal-specific#
| Attribute | Marks the type as |
|---|---|
[Get] |
Available in Get dropdowns. |
[Set] |
Available in Set dropdowns. |
A Signal type with neither attribute doesn't appear in a dropdown. Leave both off only for an internal base class.
Serialization#
Visual Script uses Unity's serializer. Choose the field attribute based on whether the field stores a concrete type or a selectable implementation:
| Use | For |
|---|---|
[SerializeField] |
Concrete types: primitives, structs, Signal wrappers such as GetString. |
[SerializeReference] |
Polymorphic fields, where the actual type is chosen from a dropdown. |
Mark every node class [Serializable], because the component stores its instances inside a [SerializeReference] array.
Don't rename or move a published node's class
[SerializeReference] stores the type's assembly-qualified name. Renaming the class, namespace, or assembly orphans every existing reference. Affected entries return as null in scenes and prefabs.
If you must rename, use Unity's [MovedFrom] attribute to preserve the mapping.
Naming#
Use the framework's naming conventions to avoid collisions and keep type roles visible:
| Element | Convention |
|---|---|
| Private serialized fields | m_PascalCase |
| Instruction classes | Instruction<Area><What> |
| Condition classes | Condition<Area><What> |
| Trigger classes | Trigger<Area><What> |
| Signal type classes | Type<ValueType><Source> |
Prefix project nodes with a short project or vendor tag, such as InstructionAcmeSpawnWave. Class names must be unique across built-in, project, and Registry assemblies.
Titles#
Every node implements GetTitle(GameObject source), which returns the collapsed line shown in an Event. This implementation includes the configured String Signal:
protected override string GetTitle(GameObject source) => $"Log {this.m_Text}";Interpolating m_Text calls the Signal's ToString() and keeps the configured source visible. TextUtils provides helpers for theming a keyword, constant, or control.
Use a phrase that describes the configured operation, such as Move Target to Position. A class name such as InstructionTransformSetPosition doesn't show those choices.
Where to go next#
- Args — follow the context every node receives.
- Extending — write each kind of node.
- Publishing — turn these attributes into a Registry listing.