Overview
The @hyperscape/client package is the web game client:
- Vite for fast builds with HMR
- React 19 UI framework
- Three.js 3D rendering (WebGPU with WebGL fallback)
- Privy authentication
- Farcaster miniapp SDK
- Tauri desktop app support
- Solana wallet integration
Rendering
WebGPU with WebGL Fallback
The client uses THREE.WebGPURenderer with automatic fallback to WebGL for compatibility:
WebGPU (Preferred):
- Modern high-performance rendering
- TSL post-processing effects
- Cascaded shadow maps (CSM)
- Requires Chrome 113+, Edge 113+, or Safari 17+
WebGL (Fallback):
- Graceful degradation for older browsers and WebViews
- Single directional shadow maps (no CSM)
- Disabled TSL post-processing
- Works in WKWebView (Tauri), older Safari, and browsers without WebGPU
Backend Detection:
import { isWebGPURenderer, getRendererBackend } from "@hyperscape/shared";
const renderer = await createRenderer();
const isWebGPU = isWebGPURenderer(renderer); // true or false
const backend = getRendererBackend(renderer); // "webgpu" or "webgl"
The settings panel displays the active renderer type to users.
Package Location
packages/client/
├── src/
│ ├── auth/ # Privy authentication
│ ├── constants/ # Client constants
│ ├── game/ # Game loop and logic
│ │ ├── character/ # Character rendering
│ │ ├── chat/ # Chat system
│ │ ├── components/ # Game-specific components
│ │ ├── dashboard/ # Agent dashboard
│ │ ├── hud/ # HUD elements
│ │ ├── interface/ # Interface manager
│ │ ├── panels/ # Game panels (inventory, bank, combat, etc.)
│ │ ├── systems/ # Client-side game systems
│ │ └── types/ # Game type definitions
│ ├── hooks/ # React hooks
│ ├── lib/ # Networking, utilities, error handling
│ ├── screens/ # UI screens
│ ├── types/ # TypeScript types
│ ├── ui/ # UI system
│ │ ├── components/ # Reusable UI components (Window, TabBar, Portal, etc.)
│ │ ├── controls/ # Form controls (Slider, Toggle, Select, etc.)
│ │ ├── core/ # Core UI systems (drag-and-drop, window management, presets)
│ │ ├── stores/ # Zustand state stores
│ │ ├── theme/ # Theme system
│ │ └── types/ # UI type definitions
│ ├── utils/ # Helper functions
│ └── index.tsx # React entry point
├── public/ # Static assets (fonts, textures, LUTs)
├── tests/ # E2E (Playwright) and unit tests (Vitest)
├── scripts/ # Deployment scripts
├── vite.config.ts # Vite configuration
├── vitest.config.ts # Vitest configuration
├── playwright.config.ts # E2E test configuration
├── wrangler.toml # Cloudflare Pages config
└── .env.example # Environment template
Screens
Located in src/screens/:
// From packages/client/src/screens/
LoginScreen.tsx // Privy authentication
LoadingScreen.tsx // Asset loading
UsernameSelectionScreen.tsx // First-time username
CharacterSelectScreen.tsx // Choose character
CharacterEditorScreen.tsx // Create/edit character with VRM preview
DashboardScreen.tsx // Game hub / lobby
GameClient.tsx // Main 3D gameplay
AdminScreen.tsx // Admin dashboard
| Screen | Purpose |
|---|
LoginScreen | Privy authentication |
UsernameSelectionScreen | First-time username entry |
CharacterSelectScreen | Choose existing character |
CharacterEditorScreen | Create/edit character (VRM preview) |
DashboardScreen | Game hub and lobby |
GameClient | Main 3D gameplay |
LoadingScreen | Asset loading state |
AdminScreen | Admin dashboard and tools |
UI System Architecture
UI System (src/ui/)
Complete UI system with components, hooks, stores, and theming:
src/ui/
├── components/ # UI components (45+ files)
│ ├── Window.tsx # Draggable, resizable windows
│ ├── Tab.tsx # Tab component
│ ├── TabBar.tsx # Tab container
│ ├── Slider.tsx # Range slider
│ ├── Portal.tsx # React portal
│ ├── MenuButton.tsx # Menu buttons
│ ├── ActionBar.tsx # Action bar
│ ├── BuffBar.tsx # Buff display
│ ├── ItemSlot.tsx # Inventory slot
│ ├── Minimap.tsx # Minimap component
│ ├── ScrollableArea.tsx # Scrollable containers
│ ├── VirtualList.tsx # Virtual scrolling
│ ├── VirtualGrid.tsx # Virtual grid
│ └── ...
├── controls/ # Form controls
│ ├── ColorControl.tsx
│ ├── KeybindControl.tsx
│ ├── SelectControl.tsx
│ ├── SliderControl.tsx
│ └── ToggleControl.tsx
├── core/ # Core UI systems
│ ├── drag/ # Drag-and-drop (@dnd-kit)
│ ├── edit/ # Edit mode (L key unlock)
│ ├── notifications/ # Toast notifications
│ ├── presets/ # Layout presets and cloud sync
│ ├── responsive/ # Breakpoints, mobile layout
│ ├── settings/ # Settings schema
│ ├── tabs/ # Tab management
│ ├── tooltip/ # Progressive tooltips
│ ├── virtual/ # Virtual scrolling
│ └── window/ # Window management
├── stores/ # Zustand stores
│ ├── windowStore.ts # Window state
│ ├── themeStore.ts # Theme state
│ ├── dragStore.ts # Drag state
│ ├── editStore.ts # Edit mode state
│ ├── presetStore.ts # Layout presets
│ ├── keybindStore.ts # Keybindings
│ ├── notificationStore.ts # Notifications
│ ├── accessibilityStore.ts # Accessibility
│ ├── complexityStore.ts # UI complexity
│ └── questStore.ts # Quest tracking
├── theme/ # Theme system
│ ├── themes.ts # Dark theme
│ └── animations.ts # CSS animations
└── types/ # TypeScript types
Game Components (src/game/components/)
Domain-organized game UI components:
src/game/components/
├── chat/ # Chat system
│ ├── ChatBox.tsx
│ ├── ChatMessage.tsx
│ ├── ChatInput.tsx
│ └── ChatTabs.tsx
├── currency/ # Currency display
│ ├── CurrencyDisplay.tsx
│ ├── CurrencyExchange.tsx
│ ├── CurrencyIcon.tsx
│ ├── CurrencyInput.tsx
│ └── CurrencyTooltip.tsx
├── dialog/ # NPC dialogue
│ ├── DialogBox.tsx
│ ├── DialogChoices.tsx
│ ├── DialogHistory.tsx
│ ├── DialogPortrait.tsx
│ └── DialogText.tsx
├── equipment/ # Equipment panel
│ ├── CharacterModel.tsx
│ ├── EquipmentPanel.tsx
│ ├── EquipmentSlot.tsx
│ ├── ItemComparison.tsx
│ └── StatsSummary.tsx
├── map/ # World map
│ ├── WorldMap.tsx
│ ├── MapControls.tsx
│ ├── MapMarker.tsx
│ ├── MapLegend.tsx
│ └── MapTooltip.tsx
├── quest/ # Quest system
│ ├── QuestLog.tsx
│ ├── QuestEntry.tsx
│ ├── QuestObjective.tsx
│ ├── QuestRewards.tsx
│ └── QuestTracker.tsx
├── settings/ # Settings panel
│ ├── SettingsPanel.tsx
│ ├── SettingsCategory.tsx
│ └── SettingsControl.tsx
└── skilltree/ # Skill tree
├── SkillTree.tsx
├── SkillNode.tsx
├── SkillConnection.tsx
└── SkillTooltip.tsx
HUD Components (src/game/hud/)
src/game/hud/
├── StatusBars.tsx # Health/Constitution display
├── ActionProgressBar.tsx # Action progress
├── Minimap.tsx # World minimap
├── MinimapCompass.tsx # Compass overlay
├── MinimapStaminaBar.tsx # Stamina indicator
├── MinimapOverlayControls.tsx
├── RadialMinimapMenu.tsx # Radial menu
├── HomeTeleportButton.tsx # Teleport home
├── ContextMenu.tsx # Right-click menus
├── EntityContextMenu.tsx # Entity interactions
├── EscapeMenu.tsx # Pause menu
├── ConnectionIndicator.tsx # Network status
├── level-up/ # Level-up system
│ ├── LevelUpNotification.tsx
│ ├── LevelUpPopup.tsx
│ └── UnlocksSection.tsx
├── overlays/ # Screen overlays
│ ├── DeathScreen.tsx
│ ├── DisconnectedOverlay.tsx
│ └── KickedOverlay.tsx
└── xp-orb/ # XP progress orbs
├── XPProgressOrb.tsx
├── XPProgressOrbs.tsx
└── FloatingXPDrops.tsx
Anchor-Based Positioning
Windows use Unity/Unreal-style anchors for responsive scaling:
- 9 anchor points: corners, edges, center
- Offset-based: Windows store offset from anchor, not absolute position
- Responsive: Preserves anchor relationships on resize
- Default anchors:
- Chat, Skills/Prayer:
bottom-left
- Minimap:
top-right
- Inventory, Menubar:
bottom-right
- Action bar:
bottom-center
Drag-and-Drop System
Powered by @dnd-kit with custom enhancements:
- Inventory items: Drag to move, combine, or drop
- Action bar: Drag skills, prayers, combat styles
- Tabs: Drag to reorder or combine windows
- Windows: Drag headers to move
- Context menus: Right-click for OSRS-style menus
Environment Variables
Development
# Required for persistent authentication
PUBLIC_PRIVY_APP_ID=your-privy-app-id
# Server URLs (defaults to localhost)
PUBLIC_API_URL=http://localhost:5555
PUBLIC_WS_URL=ws://localhost:5555/ws
PUBLIC_CDN_URL=http://localhost:8080
Production (Cloudflare Pages)
# Required
PUBLIC_PRIVY_APP_ID=your-privy-app-id
# Production endpoints
PUBLIC_API_URL=https://hyperscape-production.up.railway.app
PUBLIC_WS_URL=wss://hyperscape-production.up.railway.app/ws
PUBLIC_CDN_URL=https://assets.hyperscape.club
PUBLIC_APP_URL=https://hyperscape.club
# Optional
PUBLIC_ENABLE_FARCASTER=true
DEBUG_RPG=0
PUBLIC_PRIVY_APP_ID must match the PRIVY_APP_ID set in the server environment. Mismatched IDs will cause authentication failures.
All PUBLIC_* variables are exposed to the browser. Never put secrets in client environment variables.
Running
Development
bun run dev:client # Vite dev server with HMR
Opens at http://localhost:3333
Production Build
cd packages/client
bun run build # Build to dist/
bun run preview # Preview production build
Dependencies
| Package | Purpose |
|---|
react | UI framework (v19) |
react-dom | React DOM renderer |
three | 3D rendering (v0.181) |
@hyperscape/shared | Core engine |
@privy-io/react-auth | Authentication |
@farcaster/miniapp-sdk | Farcaster integration |
@dnd-kit/core | Drag-and-drop core |
@dnd-kit/sortable | Sortable lists |
@pixiv/three-vrm | VRM avatar support |
@solana/wallet-adapter-react | Solana wallet |
@tauri-apps/api | Desktop app integration |
livekit-client | Voice chat |
lucide-react | Icons |
d3 | Data visualization |
tailwindcss | Utility CSS |
vite | Build tool |
Deployment
Cloudflare Pages (Production)
The client deploys to Cloudflare Pages with automatic GitHub integration:
Configuration:
- Build command:
cd packages/client && bun install && bun run build
- Build output:
packages/client/dist
- Root directory:
/ (monorepo root)
- Node version: 22
Environment Variables (Cloudflare Pages):
PUBLIC_PRIVY_APP_ID=<from-privy-dashboard>
PUBLIC_API_URL=https://hyperscape-production.up.railway.app
PUBLIC_WS_URL=wss://hyperscape-production.up.railway.app/ws
PUBLIC_CDN_URL=https://assets.hyperscape.club
PUBLIC_APP_URL=https://hyperscape.club
Deployment Process:
- Push to
main branch
- Cloudflare Pages detects changes to
packages/client/**
- Builds client with Vite
- Deploys to
hyperscape.pages.dev and hyperscape.club
- Creates preview deployments for pull requests
Preview Deployments:
- URL pattern:
https://<branch>-<hash>.hyperscape.pages.dev
- Automatic for every PR
- Uses production environment variables
- CORS automatically allows
*.hyperscape.pages.dev origins
Vite Configuration
// packages/client/vite.config.ts
export default defineConfig({
envPrefix: 'PUBLIC_', // Expose PUBLIC_* vars to client
build: {
outDir: 'dist',
sourcemap: true,
rollupOptions: {
output: {
manualChunks: {
'three': ['three'],
'react': ['react', 'react-dom']
}
}
}
}
});
Only PUBLIC_* prefixed environment variables are exposed to the client. Never put secrets in client environment variables.
Key Files
| File | Purpose |
|---|
src/index.tsx | React entry point |
src/game/ | Game loop and logic |
src/screens/ | UI screens |
src/ui/ | UI system (windows, drag-drop, stores) |
vite.config.ts | Vite configuration |
vitest.config.ts | Unit test configuration |
playwright.config.ts | E2E test configuration |
wrangler.toml | Cloudflare Pages config |