Skip to content

Vex

Write one formula. Evaluate it at each record. When a value is missing, Vex tells you why.
npm i @mark1russell7/vex @mark1russell7/vex-domains
ABCDEFGHI
const centre = root.from("size")
  ._.halve()._.add("position");
centre.others((e) => e._.distance(
  e.from("size")._.halve()._.add("position")));
arrow: the nearest other box. red edge: the box overlaps another box. Point at a box to see its list.18 programs in 0.00 ms each frame

Each page below is interactive. The programs run in your browser, with the same packages that you install from npm.

Vex started as layout math. A layout engine had boxes with a position and a size, and it asked questions like “does this box overlap another box?” The program below asks that question at each box.

Drag a box. Each program on this page reads the same four boxes, so each one evaluates again. Select an origin to see the program from the view of another box. Move the slider to see each step of the evaluation.

Does the box overlap another box?origin
root.from("position")._.add("size")
  .others((e) =>
    e._.subtract("position")._.allPositive()._.and(
      e.from("position")._.add("size")._.subtract(e.origin().from("position"))._.allPositive()))
  .any()
step 27 of 27

Result at A: true

originABCD
resulttruetruefalsefalse

A formula at each record

A Vex program evaluates at one key of a space of records. A field name reads at the focus. An address reads at another key, like a spreadsheet reference.

Axes

The others axis evaluates a body at each other key. The base value comes from the origin, and the fields come from each target.

Error values

Vex does not throw. A failure is an error value with a code, for example #REF! or #N/A, and a trace shows where it started.

Your domains

A domain tells Vex which values belong to it, which ops they have, and which laws the ops obey. Tests check each law.

Install the core and the domains. Then build a chain over your own records. The chain has the type of its result.

import { space, vex } from "@mark1russell7/vex";
import { Vec2, Vec2Domain } from "@mark1russell7/vex-domains";
const A = { position: new Vec2(2, 2), size: new Vec2(5, 4) };
const B = { position: new Vec2(6, 5), size: new Vec2(4, 4) };
const separated = vex(Vec2Domain)
.over(space.record({ A, B }))
.from("position")._.add("size")
.other()._.subtract("position")
._.anyNonPositive();
separated.at("A"); // { tag: "some", value: false }
separated.explain("A"); // a trace of each step

The tour adds one call at a time to a chain. The API lists each export, and the specification shows the test status of each requirement.