> For the complete documentation index, see [llms.txt](https://docs.allout.game/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.allout.game/data-and-persistence/ao-serialize.md).

# @ao\_serialize

Select fields for scene, Inspector, and JSON serialization.

`@ao_serialize` is the annotation you place on struct/class fields to opt them into the engine's serialization system. Adding this allows you to edit script fields in the editor for easy customization and is also required if you intend to use JSON serializations/save data for structs.

```go
Enemy :: class : Component {
    // Saved, shown in inspector, included in scene data
    @ao_serialize max_health: int;
    @ao_serialize patrol_radius: float;

    // Runtime-only — not saved, not in inspector
    current_target: v2;
    aggro_timer: float;
}
```

## What it does

When you mark a field with `@ao_serialize`, the engine will:

1. **Show it in the inspector** so you can edit it on entities in the editor.
2. **Include it in JSON serialization** (`Save.set_json` / `Save.try_get_json`).

Fields without `@ao_serialize` exist only in memory at runtime. They start from their normal initializer each time the component is created, but are not included in scene or JSON serialization.

## Supported types

`@ao_serialize` works with all common CSL types:

| Type              | Example                                                              |
| ----------------- | -------------------------------------------------------------------- |
| Integers          | `s8`, `s16`, `s32`, `s64` / `int`                                    |
| Unsigned          | `u8`, `u16`, `u32`, `u64` / `uint`                                   |
| Floats            | `f32` / `float`, `f64`                                               |
| Booleans          | `bool`                                                               |
| Strings           | `string`                                                             |
| Vectors           | `v2`, `v3`, `v4`                                                     |
| Enums             | Any user-defined enum                                                |
| Fixed arrays      | `[N]T`                                                               |
| Dynamic arrays    | `[..]T`                                                              |
| Structs / classes | Nested types (their `@ao_serialize` fields are included recursively) |
| Engine references | Entities, components, and assets where supported                     |

{% hint style="info" %}
For nested structs/classes, only the fields marked `@ao_serialize` inside the nested type are serialized. The annotation doesn't cascade — you must mark each field individually.
{% endhint %}

## Using with components

The most common use is on component fields. These become editable in the editor's inspector and are saved as part of the scene.

```go
Chest :: class : Component {
    @ao_serialize capacity: int;
    @ao_serialize loot_table: string;
    @ao_serialize is_locked: bool;

    // Runtime state — no need to serialize
    has_been_opened: bool;
}
```

You can set `capacity`, `loot_table`, and `is_locked` per-entity in the editor. When the scene loads, those values are restored automatically.

## Using with the Save system

`@ao_serialize` also controls which fields are included when you use the JSON save APIs. Only marked fields are written to JSON.

```go
Player_Progress :: class {
    @ao_serialize version: s64 = 1;
    @ao_serialize xp: s64;
    @ao_serialize level: s64 = 1;
    @ao_serialize unlocked_skins: [..]string;
}

// Save
Save.set_json(player, "progress", ref progress);

// Load
progress := new(Player_Progress);
if !Save.try_get_json(player, "progress", ref progress) {
    // New player — the class defaults are already initialized.
}
```

For full details on the Save system, see [Save System](/data-and-persistence/save.md) and [JSON Serialization](/data-and-persistence/json.md).

## Using with standalone JSON

You can serialize any annotated type to/from a JSON string, independent of the Save system:

```go
config: My_Config;
config.difficulty = 3;

json_str := JSON.serialize(ref config);
// json_str contains only @ao_serialize fields

loaded: My_Config;
JSON.try_deserialize(json_str, ref loaded);
```

## Default values and schema changes

Class fields can have constant inline defaults. Put `@ao_serialize` before the field declaration:

```go
Player_Progress :: class {
    @ao_serialize version: s64 = 2;
    @ao_serialize max_health: int = 100;
    @ao_serialize unlocked_skins: [..]string;
}
```

When a serialized field is missing, class deserialization keeps that field's default. Unknown fields are ignored. Struct fields cannot have inline defaults, so initialize a struct before deserializing when it needs non-zero values.

Fixed-array deserialization is bounded by the destination size. Extra JSON items are ignored. If the input is shorter, untouched elements keep their initialized values.

## What NOT to serialize

Not every field should be serialized. Leave `@ao_serialize` off fields that are:

* **Derived at runtime** (positions computed each frame, cached lookups)
* **Temporary state** (timers, cooldown counters, frame-local flags)
* **Large data that changes every frame** (unnecessary save overhead)

A good rule of thumb: if the value is set once (in the editor or on load) and rarely changes, serialize it. If it's recomputed every frame, don't.

Marking a component field does not by itself persist runtime changes across sessions. Use Save, Economy, or Inventory when that persistence is required.

## Common patterns

### Enums for mode selection

```go
AI_Mode :: enum {
    IDLE;
    PATROL;
    CHASE;
}

Guard :: class : Component {
    @ao_serialize mode: AI_Mode;
    @ao_serialize patrol_speed: float;
}
```

### Nested structs

```go
Spawn_Point :: struct {
    @ao_serialize position: v2;
    @ao_serialize radius: float;
}

Spawner :: class : Component {
    @ao_serialize points: [..]Spawn_Point;
    @ao_serialize spawn_interval: float;
}
```

### Asset references

Some fields reference engine assets (textures, prefabs, sounds). These are serialized as asset identifiers and resolved automatically on load. See the built-in components (like `Sprite_Renderer`) for examples.
