Skip to content
The King of Half-Baked Projects edited this page Nov 17, 2024 · 49 revisions

The scribble.rs API consists of an HTTP interface and a WebSocket interface. The HTTP interface has two usecases. One being the server side rendered parts of the official web client and the other the REST-API usable by external applications.

All paths in the internal API start with ssr and resemble method names seen in programming.

  1. HTTP API
  2. WS API
  3. Example
    1. Objects
    2. Receivable Events
    3. Sendable Events

NOTE: All APIs are unstable and could change any time. This will change with the release of v1.0.0 of scribble.rs

NOTE: None of the APIs escape user input. Meaning HTML might be sent over the net. This is intentional in order to avoid unnecessary escaping and unescaping.

HTTP API

The HTTP API offers one endpoints that supports GET, PATCH, POST and PUT.

LobbyData object

Name Value
lobbyId ID of the newly created Lobby.
minDrawingTime Lower bound for the drawing time setting.
maxDrawingTime Upper bound for the drawing time setting.
minRounds Lower bound for the rounds setting.
maxRounds Upper bound for the rounds setting.
minMaxPlayers Lower bound for the maxPlayers setting.
maxMaxPlayers Upper bound for the maxPlayers setting.
minClientsPerIpLimit Lower bound for clientsPerIpLimit setting.
maxClientsPerIpLimit Upper bound for clientsPerIpLimit setting.
maxPlayers Maximum amount of players allowed to join.
rounds How many rounds will be played in this lobby til the gameOver state is reached.
public Whether the lobby can be found and join via the public lobby list.
enableVotekick Whether people are allows to kick eachother via majority votes.
customWordsChance Chance in percent of how likely a proposed word is a custom word.
clientsPerIpLimit Defines how many players in the lobby are allowed to join from the same IP / Network.
drawingBoardBaseWidth The unscaled width of canvas in order to scale drawing instructions.
drawingBoardBaseHeight The unscaled height of canvas in order to scale drawing instructions.
minBrushSize Minimum brush size in pixels.
maxBrushSize Maximum brush size in pixels.
suggestedBrushSizes An array with different brushsizes suggested for the client. The array is ordered from low to high and doesn't have to be obeyed.
canvasColor The initial / empty color of the canvas. In browser white is usually the default, this might differ in other frameworks. The value is a color object.

/v1/lobby

/v1/lobby - POST request

Creates a new lobby.

Parameters

Query Parameter Description Type
lobby_id Specifies the lobbies ID. A valid UUIDv4, such as 8696df3d-5a52-403a-baed-9c4599487961.
language Selects the word set used in the lobby. Either dutch, english, english_gb, french, german or italian.
drawing_time Determines the amount of seconds that a player has time to choose a word. An integral number between 60 and 300
rounds Amount of rounds that the game takes to complete. An integral number between 1 and 20.
max_players Determines the maximum amount of people that can join An integral number between 2 and 24.
custom_words Custom words to use instead of or on top of the word set. A comma separated list of words. The words can contain any characters.
custom_words_chance Determines how often the custom word pool gets accessed. An integral number between 1 and 100.
clients_per_ip_limit Decides how many players can have the same IP in one lobby. An integral number between 1 and 24.
enable_votekick Decides whether players can kick each other by voting. Either true or false.
public Decides whether this lobby is published on the lobby list. A boolean.
username Determines the creators username. If the name is too long, it gets trimmed. A string of a length from 1 to 30.

Answer

As a result you get a LobbyData object.

On top of that the cookie usersession gets set.

/v1/lobby - GET request

Returns all publicly available lobbies.

Returns an array of LobbyEntry objects.

LobbyEntry
Name Description Type
lobbyId Lobby ID string (UUID v4)
playerCount Currently occupied player slots. An integral number.
maxPlayers Maximum count of allowed players An integral number.
round Current round progression An integral number.
rounds How many rounds til the game is over. An integral number.
drawingTime Time that each player has in order to chose a word and draw it. An integral number.
customWords Whether custom words were entered or not. A boolean.
votekick Whether votekicking players via majority vote is allowed A boolean.
maxClientsPerIp How many players are allowed to join from the same IP / network. An integral number.
wordpack Which word (language) pack has been used string

/v1/lobby/{lobby_id} - PATCH request

Allows editing specific lobby settings after lobby creation.

Parameters

Query Parameter Description Type
custom_words Custom words to use instead of or on top of the word set. A comma separated list of words. The words can contain any characters.
language Selects the word set used in the lobby. Either dutch, english, english_gb, french, german or italian.
rounds Amount of rounds that the game takes to complete. An integral number between 1 and 20.
drawing_time Determines the amount of seconds that a player has time to choose a word. An integral number between 60 and 300
max_players Determines the maximum amount of people that can join An integral number between 2 and 24.
custom_words_chance Determines how often the custom word pool gets accessed. An integral number between 1 and 100.
clients_per_ip_limit Decides how many players can have the same IP in one lobby. An integral number between 1 and 24.
enable_votekick Decides whether players can kick each other by voting. Either true or false.
public Decides whether this lobby is published on the lobby list. A boolean.

Answer

