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

# Number Types

> Fixed-width integer and float schema constructors.

Eight constructors covering the widths `buffer` supports directly. Each writes exactly its
declared size, with no tag byte and no narrowing.

```luau theme={null}
local T = Flux.Types
```

## Unsigned integers

<ResponseField name="T.UInt8()" type="Type<number>">
  One byte. Range `0` to `255`.
</ResponseField>

<ResponseField name="T.UInt16()" type="Type<number>">
  Two bytes. Range `0` to `65,535`.
</ResponseField>

<ResponseField name="T.UInt32()" type="Type<number>">
  Four bytes. Range `0` to `4,294,967,295`.
</ResponseField>

```luau theme={null}
local Stats = Flux.Server("Stats", {
	T.UInt8(),   -- level, 1-100
	T.UInt16(),  -- health, 0-65535
	T.UInt32(),  -- total score
})

Stats:Fire(player, 42, 1500, 987654)
```

## Signed integers

<ResponseField name="T.Int8()" type="Type<number>">
  One byte. Range `-128` to `127`.
</ResponseField>

<ResponseField name="T.Int16()" type="Type<number>">
  Two bytes. Range `-32,768` to `32,767`.
</ResponseField>

<ResponseField name="T.Int32()" type="Type<number>">
  Four bytes. Range `-2,147,483,648` to `2,147,483,647`.
</ResponseField>

```luau theme={null}
local Offset = Flux.Server("Offset", {
	T.Int16(),  -- x offset, may be negative
	T.Int16(),  -- y offset
})

Offset:Fire(player, -240, 80)
```

<Note>
  `T.Int8()` is the only width the dynamic encoder never selects on its own, because small
  negative numbers fall through to `i16` there. Declaring it in a schema is the only way to
  get one-byte signed values.
</Note>

## Floats

<ResponseField name="T.Float32()" type="Type<number>">
  Four bytes. Roughly 7 significant decimal digits.
</ResponseField>

<ResponseField name="T.Float64()" type="Type<number>">
  Eight bytes. Full Luau `number` precision, lossless.
</ResponseField>

```luau theme={null}
local Physics = Flux.Server("Physics", {
	T.Float32(),  -- velocity magnitude, precision irrelevant
	T.Float64(),  -- server timestamp, must be exact
})
```

<Tip>
  This is where schemas actually pay off. The dynamic encoder writes every non-integer as an
  8-byte `f64`, because it cannot know whether you need the precision. Declaring
  `T.Float32()` halves it, and for positions, rotations, velocities and normalised values the
  loss is irrelevant.

  A `Vector3` of world coordinates sent 60 times a second costs 24 bytes per send dynamically
  and 12 under `T.Vector3()`, which is `f32`-based.
</Tip>

## Overflow and truncation

<Warning>
  These constructors pass straight through to `buffer.write*`, which does not validate.
  Out-of-range values are silently truncated to the low bits of the declared width, with no
  error and no warning.

  ```luau theme={null}
  local E = Flux.Server("E", { T.UInt8() })

  E:FireAll(300)   -- receiver reads 44   (300 mod 256)
  E:FireAll(-1)    -- receiver reads 255
  ```

  Clamp before sending anything whose range you do not control:

  ```luau theme={null}
  E:FireAll(math.clamp(math.floor(value), 0, 255))
  ```
</Warning>

<Warning>
  Passing a non-integer to an integer type also truncates rather than erroring, so
  `T.UInt8()` with `3.7` transmits `3`. Passing `nil` errors inside `buffer.write*` with an
  unhelpful message, so wrap nullable numbers in
  [`T.Optional`](/api/types/composites#optional).
</Warning>

## Choosing a width

| Data                                   | Constructor   | Why                       |
| -------------------------------------- | ------------- | ------------------------- |
| Level, count, percentage, small id     | `T.UInt8()`   | 0 to 255 covers it        |
| Health, damage, currency under 65k     | `T.UInt16()`  |                           |
| Score, large id, timestamp in ms       | `T.UInt32()`  |                           |
| Screen or grid offset                  | `T.Int16()`   | needs negatives           |
| Position component, velocity, angle    | `T.Float32()` | precision is not critical |
| `os.time()`, `os.clock()`, money-exact | `T.Float64()` | must be lossless          |

<Info>
  A `UInt32` maxes out at about 4.29 billion, which is enough for `os.time()` until 2106 but
  not for millisecond timestamps or Roblox user ids in the far future. Use `T.Float64()` when
  you need range beyond 2^32.
</Info>

## Next steps

<CardGroup cols={2}>
  <Card title="Primitives" icon="font" href="/api/types/primitives">
    `Bool`, `String` and `Any`.
  </Card>

  <Card title="Roblox datatypes" icon="cube" href="/api/types/roblox">
    Vectors, CFrames, instances and enums.
  </Card>
</CardGroup>
