---
url: /rfcs/stdlib-and-config.md
description: >-
  New math, vector, and buffer functions plus requires, config files, and error
  suppression.
---

# Stdlib and Config RFCs

*Written: {{ $frontmatter.date }}*

## Learning objectives

* You interpolate and map numbers safely.
* You validate floats before you trust them.
* You pack bits into buffers.
* You resolve modules with aliases and init files.
* You configure projects and read suppression honestly.

## Prerequisites

* [Strings and Libraries](../luau-basics/strings-and-libraries.md)
* [Modules and Require](../luau-basics/modules-and-require.md)
* [Errors and Defensive Code](../luau-basics/errors-and-defensive-code.md)
* [How to read RFC status](./implemented.md)

## Math lerp

It blends two numbers. You use it for motion, sliders, and transitions.

### Original problem

You hand-rolled blends with mixed formulas. Some missed the endpoint exactly. Some jittered near 1. Players noticed stuck doors and shimmering bars.

### Change and motivation

The library gained a tuned blend with exact endpoints. You call it with two ends and a t. Values outside zero to one extrapolate. The [math lerp RFC](https://rfcs.luau.org/function-math-lerp.html) picks speed plus exactness, monotonicity, boundedness, and consistency.

### Implemented semantics

You write math dot lerp with a, b, and t. A t of 1 returns b exactly. Equal ends return that value for any t. Reversed ends also blend. You still clamp separately with math dot clamp.

### Before and after

Before:

```luau
--!strict
local function blend(a: number, b: number, t: number): number
  return a + (b - a) * t
end
print(blend(0, 100, 0.5))
```

```txt
50
```

Your helper works but misses the exactness promise at 1 for some inputs.

After:

```luau
--!strict
print(math.lerp(0, 100, 0.5))
print(math.lerp(0, 100, 1))
```

```txt
50
100
```

The library call matches at the midpoint and lands exactly on 100. You delete the helper.

### Realistic example

You slide a gate open over two seconds.

```luau
--!strict
local function gateX(start: number, goal: number, alpha: number): number
  return math.lerp(start, goal, alpha)
end
print(gateX(0, 12, 0.25))
print(gateX(0, 12, 1))
```

```txt
3
12
```

You pass the endpoints once. Quarter alpha gives 3. Full alpha gives exactly 12, so arrival checks trigger.

### Strict implications

All three arguments are numbers. The result is a number. Passing an optional without narrowing still errors. A nil alpha means a bug.

### Edge cases

Infinite t or NaN inputs give non-finite results, so you validate network-driven t values first. The blend does not clamp, so overshoot happens past the ends.

### Status

The [math lerp RFC](https://rfcs.luau.org/function-math-lerp.html) shows **Status**: Implemented. You use it today. You still confirm it in Studio per [how to read status](./implemented.md).

## Math map

It moves a value across ranges. You use it for bars, dials, and difficulty curves.

### Original problem

Every system rewrote the same five-argument mapping. Copies drifted. Some clamped, some did not. Readers could not tell which at a glance.

### Change and motivation

The library gained one map with explicit ends. You pass the value, the input ends, and the output ends. Out-of-range inputs extrapolate. The [math map RFC](https://rfcs.luau.org/function-math-map.html) keeps clamping separate.

### Implemented semantics

You write math dot map with x, inmin, inmax, outmin, outmax. The formula scales linearly. Zero-width input ranges divide by zero, so you never pass equal input ends.

### Before and after

Before:

```luau
--!strict
local function scale(x: number): number
  return 0 + (x - 0) * (100 - 0) / (10 - 0)
end
print(scale(7))
```

```txt
70
```

Your helper hardcodes both ranges. Reuse means editing the body.

After:

```luau
--!strict
print(math.map(7, 0, 10, 0, 100))
```

```txt
70
```

The library call names both ranges at the use. Each call can differ. The output matches.

### Realistic example

You turn health into a bar width.

```luau
--!strict
local function barWidth(health: number): number
  return math.map(health, 0, 100, 0, 200)
end
print(barWidth(25))
print(barWidth(100))
```

```txt
50
200
```

You map the game range onto pixels. Quarter health gives 50. Full health fills the bar.

### Strict implications

All five arguments are numbers and the result is a number. You narrow attributes before passing them. The checker catches a swapped string immediately.

### Edge cases

Equal input ends divide by zero. Reversed ranges are allowed and behave linearly. Clamp with math dot clamp when the bar must never overflow.

### Status

The [math map RFC](https://rfcs.luau.org/function-math-map.html) shows **Status**: Implemented. You use it today. You still confirm it in Studio per [how to read status](./implemented.md).

## Isnan, isinf, isfinite

Three predicates classify floats. You use them at every untrusted numeric boundary.

### Original problem

NaN tests used the riddle x ~= x. Finite tests combined equality with absolute value against huge. Infinity needed another manual compare. New readers could not parse the intent. Networked games need these checks constantly.

### Change and motivation

The library gained three predicates with plain names. Isnan spots NaN. Isinf spots either infinity. Isfinite accepts only ordinary numbers. The [float predicates RFC](https://rfcs.luau.org/math-isnan-isfinite-isinf.html) matches other modern languages.

### Implemented semantics

You call each with one number and receive a boolean. Isnan is true only for NaN. Isinf is true only for infinities. Isfinite is true only when neither applies.

### Before and after

Before:

```luau
--!strict
local speed = 0 / 0
local broken = speed ~= speed
print(broken)
```

```txt
true
```

The idiom works but reads as a typo. Every reader relearns it.

After:

```luau
--!strict
local speed = 0 / 0
print(math.isnan(speed))
print(math.isfinite(42))
```

```txt
true
true
```

The names state the question. NaN is NaN. Ordinary 42 is finite.

### Realistic example

You accept a client-reported jump speed only when finite.

```luau
--!strict
local function speedOk(raw: unknown): boolean
  if typeof(raw) == "number" then
    return math.isfinite(raw)
  end
  return false
end
print(speedOk(16))
print(speedOk(0 / 0))
```

```txt
true
false
```

You narrow unknown to number first. You test finiteness. Infinity and NaN both fail the test. The server never integrates a bad speed.

### Strict implications

You narrow unknown before calling, since the predicates take numbers. The results are plain booleans, so truthiness tests fit. You keep the checks server side.

### Edge cases

Isinf returns false for NaN, so you test NaN separately when the distinction matters. Huge is infinite by definition. Negative infinity counts as infinite too.

### Status

The [float predicates RFC](https://rfcs.luau.org/math-isnan-isfinite-isinf.html) shows **Status**: Implemented. Engine reference lists [`math.isfinite(x: number): boolean`](https://create.roblox.com/docs/en-us/reference/engine/libraries/math#isfinite) alongside `math.isnan`/`math.isinf`. You use them today on updated Studio. You still confirm them in Studio per [how to read status](./implemented.md).

If your Studio or external solver reports `math does not contain field isfinite`, your Luau is behind: update Studio, update `luau-lsp`/`selene` via `rokit.toml`, restart. For version-proof repos use the pure fallback below (identical semantics, zero version risk), this is what `src/shared/NumberUtil.luau` ships:

```luau
--!strict
local function isFinite(value: number): boolean
  return value == value and value ~= math.huge and value ~= -math.huge
end
```

## Vector lerp

It blends vectors like math lerp blends numbers. You use `Vector3:Lerp` for paths and effects, per the [Vector3](https://create.roblox.com/docs/reference/engine/datatypes/Vector3) reference. The alpha is not clamped, so clamp it yourself when the blend must stay between the endpoints.

### Original problem

Vector blends were hand-rolled per project. Some missed endpoints. Results differed from math lerp behavior. Portable vector code had no shared spelling.

### Change and motivation

The vector library gained a lerp that mirrors math lerp, including the exact endpoint promise. Scalar alpha drives the blend. Four-wide vectors work. The [vector lerp RFC](https://rfcs.luau.org/function-vector-lerp.html) keeps both lerps consistent.

### Implemented semantics

You call vector dot lerp with two vectors and a number. A t of 1 returns the goal exactly. Other t values blend per component. Roblox Vector3 colon Lerp stays separate and makes weaker promises.

### Before and after

Before:

```luau
--!strict
local a = vector.create(0, 0, 0)
local b = vector.create(10, 0, 0)
local mid = a + (b - a) * 0.5
print(mid.X)
```

```txt
5
```

Your formula works but carries no endpoint promise. Each file repeats it.

After:

```luau
--!strict
local a = vector.create(0, 0, 0)
local b = vector.create(10, 0, 0)
print(vector.lerp(a, b, 0.5).X)
print(vector.lerp(a, b, 1).X)
```

```txt
5
10
```

The library call blends and lands exactly. Midpoint and endpoint both print cleanly.

### Realistic example

You move a marker from spawn toward a gate.

```luau
--!strict
local function markerAt(alpha: number): vector
  local spawn = vector.create(0, 5, 0)
  local gate = vector.create(0, 5, 40)
  return vector.lerp(spawn, gate, alpha)
end
print(markerAt(0.5).Z)
print(markerAt(1).Z)
```

```txt
20
40
```

Half alpha gives 20 on Z. Full alpha gives exactly 40. Arrival logic triggers on the exact value.

### Strict implications

Both ends are vectors and alpha is a number. The result is a vector. Mixing vector with Vector3 needs conversion at your boundary, since the types differ.

### Edge cases

Non-finite alpha yields non-finite components, so you validate it. The function does not clamp. Fully vector alpha vectors are out of scope; you pass one scalar.

### Status

The [vector lerp RFC](https://rfcs.luau.org/function-vector-lerp.html) shows **Status**: Implemented. Do not depend on it yet: the stdlib reference page does not list it, so confirm `vector.lerp` exists in Studio per [how to read status](./implemented.md) first. Until then prefer the manual blend or `Vector3:Lerp()` at the Engine boundary.

## Buffer bits

They read and write arbitrary bit ranges. You use them for compact packets.

### Original problem

Custom widths needed careful shifts and masks. Partial-byte writes and sequential reads across bytes were error prone. Every net module reinvented the loop.

### Change and motivation

The buffer library gained readbits and writebits. You name a bit offset and a bit count up to 32. Values are unsigned, little endian from least significant bits. The [buffer bits RFC](https://rfcs.luau.org/function-buffer-bits.html) bounds-checks every access.

### Implemented semantics

You call buffer dot writebits with buffer, bit offset, bit count, and value. Only the low count bits of the value are stored. You call buffer dot readbits with the same triple and receive an unsigned number. Zero width reads 0 and writes nothing. Out-of-range access errors.

### Before and after

Before:

```luau
--!strict
local pack = buffer.create(2)
buffer.writeu8(pack, 0, 3)
print(buffer.readu8(pack, 0))
```

```txt
3
```

Byte calls handle aligned data. Bit fields need the new pair.

After:

```luau
--!strict
local pack = buffer.create(2)
buffer.writebits(pack, 0, 3, 5)
buffer.writebits(pack, 3, 3, 2)
print(buffer.readbits(pack, 0, 3))
print(buffer.readbits(pack, 3, 3))
```

```txt
5
2
```

Two 3-bit fields share bytes. Each read returns its own value. The layout stays explicit.

### Realistic example

You pack a 2-bit team and a 6-bit level into one byte.

```luau
--!strict
local packet = buffer.create(1)
local function encode(team: number, level: number): buffer
  buffer.writebits(packet, 0, 2, team)
  buffer.writebits(packet, 2, 6, level)
  return packet
end
local data = encode(2, 40)
print(buffer.readbits(data, 0, 2))
print(buffer.readbits(data, 2, 6))
```

```txt
2
40
```

You write team into bits 0 to 1 and level into bits 2 to 7. Reads mirror the layout. One byte carries both fields.

### Strict implications

Offsets, counts, and values are numbers. The calls return number and unit respectively. You keep counts within 0 to 32 or the call errors. Buffers themselves are not nilable after creation, so no guard is needed there.

### Edge cases

Signed reads are out of scope, so you apply a bias for signed fields. Bit offsets can exceed 32-bit ranges on huge buffers, so you compute them in numbers carefully. Manual masking can beat the loop when you already proved safety, but you keep the checked call until measurements justify it.

### Status

The [buffer bits RFC](https://rfcs.luau.org/function-buffer-bits.html) shows **Status**: Implemented. You use them today. You still confirm them in Studio per [how to read status](./implemented.md).

## Require aliases

They shorten requires to shared libraries. You use them in filesystem projects with a package layout.

### Original problem

Requires carried full disk paths. Moving a library meant editing every file. Sharing readable imports across a team was painful. A package manager had no stable hook.

### Change and motivation

Projects map short names to paths in configuration. Requires starting with at resolve through that map. Submodules hang off the alias with a slash. The [require aliases RFC](https://rfcs.luau.org/require-by-string-aliases.html) also reserves the bare at name for the future and treats alias names case insensitively.

### Implemented semantics

You define aliases in configuration, then require at plus name. Relative paths still work with dot prefixes. Aliases apply only at the start of the path. Chained aliases resolve iteratively, and cycles fail. One amendment later removed the paths array and tightened resolution.

Alias requires run in toolchain and filesystem contexts. Studio instance requires differ, so you test alias setups in your actual build chain per [how to read status](./implemented.md).

### Before and after

Before:

```luau
--!strict
local shop = require("./packages/shop")
print(shop ~= nil)
```

```txt
true
```

The relative path works but encodes the layout. Moves break every importer.

After:

```luau
--!strict
local shop = require("@shop")
print(shop ~= nil)
```

```txt
true
```

The alias hides the location. Moves edit configuration only. The import line never changes.

### Realistic example

You share a formatting library between two services.

```luau
--!strict
local format = require("@shared/format")
local coins = require("@shop/prices")
print(format ~= nil)
print(coins ~= nil)
```

Both aliases resolve through configuration. Both services import the same lines. No file counts directories upward.

### Strict implications

Required modules keep their own types. You annotate the boundary when the package ships without Luau types. Aliases never change checking; they only change resolution.

### Edge cases

Alias names allow letters, digits, dots, dashes, and underscores, but no slashes. The mid-path alias never applies. Case differences resolve identically, so you pick one casing and keep it.

### Status

The [require aliases RFC](https://rfcs.luau.org/require-by-string-aliases.html) shows **Status**: Implemented. You use it where your toolchain supports it. You still confirm it in your build per [how to read status](./implemented.md).

## Amended require

It makes every require explicit. You use it to end guessing between relatives and aliases.

### Original problem

Unprefixed paths were ambiguous. Readers could not tell a relative from an alias. Resolution order debates never settled. Loose file-type preferences hid conflicts.

### Change and motivation

Every require now starts with at, dot slash, or dot dot slash. Bare paths error. The old paths array is removed. Conflicting siblings error instead of picking silently. The [amended require RFC](https://rfcs.luau.org/amended-require-resolution.html) overrides the matching part of the older aliases page.

### Implemented semantics

You prefix aliases with at. You prefix local files with dot slash or dot dot slash. Anything else fails fast. A luau plus lua file collision errors. A file colliding with a same-named init directory errors.

### Before and after

Before:

```luau
--!strict
local data = require("@shop/data")
print(data ~= nil)
```

```txt
true
```

Explicit prefixes already work. They are now the only form.

After:

```luau
--!strict
local data = require("@shop/data")
local localData = require("./data")
print(data ~= nil)
print(localData ~= nil)
```

```txt
true
true
```

Both lines carry prefixes. The alias goes to configuration. The relative stays local. No bare path remains.

### Realistic example

You wire a service to shared code and a sibling helper.

```luau
--!strict
local coins = require("@shop/prices")
local helper = require("./helper")
print(coins ~= nil)
print(helper ~= nil)
```

Shared code travels by alias. Nearby code travels by relative path. A reader knows which is which from the first character.

### Strict implications

Resolution never changes types. Autocomplete can offer aliases after at and files after dot prefixes. You keep imports static and alphabetical so tools follow them.

### Edge cases

Old tutorials show bare paths that now error, so you add prefixes when copying. Removing the paths array breaks configs that relied on it, so you convert each entry into an alias. Sibling collisions need renames, not workarounds.

### Status

The [amended require RFC](https://rfcs.luau.org/amended-require-resolution.html) shows **Status**: Implemented. You use it where your toolchain supports it. You still confirm it in your build per [how to read status](./implemented.md).

## Init dot luau

A folder with this file acts as a module. You use it to organize Rojo projects.

### Original problem

A package wanted both children and its own exports. Filesystem mapping treated package init as an ordinary nested module. Relative requires inside it resolved one level too deep. Rojo projects and plain Luau projects disagreed.

### Change and motivation

Module paths now separate modules from plain directories. A folder with init dot luau is a module. Requires inside it resolve against the folder it represents. A reserved self alias addresses its own children. The [init dot luau RFC](https://rfcs.luau.org/abstract-module-paths-and-init-dot-luau.html) aligns Rojo with the language.

### Implemented semantics

You place init dot luau inside the package folder. The folder path names the module. Inside the init file, dot slash requires resolve to siblings of the folder, while at self requires address the package children. Rojo builds keep working because the rule matches its layout.

### Before and after

Before:

```luau
--!strict
local prices = require("@shop/prices")
print(prices ~= nil)
```

```txt
true
```

Top-level code imports the package by alias. The package still needs a way to import itself.

After:

```luau
--!strict
local prices = require("@self/prices")
print(prices ~= nil)
```

```txt
true
```

Inside init dot luau, the self alias names the package children. The line works regardless of where the package folder sits.

### Realistic example

You structure a shop package with a root plus two children.

```luau
--!strict
local prices = require("@self/prices")
local format = require("@self/format")
print(prices ~= nil)
print(format ~= nil)
```

Each child is addressed through self. Moving the whole folder never edits these lines.

### Strict implications

Children keep their exported types. The root re-exports them with annotations. You avoid sibling reaches from init files, since reaching outside the folder signals a layering mistake.

### Edge cases

Renaming a file to or from init dot luau changes resolution, so you review its requires on rename. A file and a same-named folder collide by rule, so you keep names distinct. Roblox-side telemetry preceded the rollout, so you test requires after updating Studio.

### Status

The [init dot luau RFC](https://rfcs.luau.org/abstract-module-paths-and-init-dot-luau.html) shows **Status**: Implemented. You use it where your toolchain supports it. You still confirm it in your build per [how to read status](./implemented.md).

## Config dot luau

It holds project settings in Luau. You use it for modes, lints, and aliases.

### Original problem

Settings lived in JSON-like rc files. Embedding contexts without JSON tooling carried extra burden. Authors wanted one language for code and configuration.

### Change and motivation

Projects may use a config dot luau file that returns a settings table. It covers language mode, lint toggles, error flags, globals, and aliases. Extraction runs the file in an isolated VM with standard libraries only. The [config RFC](https://rfcs.luau.org/config-luauconfig.html) forbids mixing both config files in one folder.

### Implemented semantics

You return a table with a luau section. Absent fields inherit defaults and parent folders. One folder holds either the rc file or the luau file, never both. The file is not a requireable module.

### Before and after

Before:

```luau
--!strict
local strict = true
print(strict)
```

Real settings lived in JSON-like syntax elsewhere.

After:

```luau
--!strict
local config = {
  luau = {
    languagemode = "strict",
    typeerrors = true,
  },
}
print(config.luau.languagemode)
```

```txt
strict
```

The real file returns the table instead of printing it. Strict mode and error flags travel together.

### Realistic example

You set strict mode, keep lint errors visible, and map a shared alias.

```luau
--!strict
local config = {
  luau = {
    languagemode = "strict",
    linterrors = true,
    typeerrors = true,
    aliases = {
      shop = "./packages/shop",
    },
  },
}
print(config.luau.aliases.shop)
```

```txt
./packages/shop
```

Mode and flags guard quality. The alias shortens imports. Returning this table from the real file activates it.

### Strict implications

The documented config type guides autocomplete. A mistyped field fails early. You keep one config style per folder so tools never guess.

### Edge cases

Config code cannot require other scripts. Infinite loops hit extraction timeouts, defaulting around two seconds at runtime. Arbitrary logic complicates automated edits, so you keep config files declarative.

### Status

The [config RFC](https://rfcs.luau.org/config-luauconfig.html) shows **Status**: Implemented. You use it where your toolchain supports it. You still confirm it in your build per [how to read status](./implemented.md).

## Error suppression

It explains any without magic. You use the model to keep boundaries honest.

### Original problem

Any behaved as both top and bottom, which switched checking off in both directions. Cascading errors needed ad hoc quieting. Authors could not tell principled suppression from a hole.

### Change and motivation

Any stays a top type while failures flowing out of it suppress messages. Unknown stays the top for safe types. An internal error type flows beneath. The [error suppression RFC](https://rfcs.luau.org/type-error-suppression.html) makes subtyping transitive and documents the split.

### Implemented semantics

You read any as top with silent exits. You read unknown as top for safe types with enforced narrowing. Property chains through a failed lookup suppress repeats. Intersections with any can unify more precisely than before, so some functions infer tighter types.

### Before and after

Before:

```luau
--!strict
local function coins(raw: any): number
  return raw
end
print(coins(25))
```

```txt
25
```

Any lets the return through unchecked. Wrong shapes pass silently.

After:

```luau
--!strict
local function coins(raw: unknown): number
  if typeof(raw) == "number" then
    return raw
  end
  return 0
end
print(coins(25))
```

```txt
25
```

Unknown forces the guard. Numbers pass. Everything else becomes 0. The output matches.

### Realistic example

You contain a broken chain without drowning the log.

```luau
--!strict
local function zoneOf(payload: unknown): string
  if typeof(payload) == "table" then
    local zone = (payload :: { zone: string }).zone
    return zone
  end
  return "unknown"
end
print(zoneOf({ zone = "arena" }))
print(zoneOf(42))
```

```txt
arena
unknown
```

Tables cast to the expected shape after narrowing. Anything else takes the fallback. One error per real problem replaces a cascade.

### Strict implications

You choose unknown plus guards for untrusted input. You reserve any for untyped package edges and name the package. Suppression never excuses a missing guard in your own types.

### Edge cases

Tighter inference can change inferred types after the model lands, usually for the better. A free variable meeting any can unify where it once stayed open. You recheck boundary annotations when upgrading solvers.

### Status

The [error suppression RFC](https://rfcs.luau.org/type-error-suppression.html) shows **Status**: Implemented. You use its behavior today. You still confirm solver behavior in Studio per [how to read status](./implemented.md).

## Common mistakes

Wrong: you hand-roll blends in every file.

```luau
--!strict
print(math.lerp(10, 20, 0.3))
```

The library call is correct. The mistake is the scattered helper it replaces. Fix it by deleting local blends.

Wrong: you map with a hand formula and clamp by accident.

```luau
--!strict
local width = math.map(120, 0, 100, 0, 200)
print(width)
```

The call is correct and extrapolates to 240. The mistake is expecting a clamp. Fix it by wrapping with math dot clamp when bounds matter.

Wrong: you trust client numbers without predicates.

```luau
--!strict
local function accept(raw: unknown): boolean
  if typeof(raw) == "number" then
    return math.isfinite(raw)
  end
  return false
end
print(accept(10))
```

The guard is correct. The mistake is skipping it. Fix it by routing every networked number through isfinite.

Wrong: you write bare requires from old tutorials.

```luau
--!strict
local shop = require("@shop")
print(shop ~= nil)
```

The prefixed form is correct. The mistake is the bare shop slash prices shape. Fix it by adding the prefix.

Wrong: you keep both config files in one folder.

```luau
--!strict
local config = { luau = { languagemode = "strict" } }
print(config.luau.languagemode)
```

The shape is correct. The mistake is pairing it with a sibling rc file. Fix it by keeping one config per folder.

## Exercises

1. Ease a value with math lerp at three alphas.
2. Map a score range onto a bar range.
3. Reject NaN and infinities from a list.
4. Blend two vectors and land exactly.
5. Pack two bit fields and read them back.
6. Convert a bare require into prefixed form.
7. Sketch a config table with mode plus one alias.

::: details Solution 1
Run this pure snippet in the Command Bar.

```luau
--!strict
print(math.lerp(0, 50, 0))
print(math.lerp(0, 50, 0.5))
print(math.lerp(0, 50, 1))
```

```txt
0
25
50
```

You sample start, middle, and end. The end lands exactly. Arrival checks can trust it.
:::

::: details Solution 2
Run this pure snippet in the Command Bar.

```luau
--!strict
print(math.map(0, 0, 10, 0, 100))
print(math.map(5, 0, 10, 0, 100))
print(math.map(10, 0, 10, 0, 100))
```

```txt
0
50
100
```

You map the ends and the middle. Each output scales linearly. No helper is involved.
:::

::: details Solution 3
Run this pure snippet in the Command Bar.

```luau
--!strict
local inputs = { 4, 0 / 0, math.huge, 9 }
local kept = 0
for _, value in inputs do
  if math.isfinite(value) then
    kept += 1
  end
end
print(kept)
```

```txt
2
```

You keep only finite entries. NaN and infinity drop.
:::

::: details Solution 4
Run this pure snippet in the Command Bar.

```luau
--!strict
local low = vector.create(0, 0, 0)
local high = vector.create(0, 10, 0)
print(vector.lerp(low, high, 0.5).Y)
print(vector.lerp(low, high, 1).Y)
```

```txt
5
10
```

You blend on Y. The midpoint halves. The endpoint lands exactly.
:::

::: details Solution 5
Run this pure snippet in the Command Bar.

```luau
--!strict
local flags = buffer.create(1)
buffer.writebits(flags, 0, 4, 9)
buffer.writebits(flags, 4, 4, 3)
print(buffer.readbits(flags, 0, 4))
print(buffer.readbits(flags, 4, 4))
```

```txt
9
3
```

You split one byte into two nibbles. Each write owns its bits. Each read mirrors its write.
:::

::: details Solution 6
Use this shape in project files where aliases are configured. It does not run in a blank place.

```luau
--!strict
local shop = require("@shop")
local nearby = require("./nearby")
print(shop ~= nil)
print(nearby ~= nil)
```

Aliases and relatives both carry prefixes. Bare paths are gone. Copy this shape into new files.
:::

::: details Solution 7
Run this pure snippet in the Command Bar.

```luau
--!strict
local config = {
  luau = {
    languagemode = "strict",
    aliases = { shared = "./shared" },
  },
}
print(config.luau.languagemode)
print(config.luau.aliases.shared)
```

```txt
strict
./shared
```

Mode guards quality. The alias shortens imports. Return this shape from the real file.
:::

## Summary

* Lerp and map replace scattered helpers. Clamp stays separate.
* Float predicates guard networked numbers.
* Vector lerp mirrors math lerp. Buffer bits pack fields.
* Aliases shorten imports. Prefixes disambiguate. Init files organize packages.
* Config dot luau holds settings. Suppression keeps any honest.
* Next: [Glossary](../glossary.md).
