Foundations Syntax and Atoms Lesson 04

Numbers, units, vectors

Mental Model

A number can carry an opaque unit suffix:

4b
90deg
50%
250ms
1.5e2hz

Open in playground →

SJON preserves the suffix but does not interpret it. The host or plugin decides what b, deg, ms, or % means.

The e or E starts an exponent only when the next character is a digit or sign:

1e9       ; exponent
1e+9      ; exponent
1em       ; number 1 with unit em
1e-9ms    ; exponent plus unit ms

Open in playground →

Vectors are ordered lists:

[160 120]
[0.9 0.4 0.2 1.0]
[[0 0] [1 0] [1 1]]

Open in playground →

A plugin may refine a vector slot to require a length and element kind, such as “2-vector of numbers”. When a plugin only says “vector”, the validator checks that the value is a vector; when it says “2-vector of numbers”, it also checks the shape.

Worked Example

(shape :path :closed true
  :points [[0 0] [1 0] [1 1] [0 1]])

Open in playground →

Read the values:

  • true is a boolean.
  • [[0 0] [1 0] [1 1] [0 1]] is a vector of vectors.
  • Each inner vector looks like a point.

From the shapes tutorial scene:

(circle :center [160 120] :radius (* 2 16))

Open in playground →

:center is written in the conventional point shape, [x y]. :radius is an expression in a numeric slot.

Exercises

Classify the unit behavior:

  1. 1e9
  2. 1em
  3. 1e-9ms
  4. 60_000ms
  5. 50%

Repair the values:

(circle :center [160] :radius 32)

Open in playground →

If the plugin docs say :center is a 2-number point, write two numbers:

(circle :center [160 120] :radius 32)

Open in playground →

(shape :sdf :color [0.9 0.4 0.2])

Open in playground →

If :color expects RGBA, write four numbers:

(shape :sdf :color [0.9 0.4 0.2 1.0])

Open in playground →

(delay :wait 0.5)

Open in playground →

If :wait expects a unit-bearing duration, supply the unit the plugin allows:

(delay :wait 0.5s)

Open in playground →

(shape :path :points [0 0 1 0 1 1])

Open in playground →

If :points expects a vector of points, group each point:

(shape :path :points [[0 0] [1 0] [1 1]])

Open in playground →

A schema can also constrain a number’s value, not just its tag. A value-kind with a :numeric refinement pins ranges (:min, :max, :exclusive-min, :exclusive-max) and integrality (:integer true). The reference is in docs/LANGUAGE.md §6.5 (NumericBounds) and §4.3 of docs/portable-manifest-v1.md. As an author you don’t write the bound; you just see number_below_min / number_above_max diagnostics if your value falls outside the declared range.

Mastery Check

  1. Does SJON itself know that ms means milliseconds?

  2. What is the difference between 1e9 and 1em?

  3. Is [0 0 1 1] the same shape as [[0 0] [1 1]]?

  4. Can vector elements be forms?