> ## Documentation Index
> Fetch the complete documentation index at: https://docs.spurdoverse.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Vector

> 3D vector for world positions, directions and velocities.

export const like_0 = "Vec3Like"

export const name_0 = "Vector"

A 3D vector: world positions, directions, velocities. Global class, no import.

```ts theme={null}
const eye = new Vector(0, 0, 64);
const above = eye.add([0, 0, 16]);   // [x, y, z] and { x, y, z } work anywhere a Vector does
```

Fields are 32-bit floats; assigning a non-number or NaN throws.

## Overview

<CardGroup cols={2}>
  <Card title="Common" icon="layer-group" href="#common">
    `from`, `set`, `add`, `lerp`, `normalize`…
  </Card>

  <Card title="Length and distance" icon="ruler" href="#length-and-distance">
    `length`, `distTo`, `dot`, `cross`, 2D variants.
  </Card>

  <Card title="Angles" icon="compass" href="#angles">
    `toAngles`, `angleTo`.
  </Card>
</CardGroup>

***

## Common

Every argument takes any <code>{like_0}</code>, not just a <code>{name_0}</code>.

| Member | Does |
| :- | :- |
| <code>new {name_0}(value)</code>, <code>{name_0}.from(value)</code> | Copy from any <code>{like_0}</code>. |
| `set(...)` | Replaces every component in place, returns `this`. Same arguments as the constructor. |
| `clone()` | A copy. |
| `equals(other, epsilon?)` | Every component within `epsilon`. Default `0`, exact. |
| `toArray()`, `toJSON()` | Plain array, plain object. |
| `toString()` | <code>"{name_0}(…)"</code> |
| `add(other)`, `sub(other)` | Component-wise. |
| `scale(factor)` | Every component times `factor`. |
| `mul(x)`, `div(x)` | By a number, or component-wise by another value. Dividing by zero throws `RangeError`. |
| `lerp(other, t)` | Linear blend, `t` not clamped. |
| `normalize()`, `normalized()` | The first changes the value and returns `this`, the second returns a copy. |

Only `set()` and `normalize()` change the value. Nothing changes its arguments.

| Also | Returns |
| :- | :- |
| `Vector.zero()`, `Vector.one()` | `(0, 0, 0)`, `(1, 1, 1)` |
| `Vector.min(a, b)`, `Vector.max(a, b)` | Component-wise min / max |
| `negate()`, `abs()` | New `Vector` |
| `isZero(epsilon?)` | Every component within `epsilon` (default `1e-6`) of zero |
| `isFinite()` | No NaN or infinite component |

***

## Length and distance

The `2D` variants ignore `z`, which is what you want for horizontal distance on a map.

| Method | Returns |
| :- | :- |
| `length()`, `lengthSqr()` | Length, squared length |
| `length2D()`, `length2DSqr()` | Same, ignoring `z` |
| `distTo(other)`, `distToSqr(other)` | Distance, squared distance |
| `distTo2D(other)` | Distance ignoring `z` |
| `dot(other)` | Dot product |
| `cross(other)` | Cross product, a new `Vector` |

```ts theme={null}
const speed = velocity.length2D();              // horizontal speed, units/s
const near = myPos.distToSqr(pos) < 500 * 500;  // skips the sqrt
```

***

## Angles

Engine convention, in degrees: pitch positive looks down. See [QAngle](/api/types/qangle).

### toAngles

<br />

```ts theme={null}
toAngles(): QAngle
```

The view angles that look along this direction, roll `0`.

```ts theme={null}
new Vector(0, 1, 0).toAngles();   // QAngle(0, 90, 0)
velocity.toAngles().yaw;          // direction of travel
```

### angleTo

<br />

```ts theme={null}
angleTo(target: Vec3Like): QAngle
```

The view angles that aim from this point at `target`. Same as `target.sub(this).toAngles()`.

```ts theme={null}
const aim = eyePos.angleTo(headPos);
if (viewAngles.fovTo(aim) < 3) {
    // within 3° of the crosshair
}
```

For screen positions use [render.worldToScreen](/api/render#worldtoscreen), not angles.

***

## Example

Finds the enemy whose head is closest to the crosshair and circles it.

```ts theme={null}
import entities from "@native/entities";
import input from "@native/input";
import render from "@native/render";

on("render", () => {
    const me = entities.getLocalPlayer();
    const eye = me?.getEyePosition();
    const view = input.state.viewAngles;
    if (!me || !eye || !view) return;

    let best: Vector | null = null;
    let bestFov = 10;
    for (const enemy of entities.getPlayers({ skipLocal: true })) {
        if (!enemy.isEnemy(me)) continue;
        const head = enemy.getBone("head_0")?.position;
        if (!head) continue;

        const fov = view.fovTo(eye.angleTo(head));
        if (fov < bestFov) { bestFov = fov; best = head; }
    }

    const screen = best && render.worldToScreen(best);
    if (screen) render.circle(screen, 8, "#ff4040");
});
```
