---
title: "Dive into 3D Math: A Beginner's Toolkit for Twinfinity Developers"
canonical: "https://help.twinfinity.com/space/HCFD/136773638/Dive%20into%203D%20Math%3A%20A%20Beginner's%20Toolkit%20for%20Twinfinity%20Developers"
format: markdown
---
Most of the heavy 3D maths in a Twinfinity app is handled for you by Twinfinity and Babylon.js. But a working grasp of a few core ideas makes it much easier to position objects, read picks, and reason about what the viewer is doing. This is a short, practical primer.

## Vectors and points

A **vector** is a direction with a magnitude — an arrow in space, with x, y and z components. You'll use vectors for directions, offsets, and surface normals.

A **point** is a specific location. Mechanically it's also an (x, y, z) triple, but conceptually it answers *where*, not *which way*. Twinfinity and Babylon.js represent both with `Vector3`:

```ts
import { Vector3 } from '@babylonjs/core';

const position = new Vector3(4, 0, 2); // a point in the model
const up = new Vector3(0, 1, 0); // a direction
```

## Coordinate system

Twinfinity uses a **left-handed Cartesian** coordinate system, and the model unit is **metres** — so a distance of `1` in the scene is one metre in the real building.

![Left-handed Cartesian coordinate system](media://7ec38d26-e744-4132-ada4-ef65ca4b0990)

Objects also have **local** coordinates (relative to their own origin and orientation) that resolve into **world** coordinates — positions in the overall scene — through their transform.

## Transformations

Three operations move and reshape objects:

1. **Scale** — change size.
2. **Rotate** — spin around an axis.
3. **Translate** — move from one place to another.

> When you combine them, apply them in **scale → rotate → translate** order, or the result won't be what you expect.

## Dot product

The **dot product** of two vectors is a single number telling you how aligned they are — handy for angles, lighting, and "is this facing me?" checks.

![image](media://d1465d86-9466-42d6-8ece-f5634036d6b3)

For unit vectors it's `1` when they point the same way, `0` when perpendicular, and `-1` when opposite:

```ts
const a = new Vector3(1, 0, 0);
const b = new Vector3(0, 1, 0);
const d = Vector3.Dot(a, b); // 0 → the vectors are perpendicular
```

## Cross product

The **cross product** gives a vector perpendicular to two others — the basis for computing surface normals.

![image](media://24702202-5fc9-4430-8537-cc42eb68441f)

```ts
const x = new Vector3(1, 0, 0);
const y = new Vector3(0, 1, 0);
const z = Vector3.Cross(x, y); // (0, 0, 1) — perpendicular to both
```

## Normals

A **normal** is a unit vector pointing straight out of a surface — it tells you which way the surface faces. "Normalized" means its length is exactly `1`: a pure direction, not a distance.

Normals come up constantly — lighting uses them, and you can use them to place things *on* a surface. A pick returns the hit point and its normal, so you can offset along the normal to rest an object on the surface. Because the normal is unit-length, scaling it by a distance moves exactly that far — here, by the sphere's radius so it sits tangent to the face:

```ts
// From a pick(true) result, rest a sphere on the picked surface.
const position = pick.hitInfo[0].position;
const normal = pick.hitInfo[0].normal;
sphere.position = position.add(normal.scale(sphereDiameter / 2)); // offset by the radius along the normal
```

See it in action: [Place a sphere on a surface](https://playground.twinfinity.dev/?pgId=interaction/place-sphere).

## In practice

Twinfinity and Babylon.js do most of the calculation for you. But knowing what a dot product, a cross product or a normal actually *is* turns the API from mysterious into obvious — and lets you do your own positioning when you need to.