### Example: Launch Multisynq Application Session
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/1_1_hello_world.md
Demonstrates how to launch a Multisynq application session using `Multisynq.Session.join`. This method connects to a synchronizer, instantiates the model and view classes, and starts the main event loop, making the application operational.
```JavaScript
Multisynq.Session.join({
apiKey: "your_api_key",
appId: "io.codepen.multisynq.hello",
name: "public",
password: "none",
model: MyModel,
view: MyView
});
```
--------------------------------
### Install Multisynq Client with npm
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/QUICKSTART.md
This command installs the Multisynq client library using npm, suitable for projects using a bundler. It's the first step before importing the library into your JavaScript files.
```SH
npm install @multisynq/client
```
--------------------------------
### Import Multisynq Client after npm Installation
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/QUICKSTART.md
After installing the Multisynq client via npm, this snippet shows how to import it into your JavaScript file. Remember to specify the `charset` for your HTML or script tags for proper functionality.
```JS
import * as Multisynq from "@multisynq/client"
```
--------------------------------
### HTML Structure for Multisynq Data API Example
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/2_9_data.md
This HTML snippet provides the basic page structure, including meta tags, title, and a body with an image input, a message display, and the inclusion of the Multisynq client library. It sets up the environment for the JavaScript Model and View to operate, enabling user interaction for file selection and drag-and-drop.
```HTML
Data + Persistence Exampleclick to import picture, or drag-and-drop one
```
--------------------------------
### Initialize Multisynq Application Session
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/2_9_data.md
Configures and joins a Multisynq session, setting up the application ID, API key, model, view, and transaction per second (TPS) limit. This snippet also includes a call to display a QR code for the widget dock.
```javascript
Multisynq.App.makeWidgetDock(); // show QR code
Multisynq.Session.join({
appId: "com.example.datatest",
apiKey: "", // get an API key from multisynq.io/coder
model: DataTestModel,
view: DataTestView,
tps: 0,
});
```
--------------------------------
### Install Multisynq Client via npm
Source: https://github.com/multisynq/multisynq-client/blob/main/README.md
Installs the Multisynq Client library using npm, the Node.js package manager. This is the recommended way to include Multisynq in a JavaScript project.
```Shell
npm i @multisynq/client
```
--------------------------------
### Multisynq.Session.join() API Reference
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/1_1_hello_world.md
Documents the `Multisynq.Session.join` method, which is the entry point for launching a Multisynq application. It defines the parameters required to establish a session, including API key, application ID, session details, and references to the model and view classes. It also outlines the sequence of operations performed upon session start.
```APIDOC
Multisynq.Session.join({ apiKey, appId, name, password, model, view, options })
apiKey: string - Your API key for connecting to a public synchronizer.
appId: string - The application identifier.
name: string - The session name.
password: string - The session password (e.g., "none" for public sessions).
model: class - The class definition for your Multisynq Model.
view: class - The class definition for your Multisynq View.
options: object - Optional configuration parameters for the session.
Session Launch Steps:
1. Connects to a nearby public synchronizer using the provided API key.
2. Instantiates the model (either runs init routine or initializes from a saved snapshot).
3. Instantiates the view, passing a reference to the model to its constructor.
4. Creates and begins executing a main event loop.
```
--------------------------------
### Initialize Three.js Scene, Camera, and Renderer in JavaScript
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/1_5_3d_animation.md
This JavaScript snippet demonstrates the initial setup of a Three.js 3D rendering environment. It creates the main Scene object, adds an ambient light and a point light for illumination, configures a PerspectiveCamera for viewing, and instantiates a WebGLRenderer to draw the scene onto a specified HTML canvas element. The renderer is also assigned a clear color.
```JavaScript
const scene = new THREE.Scene();
scene.add(new THREE.AmbientLight(0xffffff, 0.5));
const light = new THREE.PointLight(0xffffff, 1);
light.position.set(50, 50, 50);
scene.add(light);
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 10000);
camera.position.set(0, 0, 4);
const threeCanvas = document.getElementById("three");
const renderer = new THREE.WebGLRenderer({ canvas: threeCanvas });
renderer.setClearColor(0xaa4444);
```
--------------------------------
### RootView Initialization: Spawning Pawns for Existing Actors
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/1_4_view_smoothing.md
This snippet from the `RootView` constructor ensures that when the view starts up, it checks for any active actors in the model and spawns corresponding pawns. This is crucial for handling sessions already in progress or restoring from snapshots, ensuring the view always reflects the model's current state without assumptions.
```JavaScript
model.actors.forEach(actor => this.addPawn(actor));
```
--------------------------------
### Define a Multisynq Model Class
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/1_1_hello_world.md
This JavaScript code defines `MyModel`, a subclass of `Multisynq.Model`, which handles the application's core logic and state. It includes `init()` for initial setup, `resetCounter()` to respond to view events, and `tick()` for time-based simulation updates. The model is designed to run bit-identically across all session instances and manages its own save/load operations.
```JavaScript
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();
}
}
```
--------------------------------
### WorldSaver Class (Microverse Persistence Example)
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/2_A_persistence.md
The `WorldSaver` class, found in the Microverse project, serves as a real-world, complex example of implementing data persistence. It demonstrates how a sophisticated application can manage and save its world state, providing a practical reference for advanced persistence patterns within the Multisynq ecosystem.
```APIDOC
Class: WorldSaver
Source: https://github.com/croquet/microverse/blob/644544ed0734fd62939907bb9ddea0746667bc58/src/worldSaver.js#L12
Purpose: A complex, real-world example of data persistence implementation within the Microverse project.
Context: Referenced as an example of persistence logic for a 'World' state.
```
--------------------------------
### Implement Multisynq View Class (MyView)
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/1_1_hello_world.md
Implements the `MyView` class, a subclass of `Multisynq.View`. It handles user interactions by publishing events to the model and updates the display based on model state changes. It subscribes to 'changed' events from the 'counter' scope and initializes the display on session start.
```JavaScript
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;
}
}
```
--------------------------------
### Multisynq Data API: data.fetch()
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/2_9_data.md
Fetches data associated with a given data handle from the Multisynq file server, returning an `ArrayBuffer` containing the data.
```APIDOC
Data#fetch(handle: DataHandle): Promise
```
--------------------------------
### Implement Get/Set Methods with Model.modelOnly() (JavaScript)
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/1_3_multiuser_chat.md
This example demonstrates how to create explicit `Get` and `Set` methods for a model to control data access. The `setData` method utilizes `Model.modelOnly()` to prevent accidental external writes, ensuring data modifications only occur during normal model execution.
```javascript
class MyModel extends Multisynq.Model {
init() {
this.data;
}
getData() {
return this.data;
}
setData(newData) {
this.modelOnly();
this.data = newData;
}
}
MyModel.register("MyModel");
```
--------------------------------
### Display Image from Multisynq Data API
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/2_9_data.md
Asynchronously fetches image data using a Multisynq data handle, creates a Blob from the fetched ArrayBuffer, and sets it as the background image of the document body. It also displays a message indicating the fetched file's name and size.
```javascript
async showImage(asset) {
const data = await this.session.data.fetch(asset.handle); // <== Multisynq Data API
this.showMessage(`fetched "${asset.name}" (${data.byteLength} bytes)`);
const blob = new Blob([data], { type: asset.type });
document.body.style.backgroundImage = `url(${URL.createObjectURL(blob)})`;
}
```
--------------------------------
### Multisynq Data API Reference
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/2_9_data.md
This section describes key classes and functions of the Multisynq Data API. It covers `Multisynq.Model` and `Multisynq.View` base classes, and `Multisynq.Data` static methods like `store()` for uploading data, `fetch()` for retrieving data, `toId()` for converting handles to persistent IDs, and `fromId()` for reconstructing handles from IDs.
```APIDOC
Multisynq.Model:
__init__(options: object, persisted: any):
Description: Initializes the model, subscribing to events and restoring data if persisted.
Parameters:
options: object - Initialization options.
persisted: any - Previously persisted data.
subscribe(scope: string, event: string, handler: Function):
Description: Subscribes a handler function to a specific event within a scope.
Parameters:
scope: string - The scope of the event.
event: string - The name of the event.
handler: Function - The function to call when the event is published.
publish(scope: string, event: string, data: any):
Description: Publishes an event with associated data to a specific scope.
Parameters:
scope: string - The scope of the event.
event: string - The name of the event.
data: any - The data to publish with the event.
persistSession(saveFunction: Function):
Description: Registers a function to save the model's state for persistence.
Parameters:
saveFunction: Function - A function that returns the data to be persisted.
Multisynq.View:
__init__(model: Multisynq.Model):
Description: Initializes the view, linking it to a model.
Parameters:
model: Multisynq.Model - The model associated with this view.
subscribe(scope: string, event: string, handler: Function):
Description: Subscribes a handler function to a specific event within a scope.
Parameters:
scope: string - The scope of the event.
event: string - The name of the event.
handler: Function - The function to call when the event is published.
publish(scope: string, event: string, data: any):
Description: Publishes an event with associated data to a specific scope.
Parameters:
scope: string - The scope of the event.
event: string - The name of the event.
data: any - The data to publish with the event.
Multisynq.Data:
store(data: ArrayBuffer | Blob): Promise
Description: Uploads binary data to the Multisynq file server.
Parameters:
data: ArrayBuffer | Blob - The binary data to store.
Returns: Promise - A promise that resolves with a data handle string.
fetch(handle: string): Promise
Description: Retrieves binary data associated with a given data handle.
Parameters:
handle: string - The data handle obtained from store().
Returns: Promise - A promise that resolves with the retrieved binary data.
toId(handle: string): string
Description: Converts a data handle into a persistent ID string suitable for storage in models.
Parameters:
handle: string - The data handle to convert.
Returns: string - A persistent ID string.
fromId(id: string): string
Description: Reconstructs a data handle from a persistent ID string.
Parameters:
id: string - The persistent ID string.
Returns: string - The reconstructed data handle.
```
--------------------------------
### Initialize Multisynq Global Constants
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/1_2_simple_animation.md
This snippet initializes global constants for the animation, such as the number of balls, the animation step interval, and the maximum speed. These constants are stored in `Multisynq.Constants` to ensure consistency across all users in a session and are recursively frozen once a session has started to prevent accidental modification.
```javascript
const Q = Multisynq.Constants;
Q.BALL_NUM = 25; // how many balls do we want?
Q.STEP_MS = 1000 / 30; // bouncing ball tick interval in ms
Q.SPEED = 10; // max speed on a dimension, in units/s
```
--------------------------------
### Multisynq Model for Data Persistence and Asset Management
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/2_9_data.md
This JavaScript class, `DataTestModel`, extends `Multisynq.Model` to manage assets and their persistence. It subscribes to 'add-asset' events, stores asset metadata (name, type, size, handle ID), and uses `persistSession` to save and `restoreData` to load asset information across sessions. It demonstrates how to convert data handles to and from IDs for persistence.
```JavaScript
class DataTestModel extends Multisynq.Model {
init(options, persisted) { // <== Multisynq Persistence
this.subscribe("global", "add-asset", this.addAsset);
if (persisted) this.restoreData(persisted);
}
addAsset(asset) {
this.asset = asset;
this.publish("global", "asset-added", asset);
this.persistSession(this.saveData); // <== Multisynq Persistence
}
saveData() {
const { name, type, size, handle } = this.asset;
const id = Multisynq.Data.toId(handle);
return { name, type, size, id };
}
restoreData(saved) {
const { name, type, size, id } = saved;
const handle = Multisynq.Data.fromId(id);
this.asset = { name, type, size, handle };
}
}
DataTestModel.register("DataTestModel");
```
--------------------------------
### Multisynq View for File Upload and Data Retrieval
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/2_9_data.md
This JavaScript class, `DataTestView`, extends `Multisynq.View` to handle user interactions for file upload and display. It manages drag-and-drop and file input events, reads file data, and orchestrates the upload process using `session.data.store()`. It also subscribes to 'asset-added' events to fetch and display stored data, demonstrating the client-side interaction with the Multisynq Data API.
```JavaScript
let deferredUpload = null;
class DataTestView extends Multisynq.View {
constructor(model) {
super(model);
this.subscribe("global", "asset-added", this.assetAdded);
if (model.asset) this.assetAdded(model.asset);
if (deferredUpload) {
this.uploadFile(...deferredUpload);
deferredUpload = null;
}
window.ondragover = event => event.preventDefault();
window.ondrop = event => {
event.preventDefault();
this.addFile(event.dataTransfer.items[0].getAsFile());
}
imageinput.onchange = () => {
this.addFile(imageinput.files[0]);
imageinput.value = ''; // otherwise upload of another camera image won't trigger onchange
};
}
async addFile(file) {
if (!file.type.startsWith('image/')) return this.showMessage(`Not an image: "${file.name}" (${file.type})`);
// grab file data now, even if we're disconnected
this.showMessage(`reading "${file.name}" (${file.type})`);
const data = await new Promise(resolve => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result);
reader.readAsArrayBuffer(file);
});
// the session may have been disconnected while the file chooser dialog was open
if (this.session) this.uploadFile(file, data);
else deferredUpload = [file, data]; // upload as soon as the session is back
}
// only uploading user does this
async uploadFile(file, data) {
this.showMessage(`uploading "${file.name}" (${data.byteLength} bytes}`);
const size = data.byteLength; // get size before store() destroys the data
const handle = await this.session.data.store(data); // <== Multisynq Data API
const asset = { name: file.name, type: file.type, size: size, handle };
this.publish("global", "add-asset", asset);
}
// every user gets this event via model
async assetAdded(asset) {
this.showMessage(`fetching "${asset.name}" (${asset.size} bytes}`);
this.showImage(asset);
}
showMessage(string) {
message.innerText = string;
console.log(string);
}
}
```
--------------------------------
### Multisynq Data API: Data.toId()
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/2_9_data.md
Converts a Multisynq data handle into a string representation, which is suitable for storage in JSON format for persistence.
```APIDOC
Data.toId(handle: DataHandle): string
```
--------------------------------
### Blast Model: Accessing the Game Root Model
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/1_6_multiblaster.md
This getter method in the `Blast` class provides a convenient way to access the main `Game` object, which is registered as the `modelRoot`. This allows `Blast` instances to interact with the global game state, for example, to register or unregister themselves upon creation or destruction.
```js
get game() { return this.wellKnownModel("modelRoot"); }
```
--------------------------------
### Multisynq Data API: Data.fromId()
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/2_9_data.md
Recreates a Multisynq data handle from its string representation, typically used to retrieve a handle that was previously persisted using `Data.toId()`.
```APIDOC
Data.fromId(id: string): DataHandle
```
--------------------------------
### Multisynq Data API: data.store()
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/2_9_data.md
Stores an `ArrayBuffer` asynchronously, returning a data handle. By default, the `ArrayBuffer` is detached for efficiency. To retain the original data after storage, pass `{keep: true}` in the options.
```APIDOC
Data#store(data: ArrayBuffer, options?: {keep: boolean}): Promise
```
--------------------------------
### Advanced Persistence Structure for Complex Multisynq Apps
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/2_A_persistence.md
Illustrates a more sophisticated approach to structuring persistent data in complex Multisynq applications. This example demonstrates how to separate persistence logic from core model logic, using `toSaveData` and `fromSaveData` methods, and how to incorporate versioning for future format changes. It highlights that only `persistSession` and `wellKnownModel` are Multisynq APIs, with the rest being app-specific.
```JS
class SubModel {
init(options, persisted) {
/* ... regular setup ... */
if (persisted) this.fromSaveData(persisted);
}
save() { this.wellKnownModel("modelRoot").save(); }
toSaveData() { return { /* ... some data ... */ }; }
fromSaveData(data) { /* ... set up from data ... */ }
}
class ComplexAppRootModel {
init(options, persisted) {
if (persisted) {
```
--------------------------------
### MyView.constructor(model) API Reference
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/1_1_hello_world.md
Documents the constructor for the `MyView` class. It takes a `model` object, which must be used for read-only access to prevent replication issues. The constructor initializes the base view, stores a model reference, sets up event listeners, subscribes to model changes, and performs an initial display update.
```APIDOC
MyView.constructor(model)
model: object - The model object, to be used solely for read-only access. Any modification to the model by the view here will very likely break the Multisynq replication.
super(model): Executes the base-class constructor to ensure proper initialization.
this.model = model: Stores a reference to the model for later read operations.
countDisplay.onclick = event => this.counterReset(): Binds a click event on 'countDisplay' to invoke the 'counterReset' method.
this.subscribe("counter", "changed", this.counterChanged): Subscribes the 'counterChanged' method to 'changed' events within the 'counter' scope.
this.counterChanged(): Invokes 'counterChanged' immediately to update the displayed value on session start, preventing an incorrect initial display.
```
--------------------------------
### Copy Multisynq Documentation to multisynq.io Repository
Source: https://github.com/multisynq/multisynq-client/blob/main/RELEASE.md
Steps to copy the newly built documentation from `croquet-docs` to the `multisynq.io` repository's public docs directory. This involves navigating to the target directory, removing the old client documentation, and copying the new documentation, followed by instructions to push to dev, double-check, merge to main, and double-check production.
```shell
cd ../../multisynq.io/multisynq/frontend/public/docs
rm -r client
cp -r ../../../../../croquet-docs/dist/multisynq/multisynq client
```
--------------------------------
### Multisynq Model Class Structure and Registration
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/QUICKSTART.md
Details the structure of a Multisynq Model, highlighting the `init()` method which executes only on the very first instantiation in a new session, and the mandatory `register()` static method for internal class database registration.
```JS
class MyModel extends Multisynq.Model {
init() {
...
}
}
MyModel.register("MyModel");
```
--------------------------------
### Joining a Multisynq Session
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/QUICKSTART.md
Demonstrates how to join a Multisynq session using `Multisynq.Session.join`, providing necessary session metadata like API key, app ID, session name, password, and the defined Model and View classes.
```JS
const apiKey = "your_api_key"; // paste from multisynq.io/coder
const appId = "com.example.myapp";
const name = Multisynq.App.autoSession();
const password = Multisynq.App.autoPassword();
Multisynq.Session.join({apiKey, appId, name, password, model: MyModel, view: MyView});
```
--------------------------------
### Multisynq Model API: Model#persistSession
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/2_9_data.md
Persists the current session's data, allowing access to uploaded data even if the application code changes. This method requires JSON-serializable data.
```APIDOC
Model#persistSession(data: JSON)
```
--------------------------------
### Schedule One-Time Event with future()
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/2_5_sim_time_and_future.md
Illustrates the general-purpose use of `this.future()` to schedule a single, non-recurring event in the future. This example shows how to schedule a sub-model to destroy itself after a specified delay, highlighting its utility beyond just recurring 'tick' routines.
```JavaScript
this.future(500).destroy();
```
--------------------------------
### Multisynq Get Current Simulation Time with now()
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/QUICKSTART.md
This method, available within a model, returns the current simulation time. Simulation time is advanced based on events passing through the reflector and heartbeat ticks, ensuring consistent time across model replicas.
```APIDOC
Method: Model.now(): number
Description: Returns the current simulation time.
Returns:
number: The current simulation time.
```
--------------------------------
### Game Model: Handling Player Join and Exit Events
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/1_6_multiblaster.md
The `Game` class manages the creation and destruction of spaceships for players. It subscribes to session-wide `view-join` and `view-exit` events. When a player joins, a new `Ship` instance is created and tracked; when a player exits, their corresponding ship is destroyed.
```js
class Game extends Multisynq.Model {
init() {
...
this.ships = new Map();
this.subscribe(this.sessionId, "view-join", this.viewJoined);
this.subscribe(this.sessionId, "view-exit", this.viewExited);
}
viewJoined(viewId) {
const ship = Ship.create({ viewId });
this.ships.set(viewId, ship);
}
viewExited(viewId) {
const ship = this.ships.get(viewId);
this.ships.delete(viewId);
ship.destroy();
}
...
```
--------------------------------
### Building and Watching Multisynq Client Documentation
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/README.md
Commands to build or continuously watch for changes in the Multisynq client documentation. These commands should be executed from the `croquet-docs/multisync-client` directory.
```bash
npm run build
npm run watch
```
--------------------------------
### Share Pure Functions Between Model and View
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/1_4_view_smoothing.md
This example illustrates how to define and use pure utility functions, such as 2-D vector operations, that can be safely called from both the model and the view. Pure functions do not read or modify external state, ensuring predictable behavior and avoiding desynchronization issues.
```JavaScript
function add(a,b) {
return { x: (a.x + b.x), y: (a.y + b.y) };
}
function subtract(a,b) {
return { x: (a.x - b.x), y: (a.y - b.y) };
}
```
--------------------------------
### Rebuild Multisynq Documentation in croquet-docs
Source: https://github.com/multisynq/multisynq-client/blob/main/RELEASE.md
Instructions to navigate into the `croquet-docs/multisynq` directory, execute the build script for multisynq documentation, and then open the generated `index.html` file to review the rebuilt documentation locally.
```shell
cd ../croquet-docs/multisynq
npm run build
open ../dist/multisynq/multisynq/index.html
```
--------------------------------
### Schedule First BallModel Animation Step
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/1_2_simple_animation.md
This snippet schedules the initial invocation of the `step()` method for a `BallModel` after its initialization. It uses `Multisynq.Model.future()` to defer the execution by `Q.STEP_MS`, setting up the continuous animation loop for the individual ball.
```javascript
this.future(Q.STEP_MS).step();
```
--------------------------------
### Register a Multisynq Model Subclass
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/1_1_hello_world.md
This line of JavaScript code registers the `MyModel` class with the Multisynq framework. Registration is a mandatory step for every new model subclass, allowing Multisynq to recognize and instantiate it within a session.
```JavaScript
MyModel.register("MyModel");
```
--------------------------------
### Include Multisynq Client Library via CDN
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/1_1_hello_world.md
This HTML snippet demonstrates how to add the Multisynq client library to your web application by including a script tag that points to the library hosted on a Content Delivery Network (CDN). This is the standard method for accessing Multisynq's functionalities within a JavaScript application.
```HTML
```
--------------------------------
### Pawn.constructor: Initializing Pawn and Subscribing to Actor Events
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/1_4_view_smoothing.md
The `Pawn` constructor initializes a pawn with a reference to its corresponding actor. It copies the actor's initial position and subscribes to the actor's 'moved' events using the actor's ID as scope. The subscription uses the 'oncePerFrame' option to ensure only the last 'moved' event per frame is processed, optimizing view updates.
```JavaScript
constructor(actor) {
super(actor);
this.actor = actor;
this.position = {...actor.position};
this.actorMoved();
this.subscribe(actor.id, {event: "moved", handling: "oncePerFrame"}, this.actorMoved);
}
```
--------------------------------
### Launch a Multisynq Session
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/2_2_writing_a_multisynq_app.md
Launch a Multisynq session by calling `Multisynq.Session.join`. This method requires an API key, a unique application ID, a session name, a password for encryption, and the Model and View class types. Helper functions like `Multisynq.App.autoSession()` and `Multisynq.App.autoPassword()` can simplify session and password generation.
```JavaScript
const apiKey = "your_api_key"; // paste from multisynq.io/coder
const appId = "com.example.myapp";
const name = Multisynq.App.autoSession();
const password = Multisynq.App.autoPassword();
Multisynq.Session.join({ apiKey, appId, name, password, model: MyModel, view: MyView });
```
--------------------------------
### Subscribe to BallModel Touch Event
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/1_2_simple_animation.md
This code demonstrates how a `BallModel` subscribes to a `'touch-me'` event. The subscription is scoped to the model's own ID, ensuring that only events published for this specific ball trigger the `startStop` method, which controls the ball's motion.
```javascript
this.subscribe(this.id, 'touch-me', this.startStop);
```
--------------------------------
### Defining Multisynq Model and View Classes
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/QUICKSTART.md
Illustrates the basic structure for defining `MyModel` and `MyView` classes, inheriting from `Multisynq.Model` and `Multisynq.View` respectively, including the `Model.register` call for the model.
```JS
class MyModel extends Multisynq.Model {
init() {
...
}
}
MyModel.register("MyModel");
class MyView extends Multisynq.View {
constructor(model) {
super(model);
...
}
update(time) {
...
}
}
```
--------------------------------
### Implement Custom Multisynq Main Loop
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/2_2_writing_a_multisynq_app.md
For advanced control over the application's execution, you can opt for a manual main loop by passing `step: "manual"` to `Multisynq.Session.join`. This allows you to integrate Multisynq's `session.step()` call within your own `window.requestAnimationFrame` loop, enabling custom input and output processing before and after the simulation step.
```JavaScript
const session = await Multisynq.Session.join({..., step: "manual"});
window.requestAnimationFrame(frame);
function frame(now) {
if (session.view) {
session.view.myInputMethod();
session.step(now);
session.view.myOutputMethod();
}
window.requestAnimationFrame(frame);
}
```
--------------------------------
### JavaScript Import Map Configuration for Multisynq Client
Source: https://github.com/multisynq/multisynq-client/blob/main/examples/hello/index.html
This JSON snippet defines an import map for the Multisynq client, mapping the '@multisynq/client' module to its local ESM file.
```JSON
{ "imports": { "@multisynq/client": "./multisynq-client.esm.js" } }
```
--------------------------------
### Multisynq Model Persistence API Reference
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/1_6_multiblaster.md
This section describes key methods for managing explicit data persistence in Multisynq models. It covers how to store data for future sessions using `persistSession()` and how to retrieve it upon model initialization via the `init()` method.
```APIDOC
Model:
persistSession(data: object):
description: Stores JSON data as persistent state for the current session name.
parameters:
data:
type: object
description: The JSON data to be persisted.
return: void
init(viewId: string, persistedData: object):
description: Initializes the model, optionally receiving previously persisted data.
parameters:
viewId:
type: string
description: The ID of the view associated with the model.
persistedData:
type: object | undefined
description: Data persisted from a previous session with the same name, if available.
return: void
```
--------------------------------
### Include Multisynq Client via HTML Script Tag
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/QUICKSTART.md
This snippet shows how to include the Multisynq client library directly in an HTML file using a script tag. It makes the `Multisynq` object globally available. Ensure `charset="utf-8"` is declared for consistent code hashing across browsers.
```HTML
```
--------------------------------
### Configuring Multisynq Reflector Heartbeat Tick Rate
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/1_4_view_smoothing.md
This code snippet demonstrates how to set the reflector's heartbeat tick rate using the `tps` option within the `Multisynq.Session.join` method. Heartbeat ticks enable the model to continue running even without user input, and `tps` controls their frequency. This configuration helps balance bandwidth consumption with the application's need for continuous model updates, with the example setting `tps` based on `Q.TICK_MS`.
```javascript
Multisynq.Session.join({
apiKey: "your_api_key", // paste from multisynq.io/coder
appId: "io.codepen.multisynq.smooth",
name: "public",
password: "none",
model: RootModel,
view: RootView,
tps: 1000/Q.TICK_MS,
});
```
--------------------------------
### Release Multisynq Client to npm
Source: https://github.com/multisynq/multisynq-client/blob/main/RELEASE.md
Steps to update the @croquet/croquet dependency to the latest version, perform necessary version number replacements in files (referencing earlier commits for affected files), commit changes, run tests, push to the repository, and finally publish the multisynq client package to npm.
```shell
npm i @croquet/croquet@latest
npm publish
```
--------------------------------
### Multisynq Documentation Repository Structure
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/README.md
Illustrates the required directory layout for building the Multisynq client documentation, showing the relative positions of the `multisync-client`, `croquet`, and `croquet-docs` repositories.
```plaintext
├── multisync-client
│ └── docs (this directory)
│
├── croquet
│
└── croquet-docs
└── croquet
```
--------------------------------
### Basic CSS Styling for Multisynq Client
Source: https://github.com/multisynq/multisynq-client/blob/main/examples/hello/index.html
This CSS snippet defines basic styling for the body and a counter element, including flex display, user-select prevention, and font styling.
```CSS
body { display: flex; user-select: none } #counter { margin: auto; font: 100px sans-serif; }
```
--------------------------------
### Store Three.js Scene and Renderer in View Initialization
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/1_5_3d_animation.md
This code demonstrates how the `scene` and `sceneRender` function, returned from `setUpScene()`, are stored as properties of the `MyView` instance during its initialization. This makes the rendering function available for subsequent calls within the view's lifecycle.
```JavaScript
const sceneSpec = setUpScene(); // { scene, sceneRender }
this.scene = sceneSpec.scene;
this.sceneRender = sceneSpec.sceneRender;
```
--------------------------------
### Define Multisynq Model and View Classes
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/2_2_writing_a_multisynq_app.md
To create a Multisynq application, define two classes that inherit from `Multisynq.Model` and `Multisynq.View`. The Model class contains simulation logic and must be registered with a unique name. The View class handles input and output, receiving a reference to the model in its constructor.
```JavaScript
class MyModel extends Multisynq.Model {
init() {
...
}
}
MyModel.register("MyModel");
class MyView extends Multisynq.View {
constructor(model) {
super(model);
...
}
}
```
--------------------------------
### MyView: Initializing Child Views from Model
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/1_2_simple_animation.md
This JavaScript snippet, typically found within the MyView constructor, demonstrates how to iterate through the MyModel's child objects (e.g., BallModel instances). For each child, it invokes this.attachChild to create and add its corresponding visual representation to the MyView's DOM element, establishing the initial visual hierarchy.
```JavaScript
model.children.forEach(child => this.attachChild(child));
```
--------------------------------
### Handle Pointer Move Event for Object Dragging (JavaScript)
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/1_5_3d_animation.md
This function handles `pointermove` events during an active drag operation. It prevents default browser actions and implements throttling and proximity checks to limit event processing, reducing network burden for real-time updates. It updates the `dragObject`'s position via `q_onDrag`.
```javascript
function onPointerMove(event) {
event.preventDefault();
// ignore if there is no drag happening
if (!dragObject) return;
// ignore if the event is too soon after the last one
if (event.timeStamp - lastTime < THROTTLE_MS) return;
lastTime = event.timeStamp;
const lastMouse = {...mouse};
setMouse(event);
// ignore if the event is too close on the screen to the last one
if (Math.abs(mouse.x-lastMouse.x) < 0.01 && Math.abs(mouse.y - lastMouse.y) < 0.01) return;
raycaster.setFromCamera(mouse, camera);
const dragPoint = raycaster.ray.intersectPlane(dragPlane, new THREE.Vector3());
dragObject.q_onDrag(new THREE.Vector3().addVectors(dragPoint, dragOffset));
dragged = true; // a drag has happened (so don't treat the pointerup as a click)
}
```
--------------------------------
### BallView: Initializing Touch/Click Event Handling
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/1_2_simple_animation.md
This line shows the invocation of the enableTouch method within BallView. This call is responsible for setting up the necessary event listeners on the BallView's DOM element, allowing it to respond to user interactions like touches or clicks, which will then trigger a 'touch-me' event.
```JavaScript
this.enableTouch();
```
--------------------------------
### API Reference: Model and Session Methods for Persistence and Debugging
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/2_A_persistence.md
This section provides API documentation for key methods within the Model and Session classes, focusing on their roles in persistent data management and debugging. It details parameters, return types, and behavioral aspects, including error handling and debug options.
```APIDOC
Model:
init(options, persisted):
options: Object - Configuration options for the model.
persisted: Any - The previously saved persistent data.
Description: Initializes the model, attempting to load persistent data if provided. Handles errors during loading by setting 'loadingPersistentDataErrored' and prevents saving during the loading process using 'loadingPersistentData'.
save():
Description: Saves the current session data. This method is guarded by 'loadingPersistentData' and 'loadingPersistentDataErrored' properties, preventing saving if data is currently being loaded or if a previous loading attempt failed.
fromSavedData(persisted):
persisted: Any - The data to be interpreted and used to set up the model's internal data structures.
Description: Interprets the incoming 'persisted' data and configures the model's data structures accordingly. Can raise an error if data interpretation fails.
persistSession(...):
Description: (Internal) Method responsible for actually persisting the session data. Called by 'save()' unless guarded.
Session:
join(options):
options: Object - Configuration options for joining a session.
debug: string - Optional. Specifies debug logging level.
Value: "session" - Enables additional log messages related to session loading (e.g., from snapshot or persisted data).
Description: Joins a session, with optional debug logging.
```
--------------------------------
### Handle Pointer Down Event for Object Interaction (JavaScript)
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/1_5_3d_animation.md
This function processes a `pointerdown` event, converting screen coordinates to 3D scene coordinates using `raycaster`. It identifies if the pointer intersects with a `q_draggable` object, initiating a drag operation if found. It prevents default browser actions.
```javascript
function onPointerDown(event) {
event.preventDefault();
setMouse(event); // convert from window coords to relative (-1 to +1 on each of x, y)
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObjects(scene.children);
for (let i = 0; i < intersects.length && !dragObject; i++) {
const intersect = intersects[i];
const threeObj = intersect.object;
if (threeObj.q_draggable) { // a flag that we set on just the central sphere
dragObject = threeObj;
// ... (code to start a drag) ...
}
}
}
```
--------------------------------
### Handle Pointer Up Event for Click or Drag End (JavaScript)
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/1_5_3d_animation.md
This function processes `pointerup` events, concluding a drag operation or triggering a click event. If a `dragObject` exists and no drag occurred (`dragged` flag is not set), it invokes the custom `q_onClick` method. It prevents default browser actions.
```javascript
function onPointerUp(event) {
event.preventDefault();
if (dragObject) {
if (!dragged && dragObject.q_onClick) dragObject.q_onClick();
dragObject = null;
}
}
```
--------------------------------
### MyModel Subscription to 'reset' Event for State Synchronization
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/1_5_3d_animation.md
This JavaScript code shows how `MyModel` subscribes to the 'reset' event. Upon receiving this event, it triggers `resetCenterSphere`, which in turn publishes a 'recolor-center-sphere' event. This model-level subscription is crucial for ensuring that state changes, like resetting the sphere's color, are synchronized across all user sessions via Multisynq.
```JavaScript
this.subscribe(this.id, 'reset', this.resetCenterSphere);
```
--------------------------------
### q_onClick() Event Handler Property
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/1_5_3d_animation.md
The `q_onClick` property is a function assigned directly to Three.js objects. Its primary role is to publish a 'reset' event when the associated object is clicked, triggering a global state reset managed by the application's models.
```APIDOC
q_onClick(): Function
Description: A function assigned to a Three.js object, invoked on click to publish a 'reset' event.
```
--------------------------------
### Retrieve Player Initials from Local Storage on Startup (JavaScript)
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/1_6_multiblaster.md
This JavaScript code checks `localStorage` upon application startup for previously stored player initials. If initials are found, it populates the input field and publishes them to the Multisynq model, allowing players to automatically reuse their last-entered initials.
```js
if (localStorage.getItem("io.multisynq.multiblaster.initials")) {
initials.value = localStorage.getItem("io.multisynq.multiblaster.initials");
this.publish(this.viewId, "set-initials", initials.value);
}
```
--------------------------------
### Define and Return Three.js Scene Renderer Function
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/1_5_3d_animation.md
This snippet defines the `sceneRender` function responsible for calling the Three.js renderer with the current scene and camera. It then returns an object containing both the scene and this rendering function, making it accessible for external use.
```JavaScript
function sceneRender() { renderer.render(scene, camera); }
return { scene, sceneRender };
```
--------------------------------
### BallView: Implementing Touch/Click Event Publishing
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/1_2_simple_animation.md
The BallView.enableTouch method configures the BallView's DOM element to detect user interaction. It checks for TOUCH support to assign either ontouchstart or onmousedown event handlers. Upon interaction, it prevents default browser behavior and publishes a 'touch-me' event, scoped by the element's ID, which the BallModel can then subscribe to for toggling motion.
```JavaScript
BallView.enableTouch() {
const el = this.element;
if (TOUCH) el.ontouchstart = start => {
start.preventDefault();
this.publish(el.id, 'touch-me');
}; else el.onmousedown = start => {
start.preventDefault();
this.publish(el.id, 'touch-me');
};
}
```
--------------------------------
### Ship Model: Calculating Movement Based on Thruster State
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/1_6_multiblaster.md
The `move()` method within the `Ship` class updates the ship's position and rotation. It checks the `forward`, `left`, and `right` boolean properties, which are set by thruster events, to apply acceleration and angular changes. These calculations are performed locally on each player's machine, synchronized by the thruster properties.
```js
move() {
if (this.forward) this.accelerate(0.5);
if (this.left) this.a -= 0.2;
if (this.right) this.a += 0.2;
this.x = ...
this.y = ...
```
--------------------------------
### JavaScript: Implement Asteroid Movement with Screen Wrapping
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/1_6_multiblaster.md
This JavaScript code defines the `move()` method for an asteroid object. It updates the asteroid's x, y, and angle (a) properties, ensuring that objects wrap around the screen edges using the modulo operator. The movement is animated with a `setTimeout` call for continuous updates.
```js
move() {
this.x = (this.x + this.dx + 1000) % 1000;
this.y = (this.y + this.dy + 1000) % 1000;
this.a = (this.a + this.da + Math.PI) % Math.PI;
setTimeout(() => this.move(), 50);
}
```
--------------------------------
### Basic Data Persistence in a Multisynq Root Model
Source: https://github.com/multisynq/multisynq-client/blob/main/docs/tutorials/2_A_persistence.md
Demonstrates how to implement basic data persistence in a simple Multisynq application's root model. The `init` method checks for and utilizes previously persisted data, while the `save` method uses `this.persistSession` to define and return the data to be saved for future sessions. Note that `Map`s and other non-JSON types require manual handling for persistence.
```JS
class SimpleAppRootModel {
init(options, persisted) {
/* regular setup */
...
if (persisted) {
/* use persisted data */
...
}
}
save() {
this.persistSession(() => {
const data = { /* collect data to persist */ };
return data;
});
}
}
```