How the Transform Synchronization Feature Module works

What is transform

The transform of an entity describes its location and rotation. Worker-instances generally use it to run physics simulations or render entities for a client. Note that the SpatialOS representation of transform is not the same as Unity’s representation of transform.

In the Transform Synchronization Feature Module, we represent the Transform as:

package improbable.gdk.transform_synchronization;

type FixedPointVector3 {
    sint32 x = 1;
    sint32 y = 2;
    sint32 z = 3;

type CompressedQuaternion {
    uint32 data = 1;

component TransformInternal {
    id = 11000;
    FixedPointVector3 location = 1;
    CompressedQuaternion rotation = 2;
    FixedPointVector3 velocity = 3;
    uint32 physics_tick = 4;
    float ticks_per_second = 5;

Note: The TransformInternal component contains additional fields such as velocity and physics_tick. These are implementation details of the Transform Synchronization Feature Module.

How TransformInternal is compressed


Although the Improbable Position component uses 3 doubles, a Unity transform represents location as three floats. This makes the double-precision of Position redundant, and location can be represented with 96 bits instead of 192.

To further optimise this, the FixedPointVector3 type is introduced to represent a location as three Q21.10 fixed-point values. This type represents each of its components as variable-length zig-zag encoded integers, so that smaller absolute values use fewer bits.

With the Q21.10 format, each fixed point value is within the range -2097152 to 2097151.999 at a precision of 0.0009765625 (2^-10). By encoding as a FixedPointVector3, location requires at most 96 bits instead of always requiring 96 bits.


The rotation of a transform is compressed from four floats to a single 32 bit unsigned integer, using the “smallest three” trick. As a quaternion’s length must equal 1, the largest component can be dropped and recalculated later from the values of the other components. By storing the smallest three components at a lower precision, an entire quaternion can fit into 32 bits.

The CompressedQuaternion schema type utilises 2 bits to define the index of the largest component and 10 bits to encode each quaternion element, which translates to a mean precision in Euler angles of 0.08 degrees.

How do my entities’ transform get synchronized

The behaviour of the Transform Synchronization Feature Modules differs depending on whether your worker-instance is authoritative over the TransformInternal and Position components. This behaviour can be adjusted with transform synchronization strategies, but broadly goes as follows:

On authoritative worker-instances

The Transform Synchronization Feature Module listens for changes in the native Unity transform representation (UnityEngine.Transform or UnityEngine.Rigidbody) and translates these into TransformInternal and Position component updates.

This means that, as a user, you shouldn’t manually update the TransformInternal or Position components. You can simply move your GameObjects as you normally would and these changes will be synchronized as specified in the applied strategy.

On non-authoritative worker-instances

The Transform Synchronization Feature Module listens for SpatialOS component updates in the TransformInternal component and applies these changes to the native Unity transform representation (UnityEngine.Transform or UnityEngine.Rigidbody) as specified in the applied strategy.

Search results

Was this page helpful?

Thanks for letting us know!

Thanks for your feedback

Need more help? Ask on the forums