Skip to content

cdilga/exquisite-corpse

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

57 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

Exquisite Corpse ๐Ÿ“

A collaborative writing game where players take turns adding sentences to a story while seeing only the previous line. The result is a hilariously disjointed masterpiece revealed at the end!

๐ŸŒ Live Deployment

๐Ÿš€ Production: https://exquisite-corpse.dilger.dev

๐ŸŽฎ How to Play

  1. Create a Room: Click "Create New Room" to start a game and get a 4-character room code
  2. Share the Code: Give the room code to your friends (works on mobile and desktop!)
  3. Write Your Sentence: When it's your turn, you'll see only the previous player's sentence
  4. Enjoy the Chaos: After everyone has written, the complete story is revealed!

โœจ Features

  • Real-time Multiplayer: Uses WebSockets for instant updates
  • Mobile-Friendly: Responsive design works on all devices
  • Privacy-First: Players only see the previous sentence, not the full story
  • Simple 4-Character Room Codes: Easy to share and remember
  • No Registration Required: Just enter your name and play

๐Ÿ—๏ธ Technical Architecture

Tech Stack

  • Cloudflare Durable Objects: Manages game room state and WebSocket connections
  • Cloudflare Workers: Serverless edge functions for routing
  • Vanilla JavaScript: No frameworks, just clean WebSocket API
  • Tailwind CSS: Utility-first CSS for responsive design

Architecture Overview

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚   Browser   โ”‚โ”€โ”€โ”€โ”€ WebSocket โ”€โ”€โ”€โ”
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                  โ”‚
                                 โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”          โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚   Browser   โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚   Durable    โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜          โ”‚    Object    โ”‚
                         โ”‚  (Game Room) โ”‚
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”          โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ”‚   Browser   โ”‚โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€        โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜                  โ”‚
                                 โ–ผ
                         โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                         โ”‚  Game State  โ”‚
                         โ”‚   Storage    โ”‚
                         โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

State Management

Each game room is a Durable Object instance that maintains:

  • Full Story Array: Complete list of all sentences (server-side only)
  • Player List: Names, IDs, and turn order
  • Current Turn Index: Tracks whose turn it is
  • Game Status: Lobby, in-progress, or complete

Privacy Layer: When sending turn notifications, the server only transmits the previous sentence to the next player, ensuring the "exquisite corpse" mechanic works correctly.

WebSocket Message Types

Client โ†’ Server:

  • join: Player joins with their name
  • start_game: Host starts the game
  • submit_sentence: Player submits their sentence

Server โ†’ Client:

  • connected: Connection established, playerId assigned
  • player_joined: Player list updated
  • game_started: Game begins
  • your_turn: It's your turn (includes previous sentence)
  • waiting_for_turn: Wait for another player
  • game_complete: Full story revealed
  • error: Error message

๐Ÿš€ Quick Start

# Clone the repository
git clone https://github.com/cdilga/exquisite-corpse.git
cd exquisite-corpse

# Install dependencies
npm install

# Run locally
npm run dev

# Open http://localhost:8787

๐Ÿ“ฆ Deployment

This project automatically deploys to Cloudflare Workers when you push to the main branch.

Manual Deployment

# Deploy to production
npm run deploy

# Deploy to staging
npm run deploy:staging

# Deploy to beta
npm run deploy:beta

๐Ÿงช Testing

Unit Tests

# Run unit tests (with Cloudflare Workers runtime)
npm test

# Watch mode
npm run test:watch

# Interactive UI
npm run test:ui

E2E Tests

# Run E2E tests against local server
npm run test:e2e

# Interactive mode
npm run test:e2e:ui

# Test deployed production site
npm run test:deployed

๐Ÿ› ๏ธ Development

Project Structure

exquisite-corpse/
โ”œโ”€โ”€ src/
โ”‚   โ”œโ”€โ”€ index.js           # Worker entry point & routing
โ”‚   โ”œโ”€โ”€ GameRoom.js        # Durable Object for game state
โ”‚   โ””โ”€โ”€ pages/
โ”‚       โ””โ”€โ”€ home.js        # Frontend HTML/CSS/JS
โ”œโ”€โ”€ tests/
โ”‚   โ”œโ”€โ”€ unit/
โ”‚   โ”‚   โ””โ”€โ”€ game.test.js   # Unit tests
โ”‚   โ””โ”€โ”€ e2e/
โ”‚       โ””โ”€โ”€ game.spec.js   # E2E tests
โ”œโ”€โ”€ wrangler.toml          # Cloudflare configuration
โ””โ”€โ”€ package.json

Key Files

  • src/GameRoom.js: Durable Object class that handles WebSocket connections and game logic
  • src/index.js: Worker that routes requests to Durable Objects
  • src/pages/home.js: Complete frontend application (HTML/CSS/JS in one file)
  • wrangler.toml: Cloudflare Workers configuration

Environment Variables

The following secrets are configured in GitHub Actions:

  • CLOUDFLARE_API_TOKEN: For deploying to Cloudflare
  • CLOUDFLARE_ACCOUNT_ID: Your Cloudflare account ID

๐ŸŽฏ Core Game Logic

Turn-Based Privacy Implementation

The magic happens in GameRoom.js in the handleSubmitSentence function:

// Add sentence to full story (server-side only)
state.story.push({
  playerId: playerId,
  playerName: currentPlayer.name,
  sentence: sentence.trim(),
});

// Send ONLY the previous sentence to next player
const previousSentence = state.story[state.story.length - 1].sentence;

this.sendToPlayer(nextPlayer.id, {
  type: 'your_turn',
  previousSentence: previousSentence,  // Only one sentence!
  turnNumber: state.currentTurnIndex + 1,
});

This ensures each player only sees the previous sentence, maintaining the "exquisite corpse" mechanic.

๐Ÿ› Troubleshooting

WebSocket Connection Issues

If WebSocket connections fail locally:

  1. Make sure you're using wrangler dev (not a simple HTTP server)
  2. Check that Durable Objects are properly configured in wrangler.toml

Room Code Not Working

Room codes are case-insensitive and stored using Durable Object names. Each unique code maps to a unique Durable Object instance.

๐Ÿค Contributing

This is a fun project! Feel free to add features like:

  • Adjustable number of rounds (multiple sentences per player)
  • Room passwords for private games
  • Story export/sharing functionality
  • Themed prompts or story starters
  • Vote for favorite sentence

๐Ÿ“„ License

MIT

๐Ÿค– Created with Claude

This project was automatically generated and implemented using the-ultimate-bootstrap and Claude AI.

Built with โค๏ธ using Cloudflare Workers and Durable Objects.

About

In this collaborative writing game, players take turns adding a sentence to a story while seeing only the previous line. The result is a disjointed, hilarious, and nonsensical masterpiece revealed at the end.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors