Skip to content

Vectors (std::vec)

std::vec provides floating-point vectors with 2, 3 or 4 components — useful for game math, animation, physics and colour manipulation. Import with use std::vec. Operations are functions (vec.add, vec.dot…); a native primitive type with operator overloading is planned for a future iteration.

Constructors and arithmetic

vec.vec2, vec.vec3 and vec.vec4 create vectors; vec.zero(n) creates the zero vector of dimension n. Components are accessed as fields .x, .y, .z, .w.

Addition, subtraction, scaling, dot product, cross product, length, normalisation, distance and linear interpolation.

01-constructors-and-arithmetic.zolo
Playground
// Feature: vec stdlib — 2/3/4-component float vectors

// When to use: creative coding, gameplay math, color math, plugin interop.

//

// MVP scope (today): vectors are plain tables with named axes; ops are

// functions, not operators. A future iteration will add primitive

// `vec3<f32>` types with operator overloading and full swizzling.

//

// See `specs/vec-primitive-types.md` for the full target spec.


use std::vec

// Constructors — vec2 / vec3 / vec4 plus a `zero(n)` shortcut.

let p = vec.vec3(1.0, 2.0, 3.0)
let q = vec.vec3(0.5, 0.5, 0.5)
let z3 = vec.zero(3)

// Field access by axis name.

print("p = ({p.x}, {p.y}, {p.z})")          // (1, 2, 3)

print("z3 = ({z3.x}, {z3.y}, {z3.z})")      // (0, 0, 0)


// Arithmetic — addition, subtraction, scalar scale.

let sum = vec.add(p, q)
print("p + q = ({sum.x}, {sum.y}, {sum.z})")    // (1.5, 2.5, 3.5)


let diff = vec.sub(p, q)
print("p - q = ({diff.x}, {diff.y}, {diff.z})") // (0.5, 1.5, 2.5)


let doubled = vec.scale(p, 2.0)
print("p * 2 = ({doubled.x}, {doubled.y}, {doubled.z})")  // (2, 4, 6)


// Dot product (scalar).

print("p . q = {vec.dot(p, q)}")    // 3


// Cross product (vec3-only).

let cross = vec.cross(vec.vec3(1.0, 0.0, 0.0), vec.vec3(0.0, 1.0, 0.0))
print("x x y = ({cross.x}, {cross.y}, {cross.z})")    // (0, 0, 1)


// Length / length squared.

print("|p| = {vec.length(p)}")             // 3.7416...

print("|p|^2 = {vec.length_sq(p)}")        // 14


// Normalize — handles zero-length gracefully (returns zero vector).

let n = vec.normalize(p)
print("normalize(p) = ({n.x}, {n.y}, {n.z})")

// Distance.

print("distance(p, q) = {vec.distance(p, q)}")

// Componentwise linear interpolation.

let mid = vec.lerp(p, q, 0.5)
print("lerp(p, q, 0.5) = ({mid.x}, {mid.y}, {mid.z})")

Colour aliases and swizzle

vec3/vec4 vectors also expose .r, .g, .b, .a fields — synonyms for .x, .y, .z, .w. Multi-component access (.rgb, .bgr, .xxxx…) returns a new reordered or replicated vector. Mixing the xyzw and rgba sets in the same swizzle returns nil.

rgba aliases; swizzles rgb, bgr, xy, xxxx, bgra; invalid swizzle xr returns nil; lerp between colours.

02-color-and-swizzle.zolo
Playground
// Feature: vec stdlib — color aliases and multi-component swizzling

// When to use: graphics code that reads better with rgba than xyzw.

//

// vec3/vec4 expose both .x/.y/.z/.w and .r/.g/.b/.a fields pointing at

// the same component values. Multi-component access (`.xyz`, `.bgr`,

// `.xxxx`, etc.) returns a NEW vector via the swizzle metamethod —

// reorder, reduce, or replicate components as needed.


use std::vec

let color = vec.vec4(1.0, 0.5, 0.25, 0.9)

// Single component (existing):

print("xyzw: ({color.x}, {color.y}, {color.z}, {color.w})")
print("rgba: ({color.r}, {color.g}, {color.b}, {color.a})")

// Multi-component swizzles return a NEW vector componentwise.

// Same set must be used end-to-end — `.xr` mixes xyzw with rgba and

// returns nil.

let rgb = color.rgb        // vec3(1, 0.5, 0.25)

print("rgb = ({rgb.r}, {rgb.g}, {rgb.b})")

let bgr = color.bgr        // vec3(0.25, 0.5, 1)  — reordered

print("bgr = ({bgr.r}, {bgr.g}, {bgr.b})")

let xy = color.xy          // vec2(1, 0.5)

print("xy = ({xy.x}, {xy.y})")

let xxxx = color.xxxx      // vec4(1, 1, 1, 1)  — replicated

print("xxxx = ({xxxx.x}, {xxxx.y}, {xxxx.z}, {xxxx.w})")

let bgra = color.bgra      // vec4(0.25, 0.5, 1, 0.9)  — color swap

print("bgra = ({bgra.r}, {bgra.g}, {bgra.b}, {bgra.a})")

// Invalid swizzles return nil. Mixing sets and oversize keys:

let mixed = color.xr
print("xr (mixed set) = {mixed}")   // nil


// Composing colors with lerp:

let red = vec.vec4(1.0, 0.0, 0.0, 1.0)
let blue = vec.vec4(0.0, 0.0, 1.0, 1.0)
let purple = vec.lerp(red, blue, 0.5)
print("red+blue/2 = ({purple.r}, {purple.g}, {purple.b}, {purple.a})")

Challenge

Create two vec3 vectors representing two points in space, compute the distance between them with vec.distance and verify that the normalised direction vector has length ~= 1.0.

enespt-br