Deployment Overview
Hyperscape uses a split deployment model:- Server: Railway, Fly.io, or Docker host
- Client: Vercel, Netlify, or static hosting
- Database: PostgreSQL (Neon recommended)
- Assets: CDN or object storage
Environment Variables
Server Production
Client Production
Production Domains
Hyperscape supports multiple production domains with CORS configuration (added in commits bb292c1, 7ff88d1): Game Domains:hyperscape.gg- Primary game domain (added Feb 2026)play.hyperscape.club- Alternative game domain
hyperscape.bet- Betting platform (added Feb 2026)hyperbet.win- Additional betting domain (added Feb 2026)
Railway Deployment
1
Create Railway project
Connect your GitHub repository to Railway.
2
Configure build
Set build command:
bun run build
Set start command: bun start3
Add PostgreSQL
Add PostgreSQL service from Railway marketplace.
4
Set environment variables
Add all required server environment variables.
Cloudflare Pages Deployment
The client automatically deploys to Cloudflare Pages on push to main via GitHub Actions (added commit 37c3629, Feb 26 2026).Automated Deployment
The.github/workflows/deploy-pages.yml workflow triggers on:
- Pushes to main branch
- Changes to
packages/client/**orpackages/shared/**(shared contains packet definitions) - Changes to
package.jsonorbun.lockb - Manual workflow dispatch
The client depends on
packages/shared for packet definitions. When packets change on the server, the client must rebuild to stay in sync.- Primary:
https://hyperscape.gg - Alternative:
https://hyperscape.club - Preview:
https://<commit-sha>.hyperscape.pages.dev
Required GitHub Secrets
Cloudflare R2 CORS Configuration
Assets are served from Cloudflare R2 with CORS enabled for cross-origin loading:allowed.origins/methods/headers structure (not flat allowedOrigins). The old format caused wrangler r2 bucket cors set to fail (commit 055779a).
Benefits:
- Allows
assets.hyperscape.clubto serve to all domains - Supports hyperscape.gg, hyperscape.club, and preview URLs
- Enables cross-origin asset loading for Cloudflare Pages → R2
Manual Deployment
Deploy manually using wrangler:Vercel Client Deployment
1
Import project
Import
packages/client directory to Vercel.2
Configure build
Root directory:
packages/client
Build command: bun run build
Output directory: dist3
Set environment variables
Add
PUBLIC_* environment variables.Database Setup
Neon PostgreSQL
- Create database at neon.tech
- Copy connection string
- Set as
DATABASE_URLin server environment
Migrations
CDN Setup
Option 1: Self-Hosted
Use the included Docker CDN:PUBLIC_CDN_URL to point to your CDN host.
Option 2: Cloud Storage
Upload assets to S3, R2, or similar:- Build assets:
bun run assets:optimize - Upload
packages/server/world/assets/ - Set
PUBLIC_CDN_URLto bucket URL
Vast.ai GPU Deployment
Hyperscape deploys to Vast.ai for GPU-accelerated streaming with automated CI/CD via GitHub Actions.Automated Instance Provisioning (NEW)
Thescripts/vast-provision.sh script automatically finds and rents GPU instances with display driver support:
1
Install Vast.ai CLI
2
Run Provisioner
- Search for instances with
gpu_display_active=true(REQUIRED for WebGPU) - Filter by reliability (≥95%), GPU RAM (≥20GB), price (≤$2/hr)
- Show top 5 available instances
- Automatically rent the best instance
- Wait for instance to be ready
- Output SSH connection details
3
Update GitHub Secrets
4
Trigger Deployment
scripts/vast-provision.sh to customize search criteria:
Automated Deployment
Automated Deployment
The.github/workflows/deploy-vast.yml workflow automatically deploys to Vast.ai on push to main:
- Go to Actions tab in GitHub
- Select “Deploy to Vast.ai” workflow
- Click “Run workflow”
- Select branch (usually main)
- Click “Run workflow”
- Deploying hotfixes without waiting for CI
- Re-deploying after Vast.ai instance restart
- Testing deployment process
- Write Secrets to /tmp - Saves secrets to
/tmp/hyperscape-secrets.envbefore git operations (commit 684b203) - Enter Maintenance Mode - Pauses new duel cycles, waits for active markets to resolve
- SSH Deploy - Connects to Vast.ai instance, pulls latest code, builds, and restarts
- Auto-Detect Configuration - Database mode, stream destinations, GPU rendering mode
- Start Xvfb - Virtual display started before PM2 (commit 294a36c)
- PM2 Restart - Reads secrets from
/tmp, auto-detects database mode (commits 684b203, 3df4370) - Exit Maintenance Mode - Resumes duel cycles after health check passes
Graceful Restart API (Zero-Downtime Deployments)
The server provides a graceful restart API for zero-downtime deployments during active duels: Request Graceful Restart:- If no duel active: restarts immediately via SIGTERM
- If duel in progress: waits until RESOLUTION phase completes
- PM2 automatically restarts the server with new code
- No interruption to active duels or streams
- Deploy hotfixes during active streaming
- Update server code without stopping duels
- Restart after configuration changes
Maintenance Mode API (March 2026)
The server provides a comprehensive maintenance mode system for zero-downtime deployments: Enter Maintenance Mode:- Polls
/healthendpoint every 5 seconds - Displays red warning banner when
maintenanceMode: true - Banner appears across all screens (game, admin, leaderboard, streaming)
- Message: “SERVER MAINTENANCE IMMINENT - GAME WILL PAUSE AFTER CURRENT DUEL”
- Prevents new duel cycles from starting
- Waits for active duels to complete
- Pauses betting markets
- Sets
safeToDeploy: truewhen safe to restart - Resumes automatically on exit or timeout
Required GitHub Secrets
Configure these in repository settings → Secrets → Actions:Deployment Script Improvements (March 2026)
Thescripts/deploy-vast.sh script has been significantly enhanced with recent improvements:
MediaRecorder Streaming Mode (Commits 72c667a, 7284882):
- Switched from CDP screencast to MediaRecorder mode for streaming capture
- Uses
canvas.captureStream()→ WebSocket → FFmpeg pipeline - More reliable under Xvfb + WebGPU on Vast instances
- Requires
internalCapture=1URL parameter for canvas capture bridge - Eliminates stream freezing and stalling issues
- Writes secrets to
/tmp/hyperscape-secrets.envbefore git operations ecosystem.config.cjsreads secrets file directly at config load time- Auto-detects
DUEL_DATABASE_MODEfromDATABASE_URLhostname - Prevents
sanitizeRuntimeEnv()from strippingDATABASE_URLin remote mode - Ensures secrets persist through git reset operations
- Reverted from Chrome Canary back to Chrome Beta (
google-chrome-beta) for Linux NVIDIA - Chrome Canary was experiencing instability issues on Linux NVIDIA GPUs
- Chrome Beta provides better stability for production streaming
- Uses Vulkan ANGLE backend (
--use-angle=vulkan) for optimal performance
- Starts Xvfb before PM2 to ensure virtual display is available
- Exports
DISPLAY=:99to environment ecosystem.config.cjsexplicitly setsDISPLAY=:99in PM2 environment- Prevents “cannot open display” errors during RTMP streaming
- Auto-detects remote database mode from
DATABASE_URLenvironment variable - Sets
USE_LOCAL_POSTGRES=falsewhen remote database detected - Prevents Docker PostgreSQL conflicts on Vast.ai instances
- Added
apt --fix-broken install -ybefore package installation - Resolves dependency conflicts on fresh Vast.ai instances
- Prevents deployment failures from broken package states
STREAM_ENABLED_DESTINATIONSnow uses||logic for fallback- Auto-detects enabled destinations from configured stream keys
- Explicitly forwards stream keys through PM2 environment
- Added
TWITCH_RTMP_STREAM_KEYalias to secrets file
- Auto-clones repository if it doesn’t exist on fresh Vast.ai instances
- Eliminates manual repository setup step
- Always checks and installs bun if missing
- Ensures bun is available before running build commands
scripts/deploy-vast.sh script handles the full deployment with these improvements:
Key Steps:
- Load secrets from
/tmp/hyperscape-secrets.env(commit 684b203) - Auto-detect database mode from DATABASE_URL (commit 3df4370)
- Auto-detect stream destinations from available keys (commit 41dc606)
- Configure DNS resolution (some Vast containers use internal-only DNS)
- Pull latest code from main branch
- Restore environment variables after git reset (commits eec04b0, dda4396, 4a6aaaf)
- Install system dependencies (build-essential, ffmpeg, Vulkan drivers, Chrome Beta, PulseAudio)
- GPU rendering detection and configuration (commits dd649da, e51a332, 30bdaf0, 725e934, 012450c):
- Check for NVIDIA GPU and DRI devices
- Try Xorg mode first (if DRI available)
- Detect Xorg swrast fallback and switch to headless EGL if needed
- Fall back to Xvfb mode if Xorg fails
- Fall back to headless EGL mode if X11 not available
- Install NVIDIA Xorg drivers and configure headless X server
- Force NVIDIA-only Vulkan ICD to avoid Mesa conflicts
- Install Chrome Beta channel for WebGPU support (commit 547714e)
- Setup PulseAudio for audio capture (commits 3b6f1ee, aab66b0, b9d2e41):
- Create virtual sink (
chrome_audio) for Chrome audio output - Configure user-mode PulseAudio with proper permissions
- Export PULSE_SERVER environment variable
- Install Playwright and dependencies
- Build core packages (physx, decimation, impostors, procgen, asset-forge, shared)
- Setup Solana keypair from
SOLANA_DEPLOYER_PRIVATE_KEY(commit 8a677dc) - Push database schema with drizzle-kit and warmup connection pool
- Tear down existing processes (commit b466233):
- Use
pm2 killinstead ofpm2 deleteto restart daemon with fresh env - Clean up legacy watchdog processes
- Use
- Start port proxies (socat) for external access
- Start Xvfb virtual display (commits 704b955, 294a36c):
- Start Xvfb before PM2 to ensure DISPLAY is available
- Export
DISPLAY=:99to environment
- Export GPU environment variables for PM2
- Start duel stack via PM2 (commits 684b203, 3df4370):
- PM2 reads secrets from
/tmp/hyperscape-secrets.env - Auto-detects database mode from DATABASE_URL
- Explicitly forwards DISPLAY, DATABASE_URL, and stream keys
- PM2 reads secrets from
- Wait for health check to pass (up to 120 seconds)
- Run streaming diagnostics (commit cf53ad4)
git reset operations in deploy script would overwrite the .env file, losing DATABASE_URL and stream keys.
Solution: Write secrets to /tmp before git reset, then restore after:
- Prevents database connection loss during deployment
- Ensures stream keys persist across deployments
- Required for zero-downtime deployments
- Vast.ai servers can have stale stream keys from previous deployments
- Stale values override .env file values
- Explicitly unsetting ensures PM2 picks up correct keys
- Prevents streams from going to wrong Twitch/X/Kick accounts
Solana Keypair Setup
The deployment automatically configures Solana keypairs from environment variables:System Requirements
Vast.ai Instance Specs:- GPU: NVIDIA with Vulkan support (RTX 3060 Ti or better)
- RAM: 16GB minimum
- Storage: 50GB minimum
- OS: Ubuntu 22.04 or Debian 12
- Bun (latest)
- FFmpeg (system package, not static build)
- Chrome Beta channel (google-chrome-beta) - Updated March 13, 2026 for better production stability
- Playwright Chromium
- Vulkan drivers (mesa-vulkan-drivers, vulkan-tools)
- Xorg or EGL support (for GPU rendering)
- PulseAudio (for audio capture)
- socat (for port proxying)
-
Xorg Mode (preferred if DRI/DRM available):
- Requires
/dev/dri/card0or similar DRM device - Full hardware GPU acceleration
- Best performance
- Requires
-
Xvfb Mode (fallback when Xorg fails):
- Virtual framebuffer + GPU rendering via ANGLE/Vulkan
- Works when DRI/DRM not available
- Requires X11 protocol support
-
Headless EGL Mode (fallback for containers without X11):
- Works without X server or DRM/DRI access
- Uses Chrome’s
--headless=newwith direct EGL rendering - Hardware GPU acceleration via NVIDIA EGL
- Ideal for Vast.ai containers where NVIDIA kernel module fails to initialize for Xorg
- Uses
--use-gl=egl --ozone-platform=headlessflags
- Deployment script detects when Xorg falls back to swrast (software rendering)
- Automatically switches to headless EGL mode when swrast detected
- Prevents unusable software rendering for WebGPU streaming
Streaming Configuration
The deployment uses these streaming settings (updated March 2026):- Frame Pacing Guard: Skips frames arriving faster than 85% of 33.3ms target interval
- Xvfb Compositor: Runs at 30fps without vsync (game is capped at 30fps)
- everyNthFrame: Set to 1 (Xvfb delivers at 30fps, no frame skipping needed)
- Resolution: 1280x720 matches capture viewport, eliminates upscaling overhead
- Twitch (rtmp://live.twitch.tv/app)
- Kick (rtmps://fa723fc1b171.global-contribute.live-video.net/app) - Fixed in commit 5dbd239
- X/Twitter (rtmp://sg.pscp.tv:80/x)
- YouTube explicitly disabled (commit b466233)
- All WebGL fallback code removed
STREAM_CAPTURE_DISABLE_WEBGPUandDUEL_FORCE_WEBGL_FALLBACKflags ignored- Deployment FAILS if WebGPU cannot initialize (no soft fallbacks)
- Headless mode NOT supported (WebGPU requires display server: Xorg or Xvfb)
DUEL_USE_PRODUCTION_CLIENT=truerecommended for faster page loads (180s timeout fix)STREAM_GOP_SIZEnow configurable via environment variable (default: 60 frames)
- Game music and sound effects captured via PulseAudio
- Virtual sink (
chrome_audio) routes Chrome audio to FFmpeg - Graceful fallback to silent audio if PulseAudio unavailable
- GPU Rendering Guide - GPU configuration
- Audio Streaming Guide - PulseAudio setup
Health Monitoring
The deployment includes comprehensive health checks:- Checks streaming API state
- Verifies game client is running
- Checks RTMP status file
- Lists FFmpeg processes
- Shows recent PM2 logs filtered for streaming keywords
Troubleshooting
Stream not appearing on platforms:- Check stream keys are configured:
- Check FFmpeg processes:
- Check RTMP status:
- Check PM2 logs:
DATABASE_URL to packages/server/.env after git reset to prevent it from being overwritten.
GPU rendering issues:
Check Vulkan support:
vite preview instead of dev server, eliminating JIT compilation delays.
CI/CD Configuration
GitHub Actions
The repository includes several CI/CD workflows with recent reliability improvements (Feb 2026):Build and Test (.github/workflows/ci.yml)
Runs on every push to main:
- Installs Foundry for MUD contracts tests
- Runs all package tests with increased timeouts for CI
- Validates manifest JSON files
- Checks TypeScript compilation
- Caches dependencies for faster builds
- Runs tests in parallel across packages
- Fails fast on first error
- Uses
--frozen-lockfileto prevent npm rate-limiting (commit 08aa151, Feb 25, 2026)
bun install --frozen-lockfile to prevent npm 403 rate-limiting errors:
bun installwithout--frozen-lockfiletries to resolve packages fresh from npm even when lockfile exists- Under CI load this triggers npm rate-limiting (403 Forbidden)
--frozen-lockfileensures bun uses only the committed lockfile for resolution- Eliminates npm registry calls entirely in CI
- Applied to all workflows: ci.yml, integration.yml, typecheck.yml, deploy-*.yml
- CI workflows now run reliably without npm rate-limiting failures
- Faster builds (no network calls to npm registry)
- Deterministic builds (exact versions from lockfile)
Integration Tests (.github/workflows/integration.yml)
Runs integration tests with database setup:
Database Schema Creation (commit eb8652a):
The integration workflow uses drizzle-kit push for declarative schema creation instead of server migrations:
- Server’s built-in migrations have FK ordering issues (migration 0050 references
arena_roundsfrom older migrations) drizzle-kit pushcreates schema declaratively without these problems- Prevents “relation already exists” errors on fresh test databases
SKIP_MIGRATIONS=truetells server to skip migration system (schema already created)- Fixed in commits: eb8652a (CI integration), 6a5f4ee (table validation skip)
IF NOT EXISTS guards for idempotency:
SKIP_MIGRATIONS is not set.
Deployment Workflows
- Railway:
.github/workflows/deploy-railway.yml - Cloudflare:
.github/workflows/deploy-cloudflare.yml - Vast.ai:
.github/workflows/deploy-vast.yml
RAILWAY_TOKEN- Railway API tokenCLOUDFLARE_API_TOKEN- Cloudflare API tokenVAST_API_KEY- Vast.ai API key
Docker Build Configuration
Server Dockerfile:- Uses bookworm-slim for Python 3.11+ support
- Includes build-essential for native module compilation
- Sets CI=true to skip asset download (assets served from CDN)
- Installs git-lfs for asset checks
Streaming Infrastructure
Browser Capture Configuration
The streaming system uses Playwright with Chrome for game capture: Chrome Flags for WebGPU:GPU Compatibility
Tested Configurations:- ✅ RTX 3060 Ti (Vulkan)
- ✅ RTX 4090 (Vulkan)
- ⚠️ RTX 5060 Ti (GL ANGLE only, Vulkan ICD broken)
- WebGPU + Vulkan (preferred, best performance)
- WebGPU + GL ANGLE (RTX 5060 Ti, stable)
- WebGL + Swiftshader (CPU fallback, lowest performance)
Xvfb Configuration
For headful mode with GPU compositing:Chrome Dev Channel
For latest WebGPU features on Vast.ai:Solana Betting Infrastructure
CLOB Market Mainnet Migration
The betting system migrated to CLOB (Central Limit Order Book) market program on Solana mainnet in February 2026 (commits dba3e03, 35c14f9): Program Address Updates:.env.mainnet with all VITE_ environment variables:
- Update program addresses in Rust code
- Regenerate IDL files with
anchor build - Update keeper bot logic for CLOB instructions
- Update server arena config with mainnet program IDs
- Update frontend .env.mainnet with all VITE_ vars
- Test on devnet before mainnet deployment
- Verify program deployment on Solana Explorer
Native App Releases
Hyperscape automatically builds native desktop and mobile apps for tagged releases.Creating a Release
.github/workflows/build-app.yml which builds:
- Windows:
.msiinstaller (x64) - macOS:
.dmginstaller (universal binary: Intel + Apple Silicon) - Linux:
.AppImage(portable) and.deb(Debian/Ubuntu) - iOS:
.ipabundle - Android:
.apkbundle
Download Portal
Built apps are published to:- GitHub Releases: https://github.com/HyperscapeAI/hyperscape/releases
- Public Portal: https://hyperscapeai.github.io/hyperscape/
Required GitHub Secrets
Configure these in repository settings for automated builds:The build workflow is enabled as of commit cb57325 (Feb 25, 2026). See
docs/native-release.md in the repository for complete setup instructions.Security & Browser Requirements
WebGPU Requirement
As of February 2026, Hyperscape requires WebGPU for rendering. All shaders use Three.js Shading Language (TSL) which only works with WebGPU. Browser Support:- Chrome 113+ (WebGPU enabled by default)
- Edge 113+
- Safari 18+ (macOS Sonoma+)
- Firefox Nightly (experimental)
- All procedural shaders (grass, terrain, particles) use TSL
- TSL compiles to WGSL (WebGPU Shading Language)
- No WebGL fallback possible without rewriting all shaders
- Commit: 3bc59db (February 26, 2026)
CSRF Protection Updates
The CSRF middleware was updated to support cross-origin clients (commit cd29a76): Problem:- CSRF uses
SameSite=Strictcookies which cannot be sent in cross-origin requests - Cloudflare Pages (hyperscape.gg) → Railway backend caused “Missing CSRF token” errors
- Cross-origin requests already protected by Origin validation + JWT auth
- Origin header validation (http-server.ts preHandler hook)
- JWT bearer token authentication (Authorization header)
- CSRF cookie validation (same-origin requests only)
JWT Secret Enforcement
JWT secret is now required in production and staging environments (commit 3bc59db):Production Checklist
- PostgreSQL database provisioned
- Environment variables configured
- JWT_SECRET generated and set (REQUIRED in production)
- ADMIN_CODE set (REQUIRED for production security)
- Privy credentials set (both client and server)
- CDN serving assets with CORS configured
- WebSocket URL configured
- SSL/TLS enabled
- Vast.ai API key configured (if using GPU deployment)
- CI/CD workflows configured with required secrets
- DNS configured (Google DNS for Vast.ai instances)
- Solana program addresses updated for mainnet (if using betting)
- CORS domains configured for production domains
- GitHub secrets configured for native app builds (if releasing)
- WebGPU-compatible browsers verified for users
- Maintenance mode API tested with ADMIN_CODE