Visual Effect Graph
SkillDev toolsAuthor and inspect Unity Visual Effect Graph (vfx) assets with unity-cli. Use when the user wants to read, build, or modify a .vfx graph and its systems, contexts, blocks, operators, or particle behavior, or to discover available blocks. Do not use for generic asset, material, or import operations; use `unity-asset-management` instead.
Instructions available. Your AI can read the instructions. Execution depends on the setup they require.
Account requirements not reviewed. Check the skill instructions before use; ahel provides instructions and does not run this skill.
Add ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.
Then ask your AI: use the Visual Effect Graph skill
What this skill tells your AI
The instructions your AI receives, as published by akiojin/unity-cli in .claude-plugin/plugins/unity-cli/skills/unity-vfx-graph/SKILL.md and read by ahel’s review.
With --output json, results use {success, command, data, errors, warnings}. Check the exit status and envelope success first; tool-result fields in this skill are relative to data. Read failure codes from errors[0].code; see unity-cli-usage for exit-code recovery.
Author and inspect .vfx Visual Effect Graph assets: read a graph's contexts, blocks, operators and parameters, discover the node library, and apply authoring mutations. The VFX authoring API is internal to Unity, so these operations run through dedicated bridge tools (vfx_*) rather than direct component edits. This skill is the VFX complement to unity-asset-management, which handles generic asset, material, and import operations.
Use When
- The user wants to inspect a
.vfxgraph's structure (contexts, blocks, operators, parameters, links, layout). - The user wants to discover which blocks, operators, contexts, or templates are available.
- The user wants to build or modify a graph: add/remove/link nodes, set values and settings, manage the blackboard, systems, events, subgraphs, sticky notes, groups, or canvas layout.
- The user wants to verify a graph compiles, or find out why it does not.
- The user wants to drive an exposed parameter on a live
VisualEffect(vfx_runtime), read/write VFX project settings or editor preferences (vfx_settings), or bake a Mesh into an SDF Texture3D (vfx_bake_sdf).
Do Not Use When
- The task is generic asset, material, or import work; use
unity-asset-management. - The request is about editing arbitrary serialized fields on a scene component; use
unity-gameobject-edit. (vfx_runtimeis only for VisualEffect public-API calls likeSetFloat/SendEvent.) - The work is play-mode lifecycle control or input simulation; use
unity-playmode-testing.
Preferred Flow
Prerequisite: the target project must have com.unity.visualeffectgraph installed.
The Bridge keeps it optional; VFX_PACKAGE_MISSING means to report the missing
package and obtain the user's intended package setup before authoring a graph.
Input errors return {error, code} without Console Error logs; inspect the
response before continuing. Runtime playback uses send_event with OnPlay.
- Baseline.
vfx_describe_graphbefore mutating. Note the three oracles it carries:errors(validation + compile errors, on by default),compile(outcome of the last recompile), andlayout(overlapCount+ overlapping node pairs). Write down the baselineoverlapCount: a hand-made graph often has a non-zero one (node sizes are estimated generously), and your job is to not add to it. - Discover names.
vfx_list_librarywithkind(blockdefault,operator,context,parameter,template) and afilterwhenever you are not certain of an exact descriptor name — the leading|and|_separators in names like|Set|_Colorare load-bearing. - Mutate narrowly with
vfx_apply, one op at a time. Every op response carriescompile.success; read it. If it isfalse, the graph no longer compiles —compile.exception/compile.errors/compile.logssay why. Fix that before doing anything else; never stack more ops on a broken graph. An op that returnserrorwas not applied at all. - Place what you added — mandatory; move nothing else. Add ops only keep a new node off existing ones. Before you report, run
vfx_apply op:"auto_layout". Its default scope,nodes, places only the nodes created this session — operators, and a parameter canvas node for every link made from a parameter — in free space directly left of what they feed, aligned with the consuming block's row and stacked per consumer, and moves nothing that existed before. (One exception, reported asshiftedDown: a context that grew over the next context of its own system pushes that lower part of the system down, vertically only, as a person would.) A person's canvas is theirs: re-laying out a whole system for one added block is never the right answer. Passscope:"touched"(re-lay out every system edited this session),scope:"all", orcontexts:[…]only when the user asks for a tidy-up. - Box the feature with its note. A person keeps the nodes of one feature in a group box with a sticky note explaining it; do the same for what you added:
group_nodeswith your new nodes andnote:{title, contents}creates the box and the note inside it (left of the members). ReadnonMembersInsidein the response — if the box swallows nodes that are not yours, move your own nodes closer together (move_node; nodes created this session move freely) and rungroup_nodesagain, or drop the box and keep just the note. A block cannot be grouped; name it in the note. - Verify and only then report. Re-run
vfx_describe_graphand confirm all three:compile.success == true, noerrors[]entry withtype: "Error", andlayout.overlapCountno higher than your baseline with no listed overlap involving a node you created (on a graph you built from scratch that means0). Quote those three facts in your completion report. (get_compilation_stateis C# script compilation and says nothing about a VFX graph; usecompile/ describe instead.)
Invocation: every tool runs as unity-cli raw <tool> --json '<json>'. Add --output json for a structured (parseable) result, and --port <N> to target a specific bridge (default 6400).
unity-cli raw vfx_describe_graph --json '{"assetPath":"Assets/FX/Burst.vfx"}'
unity-cli raw vfx_list_library --json '{"kind":"block","filter":"turbulence"}'
unity-cli raw vfx_apply --json '{"op":"add_block","assetPath":"Assets/FX/Burst.vfx","contextType":"Update","blockName":"Turbulence","settings":{"NoiseType":"Perlin"}}'
unity-cli raw vfx_apply --json '{"op":"add_operator","assetPath":"Assets/FX/Burst.vfx","operatorName":"Multiply"}'
unity-cli raw vfx_apply --json '{"op":"link_slots","assetPath":"Assets/FX/Burst.vfx","from":{"node":"operator","operatorIndex":0,"slot":0},"to":{"node":"block","contextType":"Update","blockIndex":0,"slot":0}}'
unity-cli raw vfx_apply --json '{"op":"add_parameter","assetPath":"Assets/FX/Burst.vfx","parameterName":"Rate","type":"Float","value":42.5,"min":0,"max":100}'
unity-cli raw vfx_describe_graph --json '{"assetPath":"Assets/FX/Burst.vfx","include":["errors"],"includeSlots":false}'
unity-cli raw vfx_apply --json '{"op":"add_block","assetPath":"Assets/FX/Burst.vfx","contextType":"Update","blockName":"Turbulence","autoCompile":false}'
unity-cli raw vfx_apply --json '{"op":"compile","assetPath":"Assets/FX/Burst.vfx"}'
unity-cli raw vfx_apply --json '{"op":"auto_layout","assetPath":"Assets/FX/Burst.vfx"}'
unity-cli raw vfx_apply --json '{"op":"group_nodes","assetPath":"Assets/FX/Burst.vfx","title":"Liquid turbulence","nodes":[{"node":"parameter","parameterIndex":12},{"node":"operator","operatorIndex":3}],"note":{"title":"Liquid turbulence","contents":"Relative-mode Perlin turbulence: Drag pulls velocity toward the noise field."}}'
Hard Rules
- Describe narrowly on a big graph. An unfiltered
vfx_describe_graphon a real graph is huge — a working hand-made graph returns ~450 KB (~112K tokens), which will swamp your context. PassincludeSlots:falseto drop the slot trees that dominate it (-61%), andinclude:[...]to keep only the top-level sections you need (include:["errors"]+includeSlots:falseis ~1K tokens). Counts andassetPathalways survive, andslotsOmitted:truemarks a filtered read so empty slot arrays are never mistaken for "no slots". Use the full describe only when you actually need slot values. - Batch edits with
autoCompile:false. Every op recompiles by default, and the cost grows with the graph — 20add_blockops cost ~34s eagerly and ~8s deferred (4.4x). PassautoCompile:falseon each op in a run of edits, then onevfx_apply op:"compile"to flush (it reportsflushedDeferred). Deferred edits live in memory until that compile — a domain reload (script recompile, play-mode enter) before it discards them, so keep a deferred run short and always close it withcompile. A deferred op response carriescompile.deferred:trueinstead of a compile summary, so rule 3 above (readcompile.success) applies to the flushingcompilecall instead. - Custom HLSL operator: at most 4 inputs. A VFX expression takes at most 4 parents, so a Custom HLSL operator whose function has 5+ parameters makes the asset stop compiling.
set_operator_setting/add_operatorrefuse such a function with a clear error; pack inputs intofloat2/3/4or split the function. Custom HLSL blocks have no such limit. - Addressing. Block ops take
contextType(first context of that type) orcontextIndex(absolute index from describe). Context ops (set_context_setting,remove_context,delete_system,set_system_name,set_bounds,link_flow/unlink_flowendpoints) takecontextTypeorindex—contextIndexis accepted as an alias everywhere. Prefer the index whenever a graph has two contexts of the same type. - New nodes take open space. Add/duplicate/insert ops and
add_sticky_noterefuse to drop a node on an existing one: if the spot is taken (auto or explicitposition) the node is moved to the nearest free space and the response sayspositionAdjusted: true. Read the returnedpositionrather than assuming the one you asked for. - Existing nodes are the person's. The default
auto_layout(scope:"nodes") never moves a node that existed before your session. The whole-system passes (touched/all/contexts) keep every existing context's x and only re-stack vertically;move_nodeon such a context keeps x and says so innote. Only a system you created this session is placed in a fresh column. - Short edges over shared nodes. Do not route one parameter node or operator across the canvas to many consumers. Give far-apart consumers their own parameter canvas node and put cheap operators beside the system they feed. The
nodespass gives every parameter link you made a node within reach of its consumer; the whole-system passes also duplicate shared operators (duplicateShared,splitParameters), so operator indices can change after them — re-describe before addressing by index. - Linked slots ignore constants.
set_slot_valueon a linked input warns (warning) —unlink_slotsfirst if you meant the constant. - Parameters must be used to survive. An exposed parameter that feeds nothing is stripped at compile and invisible at runtime (
vfx_runtimehasFloat:false). |Set|_X/Get|_Xdescriptors compose attribute blocks/operators; custom attributes are declared withadd_custom_attributeand then targeted withset_block_setting setting:"attribute".
Op Index
| Area | Ops (all vfx_apply) | Reference |
|---|---|---|
| Blocks | add_block, set_block_setting, set_block_enabled, reorder_block, move_block, duplicate_block, remove_block | ops-graph.md |
| Contexts / systems | add_context, set_context_setting, remove_context, delete_system, set_system_name, link_flow, unlink_flow, set_bounds | ops-graph.md, systems-and-events.md |
| Operators | add_operator, set_operator_setting, duplicate_operator, remove_operator, add_operator_input, remove_operator_input, set_operator_operand_type, rename_operator_input, reorder_operator_input | ops-graph.md |
| Slots / links | link_slots, unlink_slots, set_slot_value, set_slot_space, convert_to_property, convert_to_inline | ops-graph.md |
| Blackboard | add_parameter, set_parameter, rename_parameter, set_parameter_category, rename_category, reorder_category, reorder_parameter, duplicate_parameter, remove_parameter, add_custom_attribute | ops-graph.md |
| Compile / verify | compile; describe errors / compile | ops-graph.md |
| Layout / canvas | auto_layout (nodes default / touched / all / contexts), move_node, group_nodes (+ note, sticky-note members, nonMembersInside), remove_group, add_sticky_note, update_sticky_note, remove_sticky_note, reorder_sticky_note; describe layout | layout.md |
| Custom HLSL | add_block "Custom HLSL", add_operator "Custom HLSL", m_HLSLCode / m_ShaderFile / function selector | custom-hlsl.md |
| Events, subgraphs, templates, asset | GPU/output events, create_subgraph_asset, create_from_template, insert_template, designate_template, set_instancing, set_initial_event_name | systems-and-events.md |
| Runtime, settings, SDF | vfx_runtime, vfx_settings, vfx_bake_sdf | runtime-settings-sdf.md |
Examples
- "List the contexts and blocks in
Assets/FX/Burst.vfx." - "Add a Turbulence block to the Update context, set NoiseType to Perlin, and confirm it compiles."
- "Create an exposed float
Rate, drive the Constant Spawn Rate block with it, then tidy the canvas." - "Build a second particle system Init→Update→Output in this graph and confirm it is disjoint from the first."
- "Add a Custom HLSL operator that combines three floats and a float3 into a float3."
- "Why does this graph not compile?"
- "Put the graph on a VisualEffect, set
Rateto 7.5 at runtime, and read it back." - "Set the fixed time step to 0.02 in the VFX project settings."
References
- ops-graph.md: blocks, contexts, operators, slots/links, blackboard, compile/verify — parameters and semantics for every op.
- layout.md: the readable-canvas rules,
auto_layout,move_node, groups, sticky notes, and thelayoutoracle. - custom-hlsl.md: Custom HLSL blocks and operators, the 4-input operator limit, external files, function selectors, buffer/texture types.
- systems-and-events.md: building systems and variants, events (GPU/spawn/output), subgraphs, templates, instancing and initial event.
- runtime-settings-sdf.md:
vfx_runtime,vfx_settings,vfx_bake_sdf. - runtime-checklist.md: connection and instance prerequisites, runtime verification caveats.
Signals
- GitHub stars
- 106
- Forks
- 12
- Last commit
- Oct 2026
Advanced
- Item type
- skill
- Key
unity-vfx-graph-akiojin- Source
- github.com/akiojin/unity-cli