# Custom variable types

Variables store a fixed set of built-in entry types. A custom **variable value** class adds another type that designers can store, compare, list, and save.

## When you need one

Prefer an existing type when it already carries the required data:

| Instead of a new type | Consider |
| :--- | :--- |
| A data asset of your own | **Scriptable Object**, which accepts any asset |
| A reference to a component | **Game Object**, then resolve the component |
| A small struct | Several entries, or a **String** you parse |
| An enum | A **Number** or a **String** |

**Scriptable Object** accepts any data asset and exposes it to designers without a custom variable type.

Write a new type when designers need to store, compare, list, and save the value across multiple systems.

## Writing one

Derive from `TVariableValue<T>`. This example assumes you've already defined the `MyThing` type you want to store:

```cs
using System;
using UnityEngine;
using VisualScript.Icons;
using VisualScript.Runtime;

[Title("My Thing")]
[Image(typeof(IconCube), ColorTheme.Type.Blue)]

[Serializable]
public class VariableValueMyThing : TVariableValue<MyThing>
{
    [SerializeField] private MyThing m_Value;

    public override MyThing Value
    {
        get => this.m_Value;
        set => this.m_Value = value;
    }

    public override VariableValueBase Clone() => new VariableValueMyThing
    {
        m_Value = this.m_Value
    };
}
```

The type then appears in the entry-type dropdown of both [Local Variables](../../manual/variables/local-variables.md) and [Global Variables](../../manual/variables/global-variables.md).

## Cloning matters

The variable container calls `Clone()` when it initializes, creating the values it uses at runtime from the authored entries.

!!! warning "A shallow clone of a mutable object is a shared object"
    If your type is a class rather than a struct, copying the reference means every instance of the prefab shares one object. Changing it on one enemy changes it on all of them.

    Either make the type immutable, or deep-copy it in `Clone()`.

## Conversion

Variable values participate in conversion, so a Signal asking for a number can read an entry that holds something convertible. Implement conversion where it's meaningful for your type; where it isn't, the default returns the type's default value rather than throwing.

## Complete the value type

A stored value also needs ways for designers to read, edit, and use it. Add the integrations your type requires:

| Also write | So that |
| :--- | :--- |
| A [Signal type](signals.md) with variable get and set sources | Designers can read and write it |
| A [Condition](conditions.md) comparing two of them | Designers can branch on it |
| A `PropertyDrawer` for the type | Designers can edit the value in the Inspector |
| A [Memory](save/memories.md), if it isn't already serializable | It survives saving |

**Scriptable Object** already provides these integrations, which avoids maintaining a new value type and its supporting nodes.

## Saving

Variable values are serialized by the save system along with everything else in the container, so a type Unity can serialize saves without extra work. A type that holds a reference to a scene object needs the same care as any other scene reference — see [Custom memories](save/memories.md).

## Where to go next

- **[Custom Signals](signals.md)** — add the Get and Set sources a new type needs.
- **[Variables](../../manual/variables/index.md)** — inspect the designer-facing containers.
- **[Custom memories](save/memories.md)** — persist values that need explicit reconstruction.
