Part 1 - Control Animation with Swipe
Welcome to the first part of this tutorial on creating a Bitmoji Runner Game in Lens Studio! In this part we'll guide you through the steps to set up your project, import assets, create smooth animations, and write scripts to control your character. Let's get started!
Prerequisites
- Before we begin, ensure that you have Lens Studio (version 5.2 or higher) installed on your computer.
- You will also need a basic knowledge of programming; in particular JavaScript.
Before we dive into the tutorial, let's take a look at what you'll be building.
By the end of this part, you'll have a player character that smoothly moves left and right in response to swipe gestures. The movement will be controlled within a set boundary, ensuring the player doesn't go off-screen. You'll also learn how to manage animations and transitions dynamically as the player moves.
Open Lens Studio, then click on + Default to create a new project
From the Asset Library, import the Swipe Detection asset.
Install the following custom components:
- Animation State Manager.
- Bitmoji 3D.
The Animation State Manager is needed to control and manage the different animations of the player, such as transitioning between running or idle animations.
Add the Swipe Detection prefab to the Scene Hierarchy.
Test it by swiping in different directions in the preview.
Drag the 3D Bitmoji from the Asset Browser to the Scene Hierarchy. This creates a scene object with the 3D Bitmoji as a component.
In the Inspector panel, ensure that the Adapt to Mixamo option is enabled.
Enabling Adapt to Mixamo ensures compatibility with Mixamo animations, which is essential since we'll be importing animations from Mixamo for smooth playback and proper skeleton alignment.

Importing and Organizing Animations
Now we will import the animations, set up the Animation Player and organize the scene objects
Import the following animations from Mixamo:
- fast run.
- left strafe.
- right strafe
Create a folder named Animations - Mixamo in the Asset Browser and import these animations into this folder.
Organizing assets in the Asset Browser makes it easier to manage and locate files as your project grows, reducing clutter and improving workflow efficiency.
Add an Animation Player to the 3D Bitmoji scene object and enable Autoplay to test each animation.
Add the animations:
- Left Strafe (name it Left).
- Run (name it Run). Right Strafe (name it Right).
Set Playback Mode to Loop for each animation.
We'll use these clip names (Left, Run, Right) later in the Animation State Manager to create transitions between the animations.
Create a new scene object named Player. Add the 3D Bitmoji scene object as a child of Player.
The Player scene object will help organize everything related to the Player character, making it easier to manage position, movement, and animations by controlling the parent object.
Rotate the Bitmoji object by 180 degrees on the Y axis to make the Bitmoji face the opposite direction.
Adjust the scale to make the Bitmoji smaller.


Setting Up the Animation State Manager
The main goal of these steps is to set up an Animation State Manager with a blend tree to achieve smooth transitions between different animation states based on directional input, and to ensure proper control of animation playback.
Drag the Animation State Manager into the Scene Hierarchy. Then, in the Animation State Manager, add the Animation Player.
Create a blend tree named RunBlendTree.
Add the clips and their threshold values:
- Left: 0.20
- Run: 0.50
- Right: 0.80
Threshold is the value of the parameter that corresponds to the current animation clip being at full effect.
The threshold value should be between 0 and 1.
For more details, you can check the Animation State Manager guide for further explanation.
Set the parameter to direction (type: float, value: 0), which will be used as the Blend Parameter for our blend tree.
Enable Normalize Clip Duration to ensure the clip lengths are aligned during blending moments.
We will use this direction parameter later in the PlayerController script to change the character's direction when the user swipes left or right.
Set Up Transitions:
Enable Edit Transitions.
Add a transition from Entry to RunBlendTree with a transition duration of 0.
Set the condition name to direction (type: float, value: less than 1).
This step sets up the transition from Entry to RunBlendTree, triggered by the direction parameter.
Since we are controlling the animations and transitions through the Animation State Manager, disable Autoplay in the Animation Player.


