Your own UI
Restyle the default panel, build controls on your own canvas or world objects without code, or write a part in C#.
The default panel is not special. It is plain uGUI with six small components on it, each pointing
at the VideoPlayer, and anything it does your own UI can do the same way.
Restyle the panel
Everything under the player's Controls object is yours to change: colours, sprites, fonts,
layout, which buttons exist. Delete a button and the rest keep working. The parts find nothing by
name; each one holds its own references, set in the Inspector.
Build controls without code
Put these on your own canvas, a world-space menu or physical objects, and set player:
| Part | Does |
|---|---|
VideoButton |
Runs a command from a UI Button, or from Interact on a world object with a collider. Shows its state with an icon and disables itself when the local player may not use it |
VideoLabel |
Writes a field into a TextMeshPro text or a legacy Text, with an optional prefix and a text for when it is empty |
VideoSlider |
A Slider that seeks for everyone, or sets this player's own volume |
VideoLinkField |
A VRCUrlInputField: Enter queues the link, or plays it now with enterPlaysNow |
VideoShowWhen |
Shows objects while a condition holds, and can spin a loading indicator |
VideoQueueRow |
One queue entry: its title, who added it, play now and remove |
VideoButton takes a command: TogglePause, Play, Pause, Skip, Stop, Reload,
ToggleLoop, ToggleLock, ToggleMute or ClearQueue. Give it an icon and two sprites and it
swaps between them, so one button shows play or pause, a padlock shows locked or open. Leave
button empty on a world object and pressing it in VRChat runs the command instead.
VideoLabel takes a field: Title, AddedBy, Status, Time, Position, Duration,
Remaining, Volume, QueueCount, NextTitle, Owner or Url. Time fields update a few times
a second; the rest change only when the player does.
VideoShowWhen takes a condition: Idle, Loading, Playing, Paused, Failed, Live,
HasVideo, Showing, CanSeek, Locked, CanControl, CanModerate, Muted, Looping,
HasQueue or HasProblem, with invert for the opposite. It shows and hides its targets, so
put it on an object that stays active: a part that hides its own GameObject stops updating and
never comes back.
A cinema seat with one physical button and a sign above it needs no code at all: a VideoButton
on the button with TogglePause, and a VideoLabel on the sign with Title.
Write a part in C#
Derive from VideoPart and implement Refresh. It runs once the player is ready and again
whenever anything a UI shows has changed:
public class NowPlayingSign : VideoPart
{
public TextMeshProUGUI sign;
protected override void Refresh()
{
sign.text = player.IsPlaying ? player.Title : "";
}
}
Tick runs every frame after it, for things that move on their own, such as a clock. Read
Position there and keep the work small.
Call the player from anywhere: PlayUrl, Enqueue, Play, Pause, TogglePause, SeekTo,
Skip, Stop and the rest are in the reference. Commands check the lock
for you: a locked-out player's call does nothing but show a short notice in Status.
Reading the player from your own code
Read it from a VideoPart and you never have to think about timing: the part waits until the
player is ready. Code that reads the player from another behaviour's Start or Update should first
check that player.player is set. Commands can be called from anywhere, including Refresh.