# Writing scripts

A script is one Lua 5.4 file Lynx runs inside the game process, in its own sandbox next to the menu. All you need is a text editor and basic Lua.

The API is modelled on gamesense. There is no `lynx` table: the base globals are always present, plus the game's own namespace. Read [Getting started](/developers/getting-started/) first, then [Events](/developers/events/).

## The sandbox

- Standard libraries `base`, `table`, `string`, `math` and `utf8` are opened. `io`, `os`, `debug`, `package` and `coroutine` are not.
- Removed from every script: `print`, `warn`, `collectgarbage`, `dofile`, `load`, `loadfile`, `require`, `rawget`, `rawset`, `rawequal`, `rawlen`, `setmetatable`, `getmetatable`, `string.dump`.
- Each script has its own `_ENV`; two scripts never see each other's variables. Reads fall through to the standard globals, so `string.format` and `math.floor` work.
- A source file over 1 MiB is refused. At most sixteen scripts load at once.
- Only text source compiles; bytecode is never accepted.

## Capabilities

Some globals are gated. A gated global that was not granted is `nil`. A marketplace bundle lists the groups it needs in `manifest.json` under `capabilities`; a loose local script on a dev build is granted every group. Gated groups: `http`, `websocket`, `input`, `reflect`, and on cocos builds `ffi`/`objc`/`cocos`.