Documentation index for AI agents (llms.txt) A Markdown version of every page is available: request the page's source under /docs/, follow the "alternate" link in this page's head, or start from /llms.txt.
Visual Script logo Scripting API

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:

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 and Global Variables.

Cloning matters#

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

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 with variable get and set sources Designers can read and write it
A Condition comparing two of them Designers can branch on it
A PropertyDrawer for the type Designers can edit the value in the Inspector
A Memory, 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.

Where to go next#

  • Custom Signals — add the Get and Set sources a new type needs.
  • Variables — inspect the designer-facing containers.
  • Custom memories — persist values that need explicit reconstruction.
Visual Script logoVisual Script © Catsoft Works 2026. All rights reserved.