If any errors occur, the body contains an error of error messages.

This endpoint also triggers a lobby-settings-changed WS-Event which contains the same fields.

/v1/lobby/{lobby_id}/player

Header

Entering a lobby as an existing player (rejoining) requires the header value usersession to be set to your previous user session value. The lobby_id path fragment must be set in the URI with a valid UUID returned by the API previously.

Query Parameters

Name Description Type
username Determines the username if no usersession was supplied A string with a length between 1 and 30.

Answer

As a result you get a LobbyData object.

On top of that the cookie usersession gets set.

/v1/lobby/{lobby_id}/ws

This endpoint establishes the WebSocket connection necessary for all major game functionality.

Header

This endpoint requires a valid user session in the usersession field of the header.

/v1/stats

This endpoint delivers current data about open lobbies and players. This can be used to graph player / lobby data over time.

WS API

The websocket API is required for all major game functionality such as receiving relevant events, drawing and guessing.

Objects

Wordhint

Each wordhint represents a letter of the currently chosen word. A word hint object looks like this:

Name Description
character The character hinted or 0 if this character has not been revealed
underline An indication whether this character should be displayed as underlined. Indicating that it is relevant for the word. Characters such as -, _ or should always be displayed.

Player

A player contains the following fields:

Name Description
id The internal ID of this player.
name The display name of this player.
score The current score for this game.
connected Whether the player is currently connected or disconnected.
lastScore The score received last turn. An integral number between 0 and 0+.
rank How the player currently ranks in comparison to other players score.
state Either guessing, drawing or standby.

Color

This represents an RGB color.

Name Description
r uint8 representing the red value.
g uint8 representing the green value.
b uint8 representing the blue value.

Fill

This represents the usage of the fill bucket on the canvas.

Name Description
x The unscaled X coordinate on the canvas.
y The unscaled Y coordinate on the canvas.
color A color object.

Line

This represents a line drawn by a player.

Name Description
x The unscaled X coordinate on the canvas where the line starts.
y The unscaled Y coordinate on the canvas where the line starts.
x2 The unscaled X coordinate on the canvas where the line ends.
y2 The unscaled Y coordinate on the canvas where the line ends
color A color object.
width The thickness of the line.

Receivable events

All events generally contain two fields on the root level. The type, determining the kind of the event and the data field, which content can be determined depending on the type field. There might also be events where the data field is empty.

ready

The ready event contains all data needed in order to correctly portray the lobby state. This event is sent on connect, reconnect and the end of a game, e.g. when all rounds have been played out.

Name Description
playerId Your own player ID.
playerName Your own player name.
allowDrawing A boolean indicating whether you are currently drawing.
votekickEnabled Decides whether players can vote to kick others.
gameState One of: unstarted,gameOver or ongoing
ownerId ID of the player that owns the lobby (mostly the creator).
round The current round (progression) of the lobby.
rounds The round after which the game ends.
roundEndTime Amount of milliseconds before the current round runs out.
drawingTimeSetting The initial amount of seconds available for drawing each turn.
wordHints An array of word hints. If these are not available or empty, it indicates that no word has been chosen. The order needs to be respected.
players A list of all players in this lobby.
currentDrawing An array of fill and line instructions in order to redraw what has been drawn before joining. If this field is not available or empty, ignore it, since nothing has been drawn.

next-turn

This event is basically a smaller version of the ready event and only contains the fields roundEndTime, players and round.

In additional to the fields borrowed from the ready event, there's the previousWord field. If a next-turn event signals the start of the first turn, this field is set to null, otherwise it is set to either the previous word, or an empty string if no word was chosen.

Name Description
round The current round (progression) of the lobby.
players A list of all players in this lobby.
roundEndTime Amount of milliseconds before the current round runs out.
previousWord The word from the previous round.

The previousWord is always empty on the first turn. It can normally be used to display the user which word they couldn't guess previous turn. The field should generally be ignored on first turn.

game-over

The game-over event signals that all rounds have been played out. The event contains all data usually contained in the ready event, but the currentDrawing data is stripped. It's up to the client implementation whether the canvas is cleared or left with the drawing of the previous turn. On top of that, this event contains an additional field called previousWord. This field is either empty, in which case no word was chopsen last turn or contains the word from last turn.

name-change

If a players name changes, a name-change event gets broadcasted to all connected players.

Name Description
playerId Player which had a namechange occur.
playerName The players new name

update-players

This event gives you an updated list of the currently participating players. This also contains disconnected players. The objects are of type Player.

update-wordhint

This event is a personalized event and contains the word hints that you are allowed to see. It's an array of sorted word hints. The objects are of type Wordhint

message

This represents a message by a player that is not drawing and hasn't finished guessing. It contains the fields author, authorId and content, which are both strings.

Name Description
author Player name of the author.
authorId Player ID of the author.
content The content of the message.

non-guessing-player-message

This represents a message sent by a player that has either already guessed the word, or is the one who's been drawing it. Just like message, it contains an author field and a content field.

Name Description
author Player name of the author.
authorId Player ID of the author.
content The content of the message.

system-message

This represents a chat-message sent by the backend. The data field of the event contains the message content as a string.

