Skip to Content
Modlock

TypeScript

TypeScript and JavaScript mods: the build, the two runtimes and the widest library.

A TypeScript or JavaScript mod imports modlock and registers its handlers when it loads:

import { command } from 'modlock'

command('hello', (player) => {
  player.chat('Hello from TypeScript!')
})

The guides show every call in TypeScript and JavaScript; choose the language with the switch in the sidebar. Camera curves and ProbeRun for testing are in TypeScript only.

The build

The build starts from main.ts, or main.js, and type-checks a JavaScript mod from its JSDoc comments. Each build writes the library's types to node_modules/modlock for your editor and the type checker. It bundles your mod with the copy of the library built into modlock, so you install nothing else. src/wasm/wasm.proto documents every call, its arguments and its result.

Two runtimes

Every build bundles your mod for QuickJS, an interpreter that runs any JavaScript, so the build takes a moment. When your mod's frames take too long, set "runtime": "RUNTIME_WASM" in its mod.json. modlock publish then compiles it ahead of time to WebAssembly with scriptc, which modlock downloads the first time. The compiled mod runs about 2.5 times faster, but the compile takes about a minute and a few gigabytes of memory. To check that build before you publish, run modlock build --release, which compiles the same way.

In two cases the build falls back to the QuickJS bundle, and modlock publish refuses to upload it unless you pass --allow-fallback:

  • scriptc cannot compile part of the mod. The build lists each such place and the reason.
  • The two builds behave differently. To find out, the build plays both in the sandbox through a start, a player joining, a world loading and five seconds of frames. Both builds share one clock and the same random bytes. Each event goes to the QuickJS build first, and whenever the WebAssembly build makes the same call, it gets the reply QuickJS got. The build prints the first event where their calls or answers differ and what each build did there. A run of server commands is compared as a set, because their order does not change the game. The check compiles QuickJS with scriptc's copy of Zig, once per scriptc version.

On this page