Reference
Core
Scenes, cameras, nodes, shapes, text, animation, orbit controls and mounting.
import { ... } from 'cseen';Functions
Section titled “Functions”anglesOf
Section titled “anglesOf”The angles and distance of a perspective camera, the inverse of orbitPosition.
function anglesOf(position: V3, target: V3): { yaw: number; pitch: number; distance: number; }| Parameter | Type |
|---|---|
position | V3 |
target | V3 |
Returns { yaw: number; pitch: number; distance: number; }
arcSegs
Section titled “arcSegs”A circular arc as cubic segments, none longer than a quarter turn. Angles are in radians with x = cos and y = sin, and y points down like in SVG, so a positive sweep turns clockwise on screen.
function arcSegs(cx: number, cy: number, r: number, a0: number, a1: number): Seg[]| Parameter | Type |
|---|---|
cx | number |
cy | number |
r | number |
a0 | number |
a1 | number |
Returns Seg[]
Example
import { Construct, Scene, arcSegs, segsD } from 'cseen';
const s = new Scene({ view: 'front', size: [320, 320], padding: 6 });const c = new Construct({ box: [0, 0, 200, 200], size: [3, 3] });c.add({ d: segsD(arcSegs(100, 100, 70, -Math.PI / 2, Math.PI / 3)), width: 4 });s.add(c);A line with an arrowhead at the end. The same options as line, with arrow: 'end' already set.
function arrow(a: Point, b: Point, o?: PathOpts): Path| Parameter | Type |
|---|---|
a | Point |
b | Point |
o? | PathOpts |
Returns Path
Options: PathOpts
Example
import { Scene, arrow, ground } from 'cseen';
const s = new Scene();s.add(ground(), arrow([-3, 0, 0], [3, 0, 2], { role: 'accent' }));The coordinate frame: three arrows along x, y and z with labels. This is how a reader learns which way is which. Put it near the origin of a figure.
function axes(o?: NodeOpts & { length?: number; labels?: [string, string, string] | false; role?: string; }): Group| Parameter | Type |
|---|---|
o? | NodeOpts & { length?: number; labels?: [string, string, string] | false; role?: string; } |
Returns Group
Example
import { Scene, axes, ground } from 'cseen';
const s = new Scene();s.add(ground(), axes({ at: [-3, -2, 0], length: 2 }));A box standing on the point at, the centre of its base. size is a number for a cube or [x, y, z].
function box(o?: BoxOpts): Box| Parameter | Type |
|---|---|
o? | BoxOpts |
Returns Box
Options: BoxOpts
Example
import { Scene, box, ground } from 'cseen';
const s = new Scene();s.add(ground());s.add(box({ at: [-2, 0, 0], size: 1.2 })); // a cubes.add(box({ at: [1, 0, 0], size: [2, 1, 0.6], role: 'accent' })); // width, depth, heightcameraGlyph
Section titled “cameraGlyph”A pinhole camera: its apex, image plane and the rays through the corners, aimed at a target.
The glyph’s own origin is the lens, so cam.anchor([0, 0, 0]) is where rays should start.
function cameraGlyph(pos: V3, target: V3, o?: { dist?: number; w?: number; h?: number; hot?: boolean; role?: string; }): Group| Parameter | Type |
|---|---|
pos | V3 |
target | V3 |
o? | { dist?: number; w?: number; h?: number; hot?: boolean; role?: string; } |
Returns Group
Example
import { Scene, box, cameraGlyph, ground } from 'cseen';
const s = new Scene();s.add(ground(), box({ at: [2, 3, 0], size: 1.4, role: 'accent' }));s.add(cameraGlyph([-3, -3, 1.4], [2, 3, 0.8]));circle
Section titled “circle”A circle or arc in a coordinate plane, centred on at. Angles are in degrees.
function circle(at: V3, r: number, o?: PathOpts & { plane?: 'xy' | 'xz' | 'yz'; from?: number; to?: number; }): Path| Parameter | Type |
|---|---|
at | V3 |
r | number |
o? | PathOpts & { plane?: 'xy' | 'xz' | 'yz'; from?: number; to?: number; } |
Returns Path
Example
import { Scene, circle, ground } from 'cseen';
const s = new Scene();s.add(ground(), circle([0, 0, 0], 1.5, { plane: 'xy', role: 'accent' }));circleD
Section titled “circleD”A full circle as a path, starting at the top and going clockwise, so it draws on like a compass.
function circleD(cx: number, cy: number, r: number): string| Parameter | Type |
|---|---|
cx | number |
cy | number |
r | number |
Returns string
Example
import { Construct, Scene, circleD } from 'cseen';
const s = new Scene({ view: 'front', size: [320, 320], padding: 6 });const c = new Construct({ box: [0, 0, 200, 200], size: [3, 3] });c.add({ d: circleD(100, 100, 80), width: 3 });s.add(c);clampZoom
Section titled “clampZoom”Multiplies a zoom by a factor and keeps it inside the limits.
function clampZoom(zoom: number, factor: number, range?: [number, number]): number| Parameter | Type |
|---|---|
zoom | number |
factor | number |
range? | [number, number] |
Returns number
Code on any plane, coloured, optionally numbered. Animate it with typeOn.
function code(src: string | string[], o?: Omit<TextBlockOpts, 'text' | 'code'>): TextBlock| Parameter | Type |
|---|---|
src | string | string[] |
o? | Omit<TextBlockOpts, 'text' | 'code'> |
Returns TextBlock
Example
import { Scene, Timeline, code, typeOn } from 'cseen';
const s = new Scene({ view: 'front' });const src = s.add(code(['let total = 0;', 'for (const n of list) {', ' total += n;', '}'], { at: [-3, 0, -1], size: [6, 2.4], fontSize: 0.5 }));
const tl = new Timeline();tl.play(typeOn(src, 3));tl.lockFit(s);colourOf
Section titled “colourOf”a colour role (ink, faint, accent, grid, s1 to s8) or any CSS colour, as a CSS colour
function colourOf(c: string): string| Parameter | Type |
|---|---|
c | string |
Returns string
A curve through the points of a function t => [x, y, z], sampled samples times between t0 and t1.
function curve(fn: (t: number): V3, o?: ConstructorParameters<typeof Curve>[1]): Curve| Parameter | Type |
|---|---|
fn | (t: number) => V3 |
o? | (PathOpts & { range?: [number, number]; samples?: number; }) |
Returns Curve
Example
import { Scene, curve, ground } from 'cseen';
const s = new Scene();s.add(ground(), curve((t) => [-3 + 6 * t, 0, 1 + Math.sin(t * Math.PI * 2)], { role: 'accent' }));dimension
Section titled “dimension”A measured distance: a line with end ticks and a label, offset to one side so it does not cover the thing measured.
function dimension(a: V3, b: V3, text: string, o?: { offset?: V3; role?: string; }): Group| Parameter | Type |
|---|---|
a | V3 |
b | V3 |
text | string |
o? | { offset?: V3; role?: string; } |
Returns Group
Example
import { Scene, dimension, ground } from 'cseen';
const s = new Scene();s.add(ground(), dimension([-3, 0, 0], [3, 0, 0], '6 units'));A dot at a point. r is its radius in pixels, so it stays the same size however the camera zooms.
function dot(at: V3, o?: ConstructorParameters<typeof Dot>[0]): Dot| Parameter | Type |
|---|---|
at | V3 |
o? | (NodeOpts & StyleOpts & { r?: number; }) |
Returns Dot
Example
import { Scene, dot, ground } from 'cseen';
const s = new Scene();s.add(ground(), dot([0, 0, 1], { role: 'accent' }));dragToAngles
Section titled “dragToAngles”New angles after a drag of (dx, dy) pixels, in degrees. Dragging right turns the scene so its near side moves right; dragging down tips the top towards the viewer. Pitch is clamped.
function dragToAngles(a: { yaw: number; pitch: number; }, dx: number, dy: number, o?: { sensitivity?: number; limits?: OrbitLimits; }): { yaw: number; pitch: number; }| Parameter | Type |
|---|---|
a | { yaw: number; pitch: number; } |
dx | number |
dy | number |
o? | { sensitivity?: number; limits?: OrbitLimits; } |
Returns { yaw: number; pitch: number; }
Draws a line, curve or outline on from its start to its end.
function draw(n: Node, duration?: number): Anim| Parameter | Type |
|---|---|
n | Node |
duration? | number |
Returns Anim
Example
import { Scene, Timeline, arrow, draw, ground } from 'cseen';
const s = new Scene({ fit: 'sphere' });s.add(ground());const a = s.add(arrow([-3, 0, 0], [3, 0, 2], { role: 'accent' }));
const tl = new Timeline();tl.play(draw(a, 1.2));tl.lockFit(s);fadeIn
Section titled “fadeIn”Fades a node in from invisible to its own opacity.
function fadeIn(n: Node, duration?: number): Anim| Parameter | Type |
|---|---|
n | Node |
duration? | number |
Returns Anim
Example
import { Scene, Timeline, box, fadeIn, ground } from 'cseen';
const s = new Scene({ fit: 'sphere' });s.add(ground());const b = s.add(box({ at: [0, 0, 0], size: 1.5, role: 'accent' }));
const tl = new Timeline();tl.play(fadeIn(b, 1));tl.lockFit(s);fadeOut
Section titled “fadeOut”Fades a node out to invisible.
function fadeOut(n: Node, duration?: number): Anim| Parameter | Type |
|---|---|
n | Node |
duration? | number |
Returns Anim
Example
import { Scene, Timeline, box, fadeOut, ground, wait } from 'cseen';
const s = new Scene({ fit: 'sphere' });s.add(ground());const b = s.add(box({ at: [0, 0, 0], size: 1.5, role: 'accent' }));
const tl = new Timeline();tl.play(wait(0.5));tl.play(fadeOut(b, 1));tl.lockFit(s);ground
Section titled “ground”A square lattice lying on the floor (z = 0). With a parallel camera it is drawn as one repeating pattern, so it is exact and cheap.
function ground(o?: ConstructorParameters<typeof Ground>[0]): Ground| Parameter | Type |
|---|---|
o? | (NodeOpts & { step?: number; extent?: number; }) |
Returns Ground
Example
import { Scene, ground } from 'cseen';
const s = new Scene();s.add(ground());Groups nodes so they move, turn and scale together. Children keep their own positions relative to the group.
function group(o?: NodeOpts, ...children: Node[]): Group| Parameter | Type |
|---|---|
o? | NodeOpts |
children | Node[] |
Returns Group
Options: NodeOpts
Example
import { Scene, box, ground, group } from 'cseen';
const s = new Scene();s.add(ground());const g = s.add(group({ rot: [0, 0, 25] })); // turn the whole group at onceg.add(box({ at: [-1, 0, 0], size: 1 }), box({ at: [1, 0, 0], size: 1, role: 'accent' }));heightField
Section titled “heightField”A height field z = f(x, y) over a rectangle.
function heightField(f: (x: number, y: number): number, o?: SurfaceOpts & { x?: [number, number]; y?: [number, number]; }): Surface| Parameter | Type |
|---|---|
f | (x: number, y: number) => number |
o? | SurfaceOpts & { x?: [number, number]; y?: [number, number]; } |
Returns Surface
Example
import { Scene, ground, heightField } from 'cseen';
const s = new Scene();s.add(ground());s.add(heightField((x, y) => 0.6 * Math.sin(x) * Math.cos(y) + 0.7, { x: [-3, 3], y: [-2, 2], res: [24, 24], role: 'accent' }));Text that stays upright and readable, attached to a point in the scene. It always faces the viewer.
function label(text: string, at: V3, o?: TextOpts): Label| Parameter | Type |
|---|---|
text | string |
at | V3 |
o? | TextOpts |
Returns Label
Options: TextOpts
Example
import { Scene, box, ground, label } from 'cseen';
const s = new Scene();s.add(ground(), box({ at: [0, 0, 0], size: 1.2 }));s.add(label('a box', [0, 0, 1.8], { anchor: 'middle' }));layoutRows
Section titled “layoutRows”Splits text into rows that fit cols characters. The source is the lines joined with newlines, and rows
point into it, so typing progress (a count of source characters) means the same thing before and after wrapping.
word breaks at spaces (a long word is split), char breaks anywhere, none never breaks.
function layoutRows(lines: string[], cols: number, wrap: 'word' | 'char' | 'none'): Row[]| Parameter | Type |
|---|---|
lines | string[] |
cols | number |
wrap | 'word' | 'char' | 'none' |
Returns Row[]
A straight line through two or more points.
function line(a: Point, b: Point, o?: PathOpts): Path| Parameter | Type |
|---|---|
a | Point |
b | Point |
o? | PathOpts |
Returns Path
Options: PathOpts
Example
import { Scene, ground, line } from 'cseen';
const s = new Scene();s.add(ground(), line([-3, 0, 0], [3, 0, 2]));See it in the gallery.
A straight line as a path.
function lineD(a: Pt, b: Pt): string| Parameter | Type |
|---|---|
a | Pt |
b | Pt |
Returns string
Example
import { Construct, Scene, lineD } from 'cseen';
const s = new Scene({ view: 'front', size: [320, 200], padding: 6 });const c = new Construct({ box: [0, 0, 200, 100], size: [3, 1.5] });c.add({ d: lineD([10, 50], [190, 50]), width: 3 });s.add(c);lineSegs
Section titled “lineSegs”A straight segment between two points.
function lineSegs(a: Pt, b: Pt): Seg[]| Parameter | Type |
|---|---|
a | Pt |
b | Pt |
Returns Seg[]
Example
import { Construct, Scene, lineSegs, segsD } from 'cseen';
const s = new Scene({ view: 'front', size: [320, 200], padding: 6 });const c = new Construct({ box: [0, 0, 200, 100], size: [3, 1.5] });const up = lineSegs([20, 80], [100, 20]), down = lineSegs([100, 20], [180, 80]);c.add({ d: segsD(up.concat(down)), width: 4 });s.add(c);A curved arrow between two objects or points.
function link(a: Point, b: Point, o?: LinkOpts): Link| Parameter | Type |
|---|---|
a | Point |
b | Point |
o? | LinkOpts |
Returns Link
Options: LinkOpts
Example
import { Scene, box, ground, link } from 'cseen';
const s = new Scene();s.add(ground());const a = s.add(box({ at: [-3, 0, 0], size: 1 }));const b = s.add(box({ at: [3, 0, 0], size: 1, role: 'accent' }));s.add(link(a.anchor([0, 0, 1]), b.anchor([0, 0, 1]), { bend: 0.3, flow: 1.5, role: 'accent' }));measureD
Section titled “measureD”A measuring bracket between two points: a line with a short tick across each end, for showing a length.
function measureD(a: Pt, b: Pt, tick?: number): string| Parameter | Type |
|---|---|
a | Pt |
b | Pt |
tick? | number |
Returns string
Example
import { Construct, Scene, measureD } from 'cseen';
const s = new Scene({ view: 'front', size: [320, 200], padding: 6 });const c = new Construct({ box: [0, 0, 200, 100], size: [3, 1.5] });c.add({ d: measureD([30, 50], [170, 50]), width: 2 });s.add(c);Puts a scene in the page and plays it. The SVG is built once; each frame only the pieces that changed are replaced, and the drawing pauses when it is off screen.
function mount(target: Element, scene: Scene, o?: MountOpts): Player| Parameter | Type |
|---|---|
target | Element |
scene | Scene |
o? | MountOpts |
Returns Player
Options: MountOpts
Example
import { Scene, box, ground, mount } from 'cseen';import { document } from 'cseen/devices';
const s = new Scene({ view: 'iso' });s.add(ground(), box({ at: [0, 0, 0], size: 1.5, role: 'accent' }));
const player = mount(document.querySelector('#figure')!, s);// player.invalidate() redraws after you change the scene yourselfmoveBy
Section titled “moveBy”Moves a node by an offset from where it is when the animation starts.
function moveBy(n: Node, by: V3, duration?: number, ease?: EaseName): Anim| Parameter | Type |
|---|---|
n | Node |
by | V3 |
duration? | number |
ease? | 'back' | 'linear' | 'in' | 'out' | 'inOut' | 'smooth' |
Returns Anim
Example
import { Scene, Timeline, box, ground, moveBy } from 'cseen';
const s = new Scene({ fit: 'sphere' });s.add(ground());const b = s.add(box({ at: [-2, 0, 0], size: 1.2, role: 'accent' }));
const tl = new Timeline();tl.play(moveBy(b, [4, 0, 0], 1.5));tl.lockFit(s);moveTo
Section titled “moveTo”Moves a node to a point.
function moveTo(n: Node, pos: V3, duration?: number, ease?: EaseName): Anim| Parameter | Type |
|---|---|
n | Node |
pos | V3 |
duration? | number |
ease? | 'back' | 'linear' | 'in' | 'out' | 'inOut' | 'smooth' |
Returns Anim
Example
import { Scene, Timeline, box, ground, moveTo } from 'cseen';
const s = new Scene({ fit: 'sphere' });s.add(ground());const b = s.add(box({ at: [-3, 0, 0], size: 1.2, role: 'accent' }));
const tl = new Timeline();tl.play(moveTo(b, [3, 0, 0], 1.5));tl.lockFit(s);nestSvg
Section titled “nestSvg”Places an SVG document inside a rectangle of another SVG, scaled to fill it (like object-fit: cover).
function nestSvg(source: string, x: number, y: number, w: number, h: number): string| Parameter | Type |
|---|---|
source | string |
x | number |
y | number |
w | number |
h | number |
Returns string
Turns the camera of a scene with the pointer, wheel, touch and keyboard. The scene needs
fit: 'sphere' (or a locked fit) so the object keeps its size while it turns.
const player = mount(el, scene, { timeline }); orbit(el, scene, { onChange: () => player.invalidate() });
If a timeline animates the camera, the timeline wins while it plays.
function orbit(target: Element, scene: Scene, o?: OrbitOpts): Orbit| Parameter | Type |
|---|---|
target | Element |
scene | Scene |
o? | OrbitOpts |
Returns Orbit
Options: OrbitOpts
Example
import { Scene, box, ground, mount, orbit } from 'cseen';import { document } from 'cseen/devices';
const s = new Scene({ fit: 'sphere' });s.add(ground(), box({ at: [0, 0, 0], size: 1.5, role: 'accent' }));
const el = document.querySelector('#figure')!;const player = mount(el, s);orbit(el.querySelector('svg')!, s, { onChange: () => player.invalidate() }); // drag, wheel, pinch and arrow keysorbitPosition
Section titled “orbitPosition”Where a perspective camera sits when it looks at target from distance along the given angles (same angles as the parallel camera).
function orbitPosition(target: V3, yaw: number, pitch: number, distance: number): V3| Parameter | Type |
|---|---|
target | V3 |
yaw | number |
pitch | number |
distance | number |
Returns V3
Plays the animations at the same time.
function par(...anims: Anim[]): Anim| Parameter | Type |
|---|---|
anims | Anim[] |
Returns Anim
Example
import { Scene, Timeline, box, ground, moveBy, par, rotateTo } from 'cseen';
const s = new Scene({ fit: 'sphere' });s.add(ground());const b = s.add(box({ at: [-2, 0, 0], size: 1.2, role: 'accent' }));
const tl = new Timeline();tl.play(par(moveBy(b, [4, 0, 0], 1.5), rotateTo(b, [0, 0, 90], 1.5))); // both at oncetl.lockFit(s);parseSvg
Section titled “parseSvg”Reads an SVG document into a size and inner markup that plane can place. Scripts, event handlers and external references are removed and ids are made unique.
function parseSvg(source: string, o?: { recolor?: Record<string, string>; }): ParsedSvg| Parameter | Type |
|---|---|
source | string |
o? | { recolor?: Record<string, string>; } |
Returns ParsedSvg
A line through any number of points, optionally closed. The general form of line and polygon.
function path(pts: Point[], o?: PathOpts): Path| Parameter | Type |
|---|---|
pts | Point[] |
o? | PathOpts |
Returns Path
Options: PathOpts
Example
import { Scene, ground, path } from 'cseen';
const s = new Scene();s.add(ground(), path([[-3, 0, 0], [-1, 0, 2], [1, 0, 0], [3, 0, 2]]));A line being drawn by a pen: pen(points), then tween draw from 0 to 1.
function pen(rail: Point[] | ((t: number): V3), o?: PenOpts): Pen| Parameter | Type |
|---|---|
rail | Point[] | ((t: number) => V3) |
o? | PenOpts |
Returns Pen
Options: PenOpts
Example
import { Scene, Timeline, pen, tween } from 'cseen';
const s = new Scene({ view: 'front' });const stroke = s.add(pen((t) => [-3 + 6 * t, 0, 0.9 * Math.sin(t * 2 * Math.PI)], { role: 'accent', width: 2.2 }));
const tl = new Timeline();tl.play(tween(stroke, { draw: 1 }, { duration: 2, from: { draw: 0 } }));Lays an SVG (a logo, a chart, a screenshot) on any plane of the scene. Exact with a parallel camera, an approximation with perspective.
function plane(o: PlaneOpts): Plane| Parameter | Type |
|---|---|
o | PlaneOpts |
Returns Plane
Options: PlaneOpts
Example
import { Scene, plane } from 'cseen';
const s = new Scene({ view: 'front' });const svg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 60"><rect width="100" height="60" fill="none" stroke="currentColor"/><circle cx="50" cy="30" r="18" fill="currentColor"/></svg>';s.add(plane({ svg, size: [4, 2.4], at: [0, 0, 0] }));See it in the gallery.
The point at a distance and an angle (degrees, 0 to the right, 90 up) from a centre.
function polar(c: Pt, r: number, deg: number): Pt| Parameter | Type |
|---|---|
c | Pt |
r | number |
deg | number |
Returns Pt
Example
import { Construct, Scene, lineD, polar } from 'cseen';
const s = new Scene({ view: 'front', size: [320, 320], padding: 6 });const c = new Construct({ box: [0, 0, 200, 200], size: [3, 3] });for (let k = 0; k < 8; k++) c.add({ d: lineD([100, 100], polar([100, 100], 80, k * 45)), width: 3 });s.add(c);polygon
Section titled “polygon”A flat filled polygon through three or more points.
function polygon(pts: Point[], o?: FaceOpts): Face| Parameter | Type |
|---|---|
pts | Point[] |
o? | FaceOpts |
Returns Face
Options: FaceOpts
Example
import { Scene, ground, polygon } from 'cseen';
const s = new Scene();s.add(ground(), polygon([[-2, 0, 0], [2, 0, 0], [0, 0, 2.5]], { role: 'accent' }));A dot that rides along a link or a line.
function pulse(rail: Rail, o?: PulseOpts): Pulse| Parameter | Type |
|---|---|
rail | Rail |
o? | PulseOpts |
Returns Pulse
Options: PulseOpts
Example
import { Scene, Timeline, box, ground, link, pulse, tween } from 'cseen';
const s = new Scene();s.add(ground());const a = s.add(box({ at: [-3, 0, 0], size: 1 }));const b = s.add(box({ at: [3, 0, 0], size: 1, role: 'accent' }));const l = s.add(link(a.anchor([0, 0, 1]), b.anchor([0, 0, 1]), { bend: 0.3 }));const ping = s.add(pulse(l, { trail: 4 }));
const tl = new Timeline();tl.play(tween(ping, { along: 1 }, { duration: 1.6, from: { along: 0 }, ease: 'linear' }));A flat rectangle standing in a coordinate plane, as a filled face.
function rect(at: V3, size: [number, number], o?: FaceOpts & { plane?: 'xy' | 'xz' | 'yz'; }): Face| Parameter | Type |
|---|---|
at | V3 |
size | [number, number] |
o? | FaceOpts & { plane?: 'xy' | 'xz' | 'yz'; } |
Returns Face
Example
import { Scene, ground, rect } from 'cseen';
const s = new Scene();s.add(ground(), rect([0, 0, 0], [3, 2], { plane: 'xy' }));renderStill
Section titled “renderStill”The static markup of a scene at one moment: render on the server, then mount in the browser to bring it to life.
function renderStill(scene: Scene, timeline?: Timeline, t?: number): string| Parameter | Type |
|---|---|
scene | Scene |
timeline? | Timeline |
t? | number |
Returns string
Example
import { Scene, box, ground, renderStill } from 'cseen';
const s = new Scene({ view: 'iso' });s.add(ground(), box({ at: [0, 0, 0], size: 1.5, role: 'accent' }));
const svg = renderStill(s); // a standalone <svg> string: on the server, or anywhere without a browserreverse
Section titled “reverse”Plays an animation backwards: every tween runs from its end value to its start value, last one first.
Each tween needs a literal to and a from, so there is something to return to. Put it after the
animation to take a construction apart again, or to make a loop that ends where it began.
function reverse(a: Anim): Anim| Parameter | Type |
|---|---|
a | Anim |
Returns Anim
Example
import { Scene, Timeline, box, ground, reverse, tween } from 'cseen';
const s = new Scene({ fit: 'sphere' });s.add(ground());const b = s.add(box({ at: [-3, 0, 0], size: 1.2, role: 'accent' }));
const tl = new Timeline();const there = tween(b, { pos: [3, 0, 0] }, { duration: 1.5, from: { pos: [-3, 0, 0] } });tl.play(there);tl.play(reverse(there));tl.lockFit(s);A small deterministic random generator, so generated scenes are identical on server and client.
function rng(seed: number): (): number| Parameter | Type |
|---|---|
seed | number |
Returns () => number
rotateSegs
Section titled “rotateSegs”Turns segments about a point. The angle is in radians, clockwise on screen.
function rotateSegs(segs: Seg[], c: Pt, ang: number): Seg[]| Parameter | Type |
|---|---|
segs | Seg[] |
c | Pt |
ang | number |
Returns Seg[]
Example
import { Construct, Scene, lineSegs, rotateSegs, segsD } from 'cseen';
const s = new Scene({ view: 'front', size: [320, 320], padding: 6 });const c = new Construct({ box: [0, 0, 200, 200], size: [3, 3] });const leaf = lineSegs([100, 100], [100, 20]);for (let k = 0; k < 6; k++) c.add({ d: segsD(rotateSegs(leaf, [100, 100], (k * Math.PI) / 3)), width: 4 });s.add(c);rotateTo
Section titled “rotateTo”Rotates a node to Euler angles in degrees about x, y and z.
function rotateTo(n: Node, rot: V3, duration?: number): Anim| Parameter | Type |
|---|---|
n | Node |
rot | V3 |
duration? | number |
Returns Anim
Example
import { Scene, Timeline, box, ground, rotateTo } from 'cseen';
const s = new Scene({ fit: 'sphere' });s.add(ground());const b = s.add(box({ at: [0, 0, 0], size: [2, 1, 1], role: 'accent' }));
const tl = new Timeline();tl.play(rotateTo(b, [0, 0, 90], 1.5));tl.lockFit(s);scaleTo
Section titled “scaleTo”Scales a node to a factor.
function scaleTo(n: Node, scale: number, duration?: number): Anim| Parameter | Type |
|---|---|
n | Node |
scale | number |
duration? | number |
Returns Anim
Example
import { Scene, Timeline, box, ground, scaleTo } from 'cseen';
const s = new Scene({ fit: 'sphere' });s.add(ground());const b = s.add(box({ at: [0, 0, 0], size: 1, role: 'accent' }));
const tl = new Timeline();tl.play(scaleTo(b, 2, 1.2));tl.lockFit(s);Writes segments as an SVG path string. A new subpath starts wherever a segment does not begin
where the last one ended, and close ends with Z.
function segsD(segs: Seg[], close?: boolean, digits?: number): string| Parameter | Type |
|---|---|
segs | Seg[] |
close? | boolean |
digits? | number |
Returns string
Example
import { Construct, Scene, arcSegs, segsD } from 'cseen';
const s = new Scene({ view: 'front', size: [320, 200], padding: 6 });const c = new Construct({ box: [0, 0, 200, 100], size: [3, 1.5] });const lens = arcSegs(100, 50, 60, -0.6, 0.6).concat(arcSegs(100, 50, 60, Math.PI - 0.6, Math.PI + 0.6));c.add({ d: segsD(lens, true), paint: 'accent', width: 3, props: { fill: 0.3 } });s.add(c);Plays the animations one after another.
function seq(...anims: Anim[]): Anim| Parameter | Type |
|---|---|
anims | Anim[] |
Returns Anim
Example
import { Scene, Timeline, box, ground, moveBy, seq } from 'cseen';
const s = new Scene({ fit: 'sphere' });s.add(ground());const b = s.add(box({ at: [-2, 0, 0], size: 1.2, role: 'accent' }));
const tl = new Timeline();tl.play(seq(moveBy(b, [4, 0, 0], 1), moveBy(b, [0, 3, 0], 1))); // one, then the othertl.lockFit(s);sphereOf
Section titled “sphereOf”The bounding sphere of the drawable nodes, used by fit: 'sphere'. Its centre is the middle of the box around the points, so it does not change with the camera angle.
function sphereOf(prims: Prim[]): Sphere | null| Parameter | Type |
|---|---|
prims | Prim[] |
Returns Sphere \| null
stagger
Section titled “stagger”Starts each animation a little after the previous one.
function stagger(gap: number, ...anims: Anim[]): Anim| Parameter | Type |
|---|---|
gap | number |
anims | Anim[] |
Returns Anim
Example
import { Scene, Timeline, box, fadeIn, ground, stagger } from 'cseen';
const s = new Scene({ fit: 'sphere' });s.add(ground());const boxes = [-3, -1, 1, 3].map((x) => s.add(box({ at: [x, 0, 0], size: 1 })));
const tl = new Timeline();tl.play(stagger(0.25, ...boxes.map((b) => fadeIn(b, 0.6)))); // each starts a little after the lasttl.lockFit(s);surface
Section titled “surface”A parametric surface (u, v) => [x, y, z] drawn as a mesh of shaded quads.
function surface(fn: (u: number, v: number): V3, o?: SurfaceOpts): Surface| Parameter | Type |
|---|---|
fn | (u: number, v: number) => V3 |
o? | SurfaceOpts |
Returns Surface
Options: SurfaceOpts
Example
import { Scene, ground, surface } from 'cseen';
const s = new Scene();s.add(ground());// half a cylinder: (u, v) in, a point outs.add(surface((u, v) => [-2 + 4 * u, 1.3 * Math.cos(Math.PI * v), 1.3 * Math.sin(Math.PI * v)], { res: [8, 20] }));tokenize
Section titled “tokenize”Splits a line of code into coloured pieces. Deliberately small: it suits snippets in illustrations, not an editor.
function tokenize(line: string): Token[]| Parameter | Type |
|---|---|
line | string |
Returns Token[]
Animate any properties of a node or camera: tween(cube, { opacity: 0.2, pos: [1, 0, 0] }).
function tween(target: Animatable, to: Record<string, To>, o?: TweenOpts): Anim| Parameter | Type |
|---|---|
target | Animatable |
to | Record<string, To> |
o? | TweenOpts |
Returns Anim
Options: TweenOpts
Example
import { Scene, Timeline, box, ground, tween } from 'cseen';
const s = new Scene({ fit: 'sphere' });s.add(ground());const b = s.add(box({ at: [-2, 0, 0], size: 1.2, role: 'accent' }));
const tl = new Timeline();tl.play(tween(b, { pos: [2, 0, 0], rot: [0, 0, 90] }, { duration: 1.6, ease: 'inOut' }));tl.lockFit(s);typeOn
Section titled “typeOn”Types text or code onto a plane letter by letter.
function typeOn(n: Node, duration?: number): Anim| Parameter | Type |
|---|---|
n | Node |
duration? | number |
Returns Anim
Example
import { Scene, Timeline, typeOn, write } from 'cseen';
const s = new Scene({ view: 'front' });const t = s.add(write('Typed, letter by letter.', { at: [-3, 0, 0], size: [6, 1], fontSize: 0.5 }));
const tl = new Timeline();tl.play(typeOn(t, 2));tl.lockFit(s);Does nothing for a while. Use it to leave a gap between two animations.
function wait(duration: number): Anim| Parameter | Type |
|---|---|
duration | number |
Returns Anim
Example
import { Scene, Timeline, box, ground, moveBy, wait } from 'cseen';
const s = new Scene({ fit: 'sphere' });s.add(ground());const b = s.add(box({ at: [0, 0, 0], size: 1.2, role: 'accent' }));
const tl = new Timeline();tl.play(wait(1)); // nothing happens for a secondtl.play(moveBy(b, [2, 0, 0], 1));tl.lockFit(s);Text on any plane: write('hello', { at, size, u, v }). Put it on a floor, a wall, or a screen.
function write(text: string | string[], o?: Omit<TextBlockOpts, 'text'>): TextBlock| Parameter | Type |
|---|---|
text | string | string[] |
o? | Omit<TextBlockOpts, 'text'> |
Returns TextBlock
Example
import { Scene, ground, write } from 'cseen';
const s = new Scene();s.add(ground());s.add(write(['Hello,', 'floor.'], { at: [-2, -1, 0], size: [4, 1.6], fontSize: 0.7, u: [1, 0, 0], v: [0, 1, 0] }));Classes
Section titled “Classes”A box standing on the point at: the centre of its base.
new Box(o?: BoxOpts): BoxOptions: BoxOpts
Extends Node.
| Member | Description |
|---|---|
o: BoxOpts | |
pt(name: 'top' | 'bottom' | 'center' | 'front' | 'back' | 'left' | 'right'): (): V3 | named points on the box, in world space, that follow it when it moves |
collect(out: Prim[]): void | appends what this node draws right now to out, in world coordinates. Draws nothing when fully transparent. |
Camera
Section titled “Camera”World axes: x to the right, y into the scene, z up. Every scene shares them, so a figure never has to explain where “up” is.
project returns [screenX, screenY (down), depth]. Larger depth means farther away.
new Camera(kind: 'ortho' | 'persp', props: Record<string, number | number[]>): CameraExample
import { Camera, Scene, box, ground } from 'cseen';
const s = new Scene({ view: Camera.perspective({ position: [5, -9, 5], target: [0, 0, 1], fov: 35 }),});s.add(ground(), box({ at: [0, 0, 0], size: 1.5, role: 'accent' }));Extends Animatable.
| Member | Description |
|---|---|
kind: 'ortho' | 'persp' | |
axonometric(view?: View): Camera (static) | A parallel (axonometric) camera. This is the look of technical illustration. |
perspective(o: { position: V3; target?: V3; fov?: number; }): Camera (static) | A pinhole camera with real perspective. |
zoom: number | Magnification applied after the picture is framed: 1 is the framed size, 2 is twice as large. Animatable. |
scaleAt(depth: number): number | Screen size of one world unit at a given depth, relative to the framing (1 for a parallel camera). |
viewDir(): V3 | Unit vector of the direction the camera looks along (towards increasing depth), for the parallel camera. |
project(p: V3): V3 | World point to [screenX, screenY (down), depth]. Perspective divides by depth, clamped so a point behind the camera cannot flip or blow up. |
eyeSide(planePoint: V3, normal: V3): number | Which side of a plane the viewer is on: positive when the eye is on the side the normal points to, negative on the other side, near zero when the plane is seen edge-on. |
visible(p: V3): boolean | True when a point is in front of the camera (always true for a parallel camera). |
Construct
Section titled “Construct”A drawing built from parts that each draw on, fill, turn, move and fade by themselves. It is the tool for line constructions: guides, compass circles and outlines that trace, copy and turn into a finished shape. Parts paint in the order they were added.
new Construct(o?: ConstructOpts): ConstructOptions: ConstructOpts
Example
import { Construct, Scene, Timeline, arcSegs, circleD, segsD, tween } from 'cseen';
const s = new Scene({ view: 'front', size: [360, 360], padding: 6 });const c = s.add(new Construct({ box: [0, 0, 200, 200], size: [3.4, 3.4] }));const ring = c.add({ d: circleD(100, 100, 70), stroke: 'faint', width: 1.5, props: { draw: 0 } });const leaf = c.add({ d: segsD(arcSegs(160, 100, 80, 2.5, 3.78).concat(arcSegs(40, 100, 80, -0.64, 0.64)), true), paint: 'accent', width: 3, props: { draw: 0 } });
const tl = new Timeline();tl.play(tween(ring, { draw: 1 }, { duration: 1.2 }));tl.play(tween(leaf, { draw: 1, fill: 0.4 }, { duration: 1.2 }));tl.play(tween(leaf, { spin: 90 }, { duration: 1.2 }));Extends SvgPlane.
| Member | Description |
|---|---|
o: ConstructOpts | |
parts: Part[] | |
add(o: PartOpts): Part | adds a shape on top of the others and returns it, ready to animate |
at(x: number, y: number): V3 | Where a point of the drawing sits in the scene, in the plane’s own space (world units from its corner), so lines, dots and labels can be tied to the drawing: a drop line from a corner of a shape to where it lifted. |
draw(W: number, H: number): string | all parts, in order, inside one group that maps the box onto the plane (centred, uniform scale) |
A line through the samples of a function, drawn as one SVG path.
new Curve(fn: (t: number)Extends Node.
| Member | Description |
|---|---|
fn: (t: number) => V3 | |
o: PathOpts & { range?: [number, number]; samples?: number; } | |
collect(out: Prim[]): void | appends what this node draws right now to out, in world coordinates. Draws nothing when fully transparent. |
A dot of fixed size on the screen at a point of the scene.
new Dot(o?: NodeOpts & StyleOpts & { r?: number; }): DotExtends Node.
| Member | Description |
|---|---|
o: StyleOpts & { r?: number; } | |
collect(out: Prim[]): void | appends what this node draws right now to out, in world coordinates. Draws nothing when fully transparent. |
One flat polygon.
new Face(pts: Point[], o?: FaceOpts): FaceOptions: FaceOpts
Extends Node.
| Member | Description |
|---|---|
pts: Point[] | |
o: FaceOpts | |
collect(out: Prim[]): void | appends what this node draws right now to out, in world coordinates. Draws nothing when fully transparent. |
Ground
Section titled “Ground”The ground lattice. With a parallel camera it fills the whole picture.
new Ground(o?: NodeOpts & { step?: number; extent?: number; }): GroundExtends Node.
| Member | Description |
|---|---|
o: { step?: number; extent?: number; } | |
collect(out: Prim[]): void | appends what this node draws right now to out, in world coordinates. Draws nothing when fully transparent. |
A node that holds other nodes and moves, turns and scales them together.
new Group(o?: NodeOpts): GroupOptions: NodeOpts
Extends Node.
| Member | Description |
|---|---|
children: Node[] | |
add<T extends Node>(node: T): T | adds nodes to the group. Adding one node returns it, so you can keep a handle: const b = g.add(box()). |
add<T extends Node>(node: T): T | adds nodes to the group. Adding one node returns it, so you can keep a handle: const b = g.add(box()). |
add<T extends Node>(node: T): T | adds nodes to the group. Adding one node returns it, so you can keep a handle: const b = g.add(box()). |
remove(n: Node): void | takes a node out of the group. Does nothing for a node that is not in this group. |
collect(out: Prim[]): void | appends what this node draws right now to out, in world coordinates. Draws nothing when fully transparent. |
Text that stays upright and readable, attached to a point in the scene.
new Label(text: string, o?: TextOpts): LabelOptions: TextOpts
Extends Node.
| Member | Description |
|---|---|
text: string | |
o: TextOpts | |
collect(out: Prim[]): void | appends what this node draws right now to out, in world coordinates. Draws nothing when fully transparent. |
A curved arrow between two things. The ends can be objects or anchors, so the link follows them when they move.
flow: true makes dashes travel along it, and .at(t) gives the point at t (0 to 1) for a pulse to ride.
new Link(a: Point, b: Point, o?: LinkOpts): LinkOptions: LinkOpts
Extends Node.
| Member | Description |
|---|---|
a: Point | |
b: Point | |
o: LinkOpts | |
at(t: number): V3 | the point at t along the link, in world space |
collect(out: Prim[]): void | appends what this node draws right now to out, in world coordinates. Draws nothing when fully transparent. |
The base of everything in a scene. A node has a position, rotation, scale and opacity, and animatable properties.
new Node(o?: NodeOpts): NodeOptions: NodeOpts
Extends Animatable.
| Member | Description |
|---|---|
id: string | |
name?: string | undefined | |
parent?: Group | undefined | |
layer: number | |
world(p: V3): V3 | point in this node’s own space to world space |
toLocal(p: V3): V3 | a point in world space as a point in this node’s own space: the inverse of world |
worldDir(d: V3): V3 | a direction in this node’s own space as a direction in world space (rotation and scale, no translation) |
anchor(local: V3): (): V3 | a point that stays attached to this node as it moves, rotates and scales |
opacityEff: number | opacity of this node times that of every group above it |
layerEff: number | draw layer of this node plus that of every group above it |
collect(out: Prim[]): void | appends what this node draws right now to out, in world coordinates. Draws nothing when fully transparent. |
One drawn shape of a construction. Everything that changes is in props, so a timeline can animate it:
draw (how much of the outline is drawn, 0 to 1), fill (the fill’s opacity), line (the outline’s opacity),
spin (degrees about about), scale, dx, dy and op (opacity of the whole part). Any property you
add through props is also animatable and is passed to d when d is a function.
new Part(o: PartOpts): PartOptions: PartOpts
Extends Animatable.
| Member | Description |
|---|---|
o: PartOpts |
A line through points, drawn as one SVG path.
new Path(pts: Point[], o?: PathOpts): PathOptions: PathOpts
Extends Node.
| Member | Description |
|---|---|
pts: Point[] | |
o: PathOpts | |
collect(out: Prim[]): void | appends what this node draws right now to out, in world coordinates. Draws nothing when fully transparent. |
A line being drawn by a pen. draw (0 to 1) is how much has been drawn: the trail follows the rail and a pen
rides at its tip. The rail is a list of points, or a function from 0..1 to a point.
tween(p, { draw: 1 }, { duration: 2 }) writes it out.
new Pen(rail: Point[] | ((t: number)Options: PenOpts
Extends Node.
| Member | Description |
|---|---|
rail: Point[] | ((t: number) => V3) | |
o: PenOpts | |
collect(out: Prim[]): void | appends what this node draws right now to out, in world coordinates. Draws nothing when fully transparent. |
Any SVG laid on a plane in 3D. With a parallel camera the placement is exact. With perspective it is a close approximation, built from small pieces (an SVG can only be sheared, not foreshortened).
new Plane(o: PlaneOpts): PlaneOptions: PlaneOpts
Extends Node.
| Member | Description |
|---|---|
parsed: ParsedSvg | |
o: PlaneOpts | |
collect(out: Prim[]): void | appends what this node draws right now to out, in world coordinates. Draws nothing when fully transparent. |
A dot that rides along a link, a polyline or a function. Animate along from 0 to 1:
tween(p, { along: 1 }, { duration: 2, from: { along: 0 } }). It is hidden outside 0 to 1.
new Pulse(rail: Rail, o?: PulseOpts): PulseOptions: PulseOpts
Extends Node.
| Member | Description |
|---|---|
rail: Rail | |
o: PulseOpts | |
collect(out: Prim[]): void | appends what this node draws right now to out, in world coordinates. Draws nothing when fully transparent. |
A scene is a tree of nodes, a camera, and the settings to draw them. It draws whatever state its nodes are in right now. A timeline changes that state over time.
new Scene(o?: SceneOpts): SceneOptions: SceneOpts
Example
import { Scene, box, ground } from 'cseen';
const s = new Scene({ view: 'iso', title: 'A box on the ground' });s.add(ground(), box({ at: [0, 0, 0], size: 1.5, role: 'accent' }));| Member | Description |
|---|---|
root: Group | the top of the tree of nodes |
camera: Camera | |
size: [number, number] | drawing size in viewBox units |
padding: number | space around the drawing in viewBox units |
region?: Region | undefined | the part of the picture the scene may use |
light: V3 | direction towards the light, in world space |
title?: string | undefined | accessible name |
desc?: string | undefined | longer accessible description |
fit: 'auto' | 'sphere' | Fit | ‘auto’ refits every frame. ‘sphere’ frames the bounding sphere. A locked fit keeps the picture steady while things move. |
sphere?: Sphere | undefined | with fit ‘sphere’: a sphere fixed ahead of time, so a moving scene keeps its framing (see Timeline.lockFit) |
sketch?: { amp: number; seed: number; } | undefined | the hand-drawn look, if any |
split: boolean | whether faces that pierce each other are cut before sorting |
add<T extends Node>(node: T): T | Adds nodes to the scene. Adding one node returns it, so you can keep a reference to animate. |
add<T extends Node>(node: T): T | Adds nodes to the scene. Adding one node returns it, so you can keep a reference to animate. |
add<T extends Node>(node: T): T | Adds nodes to the scene. Adding one node returns it, so you can keep a reference to animate. |
prims(): Prim[] | Everything the nodes draw right now, flattened, in the order they were added. |
screen(p: V3): [number, number] | Where a point of the scene lands in the picture, in the scene’s drawing units, with the framing as it is now. Use it to line something up with the drawing, such as a grid on the page behind it. |
frame(): Frame | Draws the scene as it is now: the items back to front and the framing used. svg and mount build on it. |
lockTo(b: Bounds): void | Keeps the picture still while things move. Pass the bounds of every moment you care about (see lockFit on a timeline) so nothing is ever cropped. |
box(): { lo: V3; hi: V3; } | null | the box around every point in world space, for framing by sphere |
bounds(): Bounds | null | the box around the drawing on screen, before fitting, or null when nothing is visible |
svg(o?: { class?: string; }): string | The scene as a complete, standalone SVG string. Safe to render on the server. |
Spheres
Section titled “Spheres”Several spheres drawn as one body: overlapping balls, like a cloud, are ordered together by depth.
new Spheres(list: [V3, number][], o?: NodeOpts & StyleOpts & { fill?: number; alpha?: number; res?: number; outline?: boolean; shade?: boolean; }): SpheresExtends Node.
| Member | Description |
|---|---|
list: [V3, number][] | |
o: StyleOpts & { fill?: number; alpha?: number; res?: number; outline?: boolean; shade?: boolean; } | |
collect(out: Prim[]): void | appends what this node draws right now to out, in world coordinates. Draws nothing when fully transparent. |
Surface
Section titled “Surface”A parametric surface (u, v) to a point, drawn as a mesh of shaded quads. A function z = f(x, y) is a special case.
new Surface(fn: (u: number, v: number)Options: SurfaceOpts
Extends Node.
| Member | Description |
|---|---|
fn: (u: number, v: number) => V3 | |
o: SurfaceOpts | |
collect(out: Prim[]): void | appends what this node draws right now to out, in world coordinates. Draws nothing when fully transparent. |
SvgPlane
Section titled “SvgPlane”Anything drawn as SVG on a plane in the scene: charts, screen elements, maths figures. A subclass says how to draw itself from its current props, and gets the plane, fading and placement for free.
new SvgPlane(o: SvgPlaneOpts, fallback: [number, number]): SvgPlaneOptions: SvgPlaneOpts
Extends Node.
| Member | Description |
|---|---|
size: [number, number] | |
o: SvgPlaneOpts | |
draw(W: number, H: number): string | the drawing, in svg units: W wide and H tall, origin at the top left |
collect(out: Prim[]): void | appends what this node draws right now to out, in world coordinates. Draws nothing when fully transparent. |
TextBlock
Section titled “TextBlock”Text laid on a plane in the scene: a wall, the floor, a screen. It can be code, with colours.
It wraps to the plane and shrinks to fit, so it never runs past the edge.
type (0 to 1) is how much has been typed, so typeOn(block) animates it appearing letter by letter.
new TextBlock(o: TextBlockOpts): TextBlockOptions: TextBlockOpts
Extends Node.
| Member | Description |
|---|---|
o: TextBlockOpts | |
lines: string[] | |
length: number | characters in the source, counting a newline after every line: the scale of type |
collect(out: Prim[]): void | draws the rows typed so far, one <text> per row with a <tspan> per run of one colour |
Timeline
Section titled “Timeline”A timeline is a list of tweens. seek(t) rewinds everything to its starting state and replays up
to t, so the result depends only on t. Playing, scrubbing and rendering a still frame all work the same way.
new Timeline(): TimelineExample
import { Scene, Timeline, box, fadeIn, ground, moveBy } from 'cseen';
const s = new Scene({ fit: 'sphere' });s.add(ground());const b = s.add(box({ at: [0, 0, 0], size: 1.5, role: 'accent' }));
const tl = new Timeline();tl.play(fadeIn(b, 1));tl.chapter('move').play(moveBy(b, [2, 0, 0], 1.2));tl.lockFit(s);| Member | Description |
|---|---|
tweens: Tween[] | every tween, with start times on the timeline’s clock |
chapters: { name: string; time: number; }[] | named marks, in the order made, for step buttons and captions |
play(a: Anim): this | appends an animation after everything so far |
at(time: number, a: Anim): this | places an animation at an absolute time without moving the cursor |
wait(d: number): this | leaves a gap: the next play starts d seconds later |
chapter(name: string): this | marks the current time as a named step, for “next step” buttons and captions |
duration: number | the length in seconds: where the cursor is, so a trailing wait counts |
seek(t: number): void | puts every animated object in the state it has at time t (seconds) |
lockFit(scene: Scene, samples?: number): this | Fixes the scene’s framing to fit every moment of this timeline, so the picture does not shift as things move. Call it once after building the timeline. |
Options and types
Section titled “Options and types”Anchor
Section titled “Anchor”A point that may follow something else: a fixed position, or a function evaluated each frame.
type Anchor = V3 | (() => V3)A piece of animation. It knows its length and its tweens (starting at 0), and can be combined with others.
| Option | Type | Default | Description |
|---|---|---|---|
duration | number | length in seconds | |
tweens | Tween[] | the tweens that make it up, with start times relative to its beginning |
BoxOpts
Section titled “BoxOpts”Options of box.
Extends FaceOpts.
| Option | Type | Default | Description |
|---|---|---|---|
size? | BoxSize | [width (x), depth (y), height (z)], or one number for a cube |
ConstructOpts
Section titled “ConstructOpts”Options of a construction.
Extends SvgPlaneOpts.
| Option | Type | Default | Description |
|---|---|---|---|
box? | [number, number, number, number] | the part of the drawing’s own coordinates to show: x, y, width, height. [0, 0, 1000, 1000] by default. |
An easing function: maps progress 0 to 1 onto progress 0 to 1.
type Ease = (t: number) => numberEaseName
Section titled “EaseName”The name of a built-in easing curve.
type EaseName = keyof typeof easeFaceOpts
Section titled “FaceOpts”Options of filled surfaces.
| Option | Type | Default | Description |
|---|---|---|---|
fill? | number | colour strength, 0 to 1. Low values are a tint, 1 is the full role colour. | |
alpha? | number | see-through amount. 1 is solid, 0.2 is a faint pane of glass. | |
shade? | boolean | light the face from the scene’s light, darker or lighter by angle | |
outline? | boolean | draw the outline |
LinkOpts
Section titled “LinkOpts”Options of link.
Extends NodeOpts, __type.
| Option | Type | Default | Description |
|---|---|---|---|
bend? | number | how far the line bows away from the straight line, as a fraction of its length. 0 is straight. Default 0.25. | |
toward? | V3 | the direction it bows toward. Default up (z). | |
samples? | number | how many points the curve is sampled at |
MarkKey
Section titled “MarkKey”What a mark can match: a word, a pattern, or a [start, end) range of the source text.
type MarkKey = string | RegExp | [number, number]Words to colour in a text block: a map from the word to a role or CSS colour, or a list of [match, colour] pairs where the match is a string, a regular expression or a [start, end] range.
type Marks = Record<string, string> | Array<[MarkKey, string]>MountOpts
Section titled “MountOpts”Options of mount.
| Option | Type | Default | Description |
|---|---|---|---|
timeline? | Timeline | the timeline to play | |
autoplay? | boolean | play when mounted. Default true. | |
loop? | boolean | { pause: number; } | restart at the end. true, or { pause: seconds } to hold the last frame first. Default true. | |
speed? | number | playback speed, 1 by default | |
rest? | number | time to show for people who prefer reduced motion, and before play. Defaults to the end of the timeline. | |
onlyVisible? | boolean | only animate while on screen. Default true. | |
maxFps? | number | upper limit of redraws per second, 60 by default |
NodeOpts
Section titled “NodeOpts”Options every node takes.
| Option | Type | Default | Description |
|---|---|---|---|
at? | V3 | position of the node’s origin in its parent | |
rot? | V3 | Euler rotation in degrees | |
scale? | number | uniform scale, 1 by default | |
opacity? | number | transparency of the whole node, 0 to 1. Animatable. | |
layer? | number | draw order between groups of things: lower first. Labels default to above geometry. | |
name? | string | a name for finding the node later |
Handle to a running orbit control.
| Option | Type | Default | Description |
|---|---|---|---|
reset | () => void | back to the view the camera had when orbit was set up | |
destroy | () => void | removes the listeners and restores the element |
OrbitLimits
Section titled “OrbitLimits”How far the camera may turn and zoom. Pitch and yaw are in degrees.
| Option | Type | Default | Description |
|---|---|---|---|
pitch? | [number, number] | degrees. Default [-89, 90]: from just below the ground to straight down. | |
yaw? | [number, number] | degrees. Default: free. | |
zoom? | [number, number] | magnification. Default [0.4, 6]. |
OrbitOpts
Section titled “OrbitOpts”Options of orbit.
| Option | Type | Default | Description |
|---|---|---|---|
onChange? | (() => void) | called after the camera changed. Pass () => player.invalidate() so the picture redraws. | |
zoom? | boolean | wheel and pinch zoom. Default true. | |
limits? | OrbitLimits | how far the camera may turn and zoom | |
autoRotate? | number | degrees per second of slow turning until the person touches the figure. Default off. Ignored for reduced motion. | |
keyboard? | boolean | arrow keys turn, plus and minus zoom, 0 resets. Default true. | |
sensitivity? | number | degrees per pixel of drag. Default 0.4. | |
home? | Record<string, number | number[]> | the camera state that reset returns to (a camera.snapshot()). Default: the camera as it is when orbit starts. |
PartOpts
Section titled “PartOpts”Options of a part of a construction.
| Option | Type | Default | Description |
|---|---|---|---|
d? | string | ((p: Record<string, Value>) => string) | the outline as an SVG path, or a function of the part’s properties that makes it, so a shape can be reshaped by animating props. Leave it out for a text label. | |
text? | string | makes the part a small text label instead of an outline, drawn at at in the colour of stroke. Fade it with op. | |
at? | [number, number] | where the label sits, in the drawing’s coordinates. The text is centred on it unless anchor says otherwise. | |
size? | number | the label’s font size in svg units, 24 by default | |
anchor? | 'start' | 'end' | 'middle' | which end of the label sits at at: start, middle (default) or end | |
stroke? | string | colour of the line: a role (ink, faint, accent, s1 to s8) or any CSS colour. ink by default. | |
paint? | string | colour of the fill: a role or any CSS colour. No fill by default. | |
width? | number | line width in svg units of the drawing, 2 by default | |
about? | [number, number] | the point that spin and scale turn and grow about, the middle of the box by default | |
props? | Record<string, Value> | starting values of the part’s properties (draw, fill, line, spin, dx, dy, scale, op, or your own) |
PathOpts
Section titled “PathOpts”Options of lines and paths.
| Option | Type | Default | Description |
|---|---|---|---|
closed? | boolean | join the last point back to the first | |
arrow? | 'start' | 'end' | 'both' | where to put arrowheads | |
dash? | string | an SVG dash pattern such as '3 3' | |
flow? | number | boolean | dashes travel along the line (in the direction it is drawn): true, or cycles per second. Runs in CSS, so it works in a static SVG too. | |
draw? | number | how much of the line is drawn, 0 to 1. Animate it for a draw-on effect. |
PenOpts
Section titled “PenOpts”Options of pen.
Extends NodeOpts.
| Option | Type | Default | Description |
|---|---|---|---|
role? | string | colour role (ink, faint, accent, s1 to s8) or a role you define in CSS | |
width? | number | line width in svg units | |
lean? | V3 | which way the pen leans from its tip. Default up and a little to the right. | |
length? | number | length of the pen in world units | |
keep? | boolean | leave the pen drawn once the line is finished (default: it lifts away) | |
samples? | number | how many points a function is sampled at |
PlaneOpts
Section titled “PlaneOpts”Options of plane.
Extends NodeOpts.
| Option | Type | Default | Description |
|---|---|---|---|
svg | string | the SVG to place: its source text | |
size | [number, number] | size of the plane in world units: [width along u, height along v] | |
u? | V3 | direction of the SVG’s x axis, and of its (upward) y axis, in the node’s space. Defaults to the x and z axes: a wall facing you. | |
v? | V3 | direction of the SVG’s upward y axis in the node’s space | |
recolor? | Record<string, string> | swap hard-coded colours in the SVG for CSS variables, e.g. { ‘#ffffff’: ‘var(—c-bg)’ } | |
border? | string | false | a line around the plane | |
cells? | number | pieces per side when the camera has perspective. More is smoother and slower. | |
alpha? | number | see-through amount of the SVG, 0 to 1 |
Player
Section titled “Player”Controls a mounted scene: play, pause, seek by time or by chapter, and redraw after a change made by hand.
| Option | Type | Default | Description |
|---|---|---|---|
time | number | the current time in seconds | |
duration | number | the length of the timeline in seconds | |
play | () => void | starts or resumes playing | |
pause | () => void | stops playing, keeping the current frame | |
seek | (t: number) => void | jumps to a time in seconds | |
step | (dir?: 1 | -1) => void | jumps to the start of the next (or previous) chapter | |
destroy | () => void | stops and releases the scene | |
playing | boolean | whether it is playing | |
invalidate | () => void | Redraws the scene as it is now, without moving the timeline. Call it after changing the camera or a node by hand (orbit controls do). Calls within one frame are merged, and maxFps still applies. |
A place in the scene: a plain [x, y, z], an anchor of a node, or a node itself (its position).
type Point = Anchor | NodeWhat the renderer draws. Nodes turn themselves into these, in world coordinates.
| Option | Type | Default | Description |
|---|---|---|---|
key | string | a stable name, so a redraw replaces only what changed | |
kind | 'path' | 'dot' | 'text' | 'plane' | 'ground' | what to draw | |
pts | V3[] | the points in world space | |
role | string | colour role (ink, faint, accent, s1 to s8) or a role you define in CSS | |
opacity | number | transparency, 0 to 1 | |
layer | number | draw order between groups of things, lower first | |
closed? | boolean | join the last point back to the first | |
face? | boolean | fill the polygon as a lit surface | |
fill? | number | how strongly the role colour shows in a face, 0 to 1 (mixed into the background) | |
alpha? | number | see-through amount of a face, 1 is solid | |
mix? | number | 0 to 1: blend the face colour towards the accent, for value-coloured surfaces | |
shade? | boolean | light the face from the scene light | |
cull? | boolean | hide when the viewer is behind it. Needs a normal that points outwards. | |
normal? | V3 | the outward direction of a face, used for shading, culling and depth order | |
width? | number | line width in SVG units | |
draw? | number | how much of the line is drawn, 0 to 1 | |
arrow? | 'start' | 'end' | 'both' | where to put arrowheads | |
dash? | string | an SVG dash pattern | |
flow? | number | dashes travel along the line, this many cycles per second | |
r? | number | radius in pixels, for a dot | |
text? | string | the characters, for text | |
anchor? | 'start' | 'end' | 'middle' | which end of the text sits at the point | |
dx? | number | nudge right in pixels | |
dy? | number | nudge down in pixels | |
size? | number | font size in pixels | |
noFit? | boolean | leave out of the framing, so it never changes the size of the picture | |
group? | string | pieces of one object (a mesh, a box) are ordered among themselves by depth, not by plane tests | |
plane? | { w: number; h: number; svg: ParsedSvg; cells: number; id: string; } | an SVG to place on the plane through the first three points | |
ground? | { step?: number; extent?: number; } | the lattice on the floor |
A point in svg units.
type Pt = [number, number]PulseOpts
Section titled “PulseOpts”Options of pulse.
Extends NodeOpts.
| Option | Type | Default | Description |
|---|---|---|---|
r? | number | radius of the dot in pixels | |
role? | string | colour role (ink, faint, accent, s1 to s8) or a role you define in CSS | |
trail? | number | how many fading copies follow the pulse | |
spacing? | number | how far apart the copies are, as a fraction of the path |
One drawn row of text: a slice [start, end) of the source, and the source line it came from.
| Option | Type | Default | Description |
|---|---|---|---|
start | number | index of the first character in the source | |
end | number | index after the last character | |
line | number | the source line the row belongs to | |
first | boolean | whether it is the first row of its source line |
SceneOpts
Section titled “SceneOpts”Options of new Scene.
| Option | Type | Default | Description |
|---|---|---|---|
view? | Camera | View | a preset (‘iso’, ‘front’, ‘side’, ‘top’), explicit angles, or a ready-made Camera | |
size? | [number, number] | drawing size in viewBox units. Defaults to 320 by 200. | |
padding? | number | space around the drawing in viewBox units, 12 by default | |
region? | Region | part of the picture the scene may use, leaving room for insets | |
light? | V3 | direction towards the light, in world space | |
title? | string | accessible name and description | |
desc? | string | longer accessible description of the figure | |
sketch? | boolean | { roughness?: number; seed?: number; } | a hand-drawn look: lines wobble a little and are drawn twice. true, or { roughness, seed }. Repeatable: the same scene always wobbles the same way. | |
fit? | 'auto' | 'sphere' | ‘auto’ (default) fits the drawing each frame. ‘sphere’ fits the bounding sphere, so the object keeps its size while the camera turns. | |
split? | boolean | cut faces that pierce each other along the crossing, so they sort correctly. Off by default: it costs time on every frame, and most scenes have nothing that pierces. |
One cubic Bezier segment: start, two control points, end. Lines are cubics with the controls on the ends.
type Seg = [Pt, Pt, Pt, Pt]Sphere
Section titled “Sphere”A sphere in world space: a centre c and a radius r.
| Option | Type | Default | Description |
|---|---|---|---|
c | V3 | the centre | |
r | number | the radius |
StyleOpts
Section titled “StyleOpts”Colour and line width, shared by lines, faces and text.
| Option | Type | Default | Description |
|---|---|---|---|
role? | string | colour role: ink, faint, accent, warm, cool, s1 to s8, or any name you define in CSS as .cn-r-name | |
width? | number | line width in SVG units |
SurfaceOpts
Section titled “SurfaceOpts”Options of surface.
Extends FaceOpts.
| Option | Type | Default | Description |
|---|---|---|---|
u? | [number, number] | parameter ranges | |
v? | [number, number] | range of the second parameter, [min, max] | |
res? | [number, number] | number of cells along u and v | |
color? | ((p: V3, u: number, v: number) => number) | returns 0 to 1 per point, blending the colour from the role towards the accent |
SvgPlaneOpts
Section titled “SvgPlaneOpts”Options shared by everything that is an SVG drawing placed on a plane: charts, screens and maths figures.
Extends NodeOpts.
| Option | Type | Default | Description |
|---|---|---|---|
size? | [number, number] | size in world units | |
u? | V3 | directions of the drawing’s right and up. Default: a wall facing the viewer. | |
v? | V3 | direction of the plane’s upward axis | |
cull? | boolean | hide the plane when it is seen from behind, so a face of a closed shape does not show through the faces in front. Off by default. |
TextBlockOpts
Section titled “TextBlockOpts”Options of write and code.
Extends NodeOpts.
| Option | Type | Default | Description |
|---|---|---|---|
text | string | string[] | the text, or an array of lines | |
size? | [number, number] | size of the plane in world units. Text is laid out inside it from the top left. | |
u? | V3 | direction of the text’s x axis and of its (upward) y axis. Defaults to a wall facing the viewer. | |
v? | V3 | direction of the text’s upward y axis | |
fontSize? | number | 'sm' | 'md' | 'lg' | height of a line of text: world units, or ‘sm’ | ‘md’ | ‘lg’ relative to the box. Default fits the box. | |
lines? | number | or: this many lines fill the box | |
code? | boolean | colour the pieces of code (keywords, strings, numbers, comments) | |
numbers? | boolean | show line numbers | |
color? | string | CSS colour of ordinary text. Defaults to the theme ink. | |
pad? | number | margin inside the plane, in world units | |
lineHeight? | number | distance between lines as a multiple of the font size | |
cursor? | boolean | 'always' | show a cursor while typing, or always | |
align? | 'start' | 'end' | 'middle' | horizontal alignment inside the box | |
border? | string | false | colour role of a line drawn around the plane (e.g. ‘faint’), or false for none | |
wrap? | 'word' | 'char' | 'none' | how to break long lines: at spaces (default), anywhere, or not at all | |
overflow? | 'shrink' | 'clip' | when the text does not fit: make it smaller (default) or cut it off at the edge | |
mark? | Marks | colour chosen words: { deploy: ‘accent’ } or [[/\d+/, ‘s2’], [[0, 4], ‘faint’]]. A role name or any CSS colour. | |
charWidth? | number | width of a character as a fraction of the font size. 0.6 suits the default monospace font. |
TextOpts
Section titled “TextOpts”Options of label.
| Option | Type | Default | Description |
|---|---|---|---|
anchor? | 'start' | 'end' | 'middle' | which end of the text sits at the point | |
dx? | number | nudge in final pixels (a text always faces the viewer) | |
dy? | number | nudge down in pixels | |
size? | number | font size in pixels |
A piece of a line of code with its kind, for colouring.
| Option | Type | Default | Description |
|---|---|---|---|
text | string | the characters of the piece | |
kind | TokenKind | what the piece is |
TokenKind
Section titled “TokenKind”What a token is: plain text, a keyword, a string, a number or a comment.
type TokenKind = 'plain' | 'keyword' | 'string' | 'number' | 'comment'One change of one object’s properties over a span of time.
| Option | Type | Default | Description |
|---|---|---|---|
target | Animatable | the animated object | |
to | Record<string, To> | the values to reach, or functions of the current value | |
from? | Record<string, Value> | values set before the tween starts, so something can wait invisible until its moment | |
start | number | start time in seconds, relative to its animation | |
duration | number | length in seconds | |
ease | Ease | the easing function |
TweenOpts
Section titled “TweenOpts”Options of tween.
| Option | Type | Default | Description |
|---|---|---|---|
duration? | number | length in seconds, 1 by default | |
ease? | 'back' | Ease | 'linear' | 'in' | 'out' | 'inOut' | 'smooth' | an easing name or function, inOut by default | |
from? | Record<string, Value> | values set before the tween starts | |
delay? | number | seconds to wait before it starts |
A point or direction [x, y, z]. x runs right, y runs into the scene, z runs up.
type V3 = [number, number, number]A camera preset (iso, front, side, top) or explicit { yaw, pitch } angles in degrees.
type View = 'iso' | 'front' | 'side' | 'top' | { yaw: number; pitch: number }Values
Section titled “Values”The named easing curves: linear, in, out, inOut, smooth and back. Each maps time 0 to 1 onto progress 0 to 1.
const ease: { linear: (t: number) => number; in: (t: number) => number; out: (t: number) => number; inOut: (t: number) => number; smooth: (t: number) => number; back: (t: number) => number; }