Roblox Attributes Binary Format
This document describes the Attribute binary format. In this format there is no field for Version, so it is assumed that any future changes will be additions to the existing format or a new format entirely.
Contents
Document Conventions
This document assumes a basic understanding of Rust’s convention for numeric types. For example:
u32is an unsigned 32-bit integerf32is a 32-bit floating point
All numeric types are little endian and signed integers are stored using two’s complement. All floats are stored according to the IEEE-754 standard.
Unless otherwise noted, all structs in this document are assumed to be stored with their components in the sequence listed without any modification. That is, if a struct is listed as being composed of an i32 and an f32, it can be assumed that it is stored as an i32 followed by an f32.
File Structure
Unlike the normal binary format, the attribute format is not chunk based. Instead, it follows a basic name-type-value sequence.
The exception to this is the beginning of the blob, which indicates how many attributes are stored in the blob.
The first 4 bytes of the blob are a u32 which indicates how many attributes there are in the blob (the Length). Following that, there are Length attributes in the layout:
| Field Name | Format | Value |
|---|---|---|
| Name | String | The name of this attribute |
| Type | u8 |
The data type of this attribute |
| Value | Variant | A value whose type and layout is determined by Type |
Data Types
For every data type that attributes can be, there’s a corresponding value of Type that’s used to indicate an attribute is of that type. Despite similiarities to the binary file format, these are not transferable between the two (e.g. in the binary format, String is 0x01 but here it is 0x02). The following are attribute types supported by Roblox Studio.
String
Type ID 0x02
The String type is stored as a length-prefixed sequence of bytes. The length is stored as a u32. Strings can contain binary data, and should be considered to be an array of u8s.
| Field Name | Format | Value |
|---|---|---|
| Length | u32 |
The length of the string |
| Data | Array(Bytes) | The actual bytes that make up the string |
Bool
Type ID 0x03
The Bool type is stored as a single byte. If the byte is 0x00, the bool is false. If it is 0x01, it is true.
It is worth noting that Roblox Studio will interpret any non-zero value as true.
Int32
Type ID 0x04
The Int32 type is stored as a little-endian 32-bit integer.
Float32
Type ID 0x05
The Float32 type is stored as a single-precision float, also known as an f32 or single, or sometimes even simply float.
This type is accepted by Roblox Studio, though will almost never be generated by it. In some cases the Roblox Studio Properties widget may cause this type to appear.
Float64
Type ID 0x06
The Float64 type is stored as a double-precision float, also known as an f64 or double.
UDim
Type ID 0x09
The UDim type is stored as a struct composed of a f32 and an i32:
| Field Name | Format | Value |
|---|---|---|
| Scale | f32 |
The Scale component of the UDim |
| Offset | i32 |
The Offset component of the UDim |
As an example, the UDim {123, 456} would look like this: 00 00 f6 42 c8 01 00 00.
UDim2
Type ID 0x0A
The UDim2 type is stored as a struct composed of two UDims, one for each axis:
| Field Name | Format | Value |
|---|---|---|
| X Scale | UDim |
The X component of the UDim2 |
| X Offset | UDim |
The Y component of the UDim2 |
An encoded UDim2 with the value {1, 2, 3, 4} would look like this: 00 00 80 3f 02 00 00 00 00 00 40 40 04 00 00 00.
BrickColor
Type ID 0x0E
The BrickColor type is stored as a single u32 indicating the Number property of the BrickColor.
Color3
Type ID 0x0F
The Color3 type is stored as a set of three f32s:
| Field Name | Format | Value |
|---|---|---|
| R | f32 |
The R component of the Color3 |
| G | f32 |
The G component of the Color3 |
| B | f32 |
The B component of the Color3 |
A Color3 with the RGB value 0, 102, 255 would look like this: 00 00 00 00 cd cc cc 3e 00 00 80 3f.
Vector2
Type ID 0x10
The Vector2 type is a struct composed of two f32s:
| Field Name | Format | Value |
|---|---|---|
| X | f32 |
The X component of the Vector2 |
| Y | f32 |
The Y component of the Vector2 |
A Vector2 with the value 10, 20 looks like this: 00 00 20 41 00 00 a0 41.
Vector3
Type ID 0x11
The Vector3 type is a struct composed of three f32s:
| Field Name | Format | Value |
|---|---|---|
| X | f32 |
The X component of the Vector2 |
| Y | f32 |
The Y component of the Vector2 |
| Z | f32 |
The Z component of the Vector2 |
A Vector3 with the value 10, 20, 30 looks like this: 00 00 20 41 00 00 a0 41 00 00 f0 41.
CFrame
Type ID 0x14
The CFrame type is composed of a Vector3, a 1-byte rotation ID, and an optional rotation matrix:
| Field Name | Format | Value |
|---|---|---|
| Position | Vector3 |
The positional component of the CFrame. |
| Rotation ID | u8 |
An identifier representing axis-alignment of the rotation, determining whether the rotation matrix is present (see Rotation matrix). If the rotation is axis-aligned, this field is one of the values from the table below; otherwise, it is 00. |
| Rotation matrix | Optional<Matrix3> |
The rotational component of the CFrame, stored as a sequence of nine f32s. If Rotation ID is 00, this field is the XVector, the YVector, and ZVector, in that order; otherwise, it is absent. |
A rotation is considered “axis-aligned” if it’s in increments of 90 degrees around one or more axes. The following table shows the mapping between Rotation IDs and rotations (rotations are Euler angles in degrees, applied in the order Y -> X -> Z):
| ID | Rotation | ID | Rotation |
|---|---|---|---|
02 |
(0, 0, 0) | 14 |
(0, 180, 0) |
03 |
(90, 0, 0) | 15 |
(-90, -180, 0) |
05 |
(0, 180, 180) | 17 |
(0, 0, 180) |
06 |
(-90, 0, 0) | 18 |
(90, 180, 0) |
07 |
(0, 180, 90) | 19 |
(0, 0, -90) |
09 |
(0, 90, 90) | 1b |
(0, -90, -90) |
0a |
(0, 0, 90) | 1c |
(0, -180, -90) |
0c |
(0, -90, 90) | 1e |
(0, 90, -90) |
0d |
(-90, -90, 0) | 1f |
(90, 90, 0) |
0e |
(0, -90, 0) | 20 |
(0, 90, 0) |
10 |
(90, -90, 0) | 22 |
(-90, 90, 0) |
11 |
(0, 90, 180) | 23 |
(0, -90, 180) |
A CFrame with the value CFrame.new(1, 2, 3) * CFrame.Angles(0, 45, 0) looks like this when serialized: 00 00 80 3f 00 00 00 40 00 00 40 40 00 f3 04 35 3f 00 00 00 00 f3 04 35 3f 00 00 00 00 00 00 80 3f 00 00 00 00 f3 04 35 bf 00 00 00 00 f3 04 35 3f.
Demonstrating the axis-aligned rotation matrix case, a CFrame with the value CFrame.new(1, 2, 3) looks like this: 00 00 80 3f 00 00 00 40 00 00 40 40 02.
EnumItem
Type ID 0x15
The EnumItem type is composed of two parts:
| Field Name | Format | Value |
|---|---|---|
| Enum Name | String |
The name of the Enum of this EnumItem |
| Value | u32 |
The Value field of the EnumItem |
NumberSequence
Type ID 0x17
The NumberSequence type is stored as a struct composed of a u32 and an array of NumberSequenceKeypoints:
| Field Name | Format | Value |
|---|---|---|
| Keypoint Count | u32 |
The number of keypoints in the sequence |
| Keypoints | Array(NumberSequenceKeypoint) | The keypoints that make up the sequence |
A NumberSequenceKeypoint is stored as a struct composed of three f32s:
| Field Name | Format | Value |
|---|---|---|
| Envelope | f32 | The envelope for the keypoint |
| Time | f32 | The time for the keypoint |
| Value | f32 | The value of the keypoint |
A NumberSequence with the keypoints 0, 0, 0, 0.5, 1, 0, and 1, 1, 0.5 would look like this: 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3f 00 00 80 3f 00 00 00 3f 00 00 80 3f 00 00 80 3f
ColorSequence
Type ID 0x19
The ColorSequence type is stored as a struct composed of a u32 and an array of ColorSequenceKeypoints:
| Field Name | Format | Value |
|---|---|---|
| Keypoint Count | u32 |
The number of keypoints in the sequence |
| Keypoints | Array(ColorSequenceKeypoint) | The keypoints that make up the sequence |
A ColorSequenceKeypoint is stored as a struct composed of three f32s:
| Field Name | Format | Value |
|---|---|---|
| Envelope* | f32 | The envelope for the keypoint |
| Time | f32 | The time for the keypoint |
| Value | Color3 |
The value of the keypoint |
*ColorSequenceKeypoint has a field for Envelope despite not having one; it will always be 00 00 00 00
A ColorSequence with the keypoints 0, RGB(255, 0, 0), 0.5, RGB(0, 255, 0), and 1, RGB(0, 0, 255) would look like this: 03 00 00 00 00 00 00 00 00 00 00 00 00 00 80 3f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3f 00 00 00 00 00 00 80 3f 00 00 00 00 00 00 00 00 00 00 80 3f 00 00 00 00 00 00 00 00 00 00 80 3f
NumberRange
Type ID 0x1B
The NumberRange type is a struct composed of two f32s:
| Field Name | Format | Value |
|---|---|---|
| Min | f32 |
The Min component of the NumberRange |
| Max | f32 |
The Max component of the NumberRange |
A NumberRange with the value 10, 20 would look like this: 00 00 a0 40 00 00 20 41.
Rect
Type ID 0x1C
The Rect type is a struct composed of two Vector2s:
| Field Name | Format | Value |
|---|---|---|
| Min | Vector2 |
The Min component of the Rect |
| Max | Vector2 |
The Max component of the Rect |
A Rect with the value 10, 20, 30, 40 would look like this: 00 00 20 41 00 00 a0 41 00 00 f0 41 00 00 20 42.
Font
Type ID 0x21
The Font type is a struct composed of a u16, u8 and two Strings
| Field Name | Format | Value |
|---|---|---|
| Weight | u16 |
The weight of the font |
| Style | u8 |
The style of the font |
| Family | String |
The font family content URI |
| CachedFaceId | String |
The cached content URI of the TTF file |
The Weight and Style values refer to the FontWeight and FontStyle enums respectively. They are stored as unsigned little-endian
The CachedFaceId field will always be present, but may be an empty string.
A regular Source Sans Pro font will be stored as 90 01 00 2C 00 00 00 72 62 78 61 73 73 65 74 3A 2F 2F 66 6F 6E 74 73 2F 66 61 6D 69 6C 69 65 73 2F 53 6F 75 72 63 65 53 61 6E 73 50 72 6F 2E 6A 73 6F 6E 2A 00 00 00 72 62 78 61 73 73 65 74 3A 2F 2F 66 6F 6E 74 73 2F 53 6F 75 72 63 65 53 61 6E 73 50 72 6F 2D 52 65 67 75 6C 61 72 2E 74 74 66