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 persistence — load 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 ConfigConfig.load(path)
Section titled “Config.load(path)”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"]Config.save(path, tomlText)
Section titled “Config.save(path, tomlText)”Write tomlText to path as raw bytes, replacing the file’s contents.
Returns: Bool — true 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)")}Where save writes
Section titled “Where save writes”path resolves against the PhysFS write dir, which the engine sets at startup based on how the app was launched:
| Launch mode | Write dir |
|---|---|
| Directory project (default) | the project root — the same directory load reads from |
Archive package (.zip and friends) | none — save 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 unlesssaves/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.
Round-tripping a file
Section titled “Round-tripping a file”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.