LSL type definitions and a TypeScript-to-Lua plugin for Second Life. Full editor support, compile-time safety, minimal runtime overhead.
If TypeScript is where you're productive, you don't need to learn a new language to script for Second Life. SLua has decent tooling, but this lets you stay in the ecosystem you already know.
| Package | Description |
|---|---|
@gwigz/slua-types |
Auto-generated TypeScript declarations for all SLua/LSL APIs |
@gwigz/slua-tstl-plugin |
TSTL plugin enforcing SLua constraints |
I use this toolchain for my own projects, it's how I find the rough edges:
examples/sim-wide-relay-- Region-wide chat relay, deployed at my favorite simslua-derez-patcher-- Skips the rez-edit-take-replace cycle; patches rezzables usingll.DerezObject
Install the packages:
npm install --save-dev typescript typescript-to-lua @gwigz/slua-types @gwigz/slua-tstl-pluginCreate a tsconfig.json in your project:
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"strict": true,
"moduleDetection": "force",
"types": ["@typescript-to-lua/language-extensions", "@gwigz/slua-types"]
},
"tstl": {
"luaTarget": "Luau",
"luaLibImport": "inline",
"luaPlugins": [{ "name": "@gwigz/slua-tstl-plugin" }],
"extension": "slua"
}
}See TypeScriptToLua configuration for more config options.
Map .slua to Lua highlighting in VS Code (and forks):
// .vscode/settings.json
{
"files.associations": {
"*.slua": "lua"
}
}Tell GitHub to highlight .slua files as Lua:
# .gitattributes
*.slua linguist-language=Lua
const owner = ll.GetOwner()
LLEvents.on("touch_start", (events) => {
for (const event of events) {
const key = event.getKey()
if (key === owner) {
ll.Say(0, `Hello secondlife:///app/agent/${key}/about!`)
return
}
}
})Compile with npx tstl (or bunx tstl, pnpm tstl, etc.) to get:
local owner = ll.GetOwner()
LLEvents:on("touch_start", function(events)
for ____, event in ipairs(events) do
local key = event:getKey()
if key == owner then
ll.Say(0, ("Hello secondlife:///app/agent/" .. tostring(key)) .. "/about!")
return
end
end
end)The TSTL plugin automatically translates TypeScript patterns to native Luau/LSL equivalents for JSON, base64, string methods, array methods, bitwise operators, and floor division. See the full transform reference for details.
Due to a TSTL limitation, only valid JSDoc-style comments (/** */) are preserved in the output. Regular comments (//, /* */) are stripped:
/** This comment will appear in the Lua output */
const owner = ll.GetOwner()
// This comment will be stripped
const pos = new Vector(128, 128, 20)--- This comment will appear in the Lua output
local owner = ll.GetOwner()
local pos = vector.create(128, 128, 20)bun run generate- regeneratepackages/types/index.d.tsfrom YAML definitionsbun run build- build all workspaces that define abuildscriptbun run build:examples- build all example workspaces onlybun test- run all testsbun run lint- lint with oxlintbun run lint:fix- lint and auto-fixbun run fmt- format with oxfmtbun run fmt:check- check formatting without writing
├── packages/
│ ├── types/ # auto-generated .d.ts declarations
│ └── tstl-plugin/ # TSTL plugin for SLua constraints
├── tools/
│ └── gen-types/ # type generation tool (YAML -> .d.ts)
├── examples/
│ ├── getting-started/ # minimal example
│ ├── kitchen-sink/ # feature showcase
│ ├── sim-wide-relay/ # multi-script relay system
│ └── weather-fetcher/ # HTTP request example
└── refs/
└── lsl-definitions/ # upstream YAML definitions (submodule)