# Footprints, ruts and ground marks (world.tracks) ## What it is for `world.tracks` keeps every mark left on the ground: boot prints, tyre ruts and drag strips. Snow is the default material: alternating prints and ruts pressed into the snow layer, refilled by snowfall when `world.weather` is installed. Soft surfaces declared as data (sand, mud, dust, ash) take the contacts that land on them with their own colour, depth, lifetime, ceiling, dust, speed factor and step sound. Marks fade with time and weather and are saved with the game. A game that declares no surface keeps the snow behaviour. Each contact goes to exactly one place: the declared surface under it (highest `priority` first); else snow, where there is snow (with `world.weather`, where it lays snow; without it, only when no surface is declared); else nothing, the ground is hard. ## Turn it on ```json { "id": "world.tracks", "config": { "lifetime": 240, "wheelRuts": true } } ``` It requires `game.engine`. Optional companions: `world.weather` (snowfall fills prints, rain and melting clear them, wind, rain and snow wear surface marks faster), `world.ground` (ground height of prints), and `world.terrain`, `world.biomes` and zones, which a surface can be bound to. It conflicts with `world.fluids` in the same scene. ## First example The fixture declares a `mud` surface bound to a zone, with a colour, `opacity: 0.8`, `depth: 0.9`, `lifetime: 6`, `maxMarks: 12` and `slow: 0.5`, and a `sand` surface bound to a height band. It creates a player, a vehicle and a sled carrying `{ "type": "drag", "width": 0.5 }`, steps once, then reads `surfaces()`, `surfaceAt(x, z)` and `marks()`. Prints, tyre ruts and a drag strip are left on the declared surface under each entity, and a point on hard ground answers `null`. ## Settings and defaults | Setting | Type | Default | Meaning | |---|---|---|---| | `enabled` | boolean | `true` | Make and draw marks. | | `autoContacts` | boolean | `true` | Make prints from feet and wheels; false leaves only contacts sent by other kits. | | `includeNpcs` | boolean | `true` | NPCs in range leave prints too. | | `player` | boolean | `true` | The player leaves prints. | | `stride` | number 0.25-1.5 | `0.62` | Metres between two prints. | | `footWidth` | number | `0.18` | Print width, metres. | | `footLength` | number | `0.32` | Print length, metres. | | `footSpacing` | number | `0.12` | Metres between the centre line and each foot. | | `wheelRuts` | boolean | `true` | Vehicles (tagged `vehicle`) leave ruts behind the rear wheels. | | `rutSpacing` | number | `0.9` | Metres between two rut segments. | | `wheelWidth` | number | `0.24` | Rut width, metres. | | `gauge` | number | `0` | Metres between the two ruts; 0 is 84 % of the vehicle width. | | `lifetime` | number 10-1800 | `180` | Seconds a snow print lasts without `world.weather`. | | `maxTracks` | integer | `2048` | Snow prints kept; the oldest goes first. | | `simulationRange` | number 10-100 | `40` | Only walkers within this range of the player leave marks. | | `maxMarks` | integer | `600` | Marks alive on declared surfaces. | | `intensity` | number 0-1 | `1` | Strength of marks; 0 leaves none and hides the ones left. | | `fade` | number 0.05-20 | `1` | Fading speed multiplier. | | `weather` | number 0-5 | `1` | How much weather speeds up fading of surface marks; 0 is not at all. | | `surfaces` | array (max 32) | `[]` | Soft surfaces; also read from the `trail_surfaces` collection. | A surface is `{ id, name, layers, biomes, zones, minHeight, maxHeight, maxSlope, priority, color, opacity, depth, lifetime, maxMarks, dust, slow, sound }`. Every criterion given must hold; a surface with none covers everything. `opacity` defaults to 0.6, `depth` to 0.5, `lifetime` to 90, `dust` to true; `slow` is a speed multiplier (0.7 for deep sand). Any entity may carry the `trail` component `{ type, stride?, width?, gauge? }` with `type` one of `feet`, `wheels`, `drag` or `none` (`none` stops the default marks; `drag` leaves one strip behind the body). ## Services, events, hooks - `world.tracks` (service): `marks()` lists live surface marks (`id`, `x`, `y`, `z`, `yaw`, `kind`, `side`, `width`, `length`, `alpha`, `color`, `depth`, `surface`, `entity`); `surfaceAt(x, z)` returns the declared surface, snow, or null; `surfaces()`; `emitters()`; `snapshot()`; `contact(c)`; `reset()` (wipes without asking); `clear()` (asks `tracks.clear`, returns the count); `fadeRate()`; `version()`. - `world.tracks.settings` (service): `keys()`, `get(key)`, `set(key, value)` for `intensity` and `fade`, for `world.bindings`. - `tracks.step` (event): `{ entity, surface, kind, x, z, sound }` for each print or drag segment when surfaces are declared; for step sounds. Wheel ruts do not emit it. - `tracks.cleared` (event): `{ count }` after `clear()`. - Listened: `surface.footstep` (an explicit snow contact), `surface.tracks.reset`, `entity.spawned`. - `tracks.slow` (hook): `{ entity, type, surface, factor }`; mutable `factor` (0.05-1); cancellable (the entity is not slowed). Asked when the factor of an entity changes, never while it stays. - `tracks.clear` (hook): `{ count }`; cancellable (nothing wiped, `clear()` answers 0). On a surface whose `slow` is under 1, vehicles driven through `vehicle.drive` get that multiplier on top speed and acceleration, and the player too when its character kit serves speed factors. Snow does not slow. ## Hooks and modding A mod may override the config (except `surfaces` and `maxTracks`) and add, patch or remove documents of `trail_surfaces`: ```json { "id": "snowshoes", "hook": "tracks.slow", "match": { "type": "feet" }, "set": { "factor": 0.9 } } ``` ## Engines Snow prints are drawn on the web, Godot, Unity and Unreal from the same contact history. Declared surfaces, their marks, the `trail` component, slowing and the live settings are web and Rust only for now; the other engines ignore them. Textures bound to the slots `trail_foot` and `trail_wheel` replace the drawn print and strip. ## When it does not do what you expect - No marks: `enabled` is false, `intensity` is 0, the walker is idle, airborne or seated, or it is farther than `simulationRange`. - No print on snow: without `world.weather` and with a surface declared, snow is not assumed; with it, there is no snow there. - Marks never end: `lifetime` is long and weather is calm; raise `fade`. - A surface never matches: one of its criteria fails, or a higher `priority` surface wins. ## Limits It never adds collision geometry. Marks follow ground contacts only: no jump or teleport streaks. ## Versions Kit 1.4.0; it provides `world.tracks` 1.3.0 and requires `game.engine@^1`. Surfaces, the `trail` component and the settings date from 1.3.0; the hooks from 1.4.0.