vanilla-party
v0.6.2
Published
An easy to use library for simple multi-user JavaScript apps.
Maintainers
Readme
Vanilla Party 🎉
Vanilla Party is a library for easily prototyping online multi-user apps with JavaScript. Quickly test ideas for multiplayer games, realtime multi-user apps, and multi-computer projects.
Contents
- Introduction
- Installation
- Getting Started
- API Documentation
- Frequently Asked Questions
- Contributing
- Acknowledgements
- License
Introduction
Features
No Server-Side Code
With Vanilla Party your projects are written using only client-side JavaScript. Quickly try ideas without writing server code or setting up a back-end stack.
Real-time Data Sync
With Vanilla Party you can easily create a shared data object that is automatically synchronized between instances of your project. You can assign and read properties on these objects just like a plain old local javascript object.
Multiple Apps and Rooms
A single Vanilla Party server can support many apps and each app can group users into rooms. Vanilla Party keeps track of which clients are in each room and shares the data to the right clients.
Client-side Hosting
Vanilla Party automatically designates one (and only one) guest in each room as the host. Your code can easily check if it is the host and take care of running the party.
What is it good for?
Prototyping
Vanilla Party provides a simple, imperative interface for working with shared data inspired by the p5.party library. Vanilla Party let's you try ideas quickly without writing server code or setting up a front-end/back-end stack.
Workshops + Classes
Vanilla Party uses a deepstream.io server which is easy to set up and cheap—or free—to run. Many projects can connect to the same Vanilla Party server, so students can focus on coding instead of setting up servers.
What is it not good for?
Production
Vanilla Party is designed for prototypes. As your project grows, you'll need to look into other libraries and backends that suit your project's needs.
Security
Projects built with Vanilla Party are insecure and has no method to authenticate or authorize users. Multiple apps share a server and can read, write, and delete each other's data.
Installation
The quickest way to get started with Vanilla Party is to load or download from a CDN.
Or install via NPM using npm install vanilla-party.
Getting Started
<script src="https://unpkg.com/vanilla-party@latest/dist/vanilla-party.js"></script>window.addEventListener("load", () => {
let shared = null
let div = null
// server url
const serverUrl = "wss://vanilla-party.luizbills.com/"
// your app name (tip: avoid generic names)
const appName = "my-party-app"
// the room where users will join
const room = "main"
// connect to server
partyConnect(serverUrl, appName, room)
// load a shared data object
partyLoadShared("shared", { x: 0, y: 0 }, (data) => {
shared = data
onSharedDataReady()
})
// create a div element
div = document.createElement("div")
document.body.append(div)
div.textContent = `connecting...`
function onSharedDataReady() {
const size = 64
div.textContent = ""
div.style.cssText = `width:${size}px;height:${size}px;background:red;border-radius:100%;position:absolute;`
window.addEventListener("click", (ev) => {
// listen clicks and taps and
// write shared data
shared.x = ev.clientX - size / 2
shared.y = ev.clientY - size / 2
})
function update() {
// read shared data
div.style.left = `${shared.x}px`
div.style.top = `${shared.y}px`
}
// call update() 30 times per second
setInterval(update, 1000 / 30)
}
})Live Demo (Try in two browser windows at once)
Note: This example is using only javascript and HTML to illustrate how easy it is to get started with Vanilla Party. In our examples, we'll use P5.js for user interaction and rendering.
API Documentation
partyConnect(host, appName, roomId?, callback?)
Connects the local user to a Vanilla Party server.
Parameters
host: string
The server to connect to. You can host your own server or use my demo server: wss://vanilla-party.luizbills.com
appName: string
A unique string identifying your app, e.g. luizbills-pong
roomName: string (optional)
A string to namespace users and events within a app. Default: "main"
callback: () => void (optional)
A function to be called when the connection is ready.
Returns
Nothing.
partyDisconnect()
Immediately disconnects the local user. The user’s shared object will be removed from other guests arrays. The disconnect user will have continue to have access to shared objects, including the guest array, but they will no longer sync.
Parameters
None.
Returns
Nothing.
partyLoadShared(name, initObject?, callback?)
Loads or creates a “shared object” with the given name in the current room.
Parameters
name: string
The name of the shared object on the server.
initObject: UserData (optional)
Data to initialize the shared object with, eg. {x: 0, y: 0}.
The shared object is initialized with the values in the data object ONLY if the room is empty when the user connects. If the room already has connected users, then the data object argument will be ignored and loaded from the server.
callback: (data: JSONObject) => void (optional)
A function to be called when the shared object is ready (fully loaded from the server).
Returns
Returns an empty object {} which will be populated with the synced properties as soon as they are loaded from the server. The property values of the shared object are synchronized between connected users in the room.
partyLoadMyShared(initObject?, callback?)
Returns the local user’s shared data object.
Parameters
initObject: UserData (optional)
The data to initialize the shared object with, eg. {favoriteColor: "purple"}.
callback: (data: JSONObject) => void (optional)
A function to be called when the shared object is ready (fully loaded from the server).
Returns
The local user's shared object.
partySetShared(sharedObject, data)
Replaces the current properties of a shared object with the values given in data.
The data is overwritten, not merged. All the existing properties on sharedObject will be removed and the properties in data will replace them.
You can use this function to set all the properties of a shared object at once:
partySetShared(shared, { x: 10, y: 10, z: 10 })You can use this function to quickly clear or reset a shared object:
partySetShared(shared, {})Parameters
sharedObject: JSONObject
A shared object.
data: JSONObject
data to write in sharedObject.
Returns
Nothing.
partyLoadGuestShareds()
Vanilla Party maintains a shared object for each user in the room. partyLoadGuestShareds() returns a dynamic array of these shared objects that is kept up to date as users join and leave the room. But if an user’s shared object is empty (it has no properties) it will NOT be included in that dynamic array.
Parameters
None.
Returns
The dynamically updated array of shared objects.
partyWatchShared(shared, [path], callback, triggerNow?)
Watches a shared object and calls the callback when any of its properties change. But you can optionally provide a path on the object to watch.
Parameters
shared: JSONObject
The shared object to watch.
path: string (optional)
A path on the shared object to watch, e.g. "position.x"
callback: (data) => void
A function to call when shared is updated. With path, data will be the new value of the updated property. Without path, data will be the shared.
triggerNow: boolean (optional)
Should the callback fire immediately? Default: false
Returns
Nothing.
Examples
Watch for any changes on shared.
let shared = partyLoadShared("shared")
partyWatchShared(shared, function (sharedUpdated) {
console.log("received new data on shared:", sharedUpdated)
})Watch for changes to property x on shared.
let shared = partyLoadShared("shared", { x: 0 })
partyWatchShared(shared, "x", function (x) {
console.log("x changed to ", x)
})partyIsHost()
Check to see if the local user has designated as the room’s host.
Vanilla Party designates exactly one user in each occupied room as its host at all times.
Parameters
None.
Returns
Returns true if the local user is the host, otherwise returns false.
partyEmit(eventName, data?)
Broadcast an event message to connected users in this room.
Parameters
eventName: string
The event name.
data: JSONObject (optional)
The data to send.
Returns
Nothing.
partySubscribe(eventName, callback)
Register a callback to handle incoming event messages.
Parameters
eventName: string
The event name to subscribe to.
callback: (data: JSONObject | undefined) => void
A function to be called when event message is received.
Returns
Nothing.
partyUnsubscribe(eventName, callback?)
Stop listening to event messages.
Parameters
eventName: string
The event name to unsubscribe from.
callback: (data: JSONObject | undefined) => void
The callback that you want to remove. If you don’t provide a callback, all callbacks for the provided eventName will be removed.
Returns
Nothing.
partyCountGuests()
Returns the quantity of connected users in the room.
Parameters
None.
Returns
A number.
partyGetRoom()
Returns the Room instance used by the local user connection.
Parameters
Nothing.
Returns
The room instance.
partyToggleInfo(show?)
Use partyToggleInfo() to hide, show, or toggle the visibility of the info panel (useful during development).
The info panel can also be toggled pressing F1 key.
Parameters
show: boolean (optional)
Pass nothing to toggle from the current state. Pass true to show the panel or false to hide the panel.
Returns
Nothing.
Examples
// show the panel at startup.
partyToggleInfo(true)Frequently Asked Questions
Do I need a username and password to connect to the server?
No.
Can I set up usernames and passwords on my own deepstream.io server?
No. Vanilla Party does not provide any way to limit connections or authenticate users. Adding an authentication and permission system would significantly increase the complexity. Vanilla Party is focused on ease-of-use, experimentation, and prototyping. If you need security, Vanilla Party won’t work for you.
When do I use different app names?
Typically, you use a unique app name for every project you are making.
What would happen if I use the same app name as someone else?
If you use the same app name as someone else on the same server, your shared data and messages might accidentally get mixed up. To avoid using someone else’s app name, add a prefix to your app name. E.g.: instead of "pong", use "johnwick-pong".
What kind of data can be shared?
Shared objects can contain only data. They cannot contain methods or internal (private) state. These simple, data-only objects are sometimes called "Plain Old JavaScript Objects" (POJOs).
Shared objects can share basic data types: numbers, strings, booleans, null, arrays and other objects.
You can not share: Infinity, NaN, functions, DOM Elements, symbol values, class instances, etc.
If you set a property’s value as undefined the property will be removed.
Pro Tip: In general any data that is JSON serializable can be shared, and data that isn’t JSON serializable can not.
How do I avoid data conflicts if I have multiple clients writing to the same object?
If your game requires a shared object across multiple clients, it is pertinent that they write to the object at different times. A few ways to do that are ensuring that only one client (the host) is writing to the object as shown or creating a turn based logic.
How is the host chosen?
When an user connects to an empty room, that user is designated as host immediately and remains host until it disconnects. When the current host disconnects, another host is chosen automatically.
Can I host my own server?
You don’t necessarily need to set up your own server. You can get started with our demo server:
wss://vanilla-party.luizbills.com
This is the easiest way to get started and for quick throw-away prototypes, but don’t count on the server being around for long term. Someday it might move to a new url, have an unplanned outage, or go offline forever. Fortunately, setting up your own server and switching to it isn’t that hard.
But if you need long term stability, you might want to set up your own server using Node.js:
git clone https://github.com/luizbills/deepstream.io-public deepstream-server
cd deepstream-server
npm ci
npm startDone! Now you have a local deepstream.io server running in your machine on http://localhost:6020.
Alternatively, you can deploy it on a cloud service of your choice (Heroku, Linode, AWS, etc). Even a cheap VPS can support many connections.
Contributing
We welcome new contibuters. Please feel free to start a discussion, report issues, or request features. If you want to help with writing code or documentation, you can start by indicating your interest on an open issue or by creating your own.
Acknowledgements
Vanilla Party is heavily based on jbakse/p5.party, a P5 library builds on deepstream.io and sindresorhus/on-change. Deepstream is a realtime data-sync server that can be easily self hosted on services like Heroku, Digital Ocean, Google Cloud, Fly.io, etc. on-change uses javascript proxies to make a fully observable object.
License
Distributed under the MIT License. See LICENSE for more information.
