Inkposter

October 16, 2024 ยท View on GitHub

Inkposter

Inkposter is a browser-based multiplayer party game for 3-9 players based on skribbl.io, Gartic Phone and Fake Artist goes to New York made for course DH2643 @ KTH.

Table of Contents
  1. Description
  2. Setup
  3. Workflows
  4. Architecture
  5. The Developers

๐Ÿ”– Description

How to play

The game requires one host device where everything shared is displayed and 3-9 player devices where you see your personal prompts and drawings.

At the start of the game everyone receives a prompt that relates to a theme, except 1 player who is an Inkposter. No one knows what the theme is and no one knows who the imposter is. The Inkposter needs to observe the other drawings to blend in with the rest. The innocent players need to also pay attention to who might be late to draw without revealing too much information about the theme. Everyone draws on their personal devices and can see everyone else's drawings on the host device's screen.

When the timer runs out voting begins. The players vote what they suspect the theme is and who they think the Inkposter is. If the majority of players vote for the Inkposter then they're caught!

It is recommended to play the game using your phone and host the game on a big screen (e.g. TV, computer screen, livestream).

Demo

The layout is designed in Figma following: https://www.figma.com/design/V4OLczauxQRw13nV0fefb7/Inkposter-Design?node-id=2407-292&node-type=frame&t=S5xK8qXW5BX97cNm-0 (Also see: Architecture).

A demo is deployed on Heroku: https://inkposter-917d97c7bb64.herokuapp.com.

(Back to Top)

๐Ÿ› ๏ธ Setup

Prerequisites:

  • You will need env variables MongoDB_URI, OpenAPI_KEY, GITHUB_CLIENT_ID and GITHUB_CLIENT_SECRET set.

Built with

  • React v.18.3.1
  • Node.js
  • Express
  • MongoDB
  • Socket.io
  • OAuth 2.0 on GitHub
  • TailwindCSS
  • TypeScript
  • Jest + React Testing Library
  • Docker

Favicon created by smalllikeart - Flaticon and react-sketch-canvas package by Vinoth Pandian.

Getting started

To start the REST API server and the client application:

Docker-compose (recommended during development)

The docker image for Inkposter is deployed on: https://hub.docker.com/repository/docker/ziyi01/inkposter/.

  1. Build the image using docker-compose.yml from root:
$ docker-compose build
  1. Run the development environment/docker container on localhost:3000:
$ docker-compose up -d

Use docker-compose down -v to close the container process.

npm CLI

  1. Install npm dependencies with:
$ npm run dev-build
  1. Start the server on localhost:3000 with:
$ npm start

To run either the frontend or the backend application separately, enter the app or server folder:

  1. Install npm dependencies with:
$ npm install
  1. For the frontend application app run:
$ npm run build
  1. Run the application with:
$ npm start

(Back to Top)

๐Ÿงช Workflows

FileWorkflowDescriptionOn
node.js.ymlNode.js CIBuild and run testsPull and Push to main-branch
test.ymlCoverageRuns tests and create coverage reportPull main-branch
docker.ymlDocker CIDeploys the docker imagePush to main-branch
main.ymlDeployDeploys the application to HerokuPull request main-branch

Tests

Test coverage is reported when creating a pull-request into the main-branch. The tests uses Jest for unit testing and setup using babel.config.js and jest.config.js.

Unit tests are separated into the folders ./app/__tests__ for UI tests and ./server/__test__ for server tests:

FileTestType
App.test.tsxLogin page has login buttonUI test
App.test.tsxHomepage has join game buttonUI test
App.test.tsxProfile has log out buttonUI test
db.test.jsCreate and delete userDatabase test
db.test.jsRetrieve user statsDatabase test
db.test.jsUpdate username and retrieve userDatabase test
route.test.js/api/user/0 return test userREST API test
route.test.js/api/user/0/userStats return statsREST API test
route.test.js/api/user/10000 return 404REST API test
route.test.js/api/openai/username should return 200REST API test
route.test.js/api/openai/sessionPrompts should return 200REST API test

๐Ÿ“„ Architecture

Architecture and file structure in the project.

project-architecture

API endpoints

All API-endpoints are accessed at https://inkposter-917d97c7bb64.herokuapp.com//api/{route}.

