Skip to content

Config

Read and write TOML files under the mounted project. Tables become Maps, arrays become Lists, primitives as-is; dates/times are strings. All methods are static.

Config is TOML-text persistenceload parses a file into Wren values, and save writes a string of TOML you built yourself back to disk. It is not a scene-serialisation API: nothing walks the Scene graph, and there is no Map → TOML encoder.

Import from the engine module:

import "engine" for Config

Parse a TOML file from a mounted path.

Returns: Map — the root table of the TOML file, with String keys. Always a Map, never null (a TOML document’s root is always a table). Nested values map as:

  • table → Map (String keys)
  • array / array-of-tables → List
  • string → String
  • integer and float → Num — both arrive as a double, so integers beyond 2^53 lose precision
  • boolean → Bool
  • date, time, date-time → String (e.g. "2026-07-16", "09:30:00")

Parameters:

  • path (String) — Path to the TOML file relative to the mounted project (e.g. "game.toml", "channels.toml").

Use the returned structure to read your config. Map keys are strings; nested tables are Maps, nested arrays are Lists.

var config = Config.load("channels.toml")
var channels = config["channels"]
if (channels != null) {
for (ch in channels) {
var name = ch["name"]
var path = ch["path"]
var freq = ch["frequency"]
// ...
}
}
var gameConfig = Config.load("game.toml")
var windowW = gameConfig["Window"]["width"]

Write tomlText to path as raw bytes, replacing the file’s contents.

Returns: Booltrue only when every byte was written. false on any failure: either argument is not a String, path is empty, no write dir is set (an archive-backed package), the file could not be opened, or a short write. The reason reaches the engine log only — script cannot read it.

Parameters:

  • path (String) — Destination relative to the write dir (see below). Path traversal is rejected: .. components, \, and : all fail. A leading / is ignored.
  • tomlText (String) — The exact bytes to write. Not parsed and not validated.
var text = "[Window]\nwidth = 1280\nheight = 720\n"
if (Config.save("game.toml", text)) {
Logger.info("Saved %(text.count) bytes to game.toml")
} else {
Logger.error("Save failed (see log)")
}

path resolves against the PhysFS write dir, which the engine sets at startup based on how the app was launched:

Launch modeWrite dir
Directory project (default)the project root — the same directory load reads from
Archive package (.zip and friends)nonesave always returns false
--tool <toolDir> <dataDir>the data dir, not the tool dir
--test <appDir>the app dir
--server <appDir>the app dir

Two consequences worth planning around:

  • There is no per-user save location. Writes land next to the game’s own files, not in an OS profile/AppData directory. On an installed build that directory may be read-only, and two users on one machine share one file.
  • Parent directories are not created. The file itself is created if missing, but the directory holding it is not. Config.save("saves/slot1.toml", text) fails unless saves/ already exists, and script has no way to create it — ship the directory with the project.

Shipping as an archive silently turns every save into a no-op that returns false, so if your game persists anything, test it in the packaging mode you actually ship.

load and save share the project directory in directory mode, so a load → edit → save cycle rewrites the file in place:

import "engine" for Config, Logger
class Settings {
construct new() {
var c = Config.load("settings.toml") // empty Map if absent or malformed
var win = c["Window"]
_width = (win != null && win["width"] != null) ? win["width"] : 1280
_height = (win != null && win["height"] != null) ? win["height"] : 720
}
width=(v) { _width = v }
// Hand-rolled serializer: the engine has no Map -> TOML encoder.
serialize() {
return "[Window]\nwidth = %(_width)\nheight = %(_height)\n"
}
save() {
// Back up the PREVIOUS values first -- save() truncates before it writes.
// Config.load only hands back parsed values, never the original bytes, so
// a backup has to be re-serialized from the Map; it is not byte-exact.
var win = Config.load("settings.toml")["Window"]
if (win != null && win["width"] != null && win["height"] != null) {
Config.save("settings.bak.toml",
"[Window]\nwidth = %(win["width"])\nheight = %(win["height"])\n")
}
if (!Config.save("settings.toml", serialize())) {
Logger.error("settings save failed -- archive build, or dir not writable")
}
}
}

See Resource.loadConfig for the cached variant of load (same path returns the same instance), and Configuration for the game.toml schema the engine itself reads.