# Extending Visual Script

!!! note "Summary"
    Visual Script discovers custom nodes and system integrations from compiled C# types. Choose an extension point by whether the new type performs work, computes a value, observes an event, stores data, or configures the project.

## The extension points

<div class="grid cards" markdown>

- **[Instruction](instructions.md)** — perform an action from an Instructions list.
- **[Condition](conditions.md)** — evaluate a synchronous guard.
- **[Trigger](triggers.md)** — start an Event when an external event occurs.
- **[Signal](signals.md)** — provide a source for an existing value type.
- **[Variable value](variables.md)** — add a type that variables can store.
- **[Memory](save/memories.md)** — capture state from a component you don't own.
- **[ISaveLoad](save/isaveload.md)** — make your component or asset save itself.
- **[Storage](save/storage.md)** — write save data to another backend.
- **[Serializer](save/serializers.md)** — change the save-data format.
- **[Encryption](save/encryption.md)** — transform serialized save data before storage.
- **[Settings](settings.md)** — add project configuration to the Settings window.

</div>

You don't need to register the type. The editor discovers it by reflection after compilation.

## Choose by behavior

Choose the narrowest extension point that matches the behavior.

### Instruction or Signal?

If it **does** something, it's an Instruction. If it **computes** something, it's a Signal.

Use a Signal for a value that callers can read repeatedly without changing state. Bindings may read it every frame, so side effects would make the result depend on how often it's evaluated.

### Condition or Signal?

A **Bool** Signal and a Condition can express the same check. Prefer the Signal when the value is useful in other boolean fields, including inside other Signals. Write a Condition when the check reads more clearly as a guard in a Conditions list.

### Trigger or binding?

Before writing a Trigger, check whether a **Bool** or **Number** Signal plus an existing change Trigger provides the behavior you need. Designers can reuse the Signal in other fields, while a Trigger only works at the top of an Event.

## Where custom nodes live

You can keep custom nodes anywhere in your project, in an assembly that references `VisualScript.Runtime.Core`. There's no required folder.

Nodes installed from the [Registry](../../registry/index.md) go under `Assets/Visual Script`, sorted by kind. Keeping project nodes nearby separates them from general project code. Publishing moves a node into that folder.

## Before you write one

!!! tip "Check the Registry before creating a node"
    The [Registry](../../registry/index.md) may already contain the required node. An existing implementation also provides verified attributes and base-class usage when it needs adaptation.

Also check whether existing nodes compose into the required behavior. Two nested Signals often replace a new source.

## Keeping them maintainable

- **Keep one behavior per node.** Split a node when a mode changes its fundamental operation.
- **Document with attributes.** `[Description]`, `[Parameter]`, and `[Keywords]` make the node searchable and explain its fields. See [Conventions](../conventions.md).
- **Take Signals instead of literals.** `GetGameObject` lets a field resolve **Target**, variables, and lookups; `GameObject` accepts only a fixed reference.
- **Write a title that reads as English.** The title is the node's collapsed representation in an Event.

## Where to go next

- **[Custom Instructions](instructions.md)** — start with the base pattern shared by other nodes.
- **[Conventions](../conventions.md)** — apply attributes, serialization, naming, and titles.
- **[Args](../args.md)** — pass execution context into custom nodes.