MethodURLDescription
POST/userCreate and persist user with unique userID
GET/user/:userIDGet user information {name, avatar, previous themes}
GET/user/:userID/userStatsGet stats from user's previous games
PATCH/user/:userID/usernameUpdate username
PATCH/user/:userID/avatarUpdate avatar
PATCH/user/:userID/previousThemeAdd current theme to users previous themes
PATCH/user/:userID/sessionResultsIncrement relevant wins/losses and add drawing to user's gallery
DELETE/user/:userID/deleteDelete user
GET/openai/usernameReturn a unique username generated by OpenAI
GET/openai/sessionPromptsReturn json object with theme and prompts for both innocents and inkposter
GET/github/loginLogin route

Socket communication

Socket.io is used for real-time communication with the server and clients during the game. The clients are divided into host (the client whose display is used to show all drawings and triggers start of the game) and players (usually on a phone, where they draw and can see their role and prompt).

Below shows the events emitted and what each role does in the communication chain (not including error handlers):

socket-communication

Front-end

The front-end application uses a MVP-architecture. The code is divided into folders components (for repeated components and cripts), presenters and views. userModel.tsx is the model for the application and the app is mounted using App.tsx and index.tsx.

โ””โ”€โ”€ src/
    โ”œโ”€โ”€ components/
    โ”‚   โ”œโ”€โ”€ button.tsx
    โ”‚   โ”œโ”€โ”€ canvas.tsx
    โ”‚   โ”œโ”€โ”€ githubCallback.tsx
    โ”‚   โ”œโ”€โ”€ layout.tsx
    โ”‚   โ”œโ”€โ”€ navbar.tsx
    โ”‚   โ”œโ”€โ”€ playerInterface.ts
    โ”‚   โ”œโ”€โ”€ popup.tsx
    โ”‚   โ”œโ”€โ”€ route-component.tsx
    โ”‚   โ”œโ”€โ”€ server-requests.ts
    โ”‚   โ”œโ”€โ”€ socket-client.tsx
    โ”‚   โ””โ”€โ”€ timer.tsx
    โ”œโ”€โ”€ presenters/
    โ”‚   โ”œโ”€โ”€ homepage-presenter.tsx
    โ”‚   โ”œโ”€โ”€ host-end-presenter.tsx
    โ”‚   โ”œโ”€โ”€ host-game-presenter.tsx
    โ”‚   โ”œโ”€โ”€ host-voting-presenter.tsx
    โ”‚   โ”œโ”€โ”€ host-waiting-presenter.tsx
    โ”‚   โ”œโ”€โ”€ login-presenter.tsx
    โ”‚   โ”œโ”€โ”€ player-end-presenter.tsx
    โ”‚   โ”œโ”€โ”€ player-game-presenter.tsx
    โ”‚   โ”œโ”€โ”€ player-voting-presenter.tsx
    โ”‚   โ”œโ”€โ”€ player-waiting-presenter.tsx
    โ”‚   โ””โ”€โ”€ profile-presenter.tsx
    โ”œโ”€โ”€ views/
    โ”‚   โ”œโ”€โ”€ homepage.tsx
    โ”‚   โ”œโ”€โ”€ host-game.tsx
    โ”‚   โ”œโ”€โ”€ host-session-end.tsx
    โ”‚   โ”œโ”€โ”€ host-voting.tsx
    โ”‚   โ”œโ”€โ”€ host-waiting.tsx
    โ”‚   โ”œโ”€โ”€ loading.tsx
    โ”‚   โ”œโ”€โ”€ login-page.tsx
    โ”‚   โ”œโ”€โ”€ mock-login.tsx
    โ”‚   โ”œโ”€โ”€ player-game.tsx
    โ”‚   โ”œโ”€โ”€ player-session-end.tsx
    โ”‚   โ”œโ”€โ”€ player-voting.tsx
    โ”‚   โ”œโ”€โ”€ player-waiting.tsx
    โ”‚   โ””โ”€โ”€ profile.tsx
    โ”œโ”€โ”€ App.css
    โ”œโ”€โ”€ App.tsx
    โ”œโ”€โ”€ global.css
    โ”œโ”€โ”€ index.css
    โ”œโ”€โ”€ index.tsx
    โ””โ”€โ”€ userModel.tsx

Back-end

The back-end is quite short, routes/api.js contain the REST endpoints of the app. bin/www initialises the server and socket.io. db.js, openai.js and socket.js implement MongoDB, OpenAI and socket.io respectively.

โ””โ”€โ”€ server/
    โ”œโ”€โ”€ bin/
    โ”‚   โ””โ”€โ”€ www
    โ”œโ”€โ”€ routes/
    โ”‚   โ””โ”€โ”€ api.js
    โ”œโ”€โ”€ app.js
    โ”œโ”€โ”€ db.js
    โ”œโ”€โ”€ openai.js
    โ””โ”€โ”€ socket.js

The Team

(Back to Top)