# Readability presets and switches

Presets and switches change how the code reads, never what it does. Some of them cost something you might need, like matching line numbers.

## which preset

Use `balanced` if you don't want to think about it.

Use `faithful` if you want source that compiles to the same bytes, or stack traces that point into the right function. Just know it can be quite verbose.

Use `readable` if you want the cleanest result. It turns every switch on, so names, types and line numbers can differ from the original.

The site, the executor and the Discord bot start on `balanced`. The API and the MCP server start on `faithful`.

## presets

A preset sets every switch at once.

| switch | faithful (exact bytes) | balanced (easy to read) | readable (everything on) |
| --- | --- | --- | --- |
| Readable layout | · | ● | ● |
| Function line numbers | · | ● | ● |
| Inferred types | · | ● | ● |
| Fold constants | · | · | ● |
| Model names | · | ● | ● |
| Drop dead code | · | · | ● |
| Upvalue notes | · | ● | ● |
| Upvalue notes on own line | · | ● | ● |
| Compound assignment | · | ● | ● |
| Positive conditions | · | ● | ● |
| Early returns | · | ● | ● |
| Paragraph breaks | · | ● | ● |
| Inline small calls | · | · | ● |
| Roll up loops | · | ● | ● |
| Math constants | · | · | ● |
| Const locals | · | ● | ● |
| Field functions | · | ● | ● |
| Mutable globals | · | ● | ● |

Want `readable` without inferred types? Pick `readable` and turn that one switch off. On the site, it's under options. Over the API, send `{"preset": "readable", "inferredTypes": false}`.

## what a switch costs

| cost | what changes |
| --- | --- |
| bytes | The source no longer compiles to the same bytecode. |
| lines | Code moves off its original lines, so line numbers in errors no longer match. |
| names | Values get names the file didn't have, or lose names it did. |
| types | Type annotations appear that the file didn't have. |
| frames | A call to a small helper becomes the helper's body, so stack traces have one frame fewer. |
| version | The source uses syntax only newer Luau understands, like `const`, so older tools reject it. |

The API lists what a result's switches cost in `setting.spent`. `faithful` costs nothing.

## faithful layout

Faithful keeps every function on its original line, so you'll see runs of blank lines. Turn on Readable layout (`freeLines`) to get rid of them.

## switches

Every switch is off in `faithful`. Each example shows the same bytecode decompiled without the switch, then with it.

### Readable layout (`freeLines`)

