Dead or Not

A morbid game built using Next.js, Supabase, and the OpenAI API.

January 10, 2024


TL;DR

Check out my project at dead-or-not.com. It's a fun game I created to explore Next.js, Supabase, and the OpenAI API. The idea, suggested by a friend, is to guess whether a celebrity is alive or not.

Dead or Not homepage

Motivation

I've been using Next.js and MongoDB for over five years. Recently, I tried Postgres with Supabase because it seemed easy to use. My friend came up with the idea for a guessing game called 'Dead or Not.' At first, it seemed a bit dark, but we thought it could work like Wordle, with a new game every day for everyone. This project was challenging and helped me learn new skills. I chose to use several technologies: the Next.js app router, edge functions, Supabase for authentication, Google sign-in, and the OpenAI API with GPT-4.

Populating the Database With People

The people data is gathered from the WikiData Query Service. I generated SPARQL queries with the help of GPT-4. SPARQL, a powerful query language, allows for highly customized queries. After some trial and error, I managed to download a JSON file with many missing fields. I cleaned up the file using a Node script. This process involved extracting the person's name, profession, birth date, death date, image, and bio (if available). I imported this data into Supabase and stored it in a People table.

Tables

The game uses four Postgres tables: People, Games, Guesses, and Game Summary. The following diagram shows how the tables are linked together.

Dead or Not Supabase schema visualizer

People

This table contains all the celebrities used in the game. It stores their name, profession, birth date, death date, image, and bio.

Games

This table represents a game, with each row containing a date and foreign keys referencing the three celebrities in the People table. Each day, three random celebrities are chosen for the game.

Guesses

This table represents a user's guess for a game. It includes foreign keys referencing the Games table and the User Auth table.

Game Summary

This table represents the final game state. It is used to provide a shareable link with the id of the game as a URL search query.

Front End

The front end is a Next.js app using the app router. A middleware.ts file and api/callback/route.ts serverless function handle Supabase auth. The middleware file ensures the user session is always available, and the route file is the callback endpoint for Google OAuth. Tailwind CSS and shadcn/ui are used for styling. The app/layout.tsx file is optimized for SEO and as a PWA. The app is optimized to use React Server Components where possible. This helps achieve a Lighthouse score close to 100 across the board. The 95 Best Practice score lost 5 points due to Google Analytics.

Dead or Not Lighthouse score

Edge Functions

There are five edge functions used in the game.

/can-guess

Checks if the user can guess or not. If they have already guessed once today, they cannot guess again until tomorrow. This is based on the user's local timezone and resets at 12 AM midnight.

/delete-user

Deletes a user from the auth table and cascades to delete any related data in the other tables.

/insert-summary

Inserts a row in the Game Summary table when a user completes a game. The id of the game is included in the search query of the 'Copy link' URL. When another user loads the link, the game summary is loaded from the Game Summary table.

/refresh-bio

Used in the admin section to refresh a person's bio. GPT-4 is used to generate a new bio using the OpenAI API. A link to the user's Wikipedia page is also returned if it exists. The prompts include a system prompt and specific instructions so the generated bio is condensed to fit in the popover on the game summary page.

/update-person-count

Updates the correct or incorrect guess count of a person. This isn't being used currently, but the idea is to eventually show the 'Most correctly guessed' and 'Most incorrectly guessed' celebrity stats in the UI when enough data has been gathered.

Game Summary

This picture shows the Game Summary page, where the 'Learn More' button displays the GPT-4 generated bio. The 'Copy link' button includes the game id in a URL search query.

Dead or Not summary page

Cron Jobs

There are two cron jobs configured in the root vercel.json file.

/api/cron-bios

Runs daily to ensure the next few days' celebrities have a GPT-4 generated bio. It checks if the bio is null and, if so, generates a new bio using the OpenAI API.

/api/cron-deathday

Runs daily to ensure the celebrities' death dates are accurate. It calls a Wikidata endpoint to verify the death date and updates relevant entries in the People table. This requires iterating over many people. The Wikidata endpoint only accepts 50 requests per second, so requests are throttled to 40 requests per second.

Conclusion

'Dead or Not' has been a practical project for expanding my skills in Next.js, Supabase, and the OpenAI API. Working on this game allowed me to delve deeper into database management with Supabase and understand the practical applications of AI with OpenAI. I'm excited to see how the game evolves and how I can apply the skills I've learned to future projects.