npx skills add ...
npx skills add unity-technologies/skills --skill build-gtk
Builds node-based Editor tools with Unity Graph Toolkit (GTK) on Unity 6.6+: graphs, nodes, ports and validation, State Machine API tools on 6.7+, and runtime assets via a scripted importer. Use for custom graph, node or state machine editors, or migrating a GraphView tool. Not for Shader Graph, VFX Graph or Animator Controllers.
npx skills add unity-technologies/skills --skill build-gtk
Build Editor graph tools and state machine tools on Unity's Graph Toolkit module, using only its
public API in the Unity.GraphToolkit.Editor namespace.
Read these as needed. Paths are relative to this skill's folder.
references/graph-api.md — the Graph API surface: Graph, Node, port and option builders, context
and block nodes, subgraphs, variables, validation, toolbar and context menus. Read before writing any
graph-tool code.references/state-machine-api.md — the State Machine API (Unity 6.7+): StateMachine, State,
Condition, transitions and rules, self transitions, custom views. Read whenever states, transitions
or conditions are involved.references/runtime-and-visualization.md — compiling a graph or state machine into a runtime asset
with a ScriptedImporter, and showing live execution in the graph editor. Read when the user wants the
authored data used in the game or debugged at runtime.references/pitfalls.md — the mistakes that survive compilation. Read before handing off, and
whenever the user reports a compile error, an empty Add menu, a missing node, or an exception.Read m_EditorVersion in ProjectSettings/ProjectVersion.txt before writing code. Graph Toolkit is
an Editor module, so there is no package to install. com.unity.graphtoolkit is a deprecated shim
and must not be added to the manifest.
| Editor version | What is available |
|---|---|
| Older than 6000.4 | Only the retired experimental package (0.x). Its API differs from this skill. Recommend upgrading. |
| 6000.4 to 6000.5 | Module present, but without port capacity, type casting, wire and node visualization, USS node styling, or element IDs. |
| 6000.6 | The Graph API this skill documents. |
| 6000.7 and newer | Everything above plus the State Machine API, NodeView<T> / StateView<T> / ConditionView<T> custom UI, [GraphMenu] / [BlackboardMenu] context menus, the GraphLogger.GraphChanges change delta, port type-following, and Blackboard type restriction. Members marked 6.7 in the references. |
If the user asks for a state machine tool on an Editor older than 6000.7, say plainly that the State Machine API is not available there. Do not emulate it with the Graph API unless asked.
Graph Toolkit is an authoring framework only. It draws and persists graphs; it never executes them. The user writes the runtime data model and the code that runs it, usually fed by a ScriptedImporter.
One asset type per Graph or StateMachine subclass, identified by the file extension passed to
[Graph("ext")] or [StateMachine("ext")].
Discovery is by reflection. Node, state and condition classes in the same assembly as the graph
class are listed automatically. Classes in other assemblies opt in with [UseWithGraph] or
[UseWithStateMachine]. Abstract classes are never listed.
Every authoring class is [Serializable] and lives in an Editor-only assembly, either an Editor
folder or an asmdef restricted to the Editor platform.
Only the public API compiles for users. If a name from the left column appears in a draft, stop and use the right column:
| Never write | Write instead |
|---|---|
GraphModel, GraphObject, GraphTool, Stencil, BaseGraphTool | Graph and GraphDatabase |
NodeModel, PortModel, WireModel | Node, IPort, Wire |
StateModel, TransitionModel, ConditionModel | State, ITransition, Condition<T> |
GraphViewEditorWindow, GraphElementsExtensionMethodsCache, ModelView | the window is provided; NodeView<T> on 6000.7 for custom UI |
UnityEditor.Experimental.GraphView, graphViewChanged, Port.Create | no equivalent; model the tool as Graph and Node classes |
com.unity.graphtoolkit in the manifest | nothing; the module is built in |
Read references/graph-api.md now, before writing code; member names and builder chains come from
there, not from memory. Read references/runtime-and-visualization.md as well when step 5 applies.
Graph class. [Graph(AssetExtension)] [Serializable] class MyGraph : Graph with a
public const string AssetExtension. Add a [MenuItem("Assets/Create/...")] static method that
calls GraphDatabase.PromptInProjectBrowserToCreateNewAsset<MyGraph>(). Pass
GraphOptions.SupportsSubgraphs in the attribute when subgraphs are wanted.
Node classes. [Serializable] class MyNode : Node. Override OnDefinePorts and end every port
builder chain with .Build(). Override OnDefineOptions for inspector-editable settings, and read
them inside OnDefinePorts with GetNodeOptionByName(name).TryGetValue<T>(out var v) when ports
depend on them. Call .Delayed() on count-like options so ports are not rebuilt on every keystroke.
Use [Node("Category/Path", iconPath, title, stylesheet)] for placement, icon, default title and USS.
Validation. Override OnGraphChanged(GraphLogger logger) and report with
logger.LogError, LogWarning or Log, passing the offending node or port as context so the
marker appears on it. Never mutate the graph in this callback; put the fix in a GraphLogAction
attached to the message, a menu item, or the importer.
Structure, as requested. Context and block nodes, subgraphs, blackboard variables, type casting
through IsConnectionAllowed, a toolbar element, or a context menu. Details in graph-api.md.
Output. A ScriptedImporter registered on the same extension compiles the graph into a plain
runtime asset. The shape is always the same:
The runtime asset and its assembly must not reference Unity.GraphToolkit.Editor; keep Hash128
IDs as Hash128. Debug views and code-built graphs are in runtime-and-visualization.md.
Verify as described below.
Read references/state-machine-api.md now; there is no manual walkthrough for this API yet, so that
file and the Script Reference are the only accurate sources for its member names.
[StateMachine(AssetExtension)] [Serializable] class MySM : StateMachine
plus a menu item calling StateMachineDatabase.PromptInProjectBrowserToCreateNewAsset<MySM>().[Serializable] class Patrol : State. States have no ports; the state machine owns the
transitions. Options declared in OnDefineOptions appear only in the Graph Inspector.[Serializable] [Condition("Health")] class HealthCondition : Condition<float> with
protected override bool DisplayComparisonDropdown => true when a comparison operator is wanted.
Derive from Condition directly for a valueless trigger. Group (And/Or) and variable conditions are
built in; do not reimplement them.SelfTransition + [Transition(...)]), custom UI through
StateView<T> and ConditionView<T>, and [StateMachineMenu] / [ConditionMenu] entries.OnStateMachineChanged(StateMachineLogger logger). Same rules as
OnGraphChanged.ScriptedImporter loads with StateMachineDatabase.LoadStateMachineForImporter<MySM>,
then walks GetStates(), each state's GetOutgoingTransitions(), each transition's GetRules(),
and each rule's RootCondition tree. That tree always contains the built-in kinds as well as the
user's classes, so the compiler must handle IGroupCondition (recurse, honour Operation) and
IVariableCondition (Variable.Name, Comparison, Value) before matching custom Condition<T>
types.When a menu item, generator or tool builds or edits an asset, bracket the mutations:
LoadGraph/CreateGraph → UndoBeginRecordGraph("Action") → AddNode, Connect,
port.TrySetValue, CreateVariable → GraphDatabase.SaveGraph(graph) → UndoEndRecordGraph().
The state machine equivalents are UndoBeginRecordStateMachine, Connect(fromState, toState),
SaveStateMachine and UndoEndRecordStateMachine. Mutating inside OnEnable, OnDisable,
OnGraphChanged or OnStateMachineChanged throws InvalidOperationException.
| The user wants | Do this | Why |
|---|---|---|
| Limit how many wires a port accepts | .WithCapacity(PortCapacity.Single) (or Multi, None) in the port builder | Ports default to multiple wires, so the framework enforces the limit only if you declare it |
Connect an int output to a float input | Override Graph.IsConnectionAllowed(IPort output, IPort input) | Ports of different types refuse to connect by default; the graph only records the wire, your importer converts |
| One port that accepts several types, like Shader Graph | 6000.7+: .WithDataTypes(typeof(float), typeof(int), typeof(Vector3)) on the builder. 6000.6: an untyped port plus IsConnectionAllowed | WithDataTypes does not exist on 6000.6 |
| An execution-flow port with no data type | context.AddInputPort("In") with no type; its DataType is Untyped. Add .WithConnectorUI(PortConnectorUI.Arrowhead) for a flow look | Flow ports carry no value; typing them invites wrong connections |
| Hide a node type from the Add menu | Make it abstract, or move it to another assembly without [UseWithGraph], or set GraphOptions.DisableAutoInclusionOfNodesFromGraphAssembly and opt nodes in explicitly | Every concrete node class in the graph's assembly is listed automatically |
| Group nodes in the Add menu | [Node("Category/Sub")]. The class or title name is appended after the path | The attribute's first argument is a folder path, not the node's title |
Know what changed, like the old graphViewChanged | 6000.7+: OnGraphChanged and logger.GraphChanges.ChangedNodes with ChangeKinds flags for added and modified nodes. Removed nodes on any version, and everything on 6000.6: diff a cached HashSet<Hash128> of node IDs against GetNodes() | GraphChanges was added in 6000.7 and never reports removed nodes, only removed ports |
| Several kinds of subgraph | GraphOptions.SupportsSubgraphs on the main graph, [Subgraph(typeof(MainGraph))] on each subgraph Graph class | Without the attribute the main graph type doubles as the only subgraph type |
| Ports on a subgraph node | Blackboard variables of kind VariableKind.Input or Output inside the subgraph | Subgraph nodes have no OnDefinePorts; their ports mirror the subgraph's variables |
| Node icon or USS look | [Node(category, iconPath, title, stylesheet)]; d_ prefix for the dark-theme icon file | The Editor picks the d_ file in the dark theme and falls back otherwise |
| Show which node runs and what flows through ports at runtime | GraphVisualization API, see runtime-and-visualization.md | Graph Toolkit has no runtime; the game must push state back into the open window |
| An Animator-like state machine editor | Workflow B on 6000.7+. On 6000.6, explain it is not available | The State Machine API does not exist before 6000.7 |
| Extra UI inside a node | NodeView<MyNode> on 6000.7+. On 6000.6, only USS, DefaultColor and FillAmount | NodeView<T> was added in 6000.7 |
FirstConnectedPort, IsConnected), attributes take positional constructor arguments, and IDs are
Hash128. When a member is not listed in the references, look it up at the URL pattern below rather
than guessing its name or casing, because a guessed member fails to compile and the user cannot tell
a typo from a missing feature.Unity.GraphToolkit.Editor, and put visualization code inside a
runtime assembly under #if UNITY_EDITOR, because the module is Editor-only and any reference to it
breaks the player build.references/pitfalls.md and check the code against it before showing it to the user.Debug.Log lines that prove the
behaviour, such as the state entered or the node executed, enter Play mode, and read them. Remove or
guard them once the behaviour is confirmed.references/pitfalls.md and fix anything it flags.Give the user a short checklist: the files you created or changed and where they go, how to create and open the first asset, what the importer produces, and which Editor version the code targets. List what is left for them to decide or do next, such as more node types, the runtime executor, or the debug view, and any Console error you could not verify because no Editor was available.
Prefer WebFetch over WebSearch; it is faster and lands on the exact page. Only fetch what you need.
Replace <VERSION> before fetching:
docs.unity.com/en-us/engine/<VERSION> and docs.unity3d.com/<VERSION>/Documentation: the project's
Editor version from ProjectSettings/ProjectVersion.txt, for example 6000.6 or 6000.7.docs.unity3d.com/Packages/com.unity.graphtoolkit-samples@<VERSION>: the samples package
version shown in the Package Manager, for example 0.6.Pages, all under https://docs.unity.com/en-us/engine/<VERSION>/, served as markdown when the .md
suffix is kept:
manual/extending-the-editor/gtk-index.mdmanual/extending-the-editor/gtk-index/implementing-a-graph-tool.md, with
child pages implement-a-graph-tool.md, implement-nodes.md, implement-node-options.md,
implement-context-nodes.md, implement-block-nodes.md, type-cast-ports.md,
add-custom-toolbar-actions.md, add-subgraph-support.md, graph-processing.md under that foldermanual/extending-the-editor/gtk-index/landing-graph-interface.md, with
graph-window.md, blackboard.md, graph-inspector.md, minimap.md under itscript-reference/unity/graphtoolkit/editor/<type>.md and
.../<type>/<member>.md, all lowercase, generic arity dropped (condition.md for Condition<T>).
Example: script-reference/unity/graphtoolkit/editor/graph/ongraphchanged.md. State machine types
exist from 6000.7. The older form https://docs.unity3d.com/<VERSION>/Documentation/ScriptReference/Unity.GraphToolkit.Editor.<Type>.html
also resolves, as HTML.https://docs.unity3d.com/Packages/com.unity.graphtoolkit-samples@<VERSION>/manual/index.html.
Install com.unity.graphtoolkit-samples by name in the Package Manager, then import Texture Maker
(importer), Visual Novel Director (custom runtime and debug view) or Dungeon Graph Generator
(building a graph from code).