# How to Use FlowGraphFunctionAsset to Create Reusable Local Functions in Ceres

> Learn to use FlowGraphFunctionAsset in Ceres to create reusable local functions by storing subgraphs as ScriptableObjects for modular visual scripting in Unity.

- Repository: [AkiKurisu/ceres](https://github.com/akikurisu/ceres)
- Tags: how-to-guide
- Published: 2026-02-24

---

**Use `FlowGraphFunctionAsset` to store sub-graphs as Unity ScriptableObjects that can be invoked from any other flow graph via Execute Custom Function nodes, enabling modular, maintainable visual scripting.**

`FlowGraphFunctionAsset` is a core component of the Ceres visual scripting framework for Unity (akikurisu/ceres). It allows you to encapsulate complex logic into reusable functions that exist as standalone assets, rather than being embedded directly into a single graph. This article explains how to create, configure, and invoke these assets based on the actual source implementation.

## What Is FlowGraphFunctionAsset?

`FlowGraphFunctionAsset` is a **ScriptableObject** that serializes a sub-graph along with its input and output parameter metadata. According to the source in [`Runtime/Flow/FlowGraphFunctionAsset.cs`](https://github.com/akikurisu/ceres/blob/main/Runtime/Flow/FlowGraphFunctionAsset.cs) (lines 22-24), the asset stores this data in a `serializedInfo` field containing input and return parameters. When invoked, the asset's `GetFlowGraph()` method (lines 29-41) instantiates a fresh `FlowGraph` instance from this serialized data, allowing the function to execute in isolation while maintaining access to the parent graph's context.

## Architecture Overview

The system relies on three primary components working together:

- **`FlowGraphFunctionAsset`** (Runtime): Holds the serialized sub-graph and parameter definitions. Located at [`Runtime/Flow/FlowGraphFunctionAsset.cs`](https://github.com/akikurisu/ceres/blob/main/Runtime/Flow/FlowGraphFunctionAsset.cs).

- **`FlowGraphFunctionRegistry`** (Editor): Scans the project for all function assets and maintains a lookup table. When assets change, the static `OnFunctionUpdate` event (lines 40-42 in [`Editor/Flow/FlowGraphFunctionRegistry.cs`](https://github.com/akikurisu/ceres/blob/main/Editor/Flow/FlowGraphFunctionRegistry.cs)) clears the cache. The `GetFlowGraphFunctions(Type runtimeType)` method (lines 57-61) filters functions by compatible runtime type.

- **`FlowNode_ExecuteCustomFunction`** (Runtime): The base execution node that resolves the asset reference and runs the sub-graph. Found in [`Runtime/Flow/Models/Nodes/CustomFunctions/FlowNode_ExecuteCustomFunction.cs`](https://github.com/akikurisu/ceres/blob/main/Runtime/Flow/Models/Nodes/CustomFunctions/FlowNode_ExecuteCustomFunction.cs), this node stores the asset reference in `functionAsset` (lines 18-19) and caches the compiled sub-graph using a `WeakReference` during `Compile()` (lines 63-68).

## Creating a FlowGraphFunctionAsset

### Step 1: Create the Asset

Right-click in the Unity Project window and select **Create → Ceres → Flow Graph Function**. This creates a new `FlowGraphFunctionAsset` file. The inspector will display an empty sub-graph editor where you can build your function logic.

### Step 2: Define Inputs and Outputs

Open the asset and use the blackboard to add ports:

- Click **+ Function** to add a **Custom Function Input** node for each parameter.
- Add a **Custom Function Output** node to define the return value.

These definitions are serialized into the asset's `serializedInfo` field. The parameter types and names defined here determine the port layout when the function is invoked from other graphs.

### Step 3: Configure the Runtime Type (Optional)

If the function should only be available to specific graph types (e.g., only `ActorFlowGraph` or `ComponentFlowGraph`), select the appropriate **Runtime Type** in the asset inspector. The `FlowGraphFunctionRegistry` uses this filter in `GetFlowGraphFunctions()` to ensure type safety across your project.

## Using FlowGraphFunctionAsset in Other Graphs

Once created, you can invoke the function from any compatible flow graph:

1. **Via Node Search**: Press `Ctrl+Space` (or `Space`) in the graph editor and type the function name. Select **Execute Flow Graph Function** to create an execution node.

2. **Via Blackboard**: In the target graph's blackboard, click **+** → **Function** → select your asset. This creates a local function reference.

The generated node (based on `FlowNode_ExecuteCustomFunction`) automatically exposes input ports matching your function's parameters and an output port for the return value. At runtime, the node resolves the `functionAsset` reference, calls `GetFlowGraph()` to obtain the sub-graph instance, and executes it via `functionGraph.ExecuteEventAsyncInternal`.

## Code Examples

### Example: Creating a Simple AddInts Function

While the asset is created through the Unity Editor, the resulting structure contains this logical definition:

```csharp
// Conceptual representation of the serialized sub-graph in FlowGraphFunctionAsset
// File: Runtime/Flow/FlowGraphFunctionAsset.cs

public class AddIntsFunction : FlowGraphFunctionAsset
{
    // serializedInfo stores:
    //   Input Parameter: int a
    //   Input Parameter: int b  
    //   Return Parameter: int result
    
    // GetFlowGraph() creates instance with:
    //   CustomFunctionInput node (ports: a, b)
    //   Add node (a + b)
    //   CustomFunctionOutput node (port: result)
}

```

### Example: Executing from Another Graph

To call this function from C# or within another graph's logic:

```csharp
using Ceres.Graph.Flow.CustomFunctions;
using Cysharp.Threading.Tasks;

// This node class is automatically generated or can be manually defined
// to match the function signature: (int, int) -> int
public sealed class FlowNode_CallAddInts : FlowNode_ExecuteCustomFunctionTReturn<int, int, int>
{
    // The base class handles:
    // 1. Reading functionAsset reference
    // 2. Passing inputs via PreExecuteCustomFunction (adds to evt.Args)
    // 3. Executing sub-graph via ExecuteEventAsyncInternal
    // 4. Writing return value via PostExecuteCustomFunction
}

```

### Example: Custom Node Implementation

If you need to manually wire the execution without the generic base class:

```csharp
using Ceres.Graph.Flow;
using Ceres.Graph.Flow.CustomFunctions;
using UnityEngine;

public class MyCustomFunctionCaller : FlowNode
{
    [SerializeField]
    private FlowGraphFunctionAsset functionAsset;
    
    private WeakReference<FlowGraph> _cachedGraph;
    
    public override void Compile(FlowGraphCompilationContext context)
    {
        // Cache the compiled sub-graph
        if (_cachedGraph == null || !_cachedGraph.TryGetTarget(out _))
        {
            var subGraph = context.AddOrCreateFunctionSubGraph(functionAsset);
            _cachedGraph = new WeakReference<FlowGraph>(subGraph);
        }
        base.Compile(context);
    }
    
    protected override async UniTask ExecuteAsync(FlowGraphContext ctx)
    {
        // Resolve and execute
        if (_cachedGraph.TryGetTarget(out var graph))
        {
            await graph.ExecuteEventAsyncInternal(ctx.Event);
        }
    }
}

```

## Key Source Files

| File | Purpose | Location |
|------|---------|----------|
| [`FlowGraphFunctionAsset.cs`](https://github.com/akikurisu/ceres/blob/main/FlowGraphFunctionAsset.cs) | Defines the ScriptableObject that stores sub-graphs and parameter metadata. Implements `GetFlowGraph()` for runtime instantiation. | [`Runtime/Flow/FlowGraphFunctionAsset.cs`](https://github.com/akikurisu/ceres/blob/main/Runtime/Flow/FlowGraphFunctionAsset.cs) |
| [`FlowGraphFunctionRegistry.cs`](https://github.com/akikurisu/ceres/blob/main/FlowGraphFunctionRegistry.cs) | Editor-only singleton that scans for function assets and maintains a type-filtered lookup table. Handles cache invalidation via `OnFunctionUpdate`. | [`Editor/Flow/FlowGraphFunctionRegistry.cs`](https://github.com/akikurisu/ceres/blob/main/Editor/Flow/FlowGraphFunctionRegistry.cs) |
| [`FlowNode_ExecuteCustomFunction.cs`](https://github.com/akikurisu/ceres/blob/main/FlowNode_ExecuteCustomFunction.cs) | Abstract base node that resolves `functionAsset` references and manages sub-graph execution. Uses `WeakReference` caching during compilation. | [`Runtime/Flow/Models/Nodes/CustomFunctions/FlowNode_ExecuteCustomFunction.cs`](https://github.com/akikurisu/ceres/blob/main/Runtime/Flow/Models/Nodes/CustomFunctions/FlowNode_ExecuteCustomFunction.cs) |
| [`flow_advanced.md`](https://github.com/akikurisu/ceres/blob/main/flow_advanced.md) | Documentation covering local vs. shared functions, UI workflows, and screenshots. | `Documentation~/docs/flow_advanced.md` |

## Summary

- **FlowGraphFunctionAsset** is a Unity ScriptableObject that encapsulates reusable sub-graphs with defined inputs and outputs.
- Create assets via **Create → Ceres → Flow Graph Function**, then define parameters using Custom Function Input/Output nodes.
- The **FlowGraphFunctionRegistry** automatically discovers assets in the editor, while **FlowNode_ExecuteCustomFunction** handles runtime execution with weak-reference caching.
- Reference functions in other graphs through the node search or blackboard to expose typed input and output ports automatically.

## Frequently Asked Questions

### How do I create a FlowGraphFunctionAsset in Unity?

Right-click in the Project window and select **Create → Ceres → Flow Graph Function**. This creates a new asset file that you can open in the graph editor to define your function logic and parameters.

### What is the difference between a local function and a FlowGraphFunctionAsset?

A **local function** is embedded directly within a specific flow graph and can only be called from that graph. A **FlowGraphFunctionAsset** is a standalone ScriptableObject that can be referenced and executed from any compatible flow graph across your entire project, enabling true reusability.

### How does Ceres cache function graphs for performance?

During compilation, `FlowNode_ExecuteCustomFunction.Compile()` stores the instantiated sub-graph in a `WeakReference<FlowGraph>`. This ensures the graph is built only once per compilation pass while allowing garbage collection if the reference is no longer needed, balancing performance with memory efficiency.

### Can I restrict a FlowGraphFunctionAsset to specific graph types?

Yes. In the asset inspector, you can assign a specific **Runtime Type** (e.g., `ActorFlowGraph` or `ComponentFlowGraph`). The `FlowGraphFunctionRegistry` filters available functions based on this type in `GetFlowGraphFunctions(Type runtimeType)`, ensuring type safety across your project.