# Cordial Language Reference

Cordial is the primary source language for the Cord geometry system.
It compiles to a trigonometric intermediate representation (TrigGraph)
which can be evaluated as an f64 reference, compiled to WGSL shaders
for GPU raymarching, or lowered to pure CORDIC shift-and-add arithmetic.

File extension: `.crd`

---

## Variables

```
let r = 5
let height = 2 * pi
let s: Obj = sphere(r)
```

- `let` introduces a new variable.
- `: Obj` type annotation marks a variable as a renderable 3D object.
- Variables can be reassigned: `r = 10` (no `let` on reassignment).

---

## Constants

| Name      | Value         |
|-----------|---------------|
| `pi`, `PI`| 3.14159...    |
| `e`, `E`  | 2.71828...    |
| `x`       | Input X coord |
| `y`       | Input Y coord |
| `z`       | Input Z coord |
| `reg`     | NaN register  |

`x`, `y`, `z` are the spatial coordinates — use them to build
mathematical expressions and SDF fields directly.

---

## Arithmetic

| Syntax  | Operation      |
|---------|----------------|
| `a + b` | Addition       |
| `a - b` | Subtraction    |
| `a * b` | Multiplication |
| `a / b` | Division       |
| `a ^ b` | Power (²,³ optimized) |
| `-a`    | Negation       |

Precedence: unary > power > multiplicative > additive.
Parentheses for grouping: `(a + b) * c`.

---

## Comments

```
// line comment
/= also a line comment

/* block comment */
/* nested /* block */ comments */
```

---

## Trig Functions

| Function | Aliases | Description |
|----------|---------|-------------|
| `sin(x)` | | Sine |
| `cos(x)` | | Cosine |
| `tan(x)` | | Tangent |
| `asin(x)` | `arcsin` | Inverse sine |
| `acos(x)` | `arccos`, `arcos` | Inverse cosine |
| `atan(x)` | `arctan` | Inverse tangent |
| `sinh(x)` | | Hyperbolic sine |
| `cosh(x)` | | Hyperbolic cosine |
| `tanh(x)` | | Hyperbolic tangent |
| `asinh(x)` | `arcsinh` | Inverse hyperbolic sine |
| `acosh(x)` | `arccosh`, `arcosh` | Inverse hyperbolic cosine |
| `atanh(x)` | `arctanh` | Inverse hyperbolic tangent |

---

## Math Functions

| Function | Aliases | Description |
|----------|---------|-------------|
| `sqrt(x)` | | Square root |
| `exp(x)` | | e^x |
| `ln(x)` | `log` | Natural logarithm |
| `abs(x)` | | Absolute value |
| `hypot(a, b)` | | √(a² + b²) |
| `atan2(y, x)` | | Two-argument arctangent |
| `min(a, b)` | | Minimum |
| `max(a, b)` | | Maximum |
| `length(a, b)` | `mag` | Magnitude (2D or 3D) |
| `mix(a, b, t)` | `lerp` | Linear interpolation |
| `clip(x, lo, hi)` | `clamp` | Clamp to range |
| `smoothstep(e0, e1, x)` | | Hermite interpolation |
| `quantize(x, step)` | | Snap to grid |

---

## SDF Primitives

These construct signed distance fields centered at the origin.
All dimensions are half-extents (centered geometry).

| Function | Arguments | Description |
|----------|-----------|-------------|
| `sphere(r)` | radius | Sphere |
| `box(hx, hy, hz)` | half-extents | Axis-aligned box |
| `cylinder(r, h)` | radius, half-height | Z-axis cylinder |
| `ngon(n, side)` | sides (≥3), side length | Regular polygon prism |
| `N-gon(side)` | side length | Shorthand: `6-gon(2)` = hexagonal prism |

---

## Transforms

Transforms take an SDF as the first argument and modify its coordinate space.

| Function | Aliases | Arguments | Description |
|----------|---------|-----------|-------------|
| `translate(sdf, tx, ty, tz)` | `mov`, `move` | SDF + offsets | Translate |
| `rotate_x(sdf, angle)` | `rx` | SDF + radians | Rotate around X |
| `rotate_y(sdf, angle)` | `ry` | SDF + radians | Rotate around Y |
| `rotate_z(sdf, angle)` | `rz` | SDF + radians | Rotate around Z |
| `scale(sdf, factor)` | | SDF + uniform scale | Uniform scale |
| `mirror_x(sdf)` | `mx` | SDF | Mirror across YZ plane |
| `mirror_y(sdf)` | `my` | SDF | Mirror across XZ plane |
| `mirror_z(sdf)` | `mz` | SDF | Mirror across XY plane |

---

## CSG Boolean Operations

| Function | Aliases | Arguments | Description |
|----------|---------|-----------|-------------|
| `union(a, b)` | | two SDFs | Union (min) |
| `intersect(a, b)` | | two SDFs | Intersection (max) |
| `diff(a, b)` | `subtract` | two SDFs | Difference (max(a, -b)) |

---

## Waveform Functions

| Function | Arguments | Description |
|----------|-----------|-------------|
| `saw(x)` | input | Sawtooth wave |
| `tri(x)` | input | Triangle wave |
| `square(x)` | input | Square wave |

