Tutorial
Coordinates and cameras
The coordinates
Section titled “The coordinates”Every scene uses the same axes: x to the right, y into the scene, z up. axes() draws them, so a reader never has to guess.
Drag to turn, scroll or pinch to zoom, double click to reset.
import { Scene, axes, box, ground, label } from 'cseen';
const s = new Scene();
s.add(ground(), axes({ length: 3.5 }));
const mid = { anchor: 'middle' } as const;
s.add(box({ at: [3, 0, 0], size: 0.8 }));
s.add(label('x = 3', [3, 0, 1.3], mid));
s.add(box({ at: [0, 3, 0], size: 0.8 }));
s.add(label('y = 3', [0, 3, 1.3], mid));
s.add(box({ at: [0, 0, 2], size: 0.8, role: 'accent' }));
s.add(label('z = 2', [0, 0, 3.3], mid));
Objects sit on the ground. box({ at: [x, y, 0] }) puts the centre of the box’s base at that point, so at is where it stands. A flat diagram is a scene seen from the front, with y as depth you do not use.
Parallel cameras
Section titled “Parallel cameras”The default camera is parallel (axonometric): lines that are parallel in the scene stay parallel on the page. This is the look of technical illustration, and the one where placing things on planes is exact.
Drag to turn, scroll or pinch to zoom, double click to reset.
import { Scene, axes, ground } from 'cseen';
import { laptop, phone } from 'cseen/devices';
// parallel: lines that are parallel in the scene stay parallel on the page
const s = new Scene({ view: { yaw: 40, pitch: 20 } });
s.add(ground(), axes({ at: [-3, -2, 0], length: 1.5 }));
s.add(laptop({ at: [-1.5, 0, 0], width: 2.6 }));
s.add(phone({ at: [1.6, -0.6, 0], height: 1.5 }));
import { Scene } from 'cseen';
// 'iso' | 'front' | 'side' | 'top'const s = new Scene({ view: 'top' });// or explicit angles in degreesconst t = new Scene({ view: { yaw: 40, pitch: 20 } });Yaw turns the scene about the vertical axis. Pitch tips it towards the viewer: 0 looks along the ground, 90 looks straight down. The window controls above each demo (Iso, Front, Side, Top) set these.
Perspective
Section titled “Perspective”For a vanishing point, use a pinhole camera. This is the same scene as above, seen from a point in space: compare the two.
Drag to turn, scroll or pinch to zoom, double click to reset.
import { Camera, Scene, axes, ground } from 'cseen';
import { laptop, phone } from 'cseen/devices';
// perspective: things shrink with distance, and lines meet at a vanishing point
const s = new Scene({ view: Camera.perspective({ position: [5, -9, 5], target: [0, 0, 1], fov: 35 }) });
s.add(ground(), axes({ at: [-3, -2, 0], length: 1.5 }));
s.add(laptop({ at: [-1.5, 0, 0], width: 2.6 }));
s.add(phone({ at: [1.6, -0.6, 0], height: 1.5 }));
import { Scene, Camera } from 'cseen';
const s = new Scene({ view: Camera.perspective({ position: [5, -9, 5], target: [0, 0, 1], fov: 35 }),});Try the Perspective button on any demo. Two things behave differently under perspective: an imported SVG can only be sheared by the renderer, so it is cut into small pieces and approximated, and charts placed on planes are approximate for the same reason.
Which camera
Section titled “Which camera”| You want | Use |
|---|---|
| A technical illustration, exact placement on planes | parallel: view: 'iso' or { yaw, pitch } |
| A flat diagram | parallel: view: 'front' or 'top' |
| Depth and a sense of space | Camera.perspective(...) |
| The reader chooses the angle | either, plus orbit controls |
Cameras animate
Section titled “Cameras animate”A camera is animatable like anything else: yaw, pitch and zoom for a parallel camera, position, target and fov for a perspective one.
import { Scene, Timeline, tween } from 'cseen';
const s = new Scene();const tl = new Timeline();tl.play(tween(s.camera, { yaw: 120, pitch: 40 }, { duration: 2 }));Drag to turn, scroll or pinch to zoom, double click to reset.
import { Scene, Timeline, axes, ground, tween, wait } from 'cseen';
import { cloud, laptop, phone } from 'cseen/devices';
const s = new Scene();
s.add(ground(), axes({ at: [-3, -2, 0], length: 1.5 }));
s.add(laptop({ at: [-1.5, 0, 0], width: 2.6 }));
s.add(phone({ at: [1.6, -0.6, 0], height: 1.5 }));
s.add(cloud({ at: [0.4, 3, 2.4], size: 2 }));
const tl = new Timeline();
// the camera is animated like anything else
tl.play(tween(s.camera, { yaw: 150, pitch: 24 }, { duration: 5 }));
tl.play(wait(0.8));
Framing
Section titled “Framing”By default the scene is refitted to its contents every frame. Two alternatives keep the picture steady:
tl.lockFit(scene)fixes the framing to fit every moment of a timeline.fit: 'sphere'frames the bounding sphere, so the object keeps its size however the camera turns. Use it with orbit controls.
The figure above does both: drag it and the scene keeps its size, and the timeline never crops it.
Where to go next
Section titled “Where to go next”- Scene and nodes explains how a scene is built and changed.
- Theming shows the three-variable contract behind every colour.
- Embed in plain HTML, Astro or React put a figure on a page.
- The playground lets you change any example and share it as a link.