### 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 Example click 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; }); } } ```