Build your first playable scene
Run the playable starter game every new project opens on, see how its controller, scene script, and HUD timer work, then change it and switch to first person.
1. Run the starter game
Open a new project's Initial Scene and press Run. It is already playable: W/A/S/D move the Player in eight directions, the arrow keys turn the character and the camera swings round with it, Space jumps (or swims up in water), and C crouches while held. The scene also comes with touch controls, so on a phone or tablet a movement stick walks and Jump and Crouch buttons sit on the right; there is no touch control for turning yet. In Preview or a published game, a touch drag orbits the third-person camera, and so does the mouse once Desktop mouse look is turned on in Scene Settings; it is off by default, and the editor's Run does not use it. Walk off the edge of the platform: when you fall below the level you are put back where you started and the run timer starts again.
The scene contains eight authored objects: Ambient Light, Directional Light, Main Camera, Platform, Blue Sphere, Red Spinning Cube, Player, and the Run Timer label. It also comes with four project scripts: Character Controller on Player, Run Timer on the label, Spinning Animation on the cube, and a Game Manager selected as the scene script.
The same scene also works as a multiplayer game. Player's Player slot is 1 (multiplayer.playerSlot), which does nothing when you play alone and makes it player 1's character in a room, and the spinning cube's Script runs on is set to presentation (multiplayer.scriptRole), marking it as scenery. See Multiplayer games before you turn multiplayer on.
Starting blank
If you want to build the pieces yourself, create another scene and remove its demo objects, or use scenes_create with skip_default_objects: true. Do not add a second player and camera on top of the playable Initial Scene.
2. Inspect the Player controller
Select Player, then open its Character Controller script. The controller preserves vertical velocity, normalizes diagonal input, rotates the character from the arrow-key look booleans, and moves relative to that facing. Its directional speeds and animation playback rates are deliberately paired so the feet do not skate. The forward speed comes from the Player's Run Speed in the inspector, which the script reads with gameObject.getRunSpeed(), so you can change it there without opening the script. Crouch is input.crouch, the scene's Crouch action, which Scene Settings binds to C and to a touch button.
The important animation calls are:
function init()
gameObject.enableAutoAnimation({})
end
function update(deltaTime)
-- Apply movement and rotation first.
gameObject.updateAutoAnimation()
end
The script you open spells every clip name out so it is easy to edit, but each one is the default, so the empty table is a complete configuration for the bundled character. It also calls gameObject.setAnimationSpeed(rate, clipName) once per clip in init(), which is how the playback rates are paired with the directional speeds. It supplies idle, walk/run, backward, strafe, all four diagonals, turn, jump/fall/land, and crouch states by their default names. A custom model can override any name. See Animation playback API.
3. Inspect the scene script
Open Scene Settings and inspect the selected Game Manager. A scene script belongs to no object and runs for as long as the scene does, so it is where a game's rules go. This one records where every character starts in init(), using scene.getObjectsByType("character"), and each frame puts any character that has fallen below FLOOR (-10) back at its start with its velocity cleared.
The HUD is not the scene script's job. The Run Timer script is attached to the Run Timer label, counts up with gameObject.setText(), and starts again when it sees the Player come back from a fall. Keeping it on the label is what lets the scene play the same in a multiplayer room: there the scene script runs on the room server, which has no screen, while a GUI script runs on each player's own screen. The scene script is also the only script that receives players' actions in a room — the Game Manager's comments show where onPlayerAction goes.
4. Change one thing and test it
Make a small edit you can see: change a directional speed in Character Controller, change the Main Camera's followDistance or followHeight, or restyle the Run Timer. Run again, verify the effect, then stop to restore the authored state.
If the character moves but never changes pose, confirm updateAutoAnimation() still runs after movement. If a fall never puts you back on the platform, confirm Game Manager is still selected as the Scene Script in Scene Settings — a scene script that is written but not selected does not run. If you add a trigger volume to the level, the Player's script and the trigger's script must both call registerForCollisions(); the Character Controller already does.
Coordinate convention
Airogel characters face local +Z. The starter controller treats forward as moveZ = 1, backward as moveZ = -1, left as moveX = 1, and right as moveX = -1.
Next: first-person
Set Main Camera's controlMode to first_person and keep its targetCharacterId on Player. Set eyeHeight directly from the character's feet — about 1.65 for a 2m character — and leave followOffset.y at 0 unless you want an additional nudge. The camera hides the Player's own model in its view by default so you do not look out through the inside of its head; turn off Hide followed object to keep it.
First-person consumes every look producer directly: arrow keys, the touch look stick, mouse movement when Desktop mouse look is enabled, and touch drag. Third-person is deliberately different: the arrow keys turn the starter character through Lua, while mouse movement and touch drag orbit the boom independently. See Cameras and follow modes and Player input and touch controls.
A complete standalone first-person controller also ships as lua/fps_controller.lua.