Writing the PlayerController Script
Now we will create and organize a PlayerController script, modify swipe detection, and implement directional movement control for the Bitmoji based on user swipes.
The goal is to smoothly transition the player's position and animation direction when swiping left or right, with conditions ensuring the player remains on-screen.
To get started, add a Script Component to the Player scene object.
Next, create a folder named Scripts in the Asset Browser — this helps us organize our resources efficiently.
Once the script is created, move it into the Scripts folder and rename it to PlayerController for better clarity and management.
To control the player with swipe gestures, go to the Swipe Detection scene object and enable Show Debug Message to help monitor swipe inputs in the logger.
Then, change the script with API to be the PlayerController script, which allows us to control the player's movements.
Disable the Diagonal Swipes option, as we only need simple directional swipes.
Keep the left, right, up, and down functions unchanged, and finally, delete the Text Example scene object since it's no longer needed.
Before we start writing the PlayerController
script, take a look at the diagram to understand how swipes will trigger animations and movement in the game.
- Swipe Detection: This listens for user swipes, such as a left swipe. Once a swipe is detected, it sends a Swipe Trigger to the
PlayerController
script. - PlayerController Script: Upon receiving the trigger, this script:
- Moves the player into the new position based on the swipe direction.
- Calculates the
direction
value, normalizes it and sends it to the Animation State Manager.
- Animation State Manager: The system then compares the
direction
value with thethreshold
in the Animation State Manager. Based on this comparison, the appropriate animation (like Run or Left) is played.
We want to write a script to control the direction of the Bitmoji on swipe, so we will have four swipe functions for all directions.
We will leave upSwipe
and downSwipe
empty for now and work on leftSwipe
and rightSwipe
.
We need the Animation State Manager and the player as inputs.
These inputs are needed to control the player's animations and manage transitions, like switching between left, run, and right states.
We also need an update event where the movement will happen.
The update event is used to manage the player's movement continuously, ensuring smooth transitions and animations based on user input.
We will need a boolean variable to tell us if it is time to move, so we will create changeDir
and set it to false
at the beginning.
Then we need the local position of the player and a target position.
We will check if the current position is less than or greater than zero to determine if we need to increase, decrease, or keep the x position value the same when the user swipes left or right.
We also need a target position that will calculate the movement based on steps to make it smooth over time.
In the beginning target position will be equal to current position.
If the player's x position is 0, then it is in the middle. The player can move right or left.
We will start with the left swipe.
The user can swipe left and not make the player go out of the screen only if the x position is 0 or more.
If it is less than 0, then the player is already on the left of the screen and if we allow it to move left again, it will go out of the screen.
We'll add a condition in the left swipe to check if currentPos.x >= 0
.
If this condition is true, we set changeDir
to true
and start decreasing the x position over time to move the player to the left.
We'll create a step variable for managing movement, initializing it to 0 at the start of the script, and set it to -5 in the left swipe.
We chose -5 as a small, manageable number to move the player's x position incrementally to the left. This ensures smooth movement, as the change happens gradually with each frame in the onUpdate function and repeats until the player reaches the desired position.

Understanding Movement Time and Progress
Now that we have the swipe trigger and the direction check in place, it's time to handle the actual movement in the onUpdate function. To make the movement of the player feel natural and smooth, we need to control how the player moves from one position to another gradually.
If we simply applied a large step, like step = -10, the player would instantly jump to the left side, which would feel unnatural and jarring.
To avoid this, we have introduced two key variables:
movementTime
currentMoveTime
If we do something like:if (currentPos.x >= 0) {step = -15;}
The player will instantly snap to the left side, making the transition abrupt.
When the game begins, these variables are initialized with their default values.
When a swipe triggers, some of these variables will change. To initiate movement, changeDir will be set to true. Depending on whether the swipe is to the right or left, the step value will be either positive or negative.
Then, in the first frame after changeDir
is set to true
in the swipe function, currentMoveTime
will be checked to see if it is greater than or equal to movementTime
.
If it's not, it will increment by 0.5, and targetPos.x
will also increase by the step
amount, moving the player to the right or left.
In the diagram shown beside, we are providing an example of the leftSwipe.
In the second frame, currentMoveTime
will be 0.5 and targetPos.x
will be -5.
Since currentMoveTime
is still less than movementTime
, it will increase by 0.5 again, and targetPos.x
will also decrease by the step
value of -5 once more.
In the third frame, currentMoveTime
will be 1 and targetPos.x
will be -10.
Now, when currentMoveTime
is checked against movementTime
, they will be equal.
As a result, currentMoveTime
will reset to its default value, which is 0, and the movement will stop.





