Skip to main content

Scenes and prefabs

A scene (.tscene) and a prefab (.tprefab) are JSON documents with the same entity format. This page describes the top-level structure, entities and their hierarchy, how components and script fields are written, guid references to assets and entities, how prefab instances store overrides, and versioning. DocumentSerializer in src/Talesmith.Runtime/Serialization reads and writes both.

A scene​

This is the start of Lantern Grove's scene, samples/LanternGrove/assets/scenes/grove.tscene, with the render layers and most entities left out:

samples/LanternGrove/assets/scenes/grove.tscene
{
"version": 1,
"id": "0a82c7e43abd07d964eab07f404fe145",
"environment": {
"clearColor": "#0B1030",
"ambientLight": "#3A4A8C",
"ambientIntensity": 0.42,
"gravity": [0, 980],
"renderLayers": [
{
"name": "Background",
"layer": 0,
"lit": true
}
],
"lighting": {
"quality": "high",
"customQuality": null,
"litLayerLimit": 450,
"tileMapShadows": true,
"tileMapShadowLayer": 0
}
},
"entities": [
{
"id": "dac10e04b952ae6eb6fa055c844b8177",
"name": "Camera Focus",
"parent": null,
"active": true,
"editor": {
"hidden": false,
"locked": false
},
"prefab": null,
"components": [
{
"type": "Transform",
"data": {
"position": [256, 580]
}
},
{
"type": "ScriptComponent",
"data": {
"scripts": [
{
"type": "LanternGrove.CameraRig",
"enabled": true,
"fields": {
"player": "e4d082dc51aae5abb347ccb2921b3389",
"lookAhead": 120,
"above": 110
}
}
]
}
}
]
},
{
"id": "0ead067ff9297bdd8ff5d404286086c5",
"name": "Main Camera",
"parent": null,
"active": true,
"editor": {
"hidden": false,
"locked": false
},
"prefab": null,
"components": [
{
"type": "Transform",
"data": {
"position": [640, 580]
}
},
{
"type": "Camera",
"data": {
"zoom": 1,
"target": "dac10e04b952ae6eb6fa055c844b8177",
"followSharpness": 5,
"bounds": [-32, -32, 5120, 1024]
}
},
{
"type": "AudioListener",
"data": {}
}
]
}
]
}

A prefab​

A prefab has the same fields as a scene except environment. This is Lantern Grove's lantern, shortened to four of its eight components and some of the light's fields:

samples/LanternGrove/assets/prefabs/lantern.tprefab
{
"version": 1,
"id": "2cf62c7735fb8d62ffe82ab1b31579a3",
"entities": [
{
"id": "46f86477853958c9b4f9eba34b5c4ee4",
"name": "Lantern",
"parent": null,
"active": true,
"editor": {
"hidden": false,
"locked": false
},
"prefab": null,
"components": [
{
"type": "Transform",
"data": {
"position": [0, 0]
}
},
{
"type": "Sprite",
"data": {
"texture": "865d9676bf964c4f8a79f0b94f246fbc",
"layer": 295
}
},
{
"type": "Light2D",
"data": {
"color": "#FFB25A",
"intensity": 1.25,
"radius": 260,
"castsShadows": true,
"animation": "flicker"
}
},
{
"type": "ParticleEmitter",
"data": {
"preset": "ad5bbc63877f4a29bcc88e0c66311195"
}
}
]
}
]
}

The file in the repository also carries an environment object. Prefabs do not use it; the serializer keeps it as an unknown field and writes it back.

Top-level fields​

FieldTypeDefaultMeaning
versioninteger1The format version. Documents without one are read as version 1.
idguidThe document's own id, set when the document is created.
environmentobjectScenes only. Background, ambient light, gravity, render layers and lighting; see below.
entitiesarray[]The entities in hierarchy order: every child follows its parent.

The environment​

FieldTypeDefaultMeaning
clearColorcolor or nullnullThe color behind everything; null uses clearColor from game.json.
ambientLightcolor"#FFFFFF"The light color of unlit areas, used by the lighting module.
ambientIntensitynumber1The strength of the ambient light.
gravityvector[0, 980]World units per second squared for physics; Y points down.
renderLayersarraysix layersThe named render layers the editor offers, in drawing order. Each has name, layer (the number sprites and maps use) and lit (whether lights affect it). The defaults are Background 0, Terrain 100, Decals 200, Entities 300, Effects 400 and Overlay 500, which is unlit.
lightingobjectLighting quality and lit layers, written by the lighting module; see Lighting settings.

Lighting settings​

The lighting module stores its scene settings in the environment under lighting. Scenes without it use the defaults.

FieldTypeDefaultMeaning
qualitylow, medium, high or custommediumThe quality preset: light map resolution, light and shadow limits.
customQualityobject or nullnullThe limits for custom: resolutionScale, maxLights, maxShadowedLights, shadowResolution, shadowSamples and maxShadowCasters. Null uses the medium limits.
litLayerLimitinteger500Render layers below this number are lit; this layer and the ones above are drawn unlit.
tileMapShadowsbooleantrueWhether collision tile layers cast shadows.
tileMapShadowLayerinteger0The shadow caster layer, 0 to 31, that tile map shadows are on; lights pick the layers they shadow with shadowLayers.

The editor's lighting presets (.tlighting, in assets/lighting/) copy these values into a scene. A preset holds version, name, ambientColor, ambientIntensity and an optional lighting object of the shape above:

assets/lighting/night.tlighting
{ "version": 1, "name": "Night", "ambientColor": "#3A4A80", "ambientIntensity": 0.25, "lighting": { "quality": "high" } }

Entities​

