This tutorial is a companion document to the Verse Stand-Up template, which showcases how to use devices that support a social and cinematic experience inside of a comedy club:
Using detailed, MetaHumans Animator assets with the Character devices
Triggering gameplay events on player input bindings with Input Trigger devices
Locking a player in place to view the experience with the Chair device
A Verse device runs the show, with the key concepts of the Verse code explained below.
The Verse Stand-Up template can be found in the Feature Examples section of UEFN (Unreal Editor for Fortnite).
Devices used:
1 x Chair
4 x Input Trigger
4 x Character
The Verse concepts used in this tutorial are:
Subscriptions
If Statements
Arrays
Cinematic Sequences
Chair device API
Input Trigger device API
Be aware that most of the modified settings for device interactions are done using Verse code, therefore the modified user options for most devices will appear slimmed down.
Island Settings
Here are the modified Island Settings for the Verse Stand-Up template:
Option | Value | Explanation |
---|---|---|
Max Players | 1 | This is a single-player experience. |
Team Size | 1 | Only one team is necessary. |
Join In Progress | Spectate | Players will spectate if they join a game that has already begun. |
After Last Spawn Go To | Team Index: 1 | Players will respawn on their team. |
Voice Chat | All | Voice chat is allowed between players. |
Start With Pickaxe | False | Players will not start the game with a pickaxe. |
Allow Spectating Other Teams | Disallowed | Players cannot spectate another team. |
Time Limit | 120 | The time limit is set to two hours. |
Hide Back Bling | True | Back bling will not appear on this island. |
Allow Mantling/Hurdling | False | Players will not be able to hurdle or mantle. |
Sprinting Energy Cost Per Second | 2.0 | The energy cost consumed by sprinting. |
Invincibility | True | Players are invincible. |
Allow Building | None | Players cannot build. |
Building Can Destroy Environment | False | Building cannot destroy the environment. |
Environment Damage | Off | Players cannot damage the environment. |
Infinite Building Materials | False | Building is disabled in this experience. |
Time of Day | 12:00 AM | Night time setting. |
Light Brightness | 0 | All light sources in this experience are emanating from lamps. |
Fog Thickness | 30% | Environment is slightly foggy. |
Fog Color | Blue | Determines fog color. |
Custom Victory Callout | Thank you for coming to The Cheese Cannery | What players see after finishing the game. |
Show Elimination Feed | False | Eliminations are not displayed. |
Show Wood/Stone/Metal Resource Count | False | Resources are not displayed. |
Show Party Eliminations | False | Party eliminations are not displayed. |
Debug | True | Debug features are enabled. |
Fast Iteration Mode | True | Fast Iteration between Edit and Play mode is enabled. |
Chair Device
As the player walks into the comedy club, they see a chair in front of a lit-up stage. They are prompted to sit in this chair. Sitting in the chair keeps the player in a fixed location and sets in motion the chain of events that will take them through the rest of the experience.
Here are the modified User Options for the Chair device:
Option | Value | Explanation |
---|---|---|
Chair Model | Custom | For this experience, the chair is actually made invisible, then replaced with a Fortnite chair prop in order to better fit the club environment. |
Interaction Angle | 180 degrees | Determines the angle in either direction from the front of the chair needed to interact with it. |
Interaction Radius | 1.2m | Determines the distance the player can enter the chair from. |
Input Trigger Devices
An Input Trigger device goes hand-in-hand with the Chair device. It binds player inputs to a variety of actions, which are triggered each time the player presses the reassigned button. The input triggers are configured to allow the player to change the cameras as the performance is taking place.
The device contains twelve available inputs to choose from. Once you choose an input, you can add a HUD description to clarify what the new input does.
Here are the modified User Options for this device. Each of the devices will have a different binding and HUD Description as they are bound to distinct Cinematic Sequence devices.
Option | Value | Explanation |
---|---|---|
Creative Input | Custom 5 (Sprint) | Defines the input this device is listening for. |
HUD Description | "Previous Camera" | An opportunity to explain the new input to the player. |
Registered Player Behavior | Require Registration |
|
Character Devices
The Character devices are ways for you to interact directly with the player or with other characters in a scene. This template uses four characters that cycle during the on-stage routine.
Here are the modified User Options for the Character device:
Option | Value | Explanation |
---|---|---|
Character | Pick a character | Determines which character is displayed. |
Custom Idle | Sitting | Chooses a custom idle position for the character. |
Random Idle Start | True | Determines whether the idle should start at a random position. |
The main character is sitting on a staircase backstage, and the rest of the characters are waiting in a small room in the back.
Experiment with different character skins from the Character dropdown menu and see how they look on stage!
This template uses imported MetaHuman animations. To learn more about how these animations were captured and imported, see the Importing MetaHuman Animations page.
Cinematic Sequence Devices
The six Cinematic Sequence devices allow the player to view the show from various angles while sitting in the chair device.
This page does not go into detail about creating cinematic sequences. For more information, see the Sequencer and Control Rig page, and for a deeper dive, check out the How To Make Movies in Unreal Engine.
The only modification for this device is the loaded cinematic sequence.
How Verse Runs the Show
This template uses Verse to start the show when a player sits in the chair device, as well as change their camera to a cinematic view called TV mode. It also allows the player to switch between multiple cameras, as well as return to TV mode or Free Look for different viewing experiences.
Create a new Verse Device in your project called show_template_device.verse
using Verse Explorer and drag the device into the template. Double-click your Verse file to open it in Visual Studio Code.
You’ve set up devices in your template that help run the standup show, and now you’ll reference those devices in your code.
Add the following fields to the show_template_device
file:
First, above the
show_template_device
class definition, add alog_channel
namedlog_show_template_device
.Verse# Create a custom log channel for the show_template_device. This helps with log filtering in complex games with lots of log sources. log_show_template_device := class(log_channel){} # A Verse-authored creative device that can be placed in a level show_template_device := class(creative_device):
Now at the top of the
show_template_device
class definition, add a logger that uses thelog_show_template_device
channel, so you can tell whichPrint()
statements are coming from this device.Verse# A Verse-authored creative device that can be placed in a level show_template_device := class(creative_device): # Logger that uses custom log channel. Logger:log = log{Channel := log_show_template_device}
An editable chair device named
TheChair
. This is the chair players will sit in to start the standup show.Verse# The chair device the player should sit in. @editable TheChair:chair_device = chair_device{}
Two editable cinematic sequence devices named
MainSequence
andTVModeSequence
. TheMainSequence
is the cinematic sequence that runs the standup show, driving animation and audio on the character device in the level. TheTVModeSequence
switches the player’s camera to a viewing mode that follows along with theMainSquence
, switching between multiple angles.Verse# The sequence that drives animation and audio on the character device in the level. @editable MainSequence:cinematic_sequence_device = cinematic_sequence_device{} # The sequence that drives the TV mode sequence for viewing in the level. @editable TVModeSequence:cinematic_sequence_device = cinematic_sequence_device{}
An editable array of
cinematic_sequence_device
namedCameraSwitches
. This array holds references to each of the cameras players can switch between during the show.Verse# A list of alternative camera sequences that are provided to view from during the main sequence. @editable CameraSwitches:[]cinematic_sequence_device = array{}
Four editable
input_trigger_device
s. Each of these devices takes player input to swap between different camera modes. TheReturnToFreeLook
trigger returns the player to the default camera, whileReturnToTVMode
returns the player to theTVModeSequence
. TheNextCamera
andPreviousMode
camera switches the player between the different cinematic sequences in theCameraSwitches
array.Verse# An input trigger that will return us to free look while in the chair. @editable ReturnToFreeLook:input_trigger_device = input_trigger_device{} # An input trigger that will return us to TV mode when appropriate in the chair. @editable ReturnToTVMode:input_trigger_device = input_trigger_device{} # An input trigger that will choose the next camera while in the chair. @editable
An optional cinematic sequence device variable named
CurrentSequence
. If a cinematic sequence such asTVModeSequence
is playing, this option stores a reference to it. You don’t want to play multiple cinematic sequences for the character at once, so you can use this option to turn the current sequence off when switching to a new one.Verse# The alternative camera sequence that is playing if valid. var CurrentSequence:?cinematic_sequence_device = false
Two logic variables named
MainSequencePlaying
andInTvMode
. These let you track when theMainSequence
orTVModeSequence
are playing respectively.Verse# Helps us track when the main sequence on the character device is playing. var MainSequencePlaying:logic = false # When we are in TV mode. var InTVMode:logic = false
A variable int named
CurrentCameraIndex
. This tracks the index of the cinematic sequence in theCameraSwitches
array that is currently playing.Verse# Keeps track of what camera we are viewing when using other cameras besides TV Mode. var CurrentCameraIndex:int = -1
Five optional
cancelable
variables that track subscriptions for all the events referenced in this template. Different functions need to run when the player switches between cameras, returns to free look or TV mode, or exits the chair device. Later in this tutorial, you will subscribe the functions to the events that trigger them, and store a reference to each subscription so you can cancel them when they’re no longer needed.Verse# Subscriptions to all the events we listen for while running. var ReturnToFreeLookSubscription:?cancelable = false var NextCameraSubscription:?cancelable = false var PrevCameraSubscription:?cancelable = false var ReturnToTVModeSubscription:?cancelable = false var ChairExitSubscription:?cancelable = false
Save the script in Visual Studio Code and compile it to update your Verse-authored device in the level.
Select the
show_template_device
in your template. In the Details panel, assign each device reference in your script to the associated device in the level, including each of your input triggers and cinematic sequences.
Triggering the Sequence
The show starts when a player sits in the chair device, you’ll want the cinematic sequence to start once the player is seated. Follow the steps below to trigger the main sequence when a player sits in the chair, as well as start the TV mode so the player can watch along.
Add a new function
RunSequence()
to theshow_template_device
class. This function takes the agent who started the show and starts both the MainSequence andTVModeSequence
. Add the modifier toRunSequence()
to let it run asynchronously. This function needs to be asynchronous so that you can run other code concurrently with it, and allow the player to swap between camera views without interrupting theRunSequence()
code.Verse# Handles running the main sequence which runs the character and TV mode sequences for viewing and then calls a function to await finishing. RunSequence(Agent:agent)<suspends>:void =
In
RunSequence()
, callSleep()
for a second to let the animation of the player sitting in the chair finish before starting the show. Then callPlay()
on theMainSequence
, and setMainSequencePlaying
to true.Verse# Sleep for a second because we just entered the chair and the animation to sit takes a moment. Sleep(1.0) # Run the Main sequence on the character device and the TV mode viewing sequence. Logger.Print("Main Sequence Playing") set MainSequencePlaying = true MainSequence.Play()
Call
Play()
on theTVModeSequence
, passing the agent who started the show to change their camera to the cinematic view. SetInTVMode
to true, and call a new function that awaits the ending of theMainSequence
calledAwaitMainSequenceEnding()
, passing the agent. You’ll set up this function in the next step. Your completedRunSequence()
code should look like the following:Verse# Handles running the main sequence which runs the character and TV mode sequences for viewing and then calls a function to await finishing. RunSequence(Agent:agent)<suspends>:void = # Sleep for a second because we just entered the chair and the animation to sit takes a moment. Sleep(1.0) # Run the Main sequence on the character device and the TV mode viewing sequence. Logger.Print("Main Sequence Playing") set MainSequencePlaying = true MainSequence.Play()
Add a new function
AwaitMainSequecingEnding()
to theshow_template_device
class that takes theagent
fromRunSequence()
. This function also needs the<suspends>
modifier since you want it to run in the background and trigger when theMainSequence
ends.Verse# When the main sequence finishes, we clear the flag so that if the player sits back down, it will play again. AwaitMainSequencingEnding(Agent:agent)<suspends>:void =
In
AwaitMainSequencingEnding()
, callAwait()
on theMainSequence.StoppedEvent()
. When theMainSequence
ends, setMainSequencePlaying
tofalse
, and kick the player out of the chair using the chair’sEject()
function. Your completedAwaitMainSequencingEnding()
function should look like the following:Verse# When the main sequence finishes, we clear the flag so that if the player sits back down, it will play again. AwaitMainSequencingEnding(Agent:agent)<suspends>:void = MainSequence.StoppedEvent.Await() Logger.Print("Main Sequence Ended") set MainSequencePlaying = false # Kick the player out of the chair after the performance TheChair.Eject(Agent)
Add two new functions
DoReturnToTVMode()
andDoReturnToFreeLook()
to theshow_template_device
class. These functions handle the logic when a player returns to the TV mode or free look respectively, but you’ll leave them empty for now and fill them out in a later step.Verse# Returns us to our TV viewing mode sequence by checking where the main sequence is and aligning our playback to that point. DoReturnToTVMode(Agent:agent):void = Logger.Print("Return to TV Mode") # Determine if we are in TV mode or another camera sequence and return control to the main player camera. DoReturnToFreeLook(Agent: agent):void = Logger.Print("Return to Free Look")
Add a new function
OnSeated()
to theshow_template_device
class that takes the agent who sat inTheChair
.Verse# This function handles the player sitting down and starting up the performance if it isn't already running and setting up the input triggers. OnSeated(Agent:agent):void = Logger.Print("Player sat down")
In
OnSeated()
, if theMainSequence
is not already playing, spawn aRunSequence()
function, passing the agent who sat in the chair device. Otherwise, callDoReturnToTVMode()
with the same agent.Verse# This function handles the player sitting down and starting up the performance if it isn't already running and setting up the input triggers. OnSeated(Agent:agent):void = Logger.Print("Player sat down") # If the main sequence is not playing on the character device in the level, run it, otherwise if it is running then just return to the TV mode viewing experience. if (MainSequencePlaying = false): spawn{RunSequence(Agent)} else: DoReturnToTVMode(Agent)
Add a new function
OnChairExited()
to theshow_template_device
class that takes the player who exited the chair. You’ll fill out the logic for this function in a later step.Verse# Handles the player leaving the chair and removing access to the input triggers that are available while in the chair. OnChairExited(Agent:agent):void = Logger.Print("Player got up")
In
OnBegin()
, subscribeTheChair.SeatedEvent
to theOnSeated()
function. Now whenever a player sits inTheChair
, the show will run.Verse# Runs when the device is started in a running game. OnBegin<override>()<suspends>:void = Logger.Print("Standup Template device started") TheChair.SeatedEvent.Subscribe(OnSeated)
Save the script in Visual Studio Code, compile it, and click Launch Session in the UEFN toolbar to playtest the template. When you run your game, sitting in the chair device should start your show, and set the player’s camera to cinematic mode. When the show ends, the player should be kicked out of the chair.
Switching Cameras
During the show, the player sitting in the TheChair
can switch between multiple different camera views, handled by different cinematic sequences. Follow the steps below to set up the logic for switching between these different sequences.
Add a new function
DoCameraSwitch()
to theshow_template_device
class. This function takes the agent whose camera you’re switching, as well as anint
corresponding to the cinematic sequence index inCameraSwitches
.Verse# Switches us between camera sequences that have been specified by stopping any current ones and moving to the next appropriate one on the list. DoCameraSwitch(Agent:agent, Value:int):void =
In
DoCameraSwitch()
, in anif
statement, get the cinematic sequence at the Value index in theCameraSwitches
array. Then stop any currently playing sequences by checking ifCurrentSequence
contains a cinematic sequence and callingStop()
on it.Verse# Switches us between camera sequences that have been specified by stopping any current ones and moving to the next appropriate one on the list. DoCameraSwitch(Agent:agent, Value:int):void = if (CameraSwitch := CameraSwitches[Value]): Logger.Print("Switching Cameras to {Value}") # Stop any currently playing other camera sequence. if (PlayingSequence := CurrentSequence?): PlayingSequence.Stop(Agent)
Start playing the new cinematic sequence by calling
Play()
onCameraSwitch
. Then setCurrentSequence
to say which sequence is currently playing. Finally,Register()
theagent
whose camera you’re switching with theReturnToTVMode
andReturnToFreeLook
input triggers to allow them to return to those modes when viewing other cameras. Your completedDoCameraSwitch()
function should look like the following:Verse# Switches us between camera sequences that have been specified by stopping any current ones and moving to the next appropriate one on the list. DoCameraSwitch(Agent:agent, Value:int):void = if (CameraSwitch := CameraSwitches[Value]): Logger.Print("Switching Cameras to {Value}") # Stop any currently playing other camera sequence. if (PlayingSequence := CurrentSequence?): PlayingSequence.Stop(Agent) # Start up the new camera viewing sequence.
To switch between the next and previous cameras, you’ll set up two very similar functions,
DoNextCamera()
andDoPreviousCamera()
. You’ll fill out the logic for the next camera first, so add a new functionDoNextCamera()
to theshow_template_device
class. This function takes theagent
whose camera you’re switching.Verse# Switches to the next camera on our list, or the first if we are in TV mode. DoNextCamera(Agent:agent):void = Logger.Print("Next Camera")
In
DoNextCamera()
, check if the player is currently in TV mode. If so,Stop()
theTVModeSequence
, setInTVMode
to false and setCurrentCameraIndex
to-1
. You use-1
here because you want to index into the next cinematic sequence theCameraSwitches
array, which would be index0
.Verse# If we are currently viewing from TV Mode, end that sequence and clear associated values. if (InTVMode?): TVModeSequence.Stop(Agent) set InTVMode = false set CurrentCameraIndex = -1
You then need to figure out the next camera to switch to based on the index of the current camera. To do this, set a new variable
NextCameraValue
to theMod
of theCurrentCameraIndex + 1
andCameraSwitches.Length
. This lets you clampNextCameraValue
to a value that’s between0
and the length ofCameraSwitches
and prevents you from getting aNextCameraValue
that’s outside theCameraSwitches
array. Once you haveNextCameraValue
, setCurrentCameraValue
toNextCameraValue
, and callDoCameraSwitch()
passing theagent
and theCurrentCameraIndex
. Your completedDoNextCamera()
function should look like the following:Verse# Switches to the next camera on our list, or the first if we are in TV mode. DoNextCamera(Agent:agent):void = Logger.Print("Next Camera") # If we are currently viewing from TV Mode, end that sequence and clear associated values. if (InTVMode?): TVModeSequence.Stop(Agent) set InTVMode = false set CurrentCameraIndex = -1
To switch to the previous camera, add a new function named
DoPreviousCamera()
to theshow_template_device
class. Copy the code fromDoNextCamera()
into this function. When checking if the player is in TV mode, setCurrentCameraIndex
to0
instead of-1
. Also, changeNextCameraValue
to be theMod
ofCurrentCameraIndex - 1
andCameraSwitches.Length.
Your completedDoPreviousCamera()
function should look like the following:Verse# Switches us to the previous camera on the list or last camera if we are leaving TV mode. DoPreviousCamera(Agent:agent):void = Logger.Print("Prev Camera") # If we are currently viewing from TV Mode, end that sequence and clear associated values. if (InTVMode?): TVModeSequence.Stop(Agent) set InTVMode = false set CurrentCameraIndex = 0
When a player is sitting in TheChair
and viewing from a different camera in CameraSwitches
, they can return to either TV mode or Free Look. You set up the DoReturnToFreeLook()
and DoReturnToTVMode()
functions earlier, and you’ll fill them out now.
In the
DoReturnToFreeLook()
function, check if the player is currently in TV mode. If so,Stop()
theTVModeSequence
and setInTVMode
to false. Do the same withCurrentSequence
, checking ifCurrentSequence
contains a cinematic sequence, callingStop()
, and setting it to false if so.Verse# If TV Mode is active, stop it. if (InTVMode?): TVModeSequence.Stop(Agent) set InTVMode = false # If we are playing another viewing experience, stop it. if (TempSeq := CurrentSequence?): TempSeq.Stop(Agent) set CurrentSequence = false
Now
Register()
the agent with theReturnToTVMode
input trigger, andUnregister()
them with theReturnToFreeLook
trigger since you don’t want to return a player to free look while they’re already there. Your completedDoReturnToFreeLook()
function should look like the following:Verse# Determine if we are in TV mode or another camera sequence and return control to the main player camera. DoReturnToFreeLook(Agent: agent):void = Logger.Print("Return to Free Look") # If TV Mode is active, stop it. if (InTVMode?): TVModeSequence.Stop(Agent) set InTVMode = false # If we are playing another viewing experience, stop it.
The
DoReturnToTVMode()
function requires more logic since when returning to TV mode you need to start theTVModeSequence
at the current time of theMainSequence
. First, check if the player is already in TV mode when this function is called. If so, justreturn
since there’s nothing you need to do. Then check ifCurrentSequence
contains a cinematic sequence, callingStop()
, and setting it tofalse
if so.Verse# If we are already in TV mode no need to return to it. if (InTVMode?): return # If we have another camera sequence playing, stop it and clear associated values. if (TempSeq := CurrentSequence?): TempSeq.Stop(Agent) set CurrentSequence = false
Now you need to figure out where the
MainSequence
is along its playback and start theTVModeSequence
from the same spot. Get the playback time ofMainSequence
by callingGetPlayBackTime()
and save it in a variableCurrentSeekTime
. Set the playback time ofTVModeSequence
toCurrentSeekTime
usingSetPlaybackTime()
, andPlay()
the sequence passing the agent. Then setInTVMode
totrue
.Verse# Figure out where the main sequence is in its playback and start up the TV mode sequence at the same spot to provide the proper viewing experience. CurrentSeekTime := MainSequence.GetPlaybackTime() TVModeSequence.SetPlaybackTime(CurrentSeekTime) TVModeSequence.Play(Agent) set InTVMode = true
Finally
Unregister()
the agent from theReturnToTVMode
input trigger, andRegister()
them with theReturnToFreeLook
trigger. Your completedDoReturnToTVMode()
function should look like the following:Verse# Returns us to our TV viewing mode sequence by checking where the main sequence is and aligning our playback to that point. DoReturnToTVMode(Agent:agent):void = Logger.Print("Return to TV Mode") # If we are already in TV mode no need to return to it. if (InTVMode?): return # If we have another camera sequence playing, stop it and clear associated values. if (TempSeq := CurrentSequence?):
Linking Everything Together
You’ve set up a lot of functions in the previous part of this tutorial, and now it’s time to link them all together to the various input triggers that call them.
In
OnSeated()
,Register()
the agent with theReturnToFreeLook
,NextCamera
, andPreviousCamera
input triggers, since these are the triggers a player will initially have access to when they first sit in the chair. Then setReturnToFreeLookSubscription
,NextCameraSubscription
, andPreviousCameraSubscription
by subscribing each input trigger to their associated function. Set theReturnToTVModeSubscription
andChairExitSubscription
in the same way.Verse# Register for the input trigger for free look and subscribe to the pressed event when sitting. ReturnToFreeLook.Register(Agent) set ReturnToFreeLookSubscription = option{ReturnToFreeLook.PressedEvent.Subscribe(DoReturnToFreeLook)} # Register for the input trigger for the next camera and subscribe to the pressed event when sitting. NextCamera.Register(Agent) set NextCameraSubscription = option{NextCamera.PressedEvent.Subscribe(DoNextCamera)} # Register for the input trigger for the previous camera and subscribe to the pressed event when sitting. PreviousCamera.Register(Agent)
Add a new function
CancelSubscription()
which takes optional cancelable value to theshow_template_device
class. InCancelSubscription()
, check if theSubscription
contains a value. If so,Cancel()
it. Your completedCancelSubscription()
should look like the following:Verse# Cancel a subscription if it is valid. CancelSubscription(Subscription:?cancelable):void = if (SubscriptionToCancel := Subscription?): SubscriptionToCancel.Cancel()
When a player exits the chair, you need to stop any currently playing sequences on the player, as well as cancel any subscriptions to input triggers the player was registered to. To the
OnChairExited()
function, like inDoReturnToFreeLook()
, check if the player is in TV mode, as well as ifCurrentSequence
contains a cinematic sequence. CallStop()
on each sequence if so, and setInTVMode
tofalse
if the player is in TV mode. Then setCurrentSequence
tofalse
.Verse# Stop the TV camera view when we leave the chair if it is active. if (InTVMode = true): TVModeSequence.Stop(Agent) set InTVMode = false # Stop the camera sequence we were using if it is active when we leave the chair. if (TempSeq := CurrentSequence?): TempSeq.Stop(Agent) # Clear whatever the current sequence was when we leave the chair.
Now cancel all player subscriptions by passing each subscription to the
CancelSubscription()
function. AlsoUnregister()
the player from each input trigger since they shouldn’t be able to access those buttons when leaving the chair. Your completedOnChairExited()
function should look like the following:Verse# Handles the player leaving the chair and removing access to the input triggers that are available while in the chair. OnChairExited(Agent:agent):void = Logger.Print("Player got up") # Stop the TV camera view when we leave the chair if it is active. if (InTVMode = true): TVModeSequence.Stop(Agent) set InTVMode = false # Stop the camera sequence we were using if it is active when we leave the chair.
Save the script in Visual Studio Code, compile it, and click Launch Session in the UEFN toolbar to playtest the template. When you playtest, sitting in the chair device should start the show. During the show, you should be able to switch between TV mode, free look, and multiple other camera angles. Returning to TV mode should align the TV mode sequence with the main sequence. When the show ends, you should be returned to free look and exit the chair.