Implementing Smooth Player Movement with the onUpdate Function
Let's walk through how to write the onUpdate
function, which will handle the movement of the player based on swipes.
At the start of the script, we'll create two variables:
currentMoveTime
, set to 0 to track progress. andmovementTime
, set to 1 as a starting point.
You can adjust
movementTime
later to ensure it moves the player just enough without going off-screen.
In the onUpdate function, we'll start by adding a condition to check if the player is in the process of changing direction (based on a swipe).
If the player is moving (changeDir
is true), we'll also check if the movement has lasted long enough by comparing currentMoveTime
with movementTime
.
If the duration has exceeded the time limit, we'll stop the movement by resetting currentMoveTime
to 0 and setting changeDir
to false to signal the movement has finished.
But if we're still within the allowed movement time, we'll gradually increase currentMoveTime
by 0.5 on each frame
and update the targetPos.x
by adding the step value.
This will make the player move smoothly left or right depending on the swipe direction.
Finally, we'll apply the updated target position to the player's transform, ensuring the player's position is updated correctly on the screen.
You can now test and see that the player moves left successfully when you swipe left.
If you swipe left again, the player stays in position and doesn't go off the screen.
However, when you swipe right, the player doesn't move yet.
To make the player move right on a right swipe, we'll use similar logic to the left swipe.
In the rightSwipe
function, movement should only happen if currentPos.x
is less than or equal to 0, meaning the player is on the left side or in the middle of the screen.
The step
value should be positive (set to 5) to increase the x position and move the player to the right.
Set changeDir
to true
to start the movement.
Synchronizing Animation with Swipe Direction
Now that the player moves with swipes, we need to update the Bitmoji's direction.
Now we can see that the player's x position changes when we swipe left or right, but the direction of the Bitmoji remains the same.
We need to change the direction
parameter value to switch between left, right, and run animations.
We created the direction parameter earlier when setting up the RunBlendTree in the Animation State Manager.
We'll now use it to control the character's animation direction based on swipes.
For that, we will need currentDir
and targetDir
variables set to 0 at the beginning.
The target direction will change in the swipe function:
in the left swipe, it will be -1; in the right swipe, it will be 1.
In the update function, if no swipe is happening, the target direction should remain at 0.
To handle this, in the else block where changeDir
is false, simply reset targetDir
to 0.
We will update currentDir
to be between the current direction, which is now 0, and the target direction, which will become 1 or -1, or remain 0 if no swipe happened.
To do this, we use MathUtils.lerp
to gradually interpolate between currentDir
and targetDir
.
The 0.3 is the interpolation factor, controlling how quickly the transition happens. A higher value makes the transition faster, while a lower value slows it down.
Next, we'll update the animation state to match the player's current direction.
We do this by using the setParameter method, passing the name of the parameter direction and its value, which is the normalized current direction.
The expression (currentDir + 1) / 2
normalizes the currentDir
value, which ranges from -1 to 1, into a range between 0 and 1.
This is necessary because the animation system expects values within this range for smooth transitions between left, right, and run animations.
Now that your Bitmoji movement is functional, you can fine-tune the values to get the desired effect.
For example, try adjusting the movementTime
from 1 to 1.5 to make the Bitmoji move further to the left and right when swiping.
Additionally, ensure that your project stays organized as it grows.
Group related objects under main scene objects to make navigation easier, especially when the project becomes more complex with additional assets and components.

Summary
In this part of the Bitmoji Runner Game tutorial, you've set up the core movement for your Bitmoji character, allowing it to move left and right based on swipe gestures. By adjusting parameters like the direction and movement time, you've created smooth transitions between animations. Additionally, you've learned the importance of keeping your project organized as it grows.
Tip: Don't forget to experiment with different movement settings and ensure all your assets are neatly organized as we move into more complex gameplay elements in the next part!