A web 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.
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!
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: Code architecture).
A demo is deployed on Heroku: https://inkposter-917d97c7bb64.herokuapp.com.
Prerequisites:
.env
file in the root folder with environment variables: MONGODB_URI
, OPENAI_API_KEY
and NODE_ENV
.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/.
docker-compose.yml
from root:
$ docker-compose build
localhost:3000
:
$ docker-compose up -d
Use docker-compose down -v
to close the container process.
npm CLI
$ npm run dev-build
localhost:3000
with:
$ npm start
To run either the frontend or the backend application separately, enter the app
or server
folder:
$ npm install
app
run:
$ npm run build
$ npm start
Method | URL | Description |
---|---|---|
POST |
/user |
Create user with unique userID. If user exists, return a confirmation. |
GET |
/user/:userID |
Get information about user userID from database |
GET |
/user/:userID/userStats |
Get stats from user's previous games from database |
PATCH |
/user/:userID/username |
Update username of user userID in database |
PATCH |
/user/:userID/avatar |
Upload avatar to user userID in database |
PATCH |
/user/:userID/previousTheme |
Add current game theme to user userID 's previous themes |
PATCH |
/user/:userID/sessionResults |
Add results of the game to user userID |
DELETE |
/user/:userID |
Delete user of id userID |
GET |
/openai/username |
Return a unique username generated by OpenAI |
PATCH |
/openai/sessionParams |
Generates theme and prompts for the game |
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:
File | Workflow | Description | On |
---|---|---|---|
node.js.yml |
Node.js CI |
Build and run tests | Pull and Push to main -branch |
test.yml |
Coverage |
Runs tests and create coverage report | Pull main -branch |
docker.yml |
Docker CI |
Deploys the docker image | Push to main -branch |
main.yml |
Deploy |
Deploys the application to Heroku | Pull request main -branch |
Test coverage is reported when creating a pull-request into the main
-branch. Unit tests are separated into the folders ./app/__tests__
for UI tests and ./server/__test__
for server tests:
File | Test | Type |
---|---|---|
App.test.tsx |
App renders login page properly |
UI test |
App.test.tsx |
Login button fires off callback |
UI test |
App.test.tsx |
Redirect to /login when app rendered |
UI test |
db.test.js |
Create and delete user |
Database test |
db.test.js |
Retrieve user stats |
Database test |
db.test.js |
Update username and retrieve user |
Database test |
route.test.js |
/api/user/0 return test user |
REST API test |
route.test.js |
/api/user/0/userStats return stats |
REST API test |
route.test.js |
/api/user/10000 return 404 |
REST API test |
route.test.js |
/api/openai/username should return 200 |
REST API test |
route.test.js |
/api/openai/sessionPrompts should return 200 |
REST API test |
File structure in the project that is used to build the application.
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
.
└── app/src/
├── components/
│ ├── githubCallback.tsx
│ ├── layout.tsx
│ ├── popup.js
│ ├── timer.tsx
│ ├── socket-client.tsx
│ └── canvas.tsx
├── presenters/
│ ├── homepage-presenter.tsx
│ ├── host-end-presenter.tsx
│ ├── host-game-presenter.tsx
│ ├── host-voting-presenter.tsx
│ ├── host-waiting-presenter.tsx
│ ├── player-end-presenter.tsx
│ ├── player-game-presenter.tsx
│ ├── player-voting-presenter.tsx
│ └── player-waiting-presenter.tsx
├── views/
│ ├── homepage.tsx
│ ├── host-game.tsx
│ ├── host-session-end.tsx
│ ├── host-voting.tsx
│ ├── host-waiting.tsx
│ ├── loading.tsx
│ ├── login-page.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
├── server-requests.tsx
├── userModel.tsx
└── logo.svg
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