# Score Vectors

> Runtime 3D vectors on Minecraft scoreboards with Kore - look directions, dot and cross products, exact length, normalize, teleports and motion.

Updated 2026-10-24. Canonical: https://kore.ayfri.com/docs/helpers/score-vectors

A `ScoreVector` is a runtime 3D vector stored in three scores of an entity (`<name>_x`, `<name>_y`, `<name>_z`). It
reads positions, motion and look directions, does the vector maths, then writes the result back as a teleport, a
motion or a rotation. The same data covers what Bookshelf splits into `bs.vector`, `bs.position`, `bs.move` and
`bs.view`.

```kotlin
val math = registerMath()

function("dash") {
	val dash = math.vector("dash", player)
	dash.setToLookDirection(self())
	dash *= 3
	dash.teleport(self(), TeleportMode.RELATIVE)
}
```

Components are fixed-point with a `scale` of `1000` by default, so `1500` means `1.5` blocks. `math.vector` registers the
three objectives in the math load function. Operations between two vectors expect the same scale.

> [!FOOTPRINT]
> - **Objectives:** `<name>_x`, `<name>_y` and `<name>_z` per vector, plus `kore_math`.
> - **Storage:** `<pack>:kore_math`, holding the `len` of `normalize`, the `rotation` of `setToLookDirection`, the motion read by `setToMotion` and the `teleport` and `look` macro arguments.
> - **Entities:** one `minecraft:marker`, UUID `4b4f5245-0000-0000-0000-000000000001`, tagged `kore.math`, `smithed.entity` and `smithed.strict`, summoned once at -30000000 0 1664 by the operations that read positions or directions.
> - **Forceloaded chunks:** the one holding those entities, x -30000000 z 1664.
> - **Every tick:** no.
> - **Load and files:** `kore_math_init` creates the objectives, entities, storage and the `#<n>` constants.

## Reading vectors

```kotlin
function("track_arrow") {
	val velocity = math.vector("velocity", arrow)
	velocity.setToMotion(self()) // blocks per tick
}
```

- `setToPosition(entity)` reads the position off the math marker teleported onto the entity, never touching its NBT,
  since reading any field of a player's NBT serializes the whole player. `setToMotion(entity)` copies `Motion` to
  storage once and reads the three components from there.
- `setToLookDirection(entity)` gives the unit vector the entity looks along, the direction of `^ ^ ^1`, truncated
  toward zero. The math marker copies the entity's rotation, then one `compute` per component applies the game's sine
  table to it, so no player NBT is read.
- `set(x, y, z)` takes plain numbers, `set(0.0, 0.5, 0.0)` stores `0 500 0`.
- `setTo(other)` copies another vector.

## Arithmetic

Operators come first, they read like plain Kotlin:

```kotlin
function("wind_push") {
	velocity += wind
	velocity *= 2
	velocity /= 4
}
```

- `+=` / `-=` add or subtract another vector.
- `*=` / `/=` with an `Int` scale every component, with Minecraft's floored division.
- `*=` with a `ScoreboardEntity` multiplies by a fixed-point factor of the same scale, `500` halves the vector.

## Dot and cross products

```kotlin
function("backstab_check") {
	attackerLook.dot(victimLook, alignment) // 1000 = same direction
}
```

`dot(other, output)` writes the fixed-point dot product in one `compute`. `cross(other, output)` writes `this × other`
into a third vector with one `compute` per component, the output must differ from both operands. A product or a sum
that doesn't fit an `Int` (past about `46` blocks per component at scale `1000`) writes `0`.

A `compute` reads the scores of one real entity at most. When the two vectors belong to different real entities, the
scores of the second are first copied into scratch fake players, one extra command each. Every vector read by `dot`,
`cross`, `length`, `distanceTo`, `lengthSquared` and `normalize` must belong to a single entity (`limitToOne`), or building
the datapack throws.

## Length and distance

```kotlin
function("leash_range") {
	playerPos.distanceTo(petPos, distance)
}
```

`length(output)` and `distanceTo(other, output)` write the length, rounded down, in the vector's scale. One `compute`
runs the game's `length` provider, which sums the squares as floats, so it never overflows and stays within 1 unit of
the exact length. A component difference that doesn't fit an `Int` in `distanceTo` writes `0`.

To measure the distance between two non-player entities without filling vectors first,
[`Entity.distanceTo`](https://kore.ayfri.com/docs/oop/entities-and-players.md#distance-between-two-entities) of the `oop` module reads both `Pos`
lists straight into one `compute`, about 6x faster than two `setToPosition` plus `distanceTo`. It reads the coordinates
as floats, so it loses precision far from the origin (about 1 unit at 10,000 blocks), where `setToPosition` stays exact.

`lengthSquared(output)` is one `compute` and is enough for comparisons, but it writes `0` past about `46` blocks at
scale `1000`.

## Normalizing

```kotlin
function("homing_missile") {
	toTarget.setTo(targetPos)
	toTarget -= missilePos
	toTarget.normalize()
}
```

`normalize()` rescales the vector to a length of `1000`, each component truncated toward zero. One `compute` stores the
length in the math storage, then one `compute` per component divides by it. A zero vector has no direction and stays
`0`.

## Writing vectors back

```kotlin
function("launch_pad") {
	launch.set(0.0, 1.2, 0.0)
	launch.applyAsMotion(self())
}
```

- `applyAsMotion(entity)` writes `Motion`, in blocks per tick. Players ignore `Motion` changes, teleport them instead.
- `teleport(entity, mode)` teleports through a macro `tp`, so it works on players:
	- `TeleportMode.ABSOLUTE` treats the vector as world coordinates,
	- `TeleportMode.RELATIVE` offsets from the entity (`~x ~y ~z`),
	- `TeleportMode.LOCAL` offsets along the entity's view (`^x ^y ^z`, x is left, z is forward).
- `lookAlong(entity)` turns the entity to face along the vector, through a macro `rotate` so it also works on players.
  A zero vector keeps the rotation.

## Native physics attributes

For bounces and sliding, the game's attributes handle collision themselves, with no per-tick resolution in the pack:
`bounciness` sets how much velocity survives a collision, `friction_modifier` scales ground friction, and
`air_drag_modifier` scales air drag.

```kotlin
function("rubber_slime") {
	attributes(self(), Attributes.BOUNCINESS) {
		base { set(0.9) }
	}
}
```

## See also

- [Scoreboard Math](https://kore.ayfri.com/docs/helpers/scoreboard-math.md) - Sine, cosine, atan2 and square root on the same fixed-point scale.
- [Raycasts](https://kore.ayfri.com/docs/helpers/raycasts.md) - Step along a look direction until a block is hit.
- [Display Entities](https://kore.ayfri.com/docs/helpers/display-entities.md) - Compile-time transformations with `Vec3f` and quaternions.
