A web-based ephemeral chat site that lets users send simple, short messages along with a 2-second video of themselves.
The offical server can be found at https://chat.meatspac.es
- Send a message to anyone connected to the same seatcamp server
- Provides jpeg (filmstrip-style) videos alongside chats, which tend to be more efficient to display than videos used in meatspace-chat-v2 (h264 videos are provided for legacy clients)
- No signup required, but users receive a unique ID on first visit (displayed to users as an identicon alongside messages).
- Allows for muting users based on their ID, removing all their current messages and blocking any future ones
- Performs extremely minimal DOM element creation and recycles message elements, meaning the page loads quickly and is quite stable over long periods of time.
The easiest way to run your own server is via Docker. There are official Docker images maintained on
DockerHub. These include all the
necessary dependencies, and can be configured similarly to running the server locally. See the
deployment/
directory for docker-compose
files that will also set up the necessary SSL
certificates.
If not using Docker, seatcamp requires node >=18.0.0 and ffmpeg in order to work. Node can be downloaded its official site. ffmpeg can generally be installed from your OS's package manager, or from source. Examples of installing it:
OSX
$ brew install ffmpeg --with-ffplay --with-freetype --with-frei0r --with-libass --with-libvorbis --with-libvpx --with-opencore-amr --with-openjpeg --with-opus --with-theora --with-tools
Ubuntu/Debian
$ sudo apt-get install ffmpeg
Server configuration is handled through a .env
file. See sample.env
for the available options.
For a local development server you can likely just do:
$ cp sample.env .env
This will set you up with a server running on port 3456
.
The server can then be run with:
$ npm start
Using a webcam from websites requires HTTPS (except for local addresses). The seatcamp server does not provide direct support for HTTPS, under the expectation that this will be handled better at a different layer. There are a variety of TLS termination applications to choose from that will work well for this purpose, such as nginx or HAProxy.
The protocol of seatcamp is built around socket.io, making use of binary frames where appropriate.
Upon connecting, clients must send a fingerprint to the server. This fingerprint should uniquely identify a particular client, and be relatively stable. Examples of good choices for this would be a hardware identifier (e.g. Android ID), or a fingerprint constructed from many data points that don't change often (e.g. fingerprintjs). Bad choices are things like IP addresses, since these could potentially change a lot, as well as collide for multiple users.
To send the fingerprint, clients simply emit a fingerprint
message with the fingerprint data as
the body, i.e.
io.emit('fingerprint', 'myCoolFingerprint')
The server will reply with a userid
message containing the ID it has calculated for this client,
which should be saved so that a client can recognize which messages are its own. This ID will be
constant for the lifetime of the websocket connection. An example of handling the message would be:
io.on('userid', function (userId) {
myId = userId
})
Clients should then specify what type of video they would like to receive by joining a channel. They
may do this using the join
message:
io.emit('join', 'jpg')
At present, the server supports two video types: jpg
(vertically-stacked JPEG filmstrip) or
h264
.
Messages are transmitted to clients using the chat
message. The format of the data passed in this
message is:
{
"video": ArrayBuffer(),
"videoType": "jpg",
"videoMime": "image/jpeg",
"key": "AUniqueIdForTheMessage",
"text": "The text the user sent",
"sent": 1421135370231,
"userId": "TheUserIDOftheSender",
"from": "seatcamp"
}
videoType
and videoMime
will change based on what video format you subscribed to. sent
is a
unix timestamp corresponding to when the message was originally sent. from
specifies what server
the message originated from (and can currently only be seatcamp
).
Clients can send messages by sending a chat
message themselves, with the first parameter in the
following format:
{
"text": "The text the user wants to send",
"format": "image/jpeg",
"ack": "AUniqueIdTheServerShouldAckWith"
}
Clients should send an array of 10 frames (as binary) as the second parameter, e.g.
io.emit('chat', message, frames)
format
specifies what format these frames are in. At present, only image/jpeg
is accepted. If
ack
is specified, the server will send a response message containing the ID given, allowing
clients to find out if specific messages succeeded or failed. Acks are transmitted via an ack
message, formatted as:
{
"key": "AckIdThatWasSpecified",
"err": "An error message (if applicable)"
}
If err
is not set, the message sending succeeded.
The server will send clients a number of different status updates to allow things like user counts to be known. These are all handled through seperate messages, which are:
Specifies how many users are currently connected.
io.on('active', function (numActive) {
alert('There are ' + numActive + ' active seatcamp users!')
})
seatcamp is written using ES6-compliant JavaScript, compiled to ES5 using babel. Client-side code
is similarly written, but compiled with browserify
and babelify
. Contributions should attempt to
make use of ES6 features where they make sense. Pull requests are accepted and will be looked at in
a timely manner. If you are contributing a new feature (rather than a bug fix), its a good idea to
open a PR early to discuss the viability of that feature in the larger ecosystem before you attempt
to write code for it.
New features will be accepted if they fortify/enhance behavior that developed from the community (e.g. hashtags on Twitter), but will likely be denied if they are something completely outside of the way the community uses the site.
- ednapiranha for creating meatspace
- thethp for whosthatmeat which inspired the identicons feature
- llkats for meatdelay which inspired the built-in time delay feature that will be implemented REAL SOON NOW
MIT