TSCN file format
The TSCN (text scene) file format represents a single scene tree inside Godot. Unlike binary SCN files, TSCN files have the advantage of being mostly human-readable and easy for version control systems to manage.
.import/ folder. This reduces the data size and speeds up loading, as binary formats are faster to load compared to text-based formats.
resource_format_text.cpp in the ResourceFormatLoaderText class.
File structure
There are five main sections inside the TSCN file:
- File Descriptor
- External resources
- Internal resources
- Nodes
- Connections
[gd_scene load_steps=3 format=2]and should be the first entry in the file. Theload_stepsparameter is equal to the total amount of resources (internal and external) plus one (for the file itself). If the file has no resources,load_stepsis omitted. The engine will still load the file correctly ifload_stepsis incorrect, but this will affect loading bars and any other piece of code relying on that value.[ext_resource .....].;). However, comments will be discarded when saving the file using the Godot editor.Entries inside the file
[<resource_type> key=value key=value key=value ...]where resource_type is one of:
ext_resourcesub_resourcenodeconnectionkey = valuepairs. The values can be complex datatypes such as Arrays, Transforms, Colors, and so on. For example, a spatial node looks like:[node name="Cube" type="Spatial" parent="."]transform=Transform( 1.0, 0.0, 0.0 ,0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0 )
The scene tree
[node type="Camera" name="PlayerCamera" parent="Player/Head"]Other valid keywords include:instance
instance_placeholderownerindex(sets the order of appearance in the tree. If absent, inherited nodes will take precedence over plain ones)groupsparent=Path/To/Nodeentry in its heading. All scene files should have exactly one scene root. If it doesn’t, Godot will fail to import the file. The parent path of other nodes should be absolute, but shouldn’t contain the scene root’s name. If the node is a direct child of the scene root, the path should be".". Here is an example scene tree (but without any node content):
Similar to the internal resource, the document for each node is currently incomplete. Fortunately, it is easy to find out because you can simply save a file with that node in it. Some example nodes are:[node name="Player" type="Spatial"] ; The scene root[node name="Arm" parent="." type="Spatial"] ; Parented to the scene root[node name="Hand" parent="Arm" type="Spatial"][node name="Finger" parent="Arm/Hand" type="Spatial"]
[node type="CollisionShape" name="SphereCollision" parent="SpherePhysics"]shape = SubResource(8)transform = Transform( 1.0 , 0.0 , -0.0 , 0.0 , -4.371138828673793e-08 , 1.0 , -0.0 , -1.0 , -4.371138828673793e-08 ,0.0 ,0.0 ,-0.0 )[node type="MeshInstance" name="Sphere" parent="SpherePhysics"]mesh = SubResource(9)transform = Transform( 1.0 , 0.0 , -0.0 , 0.0 , 1.0 , -0.0 , -0.0 , -0.0 , 1.0 ,0.0 ,0.0 ,-0.0 )[node type="OmniLight" name="Lamp" parent="."]light_energy = 1.0light_specular = 1.0transform = Transform( -0.29086464643478394 , -0.7711008191108704 , 0.5663931369781494 , -0.05518905818462372 , 0.6045246720314026 , 0.7946722507476807 , -0.9551711678504944 , 0.199883371591568 , -0.21839118003845215 ,4.076245307922363 ,7.3235554695129395 ,-1.0054539442062378 )omni_range = 30shadow_enabled = truelight_negative = falselight_color = Color( 1.0, 1.0, 1.0, 1.0 )[node type="Camera" name="Camera" parent="."]projection = 0near = 0.10000000149011612fov = 50transform = Transform( 0.6859206557273865 , -0.32401350140571594 , 0.6515582203865051 , 0.0 , 0.8953956365585327 , 0.44527143239974976 , -0.7276763319969177 , -0.3054208755493164 , 0.6141703724861145 ,14.430776596069336 ,10.093015670776367 ,13.058500289916992 )far = 100.0
NodePath
NodePath(Path/To/Node)structure to refer to another node or attribute of the node anywhere in the scene tree. For instance, MeshInstance usesNodePath()to point to its skeleton. Likewise, Animation tracks useNodePath()to point to node properties to animate.[node name="mesh" type="MeshInstance" parent="Armature001"]mesh = SubResource(1)skeleton = NodePath("..:")
[sub_resource id=3 type="Animation"]...tracks/0/type = "transformtracks/0/path = NodePath("Cube:")...
Skeleton
bones/Id/Attribute=Value. The bone attributes consist of:nameparentrestposeenabledbound_children
namemust be the first attribute of each bone.parentis the index of parent bone in the bone list, with parent index, the bone list is built to a bone tree.restis the transform matrix of bone in its “resting” position.poseis the pose matrix; userestas the basis.bound_childrenis a list ofNodePath()which point to BoneAttachments belonging to this bone. Here’s an example of a skeleton node with two bones:[node name="Skeleton" type="Skeleton" parent="Armature001" index="0"]bones/0/name = "Bone.001"bones/0/parent = -1bones/0/rest = Transform( 1, 0, 0, 0, 0, -1, 0, 1, 0, 0.038694, 0.252999, 0.0877164 )bones/0/pose = Transform( 1.0, 0.0, -0.0, 0.0, 1.0, -0.0, -0.0, -0.0, 1.0, 0.0, 0.0, -0.0 )bones/0/enabled = truebones/0/bound_children = [ ]bones/1/name = "Bone.002"bones/1/parent = 0bones/1/rest = Transform( 0.0349042, 0.99939, 0.000512929, -0.721447, 0.0248417, 0.692024, 0.691589, -0.0245245, 0.721874, 0, 5.96046e-08, -1.22688 )bones/1/pose = Transform( 1.0, 0.0, -0.0, 0.0, 1.0, -0.0, -0.0, -0.0, 1.0, 0.0, 0.0, -0.0 )bones/1/enabled = truebones/1/bound_children = [ ]
BoneAttachment
bone_name=NameOfBoneattribute, and the corresponding bone being the parent has the BoneAttachment node in itsbound_childrenlist. An example of one MeshInstance parented to a bone in Skeleton:[node name="Armature" type="Skeleton" parent="."]transform = Transform(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, -0.0219986, 0.0125825, 0.0343127)bones/0/name = "Bone"bones/0/parent = -1bones/0/rest = Transform(1.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0)bones/0/pose = Transform(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0)bones/0/enabled = truebones/0/bound_children = [NodePath("BoneAttachment:")][node name="BoneAttachment" type="BoneAttachment" parent="Armature"]bone_name = "Bone"[node name="Cylinder" type="MeshInstance" parent="Armature/BoneAttachment"]mesh = SubResource(1)transform = Transform(1.0, 0.0, 0.0, 0.0, 1.86265e-09, 1.0, 0.0, -1.0, 0.0, 0.0219986, -0.0343127, 2.25595)
AnimationPlayer
anim/Name=SubResource(ResourceId); each line refers to an Animation resource. All the animation resources use the root node of AnimationPlayer. The root node is stored asroot_node=NodePath(Path/To/Node).[node name="AnimationPlayer" type="AnimationPlayer" parent="." index="1"]root_node = NodePath("..")autoplay = ""playback_process_mode = 1playback_default_blend_time = 0.0playback_speed = 1.0anims/default = SubResource( 2 )blend_times = [ ]
Resources
Resources are components that make up the nodes. For example, a MeshInstance node will have an accompanying ArrayMesh resource. The ArrayMesh resource may be either internal or external to the TSCN file.idnumbers in the resource’s heading. External resources and internal resources are referred to withExtResource(id)andSubResource(id), respectively. Because there have different methods to refer to internal and external resources, you can have the same ID for both an internal and external resource.[ext_resource id=3 type="PackedScene" path=....], you would useExtResource(3).External resources
External resources are links to resources not contained within the TSCN file itself. An external resource consists of a path, a type and an ID.res://, but paths relative to the TSCN file’s location are also valid. Some example external resources are:[ext_resource path="res://characters/player.dae" type="PackedScene" id=1][ext_resource path="metal.tres" type="Material" id=2]
;). However, comments will be discarded when saving the resource using the Godot editor.Internal resources
internal resources section of the file. The heading for an internal resource looks similar to those of external resources, except that it doesn’t have a path. Internal resources also havekey=valuepairs under each heading. For example, a capsule collision shape looks like:
before the reference to it. This means that order matters in the file’s internal resources section. Unfortunately, documentation on the formats for these subresources isn’t complete. Some examples can be found by inspecting saved resource files, but others can only be found by looking through Godot’s source.[sub_resource type="CapsuleShape" id=2]radius = 0.5height = 3.0
ArrayMesh
surface\Index={}. Each surface is a set of vertices and a material. TSCN files support two surface formats: 1.
primitivearraysmorph_arraysprimitiveis an enumerate variable,primitive=4which isPRIMITIVE_TRIANGLESis frequently used.
arraysis a two-dimensional array, it contains:Vertex positions array
- Normals array
- Tangents array
- Vertex colors array
- UV array 1
- UV array 2
- Bone indexes array
- Bone weights array
- Vertex indexes array
morph_arraysis an array of morphs. Each morph is exactly anarrayswithout the vertex indexes array. An example of ArrayMesh:[sub_resource id=1 type="ArrayMesh"]surfaces/0 = { "primitive":4, "arrays":[ Vector3Array(0.0, 1.0, -1.0, 0.866025, -1.0, -0.5, 0.0, -1.0, -1.0, 0.866025, 1.0, -0.5, 0.866025, -1.0, 0.5, 0.866025, 1.0, 0.5, -8.74228e-08, -1.0, 1.0, -8.74228e-08, 1.0, 1.0, -0.866025, -1.0, 0.5, -0.866025, 1.0, 0.5, -0.866025, -1.0, -0.5, -0.866025, 1.0, -0.5), Vector3Array(0.0, 0.609973, -0.792383, 0.686239, -0.609973, -0.396191, 0.0, -0.609973, -0.792383, 0.686239, 0.609973, -0.396191, 0.686239, -0.609973, 0.396191, 0.686239, 0.609973, 0.396191, 0.0, -0.609973, 0.792383, 0.0, 0.609973, 0.792383, -0.686239, -0.609973, 0.396191, -0.686239, 0.609973, 0.396191, -0.686239, -0.609973, -0.396191, -0.686239, 0.609973, -0.396191), null, ; No Tangents, null, ; no Vertex Colors, null, ; No UV1, null, ; No UV2, null, ; No Bones, null, ; No Weights, IntArray(0, 2, 1, 3, 1, 4, 5, 4, 6, 7, 6, 8, 0, 5, 9, 9, 8, 10, 11, 10, 2, 1, 10, 8, 0, 1, 3, 3, 4, 5, 5, 6, 7, 7, 8, 9, 5, 0, 3, 0, 9, 11, 9, 5, 7, 9, 10, 11, 11, 2, 0, 10, 1, 2, 1, 6, 4, 6, 1, 8) ], "morph_arrays":[]}
Animation
length,loopandstepapplied to all the tracks.lengthandstepare both durations in seconds.tracks/Id/Attribute. Each track includes:
typepathinterpkeysloop_wrapimportedenabled
typemust be the first attribute of each track. The value oftypecan be:transform
valuemethod
pathhas the formatNodePath(Path/To/Node:attribute). It’s the path to the animated node or attribute, relative to the root node defined in the AnimationPlayer.interpis the method to interpolate frames from the keyframes. It is an enum variable with one of the following values:0(constant)
1(linear)2(cubic)
keyscorrespond to the keyframes. It appears as aPoolRealArray(), but may have a different structure for tracks with different types.keysto describe a keyframe. The first number is the timestamp. The second number is the transition followed by a 3-number translation vector, followed by a 4-number rotation quaternion (X, Y, Z, W) and finally a 3-number scale vector. The default transition in a Transform track is 1.0.[sub_resource type="Animation" id=2]length = 4.95833loop = falsestep = 0.1tracks/0/type = "transform"tracks/0/path = NodePath("Armature001")tracks/0/interp = 1tracks/0/loop_wrap = truetracks/0/imported = truetracks/0/enabled = truetracks/0/keys = PoolRealArray( 0, 1, -0.0358698, -0.829927, 0.444204, 0, 0, 0, 1, 0.815074, 0.815074, 0.815074, 4.95833, 1, -0.0358698, -0.829927, 0.444204, 0, 0, 0, 1, 0.815074, 0.815074, 0.815074 )tracks/1/type = "transform"tracks/1/path = NodePath("Armature001/Skeleton:Bone.001")tracks/1/interp = 1tracks/1/loop_wrap = truetracks/1/imported = truetracks/1/enabled = falsetracks/1/keys = PoolRealArray( 0, 1, 0, 5.96046e-08, 0, 0, 0, 0, 1, 1, 1, 1, 4.95833, 1, 0, 5.96046e-08, 0, 0, 0, 0, 1, 1, 1, 1 )
