Try it out!
Click or scan the QR code above to launch a new CodePen instance. Typing a message in either window will post the text to the shared chat screen under a randomly assigned nickname. Other people reading this documentation can also join the conversation!What You’ll Learn
User Lifecycle Events
Use
"view-join"
and "view-exit"
events to track connectionsView-Specific Data
Store user information using
viewId
as unique identifierDirect Model Reading
Safely read from model without breaking synchronization
Timeout Management
Schedule actions with
future()
and model.now()
Architecture Overview
The application uses a single Model subclass calledChatModel
that handles four main responsibilities:
- User Management: Maps active views to their nicknames
- Message History: Maintains chat conversation history
- Event Handling: Processes chat posts and reset commands
- Cleanup: Automatically clears inactive chats
Chat Model Implementation
Initialization
We use
Map
instead of plain objects for key-value collections to ensure identical behavior across users. Maps maintain insertion order when serialized/deserialized.User Lifecycle Management
Handling User Joins
- Check if the
viewId
already exists (for reconnections) - Generate a random nickname if it’s a new user
- Increment the participant count
- Notify views to refresh their user information
Handling User Exits
The
viewId
remains the same if a user reconnects from the same device. However, each browser tab gets a different viewId
, even on the same device.Message Management
Processing New Messages
- Extract the sender’s
viewId
from the event data - Look up the user’s nickname
- Build HTML chat line with nickname and escaped message
- Add to history with size limit (100 messages)
- Schedule inactivity timeout check
Inactivity Management
inactivity_timeout_ms
milliseconds have passed since the last post. If another post arrived during the timeout period, lastPostTime
will be different, and the reset is skipped.
The inactivity check uses simulation time (
this.now()
) rather than wall-clock time. This ensures consistent behavior across all users regardless of their local time settings.Chat Reset Functionality
- Inactivity timeout: No posts for 20 minutes
- User command: Someone types
/reset
- New user alone: Solo user with no previous messages
Deterministic Random Names
Even though separate instances run locally for each user, they all pick the same “random” name because
Math.random()
calls from within the model are deterministic and synchronized.Chat View Implementation
Constructor Setup
Key Constructor Principles
Store Model Reference
Store Model Reference
Keep a reference to the model for direct reading access
Initialize from Model State
Initialize from Model State
Set up the view completely from current model state
Subscribe to Updates
Subscribe to Updates
Rely on subscriptions for ongoing synchronization
Direct Reading Only
Direct Reading Only
Views can read from models but must never write directly
Message Sending
/reset
command. Note that this.viewId
is automatically available in all View classes.
Display Updates
User Information Display
Chat History Display
Model Safety with modelOnly()
To prevent accidental model modification, you can use explicit getter/setter methods:
Model.modelOnly()
throws an error if called outside normal model execution. Use this in setter methods to prevent accidental view access.Key Architecture Patterns
Event Scoping
Use different scopes (
"input"
, "history"
, "viewInfo"
) to organize eventsViewId as Key
Use
viewId
as unique identifier for user-specific dataFuture Scheduling
Schedule cleanup operations with
future()
methodSafe Model Access
Read from model freely, but write only through events
System Events Reference
view-join
view-join
Sent when a user joins the session. Contains the user’s
viewId
. Sent to all users including the one who joined.view-exit
view-exit
Sent when a user leaves the session. Contains the user’s
viewId
. Not sent to the user who left.Event Scope
Event Scope
Both events use
this.sessionId
as the scope, which is the default for system-generated events.Best Practices Demonstrated
Deterministic Behavior
Use model’s random() for consistent results across users
Resource Management
Limit history size to prevent memory growth
Graceful Cleanup
Auto-reset inactive chats for fresh user experience
Reconnection Handling
Preserve user nicknames across reconnections
Next Steps
View Smoothing
Learn animation interpolation techniques
3D Animation
Integrate Three.js for 3D synchronized experiences