Find the server repo here.
Find the client repo here.
You can play the game here with your friends or teammates.
What's the Story? is a hilarious multiplayer game that's best described as a cross between Mad Libs and Telephone where players create collaborative stories written one sentence at a time.
Each player can only see the latest sentence of the story!
- From the Home screen, players can choose to either:
- Start a new game where they will be given a randomly generated Room Code to share with other players.
- Join an existing game by entering a Room Code generated by someone else.
- Once all players have joined, the Start Game button allows players to, well... Start the Game!
- After submitting an initial sentence, each story is passed to the next player.
- Play continues with each player adding a sentence to the story based on only the preceding sentence without further context.
- The game ends when each story reaches a predetermined length (measured in number of sentences).
- Players can then select and read all the stories created during the game.
What's the Story? is a collaborative game emphasizing creativity and originality. As such, there is no "winner", per se. Players win together to the extent that they use their creativity to come up with interesting stories.
The tech stack for this project includes:
Node.js
serverExpress
for route handlingMongoDB
/Mongoose
for the persistence layerSocket.IO
for real-time multiplayer communication with game clientsReact
frontend withRedux
for state managementChance.js
for generating random names and Room CodesMocha/Chai
for backend testingEnzyme/Jest
for frontend testing
Purpose: Create a new game session.
Example: POST https://example.com/
Request body:
{
"playerName": "Susan"
}
Response body:
{
"started": false,
"completed": false,
"roomCode": "ABCDEF",
"players": [
{
"readyState": false,
"inSession": true,
"name": "Susan",
"createdAt": "2018-11-02T22:28:55.386Z",
"updatedAt": "2018-11-02T22:28:55.386Z",
"id": "aaaaaaaaaaa1"
}
],
"stories": [],
"id": "bbbbbbbbbbbb"
}
All other game interactions are performed over the socket.io connection as Redux style actions where the action.type
of actions sent to the server begin with SERVER_
.
The socket connection requires setting up custom middleware using socket.io-client from npm.
Purpose: Add a player to a channel corresponding to an existing game session.
{
type: 'SERVER_JOIN_ROOM',
roomCode: 'ABCDEF'
}
Purpose: Add a player to an existing game.
{
type: 'SERVER_JOIN_GAME',
roomCode: 'ABCDEF',
playerName: 'Mabelle'
}
Purpose: Start an existing game.
{
type: 'SERVER_START_GAME',
roomCode: 'ABCDEF'
}
Purpose: Add a player's sentence to the proper story inside the gameSession.
{
type: 'SERVER_ADD_SENTENCE',
roomCode: 'ABCDEF',
text: 'Sentence to add goes here.',
author: 'Mabelle',
storyId: 'cccccccccccc'
}
Purpose: Send full gameSession data to newly joined players.
{
type: 'JOIN_GAME_SUCCESS',
id: 'bbbbbbbbbbbb',
roomCode: 'ABCDEF',
players: [
{
readyState: false,
inSession: true,
name: 'Susan',
createdAt: 2018-11-02T22:28:55.386Z,
updatedAt: 2018-11-02T22:28:55.386Z,
id: 'aaaaaaaaaaa1'
},
{
readyState: false,
inSession: true,
name: 'Mabelle',
createdAt: 2018-11-03T19:24:19.799Z,
updatedAt: 2018-11-03T19:24:19.799Z,
id: 'aaaaaaaaaaa2'
},
],
started: false,
completed: false,
stories: []
}
Purpose: Send only the updated players list to existing players when a new player joins the game.
{
type: 'UPDATE_PLAYERS',
players: [
{
readyState: false,
inSession: true,
name: 'Susan',
createdAt: 2018-11-02T22:28:55.386Z,
updatedAt: 2018-11-02T22:28:55.386Z,
id: 'aaaaaaaaaaa1'
},
{
readyState: false,
inSession: true,
name: 'Mabelle',
createdAt: 2018-11-03T19:24:19.799Z,
updatedAt: 2018-11-03T19:24:19.799Z,
id: 'aaaaaaaaaaa2'
},
]
}
Purpose: Let a player know if an attempt to join a room was unsuccessful.
{
type: 'JOIN_ROOM_ERROR',
error: 'Unable to join room'
}
Purpose: Let a player know if an attempt to join a game was unsuccessful.
{
type: 'JOIN_GAME_ERROR',
error: 'Unable to join game. Check your code and try again.'
}
Purpose: Let all players in the channel know that the game has started.
{
type: 'START_GAME_SUCCESS',
gameSession: {
started: true,
completed: false,
roomCode: 'ABCDEF',
players: [
{
readyState: false,
inSession: true,
name: 'Susan',
createdAt: 2018-11-02T22:28:55.386Z,
updatedAt: 2018-11-03T20:17:23.713Z,
passesTo: 'Mabelle',
id: 'aaaaaaaaaaa1'
},
{
readyState: false,
inSession: true,
name: 'Mabelle',
createdAt: 2018-11-03T19:24:19.799Z,
updatedAt: 2018-11-03T20:17:23.713Z,
passesTo: 'Susan',
id: 'aaaaaaaaaaa2'
}
],
stories: [
{
completed: false,
completionLength: 10,
creator: 'Susan',
sentences: [],
id: 'ccccccccccc1'
},
{
completed: false,
completionLength: 10,
creator: 'Mabelle',
sentences: [],
id: 'ccccccccccc2'
}
],
id: 'bbbbbbbbbbbb'
}
}
Purpose: Let a player know if an attempt to start a game was unsuccessful.
{
type: 'START_GAME_ERROR',
error: 'Unable to start game.'
}
Purpose: Send an initial prompt to each player to help them start their story.
{
type: 'ADD_INITIAL_PROMPT',
receiver: 'Susan',
storyId: 'ccccccccccc1',
prompt: 'Add a sentence to start your story. The only limit is your imagination!'
}
Purpose: Let all players know that a sentence was successfully added to a story, so they can update their local data with the new sentence.
{
type: 'ADD_SENTENCE_SUCCESS',
text: 'Sample sentence added by Susan',
author: 'Susan',
id: 'ddddddddddd1',
storyId: 'ccccccccccc1'
}
Purpose: Let a player know that their attempt to add a sentence was unsuccessful.
{
type: 'ADD_SENTENCE_ERROR',
error: 'Unable to add sentence. Weird.'
}
Purpose: Pass a newly added sentence as a prompt to the next player in the rotation for that story.
{
type: 'ADD_UPCOMING_PROMPT',
storyId: 'ccccccccccc1',
prompt: 'Sample sentence added by Susan',
receiver: 'Mabelle'
}
Purpose: Let all players know that the game has been completed.
{
type: 'FINISH_GAME',
completed: true
}