Lays functions out as reads best, not padded or packed onto their original lines. On in `balanced` and `readable`. Costs: [bytes, lines](https://unreadable.gg/docs/readability#costs).

Without:

```lua
print(1) print(2)
function done()
	print(3)
end
done()
```

With:

```lua
print(1)
print(2)

function done()
	print(3)
end
done()
```

### Function line numbers (`lineNotes`)

Under the readable layout, ends each function's first line in the line it was defined on. On in `balanced` and `readable`.

Without:

```lua
print(1)
print(2)

function done()
	print(3)
end
done()
```

With:

```lua
print(1)
print(2)

function done() -- line 2
	print(3)
end
done()
```

### Inferred types (`inferredTypes`)

Adds the type annotations inference concludes, beside the input's own. On in `balanced` and `readable`. Costs: [bytes, types](https://unreadable.gg/docs/readability#costs).

Without:

```lua
local function label(n)
	return "item " .. tostring(n)
end
return label(3)
```

With:

```lua
local function label(n: number): string
	return "item " .. tostring(n)
end
return label(3)
```

### Fold constants (`foldConstants`)

Writes a computation on literals as its value: `7` for `math.max(4, 7)`. On in `readable`. Costs: [bytes](https://unreadable.gg/docs/readability#costs).

Without:

```lua
local width = math.max(4, 7)
print(width)
```

With:

```lua
local width = 7
print(width)
```

### Model names (`modelNames`)

Names the values the input left unnamed, never with a name that could change the program. On in `balanced` and `readable`. Costs: [names](https://unreadable.gg/docs/readability#costs).

Without:

```lua
local function v0(arg0)
	local v1 = 0
	for i = 1, #arg0 do
		v1 = v1 + arg0[i]
	end
	return v1
end
return v0({ 1, 2, 3 })
```

With:

```lua
local function sum(values)
	local sum1 = 0
	for i = 1, #values do
		sum1 = sum1 + values[i]
	end
	return sum1
end
return sum({ 1, 2, 3 })
```

### Drop dead code (`dropDeadCode`)

Leaves out values nothing reads and branches that never run. On in `readable`. Costs: [bytes, names](https://unreadable.gg/docs/readability#costs).

Without:

```lua
local unused = 21
print("ready")
```

With:

```lua

print("ready")
```

### Upvalue notes (`upvalueNotes`)

Says on each function's first line which outer variables it captures, and whether it sees their later changes. On in `balanced` and `readable`.

Without:

```lua
local function counter(k)
	local n = 0
	return function()
		n += k
		return n
	end
end
print(counter(2)())
```

With:

```lua
local function counter(k)
	local n = 0
	return function() -- upvalues: n (ref), k (copy)
		n += k
		return n
	end
end
print(counter(2)())
```

### Upvalue notes on own line (`upvalueNotesOwnLine`)

Puts the upvalue note on a line of its own under the function's first line. On in `balanced` and `readable`. Costs: [lines](https://unreadable.gg/docs/readability#costs).

Without:

```lua
local function counter(k)
	local n = 0
	return function() -- upvalues: n (ref), k (copy)
		n += k
		return n
	end
end
print(counter(2)())
```

With:

```lua
local function counter(k)
	local n = 0
	return function()
		-- upvalues: n (ref), k (copy)
		n += k
		return n
	end
end
print(counter(2)())
```

### Compound assignment (`compoundEverywhere`)

Writes `x op= e` wherever it means the same thing. On in `balanced` and `readable`. Costs: [bytes](https://unreadable.gg/docs/readability#costs).

Without:

```lua
local t = { k = 1 }
t.k = t.k + 2
print(t.k)
```

With:

```lua
local t = { k = 1 }
t.k += 2
print(t.k)
```

### Positive conditions (`positiveBranches`)

Tests an `if` without `not`, and puts a short exit arm first. On in `balanced` and `readable`. Costs: [bytes, lines](https://unreadable.gg/docs/readability#costs).

Without:

```lua
local function check(ok)
	if not ok then
		print("no")
	else
		print("yes")
	end
end
check(true)
```

With:

```lua
local function check(ok)
	if ok then
		print("yes")
	else
		print("no")
	end
end
check(true)
```

### Early returns (`earlyExits`)

A function that ends in one big `if` returns early instead. On in `balanced` and `readable`. Costs: [bytes](https://unreadable.gg/docs/readability#costs).

Without:

```lua
local function save(s)
	if s then
		print(s)
		print(#s)
	end
end
save("x")
```

With:

```lua
local function save(s)
	if not s then return end
	print(s)
	print(#s)
end

save("x")
```

### Paragraph breaks (`paragraphBreaks`)

Adds a blank line between the steps of the code. On in `balanced` and `readable`. Costs: [bytes, lines](https://unreadable.gg/docs/readability#costs).

Without:

```lua
local squares = {}
for i = 1, 3 do
	squares[i] = i * i
end
return squares
```

With:

```lua
local squares = {}
for i = 1, 3 do
	squares[i] = i * i
end

return squares
```

### Inline small calls (`inlineCalls`)

Writes a call of a small local helper as the helper's body. On in `readable`. Costs: [bytes, names, frames](https://unreadable.gg/docs/readability#costs).

Without:

```lua
local function key(name, n)
	return name .. "_" .. n
end
local k = key("hp", 3)
print(k)
```

With:

```lua



local k = "hp" .. "_" .. 3
print(k)
```

### Roll up loops (`rerollLoops`)

Writes lines repeated with 1, 2, 3 in them as the `for` loop that runs them. On in `balanced` and `readable`. Costs: [bytes](https://unreadable.gg/docs/readability#costs).

Without:

```lua
local t = { 5, 6, 7 }
print(t[1])
print(t[2])
print(t[3])
```

With:

```lua
local t = { 5, 6, 7 }
for i = 1, 3 do
	print(t[i])
end
```

### Math constants (`unfoldMath`)

Writes a number the `math` library computes as that expression: `math.pi / 2` for `1.5707963267948966`. On in `readable`. Costs: [bytes](https://unreadable.gg/docs/readability#costs).

Without:

```lua
local quarter = 1.5707963267948966
print(math.sin(quarter))
```

With:

```lua
local quarter = math.pi / 2
print(math.sin(quarter))
```

### Const locals (`constLocals`)

Declares a local nothing assigns again as `const`. On in `balanced` and `readable`. Costs: [version](https://unreadable.gg/docs/readability#costs).

Without:

```lua
local limit = tonumber("8")
local count = 0
count = count + (limit :: any)
print(count)
```

With:

```lua
const limit = tonumber("8")
local count = 0
count = count + (limit :: any)
print(count)
```

### Field functions (`fieldFunctions`)

Writes a table of keyed functions as `local t = {}` and a `function t.k()` per function. On in `balanced` and `readable`. Costs: [bytes, names](https://unreadable.gg/docs/readability#costs).

Without:

```lua

return { ["clamp"] = function(arg0)
	return math.max(0, math.min(arg0, 1))
end,
["twice"] = function(arg0)
	return arg0 * 2
end }
```

With:

```lua
local module = {}
function module.clamp(arg0)
	return math.max(0, math.min(arg0, 1))
end
function module.twice(arg0)
	return arg0 * 2
end
return module
```

### Mutable globals (`mutableGlobals`)

Writes `game.Players` for `(game).Players`, as scripts compiled with those globals mutable read them. On in `balanced` and `readable`. Costs: [bytes](https://unreadable.gg/docs/readability#costs).

Without:

```lua
local camera = (workspace).CurrentCamera
print(camera)
```

With:

```lua
local camera = workspace.CurrentCamera
print(camera)
```
