Learn to create smooth animations by interpolating between model updates for better user experience
This tutorial demonstrates how to smooth the view so that objects move continually even if the model only updates intermittently. This technique is essential for creating smooth user experiences and handling connectivity issues gracefully.
Click or scan the QR code above to launch a new CodePen instance. You’ll see several moving colored dots - one for each device currently connected to the session. Some dots may even belong to other Multisynq developers reading this documentation!
Click or tap the screen to tell your dot where to go.
The unsmoothed position of your dot is shown in gray. Notice how it jumps forward every time the model performs an update. The view uses this information to calculate each dot’s smoothed position.
In this example, the model updates only twice per second, but the dots move smoothly at 60 frames per second because the view interpolates their position between model updates.
Define constants that contribute to session synchronization
Share utility functions safely between model and view
Use "oncePerFrame"
to limit view updates efficiently
Handle infrequent model updates with smooth animations
Constants used by the model should be included in the session hash to ensure synchronization. Changing these constants will create a new session, preventing desynchronization issues.
Multisynq.Constants
contributes to the hash used to generate a session ID. Use a short alias like Q
to make your code more readable.
You can safely share utility functions between model and view as long as they are purely functional:
No External Dependencies
Function only uses parameters passed to it
No Parameter Modification
Function doesn’t modify input parameters
No State Persistence
Function doesn’t save state outside its execution scope
Consistent Results
Same inputs always produce same outputs
Pure function code isn’t included in the session ID hash. If you change these functions frequently, ensure all users have the same version to maintain synchronization.
The root classes handle spawning and managing Actor-Pawn pairs:
RootModel
spawns an Actor
, which tells RootView
to spawn a Pawn
RootModel
removes the Actor
, which tells RootView
to remove the Pawn
During initialization, the view should never assume the model’s current state. Always read the model state and build accordingly, as the view might be joining a session in progress or restoring from a snapshot.
The goto
method calculates movement vectors:
Q.CLOSE
distance)Since actors step forward fixed distances and usually overshoot goals, arrival is detected by checking if the direction to the goal has reversed (negative dot product).
Each tick:
Key features:
"oncePerFrame"
to optimize event handling"oncePerFrame"
discards all but the last event of this type during each frame. This is crucial for high-frequency updates where only the latest position matters.
Simply timestamps when the actor last moved, enabling position extrapolation.
The smoothing algorithm:
The Q.SMOOTH
value (0 < SMOOTH ≤ 1) controls interpolation behavior:
No interpolation - instant position updates (jerky)
Balanced smoothing - good responsiveness
Heavy smoothing - very smooth but less responsive
Rule of thumb: Tune Q.SMOOTH
so the pawn spends about half its time behind the actor’s position and half ahead. This provides optimal balance between smoothness and responsiveness.
The tps
(ticks per second) option controls reflector heartbeat frequency:
In this tutorial, Q.TICK_MS = 500
means the reflector sends heartbeat ticks twice per second maximum. Set heartbeat rate to match your model’s update frequency.
Increasing heartbeat tick rate will NOT make your app more responsive. User input events are sent immediately and processed as soon as received. Heartbeat ticks only affect model updates when no other events are received.
Discards redundant events within single frame
Only update pawns that have actually moved
Predict position between model updates
Smooth transitions prevent visual “popping”
Model Tick Rate
Match heartbeat rate to your model’s natural update frequency
Smoothing Factor
Balance between smoothness and responsiveness based on your use case
Movement Speed
Adjust based on model tick rate and expected latency
Proximity Threshold
Set arrival detection distance appropriate for your coordinate system
Models handle logic, views handle presentation
Smooth 60fps animations from low-frequency model updates
Gracefully handles network hiccups and connectivity issues
Efficient event handling with frame-rate limiting
Avoid These Mistakes:
Q.SMOOTH
to 0 (causes no movement)Apply smoothing techniques to Three.js 3D scenes
See smoothing in action in a complete game
This tutorial demonstrates essential techniques for creating smooth, responsive user experiences in Multisynq applications. The Actor-Pawn pattern with interpolation is fundamental for professional-quality real-time applications.