line

See Line.

fill

See Fill.

drawing

This event is received after sending the request-drawing event. The return value is an array containing line and fill events that have to be applied to the canvas in order.

clear-drawing-board

This event signals that the player that is currently drawing has cleared the canvas.

your-turn

This event signals that it's now your turn to choose and draw a word. The data field of the event contains all the words you can choose as a string array. As soon as you received this event, you can send a [choose-word](#Choose word) event, after which you can start sending line and fill events.

close-guess

Sent if any player almost guesses the word correctly. The event data is the received message content.

correct-guess

Sent if any player guesses the word correctly. The event data is simply the players id.

kick-vote

This event is used to signal that one or more player wishes to kick another player from the lobby.

Name Description
playerId Player to potentially kick.
playerName The players name (convenience field)
voteCount How many players currently wish to kick the player.
requiredVoteCount How many votes are overall necessary to kick the player.

owner-change

This event occurs when the lobby owner (,initially the creator, ) changes. The owner has rights to change settings during the match.

Name Description
playerId Player ID of the new lobby owner.
playerName Player name of the new owner (convenience field)

drawer-kicked

This event signals that the drawer has been kicked, which implies that all points gained this round have been redacted. There is no data in this event.

lobby-settings-changed

This event signals that the lobby settings have been changed.

Name Description
maxPlayers Maximum amount of players allowed to join.
public Whether the lobby can be found and join via the public lobby list.
enableVotekick Whether people are allows to kick eachother via majority votes.
customWordsChance Chance in percent of how likely a proposed word is a custom word.
clientsPerIpLimit Defines how many players in the lobby are allowed to join from the same IP / Network.

Sendable events

start

The start event contains no data field and can only be sent by the lobby owner. Whether you are the owner or not can be found out by comparing your own ID to the owners ID. You receive both in the ready object.

clear-drawing-board, line, fill

The sendable drawing events are the same as the as the ones you receive. Meaning clear-drawing-board, line and fill.

message

This event can be used to either guess the current drawing or to send a chat message. The data field expects the guess or chat message as a string.

choose-word

This event will select the current word for the lobby. It can only be send by the lobbies drawer.

It expects the word to be selected by the index of the words presented in the your-turn event. The index starts at 0.

Example

socket.send(JSON.stringify({
  type: "choose-word",
  data: 0
}));

name-change

This event allows you to change your own display name. In the web client, this name will be persisted in your browser in form of a cookie, so that upon the next connection, the server automatically reuses your previous name. The data field has to be your desired name. Depending on your input, the server might manipulate your name. Names longer than 30 characters are truncated. By passing an empty string in the data field, you can reset your name to a random pet name.

Example

socket.send(JSON.stringify({
  type: "name-change",
  data: "Kevin"
}));
socket.send(JSON.stringify({
  type: "name-change",
  data: ""
}));

request-drawing

This event can be sent if for some reason the drawing data on the client has been lost. There should be no data field set. The drawing will be sent in form of the drawing event.

kick-vote

This allows you to cast your vote in favour of kicking a fellow player. The data field has to be filled with the target's player ID in playerId.

Example

socket.send(JSON.stringify({
  type: "vote-kick",
  data: "713efb69-95f2-4532-a093-ee37f100d0bf"
}));

keep-alive

This event is being used to keep the connection between client and server alive. Some WebSocket configurations would close connections over a fixed period of time, if no data was being sent.

Example

Here's a little example written in Go. It creates a new lobby and establishes a websocket connection.

package main

import (
	"encoding/json"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"

	"github.com/gorilla/websocket"
)

type LobbyData struct {
	LobbyID                string `json:"lobbyId"`
	DrawingBoardBaseWidth  int    `json:"drawingBoardBaseWidth"`
	DrawingBoardBaseHeight int    `json:"drawingBoardBaseHeight"`
}

func main() {
	//This example doesn't do error handling!

	//Create new lobby. This will return the ID of the newly created lobby.
	r, _ := http.PostForm("http://localhost:8080/v1/lobby", url.Values{
		"username":             {"Marcel"},
		"language":             {"english"},
		"max_players":          {"24"},
		"drawing_time":         {"120"},
		"rounds":               {"5"},
		"custom_words_chance":  {"50"},
		"enable_votekick":      {"true"},
		"clients_per_ip_limit": {"1"},
	})

	rawData, _ := ioutil.ReadAll(r.Body)
	lobbyData := &LobbyData{}
	json.Unmarshal(rawData, lobbyData)

	//The usersession gets stored in a cookie
	userSession := r.Cookies()[0].Value
	log.Println("Created lobby: " + lobbyData.LobbyID)
	log.Println("Usersession: " + userSession)

	//Connecting the socket by setting the Usersession and dialing.
	u := &url.URL{Scheme: "ws", Host: "localhost:8080", Path: "/v1/ws", RawQuery: "lobby_id=" + lobbyData.LobbyID}
	header := make(http.Header)
	header["Usersession"] = []string{userSession}
	socketConnection, _, _ := websocket.DefaultDialer.Dial(u.String(), header)
	defer socketConnection.Close()

	//Do stuff with connection ...
}