@cinevva/rt — Cinevva Game Runtime
A tiny, versioned, CDN-hosted component library for browser Three.js games. It owns the sign-bearing player-controls math (camera, movement, gravity, collision) so a game never has to write it. Hand-rolled control rigs ship inverted signs constantly (W walks backward, mouse-look pitches the wrong way, camera clips into walls); this library is correct by construction and regression-tested.
Peer dependency: three (resolved from the host game's import map). Nothing else.
Versioning
Immutable, path-versioned on the CDN:
https://cdn.cinevva.com/rt/1.0.0/controls.mjs— exact, never changes.https://cdn.cinevva.com/rt/1/controls.mjs— latest non-breaking1.x(gets bug fixes).
Pin to rt/1/ for automatic fixes, or rt/1.0.0/ for a frozen build. Breaking changes ship under rt/2/.
controls.mjs — createControls(options)
One call gives you a first-person, third-person, or top-down player with movement, gravity, jump, wall/ground collision, mouse-look, and mobile touch controls (on-screen joystick + drag-look + jump button, auto-enabled on touch devices).
import * as THREE from 'three';
import { createControls } from 'https://cdn.cinevva.com/rt/1/controls.mjs';
// ...set up renderer, scene, camera, and a `player` Object3D added to the scene...
const controls = createControls({
mode: 'thirdPerson', // 'fps' | 'thirdPerson' | 'topDown'
camera,
renderer, // (or pass domElement) — where pointer-lock / touch attach
scene, // colliders default to every mesh in the scene except the player
target: player, // the Object3D the controls move
});
renderer.setAnimationLoop(() => {
const dt = clock.getDelta();
const s = controls.update(dt); // moves player + camera, returns state
renderer.render(scene, camera);
});controls.update(dt) returns per-frame state you can drive animation from:
{
name: 'idle' | 'walk' | 'run' | 'jump' | 'fall' | 'land',
position: { x, y, z },
velocity: { x, y, z },
grounded: boolean,
facing: number, // radians, target's Y rotation
moving: boolean,
}Options
| option | default | meaning |
|---|---|---|
mode | 'thirdPerson' | 'fps', 'thirdPerson', or 'topDown' |
camera | — | required. Your THREE.Camera. |
target | — | required. The Object3D to move (the player body). In fps you can hide it. |
scene | — | scene to auto-collect colliders from (needed for collision unless you pass colliders) |
renderer / domElement | document.body | element that receives pointer-lock and touch input |
colliders | auto | explicit array of meshes to collide against (overrides autoColliders) |
moveSpeed | 6 | m/s walk speed |
runMultiplier | 1.8 | Shift-to-run multiplier |
jumpSpeed | 8 | initial jump velocity |
gravity | -22 | m/s² |
radius / height | 0.35 / 1.8 | capsule size for collision |
slopeLimitDeg | 55 | steeper ground blocks like a wall |
distance | 6 | third-person boom length / top-down camera height |
lookSensitivity | 0.0025 | mouse/touch look speed |
invertY | false | invert vertical look |
cameraCollision | true | third-person anti-clip: the camera pulls in when a wall is behind the player, so you never get "camera/arm in my face" |
pointerLock | true | fps/third-person grab the pointer on click for mouse-look |
enableTouch | true | auto-show the mobile joystick + jump button on touch devices |
Controls given to the player
- Desktop: WASD / arrows to move, mouse to look (click to capture), wheel to zoom (third-person/top-down), Shift to run, Space to jump.
- Mobile: left-thumb virtual joystick to move, right-thumb drag to look, on-screen jump button. Auto-enabled; no extra code.
Notes
- Collision is raycast-based against your scene meshes: a downward ray for ground height/normal and a forward ray per axis for walls (so you slide along walls). Good for flat ground, platforms, mazes, and props. Very dense scenes or thin fast-moving geometry may want custom handling.
- Movement is always resolved against the camera yaw (except top-down, which uses fixed screen axes), so "forward" is always where the camera looks. This is the single most common bug in hand-written rigs, fixed here.
- Call
controls.dispose()to remove all listeners and the touch UI.
Roadmap
anim.mjs(v1.1) —AutoAnimator: feed it thestate.name+velocityfromcontrols.update()and a GLTF character on the Quaternius universal skeleton, and it cross-fades idle/walk/run/jump/fall/land clips automatically. Sourced from Cinevva World's resolver-driven animation FSM.