We Meme

NodeJS • Socket.io • Function & Process Modeling Database • Mockups & Wireframes • Testing • Google Analytics

Memes are one of the biggest online trends within the last few years. People laugh, share and post them almost everywhere. From corporate chats to gaming rooms to giant meme pages on social media – they are present almost all over the internet.

Inspired by the physical card game What do You Meme?, Julia and I’ve created We Meme. Multiple players join a private game in the multiplayer browser game or, alternatively, can play together with other players in the public room. At We Meme funny pictures or GIFs (animated memes without text) are shown to the participating players. Each player has 60 seconds to think of a funny caption for the picture. After the time runs up (or after all players have submitted a caption), all players' captions are displayed. Each player can vote for the funniest, most creative and hilarious caption of all players. After all players have voted, the newly created meme with its winning caption is displayed to all players for ten seconds. After ten rounds, i.e. ten newly created memes, the winner is announced: The player with the most votes wins the game.

In the first step, we considered how the game should roughly look like and what the basic functions are.

Desktop wireframe game room
Wireframe Game Room (Desktop)
Mobile wireframe game room showing a placeholder image and input field
Wireframe Game Room with Focus on Meme and Input (Mobile)

Mobile wireframe game room with open chat window
Wireframe Game Room with Chat open (Mobile)

The image (meme) to be described should take up most of the space. Right below is an input field where players can enter and submit their caption. To allow players to interact during the game (if they are not talking on the phone or via Zoom anyway), a chat is part of the application. Last but not least, we need a scoreboard to indicate the current round and the number of points of all players. All those information must be available not only on the desktop version, but also on mobile devices with much smaller screens. We decided to focus on the meme itself on the mobile version as well. The scores can be viewed in a horizontal slider at the top of the page. The messages in the chat can be entered at the bottom of the screen and can be hidden during the game. The responsive layout is well achievable via CSS grids.

Quickly it became very quickly clear to us that the web page (game room) should in no case be reloaded when the caption was submitted or a new round including new memes started. For the asynchronous transfer we decided to use NodeJS in combination with Socket.io.

Back in the days when we started the project, I didn’t really know much about NodeJS and what exactly web sockets are. But I made the most of the cold gray winter days and moonlighted to get new skills!

In a first shot, we have brainstormed to visualize the most important features and functions of the game flow.

Drawing board showing the process of all NodeJS functions
First Draft of the Functions Flow and Diagram

We roughly split the NodeJS functions and worked in parallel via Git on the server-side "brain" (NodeJS) and the frontend (game room).

We have tested individual functions in separate files, but combined them into one major file to work together. In retrospect, this made the project and the accruing bug fixes very confusing and complex.

The database structure was a bit of a challenge for us at the beginning. After some considerations we decided on the following tables.

Database structure for users and captions table
Database Structure

users.room contains the game room, the player is participating in. The game room is created as new file once a user clicks “start a new game” on the homepage. The room and the associated URL is a timestamp (e.g. https://we-meme.io/1619953485983) which ensures unique names. users.state can be either thinking, while the user has up to 60 seconds time to think of a funny caption, submitted after the user submitted the captions or voted after the user has voted for the funniest caption in the particular round. Based on this information (e.g. all players have submitted a caption) the next step is initiated by the server: e.g. showing the popup containing all captions. users.score contains the score (number of total votes) of the particular player. users.round is a relic from early thoughts in case users were joining a running game.

captions.caption holds all user inputs for the displayed image. If users vote for a users caption, the integer (number of votes) in captions.votes is increased within the particular dataset. captions.round counts the number of shown images to end the game session after ten rounds.

The most important part had to be decided yet: where and how can we host the game? I've decided to use Hetzner Cloud Hosting. There are a huge number of blog posts and YouTube videos available, which explain how to set up Ubuntu on a cloud server, no matter which provider owns the server physically. After some initial wrangling the external domain connection and the installation of the SSL certificate was working. Since NodeJS terminates individual processes after a certain time with a timeout, I have configured PM2, a Production Process Manager for Node.JS, to keep the index file, which is the brain of the browser game, permanently running and online.

To get an overview and track the gameplay, we have integrated Google Analytics. Most of the players, who have clicked on the shared link to the game room, visit only one page (the game room), but remain online for a decent time. Therefore the standard Google Analytics data is only of limited use. That's why I’ve added additional custom events via Google Tag Manager. It was much easier and more accurate not to select and track events in the frontend using GTM, but to integrate JavaScript events directly into the client-side HTML file (game room).

   event: 'imagecaptionEnteredAutomically',

Example: It is tracked how often the default placeholder was submitted as caption instead of funny user generated captions. Originally, users had only 30 seconds to enter a caption. When we've increased the time span to 60 seconds, we had more custom captions on a percentage basis.

Besides Google Analytics we’ve integrated Hotjar to track user behaviour visually. Hotjar offers screen tracking and a feedback form, which can be added easily to websites. The qualitative feedback we received from users was particularly helpful.

A sample of feedback:

  • I don’t understand what to do. Can you add an introduction?
  • The game stops if a player does not enter a caption or closes the browser tab (all players must enter a caption)
  • Some cheaters vote only for their own capture. Can you disable own captions?

Inspired by the feedback, we are using the chat to show a quick introduction: A chatbot (“Meme Bot”) posts the gameplay to the chat, which makes the rules clear for everyone.

Chat including game instructions

To avoid interrupting the game by not entering the captions, I added a timer (described above).

Loading bar showing time left to submit caption
Loading bar indicating time left to submit caption

As long as only two players are online, both players' captions remain visible for voting. If three or more players are online in the game room, their own captions are hidden so that only other players' captions can be voted for.

Up to now, We Meme is a hobby project. In order to cover the running server costs, we have placed affiliate links referring to the original card game on different pages. Nevertheless, of course, we plan to promote the game further. If you have any ideas for marketing and expanding the reach of the game, I'd love to hear from you in a comment or via email.

Screenshot from current Version of We-Meme.io Game Room
Current version of We-Meme.io

The thoughts, ideas and issues we fixed while creating the game go far beyond this article. If you have any questions, kudos, feedback, or comments, I'd love to hear from you!

When you realize that we-meme.io has gone live – GIF

Happy playing!

Leave a Reply

Your email address will not be published. Required fields are marked *