STF - Squirrel Transfer Format
A modular file-format for 3D assets Intended for (not only) game development use-cases.
Install STF support for:
Try to import this example model!
Relevant future implementation targets include: 3dsMax, Unreal Engine, Maya, Bevy, BabylonJs, ...
Concept
STF by itself is merely a shell format. It provides a framework for different modules to parse and serialize resourses.
Resources are stored as Json-objects, identified by a unique ID. Resources can reference binary buffers and each other.
A few modules, including but not limited to stf.prefab
, stf.mesh
, stf.material
or stf.image
, are provided by default.
Additional modules can be easily implemented by third parties. Each STF implementation provides an easy and convenient way to hot-load module-plugins.
As the format is focussed on interoperability, the default module for meshes for example stores its data both, triangulated, and the original topology. If it gets imported into a game-engine, the triangulated data will be used, if imported into a modeling tool, the original topology will be imported. This is possible with negligible storage impact.
Learn how STF compares to other 3d file-formats: Comparisons
Anatomy of an STF file
Installation
Add STF support to:
Blender Installation
To install the Blender STF extension:
Drag & drop THIS link into an open Blender window!
After the repository has been added, go to Preferences
→ Get Extensions
, search for "stf" and press Install
.
Read the User Guide
See the Source Code: Codeberg - GitHub
Unity Installation
Unity Package Manager
Under Window
→ Package Manager
→ +
→ Add package from git URL…
add the following URL:
https://github.com/emperorofmars/stf_unity.git#upm
VRChat Creator Companion
Add this repository
Then, in the Creator Companion, go to Manage Project
and add the STF
package.
See the Source Code: Codeberg - GitHub
Godot Installation
Download the latest release and unpack the addons/stf_godot
directory into the addons
directory of your Godot project.
See the Source Code: Codeberg - GitHub
STF Format
Introduction
STF is a binary file format, containing a binary header, a Json definition and a set of binary buffers.
The Json definition contains meta information, arbitrary resources and buffer references.
Resources have a type
property, and are identified by a unique ID as a string.
Based on a resources type, a module gets selected which provides support to import & export it.
The minimum required set of supported modules is specified in Modules.
STF implementations must provide an easy to use plugin system for modules. If in any way possible, modules should be hot-loadable at runtime.
Key Facts
- The file extension for stf binary files is
.stf
. - The media-type for stf binary files is
model/stf+binary
. - The STF binary header is stored in
little endian
byte order. - The Json definition is encoded as
utf8
. - STF uses the same coordinate system as glTF 2.0. (See glTF-2.0. coordinate-system-and-units)
Binary Format
An STF binary file consists of a binary header, a json-definition, and zero or more binary buffers.
Length (Bytes) | Content |
---|---|
4 | Magic number: STF0 |
4 | STF binary format version major |
4 | STF binary format version minor |
4 | Number of buffers, including the Json definiton buffer |
8 * {number of buffers} | Buffer lengths in bytes |
{length of all buffers} | Buffers |
The Json definition is the first and only required buffer.
Json Definition
The root Json element is an object. It contains 3 properties: stf
, resources
and buffers
.
stf object
The stf
object holds meta information.
stf
object properties:
Key | Required | Type | Description |
---|---|---|---|
version_major | Yes | Int | Major version of STF |
version_minor | Yes | Int | Minor version of STF |
root | Yes | resource-ID | ID of the root resource |
meta | No | Map<String, String> | Meta information such as authors, license or documentation link. |
generator | No | String | The name of the STF implementation that created this file. |
timestamp | No | String | Timestamp as a String in the ISO format. |
metric_multiplier | No | Float | Which number represents one meter. The default value is 1.0 . |
The root resource must be a stf.prefab
. It represents the assets scene-hierarchy.
"stf": {
"version_major": 0,
"version_minor": 0,
"meta": {
"asset_name": "STF Example 1"
},
"metric_multiplier": 1.0,
"root": "5f1ea7e8-ee26-46c9-91dc-cd002cb9b0a5"
}
resources object
The resources
object is a map of resource objects identified by an ID.
The various resource objects describe the files actual content. Any further properties are defined by each resources module.
Resource object general properties:
Key | Required | Type | Description |
---|---|---|---|
type | Yes | String | Type of the resource. |
referenced_resources | No | List | IDs of resources this resource references. |
referenced_buffers | No | List | IDs of buffers this resource references. |
name | No | String | Display name of the resource. |
version_major | No | Int | Major version of this resource. The default value is 0 . |
version_minor | No | Int | Major version of this resource. The default value is 0 . |
degraded | No | Boolean | Has this resource lost information at some point, but retained the same ID. The default is False . |
If a referenced resource is not contained within the Json keys children
, root_nodes
, components
or instance
, it must be additionally stored in the referenced_resources
field. This is only required for non-default modules.
A referenced buffer must be additionally stored in the referenced_buffers
field. This is only required for non-default modules.
Resource Kinds
Resources can be Data
, Node
, Instance
and Component
kinds.
Each of these kinds has additional properties.
The information about what kind
a resource is, must be known by the resource-type's implementation and is not contained in STF files itself.
Data
Suppport for module plugins of this kind is required.
Data resource properties:
Key | Required | Type | Description |
---|---|---|---|
fallback | No | Resource-ID | ID of a resource that should be used in case this one's type is not supported in this implementation |
components | No | List | Component resource IDs |
Node
For now only stf.node
and stf.bone
exist.
Suppport for module plugins of this kind is not required.
Node resource properties:
Key | Required | Type | Description |
---|---|---|---|
enabled | No | boolean | True by default |
children | No | List | IDs of child-nodes |
components | No | List | Component resource IDs |
Instance
They represent an instance of a data
resource in the scene hierarchy.
These include for example mesh or armature instances.
Instances can provide data relevant for the instance of the resource, such as an armatures pose or meshes blendshape value or material assignments.
An instance resource can be referenced only once by a Node
resource.
Suppport for module plugins of this kind is required.
Instance resource properties:
Key | Required | Type | Description |
---|---|---|---|
enabled | No | boolean | True by default |
Component
They Represents additional functionality or information for Data
and Node
resources.
A component resource can be referenced only once by a Data
or Node
resource.
Suppport for module plugins of this kind is required.
Component resource properties:
Key | Required | Type | Description |
---|---|---|---|
enabled | No | boolean | True by default |
overrides | No | List | References Component kind types that should not be processed, if this type is supported |
"resources": {
"b5f96f63-d5ce-4210-b4d6-8f43fbf557dd": {
"type": "stf.material",
"name": "Body Material",
"properties": {
"albedo.texture": {
"type": "image",
"values": [
{
"image": "f518a35d-d788-4692-a2dd-84d036d259e8"
}
]
}
}
},
"60b9192c-0c82-434b-b1cf-27d8add2c071": {
"type": "stf.image",
"name": "Awesome Texture.png",
"format": "png",
"buffer": "d07b09a0-3184-4a39-8650-d1fc90c64df2",
"data_type": "color"
},
"3ca7f62c-b2a8-4315-bb1d-e4c6118ead70": {
"type": "stf.texture",
"resolution": [2048, 2048],
"quality": 0.7,
"texture_type": "color",
"downscale_priority": 0
}
}
buffers object
The buffers
object is a map of buffer objects identified by an ID.
Each buffer object has a type
property. Any further properties are defined in the buffer-type's definition.
For now, stf.buffer.included
is the only supported buffer type. Support for hot-loading different buffer-types is not required.
stf.buffer.included
This type represents a buffer contained in the same file.
stf.buffer.included
properties:
Key | Required | Type | Description |
---|---|---|---|
index | Yes | Int | Index of the binary buffer in the file. An index of 0 means the first buffer after the Json definition buffer. |
"buffers": {
"2c04d7f9-96cd-4867-baf3-2a54d4d31a67": {
"type": "stf.buffer.included",
"index": 666
}
}
Minimal Definition Example
Default Cube.stf
Default Cube.stf
{
"stf": {
"version_major": 0,
"version_minor": 0,
"root": "979c1726-222d-4184-89b1-72f9b2c82d60",
"asset_info": {
"asset_name": "Default Cube"
},
"generator": "stf_blender",
"generator_version": "0.0.7",
"timestamp": "2025-08-04T16:43:03.324405+00:00",
"metric_multiplier": 1
},
"resources": {
"5ced8683-2dff-49de-aefe-3f02c4856e86": {
"type": "stf.material",
"name": "Material",
"properties": {
"albedo.color": {
"type": "color",
"values": [
[
0.800000011920929,
0.800000011920929,
0.800000011920929,
1.0
]
]
},
"roughness.value": {
"type": "float",
"values": [
0.5
]
},
"metallic.value": {
"type": "float",
"values": [
0.0
]
}
},
"style_hints": [
"realistic",
"pbr"
],
"shader_targets": {
"stfblender": [
"ShaderNodeBsdfPrincipled"
]
}
},
"89abf95c-575c-4033-adbc-fffe3f59cdb9": {
"type": "stf.mesh",
"name": "Cube",
"material_slots": [
"5ced8683-2dff-49de-aefe-3f02c4856e86"
],
"float_width": 4,
"indices_width": 1,
"vertices": "c69104d6-55a9-4460-a8fc-e2f3a70da3eb",
"face_corners": "214dd09d-b2eb-4b1f-83bb-c1650222a897",
"splits": "a7ca9d09-169f-4f65-8af5-265a3e1c1128",
"split_normals": "497cd907-6bbf-4017-bbf4-bdb57f34a6b4",
"uvs": [
{
"name": "UVMap",
"uv": "f88f80c6-4b95-4103-88d6-056af49e454b"
}
],
"tris": "f705415c-93c5-48d1-8c12-fa6fc6a976b1",
"material_indices_width": 1,
"faces": "42b4c79a-12b9-4fc9-97b0-518bcdef6043",
"material_indices": "e443faf5-38d0-485a-8f5f-30735c49bf2c",
"sharp_face_indices": "9c25f6ef-f33b-4aa7-9860-da7427d01bdb",
"lines": "3d232b23-6deb-41ad-b09e-5805869fff1c",
"sharp_edges": "cc4206c5-2ff7-4d28-9e90-f4d3c6a8130a",
"components": [
"4ab71531-2a97-4d63-b574-3ab760290f4a"
]
},
"4ab71531-2a97-4d63-b574-3ab760290f4a": {
"type": "stfexp.mesh.seams",
"indices_width": 1,
"referenced_buffers": [
"29e557ab-6f20-4302-9396-a2287cda0b6e"
],
"seams": "29e557ab-6f20-4302-9396-a2287cda0b6e"
},
"9742257e-e1b3-424f-882f-33c44c746d98": {
"type": "stf.instance.mesh",
"name": "",
"mesh": "89abf95c-575c-4033-adbc-fffe3f59cdb9"
},
"25f8b224-46a3-404c-a15a-8594f2c9e8fc": {
"type": "stf.node",
"name": "Cube",
"children": [],
"trs": [
[
0.0,
0.0,
-0.0
],
[
0.0,
0.0,
-0.0,
1.0
],
[
1.0,
1.0,
1.0
]
],
"instance": "9742257e-e1b3-424f-882f-33c44c746d98"
},
"53650c64-eb81-4873-a4f0-4e274c02597f": {
"type": "stf.node",
"name": "Light",
"children": [],
"trs": [
[
4.076245307922363,
5.903861999511719,
-1.0054539442062378
],
[
0.16907574236392975,
0.7558803558349609,
-0.27217137813568115,
0.570947527885437
],
[
1.0,
1.0,
0.9999999403953552
]
]
},
"57d85e39-1994-4604-b4fc-4acd76a5f635": {
"type": "stf.node",
"name": "Camera",
"children": [],
"trs": [
[
7.358891487121582,
4.958309173583984,
6.925790786743164
],
[
0.483536034822464,
0.33687159419059753,
-0.20870360732078552,
0.7804827094078064
],
[
1.0,
1.0,
1.0
]
]
},
"979c1726-222d-4184-89b1-72f9b2c82d60": {
"type": "stf.prefab",
"name": "Collection",
"root_nodes": [
"25f8b224-46a3-404c-a15a-8594f2c9e8fc",
"53650c64-eb81-4873-a4f0-4e274c02597f",
"57d85e39-1994-4604-b4fc-4acd76a5f635"
],
"animations": []
}
},
"buffers": {
"c69104d6-55a9-4460-a8fc-e2f3a70da3eb": {
"type": "stf.buffer.included",
"index": 0
},
"214dd09d-b2eb-4b1f-83bb-c1650222a897": {
"type": "stf.buffer.included",
"index": 1
},
"a7ca9d09-169f-4f65-8af5-265a3e1c1128": {
"type": "stf.buffer.included",
"index": 2
},
"497cd907-6bbf-4017-bbf4-bdb57f34a6b4": {
"type": "stf.buffer.included",
"index": 3
},
"f88f80c6-4b95-4103-88d6-056af49e454b": {
"type": "stf.buffer.included",
"index": 4
},
"f705415c-93c5-48d1-8c12-fa6fc6a976b1": {
"type": "stf.buffer.included",
"index": 5
},
"42b4c79a-12b9-4fc9-97b0-518bcdef6043": {
"type": "stf.buffer.included",
"index": 6
},
"e443faf5-38d0-485a-8f5f-30735c49bf2c": {
"type": "stf.buffer.included",
"index": 7
},
"9c25f6ef-f33b-4aa7-9860-da7427d01bdb": {
"type": "stf.buffer.included",
"index": 8
},
"3d232b23-6deb-41ad-b09e-5805869fff1c": {
"type": "stf.buffer.included",
"index": 9
},
"cc4206c5-2ff7-4d28-9e90-f4d3c6a8130a": {
"type": "stf.buffer.included",
"index": 10
},
"29e557ab-6f20-4302-9396-a2287cda0b6e": {
"type": "stf.buffer.included",
"index": 11
}
}
}
Comparison to other Formats
FBX
FBX is the industry standard. Unfortunately it is not extensible, undocumented, and its official implementation is proprietary.
Many open-source projects, like Blender and Godot, rely on unofficial reverse engineered implementations, with varying success.
glTF 2.0
Similar to glTF 2.0, an STF file consists of a Json definition and binary data. Contrary to glTF, STF is made for interchange of 3d assets, not runtime loading or asset-streaming.
GLTF is made to be delivered to the end-user and loaded directly into video-memory. STF is made to be delivered to a games-developer or artist.
Game-engines are responsible for runtime optimization (at asset-import and/or build time), not the 3d file format or 3d modeling tool.
USD
The official OpenUSD FAQ does a better job at explaining this, than the author of this documentation ever could.
USD can instantiate assets from other regular 3D file-formats, similar to how game-engine scenes can instantiate assets from imported 3d models.
USD does not replace regular 3d file-formats and vice versa. STF is a "regular 3d file-formats" in this sense.
STF Modules
-
Core Modules (
stf.*
)
Suppport for these modules is required for a valid STF implementation. -
Expanded Modules (
stfexp.*
)
Recommended modules which support not 100% universal information. -
VR & V-Tubing Avatar Modules (
ava.*
)
Modules which represent functionality of VR & V-Tubing Avatars.
Core Modules (stf.*)
Modules which every STF implementation must support are in the main namespace stf.*
.
- stf.prefab
- stf.node
- stf.armature
- stf.bone
- stf.instance.armature
- stf.mesh
- stf.instance.mesh
- stf.material
- stf.image
- stf.texture
stf.prefab
A prefab represents a hierarchy of nodes.
Properties
Key | Required | Type | Description |
---|---|---|---|
root_nodes | Yes | List | IDs of the root nodes within this prefab |
animations | No | List | Animations which originate from this prefab's root |
The only allowed type for nodes in root_nodes
is stf.node
.
Implementations
Json Example
"f23cdae6-3b52-4212-b180-dfdb0fcfcaba": {
"type": "stf.prefab",
"name": "Warrior of the Squeak",
"root_nodes": [
"bf97e4a7-2aa8-4d90-9a4b-b7fa6223d8e7",
"899799a1-17a6-439f-a6fb-1017d07f5a04"
],
"animations": [
"b3879585-9587-4362-b6c5-58130e4c03ef",
"d7d5365a-9d0a-4fab-bbe6-193fb1f23b9e",
"3e8fb358-4501-41a6-a9f7-57ee47e1ffdb",
"aeecdee5-eb5c-4923-8b28-f89e3f6769a4",
"a63aa1f8-b819-4af3-99b4-c62aa5faae71",
"4c2cc28b-937f-4e27-bc19-7f8dfe2c56d8",
"4b63a246-e0eb-41c7-a999-ceb237f5f159",
"798af1e9-7bee-4c46-99b8-4d1510ab46de",
"c472603c-9bc7-4420-8766-7638df8621a3",
"4b393856-2189-4e9d-a282-a8810342d8fe",
"11826e52-f1f8-478d-b4dd-94e91d4a225f",
"947d80c1-7f75-453f-a32d-00e6f0fb075c"
],
"components": [
"19615892-fdcf-4f23-b47e-b59504b38561",
"346ebced-a516-426c-879f-dd6a6607fc55",
"8cd515fa-c589-49e1-a211-dbfd368d6a97"
]
}
stf.node
A node that exists in 3d space. It defines its location, rotation and scale relative to its parent.
Properties
Key | Required | Type | Description |
---|---|---|---|
trs | Yes | TRS | The nodes 3D transform |
instance | No | Resource-ID | Reference to an instance-resource. |
parent_binding | No | Path | Path to the parent resource. Usually, when the parent node is an armature-instance, its the path to a bone within the instantiated armature. |
Only other stf.node
type resources are allowed as its children. Children may never loop.
Implementations
Json Example
"880c2403-471d-46e4-99ac-0b218f201337": {
"type": "stf.node",
"name": "ArmatureHair",
"enabled": true,
"children": [
"0912ff56-e534-4c8e-a99e-d3ef2a9ea8ba"
],
"trs": [
[
-6.138677122180525e-09,
1.584037184715271,
-0.029444340616464615
],
[
-3.725290298461914e-09,
-4.618527782440651e-14,
1.7659484985443896e-15,
1.0
],
[
1.0,
1.0,
1.0
]
],
"instance": "73d67945-2937-41c8-b683-7a992cbca5c5",
"components": [
"3051ea80-cc8a-4b6a-afce-dd75e1868fa5"
],
"parent_binding": [
"9fac8ebe-54ee-4c97-a193-235fcc5ebe7f",
"instance",
"9a6e0ab7-29e4-48b1-ba25-5e0cd86988e7"
]
}
stf.armature
A armature represents a hierarchy of bones.
Properties
Key | Required | Type | Description |
---|---|---|---|
root_bones | Yes | List | IDs of nodes |
The only allowed type for nodes in root_bones
is stf.bone
.
Armatures can be instantiated by stf.instance.armature
.
Implementations
Json Example
"90b9fbb6-3e2d-44e5-8821-454c97c8d15a": {
"type": "stf.armature",
"name": "Armature",
"root_bones": [
"ed9fac3c-1500-436e-9c4e-fd88822be434"
],
"components": [
"1e7c6be0-e53c-4af5-8e2d-c1bdc7c687c5",
"1b453833-a3c8-4ac8-9d26-7a9e84eb27f9",
"8324983e-c79f-466b-b21d-b1cdbe5bf229"
]
}
stf.bone
Can only exist within stf.armature
.
Properties
Key | Required | Type | Description |
---|---|---|---|
translation | Yes | Translation | The position of the bone relative to its armature position. |
rotation | Yes | Rotation | The rotation of the bones head relative to its armature position. |
length | Yes | Float | The bones length |
connected | No | Boolean | Default false |
Only other stf.bone
type resources are allowed as its children.
Implementations
Json Example
"0936400e-013c-475f-bd43-8d3f643e46a3": {
"type": "stf.bone",
"name": "LowerArm.R",
"children": [
"534a659c-5d6e-4692-9228-2974debbb46e",
"3ea99969-ff70-48b6-9f47-168367e54296",
"31832adf-f1eb-4902-9458-9946bbbdb463"
],
"connected": true,
"translation": [
-0.32599180936813354,
1.0100003480911255,
-0.04301619902253151
],
"rotation": [
-0.5354142189025879,
0.5126163959503174,
0.5126165747642517,
0.4333362877368927
],
"length": 0.21657702326774597
}
stf.instance.armature
Instantiates an armature onto a node.
Properties
Key | Required | Type | Description |
---|---|---|---|
armature | Yes | Resource-ID | ID of the instantiated armature resource, usually stf.armature |
pose | No | Map<Resource-ID, TRS> | Map of the corresponding bone and TRS. |
Implementations
Json Example
"73d67945-2937-41c8-b683-7a992cbca5c5": {
"type": "stf.instance.armature",
"name": "",
"armature": "5251057d-a989-417b-a007-0bbc2fad19d3",
"pose": {
"ead3e787-8014-48ac-9af9-37db03edaed6": [
[ 3.166873430160422e-10, 0.009894609451293945, -0.0011758268810808659 ],
[ 0.5493189096450806, 9.955886071111308e-08, 6.540119557030266e-08, 0.8356127738952637 ],
[ 1.0, 1.0, 1.000001072883606 ]
],
"793cd8e7-81aa-4034-939b-33fda8582fd8": [
[ 2.4785646868252798e-09, 0.02414402738213539, -0.010395778343081474 ],
[ 0.09529310464859009, -2.0173215489194263e-06, -1.7039580768596352e-07, 0.9954492449760437 ],
[ 1.0, 0.9999999403953552, 0.9999999403953552 ]
],
"9a663148-f9a4-4b24-8f4c-7f4d388330dc": [
[ -3.951510230137956e-09, 0.04944222792983055, 0.016573714092373848 ],
[ 0.19152779877185822, -3.042036723854835e-06, -5.479599849422812e-07, 0.9814872145652771 ],
[ 1.0, 0.9999999403953552, 0.9999998807907104 ]
]
}
}
stf.mesh
Datemodel
Face -> Triangle -> Face Corner -> Split -> Vertex
Face: Material Index Split: Normal, UVs, Colors Vertex: Position
Properties
Key | Required | Type | Description |
---|---|---|---|
float_width | No | uint | Byte-width of float-values |
indices_width | No | uint | Byte-width of indices |
material_slots | No | List<Resource-ID / null> | List of material IDs in the order of the meshes material-slots |
vertices | Yes | Buffer-ID | 3 floats per vertex |
face_corners | Yes | Buffer-ID | Index of the split for each face corner |
splits | Yes | Buffer-ID | Vertex index for each unique combination of normals, uvs, colors, etc.. |
split_normals | No | Buffer-ID | 3 floats per normal |
split_colors | No | Buffer-ID | 4 floats per color (rgba) |
tris | No | Buffer-ID | 3 indices per triangle |
faces | No | Buffer-ID | number of tris for the face |
material_indices | No | Buffer-ID | |
sharp_edges | No | Buffer-ID | |
sharp_face_indices | No | Buffer-ID | |
lines | No | Buffer-ID | |
armature | No | Resource-ID | ID of the armature if the mesh is skinned |
weight_lens_width | No | uint | |
bone_indices_width | No | uint | |
bones | No | List | Bone references in the order by which they will be referenced by bone_indices . |
weight_lens | No | Buffer-ID | |
bone_indices | No | Buffer-ID | |
weights | No | Buffer-ID | |
uvs | No | List | |
blendshapes | No | List | |
vertex_groups | No | List |
UV-Object properties
Key | Required | Type | Description |
---|---|---|---|
name | Yes | string | |
uv | Yes | Buffer-ID | 2 floats per split |
Blendshape-Object properties
Key | Required | Type | Description |
---|---|---|---|
name | Yes | string | |
default_value | No | float | default: 0 |
limit_upper | No | float | default: 1 |
limit_lower | No | float | default: 0 |
indices | No | Buffer-ID | int |
position_offsets | Yes | Buffer-ID | 3 floats per vertex |
split_indices | No | Buffer-ID | int |
split_normals | No | Buffer-ID | 3 floats per split |
VertexGroup-Object properties
Key | Required | Type | Description |
---|---|---|---|
name | Yes | string | |
indices | No | Buffer-ID | int |
weights | Yes | Buffer-ID | float per vertex |
...TODO
Implementations
Json Example
"783134da-9e2a-4d69-a1f0-59952bc36895": {
"type": "stf.mesh",
"name": "Superawesome Mesh",
"material_slots": [
"dc07246c-47e9-41bb-b009-5a4eb60303e4"
],
"float_width": 4,
"indices_width": 2,
"vertices": "23ec5dc3-2e0e-460b-b07d-413e64f9326e",
"face_corners": "3e6c056e-6dd9-4011-bb14-97cf8e6eaaa0",
"splits": "c4c432c7-2b1e-4282-92a3-af1a001b08bf",
"split_normals": "528e70e1-65a1-4155-bff5-cc60fa140d14",
"uvs": [
{
"name": "UVMap",
"uv": "a0001434-7844-4038-ba8a-2e0540fe65c8"
}
],
"tris": "98ef746d-1023-424b-ac04-2b27540637b6",
"material_indices_width": 1,
"faces": "f15060e3-49f1-43d6-a6e9-117984cbe8fe",
"material_indices": "04a31482-e1cd-437b-be16-be26f164bfdb",
"sharp_face_indices": "5ef64c4d-0cc8-4ad1-aadc-898b8cc7b436",
"lines": "13084993-3492-48ca-956b-0ee0766527bf",
"sharp_edges": "a9d12c37-94d3-43f0-ae48-4a4619416f6e",
"vertex_groups": [
{
"name": "Select Some Things",
"weights": "14f9133b-fcd4-4c00-95ee-7d8c7dab8bff",
"indices": "af4f4676-5e26-49fc-a639-4e467076828e"
},
{
"name": "Normal Project Blend Weights",
"weights": "2a69a2fe-1a2e-4472-a3cf-064762d6b974"
}
],
"blendshapes": [
{
"name": "ToggleOff",
"default_value": 0.0,
"limit_upper": 1.0,
"limit_lower": 0.0,
"indices": "313f0ad4-4933-49bf-8c0c-6957c2750d16",
"position_offsets": "b4d196a5-1776-460f-8e04-721d7cff5281",
"split_indices": "c854ed9b-93df-41f5-ab43-e0e9b8ae2625",
"split_normals": "5fa5f424-6f4e-49c4-82b5-fb8dcaff82ef"
},
{
"name": "Vis_AA",
"default_value": 0.0,
"limit_upper": 1.0,
"limit_lower": 0.0,
"position_offsets": "9db99d09-0ff7-4f92-896e-0318a31bfd46",
"split_normals": "949c0d7a-edb7-4d8e-9b9f-c24a56646f65"
},
{
"name": "Vis_IH",
"default_value": 0.0,
"limit_upper": 1.0,
"limit_lower": 0.0,
"position_offsets": "37118f5c-3dee-4e75-8067-adec146769d0",
"split_normals": "7c88cbd6-38c2-4755-90aa-54fcd9a880d3"
}
],
"components": [
"60850594-9bab-4cb2-ac64-657ec5589f5f",
"5e6c4973-d3cf-423f-aabe-a6a6d0959e40"
]
}
stf.instance.mesh
Instantiates a mesh onto a node.
Properties
Key | Required | Type | Description |
---|---|---|---|
mesh | Yes | ID | Resource-ID of the instantiated mesh resource, usually xref:../data/stf_mesh.adoc[stf.mesh ] |
armature_instance | No | Resource-ID | ID of a node with an instantiated armature. Usually the instance resource is xref:./stf_instance_armature.adoc[stf.instance.armature ] |
blendshape_values | No | List | |
materials | No | List |
Implementations
Json Example
"799b9826-85d9-40a3-a58b-b6489ba60452": {
"type": "stf.instance.mesh",
"mesh": "8dedc60f-91cd-4e5e-a032-07dc82358519",
"armature_instance": "e6ae2ed1-fc53-43ee-ac53-05bf296d5fc1",
"blendshape_values": [
null,
0.3,
0.65,
null,
null,
null,
1.0,
null
]
},
stf.material
Properties
Key | Required | Type | Description |
---|---|---|---|
style_hints | No | List | Hints on the visual style of the material |
shader_targets | No | Dict<List | Hints on the target stader per target application |
properties | Yes | Dict<String, Property-Object> | Dict of Property-ID as a string to an Object |
Property-Object properties
Key | Required | Type | Description |
---|---|---|---|
type | No | String | Type of the value variables |
values | No | List | List of values. The value object is determined by the type |
The following types for property-values are supported:
float
Json float value
int
Json int value
color
Json array of four floats, corresponding to the RGBA color channels.
image
An Image-Property-Value-Object:
Key | Required | Type | Description |
---|---|---|---|
image | Yes | Resource-ID | ID of an stf.image or compatible resource. |
TODO: the image object should be expanded with UV-offsets and such
Implementations
Json Example
"bdf11d99-70d2-42df-8a58-19f1e5238662": {
"type": "stf.material",
"name": "Body",
"style_hints": [
"realistic",
"pbr"
],
"shader_targets": {
"stfblender": [
"ShaderNodeBsdfPrincipled"
],
"unity": [
"PoiyomiToon"
]
},
"properties": {
"albedo.texture": {
"type": "image",
"values": [
{
"image": "1bf800ea-1bda-491c-ba89-c7bfa364e239"
}
]
},
"roughness.texture": {
"type": "image",
"values": [
{
"image": "155888f8-041c-4fe7-bf57-a558bd7b2137"
}
]
},
"metallic.texture": {
"type": "image",
"values": [
{
"image": "937ef22d-5175-4c4b-aa89-51da4c445dd4"
}
]
},
"normal.texture": {
"type": "image",
"values": [
{
"image": "e0c8e0ce-f667-49cc-b39a-5fb2dcde48ee"
}
]
}
}
}
stf.image
Properties
Key | Required | Type | Description |
---|---|---|---|
format | Yes | String | Format of the image. Officially supported formats are: png , jpg |
buffer | Yes | Buffer-ID | Buffer containing the image file |
data_type | No | String | Type of image data. As of not it can be color or non_color . |
Implementations
Json Example
"1bf800ea-1bda-491c-ba89-c7bfa364e239": {
"type": "stf.image",
"name": "Body_BaseColor.png",
"format": "png",
"buffer": "ef192623-cc41-445e-acd7-e435be793e95",
"data_type": "color",
"components": [
"f79c8521-845f-4a6c-a44f-bd2647877e0e"
]
}
stf.texture
Information on how an image is to be converted into a GPU texture.
Properties
Key | Required | Type | Description |
---|---|---|---|
width | Yes | int | Width of the resulting GPU texture |
height | Yes | int | Height of the resulting GPU texture |
downscale_priority | Yes | int | In case of an enforced memory limit, how quickly should the resolution of the resulting GPU texture reduced. |
quality | Yes | float | Indicate how much the GPU texture can be compressed. Value range is from 0 to 1. 1 means not compression should be used. |
mipmaps | Yes | bool | Whether to generate mipmaps |
Implementations
Json Example
"f0aa405c-8548-453d-8758-516e5c43d45e": {
"type": "stf.texture",
"width": 1024,
"height": 1024,
"downscale_priority": 0,
"quality": 0.800000011920929,
"mipmaps": true
}
stf.animation
An animation relative to a prefab.
Properties
Key | Required | Type | Description |
---|---|---|---|
loop | Yes | string | Whether to loop the animation and how |
fps | Yes | float | |
range | Yes | List | Beginning and end frame of the animation |
bake_on_export | No | bool | Whether the animation should be baked on |
tracks | Yes | List |
Track-Object properties
Key | Required | Type | Description |
---|---|---|---|
target | Yes | Path | STF path of the target property |
subtracks | Yes | List<Subtrack-Object / null> |
Subtrack-Object properties
Key | Required | Type | Description |
---|---|---|---|
keyframes | Yes | List<Keyframe-Array / null> | |
baked | No | Buffer-ID | Baked values between range[0] and range[1] |
Keyframe-Array
Index | Type | Description |
---|---|---|
0 | bool | true if this keyframe is a source of truth, as in not baked or generated. |
1 | float | Timepoint in frames |
2 | float | The main value |
3 | string | interpolation type |
In case the previous keyframe has an out-tangent, this keyframes in-tangent is added at the last position in the keyframe-array.
Index | Type | Description |
---|---|---|
last | float | In-tangent x and y offset, present only if the previous keyframe has an out-tangent |
Depending on the interpolation type
, the following properties are added.
bezier
Index | Type | Description |
---|---|---|
4 | string | tangent type |
5 | List | Out-tangent x and y offset |
Implementations
Json Example
"6a60e775-4374-4439-bbbe-49ea5edc9438": {
"type": "stf.animation",
"name": "Anim Test",
"loop": "none",
"fps": 24,
"bake_on_export": true,
"range": [
1.0,
16.0
],
"tracks": [
{
"target": [
"737c6e44-4269-409b-95a8-cfc8e680a13b",
"t"
],
"subtracks": [
{
"keyframes": [
[
true,
1.0,
-0.7435536980628967,
"bezier",
"aligned",
[
2.0,
0.0
]
],
[
true,
16.0,
-0.2216922640800476,
"bezier",
"aligned",
[
3.0,
0.0
],
[
-3.0,
0.0
]
]
],
"baked": "ba4b975f-3df3-42cf-8508-d527b1468b18"
},
{
"keyframes": [
[
true,
1.0,
2.200054168701172,
"bezier",
"aligned",
[
2.0,
0.0
]
],
[
true,
16.0,
0.4340066909790039,
"bezier",
"aligned",
[
3.0,
0.0
],
[
-3.0,
0.0
]
]
],
"baked": "591f8e72-d4bc-456f-8420-95a46a687329"
},
{
"keyframes": [
[
true,
1.0,
1.996330738067627,
"bezier",
"aligned",
[
2.0,
0.0
]
],
[
true,
16.0,
0.2330167293548584,
"bezier",
"aligned",
[
3.0,
0.0
],
[
-3.0,
0.0
]
]
],
"baked": "b1951f62-a79e-4cfb-bb3b-75e431d52ca0"
}
]
},
{
"target": [
"737c6e44-4269-409b-95a8-cfc8e680a13b",
"instance",
"blendshape",
"Key 1",
"value"
],
"subtracks": [
{
"keyframes": [
[
true,
1.0,
0.0,
"bezier",
"aligned",
[
2.0,
0.0
]
],
[
true,
7.0,
0.7300613522529602,
"bezier",
"aligned",
[
3.0,
0.0
],
[
-2.0,
0.0
]
],
[
true,
16.0,
0.0,
"bezier",
"aligned",
[
3.0,
0.0
],
[
-3.0,
0.0
]
]
],
"baked": "fba2e828-e6c9-476f-b47c-d1851bcacc7d"
}
]
}
]
},
stfexp.*
stfexp.mesh.seams
stfexp.mesh.creases
stfexp.constraint.twist
stfexp.constraint.rotation
stfexp.constraint.translation
stfexp.constraint.parent
stfexp.constraint.lookat
stfexp.lightprobe_anchor
stfexp.armature.humanoid
ava.*
ava.avatar
ava.collider.sphere
ava.collider.capsule
ava.collider.plane
ava.secondary_motion
ava.eyerotation.bone
ava.eyelids.blendshape
ava.visemes.blendshape
ava.emotes
Guides
STF Blender User Guide
Export - Import
An STF asset is represented by a Blender Collection. By default the Scene Collection is used.
If you wish to use another one, select it and check Use as STF Prefab
in the STF Editor
panel.
If you click the Set as STF export root
button, it will be automatically selected on export.
Anything parented to the Collection will be exported.
When an STF file gets imported, it will become its own Collection.
Resources
Everything that can be exported in STF will get its own unique ID. If it is not set on before export, STF will automatically assign one. If STF encounters a duplicate ID, it will reassing it.
By default the Blender name of a resource will be used. It can be optionally overridden.
Component Resources
Resource have Components. These are 'sub-resources' which add additional information/data to their parent resource. Some, like mesh-seams are natively supported by Blender, however most arent.
Components can be added/edited in the Components
section of each resources panel.
Unity
TBD
Godot
TBD