> ## Documentation Index
> Fetch the complete documentation index at: https://klyne-research.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Intrinsics

> Vector geometry, pack/unpack, and type-casting intrinsics callable inside @enigma.kernel bodies.

For arithmetic, math, and comparison ops, see
[Operations](/programming-guide/operations). This page covers the API surface
for the remaining intrinsics: vector construction, geometry, packing/unpacking
between float vectors and packed integers, and type casting.

## Type casting

### `enigma.metal_cast(value, dtype) -> IRValue`

Numeric conversion. Lowers to MSL `static_cast<T>(x)`.

| Parameter | Type                 | Description                                                            |
| --------- | -------------------- | ---------------------------------------------------------------------- |
| `value`   | IRValue or int/float | Value to cast                                                          |
| `dtype`   | type or str          | Target type, e.g. `enigma.f32`, `"float"`, `"int"`, `"uint"`, `"half"` |

### `enigma.as_type(value, dtype) -> IRValue`

Bitwise reinterpret. Target type must have the same bit width. Lowers to MSL
`as_type<T>(x)`.

```python theme={null}
bits = enigma.as_type(x_f32, "uint")   # IEEE-754 bits of a float
```

***

## Vector construction

Short vectors are `IRValue`s with dtype `"vec<N,elem>"` and map to Metal
`floatN` / `halfN` / `intN` / `uintN` types.

### `enigma.make_vec(*components) -> IRValue`

Construct a vector from 2, 3, or 4 scalar components. All components must
share the same dtype.

### Convenience constructors

| Function                         | Equivalent                        |
| -------------------------------- | --------------------------------- |
| `enigma.make_float2(x, y)`       | `make_vec(x, y)` over `f32`       |
| `enigma.make_float3(x, y, z)`    | `make_vec(x, y, z)` over `f32`    |
| `enigma.make_float4(x, y, z, w)` | `make_vec(x, y, z, w)` over `f32` |

### Lane access

```python theme={null}
v = enigma.make_float3(a, b, c)
x = v.x         # equivalent to enigma.vec_extract(v, 0)
y = v.y
z = v.z
```

| Function                      | Description                            |
| ----------------------------- | -------------------------------------- |
| `enigma.vec_extract(v, lane)` | Extract scalar at lane index (0-based) |
| `v.x` / `v.y` / `v.z` / `v.w` | Property-style component access        |

***

## Geometry

All take vector `IRValue`s. Returns are scalar or vector as noted.

### Scalar-returning

| Function                | Signature              | Description             |
| ----------------------- | ---------------------- | ----------------------- |
| `enigma.dot(a, b)`      | `(vec, vec) -> scalar` | Dot product             |
| `enigma.length(v)`      | `(vec) -> scalar`      | Euclidean length        |
| `enigma.distance(a, b)` | `(vec, vec) -> scalar` | Distance between points |

### Vector-returning

| Function                         | Signature                   | Description                    |
| -------------------------------- | --------------------------- | ------------------------------ |
| `enigma.normalize(v)`            | `(vec) -> vec`              | Unit vector                    |
| `enigma.cross(a, b)`             | `(vec3, vec3) -> vec3`      | Cross product (3D only)        |
| `enigma.reflect(i, n)`           | `(vec, vec) -> vec`         | Reflect `i` about normal `n`   |
| `enigma.refract(i, n, eta)`      | `(vec, vec, scalar) -> vec` | Refract with index `eta`       |
| `enigma.faceforward(n, i, nref)` | `(vec, vec, vec) -> vec`    | Flip `n` if `dot(i, nref) < 0` |

***

## Pack / unpack (color and texture formats)

Convert between float vectors and packed integer representations. These mirror
MSL's `pack_float_to_*` / `unpack_*_to_float` functions used for color and
texture encoding.

For integer-only packing (uint8, int4) used in quantized GEMM, see
[Quantization Helpers](/programming-guide/high-level-ops#quantization-helpers).

### Pack: vector → uint

All take a vector `IRValue` and return a `uint` `IRValue`.

| Function                                | Input  | Description                    |
| --------------------------------------- | ------ | ------------------------------ |
| `enigma.pack_float_to_snorm4x8(v)`      | float4 | Signed normalized 4×8-bit      |
| `enigma.pack_float_to_unorm4x8(v)`      | float4 | Unsigned normalized 4×8-bit    |
| `enigma.pack_float_to_snorm2x16(v)`     | float2 | Signed normalized 2×16-bit     |
| `enigma.pack_float_to_unorm2x16(v)`     | float2 | Unsigned normalized 2×16-bit   |
| `enigma.pack_float_to_srgb_unorm4x8(v)` | float4 | sRGB unsigned normalized 4×8   |
| `enigma.pack_float_to_unorm10a2(v)`     | float4 | 10-10-10-2 unsigned normalized |

### Unpack: uint → vector

All take a `uint` `IRValue` and return a vector `IRValue`.

| Function                                  | Output | Description                    |
| ----------------------------------------- | ------ | ------------------------------ |
| `enigma.unpack_snorm4x8_to_float(x)`      | float4 | Signed normalized 4×8          |
| `enigma.unpack_unorm4x8_to_float(x)`      | float4 | Unsigned normalized 4×8        |
| `enigma.unpack_snorm2x16_to_float(x)`     | float2 | Signed normalized 2×16         |
| `enigma.unpack_unorm2x16_to_float(x)`     | float2 | Unsigned normalized 2×16       |
| `enigma.unpack_srgb_unorm4x8_to_float(x)` | float4 | sRGB unsigned normalized 4×8   |
| `enigma.unpack_unorm10a2_to_float(x)`     | float4 | 10-10-10-2 unsigned normalized |

### Example: round-trip

```python theme={null}
v = enigma.make_float4(r, g, b, a)
packed = enigma.pack_float_to_unorm4x8(v)
restored = enigma.unpack_unorm4x8_to_float(packed)
r_back = restored.x   # quantized to 8-bit precision
```
