3D Projections

The 3D library supports five projection types for converting 3D scenes to 2D representations, plus an orbital camera system.

Projection Types

setProjection3D(type, config)

Change the active projection for the 3D scene.

app.setProjection3D('perspective', { fov: 60 });
app.setProjection3D('isometric');
app.setProjection3D('cabinet', { angle: 45, scale: 0.5 });

Perspective

Mimics human vision with realistic depth perception. Objects farther away appear smaller.

app.setProjection3D('perspective', {
  fov: 60,       // Field of view in degrees (default: 60)
  aspect: 1,     // Aspect ratio (default: 1)
  near: 0.1,     // Near clipping plane (default: 0.1)
  far: 1000      // Far clipping plane (default: 1000)
});

Best for: Realistic 3D scenes, product visualization, games

Orthographic

Maintains parallel lines and true proportions. No perspective foreshortening.

app.setProjection3D('orthographic', {
  width: 400,    // View width (default: 400)
  height: 400,   // View height (default: 400)
  near: -500,    // Near plane (default: -500)
  far: 500       // Far plane (default: 500)
});

Best for: Technical drawings, architectural plans, UI elements

Isometric

Classic 30-degree axonometric view with equal visual weight on all three axes.

app.setProjection3D('isometric', {
  scale: 1       // Scale factor (default: 1)
});

Internally applies rotations of ~35.264° (X) and 45° (Y) to achieve the standard isometric angle.

Best for: Strategy games, architectural diagrams, infographics

Cabinet

Oblique projection with depth scaled to half, popular in technical illustration.

app.setProjection3D('cabinet', {
  angle: 45,     // Shear angle in degrees (default: 45)
  scale: 0.5     // Depth scale factor (default: 0.5)
});

Best for: Furniture drawings, mechanical parts, technical manuals

Cavalier

Oblique projection with full depth scale (no depth reduction).

app.setProjection3D('cavalier', {
  angle: 45      // Shear angle in degrees (default: 45)
});

Identical to cabinet but with scale: 1.0 — depth lines are not shortened.

Best for: Military projections, simple 3D diagrams

Projection Comparison

Projection Depth Reduction Parallel Lines Realistic Use Case
Perspective Yes (1/z) No Yes Visualization
Orthographic No Yes No Technical
Isometric No Yes No Games/Infographics
Cabinet Half (0.5) Yes Partial Technical
Cavalier No Yes No Diagrams

Camera

setCamera3D(config)

Set the 3D camera position, target, and up vector.

app.setCamera3D({
  position: { x: 3, y: 2, z: 5 },
  target: { x: 0, y: 0, z: 0 },
  up: { x: 0, y: 1, z: 0 }
});

Parameters:

Param Type Default Description
position {x,y,z} {x:0, y:0, z:5} Camera position in world space
target {x,y,z} {x:0, y:0, z:0} Point the camera looks at
up {x,y,z} {x:0, y:1, z:0} Up direction vector

Standalone Camera API

import * as Camera3D from './js/3d/projection/Camera3D.js';

// Create camera
const camera = Camera3D.createCamera({
  position: { x: 0, y: 0, z: 5 },
  target: { x: 0, y: 0, z: 0 }
});

// Get view matrix (4x4 lookAt matrix)
const viewMatrix = Camera3D.getViewMatrix(camera);

// Orbit around target (horizontal and vertical angles in radians)
const orbited = Camera3D.orbit(camera, Math.PI / 6, Math.PI / 12);

// Re-target while maintaining distance
const retargeted = Camera3D.lookAtTarget(camera, { x: 1, y: 0, z: 0 });

Orbit constraints: Elevation is clamped to [0.01, PI-0.01] radians to prevent gimbal lock at the poles.

Standalone Projection API

import * as Projections from './js/3d/projection/Projections.js';

// Get projection matrix by name
const projMatrix = Projections.getProjection('perspective', { fov: 60 });

// Project 3D vertices to 2D screen coordinates
const result = Projections.projectVertices(
  vertices3D,      // Array of {x, y, z}
  viewProjMatrix,  // Combined view * projection matrix
  halfWidth,       // Canvas width / 2
  halfHeight       // Canvas height / 2
);
// result: { vertices2D: [{x, y}, ...], depth: number }

Coordinate system: Screen Y is flipped (screenY = -ndcY * halfH + halfH) to match canvas conventions where Y increases downward.