Entity types and property sets
Description: The schema layer — how a character, an item, or a quest objective knows which fields it has.

A character has a name, a role, a bio and a portrait. An item has a stack size. A kill objective has a target. All three are the same idea wearing different clothes: a thing with a set of fields, and a definition somewhere that says which fields it gets.
In Narratyr that definition is split in two. An entity type is the template — "this is what a Character is." A property set is a reusable bundle of fields that types are assembled from. And an entity is one actual thing built to that template, holding the values.
| Layer | What it is | Example |
|---|---|---|
| Property set | A named group of fields | CharacterProperties: FullName, Gender, Role, Bio |
| Entity type | A template: one or more property sets, plus how it's used and shown | Character includes CharacterProperties and RelatedEntities |
| Entity | One thing of that type, with values filled in | Mira Thorne — FullName "Mira Thorne", Role NPC |
Each layer has its own view in the left sidebar: Property Sets, Types, and Characters & Items. Most days you'll work in the last of those; the first two are where you go when the shape of something needs to change.
Why fields live in property sets
The split exists so that fields can be defined once and used by several types. A project with
Player, NPC and Merchant types doesn't want three separate definitions of "first name, last
name, role" that drift apart — it wants one CharacterProperties set attached to all three.
Adding a field to that set gives it to all three at once.
That sharing is worth being deliberate about, because it cuts both ways. When you edit a property set from inside a type that isn't its only user, the editor tells you which other types are affected and offers Make unique — that copies the set, attaches the copy to the type you're editing, and detaches the original, so you can change fields without touching anything else.
A set used by exactly one type is perfectly normal too. KillObjective holding a single TargetId
field will never be shared with anything, and that's fine — the grouping still shows up in the
editor and in your exported code.
Property sets
A property set has a name, an optional description, and a list of fields. It also has a folder path, so the Property Sets view is a tree you can organise the way you organise everything else.
The name is an identifier — letters, digits and underscores, no spaces — because exporters use it directly as the name of a generated class or struct. Pick it the way you'd name a type in code.
Fields
A field looks a lot like a variable: a name, a type, and a default value. The difference is where the value lives. A variable holds one value for the whole game; a field holds a different value on every entity that has it.
Fields cover the same types variables do — text, number, whole number, true/false, an option set, a reference to another entity, and lists or sets of those — plus one variables don't have: an asset, so a type can carry an image, a sound, or any other file in your project.
A few per-field switches change how the field behaves in the editor and in export:
- Required — the validator reports an error for any entity that leaves it empty. Nothing stops you saving in the meantime; it's a check, not a lock.
- Multiline and Rich Text — how a text field is edited. Both apply to text fields only.
- Translatable — marks a text field as player-facing content that needs localising, as opposed to an internal note.
An entity-reference field can be narrowed to a specific entity type, so a Merchant field that
should point at a shop location offers locations rather than every entity in the project. A list
or set of entity references models "many of these" — a character's known associates, an
objective's several targets.
Fields are for what belongs to a specific thing; variables are for what belongs to the world. A character's role is a field. Whether the player has met that character is a variable.
Entity types
A type is mostly a list of the property sets it includes. Its fields are the union of every attached set, in the order the sets are listed — drag them to reorder, and the entity editor follows, showing one labelled group per set.
Alongside that, a type carries:
| Setting | What it does |
|---|---|
| Name | An identifier, used in the editor and as the generated class name on export |
| Description | A note to yourself; shown as a tooltip in the type list |
| Usage | What kind of thing this type describes — see below |
| Color and Icon | How instances of the type are shown in the editor. The icon is an image asset from your project |
| Associated Option Set/Entry | Pairs the type with one entry of an option set, for the dispatch pattern below |
Types aren't organised in folders. The Types view lists them grouped by usage and sorted by name, which is short enough to scan even in a large project.
Usage: not everything is a character
The Usage setting is the part that surprises people. Entity types don't only describe things in your game world — the same schema machinery is what lets graph nodes carry custom data. A type's usage says which of those jobs it's doing, and the editor only offers it where it fits.
| Usage | Describes |
|---|---|
entity |
An ordinary thing — a character, a location, a piece of lore. Created in Characters & Items |
item |
The same, marked as an inventory item |
dialogue_node |
A variant of a dialogue node — a narrator line that carries an intonation, say. Chosen per node in its properties |
quest_node |
Extra data on a quest graph's Quest Node |
quest_objective_data |
The fields one kind of objective needs — a target to kill, an item and a count to fetch |
custom_node |
The payload of a custom node: the data your game receives with the event |
graph_metadata |
Per-graph metadata on a quest or dialogue, picked as that graph's Metadata Type |
performance |
Reserved for the built-in Performance type, which supplies the delivery fields on dialogue nodes |
Two consequences worth knowing:
- Only
entityanditemtypes are referenceable. An entity-reference variable or field offers characters and items, never node-shaped types — those describe the shape of a node, not something addressable in your world. In the Characters & Items Add menu, the same split is why the supporting types appear greyed out below the ones you actually create. - The Performance type is created for you and can't be deleted. Its property sets are yours to edit, though: whatever fields you put on it are the ones every dialogue node's performance offers.
Pairing a type with an option set
quest_objective_data types use the associated option set to work out which fields go with which
kind of objective. An Objective node asks you to pick an Objective Type from an option set —
Kill, Fetch, TalkTo — and the editor then looks for the type whose associated entry matches
the one you picked, and shows that type's fields. Pick Kill and you get KillObjective's
target field; pick Fetch and you get an item and a count.
So adding a new kind of objective to a project is two steps rather than a code change: add an entry to the option set, then add an entity type that points at it and carries the fields that kind of objective needs.
Changing a schema later
Schemas move as a project grows. What's safe and what isn't:
- Renaming is safe. Values are stored against a field's internal id, not its name, so renaming a field — or a property set, or a type — never disturbs the values already filled in. See Documents and the file format for how that's stored.
- Adding a field is safe. Every entity of every type that includes the set gains it. Entities created afterwards start from the field's default value; ones that already existed show it empty until you fill it in.
- Detaching a property set from a type is reversible. The fields stop appearing, but the values stay on the entities — re-attach the set and they're back.
- Deleting a field or a property set removes data. The stored values go with it, on every entity and every graph node that used it. Undo covers you until you save; after that, source control does.
- An entity's type is fixed once it exists. Narratyr stores entities in a folder per type, so a character can't be turned into an item. Create the new one and copy the values across.
What reaches your game
Both layers survive export. Each property set becomes a class or struct named after it, and each
entity type becomes a class holding one member per attached set — so the grouping you author is
the grouping your game code sees. In Unity, a Character type built from a CharacterProperties
set comes out as:
[System.Serializable]
public class CharacterProperties
{
public string FullName;
public CharacterRoleEnum Role;
public string Bio;
}
[System.Serializable]
public class CharacterEntity : Narratyr.NarratyrEntity
{
public CharacterProperties CharacterProperties;
}
That's why type and property-set names have to be identifiers, and why they're worth choosing carefully: they're the names your programmers type. An individual entity's handle is separate — its External ID, which you set per entity and which your game uses to find that specific character. See Exporting.
Next
Add a character walks through creating an entity against a type that already exists. Variables covers the other half of the data model — the global state that isn't attached to any one thing — and Documents and the file format covers how types, property sets, and entities are stored on disk.