Appearance
Making mods (preview)
Mods add to the game: weather, things on the screen, and behaviour through scripts, with cars, places, models, sounds, paints and outfits to come. A mod is one file you drop into a folder; players switch it on or off and set its order on the game's Mods page (Esc).
A preview
Mods arrive with the downloadable game (they don't run in the browser). The format below is the first version: what the script API offers will grow, and what's here stays.
Where mods go
Documents/Nowhere in Particular/mods/ on your computer. Each mod is a .zip (or an exported Godot .pck). The game reads them at start; a change on the Mods page applies from the next start.
What's in a mod
A zip of plain files, laid out as they'll appear in the game (no Godot needed to make one):
mods/<id>/mod.json the manifest (below)
mods/<id>/main.gd a script, if your mod has one
mods/<id>/vehicles/<key>/vehicle.json a car (below), with its model beside it
mods/<id>/regions/<key>/region.json a place (below), with its tiles and map
mods/<id>/places/<name>.json things placed in the world (below)
mods/<id>/outfits/<key>.json how you look on foot
mods/<id>/weather/presets.json weather presets
mods/<id>/sounds/sounds.json sounds, by name
mods/<id>/props/props.json trees, bushes, rocks and grass
mods/<id>/mixtape/stations.json Mixtape stations: your own tracks, or a stream
mods/<id>/... anything else it brings
weather/presets.json a replacement for one of the game's files (declared in "replaces")mod.json:
json
{
"id": "hello-mods",
"name": "Hello, mods",
"version": "1.0.0",
"author": "You",
"licence": "CC0-1.0",
"description": "What it does, in a line.",
"game": ">=0.5",
"api": 1,
"requires": ["another-mod>=1.0"],
"load_after": ["better-sky"],
"replaces": ["res://weather/presets.json"],
"main": "main.gd"
}id: lowercase letters, digits and dashes, and the name of its folder undermods/.versionandlicenceare required. The licence is shown to players with your name.gameandapi: the oldest game version and script API it works with.requires: other mods it needs (it isn't loaded without them);load_after: mods it should come after when they're there.replaces: the game's files it replaces. A mod may only put files undermods/<id>/, or at the paths it lists here; anything else and the game refuses the mod and says why. When two mods replace the same file, the one later in the player's order wins, and the Mods page shows the clash.
A .pck exported from a Godot project works too (for scenes and imported resources), but only adds files: replacements go in a zip.
Cars
A car is a folder under vehicles/: a vehicle.json and its model, a glTF (.glb, with its textures where the model expects them). It shows up in the game's vehicle list (the quick menu's Change vehicle, the phone's Garage) after the game's own cars.
json
{
"format": 1,
"name": "Taxi",
"desc": "The sedan, in yellow, a little livelier",
"model": "model.glb",
"scale": 1.65,
"tint": "#ffe48a",
"idle": 720,
"mass": 1350,
"torque": 0.95,
"front": 1.0,
"spring": 0.85,
"com": 0.52,
"grip": 1.0,
"offroad": 1.0,
"licence": "CC0-1.0",
"author": "Kenney (Car Kit)"
}tint multiplies the model's colours; engine is which engine it sounds like (r4, r6, v6, v8_diesel, flat2, single_2t, twin_2t; the Sounds below); idle is the engine's idle speed (rpm); mass is in kg; torque scales the engine's pull; front is the share of the drive at the front wheels (0 rear, 1 front, between for four-wheel drive); spring the suspension's stiffness; com how high the centre of mass sits; grip and offroad the tyres' grip on roads and off them. "transfer": true gives it a transfer case (2H, 4H, 4L) and diff locks, in the quick menu's Drive. "gear": {"roof": ["roof_tent", "jerrycan"], "bed": ["cooler", "water_drum", "duffel"]} loads it with the game's gear (also recovery_boards), packed where it fits; wear (0 to 0.6, default 0.1) is how worn it starts (faded paint, chips low down; it wears more off road). With offroad 1.2 or more the HUD shows the off-road gauges (an inclinometer and a compass); "inclinometer": true or false says so either way. The wheels are found by their names in the model (wheel-front-left, ... as in Kenney's Car Kit). "paint" names the model's body-colour material (for models with flat colours per material, such as "paint": "Paint"): it takes the tint, and the colour players choose in the phone's Garage › Colour (their friends see it in a roam); the first colour offered is the car's own tint.
A bicycle or a motorcycle has "kind": "bicycle" or "motorcycle", and a model whose moving parts are nodes at their pivots: frame, fork (its +Y the steering axis), wheel-front, wheel-rear, on a bicycle crank, pedal-left, pedal-right, and empty markers seat, grip-left, grip-right (under fork) and, on a motorcycle, peg-left, peg-right; the materials named frame (coloured by tint), accent (by "accent"), dark, tyre, rim, saddle. The game's own are in vehicles/bicycle and vehicles/dirt-bike, made by scripts/prep_bicycle.py and scripts/prep_enduro.py (in Blender, from models with open licences). A bicycle takes power (W) and push (N) instead of torque; rider_lean (degrees) leans the rider forward to the bars; seat_back (m) sits the rider that far behind the seat marker and grip_back (m) puts the wrists that far behind the grips; drag is the air's.
A car's lamps go where its model says, if it has marker nodes (empty nodes named lamp-head-left, lamp-head-right, lamp-tail-left, lamp-tail-right, blink-front-left, ... blink-rear-right); "head_material", "tail_material" and "reverse_material" name its own lamp materials, and "blink_materials" its blinkers' (["left material", "right material"]), which then glow (else boxes are put on the body at its bounds).
In the first person every car gets the game's own cockpit: a dash with the cluster (one wide screen, the map and the weather on its right) in its binnacle, the phone on its mount, a wheel that turns, the door cards and the seats, fitted to your model from the driver's eyes; whatever of the model's own interior is in front of you is hidden meanwhile (its windscreen pillars kept). "eye": [x, y, z] says where the driver's eyes are (metres, in the car's own frame: x right, y up, -z forward), when the seat isn't where the body's size suggests (a motorcycle's too, where the cluster and the phone go on the bars). Where the fit isn't right, "interior" sets it by hand: "foot": [down, ahead], where the windscreen's glass ends from the eyes (metres, down negative: [-0.28, 1.0]; the dash's top meets it there, else it's found by looking), "offset": [x, y, z] moves the whole interior, "band" (m) is how wide a strip is kept by each window for the model's pillars, and "clip": [x0, y0, z0, x1, y1, z1] (from the eyes) is the box of the model's own interior to hide. ("head_unit", a centre screen until 2026-10-23, is ignored.)
A car can carry a bike or a boat: "mounts": ["roof", "hitch", "bed"] lists where, in order of preference (roof, a roof rack, takes a bicycle or the kayak; hitch, the tow hook, a bicycle on its rack or the jet ski on its trailer; bed, a pickup's, a bicycle or a motorcycle); the places come from the car's body. Taking it down, putting it back, hitching and launching are the game's Use spots (F on foot by the rack or the trailer): nothing more to set.
Places
A place is a region as the game's generator builds it from open data: region.json, map.json, map.mapi and the tiles/ folder, under mods/<id>/regions/<key>/. The world is one grid for all of Europe, so a place near the game's own joins it: you drive straight into it. One further away is a world of its own (the game starts there with --start=<key>). A "join": true or false in its region.json decides it either way. The tools to build and pack a place from OpenStreetMap and national elevation data come with the map editor; the data's licences (OpenStreetMap's ODbL, the elevation's) go in your mod's licence. region.json lists every tile (a file per layer of the tile, in tiles/<zone>/<layer>/) with its versions (each file's hash: its SHA-256, size, built), as the generator writes it; nip-gen mod check refuses a tile that isn't the one listed, so rebuild the place rather than swapping tile files by hand.
The game's own places aren't in its pack: their tiles are files in a folder beside the game (its tile store). A mod's place lies over it: the game takes a tile from your mod first and from its own store only where your mod has none, so turning the mod off brings the game's place back as it was. A mod that stands in for one of the game's places (an edited copy: the editor's Export as mod) says so with "replaces_regions": ["<key>"].
Placing things in the world
A mod can add to any place, the game's own included, without touching it: a landmark, a statue, benches, a car park full of parked cars. Any number of mods can add to the same town. List them in places/<name>.json:
json
{"places": [
{"model": "res://assets/third_party/kenney-car-kit/van.glb", "lat": 51.96095, "lon": 19.70745,
"heading": 25, "scale": 1.75},
{"model": "statue.glb", "e": 4985962.0, "n": 3250026.0, "heading": 70, "collide": "mesh"}
]}model: one of the game's (res://...: its cars, trees, rocks, people) or your own glTF.- Where:
latandlon, oreandn, metres on the game's world grid (the pan-European ETRS89-LAEA grid, EPSG:3035). Things stand on the ground;ylifts them (metres). heading: degrees clockwise from north; a model's front is its +Z (glTF's forward).scale;collide:"box"(the model's bounds, the default),"mesh"(its shape: for something you can walk around and into) or"none";range: how far it's drawn (800 m).replaces: buildings the game generated, by their OpenStreetMap ids, left out where your model stands (a petrol station's real canopy instead of the box the map data gave; a landmark modelled properly).removes: buildings left out with nothing in their place (a place with onlyremovesneeds nomodel). They go from the drawing, the collisions and all; a building mapped in parts (building:part: a tower, a wing) goes whole by its outline's id. A bridge's deck goes the same way, by its way's id (your model brings its own deck).clear: metres round the place cleared of what the game stood there, andwhat: any of"trees","lamps","signals"(all three by default). With nomodel, a clearing on its own.
json
{"places": [
{"model": "station.glb", "lat": 51.956574, "lon": 19.701708, "replaces": [181360832]},
{"removes": [160618132, 160618140]},
{"lat": 51.95, "lon": 19.72, "clear": 25, "what": ["trees"]}
]}Using the game's models
Anything a mod names as res://... is the game's own file: a car can use the game's models (res://assets/third_party/kenney-car-kit/suv.glb), an outfit the game's bodies and hair, a nature set or a place the game's trees and rocks. The game's models are listed in its vehicles/, props/props.json and outfits/ files.
Outfits, weather, sounds and nature
These are small JSON files the game merges with its own: a key in your file replaces the game's, and a key written with a + adds to a list instead. File names are relative to the JSON file (or res://... for the game's own files).
- Outfits (
outfits/<key>.json): a body (res://assets/third_party/quaternius/character_male.glborcharacter_female.glb), hair models, and the colours ofskin,hair_color,shirt,trousers,shoes("#rrggbb"),long_sleeves, and itsfigure("man"or"woman": the phone's Me > Body picks the game's own,defaultorwoman). Start the game with--outfit=<key>to wear any one. The colours players choose in Me › Looks go on its garments by part (the top, the trousers, the shoes), found by the meshes' names ("shirt", "sweater", "pants", "shoes"...), the skin's tone on its body and the hair's colour on its hair ("hair", "ponytail"... and the eyebrows); an outfit can name its own:"parts": {"top": ["poncho"], "trousers": ["kilt"], "hair": ["braids"]}. - Weather (
weather/presets.json):{"presets": {"heatwave": {"cloud": 0.02, "wind": 1.0, "temp": 33}}, "+order": ["heatwave"]}. The fields arecloud,low,mid,high(cloud layers, 0 to 1),rain,snow,fog,storm,wind(m/s),temp(°C, optional). - Sounds (
sounds/sounds.json):birds,crickets(loops),impacts_hard,impacts_soft(lists); OGG, WAV or MP3.{"birds": "dawn-chorus.ogg"}replaces the birds. The vehicles' and the weather's are there too, a level deep, so one can be replaced alone:tyres(roar,crunch_dull,crunch_bright,soft_dull,soft_bright,mud,hiss,wade,squeal: loops;splash,thump,squeak: one-shots),wind,rain_roof,steps(hard,grass,gravel,dirt,snow,soft,water: lists of takes),thunder(near,mid,far),leaves_rain,water_lapping,geese(near,far),horn(car,low,moto: loops;bell),blinker, andengine(by the vehicle'sengine:r4,r6,v6,v8_diesel,flat2,single_2t,twin_2t, and the game's ownfourandsingle:rpm, a list of points, with anonand anoffloop at each, recorded at that rpm;electric:hz,whine,hum). A kind with no loops plays the nearest the game has: the single for the bikes and two-strokes, the four for the rest; so a mod can give the V8 its own sound by naming"engine": {"v8_diesel": {...}}.{"tyres": {"crunch_bright": "gravel.ogg"}}replaces the gravel. The game's own are in itssounds/sounds.json. - Nature (
props/props.json):modelsmaps a name to a model;deciduous,conifers,bushes,rocks,grassare the sets the world picks from.{"models": {"tree_oak": "my-oak.glb"}}reskins the oaks everywhere;{"models": {"birch": "birch.glb"}, "+deciduous": ["birch"]}adds a tree.floranames the sets of models a region's generator plants (its forests, towns, waterside and scrub), chosen in a region'sregion.tomlby[climate] flora; append to the lists (+deciduous), since the tiles name a model by its place in its list.
Mixtape stations
A mod can bring stations to the phone's Mixtape: music of its own (tracks in the mod, played from it, so they work offline and in the browser) or a live stream's address. They're listed after the game's own station, Nowhere FM, and before the live ones, each in its colour.
json
{
"stations": [
{
"id": "night-shift",
"name": "Night Shift FM",
"colour": "#9fd0c7",
"tracks": [
{"file": "night-1.ogg", "title": "Neon Underpass", "mood": "lofi"},
{"file": "dawn.ogg", "title": "First Bus", "mood": "ballad"}
]
},
{"id": "groove-salad", "name": "Hello, Groove Salad", "url": "https://ice5.somafm.com/groovesalad-128-mp3"}
]
}- Tracks (
tracks): Ogg Vorbis (best), MP3 or WAV, relative to the file. They're shuffled with a crossfade from one into the next, and the time of day weighs them bymood:lofiandpostrockat night,jazzin the afternoon,balladin the morning and evening; any other mood (or none) plays as often at any hour. Thetitleis what the phone and the screen show as the song. Only music you may give out with your mod (the licence is inmod.json). - A stream (
url): https, MP3, AAC or Ogg, as the game's own live stations. It plays only where they do (the Steam builds for now, with Online on). colour("#rrggbb") is optional: without it the station gets a colour made from your mod's id.nip-gen mod checkchecks the file and that the tracks are there.
Scripts
A mod's script extends NipMod and talks to the game through api (version 1):
gdscript
extends NipMod
func _ready() -> void:
api.register_weather("heatwave", {cloud = 0.02, wind = 1.0, temp = 33.0})
api.world_ready.connect(func(): api.toast("Hello from a mod"))
api.on_foot.connect(func(_walker): api.toast("Mind the puddles"))| Signals | world_ready, car_spawned(car), on_foot(walker), in_car(car), hour_changed(hour), weather_changed(preset) |
| Calls | toast(text), add_hud(control), register_weather(name, preset), add_use(name, finder) and remove_use(name) (a place on foot where F does something of yours, below) |
| Reading | local_time(), weather(), position() (world metres, latitude and longitude, on foot or not), car() |
| Your files | storage(): a folder of your own for what your mod keeps |
Things to do with F. On foot, F (a gamepad's D-pad left) does what's by you, and a prompt says what. add_use(name, finder) adds places of yours: the game calls finder(where) a few times a second with where you stand (world metres, as position()), and it returns the places near there, each {id, at, reach, verb, why, act}: at a Vector3 in world metres, reach how near you must be (metres), verb what the prompt says ("Ring the bell"), why "" when it can be done now (else why not, shown greyed), act a Callable that does it. Keep it quick: only what's near.
gdscript
var bell := Vector3(120.0, 4.0, -340.0)
api.add_use("bell", func(_where: Vector3) -> Array:
return [{id = "bell", at = bell, reach = 2.0, verb = "Ring the bell", why = "",
act = func(): api.toast("Ding")}])Anything else a script can reach in the game is its insides, and may change in any release; the API is what stays. Scripts run inside the game's sandbox (the game runs in WebAssembly, on gasm): a mod can't touch your computer, and it reaches the network only if it asks for a host and the player allows it.
Tools
A mod is a zip of the layout above, zipped from inside the folder (so the zip starts with mods/). The map editor and mod tools start a mod, add a place or a car to it, check it the way the game does, and pack it; the editor exports a place you built and edited as a mod.
An example
An example mod comes with each download, hello-mods.zip: a car (a taxi), parked cars and a tree on a street in Głowno, an outfit (a raincoat: --outfit=raincoat), a heatwave in the weather list, a Mixtape station (a stream), a greeting, a word when you get out of the car, and the hour on the screen. Unzip it to see how it's made, or drop it into your mods folder as it is.