Skip to content

Data files and the rate grammar

designed · Phase 1 (#29, #32) · PLAN §5.5, §6.10, §15.2, §18.5, §22.2

data/
├── templates/      npc_villager.template.json, building_wooden, berry_bush, wood_pile, campfire, bucket
├── scenarios/      village.scenario.json
├── materials/      (Phase 1: unused)
├── rules/          (Phase 3)
└── world-schema.json

Templates

{ id, kind, components[], attributes{} }. An attribute value is a number, a string, a bool, { "value", "variance" } or { "min", "max" } (sampled at spawn from the seeded RNG), or a rate string.

The rate grammar

Rates and durations are stored in sim-time with the unit in the key. A data file may write the value as a number in that unit or as a string the loader parses:

<number> [± <number>] <unit>          "3 hours"   "60 ± 15 years"   "2 days"
<number> / <unit>                     "100/day"   "80/day"   "0.4/hour"
units: minutes | hours | days | weeks | seasons | years

The parsed value must match the unit the key names: "hunger_rate_per_day": "100/day" is fine; "hunger_rate_per_day": "4/hour" is converted (96/day); "hunger_rate_per_day": "3 hours" is rejected (a duration is not a rate). A bare per-tick number for a rate key, or any key ending in _per_tick, is rejected at load — invariant 9.

Keys: *_per_day, *_per_hour, *_hours, *_days, *_years, *_minutes.

Scenario

{ "id": "village", "world": { "ticks_per_day": 200, "ambient_temperature": 15 },
  "locations": [ { "id": "inn", "template": "building_wooden", "components": ["ThermalBody"] }, … ],
  "edges":     [ { "from": "fire_pit", "to": "inn", "relation": "connected_to",
                   "properties": { "permeability.heat": 0.4, "permeability.sound": 0.5, "permeability.light": 0.6 } }, … ],
  "factions":  [ { "id": "villagers", "knows": { "locations": "all", "resources": "all" } } ],
  "spawn":     [ { "template": "npc_villager", "count": 20, "in": "village_square", "faction": "villagers" }, … ] }

factions[].knows seeds knows edges (provenance: "seeded") from the faction node to the named locations and resource nodes (PLAN §7.3, §15.2).

World schema

{ "attributes": [ { "name": "food_value", "type": "float", "bounds": { "min": 0 }, "depletable": true, "salient": true }, … ],
  "components": [ … ], "events": [ … ] }

A depletable attribute without min is rejected at load. salient marks what PerceptionSystem records as facts. Manifests add their contracts at load to form the live schema (reads/writes for components, attributes, edges, events; writes.actions with needs).