---

## DSP / Signal Functions

| Function | Arguments | Description |
|----------|-----------|-------------|
| `am(signal, carrier, depth)` | | Amplitude modulation |
| `fm(signal, carrier, index)` | | Frequency modulation |
| `lpf(signal, cutoff)` | | Low-pass filter approximation |
| `hpf(signal, cutoff)` | | High-pass filter approximation |
| `bpf(signal, lo, hi)` | | Band-pass filter approximation |
| `dft(signal, n)` | | Discrete Fourier approximation |
| `hilbert(x)` | `envelope` | Analytic signal envelope |
| `phase(x)` | | Instantaneous phase |

---

## User-Defined Functions

```
f(a, b) = a^2 + b^2
let result = f(3, 4)
```

Define with `name(params) = body`. Body extends to the next
newline or semicolon. Functions are expanded inline at each call site.

---

## Schematics (`sch`)

Schematics are parameterized multi-statement blocks — like functions but
with full block bodies containing `let` bindings, intermediate variables,
and arbitrary nesting. The last expression is the return value.

```
sch Bracket(w, h, t) {
    let plate: Obj = box(w, h, t)
    let rib: Obj = box(t, h/2, t)
    union(plate, translate(rib, w/2, 0, 0))
}

let b = Bracket(10, 5, 0.5)
cast(b)
```

Schematics can call other schematics and user-defined functions.
They can contain any number of statements.

```
sch Peg(r, h) {
    let shaft = cylinder(r, h)
    let head = translate(sphere(r * 1.5), 0, 0, h)
    union(shaft, head)
}

sch PegRow(n, spacing) {
    map(i, 0..n) { translate(Peg(0.5, 3), i * spacing, 0, 0) }
}
```

---

## Iteration (`map`)

`map` evaluates a body for each integer in a range and unions all
results. Iteration is unrolled at parse time — the TrigGraph is a DAG
with no runtime loops.

```
map(variable, start..end) { body }
```

- `variable` — bound to each integer in `[start, end)`
- `start..end` — exclusive range; bounds must resolve to constants
- `body` — any expression or block; can reference the iteration variable
- All iterations are unioned (min)
- Max 1024 iterations

### Examples

```
// Row of 5 spheres along X
let row = map(i, 0..5) { translate(sphere(1), i * 3, 0, 0) }

// Ring of 8 spheres
let ring = map(i, 0..8) {
    rotate_z(translate(sphere(0.5), 5, 0, 0), i * pi/4)
}

// Grid using nested maps inside a schematic
sch Grid(nx, ny, spacing) {
    map(i, 0..nx) {
        map(j, 0..ny) {
            translate(sphere(0.4), i * spacing, j * spacing, 0)
        }
    }
}

let g = Grid(4, 6, 2)
cast()
```

Since `map` is an expression, it works anywhere: inside `let` bindings,
as arguments to functions, inside schematic bodies, or nested in other maps.

---

## Rendering with `cast()`

Nothing renders without an explicit `cast()` call.

| Syntax | Effect |
|--------|--------|
| `cast()` | Render all defined variables |
| `cast(name)` | Render a specific variable |
| `name.cast()` | Dot syntax (Obj-typed variables only) |

Multiple `cast()` calls accumulate. The GUI provides a Render button
that inserts `cast()` automatically when new variables exist since
the last cast.

### Example

```
let a: Obj = sphere(3)
let b: Obj = box(4, 2, 1)
let c: Obj = translate(a, 5, 0, 0)
cast()
```

This renders `a`, `b`, and `c` as a union. Without `cast()`, nothing appears.

---

## Plotting with `plot()`

| Syntax | Effect |
|--------|--------|
| `plot()` | Plot all bare expressions |
| `plot(expr)` | Plot a specific expression |

The GUI provides a Plot button that inserts `plot()` when new
expressions exist since the last plot.

### Example

```
sin(x) * exp(-x^2)
plot()
```

---

## Complete Example

```
// Bolt head: hexagonal prism with a sphere on top
let head: Obj = 6-gon(3)
let dome: Obj = translate(sphere(3.2), 0, 0, 1.5)
let cap: Obj = intersect(head, dome)

// Shaft
let shaft: Obj = cylinder(1.2, 8)
let bolt: Obj = union(translate(cap, 0, 0, 8), shaft)

// Cross hole
let slot: Obj = box(0.4, 3, 10)
let slot2: Obj = rotate_z(slot, pi/2)
let cross: Obj = union(slot, slot2)

let final: Obj = diff(bolt, cross)
cast(final)
```

### Schematics + Iteration

```
// Reusable peg schematic
sch Peg(r, h) {
    let shaft = cylinder(r, h)
    let head = translate(sphere(r * 1.5), 0, 0, h)
    union(shaft, head)
}

// Base plate with a ring of pegs
let plate: Obj = box(20, 20, 1)
let pegs: Obj = map(i, 0..8) {
    rotate_z(translate(Peg(0.5, 3), 8, 0, 1), i * pi/4)
}
let assembly: Obj = union(plate, pegs)
cast(assembly)
```
