Roblox Attributes Binary Format

Roblox DOM and (de)serialization implementation in Rust


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:

  • u32 is an unsigned 32-bit integer
  • f32 is 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