Broth & Bullets - Alpha Launch
License: Apache 2.0 React Vite SpacetimeDB
What started as an open source project for a generic 2D survival game is now a full-fledged game called Broth & Bullets. You can read more about it at https://www.brothandbullets.com/blog.
I've committed to open sourcing the entire project and providing the best documentation possible to help you get up and running, fork the project, create your own games, or even contribute back to Broth & Bullets itself. This repository has evolved into an exhaustive, feature-rich project with almost every pattern you can think of—constantly in development and running on SpacetimeDB 2.0. A stripped-down true "starter kit" for 2D MMORPGs (all the main features without the bloat) is planned for release soon.
💬 Want to chat? Join the discussion on Discord
- ⚡ Quick Local Setup
- 🐳 Docker Compose (Alternative)
- 🗺️ Roadmap
- 🛠️ Tech Stack
- 🔐 Authentication Setup
- 📜 Cursor Rules & Code Maintainability
- ⚙️ Client Configuration
- 🤖 SOVA AI Assistant Configuration
- 🌍 World Configuration
- 📁 Project Structure
- 🔧 Troubleshooting Local Setup
- 🔄 Development Workflow
- 🚀 Deployment Scripts
- 🎨 Art Generation Prompts
- 🤝 Contributing
- 📜 License
For experienced users familiar with Node.js, Rust, and SpacetimeDB. See detailed sections below for troubleshooting or authentication specifics.
This project uses:
- SpacetimeDB CLI:
2.0.x - SpacetimeDB Rust Crate:
2.0 - SpacetimeDB TypeScript SDK:
spacetimedb@2.0.1(npm package)
0. Install SpacetimeDB CLI:
Follow the instructions for your OS: https://spacetimedb.com/install
(e.g., curl -sSf https://install.spacetimedb.com | sh on macOS/Linux)
1. Clone & Install Dependencies:
git clone https://github.com/SeloSlav/vibe-coding-starter-pack-2d-multiplayer-survival.git
cd vibe-coding-starter-pack-2d-multiplayer-survival
npm install2. Generate Auth Keys:
# Ensure OpenSSL is installed (https://www.openssl.org/source/)
mkdir keys
openssl genpkey -algorithm RSA -out keys/private.pem -pkeyopt rsa_keygen_bits:2048
openssl rsa -pubout -in keys/private.pem -out keys/public.pem3. Start Core Services (3 Terminals):
Terminal 1 - Auth Server:
cd auth-server-openauth/
npm install
npm run dev
# Auth Server running on http://localhost:4001Terminal 2 - SpacetimeDB Server:
cd server/
spacetime start
# SpacetimeDB Server running on http://localhost:3000Terminal 3 - Client:
npm run dev
# Client running on http://localhost:3008 (or similar)4. Deploy Database (First Time Setup):
# In server/ directory - choose one:
./deploy-local-clean.ps1 # Windows - Fresh database
./deploy-local.ps1 # Windows - Update existing database
# Or manually:
spacetime publish --no-config -p . broth-bullets-local -y
spacetime generate --no-config --include-private -p . -l typescript -o ../client/src/generated -y🎉 That's it! Your multiplayer survival game is up and running! 🎮✨
For rapid local setup without managing multiple terminals. Does not affect Railway deployments (Railway uses per-service configs).
Prerequisites: Docker, Docker Compose, SpacetimeDB CLI (for database deploy step)
# 1. Clone & create .env
git clone https://github.com/SeloSlav/vibe-coding-starter-pack-2d-multiplayer-survival.git
cd vibe-coding-starter-pack-2d-multiplayer-survival
copy .env.example .env # Windows (or cp .env.example .env on macOS/Linux)
# Add API keys to .env for SOVA (OPENAI_API_KEY, GROK_API_KEY, etc.)
# 2. Start all services
docker compose up --build
# 3. Deploy database (run in a new terminal, one-time or after server changes)
cd server
spacetime publish --no-config -p . broth-bullets-local -y
spacetime generate --no-config --include-private -p . -l typescript -o ../client/src/generated -y
# 4. Open http://localhost:3008Services: SpacetimeDB (3000), Auth Server (4001), Client (3008), Kokoro TTS (8001).
Create .env from .env.example and add API keys before first run:
copy .env.example .env # Windows
# cp .env.example .env # macOS/LinuxOnly needed if you want to use the in-game AI assistant (SOVA).
1) Configure API keys in root .env:
# Create .env file in project root first
# OpenAI API key is REQUIRED for Whisper (speech-to-text)
echo "OPENAI_API_KEY=sk-your-openai-api-key-here" > .env
# Add at least one AI provider key for SOVA responses:
echo "GROK_API_KEY=xai-your-grok-api-key-here" >> .env
# OR echo "GEMINI_API_KEY=your-gemini-api-key-here" >> .env
# Optional provider selection (defaults to grok)
echo "VITE_AI_PROVIDER=grok" >> .env2) Terminal 4 - Kokoro TTS Backend:
cd tts-backend
python -m venv venv
.\venv\Scripts\Activate.ps1 # Windows PowerShell
pip install -r requirements.txt
python app.py
# Kokoro TTS running on http://localhost:80013) Client environment variables (for AI assistant):
# Add to .env file in project root
echo "VITE_KOKORO_BASE_URL=http://localhost:8001" >> .envSee the SOVA AI Assistant Configuration section below for details.
Open a new terminal and run npm run dev again. The second client will open on a different port. Open this URL in a separate browser tab to test multiplayer functionality!
Quick Updates: Use deployment scripts in server/ directory:
cd server/
./deploy-local.ps1 # Update local database
./deploy-local-clean.ps1 # Fresh local database (wipes data)
./deploy-production.ps1 # Update production database
./deploy-production-clean.ps1 # Fresh production database (wipes data)Manual Deployment:
cd server/
spacetime publish --no-config -p . broth-bullets-local -y # Local
# OR
spacetime publish --server maincloud -p . broth-bullets # Production
spacetime generate --no-config --include-private -p . -l typescript -o ../client/src/generated -yCompleted (✅):
- 🌐 Real-time Multiplayer: Basic player movement synchronization
- 🌓 Environment Systems: Day/night cycle, Full moon nights, Rain system that affects gameplay and atmosphere
- 🪓 Survival Mechanics: Basic resource harvesting
- 🌱 Resource Respawning: Trees, Stones, Plants
- ❤️ Survival Systems: Health, Hunger, Thirst, Warmth, Death/Respawn
- 🗺️ World Discovery: Minimap
- 🎮 Hotbar: Item selection, weapon cooldown indicators
- 🎒 Inventory Management: Moving, swapping, stacking, stack splitting
- ⚔️ Armor: Defense bonuses, warmth protection
- 🔥 Placeables: Campfire (Multi-slot placement & interaction)
- 🛠️ Crafting System: Item recipes
- 📦 Storage Containers (Chests)
- 💰 Looting Mechanics (Containers)
- 🔐 Authentication/Account System
- 🍳 Cooking System: Food preparation using campfire with raw, cooked and burnt states
- ⚔️ Combat System: Multiple weapon types (melee, thrown, ranged), improved hit detection, PvP balancing
- 🏹 Ranged Weapons & Ammunition: Bow combat with different arrow types (stone, iron, fire arrows), arrow cycling system
- 🩸 Active Effects System: Bleed damage, burn damage, and other status effects
- 💀 Player Corpses: Harvestable corpses that yield primitive resources when players die
- 😵 Knock Out System: Combat state with temporary incapacitation and a chance to spontaneously recover
- 🏠 Player Shelter: Personal shelter system where only the owner can enter and keep their campfire safe from the rain
- 🛏️ Sleeping Bags: Placeable respawn points that persist between deaths
- 🏗️ Construction System: Base building (walls, floors, etc.)
- 🌱 Farming System: Planting, growing, harvesting crops
- 🦌 Hunting System: NPC animals (foxes, wolves, etc.), tracking, hunting mechanics
- 🎨 Terrain Autotiling: Edge detection, Wang tiles, seamless transitions between biomes
- 🛡️ Advanced Armor System: Damage resistance by type (melee, projectile, fire, blunt, slash, pierce), warmth bonuses, movement speed modifiers, set-based immunities (burn, cold, wetness, knockback, bleed), special effects (melee damage reflection, detection radius, low health damage bonus, silent movement, animal intimidation), cold resistance scaling, and drying speed modifiers
- 🌦️ Dynamic Chunk-Based Weather: Evolving weather patterns with chunk-level granularity, smooth transitions, and gameplay effects (rain intensity, temperature, visibility)
- 🌍 Procedural World Generation: Multi-biome terrain generation (grasslands, forests, beaches, rivers), island-based maps with configurable parameters, noise-based terrain shaping, and resource distribution
- 🤖 Advanced AI: Hostile NPC behaviors (wolves, foxes), state-based AI systems (idle, wander, chase, attack, flee), pathfinding, aggression mechanics, and animal-specific behaviors
- 🏛️ Monuments System: Pre-designed structures spawned in the world - abandoned buildings, caves, military outposts, research facilities with unique loot tables and environmental storytelling
- 🏢 Central NPC Compound: Neutral trading hub with shared crafting stations, vending machines, AI-driven auction house, and insurance pool system for collective resource sharing
- 👥 Team/Social Features: Shared map markers, team chat, private messaging, player notes, and group formation
- 🍲 Broth System: Placeable broth pots over campfires with water filling mechanics, multi-ingredient cooking, stirring mini-game, and recipe spoilage mechanics
- 🧱 Walls & Gates: Buildable wooden walls, lockable gates, lockable storage, fire arrow structure damage, and water-based fire extinguishing
- ⚔️ Tool/Weapon Durability
- 🔫 Firearm System: Guns with ammo types, reloading mechanics, and recoil
Planned (📋):
- 🔫 Firearms & Advanced Combat: Need to add more gun types and maybe a "zoom" feature which will be tricky in 2D but I have some ideas (like partitioned viewport)
- 🤖 Neutral Faction & NPCs: Need to add AI NPCs in the monuments (add more monuments) that you can interact with or give quests
- 🔑 Social Auth (Steam, Discord, Twitch)
- 🔬 Advanced Tech Tree: The "faction" unlocks which I'll work on if the game gets traction but as of now the main survival tech tree is fully unlocked
- 🎨 Graphical Overhaul (Hiring Pixel Artists!)
Note: Between this project and others, I might be away for some time - usually tending to olive trees or working on freelance projects. Feel free to contribute! If you're interested in contributing to the main project, the planned features listed above would be fantastic starting points! I'd love to see what the community builds with this foundation. 🎮
Support the Project: If you find this starter kit helpful and want to support continued development, consider trying some premium olive oil from my family farm! 🫒
- 🛒 Selo Olive Oil Discount: Use code
VIBE15for 15% off at seloolive.com/discount/VIBE15 - available in the US
| Layer | Technologies |
|---|---|
| Frontend | React 19, Vite 6, TypeScript |
| Multiplayer | SpacetimeDB 2.0 |
| Backend | Rust (WebAssembly) |
| Development | Node.js 22+ |
This project implements user authentication using a custom Node.js authentication server built with OpenAuthJS and Hono, bridged to SpacetimeDB via standard OpenID Connect (OIDC) JWTs.
Approach:
- Client: Initiates an OIDC Authorization Code Flow with PKCE, manually constructing the
/authorizeURL for the custom auth server and specifyingacr_values=pwdto request the password flow. - Auth Server (
auth-server-openauth/): A Node.js/Hono server that:
- Intercepts the
/authorizerequest. - If
acr_values=pwd, redirects the user to custom HTML login/registration forms, forwarding OIDC parameters (client_id,redirect_uri,state,code_challenge, etc.). - Handles POST submissions from these forms, verifying user credentials against a local user store (
data/users.json). - On successful login/registration, generates a one-time authorization
codeand stores it along with the user ID and PKCE challenge. - Redirects the user back to the client's specified
redirect_uriwith thecodeandstate.
- Client: Receives the redirect at its
/callbackURI, extracts thecode. - Client: Makes a
fetchPOST request to the auth server's custom/tokenendpoint, sending thecode, PKCEcode_verifier,client_id, andredirect_uri. - Auth Server (
/token):
- Receives the code exchange request.
- Looks up the code, retrieves the associated user ID and PKCE challenge.
- Verifies the
code_verifieragainst the storedcode_challenge. - If valid, mints a new JWT
id_tokenandaccess_token, signed using a private RSA key (RS256 algorithm). - Returns the tokens to the client.
- Client: Receives the tokens, stores the
id_token(used as thespacetimeToken). - Client: Connects to the main SpacetimeDB game server (
server/) using theid_token. - SpacetimeDB Server (
server/):
- Configured with the
issuerURL of the auth server. - Fetches the OIDC discovery document (
/.well-known/openid-configuration) and then the public keys (/.well-known/jwks.json) from the auth server. - Verifies the
id_token's signature using the fetched public key and validates theiss(issuer) andaud(audience) claims. - Grants the connection access based on the identity (
subclaim) in the validated token.
This approach uses standard OIDC practices with asymmetric key signing (RS256), allowing SpacetimeDB to securely verify tokens without needing a shared secret.
To get authentication working during local development, follow these steps:
- Generate RSA Keys: You need an RSA key pair for signing and verifying tokens. Use OpenSSL:
- Open a terminal in the project root directory.
- Run the following commands:
# Create a directory for keys if it doesn't exist mkdir keys # Generate a 2048-bit RSA private key openssl genpkey -algorithm RSA -out keys/private.pem -pkeyopt rsa_keygen_bits:2048 # Extract the public key from the private key openssl rsa -pubout -in keys/private.pem -out keys/public.pem
- This creates
keys/private.pem(keep secret, used by auth server) andkeys/public.pem(used for verification). - Important: The
.gitignorefile is configured to prevent these keys from being committed to Git.
- Configure Auth Server (
auth-server-openauth/):
- No
.envfile is strictly required for basic local operation, as defaults are set inindex.ts. - The server automatically loads
keys/private.pemandkeys/public.pemfor signing tokens and serving the JWKS endpoint. - It manages user data in
data/users.json(which will be created automatically if it doesn't exist). The.gitignorealso prevents this file from being committed.
- Run Auth Server:
- Open a terminal in the
auth-server-openauth/directory. - Run
npm installif you haven't already. - Run
npm start. - Keep this terminal running. You should see
🚀 Auth server → http://localhost:4001. Logs for authentication steps will appear here.
- Configure SpacetimeDB Server (
server/data/config.toml):
- Ensure the
server/data/config.tomlfile has the following[auth]configuration to trust your auth server:
- Run Main SpacetimeDB Server (
server/):
- Open a separate terminal.
- Run
spacetime start. - Keep this terminal running.
- Client Configuration: No changes are needed for default local play. Auth and Spacetime endpoints are resolved in
client/src/config/backendEnv.ts(localhost + Vite dev usehttp://localhost:4001andws://localhost:3000). See Client Configuration for optional env overrides. - Run Client:
- Open a terminal in the project root directory.
- Run
npm run dev.
Now, when you sign in via the client's login screen, the full authentication flow using your custom OpenAuthJS server and RS256 keys should execute.
- Auth Server: Deploy the
auth-server-openauthNode.js application to a hosting provider. Ensure thekeys/private.pemandkeys/public.pemfiles are securely deployed alongside the application (or manage keys via environment variables/secrets management if your host supports it). Ensure it's served over HTTPS. - Client: Set production auth and Spacetime defaults via Vite env at build time (see Client Configuration), or use
VITE_AUTH_SERVER_URL/VITE_SPACETIME_*overrides for your deployed auth server URL (HTTPS) and database. - SpacetimeDB: Configure your SpacetimeDB Maincloud/Enterprise instance with the production
issuerandjwks_uriof your deployed auth server, and the correctaudience.
- Basic Forms: The login/register forms served by the auth server are very basic HTML. They could be enhanced or replaced with a proper frontend framework if desired.
- Error Handling: Error handling in the manual auth routes could be more user-friendly.
- No Refresh Token Handling: This setup doesn't implement refresh tokens. If the
id_tokenexpires, the user would need to log in again.
This project utilizes Cursor's AI features, including Rules, to aid development. Rules are markdown files (.mdc) that provide context and guidelines to the AI assistant.
guide.mdc: Contains general architectural guidelines, technology choices, and development workflow information.resources.mdc: Outlines the specific steps for adding new resources or gatherable nodes consistently.
As the project grows, more specific rules will be added for core features (e.g., crafting, building, combat) to ensure the AI can provide consistent and relevant assistance.
While the project is still evolving, a key goal is maintainability. As features are added, we aim to:
- Keep individual file sizes manageable (ideally under ~600 lines where practical).
- Refactor logic into reusable helper functions and potentially dedicated modules (like the planned
inventory_logic.rs). - Utilize abstraction to avoid code duplication, especially for common interactions like container management.
Auth and SpacetimeDB WebSocket URLs are resolved in client/src/config/backendEnv.ts and consumed by AuthContext.tsx and GameConnectionContext.tsx.
Default behavior
- Vite dev or
localhost: Authhttp://localhost:4001, Spacetimews://localhost:3000, databasebroth-bullets-local. - Deployed site (not localhost): Auth
https://broth-and-bullets-production.up.railway.app, Spacetimewss://maincloud.spacetimedb.com, databasebroth-bullets.
Local UI with production backends (no local Spacetime or auth)
Create .env.local in the project root (next to vite.config.ts) or set env vars before npm run dev:
VITE_USE_PRODUCTION_BACKENDS=trueRestart the dev server after changing env files. The client uses the production auth server and Maincloud; ensure the deployed auth server allows CORS from your dev origin (e.g. http://localhost:5173).
Optional overrides (highest precedence; use for forks or staging)
| Variable | Purpose |
|---|---|
VITE_AUTH_SERVER_URL |
Full auth issuer base URL. |
VITE_SPACETIME_WS_URL |
SpacetimeDB WebSocket URI. |
VITE_SPACETIME_DATABASE |
Database name. |
See .env.example in the project root for commented templates (including backend overrides).
This project includes SOVA (Sentient Ocular Virtual Assistant), an intelligent AI assistant with voice synthesis capabilities. SOVA provides tactical advice, game tips, and responds with a military-themed personality.
All API keys are secured server-side - never exposed to the browser.
- Set server-side API keys in root
.env:
# Create .env file in project root
# OpenAI API key is REQUIRED for Whisper (speech-to-text)
echo "OPENAI_API_KEY=sk-your-openai-api-key-here" > .env
# Add at least one AI provider key for SOVA responses:
echo "GROK_API_KEY=xai-your-grok-api-key-here" >> .env
# OR echo "GEMINI_API_KEY=your-gemini-api-key-here" >> .env
# Optional provider selection (defaults to 'grok')
echo "VITE_AI_PROVIDER=grok" >> .env- Start Kokoro TTS Backend (Self-hosted, Free): Prerequisites: Python 3.10-3.12 (Python 3.13 not supported yet) See KOKORO_INTEGRATION.md for detailed setup instructions, troubleshooting, and system requirements.
- Configure Client (No API Keys Needed!):
# Add to .env file in project root
echo "VITE_KOKORO_BASE_URL=http://localhost:8001" >> .env- 🎤 Voice Synthesis: High-quality voice responses using Kokoro TTS (self-hosted, free)
- 🎙️ Voice Commands: Hold V key for speech-to-text input (OpenAI Whisper)
- 🧠 AI Personality: Intelligent responses powered by multiple providers (Grok/OpenAI/Gemini)
- 🔄 Provider Switching: Easy switching between AI providers via
VITE_AI_PROVIDERenvironment variable - 🔒 Secure: All API keys stay on server - never exposed to browser
- 🎯 Game Knowledge: Contextual survival tips and tactical advice
- 🎪 Easter Eggs: Special responses (try asking "What does SOVA stand for?")
- 🔄 Fallback System: Works without API keys using predefined responses
- Push-to-Talk: Hold V key to activate voice recording
- Cyberpunk UI: Animated recording interface with status indicators
- Speech-to-Text: OpenAI Whisper converts speech to text
- Chat Integration: Voice messages appear in chat like typed messages
- AI Response: SOVA responds intelligently with voice synthesis (Kokoro TTS)
You need 2 services running for full voice functionality:
- Kokoro TTS Backend (
tts-backend/) - Local text-to-speech synthesis - Game Client (
npm run dev) - React frontend
- docs/setup/ENVIRONMENT_SETUP.md - Complete AI environment variable guide
- KOKORO_INTEGRATION.md - Complete Kokoro TTS setup guide (Python version requirements, troubleshooting, voice options, production deployment)
- WHISPER_OPTIMIZATION.md - Speech-to-text optimization guide
Changing the tile size, chunk configuration, or overall world dimensions requires coordinated modifications in both the client and server code to ensure consistency between rendering, collision detection, game logic, and world generation.
Tile & World Size:
TILE_SIZE: Visual pixel size of each grid tile (e.g.,48). Must match server'sTILE_SIZE_PX.SERVER_WORLD_WIDTH_TILES: Assumed width of the server's world in tiles (e.g.,500). Must match server'sWORLD_WIDTH_TILES.SERVER_WORLD_HEIGHT_TILES: Assumed height of the server's world in tiles (e.g.,500). Must match server'sWORLD_HEIGHT_TILES.
Chunk Configuration:
CHUNK_SIZE_TILES: Number of tiles along one edge of a square chunk (e.g.,10). Must match server'sCHUNK_SIZE_TILES.
Legacy/Compatibility Values:
worldWidthandworldHeight: Should matchSERVER_WORLD_WIDTH_TILESandSERVER_WORLD_HEIGHT_TILES.spriteWidthandspriteHeight: Player/entity sprite dimensions, typically matchTILE_SIZE.
Primary Constants:
TILE_SIZE_PX: Size of each tile in pixels (e.g.,pub const TILE_SIZE_PX: u32 = 48;).WORLD_WIDTH_TILES: World width in tiles (e.g.,pub const WORLD_WIDTH_TILES: u32 = 500;).WORLD_HEIGHT_TILES: World height in tiles (e.g.,pub const WORLD_HEIGHT_TILES: u32 = 500;).
Derived Values (automatically calculated):
WORLD_WIDTH_PX: World width in pixels ((WORLD_WIDTH_TILES * TILE_SIZE_PX) as f32).WORLD_HEIGHT_PX: World height in pixels ((WORLD_HEIGHT_TILES * TILE_SIZE_PX) as f32).
Chunk System:
CHUNK_SIZE_TILES: Size of a chunk in tiles (e.g.,pub const CHUNK_SIZE_TILES: u32 = 10;). Must match client.WORLD_WIDTH_CHUNKS: Number of chunks across world width (auto-calculated).CHUNK_SIZE_PX: Size of a chunk in pixels (auto-calculated).
The WorldGenConfig struct controls procedural world generation:
world_width_tiles: Should matchWORLD_WIDTH_TILESinlib.rs.world_height_tiles: Should matchWORLD_HEIGHT_TILESinlib.rs.chunk_size: Should matchCHUNK_SIZE_TILESinenvironment.rs.- Other generation parameters:
seed,island_border_width,beach_width,river_frequency, etc.
When changing world dimensions or tile size:
- Update Server Core (
server/src/lib.rs):
pub const TILE_SIZE_PX: u32 = 48; // Your desired tile size
pub const WORLD_WIDTH_TILES: u32 = 500; // Your desired world width
pub const WORLD_HEIGHT_TILES: u32 = 500; // Your desired world height- Update Server Environment (
server/src/environment.rs):
pub const CHUNK_SIZE_TILES: u32 = 10; // Your desired chunk size- Update World Generation Config (in
init_moduleor world generation):
WorldGenConfig {
world_width_tiles: 500, // Match WORLD_WIDTH_TILES
world_height_tiles: 500, // Match WORLD_HEIGHT_TILES
chunk_size: 10, // Match CHUNK_SIZE_TILES
// ... other generation settings
}- Update Client Config (
client/src/config/gameConfig.ts):
const TILE_SIZE = 48; // Match server TILE_SIZE_PX
const SERVER_WORLD_WIDTH_TILES = 500; // Match server WORLD_WIDTH_TILES
const SERVER_WORLD_HEIGHT_TILES = 500; // Match server WORLD_HEIGHT_TILES
const CHUNK_SIZE_TILES = 10; // Match server CHUNK_SIZE_TILES- Rebuild and Republish:
cd server
spacetime publish -c --no-config -p . broth-bullets-local -y # Clear DB for schema changes
spacetime generate --no-config --include-private -p . -l typescript -o ../client/src/generated -y
cd ..Important: Ensure the TILE_SIZE (in gameConfig.ts) / TILE_SIZE_PX (in lib.rs) and the SERVER_WORLD_WIDTH_TILES/SERVER_WORLD_HEIGHT_TILES (in gameConfig.ts) / WORLD_WIDTH_TILES/WORLD_HEIGHT_TILES (in lib.rs) values are kept consistent between the client and server configuration files. The gameConfig.worldWidth and gameConfig.worldHeight should also mirror these tile dimension values.
After making server-side changes, remember to re-publish the module:
# From the server/ directory
spacetime publish --no-config -p . broth-bullets-local -y
# No need to regenerate client bindings for changing only these constantsvibe-coding-starter-pack-2d-survival/
├── .cursor/ # Cursor AI configuration
│ └── rules/ # *.mdc rule files for AI context
├── agent/ # NPC AI agent system (TypeScript)
│ ├── src/ # Agent source code
│ │ ├── index.ts # Agent entry point
│ │ ├── planner.ts # AI planning logic
│ │ ├── config.ts # Agent configuration
│ │ └── generated/ # Auto-generated SpacetimeDB bindings
│ └── package.json # Node.js dependencies
├── auth-server-openauth/ # Authentication server (Node.js/Hono)
│ ├── data/ # User storage (users.json)
│ ├── index.ts # Main auth server logic
│ └── package.json # Node.js dependencies
├── tts-backend/ # Kokoro TTS backend (Python/FastAPI)
│ ├── app.py # FastAPI server for text-to-speech
│ ├── requirements.txt # Python dependencies
│ └── README.md # Kokoro setup instructions
├── client/ # React frontend (UI, rendering, input)
│ ├── public/ # Static files (index.html, favicons)
│ ├── src/
│ │ ├── assets/ # Sprites, textures, sounds
│ │ │ ├── doodads/ # Decorative game objects
│ │ │ ├── environment/ # Environmental assets (clouds, etc.)
│ │ │ ├── items/ # Item sprites and assets
│ │ │ ├── states/ # UI state assets
│ │ │ └── tiles/ # Tile textures
│ │ ├── components/ # React components (UI, Canvas)
│ │ ├── config/ # Client-side game configuration
│ │ ├── contexts/ # React contexts (Auth, Game state)
│ │ ├── effects/ # Visual effects and animations
│ │ ├── engine/ # Runtime engine core (loop, adapters, snapshot store)
│ │ ├── generated/ # Auto-generated SpacetimeDB bindings
│ │ ├── hooks/ # Custom React hooks
│ │ ├── types/ # Shared TypeScript types
│ │ └── utils/ # Helper functions (rendering, logic)
│ │ ├── auth/ # Authentication utilities
│ │ └── renderers/ # Rendering utilities
│ └── package.json
├── server/ # SpacetimeDB server logic (Rust)
│ ├── data/ # Server data and configuration
│ │ ├── cache/ # Runtime caches and temp files
│ │ ├── control-db/ # SpacetimeDB control database
│ │ ├── logs/ # Server logs
│ │ └── program-bytes/ # Compiled WASM modules
│ ├── src/ # Rust source code
│ │ ├── lib.rs # Main server module entry point
│ │ ├── environment.rs # World generation and resource spawning
│ │ ├── player_movement.rs # Player physics and movement
│ │ ├── combat.rs # Combat system and weapons
│ │ ├── crafting.rs # Crafting recipes and logic
│ │ ├── world_generation.rs # Procedural world generation
│ │ └── [other modules] # Additional game systems
│ ├── target/ # Rust build artifacts
│ └── Cargo.toml # Rust dependencies and configuration
├── components/ # Shared/reusable components (legacy)
├── data/ # Shared game data files
├── keys/ # RSA keys for authentication (generated)
│ ├── private.pem # Private key (keep secret)
│ └── public.pem # Public key for verification
├── eslint.config.js # ESLint configuration
├── github.png # Banner image
├── guide.mdc # Development guide (Cursor rules)
├── index.html # Root HTML file
├── CONTRIBUTING.md # Contribution guidelines
├── LICENSE # Apache 2.0 License
├── NOTICE # IP and attribution notices
├── package.json # Root package.json with client scripts
├── preview.png # Gameplay preview image
├── README.md # This file
├── tsconfig.*.json # TypeScript configurations
└── vite.config.ts # Vite build configuration
**Cannot find module './generated'error in client:**- Ensure you ran
spacetime generate --lang typescript --out-dir ../client/src/generated -p .from theserverdirectory after the lastspacetime publishwas successful. Check the publish output for errors. - Make sure the
client/src/generatedfolder was actually created and contains.tsfiles, includingindex.ts. - Restart the Vite dev server (
npm run dev). Sometimes Vite needs a restart after significant file changes.
- Ensure you ran
- Client connects but game doesn't load / players don't appear:
- Check the browser console (F12) for JavaScript errors (e.g., subscription failures, rendering issues).
- Check the terminal running
spacetime startfor server-side Rust errors (e.g., reducer panics, assertion failures).
- Old players/data still appearing after disconnect/refresh:
- Verify the
identity_disconnectedlogic inserver/src/lib.rsis correctly deleting the player, inventory, and equipment. - For a guaranteed clean slate during development, delete and recreate the local database:
# Stop spacetime start (Ctrl+C in its terminal) spacetime delete broth-bullets-local # Run from any directory spacetime start # Restart the server # Then re-publish and re-generate (Step 4 above)
- Verify the
**spacetime publishtries to publish to Maincloud instead of local:**- Ensure you are logged out:
spacetime logout. - Ensure the
spacetime startserver is running before you publish. - Check your SpacetimeDB config file (
%LOCALAPPDATA%/SpacetimeDB/config/cli.tomlon Windows,~/.local/share/spacetime/config/cli.tomlon Linux/macOS) and make suredefault_serveris set tolocalor commented out.
- Ensure you are logged out:
- Server Development (
server/src):
- Modify Rust code (add features, fix bugs).
- Deploy changes using scripts:
cd server/ ./deploy-local.ps1 # Quick local update ./deploy-local-clean.ps1 # Fresh local database (for schema changes)
- Client Development (
client/src):
- Modify React/TypeScript code.
- The Vite dev server (
npm run dev) provides Hot Module Replacement (HMR) for fast updates.
- Engine (
client/src/engine/**) owns frame timing, runtime snapshots, and SpacetimeDB adapter wiring. - React UI owns rendering widgets, menu/chat panels, and dispatching user intents.
GameCanvasis a render adapter: it consumes runtime state and emits interactions, but it does not directly subscribe toworld_chunk_data.useEngineSnapshot()is the preferred way for UI components to read runtime state slices.
The project includes PowerShell scripts in the server/ directory for streamlined deployment:
**deploy-local.ps1** - Updates existing local database- Publishes to
broth-bullets-local - Seeds SOVA AI config from root
.env - Regenerates client bindings
- Preserves existing data
- Publishes to
**deploy-local-clean.ps1**- Fresh local database deployment- Clears and republishes
broth-bullets-localdatabase - Seeds SOVA AI config from root
.env - Regenerates client bindings
⚠️ Wipes all data - use for schema changes
- Clears and republishes
**deploy-production.ps1** - Updates production database- Publishes to
broth-bulletson maincloud - Seeds SOVA AI config from root
.env - Regenerates client bindings
- Commits from root directory to capture all changes (server + client)
- Pushes to trigger Railway deployment
- Preserves existing data
- Publishes to
**deploy-production-clean.ps1** - Fresh production deployment- Deletes existing
broth-bulletsdatabase on maincloud - Creates fresh database with latest schema
- Seeds SOVA AI config from root
.env - Regenerates client bindings
- Commits from root directory to capture all changes (server + client)
- Pushes to trigger Railway deployment
⚠️ Wipes all production data - use carefully
- Deletes existing
# Local development - quick update
cd server/
./deploy-local.ps1
# Local development - schema changes
cd server/
./deploy-local-clean.ps1
# Production deployment - safe update
cd server/
./deploy-production.ps1
# Production deployment - major schema changes
cd server/
./deploy-production-clean.ps1 # ⚠️ Use with caution!📝 Important Note: Production scripts automatically navigate to the root directory before committing to ensure all changes (both server and client bindings) are captured in the git commit. This ensures Railway deployments include the latest generated client bindings.
This section contains the prompts used for generating game assets with AI tools like GPT-4o.
For generating game item icons (weapons, tools, consumables, etc.):
A pixel art style icon with consistent pixel width and clean black outlines, designed as a game item icon. Rendered with a transparent background, PNG format. The object should have a clear silhouette, sharp pixel-level detail, and fit naturally in a top-down RPG game like Secret of Mana. No background, no shadows outside the object. Stylized with a warm palette and light dithering where appropriate.
Subject: SUBJECT, i.e. Rope
Usage: Replace "SUBJECT" with the specific item (e.g., "hammer", "health potion", "wooden sword")
For generating environment objects, structures, and decorative elements:
Pixel art sprite in a 16-bit RPG style, 3/4 top-down view (slightly angled perspective), clean outlines, vibrant color palette, soft shading with no directional highlights (shading handled via in-game shaders), set on a transparent background. Focus on a blocky, detailed silhouette with depth visible in the form. Centered and properly grounded in the scene.
Subject: SUBJECT, i.e. Oak Tree
Usage: Replace "SUBJECT" with the specific environment object (e.g., "Oak Tree", "Stone Boulder", "Wooden Campfire", "Small Bush")
For generating character animations and complex sprite sequences, use retrodiffusion.ai to generate spritesheets.
This specialized tool is designed specifically for creating pixel art spritesheets with consistent character designs across multiple frames, making it ideal for:
- Character walking animations
- Idle animations
- Object state variations
- Multi-directional sprites
The tool maintains consistency between frames and generates properly formatted spritesheets that can be directly imported into game engines.
We welcome contributions that improve correctness, stability, or player experience!
Please see CONTRIBUTING.md for detailed guidelines on:
- What types of contributions are welcome
- How to set up your development environment
- The pull request process
- Code style guidelines
- How to report exploits (privately!)
Quick Start:
- Fork the repository
- Clone your fork and set up the development environment
- Create a feature branch (
git checkout -b feature/your-feature-name) - Make your changes and test thoroughly
- Submit a Pull Request
Whether you're interested in adding new gameplay mechanics, improving existing systems, or enhancing the codebase, your contributions are valuable!
For questions or discussions, feel free to open an issue first or join our Discord.
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
The game's assets and IP remain protected, and the official Broth & Bullets servers will continue to be operated by Martin Erlic. For more information see NOTICE.
To avoid any confusion, here is a clear summary of what is allowed and what is not:
You can:
- ✅ Read and study the code to better understand how the game works
- ✅ Modify and experiment with the code locally
- ✅ Run your own servers for experimentation and learning
- ✅ Use it as a reference for building your own projects
- ✅ Make a game similar to Broth & Bullets with your own IP (art and themes) using our code as a basis
- ✅ Contribute back to the project via Pull Requests
You cannot:
- ❌ Use Broth & Bullets' art, game content, music, or other protected assets
- ❌ Use the "Broth & Bullets" name, branding, or story for commercial purposes
- ❌ Present forks or derivative works as official Broth & Bullets
- ❌ Operate official, unofficial, private, or competing Broth & Bullets servers
- ❌ Use original character designs or hand-crafted assets without permission
- ❌ Do anything that violates the Apache 2.0 license
We truly appreciate any reporting of in-game exploits. To ensure that exploits are addressed quickly and not abused by other players, we ask that you submit them privately. Do not create public issues or share exploit details in Discord.
Contributors who report meaningful, previously unreported, and verified exploits may receive special recognition.
For licensing inquiries regarding Broth & Bullets intellectual property, please contact Martin Erlic.
Created by SeloSlav
💬 Want to chat? Join the discussion on Discord