Coordinate System & Cameras
Understanding the engine's spatial orientation and camera strategies is essential for spatial logic, culling, and input.
Right-Handed Coordinate System
Small World uses a right-handed coordinate system:
- X axis (+X): Right
- Y axis (+Y): Up
- Z axis (+Z): Backward (pointing out of the screen)
- -Z axis (-Z): Forward / front (pointing into the screen)
+Y
^ -Z (Forward)
| /
| /
|/
+-------> +X (Right)
/
/
+Z (Backward)Camera Control & Look Formulas
When writing custom look/orbit math or relative movement controls (e.g. WASD), use look-relative trigonometry:
- Angular orientation: Theta ($\theta$) and Phi ($\phi$) are defined relative to the $-Z$ vector.
- Direction vector: $$\text{dirX} = \sin(\theta) \cdot \cos(\phi)$$ $$\text{dirY} = \sin(\phi)$$ $$\text{dirZ} = -\cos(\theta) \cdot \cos(\phi)$$
Camera Strategies
The camera system supports several strategy patterns:
- Fixed Camera: Constant position and target. Used for isometric backdrops.
- Smooth Follow: Linearly interpolates position and target toward a target Object3D, damping the focus.
- FPS Camera: Full mouse-/keyboard-relative look control and WASD movement. Supports terrain-height snapping.
- Isometric Camera: Parallel orthographic projections with pixel-precise viewport snapping.
typescript
// Lock in the FPS strategy during setup
this.camera.setStrategy(CameraStrategyType.FPS);
this.camera.addBehavior(
new FPSController({
moveSpeed: 8.0,
enableCollision: false,
scene: this.scene,
}),
);Frustum Culling
To maximize performance, the engine dynamically discards geometry outside the field of view via frustum culling:
typescript
// Called internally within the renderer's render-list builder
if (frustum.intersectsVolume(object.bounds)) {
renderList.opaque.add(object);
}All geometries dynamically compute an axis-aligned bounding box (AABB). Frustum culling can be disabled for static background overlays by setting frustumCulled = false on an object (e.g. a skybox).
2.5D Backgrounds & Texture Orientation
When creating 2.5D matte paintings, UI backgrounds, or billboards:
- Use
Planegeometry: Always usePlane({ width, height })for flat backgrounds.Planegenerates standard UV coordinates ($U \in [0, 1]$ left to right, $V \in [1, 0]$ top to bottom), facing $+Z$. - WebGL texture vertical flip (
flipY) & WebP format: DOM/HTML images have their pixel origin $(0,0)$ at the top left, while WebGL texture coordinates start at $(0,0)$ at the bottom left. Always pass{ flipY: true }when loading textures. Prefer WebP (.webp) over JPEG for 2D art, to avoid dark block artifacts and to enable alpha-channel transparency for foreground layers:typescriptconst bgTex = await Texture.fromUrl("/assets/path/image.webp", { flipY: true }); - No negative-scale hacks: Never apply negative scale factors (e.g.
scale.set(-1, -1, 1)) to 3D objects to mirror textures. Negative scale reverses spatial parity, flips the winding order, and mirrors horizontal coordinates (swapping left and right). - 16:9 aspect ratio standard: Standardize 2.5D background planes and AI-generated matte paintings on a 16:9 ratio (e.g.
Plane({ width: 16, height: 9 })). Centering at $Y = 4.5$ aligns the bottom edge flush with the stage floor at $Y = 0.0$.