UdonSharp Setup and Your First Script: A Cube That Changes Color

Created: 2025-12-19Last updated: 2026-10-01

UdonSharp ships with the VRChat Worlds SDK, so there is nothing extra to install. Write your first U# Script and make a cube that changes color when used.

Running your own code in a VRChat world for the first time. That first step is a Cube that reacts when you touch it.

Going straight for the color change causes trouble when it doesn't work, though. Was the press not registering, was the code wrong, or was the color specified incorrectly? There's no way to tell.

This article confirms that the press lands with a log first, then adds the color change. We build it so you can isolate problems in order.

Touching the Cube switches its color, with a line running from a gear card to the Cube

What You'll Learn

  • The roles of the C# file, the Program Asset, and the Udon Behaviour
  • How to confirm Interact ran with a log, before touching color
  • The order to check when nothing responds
  • The feel of changing a value exposed in the Inspector without touching code

Start from a scene with a floor. If you don't have one, build it in your first world. UdonSharp is included in the current Worlds SDK, so it is already there once you create a Worlds project in VCC (or ALCOM). You don't need to find and install it separately (see project setup).

Sponsored


Three things get made: a notebook, a translated card, and a nameplate

Creating a U# Script produces two files, and a third appears in the Inspector. That's a common point of confusion, so let's sort it out first.

How the C# file, Program Asset, and Udon Behaviour relate
  • The C# file (.cs) is the notebook you write in. "Change color when pressed" goes here
  • The Udon Sharp Program Asset is a card translating that notebook into a form VRChat can read. It updates automatically on save, so there's no need to open it. Don't delete it
  • The Udon Behaviour is the nameplate attached to the Cube. It means "this Cube behaves according to that card"

You only edit the notebook. Saving updates the card, and the nameplate merely looks at that card.

So attaching the same notebook to any number of Cubes gives them identical logic. But state like "what color is it right now" is held separately per Cube.

Sponsored

Hands-On: Build a Cube that changes color when pressed

When you're done, approaching and using the Cube alternates it between blue and orange.

1. Place a Cube and a material

Work with Play stopped. Settings changed during Play revert when you stop.

Create a "3D Object → Cube" in the Hierarchy and name it ColorCube.

TransformXYZ
Position011
Rotation000
Scale111

The floor's top surface is at Y=0, so a center at Y=1 puts the bottom at 0.5 — clear of the floor and at a comfortable height to use. Leave the Box Collider as is and Is Trigger off. Don't add a Rigidbody. Interact needs only a Collider and a program.

Next, prepare a vessel for the color. Create a Materials folder under Assets, make ColorCubeMaterial with "Create → Material," and set its Shader to Standard. Drag the material onto ColorCube.

2. Create a U# Script

Create a Scripts folder under Assets and right-click to choose "Create → U# Script."

Here's the first fork in the road. Pick "U# Script," not "C# Script." Picking C# Script gives you an ordinary Unity script that won't run as Udon even when attached to the Cube. You can spot it because no Program Asset appears beside it.

Name it ColorChanger. The file name and the class name in the code must match. They won't compile if they differ. Avoid names with spaces too.

3. Log first

Don't change color yet — confirm only whether the press lands. Open ColorChanger.cs, set it to this, and save.

using UdonSharp;
using UnityEngine;

[UdonBehaviourSyncMode(BehaviourSyncMode.None)]
public class ColorChanger : UdonSharpBehaviour
{
    // The entry point receiving the "use" action. Drop public override and it never fires
    public override void Interact()
    {
        Debug.Log("[ColorChanger] Pressed");
    }
}

Watch the public override void Interact() spelling. Writing just void Interact() still compiles, but it will never be called, with no error either. It's the classic failure that's hard to trace.

Return to Unity and wait for compilation. Then attach it to the Cube.

  1. Select ColorCube in the Hierarchy
  2. Add Udon Behaviour via "Add Component"
  3. Drag ColorChanger's Program Asset from Project into Program Source

Press Play once here. Click the Game view to hand over control and aim at the Cube. When the prompt appears, left-click on desktop.

Seeing "Pressed" in the Console means it worked. Add the color logic only after that passes.

4. Add the color change

Stop Play and replace the code with this.

using UdonSharp;
using UnityEngine;

[UdonBehaviourSyncMode(BehaviourSyncMode.None)]
public class ColorChanger : UdonSharpBehaviour
{
    [SerializeField] private MeshRenderer targetRenderer;  // What to recolor
    [SerializeField] private Color startColor = Color.blue;
    [SerializeField] private Color changedColor = new Color(1f, 0.5f, 0f);

    private Material instanceMaterial;  // A material just for this Cube
    private bool isChanged;             // Whether it's currently switched

