Cloudflare Pages Deployment
This guide covers deploying the Hyperscape web client to Cloudflare Pages with automatic builds and R2 asset hosting.Overview
The Cloudflare deployment consists of:- Client: Static site hosted on Cloudflare Pages
- Assets: 3D models, textures, audio hosted on Cloudflare R2
- CORS: Configured for cross-origin asset loading
Architecture
Prerequisites
Cloudflare Account
- Sign up at Cloudflare
- Create a Pages project named
hyperscape - Create an R2 bucket named
hyperscape-assets
GitHub Secrets
Configure in repository settings (Settings → Secrets and variables → Actions):
| Secret | Description | Where to Find |
|---|---|---|
CLOUDFLARE_API_TOKEN | API token with Pages and R2 permissions | Cloudflare Dashboard → My Profile → API Tokens |
PUBLIC_PRIVY_APP_ID | Privy app ID (optional, has default) | Privy Dashboard |
Cloudflare API Token Permissions
Create a token with these permissions:- Account → Cloudflare Pages → Edit
- Account → R2 → Edit
Automatic Deployment
Workflow Trigger
The client deploys automatically on push tomain when these paths change:
packages/client/**packages/shared/**(contains packet definitions)package.jsonbun.lockb
Workflow File
.github/workflows/deploy-pages.yml
Build Process
- Checkout code with submodules
- Setup Bun (latest version)
- Install dependencies (
bun install --frozen-lockfile) - Build client (
bun run build:client):- Builds
packages/sharedfirst (via Turbo) - Builds
packages/physx-js-webidl(WASM bindings) - Builds
packages/client(Vite production build)
- Builds
- Deploy to Pages using Wrangler:
- Project:
hyperscape - Branch:
main - Commit hash and message included
- Project:
Build Environment Variables
Set during build (in workflow):Manual Deployment
From Local Machine
From GitHub Actions
- Go to Actions → Deploy Client to Cloudflare Pages
- Click Run workflow
- Select
mainbranch - Choose environment:
productionorpreview - Click Run workflow
R2 Asset Hosting
Bucket Setup
-
Create R2 bucket:
- Name:
hyperscape-assets - Location: Automatic (Cloudflare chooses optimal location)
- Name:
-
Configure custom domain:
- Go to R2 bucket → Settings → Custom Domains
- Add
assets.hyperscape.club - Create DNS record as instructed by Cloudflare
-
Configure CORS:
Or manually via Wrangler:
Upload Assets
Assets are uploaded separately (not part of client deployment):packages/server/world/assets/→ R2 bucket- Preserves directory structure
- Skips unchanged files (checksum comparison)
Custom Domains
Primary Domain (hyperscape.gg)
-
In Cloudflare Pages:
- Go to project → Settings → Custom domains
- Add
hyperscape.gg - Add
www.hyperscape.gg(optional redirect)
-
DNS Configuration:
- Cloudflare will show required DNS records
- If using Cloudflare DNS, records are added automatically
- If using external DNS, create CNAME records as shown
-
SSL/TLS:
- Cloudflare automatically provisions SSL certificates
- Wait for certificate status to become “Active”
Asset Domain (assets.hyperscape.club)
-
In R2 bucket:
- Go to Settings → Custom Domains
- Add
assets.hyperscape.club
-
DNS Configuration:
- Create CNAME record:
assets.hyperscape.club→<bucket-id>.r2.cloudflarestorage.com - Cloudflare will show the exact target
- Create CNAME record:
CORS Configuration
Why CORS is Needed
The client (hyperscape.gg) loads assets from a different origin (assets.hyperscape.club), requiring CORS headers.R2 CORS Configuration
Thescripts/configure-r2-cors.sh script configures:
* (all origins) - safe for public read-only assets
Allowed methods: GET, HEAD - read-only access
Exposed headers: ETag - for cache validation
Max age: 3600 seconds (1 hour) - browser caches CORS preflight
Verify CORS
Environment Variables
Build-Time Variables
Set in.github/workflows/deploy-pages.yml:
Runtime Variables
Cloudflare Pages does not support runtime environment variables for static sites. All configuration must be set at build time.Deployment URLs
Production
- Client: https://hyperscape.gg
- Assets: https://assets.hyperscape.club
- Game Server: https://hyperscape-production.up.railway.app
- WebSocket: wss://hyperscape-production.up.railway.app/ws
Preview
Each commit gets a preview URL:- Format:
https://<commit-hash>.hyperscape.pages.dev - Example:
https://50f1a285aa6782ead0066d21616d98a238ea1ae3.hyperscape.pages.dev
Troubleshooting
Assets not loading (404 errors)
Symptom: Console errors likeFailed to load resource: https://assets.hyperscape.club/models/player/human.glb
Causes:
- Assets not uploaded to R2
- CORS not configured
- Custom domain not set up
CORS errors
Symptom: Console errorAccess to fetch at 'https://assets.hyperscape.club/...' from origin 'https://hyperscape.gg' has been blocked by CORS policy
Fix:
Build failures
Symptom: GitHub Actions workflow fails during build Common causes:- TypeScript errors
- Missing dependencies
- Out of memory
WebSocket connection failures
Symptom: Client cannot connect to game server Causes:PUBLIC_WS_URLpointing to wrong server- Railway server not running
- CORS/Origin validation failing
- Verify
PUBLIC_WS_URLin workflow matches Railway server - Check Railway deployment status
- Verify server allows
hyperscape.ggorigin (see docs/csrf-cross-origin.md)
Advanced Configuration
Multiple Environments
To deploy to staging/preview environments:- Create separate Pages project:
hyperscape-staging - Update workflow to deploy to different project based on branch:
Custom Build Configuration
Editpackages/client/vite.config.ts to customize:
- Output directory
- Asset optimization
- Code splitting
- Source maps
Caching Strategy
Cloudflare Pages automatically caches:- HTML: No cache (always fresh)
- JS/CSS: Immutable (hashed filenames)
- Assets: Long cache (1 year)
packages/client/public/_headers:
Monitoring
Deployment Status
Check deployment status in:- GitHub Actions: Actions tab → Deploy Client to Cloudflare Pages
- Cloudflare Dashboard: Pages → hyperscape → Deployments
Analytics
Cloudflare Pages provides:- Web Analytics: Visitor stats, page views, bandwidth
- Real User Monitoring: Performance metrics, Core Web Vitals
- Error tracking: JavaScript errors, failed requests
Logs
View deployment logs:- GitHub Actions: Click on workflow run → View logs
- Cloudflare: Pages → hyperscape → Deployments → View build log
Related Documentation
- docs/vast-deployment.md - Vast.ai GPU streaming deployment
- docs/railway-dev-prod.md - Railway game server deployment
- docs/webgpu-requirements.md - Browser requirements
- .github/workflows/deploy-pages.yml - Deployment workflow
- packages/client/wrangler.toml - Wrangler configuration
- scripts/configure-r2-cors.sh - CORS setup script