Introduction
Welcome to your first Multisynq application! This tutorial will guide you through building a simple but powerful real-time counter that synchronizes perfectly across all users. When one user clicks the counter, it resets for everyone instantly.
What You’ll Learn
By the end of this tutorial, you’ll understand:
How to include the Multisynq client library in your application
The Model-View architecture that powers Multisynq apps
Event-driven communication between models and views
Session sharing using QR codes and URLs
Try It Live
Test Real-time Sync : Click the QR code in the demo above to open a second instance. Notice how both counters stay perfectly synchronized!
Understanding the Session Badge
The session badge (colored rectangle with QR code) indicates which session you’re in. Users seeing the same badge colors and code word are guaranteed to be synchronized. Any change to the model code creates a new session with a different badge.
Setting Up Multisynq
1. Include the Client Library
Add the Multisynq client library to your HTML:
< script src = "https://cdn.jsdelivr.net/npm/@multisynq/client@latest" ></ script >
2. Get Your API Key
Get API Key Sign up for free at multisynq.io to get your API key
Building the Application
Every Multisynq application consists of two parts:
Model Handles computation and state
Runs identically on all instances
Manages application logic
Never directly accesses the view
View Handles UI and user input
Processes user interactions
Updates the display
Can read from model (read-only)
Critical Rules :
Models MUST NEVER communicate directly with views
Views MUST NEVER write directly to models
All communication happens through publish/subscribe events
The Model Code
Our counter model is surprisingly simple:
class MyModel extends Multisynq . Model {
init () {
this . count = 0 ;
this . subscribe ( "counter" , "reset" , this . resetCounter );
this . future ( 1000 ). tick ();
}
resetCounter () {
this . count = 0 ;
this . publish ( "counter" , "changed" );
}
tick () {
this . count ++ ;
this . publish ( "counter" , "changed" );
this . future ( 1000 ). tick ();
}
}
MyModel . register ( "MyModel" );
Breaking Down the Model
init()
- Model Initialization
init () {
this . count = 0 ;
this . subscribe ( "counter" , "reset" , this . resetCounter );
this . future ( 1000 ). tick ();
}
Model Initialization Details
this.count = 0
: Initialize our counter state
this.subscribe("counter", "reset", this.resetCounter)
: Listen for reset events from the view
this.future(1000).tick()
: Schedule the first tick in 1 second
Important : init()
only runs once when a session starts. After that, the model state is automatically saved and restored for new users joining.
resetCounter()
- Handle Reset Events
resetCounter () {
this . count = 0 ;
this . publish ( "counter" , "changed" );
}
When a user clicks the counter, this method:
Resets the count to 0
Notifies all views that the counter changed
tick()
- The Heartbeat
tick () {
this . count ++ ;
this . publish ( "counter" , "changed" );
this . future ( 1000 ). tick ();
}
This method runs every second:
Increments the counter
Notifies views of the change
Schedules the next tick
Future Messages : this.future(1000).tick()
is a powerful Multisynq feature that schedules method calls in the future. This ensures perfect synchronization across all users.
register()
- Class Registration
MyModel . register ( "MyModel" );
Every model class must be registered so Multisynq can instantiate it.
The View Code
The view handles user interface and interactions:
class MyView extends Multisynq . View {
constructor ( model ) {
super ( model );
this . model = model ;
countDisplay . onclick = event => this . counterReset ();
this . subscribe ( "counter" , "changed" , this . counterChanged );
this . counterChanged ();
}
counterReset () {
this . publish ( "counter" , "reset" );
}
counterChanged () {
countDisplay . textContent = this . model . count ;
}
}
Breaking Down the View
constructor(model)
- View Setup
constructor ( model ) {
super ( model );
this . model = model ;
countDisplay . onclick = event => this . counterReset ();
this . subscribe ( "counter" , "changed" , this . counterChanged );
this . counterChanged ();
}
super(model)
: Call the parent View constructor
this.model = model
: Store model reference for read-only access
countDisplay.onclick = ...
: Set up click handler
this.subscribe("counter", "changed", ...)
: Listen for counter changes
this.counterChanged()
: Update display immediately
counterReset()
- Handle User Clicks
counterReset () {
this . publish ( "counter" , "reset" );
}
When the user clicks, publish a reset event that the model will receive.
counterChanged()
- Update Display
counterChanged () {
countDisplay . textContent = this . model . count ;
}
Update the displayed number when the model changes.
HTML Structure
The HTML is minimal:
<! DOCTYPE html >
< html >
< head >
< title > Multisynq Hello World </ title >
</ head >
< body >
< h1 > Multisynq Hello World </ h1 >
< div id = "countDisplay" > 0 </ div >
< p > Click the counter to reset it! </ p >
< script src = "https://cdn.jsdelivr.net/npm/@multisynq/client@latest" ></ script >
< script >
// Model and View code goes here
// Start the application
Multisynq . Session . join ({
apiKey: "your_api_key_here" ,
appId: "com.example.hello-world" ,
name: Multisynq . App . autoSession (),
password: Multisynq . App . autoPassword (),
model: MyModel ,
view: MyView
});
</ script >
</ body >
</ html >
Starting Your Session
The magic happens with Multisynq.Session.join()
:
Multisynq . Session . join ({
apiKey: "your_api_key_here" ,
appId: "com.example.hello-world" ,
name: Multisynq . App . autoSession (),
password: Multisynq . App . autoPassword (),
model: MyModel ,
view: MyView
});
Session Parameters
Unique identifier for your app (e.g., “com.example.hello-world”)
Session name. Use Multisynq.App.autoSession()
for auto-generated names
Session password. Use Multisynq.App.autoPassword()
for auto-generated passwords
What Happens When You Join
Connect to a nearby Multisynq reflector
Initialize or restore the model state
Create your view instance
Start the event loop
Begin synchronization with other users
Testing Your App
1. Single User Testing
Start by testing the basic functionality with one browser tab.
2. Multi-User Testing
Open your app in multiple browser tabs or devices to test synchronization.
3. QR Code Sharing
Use QR codes to easily share sessions with mobile devices.
Mobile Testing : The QR code feature makes it incredibly easy to test your app on mobile devices. Just scan the code with your phone’s camera!
Common Patterns
Automatic Helpers
Multisynq provides helpful utilities:
// Generate random session names
name : Multisynq . App . autoSession (), // Returns something like "abc12"
// Generate random passwords
password : Multisynq . App . autoPassword (), // Returns a secure password
Event Scoping
Use meaningful scope names for your events:
// Good: Descriptive scopes
this . subscribe ( "game" , "playerJoined" , this . handlePlayerJoined );
this . subscribe ( "ui" , "buttonClicked" , this . handleButtonClick );
// Avoid: Generic scopes
this . subscribe ( "events" , "something" , this . handleSomething );
State Management
Keep your model state simple and serializable:
// Good: Simple data types
this . count = 0 ;
this . players = [];
this . gameState = "waiting" ;
// Avoid: Complex objects or functions
this . domElement = document . getElementById ( "something" ); // No!
this . callback = () => {}; // No!
Next Steps
Troubleshooting
Check that your API key is valid
Ensure MyModel.register("MyModel")
is called
Verify the model’s tick()
method is being called
Multiple users not synchronized
Confirm all users have the same appId
Check that all users joined the same session name
Ensure the model code is identical across all instances
Verify the QR code generation service is accessible
Check that the URL in the QR code is correct
Test the URL manually in a browser
Complete Example
Here’s the full working example you can copy and paste:
<! DOCTYPE html >
< html >
< head >
< title > Multisynq Hello World </ title >
< style >
body {
font-family : Arial , sans-serif ;
text-align : center ;
padding : 50 px ;
}
#countDisplay {
font-size : 72 px ;
color : #007bff ;
cursor : pointer ;
user-select : none ;
padding : 20 px ;
border : 2 px solid #007bff ;
border-radius : 10 px ;
display : inline-block ;
margin : 20 px ;
}
#countDisplay:hover {
background-color : #f8f9fa ;
}
</ style >
</ head >
< body >
< h1 > Multisynq Hello World </ h1 >
< p > Counter updates every second. Click to reset! </ p >
< div id = "countDisplay" > 0 </ div >
< p >< small > Open this page in multiple tabs to see real-time sync! </ small ></ p >
< script src = "https://cdn.jsdelivr.net/npm/@multisynq/client@latest" ></ script >
< script >
class MyModel extends Multisynq . Model {
init () {
this . count = 0 ;
this . subscribe ( "counter" , "reset" , this . resetCounter );
this . future ( 1000 ). tick ();
}
resetCounter () {
this . count = 0 ;
this . publish ( "counter" , "changed" );
}
tick () {
this . count ++ ;
this . publish ( "counter" , "changed" );
this . future ( 1000 ). tick ();
}
}
MyModel . register ( "MyModel" );
class MyView extends Multisynq . View {
constructor ( model ) {
super ( model );
this . model = model ;
countDisplay . onclick = event => this . counterReset ();
this . subscribe ( "counter" , "changed" , this . counterChanged );
this . counterChanged ();
}
counterReset () {
this . publish ( "counter" , "reset" );
}
counterChanged () {
countDisplay . textContent = this . model . count ;
}
}
// Start the application
Multisynq . Session . join ({
apiKey: "your_api_key_here" , // Get your free key at multisynq.io/coder
appId: "com.example.hello-world" ,
name: Multisynq . App . autoSession (),
password: Multisynq . App . autoPassword (),
model: MyModel ,
view: MyView
});
</ script >
</ body >
</ html >
Don’t forget to replace "your_api_key_here"
with your actual API key from multisynq.io/coder !
Summary
Congratulations! You’ve built your first Multisynq application. You learned:
✅ How to structure a Multisynq app with Models and Views
✅ Event-driven communication using publish/subscribe
✅ Future messages for time-based events
✅ Session management and sharing
✅ Real-time synchronization across multiple users
This simple counter demonstrates all the core concepts you’ll use in more complex Multisynq applications. The same patterns scale from simple demos to full-featured collaborative applications!
Responses are generated using AI and may contain mistakes.