{"id":48217694,"url":"https://github.com/cdilga/exquisite-corpse","last_synced_at":"2026-04-04T19:01:43.719Z","repository":{"id":331331706,"uuid":"1125786526","full_name":"cdilga/exquisite-corpse","owner":"cdilga","description":"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.","archived":false,"fork":false,"pushed_at":"2026-01-14T09:10:36.000Z","size":407,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-14T11:26:51.177Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cdilga.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-31T11:06:21.000Z","updated_at":"2026-01-14T07:45:19.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/cdilga/exquisite-corpse","commit_stats":null,"previous_names":["cdilga/exquisite-corpse"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/cdilga/exquisite-corpse","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cdilga%2Fexquisite-corpse","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cdilga%2Fexquisite-corpse/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cdilga%2Fexquisite-corpse/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cdilga%2Fexquisite-corpse/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cdilga","download_url":"https://codeload.github.com/cdilga/exquisite-corpse/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cdilga%2Fexquisite-corpse/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31409471,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-04T10:20:44.708Z","status":"ssl_error","status_checked_at":"2026-04-04T10:20:06.846Z","response_time":60,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-04-04T19:01:43.223Z","updated_at":"2026-04-04T19:01:43.701Z","avatar_url":"https://github.com/cdilga.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Exquisite Corpse 📝\n\nA 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!\n\n## 🌐 Live Deployment\n\n🚀 **Production**: [https://exquisite-corpse.dilger.dev](https://exquisite-corpse.dilger.dev)\n\n## 🎮 How to Play\n\n1. **Create a Room**: Click \"Create New Room\" to start a game and get a 4-character room code\n2. **Share the Code**: Give the room code to your friends (works on mobile and desktop!)\n3. **Write Your Sentence**: When it's your turn, you'll see only the previous player's sentence\n4. **Enjoy the Chaos**: After everyone has written, the complete story is revealed!\n\n## ✨ Features\n\n- **Real-time Multiplayer**: Uses WebSockets for instant updates\n- **Mobile-Friendly**: Responsive design works on all devices\n- **Privacy-First**: Players only see the previous sentence, not the full story\n- **Simple 4-Character Room Codes**: Easy to share and remember\n- **No Registration Required**: Just enter your name and play\n\n## 🏗️ Technical Architecture\n\n### Tech Stack\n\n- **Cloudflare Durable Objects**: Manages game room state and WebSocket connections\n- **Cloudflare Workers**: Serverless edge functions for routing\n- **Vanilla JavaScript**: No frameworks, just clean WebSocket API\n- **Tailwind CSS**: Utility-first CSS for responsive design\n\n### Architecture Overview\n\n```\n┌─────────────┐\n│   Browser   │──── WebSocket ───┐\n└─────────────┘                  │\n                                 ▼\n┌─────────────┐          ┌──────────────┐\n│   Browser   │──────────│   Durable    │\n└─────────────┘          │    Object    │\n                         │  (Game Room) │\n┌─────────────┐          └──────────────┘\n│   Browser   │──────────        │\n└─────────────┘                  │\n                                 ▼\n                         ┌──────────────┐\n                         │  Game State  │\n                         │   Storage    │\n                         └──────────────┘\n```\n\n### State Management\n\nEach game room is a Durable Object instance that maintains:\n- **Full Story Array**: Complete list of all sentences (server-side only)\n- **Player List**: Names, IDs, and turn order\n- **Current Turn Index**: Tracks whose turn it is\n- **Game Status**: Lobby, in-progress, or complete\n\n**Privacy Layer**: When sending turn notifications, the server only transmits the previous sentence to the next player, ensuring the \"exquisite corpse\" mechanic works correctly.\n\n### WebSocket Message Types\n\n**Client → Server:**\n- `join`: Player joins with their name\n- `start_game`: Host starts the game\n- `submit_sentence`: Player submits their sentence\n\n**Server → Client:**\n- `connected`: Connection established, playerId assigned\n- `player_joined`: Player list updated\n- `game_started`: Game begins\n- `your_turn`: It's your turn (includes previous sentence)\n- `waiting_for_turn`: Wait for another player\n- `game_complete`: Full story revealed\n- `error`: Error message\n\n## 🚀 Quick Start\n\n```bash\n# Clone the repository\ngit clone https://github.com/cdilga/exquisite-corpse.git\ncd exquisite-corpse\n\n# Install dependencies\nnpm install\n\n# Run locally\nnpm run dev\n\n# Open http://localhost:8787\n```\n\n## 📦 Deployment\n\nThis project automatically deploys to Cloudflare Workers when you push to the `main` branch.\n\n### Manual Deployment\n\n```bash\n# Deploy to production\nnpm run deploy\n\n# Deploy to staging\nnpm run deploy:staging\n\n# Deploy to beta\nnpm run deploy:beta\n```\n\n## 🧪 Testing\n\n### Unit Tests\n\n```bash\n# Run unit tests (with Cloudflare Workers runtime)\nnpm test\n\n# Watch mode\nnpm run test:watch\n\n# Interactive UI\nnpm run test:ui\n```\n\n### E2E Tests\n\n```bash\n# Run E2E tests against local server\nnpm run test:e2e\n\n# Interactive mode\nnpm run test:e2e:ui\n\n# Test deployed production site\nnpm run test:deployed\n```\n\n## 🛠️ Development\n\n### Project Structure\n\n```\nexquisite-corpse/\n├── src/\n│   ├── index.js           # Worker entry point \u0026 routing\n│   ├── GameRoom.js        # Durable Object for game state\n│   └── pages/\n│       └── home.js        # Frontend HTML/CSS/JS\n├── tests/\n│   ├── unit/\n│   │   └── game.test.js   # Unit tests\n│   └── e2e/\n│       └── game.spec.js   # E2E tests\n├── wrangler.toml          # Cloudflare configuration\n└── package.json\n```\n\n### Key Files\n\n- **`src/GameRoom.js`**: Durable Object class that handles WebSocket connections and game logic\n- **`src/index.js`**: Worker that routes requests to Durable Objects\n- **`src/pages/home.js`**: Complete frontend application (HTML/CSS/JS in one file)\n- **`wrangler.toml`**: Cloudflare Workers configuration\n\n### Environment Variables\n\nThe following secrets are configured in GitHub Actions:\n- `CLOUDFLARE_API_TOKEN`: For deploying to Cloudflare\n- `CLOUDFLARE_ACCOUNT_ID`: Your Cloudflare account ID\n\n## 🎯 Core Game Logic\n\n### Turn-Based Privacy Implementation\n\nThe magic happens in `GameRoom.js` in the `handleSubmitSentence` function:\n\n```javascript\n// Add sentence to full story (server-side only)\nstate.story.push({\n  playerId: playerId,\n  playerName: currentPlayer.name,\n  sentence: sentence.trim(),\n});\n\n// Send ONLY the previous sentence to next player\nconst previousSentence = state.story[state.story.length - 1].sentence;\n\nthis.sendToPlayer(nextPlayer.id, {\n  type: 'your_turn',\n  previousSentence: previousSentence,  // Only one sentence!\n  turnNumber: state.currentTurnIndex + 1,\n});\n```\n\nThis ensures each player only sees the previous sentence, maintaining the \"exquisite corpse\" mechanic.\n\n## 🐛 Troubleshooting\n\n### WebSocket Connection Issues\n\nIf WebSocket connections fail locally:\n1. Make sure you're using `wrangler dev` (not a simple HTTP server)\n2. Check that Durable Objects are properly configured in `wrangler.toml`\n\n### Room Code Not Working\n\nRoom codes are case-insensitive and stored using Durable Object names. Each unique code maps to a unique Durable Object instance.\n\n## 🤝 Contributing\n\nThis is a fun project! Feel free to add features like:\n- Adjustable number of rounds (multiple sentences per player)\n- Room passwords for private games\n- Story export/sharing functionality\n- Themed prompts or story starters\n- Vote for favorite sentence\n\n## 📄 License\n\nMIT\n\n## 🤖 Created with Claude\n\nThis project was automatically generated and implemented using [the-ultimate-bootstrap](https://github.com/cdilga/the-ultimate-bootstrap) and Claude AI.\n\nBuilt with ❤️ using Cloudflare Workers and Durable Objects.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcdilga%2Fexquisite-corpse","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcdilga%2Fexquisite-corpse","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcdilga%2Fexquisite-corpse/lists"}