---
title: Wire types
description: The primitive types every packet is built from, and what JavaScript values they map to.
---

Every packet field in the [Packets](/packets) reference is one of the types below, an array of them, or a struct of them. This page tells you what to pass to `sendPacket` and what you get back from a parsed packet.

All types are big-endian. Each lives in `src/Core/Types/<Name>.ts` and exports `read(buf, off)` and `write(value)`.

## Numbers

| Type | Bytes | JS value | Notes |
| --- | --- | --- | --- |
| `Boolean` | 1 | `boolean` | `0x00` or `0x01`. |
| `Byte` | 1 | `number` | Signed, -128 to 127. |
| `UByte` | 1 | `number` | Unsigned, 0 to 255. |
| `Short` | 2 | `number` | Signed. Throws `RangeError` on a truncated buffer. |
| `UShort` | 2 | `number` | Unsigned, 0 to 65535. Used for the port in `Intension`. |
| `Int` | 4 | `number` | Signed 32-bit. |
| `Long` | 8 | `bigint` | Read as `bigint`. Write accepts `bigint`, `number`, or a numeric `string`. |
| `Float` | 4 | `number` | IEEE 754 single. |
| `Double` | 8 | `number` | IEEE 754 double. |
| `VarInt` | 1–5 | `number` | See below. |
| `VarLong` | 1–10 | `bigint` | Same encoding as VarInt over 64 bits. Write accepts `bigint`, `number`, or `string`. |
| `Angle` | 1 | `number` | Rotation in 1/256ths of a turn, 0 to 255. Used for entity yaw/pitch. |

### VarInt

Seven payload bits per byte, low bits first, high bit set on every byte except the last. Values fit in 1 to 5 bytes; a sixth byte throws `RangeError: VarInt exceeds 5 bytes`. Negative numbers always take 5 bytes.

VarInt is also what prefixes every frame, every string, and every array in the protocol, so it is the most common type on the wire by far.

```ts
VarInt.write(300);            // <Buffer ac 02>
VarInt.read(buf, { value: 0 }); // 300, and off.value is now 2
```

Wire types live in `src/Core/Types/` in this repository. The published package only exports `.`, `./26.2`, `./776`, and `./package.json`, so `import … from "mc-protocol/src/Core/Types/…"` will not resolve for consumers.

`read` functions take a mutable offset object and advance `off.value` past the bytes they consumed.

## Text and identifiers

| Type | Encoding | JS value |
| --- | --- | --- |
| `String` | VarInt byte length, then UTF-8 | `string` |
| `UUID` | 16 raw bytes | 32-character lowercase hex `string`, **no dashes**. Write parses hex two characters at a time, so pass it undashed. |
| `TextComponent` | Network NBT | Plain object, see below |

Identifiers like `minecraft:overworld` are ordinary `String`s.

### TextComponent and NBT

Chat messages, titles, and item names are NBT text components. You pass a plain JavaScript value and `writeNbt` maps it:

| JS value | NBT tag |
| --- | --- |
| `null` / `undefined` | End (`0`) |
| `boolean` | Byte |
| integer `number` in int32 range | Int |
| other `number` | Double |
| `bigint` | Long |
| `string` | String |
| array | List |
| object | Compound |
| `{ type, value }` | Used verbatim, for when you need a specific tag such as Byte Array |

So `{ text: "Hello", color: "aqua" }` becomes a compound with two string tags, which is what the client expects. Reading does the inverse and returns plain values.

## Spatial

### `Position`

A block position packed into one 64-bit integer: 26 bits X, 26 bits Z, 12 bits Y, all signed. JS value is `{ x, y, z }`. Range is ±33 million horizontally and -2048 to 2047 vertically.

```ts
await client.sendPacket("DefaultSpawnPosition", {
  dimension: "minecraft:overworld",
  position: { x: 0, y: 64, z: 0 },
  yaw: 0, pitch: 0,
});
```

### `LpVec3`

The 26.2 compressed velocity vector. JS value is `[x, y, z]`. A zero vector is one byte; anything else is 6 bytes with 15-bit quantized components plus a scale, and a VarInt continuation for magnitudes above 3. Precision is relative to the largest component, so tiny values next to large ones lose detail.

### `FixedBitSet`

A fixed number of bytes with no length prefix. The packet definition supplies the length. JS value is a `Buffer`.

## Composite shapes

The generated packet code combines primitives in a few standard ways. When a field table in the packet reference says one of these, this is what it means:

| Shape | Wire format | JS value |
| --- | --- | --- |
| `Struct` | Fields in order, no header | Plain object with those fields |
| Array | VarInt count, then each element | JS array |
| Optional | Boolean present flag, then the value if `true` | Value or `null` / `undefined` |
| Enum | VarInt index | Write: the string name or the `number` index. Read: `{ value, translation }`, where `value` is the index and `translation` the name. |
| Byte array | VarInt length, then raw bytes | `Buffer` |
| ID or inline | VarInt; `0` means an inline value follows, otherwise `id - 1` | `number` or object |
| ID set | VarInt `type`; `0` means a tag name follows, otherwise `type - 1` IDs | `{ type, tagName }` or `{ type, ids }` |

Larger game structures (`Slot`, item data components, particles, sounds, command nodes) are structs of the above and live in `src/Core/Helpers/`. Their exact layouts follow the vanilla 26.2 protocol.

### `Slot`

One item stack. On the wire: VarInt `itemCount`, and when it is non-zero, VarInt `itemId`, VarInt counts of added and removed components, then the component arrays.

**Writing**, pass `{ itemCount: 0 }` for an empty slot, or `{ itemCount, itemId, components, removeComponents }`. Each entry in `components` is `{ type, data }` and each entry in `removeComponents` is `{ type }`, with `type` the unnamespaced 26.2 name such as `custom_name` or `enchantments`. The writer derives both counts from the array lengths; `componentsToAdd` and `componentsToRemove` are accepted as aliases.

**Reading** returns the same fields plus `addedComponentCount` and `removedComponentCount`, and every enum (including each component's `type`) comes back as `{ value, translation }`, for example `{ value: 6, translation: "custom_name" }`. Decoded slots can be written back unchanged.

Two serverbound packets use related but distinct types. [ContainerClick](/packets/play/containerclick) carries `HashedSlot`: `itemId`, `itemCount`, then `{ type, hash }` pairs and a `removeComponents` list, with no component payloads. [SetCreativeModeSlot](/packets/play/setcreativemodeslot) carries `UntrustedSlot`: the same layout as `Slot`, but each component's `data` is a length-prefixed raw `Buffer` instead of a decoded value.

You rarely need to build a `Slot` by hand. `helpers.createSlot("diamond_sword", options)` and `helpers.emptySlot()` return packet-ready objects. Short names and `minecraft:` names resolve through the bundled 26.2 item registry. `helpers.getItemId(name)` also provides the numeric ID for other packet fields; see [Items and slots](/docs/items).

## Field aliases

Most generated packets accept the vanilla field name as an alias when writing. `Intension` takes `protocolVersion` or `protocol`, `serverHost` or `address`, `nextState` or `intent`. The packet reference lists the aliases for each field.

Parsed packets usually use the write-side primary name. Two handshake/login packets do not: `Intension` reads `protocol` / `address` / `port` / `intent` and writes `protocolVersion` / `serverHost` / `serverPort` / `nextState`; `Hello` reads `name` / `uuid` and writes `username` / `playerUUID`. Lifecycle code accepts both sets.
