# 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](../registry/index.md) 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.

!!! tip "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.

!!! warning "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:

```cs
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](args.md)** — follow the context every node receives.
- **[Extending](extending/index.md)** — write each kind of node.
- **[Publishing](../registry/publishing.md)** — turn these attributes into a Registry listing.
