A third-person 3D character controller playground built with React, Three.js, and real-time physics.
Perspecta is an experimental 3D web application showcasing a modular third-person character controller with physics, animation blending, camera presets, and multiple interactive environments.
The project is designed for:
- Frontend / graphics engineers exploring Three.js + React
- Developers prototyping game-like mechanics on the web
- Learning character movement, camera systems, and physics integration
It focuses on clean separation of concerns: rendering, physics, input, animation, and camera logic are all isolated and configurable at runtime.
- Third-person character controller with smooth animation blending
- Physics-based movement using Rapier
- Keyboard + touch input support
- Runtime-tunable controls via Leva
- Camera presets (near / far) with smooth follow & look-at
- Multiple GLTF environments with proper collision meshes
- Shadow-mapped lighting with orthographic shadow camera
- Modular, extensible architecture
- React 19
- @react-three/fiber
- Three.js
- @react-three/drei
- GLTF animations & assets
- @react-three/rapier (Rapier3D)
- Leva (live parameter tuning)
- KeyboardControls (abstracted input mapping)
- Vite
- TypeScript
- ESLint + Prettier
Perspecta is structured as a single-page 3D runtime, where React orchestrates lifecycle and configuration, and Three.js handles rendering and animation.
graph TD
App --> Canvas
Canvas --> Experience
Experience --> Physics
Physics --> Map
Physics --> CharacterController
CharacterController --> Character
CharacterController --> Camera
- App.tsx Bootstraps rendering, keyboard input, and loading state.
- Experience Sets up lighting, environment, physics world, and active map.
- CharacterController Handles input, movement logic, animation state, and camera following.
- Character Pure visual + animation layer.
- Map Loads environment GLTFs and attaches static colliders.
.
├── public/ # Static assets & icons
├── src/
│ ├── assets/ # GLB models & exports
│ ├── components/ # Core 3D & logic components
│ │ ├── character.tsx
│ │ ├── character-controller.tsx
│ │ ├── experience.tsx
│ │ └── map.tsx
│ ├── constants/ # Configurable runtime constants
│ │ ├── camera.ts
│ │ ├── character.ts
│ │ ├── keyboard-map.ts
│ │ └── maps.ts
│ ├── App.tsx # App entry
│ ├── main.tsx # React bootstrap
│ └── index.css
├── vite.config.ts
├── tsconfig.json
└── package.jsoncharacter-controller.tsx→ Movement, physics, camera, animation synccamera.ts→ Camera presets & Leva configmaps.ts→ Environment registry (scale, position, model)
sequenceDiagram
participant Input
participant Controller
participant Physics
participant Camera
participant Renderer
Input->>Controller: Keyboard / Touch input
Controller->>Controller: Compute direction & speed
Controller->>Physics: Apply linear velocity
Controller->>Renderer: Update animation state
Controller->>Camera: Update follow & lookAt
- Physics drives actual movement (no manual position updates)
- Animation updates only trigger on state change (idle / walk / run / wave)
- Camera smoothly interpolates toward target transforms
- Node.js ≥ 18
- npm
npm installnpm run devnpm run buildnpm run previewNo environment variables are required.
- W / A / S / D or Arrow keys → Move
- Shift → Run
- Enter / F → Wave animation
- Use Leva panel to:
- Switch maps
- Tune walk/run speed
- Adjust camera mode & offsets
Touch / mouse input is automatically detected and supported.
- Single-character, single-player only
- No networking or persistence
- Physics tuned for demo scale, not large worlds
- Mobile support is experimental
- Assets are static and preloaded
- Jumping & air control
- Slope & terrain handling
- Multiplayer / sync experiments
- Asset streaming & LODs
- State machines for animation logic
- Automated tests for control logic
- Performance profiling & optimizations
This project is licensed under the MIT License. See the for details.
