A browser-based Mixed Reality (MR) racing game client that allows users to control physical Unmanned Ground Vehicles (UGVs) through an augmented reality interface.
- Frontend Framework: React with TypeScript
- Build Tool: Vite
- 3D Rendering: three.js
- AR Processing: js-aruco for marker detection
- Real-time Communication: WebRTC, WebSocket
- Styling: Tailwind CSS
- Node Version: v22.15.0 (LTS)
- Package Manager: npm v10.9.2
src/
├── engine/ # Core game engine (framework-agnostic)
│ ├── core/ # Main engine coordination
│ │ └── Engine.ts # Central engine manager
│ ├── renderer/ # Three.js rendering
│ │ ├── SceneManager.ts # Scene and rendering
│ │ └── CameraManager.ts # Camera handling
│ ├── ar/ # Augmented reality
│ │ └── ARManager.ts # Marker detection/tracking
│ └── network/ # Real-time communication
│ └── WebRTCManager.ts # Video streaming
├── hooks/ # Custom React hooks
├── utils/ # Utility functions
└── types/ # TypeScript type definitions
└── js-aruco.d.ts # AR library types
- Button: Customizable button with variants (primary, secondary, danger), sizes, and loading state
- Modal: Accessible modal dialog with backdrop blur and dark theme
- LoadingState: Loading indicator with multiple variants and sizes
- AppLayout: Base application layout with loading state management
- GameLayout: Game-specific layout with AR canvas and HUD layers
- WelcomeScreen: Landing page with quick play, custom game, settings, and tutorial options
- LobbyScreen: (Coming soon) Browse and create race sessions
- RaceScreen: (Coming soon) Main game interface with AR view and controls
- ResultsScreen: (Coming soon) Post-race summary and leaderboard
The project uses Tailwind CSS for styling, providing:
- Custom gaming theme with dark mode by default
- Responsive design utilities
- GPU-accelerated animations
- Modern backdrop blur effects
- Consistent spacing and typography
- Three.js-based scene management
- Efficient resource handling and cleanup
- Automatic window resize handling
- Shadow and lighting support
- Real-time marker detection using js-aruco
- 3D pose estimation from 2D markers
- Camera calibration support
- Smooth marker tracking
The system uses js-aruco's POSIT (Pose from Orthography and Scaling with ITerations) algorithm for 3D pose estimation:
interface Marker {
id: number;
corners: { x: number; y: number }[];
center: { x: number; y: number };
pose?: {
bestError: number;
bestRotation: number[][]; // 3x3 rotation matrix
bestTranslation: number[]; // [x, y, z] translation vector
alternativeError: number;
alternativeRotation: number[][];
alternativeTranslation: number[];
};
}
The system handles three different coordinate spaces:
-
Video Space (2D)
- Origin: Top-left corner of video
- X: Right, Y: Down
- Units: Pixels
-
js-aruco POSIT Space (3D)
- Origin: Camera center
- Y-axis: Down (screen coordinates)
- Z-axis: Into marker (away from camera)
- Units: Millimeters (based on MARKER_SIZE_MM)
- Right-handed coordinate system
-
THREE.js Scene Space (3D)
- Origin: Center of screen
- Y-axis: Up
- Z-axis: Toward camera
- Units: Scene units (normalized)
- Right-handed coordinate system
- Video to Scene Space (2D Positioning)
// For X coordinates
x = ((marker.x / videoWidth) - 0.5) * 2 * scaleX * VIDEO_SCALE
// For Y coordinates (flip Y axis)
y = (0.5 - (marker.y / videoHeight)) * 2 * scaleY * VIDEO_SCALE
- POSIT to THREE.js Rotation Matrix
// Convert POSIT rotation matrix to THREE.js coordinate system
rotationMatrix.set(
r[0][0], r[0][1], -r[0][2], 0, // Keep X, flip Z
r[1][0], r[1][1], -r[1][2], 0, // Keep X/Y, flip Z
-r[2][0], -r[2][1], r[2][2], 0, // Flip X/Y for Z-up
0, 0, 0, 1
);
The video background can be configured with the following parameters:
interface VideoPlaneConfig {
distance?: number; // Distance from camera (default: 0.1)
baseHeight?: number; // Base height in world units (default: 4.0)
scale?: number; // Additional scale factor (default: 1.0)
}
Example usage in ARManager:
videoBackground.initialize(videoElement, {
distance: 0.1, // Closer to camera = larger view
baseHeight: 2.0, // Base size of video plane
scale: 1.5 // Additional scaling if needed
});
Tips for configuration:
- Decrease
distance
to make video appear larger
-
Marker Tracking
- Uses video coordinates for X/Y positioning to ensure accurate screen tracking
- POSIT's Z-translation provides depth perception
- Scale factor (0.0001) converts millimeters to scene units
-
Rotation Handling
- Maintains proper axis alignment between coordinate systems
- Preserves right-handed coordinate system properties
- Correctly handles all rotation axes (X, Y, Z)
-
Corner Visualization
- Corner markers follow marker in screen space
- Positions updated relative to marker center
- Transformed to local space for proper rotation
-
Performance Optimization
- Marker detection every 3rd frame
- Efficient matrix transformations
- Minimal coordinate system conversions
The application includes debug tools to help with development and testing. These tools provide real-time information about video sources, AR marker detection, and system performance.
Debug tools can be enabled in three ways:
-
Development Mode (Automatic)
- Debug tools are automatically enabled when running in development mode (
npm run dev
)
- Debug tools are automatically enabled when running in development mode (
-
Environment Variable
- Create a
.env.local
file in the project root:VITE_DEBUG_TOOLS_ENABLED=true
- Or set the variable before running:
VITE_DEBUG_TOOLS_ENABLED=true npm run dev
- Create a
-
Browser Storage
- Open browser console and run:
localStorage.setItem('DEBUG_TOOLS_ENABLED', 'true');
- Refresh the page
- Open browser console and run:
-
Video Source Debug Panel
- Video source status and controls
- Resolution and frame rate information
- Source switching options
-
AR Debug Panel
- Marker detection statistics
- Detection FPS counter
- Current and total markers detected
- Error tracking
- Frame skip monitoring
-
Visual Debugging
- Wireframe marker visualization
- Corner point indicators
- Axes helpers for orientation
- Grid overlay for spatial reference
- Increase
baseHeight
for larger base size - Use
scale
for fine-tuning the final size - Keep
distance
> 0.1 to avoid z-fighting
- WebRTC video streaming
- Peer connection management
- Signaling protocol support
- Connection state handling
- Ensure you have Node.js installed (preferably using nvm)
nvm install # Installs Node version from .nvmrc
nvm use # Switches to the project's Node version
- Install dependencies
npm install
- Start development server
npm run dev
# Run without debug logs
npm run build && npm run preview
- 30 FPS AR overlay minimum
- < 200ms control latency
- Marker detection every 3rd frame
- Efficient memory management
- Mobile device optimization
- Chrome (desktop & mobile)
- Firefox (desktop & mobile)
- Safari (desktop & iOS)
npm run build
- Maintain the hybrid architecture pattern
- Keep real-time operations in the core engine
- Use React only for non-critical UI
- Follow TypeScript best practices
- Document performance-critical code
[License information pending]
This is a simple 3D game prototype built with React, Three.js and RAPIER physics.
The codebase follows a modular architecture with clear separation of concerns:
core/physics/GamePhysicsSystem.ts
- RAPIER-based physics systemcore/renderer/GameRenderSystem.ts
- Three.js rendering and visual effectscore/input/InputController.ts
- Keyboard input handlingcore/game/GameLoop.ts
- Main game loop and logic
components/screens/TestGameScreen.tsx
- Main game screen componentcomponents/hud/GameHUD.tsx
- HUD display for game information
shared/types/GameTypes.ts
- Common type definitions
To adjust the movement and rotation settings, modify these values in src/engine-layer/core/game/GameLoop.ts
:
// Line ~82: Rotation speed (higher = faster turning)
const rotationSpeed = 3.0;
// Line ~87: Movement speed (higher = faster acceleration)
const speed = 8.0;
// Line ~88: Maximum velocity cap (higher = faster top speed)
const maxVelocity = 3.0;
// Line ~126: Acceleration smoothing (higher = more responsive)
const lerpFactor = 0.2;
// Line ~146: Braking strength (lower = slower braking)
// currentVel.x * 0.15
- W / Up Arrow: Move forward
- S / Down Arrow: Move backward
- A / Left Arrow: Turn left
- D / Right Arrow: Turn right
This game prototype uses React for the UI components and Three.js for 3D rendering, with RAPIER providing the physics simulation.
To modify the game's visuals, such as the track and objects, see GameRenderSystem.ts
.
To adjust physics behavior or collision detection, see GamePhysicsSystem.ts
.