    private void Start()
    {
        if (targetRenderer == null)
        {
            Debug.LogWarning("[ColorChanger] Target Renderer is not set.");
            return;
        }

        instanceMaterial = targetRenderer.material;
        instanceMaterial.color = startColor;
    }

    public override void Interact()
    {
        if (instanceMaterial == null) return;

        isChanged = !isChanged;                                        // Flip the boolean
        instanceMaterial.color = isChanged ? changedColor : startColor; // Pick by condition
    }
}

The code splits into three parts.

Values you configure are the first three lines. [SerializeField] makes them settable from the Inspector even though they're private.

Initial setup is Start(). If the target isn't set, it prints the reason to the Console and stops. If it is, it takes the material and applies the starting color.

What happens on press is Interact(). isChanged holds true or false, and ! flips it. condition ? A : B picks A when the condition is true and B when it's false.

ActionisChangedColor shown
Just startedfalseBlue
First presstrueOrange
Second pressfalseBlue

There's no Update() running every frame. The logic runs only at the moment of a press.

There's a reason for using targetRenderer.material. It takes a material belonging to that Renderer alone. Rewriting sharedMaterial would recolor every other Cube using the same material along with it.

5. Assign the reference

Back in Unity, new fields have appeared on the Udon Behaviour.

Connecting C# to Program Asset to Udon Behaviour, with the Cube's Mesh Renderer set as Target Renderer
  1. Drag ColorCube from the Hierarchy into Target Renderer (its Mesh Renderer goes in)
  2. Confirm Start Color is blue and Changed Color is orange
  3. Set Interaction Text to Change color
  4. Save the scene

Interaction Text is the prompt shown when you get close. It works when empty too. It exists to make interaction easy, so use short wording that says what will happen.

6. Confirm with ClientSim

Press Play, click the Game view, and approach the Cube.

ActionExpected result
Aim at the CubeThe "Change color" prompt appears
Use it (left-click)It goes from blue to orange
Use it againIt returns to blue
Stop Play and start againIt starts from blue
The Cube's color changing each time you use it

This shows an earlier version of the example. The code in this article alternates between blue and orange.

Clicking the Cube in the Scene view is not the same as using it as a player in the Game view. If clicking only outlines it, you're touching the editing view.

The order to check when nothing responds

Working down this list tells you where it stopped.

Four things to check, in order
  1. Does the prompt appear when you aim at it? → If not, check for a Collider, whether you're too far away, and whether another object is in front
  2. Does a press log appear in the Console? → If not, check the public override void Interact() spelling, or whether Program Source is empty
  3. Are there red errors in the Console? → If so, read the file name and line number of the topmost error
  4. Is Target Renderer set to None? → A warning should have appeared at startup
  5. If the color doesn't change, are the two colors the same value?

Two more common failures. Attaching the program to an empty parent while the Collider is on a child Cube means Interact won't fire. Both must be on the same object. The other is editing the Inspector during Play and losing it on stop. Enter settings with Play stopped, and save.

Sponsored

Change values and confirm

Once it works, try two things. You'll feel how results change without touching code.

Change only Changed Color to green. Without altering a single character of code, the second color changes. That shows Inspector values passing straight into the logic.

Place another Cube and set the second one as Target Renderer. Pressing the first changes the second one's color. The place that receives the action and the place where the result appears can be different — a concept you'll use over and over.

That covers three things: events, state, and references.

Bonus: Good to Know Up Front

  • Debug.Log is your first companion: When something doesn't work, it tells you whether execution got that far. One line at the entry of a routine cuts the possible causes in half
  • Interact needs you close: The default distance is around 2m. When a distant object doesn't respond, walk up to it first
  • Don't combine it with VRC Pickup: Grabbing takes priority and Interact stops working
  • Don't think about synchronization yet: This code changes color only on the presser's screen. Reaching everyone is the subject of networking basics
  • Changes during Play aren't saved: If you tune colors or positions during Play, note the values, stop, and enter them again

Summary

Your first UdonSharp is three things connected.

  • Writing the notebook (the C# file) produces the translated card (the Program Asset) automatically
  • That card goes into the Cube's nameplate (the Udon Behaviour)
  • Confirm the press lands with a log before touching color
  • Dropping the public override void Interact() spelling gives silence with no error

The question to ask when it doesn't work is: "Does the prompt appear, and does the log appear?" Those two split the cause between input and code.

If programming is new to you, go next to the four parts of a program for variables, if, for, and functions in one pass. If you already know how to write, head to variables and references or methods and custom events.

Read nextNext in the learning path
Syntax

C# Basics for UdonSharp: Variables, if, for, and Functions

Read this note
VRChat Notes in this section63