Mesh Visual Scripting Programmer's Guide

Go to the Visual Scripting overview article

Limitations

  • Only a subset of Unity functionality is exposed to visual scripts.
  • Variables and properties with non-simple types (including object references) aren't automatically shared. See Sharing and networking below to learn more about this.

Hello World

The simplest visual script you can create is one that just opens a message box:

Screen shot of the visual script graph of the Hello World sample

This is how it looks in Mesh:

Mesh browser window with a popup dialog displaying Hello World and an OK button

Screen shot of the Unity Editor with the Mesh Visual Scripting Hello World scene open.

Testing your scripts

Before you upload your scene to Mesh, you can develop and test visual scripts, even with multiple clients in split screen mode, using Play Mode with Mesh Emulation.

Visual script diagnostics in the Editor

When a GameObject with a Script Machine is selected in the transform hierarchy, Mesh displays the Mesh Visual Scripting Diagnostics panel at the bottom of the Inspector panel:

Screen shot of the Mesh Visual Scripting diagnostics panel

The diagnostics panel gives immediate feedback on any warnings or errors that might prevent your scripts from working well in Mesh.

Current limitation: Future versions of the diagnostics panel may also give insight into the visual script's use of shared variables and properties and display additional diagnostics and warnings.

Uploading to Mesh

Use the Mesh Uploader to upload scenes that contain visual scripts. To open the Uploader, on the Mesh Toolkit menu, select Environments.

Note: Mesh Uploader validates visual scripts before upload and refuses to upload when there are any validation errors in any visual scripts. Detailed diagnostics are output to the Console.

Sharing and networking

Shared and local script state

Mesh uses Unity Visual Scripting, which is designed to work without networking. Visual scripts run on each client independently. However, the users' Mesh experience is shared; all users experience a single shared scene that looks the same on all clients.

The effect of a visual script's execution is how it changes the scene's state.

By default, Mesh automatically replicates scene changes done by visual scripts on one client to all other clients. Aside from everything that's shared in a scene, some state remains independent on each client (in other words, local).

Local changes temporarily take precedence over changes coming in from clients. Example: If you keep animating an object locally, your local animation isn't compromised by changes coming in from other clients.

There's some automatic update rate limiting. A client doesn't send additional updates while one is still in flight; there's one update sent per roundtrip through the server. This amounts to approximately five to six updates per second in practical situations. This means that a smooth animation driven by one client won't look smooth on other clients. The best practice is to do smooth animations locally, ideally not through visual scripts but through the normal Unity animation system.

Eventual consistency of shared state is guaranteed (even if clients' states can temporarily be different).

Local state:

  • Natural local state – sounds, UI, rendering.
  • User-controlled local state – sub-scenes marked with the Local Script Scope component.
  • Technical local state – objects that aren't part of the scene hierarchy (for example, renderer materials, assets).

Shared state:

  • Limited to visual script variables and the properties of GameObjects and scene components that are part of the scene hierarchy.
  • Only variables and properties of simple types can be replicated: integers, floating-point numbers, booleans, strings, Color, Vector2/3/4, Quaternion, Matrix4x4, and Rect.

Any change to shared state is sent over the network. This increases network traffic and, if used carelessly, can consume significant bandwidth.

Shared and local script triggers

All visual script flows start in response to an event.

  • If the event originates on a single client (for example, the user clicks a button), the visual script executes only on that client.
  • If the event occurs on all clients, the visual script executes on all clients (for example, timer event, shared property change, shared variable update, avatar enters trigger, physics body touches collider).

When adding a node to detect if an object is selected, it's important to choose the correct one. You have two choices: Mesh Interactable Body: Is Selected Locally, and Mesh Interactable Body: Is Selected. Let's say, for example, you want to have a button that can be clicked to trigger teleportation. To have the attendee click the button and transport only themselves, use the Mesh Interactable Body: Is Selected Locally node.

Screen shot of the Mesh Interactable Body Is Selected locally node.

To have the attendee click the button and teleport everyone in the experience, use the Mesh Interactable Body: Is Selected node. In each case, the text above the node tells you the behavior to expect:

Screen shot of the Mesh Interactable Body Is Selected node, which will affect all clients.

If a local script sets a shared variable and a second script listens to changes to this variable (using the On State Changed trigger; see below), the second script will be executed on all clients.

Mesh offers some special script nodes:

  • On Interval triggers at regular intervals synchronously on all clients.
  • On State Changed triggers when its inputs change (for example, shared properties, shared variables, local).
  • Show Dialog displays a message dialog with custom text that may optionally provide buttons as response options.

Mesh makes certain trade-offs in favor of simplicity:

  • If more than one client tries to change the same data, the last client wins (instead of using a transaction-based data update model).
  • To ensure data consistency, visual scripts that run on all clients must not read and then write shared properties or variables. If this occurs, it triggers a runtime error and aborts the script flow's execution.

Best practices

Visual scripts are significantly slower than native C# code. In addition, Mesh augments visual scripts with network and other integration features, and seemingly low-overhead visual script actions may result in network traffic. To learn about getting the best performance from your visual scripts, we recommend that you view the following articles:

Visual Scripting best practices overview
Visual Scripting best practices for performance
Visual Scripting best practices for networking
Visual Scripting best practices for debugging

Security

Mesh protects users from threat scenarios such as these:

  • Compromised scene content—for example, malicious attempts to access sensitive local data.
  • Compromised client or transport channel—for example, malicious attempts to read or write inaccessible remote data on other clients.

To achieve this, Mesh runs visual scripts in a sandbox (like JavaScript in a web browser).

At scene startup, Mesh uses a curated allowlist to validate visual scripts to limit access to certain types of Unity components and a safe subset of their properties.

At scene runtime, Mesh limits access to certain parts of the scene:

  • Locally: by preventing access to Mesh internals and other sensitive data.
  • Remotely: by checking that the scene's author intends this part of the scene to be modified. This is done by statically analyzing visual scripts on the receiver's side for their potential scene writes.

Examples:

  • A malicious local visual script wants to give all avatars bobble heads. To that end, it attempts to scan the entire scene for GameObjects that represent avatar heads. Mesh automatically filters the scanning results to exclude the avatar system.
  • A malicious remote client wants to deface the scene by flipping all GameObjects upside down. To achieve that, it sends a property update that sets the vertical scale of each GameObject in the scene. However, since no visual script on the receiving client is designed to do anything like that, the local client ignores the remote input.

Mesh integration

Current limitation: This section describes a preview of features that are still works in progress.

Generally, integration with other components is often done by changing and listening to component property changes. For example:

  • Interactables: observe "Is Hovered" and "Is Selected" properties.

  • Physics interactions: observe bodies in trigger volume or in contact with collider.

  • Avatars: read avatar position, view rotation, and name plate. (Not available yet.)

  • Session state: list participants and read participant info. (Not available yet.)

  • Cloud Scripting: operate in tandem with cloud scripts that can read and write variables and component properties. (Not available yet.)

Some components provide local actions:

  • Audio Manager
  • Timeline
  • Animators
  • Rendering: read and write material and shader properties

Physics is handled specially because simulation for any given physics object is always authoritatively done by one client only: its owner. To make this work, setting physics properties triggers an automatic ownership transfer to the client that applies the change.

Next steps