Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/facepunch/sbox-public/llms.txt

Use this file to discover all available pages before exploring further.

The [Sync] attribute tells s&box to automatically replicate a component property from the owner to every other connected client. This page covers how [Sync] works, what SyncFlags control, and how to enable smooth interpolation between network ticks.

Adding [Sync] to a property

Decorate any public property on a component with [Sync] to have its value sent over the network whenever it changes:
public class PlayerHealth : Component
{
    [Sync] public float Health { get; set; } = 100f;
    [Sync] public bool IsAlive { get; set; } = true;
}
The engine instruments the property’s getter and setter at compile time. When the owner writes to Health, the new value is queued for transmission and applied on all remote clients before any RPC that references the same object fires.
[Sync] properties are sent reliably by default. The current value is always up-to-date on remote clients before an RPC is delivered on that object.

What types can be synced?

Any serializable value type works: bool, int, float, double, string, Vector3, Rotation, Angles, Transform, Color, enums, and structs made up of those types. Reference types (classes) are not directly supported.

Who sends the sync?

By default the owner of the NetworkObject is the sender, and all other clients receive the value as read-only. The host controls objects that have no owner (IsUnowned == true).

SyncFlags.FromHost

To make the host the authoritative writer — regardless of who owns the object — add SyncFlags.FromHost:
// Only the host may write this value; all clients receive it
[Sync( SyncFlags.FromHost )] public int Score { get; set; }
This is equivalent to the deprecated [HostSync] attribute, which was a shorthand for [Sync( SyncFlags.FromHost )]. Prefer the SyncFlags form in new code.

SyncFlags reference

Pass flags to the [Sync] constructor to change synchronization behaviour. Flags can be combined with |.
FlagDescription
SyncFlags.FromHostThe host is the authoritative writer, not the owner.
SyncFlags.QueryThe engine polls the getter each tick for changes instead of relying on the setter being called. Use this when the value can change without going through the property setter.
SyncFlags.InterpolateThe received value is interpolated between ticks on remote clients. Supported for float, double, Angles, Rotation, Transform, and Vector3.
// Polled every tick instead of tracking setter calls
[Sync( SyncFlags.Query )] public float SimulatedValue => _internal;

// Smooth position on remote clients
[Sync( SyncFlags.Interpolate )] public Vector3 NetworkPosition { get; set; }

// Combine flags
[Sync( SyncFlags.FromHost | SyncFlags.Interpolate )] public Rotation NetworkRotation { get; set; }

Interpolation

When SyncFlags.Interpolate is set, the engine maintains an InterpolatedSyncVar<T> buffer for the property. On remote clients the getter returns a smoothed value sampled at Time.Now - Networking.InterpolationTime (100 ms by default), which eliminates the jitter you would see if you rendered the raw network-tick value directly.
public class MovingPlatform : Component
{
    // Remote clients see a smooth position; owner writes raw position each tick
    [Sync( SyncFlags.Interpolate )] public Vector3 PlatformPosition { get; set; }

    protected override void OnFixedUpdate()
    {
        if ( GameObject.Network.IsProxy )
            return;

        PlatformPosition = Transform.Position;
    }
}
Interpolation only affects how remote clients read the property. The owner always writes and reads the true current value.

Supported interpolation types

TypeNotes
floatLinear interpolation
doubleLinear interpolation
Vector3Component-wise lerp
RotationSlerp
AnglesComponent-wise lerp
TransformPosition lerp + rotation slerp
Any type that implements IInterpolator<T> is also supported, allowing you to provide custom interpolation logic.

Reliable vs. unreliable delivery

[Sync] values are transmitted via the reliable data table path by default, meaning the engine guarantees delivery and ordering. For values you mark with SyncFlags.Query, changes are included in the unreliable snapshot stream that is broadcast every network tick, so they may arrive slightly later than values changed through the setter.
If a property is only written via methods that bypass the setter (e.g., a field mutated by reference), set SyncFlags.Query so the engine polls for the change. Otherwise the update will never be sent.

Reading sync values safely

On proxy clients, [Sync] properties are read-only by convention — writing to them from a non-owner has no effect on remote machines. Guard against accidental writes with the IsProxy check:
protected override void OnUpdate()
{
    if ( !GameObject.Network.IsProxy )
    {
        Health -= Time.Delta * DamageRate;
    }

    // Read Health on all clients — it will be up to date
    HealthBar.SetProgress( Health / MaxHealth );
}

Combining [Sync] with RPCs

Synced values are flushed before an RPC is delivered on the same object, so you can safely read them inside an RPC handler:
[Sync] public string PlayerName { get; set; }

[Rpc.Broadcast]
public void AnnounceJoin()
{
    // PlayerName is guaranteed to be up-to-date here on all clients
    Log.Info( $"{PlayerName} joined the game" );
}

NetworkFlags and transform sync

For the GameObject transform itself (position, rotation, scale), use NetworkFlags rather than [Sync]. See Networking overview for the full flag list.

Next steps

RPCs

Trigger behaviour on remote clients with Rpc.Broadcast, Rpc.Host, and Rpc.Owner.

Networking overview

Understand the host/client model, ownership, and NetworkObject.

Build docs developers (and LLMs) love