ts2.config.json
A ts2 project is a directory containing ts2.config.json and a folder of .ts2
sources. Every setting has a default, so the file can be empty — or absent, if
the defaults suit.
{ "src": "./src", "outDir": "./dist", "registry": "./ts2-state.lock.json", "bytecode": true, "scriptIdBase": 22000, "interfaceIdBase": 1200, "externalTypes": ["./src/game/config-params.d.ts2"]}The build looks for ts2.config.json in the directory you point it at and then
in each parent. Every path in it resolves against
the directory the file is in.
Reference
Section titled “Reference”dialect
Section titled “dialect”Which client this project targets.
Default: "rift-extended"
"rift-extended" | The Rift client. Everything in the language is available. |
"rift-standard" | A stock client. Anything the Rift client added is unavailable. |
Building on rift-standard refuses anything the stock client would not
understand (TS2E222), naming what you used. Engine hooks — defineEngineHooks — exist only on rift-extended (TS2E350).
Every build prints which dialect it used, including the default.
The directory scanned for .ts2 sources, recursively. Every file under it is an
entry point: compiled whether or not anything imports it, so a component
nobody uses yet is still checked.
Default: "./src"
The directory a source’s name is spelled from. A function’s qualified name — and so the number the build gives it — is its path relative to this directory.
Default: the value of src
You set it only in a workspace: a folder that is one project of many names the workspace’s root here, so its files and the shared ones it imports keep the names the workspace’s full build gives them.
shared
Section titled “shared”Directories a source may import from without their files being entry
points. Only the files src reaches through imports, transitively, are
loaded from them. Each must exist.
Default: []
externalRefs
Section titled “externalRefs”A JSON file mapping module-scope ref names to the component each is bound to,
written by a full build of the workspace as dist/module-refs.json. A
createRef declared in the compiled set but bound to an element outside it
resolves through this table instead of failing the rule that every ref is
bound.
Default: none
externalTypes
Section titled “externalTypes”Files of declarations this project adds to the global scope — chiefly the
parameter fields an item, an NPC or a world object carries, so that
item.levelrequire! is a field. Each path must exist.
Default: []
See Reading game data.
outDir
Section titled “outDir”Where build outputs are written. Everything under it is derived and rewritten on every build. Do not commit it, and do not edit anything in it. Project outputs says what each file is for.
Default: "./dist"
registry
Section titled “registry”Path to the persisted-state lockfile. See The state registry below.
Default: "./ts2-state.lock.json"
bytecode
Section titled “bytecode”Whether the build also writes the form the game loads for each function beside
its readable one, under dist/scripts/.
Default: true
The id bases
Section titled “The id bases”Every number the build hands out — to an interface, to a function, to a collection you declared — is counted up from a base. Two projects packed into one game must start from different bases, or the second overwrites the first.
| Setting | Numbers | Default |
|---|---|---|
scriptIdBase | functions, components and handlers | 20000 |
interfaceIdBase | interfaces | 1000 |
collectionIdBase | lists and maps declared with listOf and mapOf | the build’s own base |
dbTableIdBase | the tables behind collections of records | the build’s own base |
dbRowIdBase | the rows of those tables | the build’s own base |
Change them only when packing more than one project into one game.
catalystHome
Section titled “catalystHome”Set by the toolchain, for the build to find what the client can do. You should not need it.
Workspaces
Section titled “Workspaces”A folder of a workspace compiles alone. Three settings make it one:
{ "root": "..", "src": ".", "shared": [".."], "externalRefs": "../dist/module-refs.json"}rootspells the folder’s names as the workspace’s full build spells them.sharedlets the folder import from its neighbours and the library, loading only what it reaches.externalRefsresolves the refs the shared code declares but binds in another folder — a frame’s slots, say — to where the full build put them.
A ref bound in an interface this folder hosts is this folder’s, whatever the table says. A hosting refusal for a shared component that no interface here opens is not raised; every other refusal in a shared file stands.
Ship the workspace’s full build. Give each folder’s collections and tables bases above the workspace’s, so nothing it numbers shadows what the full build numbered.
The state registry
Section titled “The state registry”ts2-state.lock.json records every
persistedState key the project
has ever declared, and which slot it was given.
Commit it. The build maintains the file; you review the diff.
The rules it enforces:
- A slot never moves, even when a declaration sorting before it is added.
- A removed key is retired rather than deleted — its slot must never be reused, because saved values still sit under it.
- The same key coming back reclaims its original slot, recovering those values.
- Two declarations cannot share a key (
TS2E126).
Run CI with --frozen so a build that would add a key fails instead:
ts2 . --frozenTroubleshooting
Section titled “Troubleshooting”The build says it found no config
Section titled “The build says it found no config”It walks up from the directory you gave it. Either you pointed it somewhere
outside the project, or the file is named something other than
ts2.config.json. A missing config is not fatal — it builds with the defaults —
so check the path it reports on the first line of output.
The build says a source directory does not exist
Section titled “The build says a source directory does not exist”src resolves against the directory holding the config. shared directories and
externalTypes files are checked the same way, and a missing one is refused
before anything compiles.
A build that passed locally fails in CI
Section titled “A build that passed locally fails in CI”Most often --frozen: you added a persisted key and did not commit the
lockfile.
A ref is “never bound to a node” in a folder that compiles fine as part of the whole
Section titled “A ref is “never bound to a node” in a folder that compiles fine as part of the whole”The folder declares or imports a createRef that another folder binds. Point
externalRefs at the full build’s dist/module-refs.json.