---
title: "Units and precision"
description: "Millimetres everywhere, degrees for angles, exact arithmetic internally, 0.1 mm on display — and the rule that stops a rounded cut list breaking a clearance that passed."
url: https://kaicad.barpom.xyz/docs/schema/units-and-precision
schema: "0.1"
source: packages/spec/src/units.ts
---

# Units and precision

## Metric only

Every length in a design is **millimetres**. Every angle is **degrees**. There is no
alternative unit, no per-field unit suffix and no conversion layer.

```yaml
units: mm
```

The `units` key accepts only `mm`. It exists so that a document written in inches is rejected
with a clear message rather than compiled into a piece of furniture forty times too large.

This is not a preference. Mixed units are one of the classic ways a parametric model goes
quietly wrong, and the cost of supporting them — every expression, every catalogue entry and
every finding carrying a unit — buys nothing that a converted number at the point of authoring
does not.

**If you think in inches**, convert once, when you write the file: 3/4″ is 19 mm, 1½″ is
38 mm, 4′ × 8′ is 1220 × 2440. The catalogue's milled sizes are metric actuals, so 19 mm and
25 mm are real thicknesses you can buy.

Degrees rather than radians for angles, because a human writes this file.

## Exact inside, rounded only to show you

Internally every length is a floating-point millimetre and stays that way. Nothing is rounded
in transit — not between the resolver and the assembler, not between the assembler and the
validator, not on the way into an export.

Rounding happens at **presentation only**: 0.1 mm on the cut list, in the inspector and on a
drawing's dimensions. A part 1636.0000001 mm long reads as 1636 mm, and the validator still
saw the number it actually was.

Two lengths closer than 10⁻⁶ mm are the same length as far as validation is concerned. That
tolerance sits well below the display precision on purpose: anything you can see in the UI is
also distinguishable to the validator.

## The rule that matters

> A value rounded for a cut list must never silently violate a clearance that passed on the
> exact value.

Consider a clearance that requires at least 6 mm and comes out at 5.96 mm. It fails, and you
are told. Now consider one that comes out at 5.9999 mm against a 6 mm minimum: it fails on the
exact number, but a cut list printed at 0.1 mm would say **6.0**, and a person reading that
sheet would have no way of knowing the design did not pass.

The compiler detects exactly that case — where the exact value is on one side of a limit and
the rounded value is on the other — and does not let the rounded figure stand alone. What you
read on a sheet and what the validator checked cannot disagree about which side of a limit a
number is on.

## What this means when you author

**Do not pre-round.** Write the expression, not the answer:

```yaml
derived: mattress.width + 2 * mattress_clearance     # yes
value: 1536                                          # no
```

The second form is correct until something upstream moves, and then it is wrong with nothing
to say so.

**Do not chase the last 0.1 mm.** If a finding says a shelf sags 4.6 mm against a 4.5 mm
limit, the fix is a thicker shelf or a shorter span, not a slightly different number. The
suggestion in the finding is already computed — it will tell you which.

**Trust the material, not the nominal size.** The catalogue's thicknesses are what the board
actually measures, not what it is sold as. A "1 inch" board is 19 mm or 25 mm depending on the
family, and the resolver will reject a thickness that nothing is milled at rather than let you
design around a board that does not exist.

## Display, in practice

| Where | Precision |
| --- | --- |
| Cut list, BOM | 0.1 mm |
| Inspector, part properties | 0.1 mm |
| Drawing dimensions | 0.1 mm |
| Exports (STEP, GLB, STL) | Full precision |
| Validation findings | 0.1 mm, computed from the exact value |

Angles display as whole degrees unless they are not whole.