FieldTypeDefaultMeaning
idguidThe entity's stable id within its document. Entity references and prefab overrides use it.
namestring""The name shown in the hierarchy.
parentguid or nullnullThe id of the parent entity, which comes earlier in the file, or null for a root.
activebooleantrueInactive entities are created with an Inactive component, which systems that draw skip.
editorobjectEditor-only state the runtime ignores: hidden (hidden in the viewport) and locked (cannot be picked in the viewport).
prefabobject or nullnullSet when the entity is an instance of a prefab; see Prefab instances.
componentsarray[]The components in inspector order, each { "type", "data" }.

The order of entities in the file is the order of the hierarchy. Saved transforms are local: a child's position is relative to its parent. The runtime gives child entities Parent and LocalTransform components and computes their world Transform.

Components​

Each component is an object with a type and a data object of property values.

FieldMeaning
typeThe component's type name. Engine components marked [Component] use their short name, such as Sprite or Light2D. Every other component uses its full .NET name, such as LanternGrove.Parallax or MyGame.Health, so plugins and scripts cannot collide with each other or with the engine.
dataThe component's public fields and settable properties by camelCase name. Missing properties keep the component's defaults. The editor writes every property; the samples were partly written by hand and leave defaults out.

Components whose type is not registered, for example because the plugin that defines them is switched off, are kept with their data and written back unchanged. Values that cannot be read are logged and keep their defaults; the rest of the component still loads.

Scripts​

Scripts attached to an entity are one component, ScriptComponent, with a list of scripts. Each has its class's full name, whether it is enabled, and its saved fields:

{
"type": "ScriptComponent",
"data": {
"scripts": [
{
"type": "LanternGrove.PlayerController",
"enabled": true,
"fields": {
"runSpeed": 320,
"jumpSpeed": 860
}
}
]
}
}

Scripts whose class does not exist, for example after a rename or while the project does not compile, are kept as missing scripts and written back unchanged.

Value encoding​

ValueWritten asExample
Numbers, booleans, stringsJSON numbers, booleans and strings"intensity": 1.25
EnumscamelCase names; flags as names separated by commas"shape": "circle", "animation": "flicker"
Vectors[x, y]"position": [256, 672]
Rectangles[x, y, width, height]"bounds": [-32, -32, 5120, 1024]
Colors"#RRGGBB" or "#AARRGGBB""color": "#FFB25A"
Curves and gradientsLists of keys and stops, as in the shared rules
Lists and setsJSON arrays; sets of comparable values are sorted so files do not change needlessly"values": ["lantern"]
Nested objectsJSON objects of their fields
Asset referencesThe asset's guid, or null"texture": "865d9676bf964c4f8a79f0b94f246fbc"
Entity referencesThe id of an entity in the same document, or null"target": "dac10e04b952ae6eb6fa055c844b8177"
AnglesRadians, clockwise"rotation": 1.9477875

Vectors, rectangles and other lists of up to four numbers are written on one line to keep files readable. Vectors are also read from { "x": …, "y": … }.

Asset references are loaded before the scene's entities are created, so a component never sees a missing texture or preset that exists on disk. A texture field holds the guid of the texture asset; the sprite within it is a separate field, such as the Sprite component's sprite. Plugins add converters for their own types with services.AddValueConverter<T>().

Prefab instances and overrides​

An instance of a prefab is an entity with a prefab link. Its own components list holds components added to the prefab's root or replacing ones of the same type; usually that is only the Transform:

samples/LanternGrove/assets/scenes/grove.tscene
{
"id": "b15b4b6af939a059a589cf862cfbd361",
"name": "Lantern 2",
"parent": "371c32b5f2c37b21ee0d4b546557d255",
"active": true,
"editor": {
"hidden": false,
"locked": false
},
"prefab": {
"asset": "b3678458367d4fcdb8d2e23cb30aab79",
"overrides": [],
"removedComponents": []
},
"components": [
{
"type": "Transform",
"data": {
"position": [1408, 422.4]
}
}
]
}
FieldTypeMeaning
assetguidThe guid of the .tprefab asset, from its .meta file. This is not the id inside the prefab.
overridesarrayProperty values that differ from the prefab, applied in order.
removedComponentsarrayComponents of the prefab's entities that this instance does not have, each { "entity", "component" }.

An override names an entity of the prefab, a component type, a property path and the value. If the second lantern in Lantern Grove had a red light, its overrides would read:

"overrides": [
{
"entity": "46f86477853958c9b4f9eba34b5c4ee4",
"component": "Light2D",
"path": "color",
"value": "#FF0000"
}
]
  • entity is the id of the entity within the prefab file. For entities of a nested prefab, it is their id as expanded inside the enclosing prefab, so overrides reach any depth.
  • path is dot-separated with list items as numbers, such as tint or frames.2.duration.
  • value is written in the same encoding as component data.

When a scene is loaded, the prefab's first root entity becomes the instance entity and takes the instance's id. Every other prefab entity gets an id derived from the instance id and its prefab id (PrefabIds.Derive), the same on every machine and every load, so overrides and entity references keep their targets. Entity references inside a prefab resolve to entities of the same instance first. Changing the prefab file changes every instance that did not override the changed property.

Versioning​

Both formats are at version 1 (SceneDocument.CurrentVersion and PrefabDocument.CurrentVersion).

  • Reading a document with a newer version fails with a message asking you to update Talesmith.
  • Reading an older document runs each registered IDocumentMigration for its kind and version in order, updating the version field after each step, before the document is read.
  • Unknown fields at any level (document, environment, entity, component, render layer) are kept and written back unchanged, which is how the lighting module's lighting object survives in projects without the lighting module.
  • Prefabs in the guide shows how to make, edit, apply and revert prefabs.
  • Meta files explains the guids that references point to.
  • Editor architecture explains how the editor applies edits to a scene document.