{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://iamar.world/schemas/manifest-0.schema.json",
  "title": "iamar world package manifest (format 0)",
  "description": "manifest.json at the root of an iamar world package. See docs/WORLD_FORMAT.md.",
  "type": "object",
  "required": [
    "format",
    "format_version",
    "id",
    "name",
    "author",
    "version",
    "api_version",
    "budgets"
  ],
  "additionalProperties": false,
  "patternProperties": {
    "^x-": {}
  },
  "properties": {
    "format": {
      "const": "iamar-world"
    },
    "format_version": {
      "const": 0
    },
    "id": {
      "$ref": "#/$defs/id",
      "description": "Stable world id, lowercase. The package's local id, and the <world> part of iamar://<owner>/<world>."
    },
    "name": {
      "type": "string",
      "minLength": 1,
      "maxLength": 80
    },
    "description": {
      "type": "string",
      "maxLength": 2000
    },
    "author": {
      "type": "object",
      "required": [
        "name"
      ],
      "additionalProperties": false,
      "properties": {
        "name": {
          "type": "string",
          "minLength": 1,
          "maxLength": 80
        },
        "contact": {
          "type": "string",
          "maxLength": 200
        },
        "owner": {
          "$ref": "#/$defs/id",
          "description": "iamar hub account name (the <owner> of iamar://<owner>/<world>)."
        }
      },
      "patternProperties": {
        "^x-": {}
      }
    },
    "version": {
      "type": "string",
      "pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+([-+][0-9A-Za-z.-]+)?$"
    },
    "api_version": {
      "type": "string",
      "pattern": "^[0-9]+\\.[0-9]+$",
      "description": "World API version the package targets, major.minor. This format is api 0.1."
    },
    "scene": {
      "$ref": "#/$defs/path",
      "description": "Scene file, default scene.json."
    },
    "spawn": {
      "description": "Where visitors appear: a spawn point id from scene.spawn_points, or an explicit point.",
      "oneOf": [
        {
          "$ref": "#/$defs/id"
        },
        {
          "type": "object",
          "required": [
            "position"
          ],
          "additionalProperties": false,
          "properties": {
            "position": {
              "$ref": "#/$defs/vec3"
            },
            "yaw": {
              "type": "number"
            }
          },
          "patternProperties": {
            "^x-": {}
          }
        }
      ]
    },
    "budgets": {
      "type": "object",
      "description": "What the world promises to stay under. The browser refuses a package that exceeds its own declared budgets, or declares more than the browser allows.",
      "required": [
        "triangles",
        "objects",
        "texture_size"
      ],
      "additionalProperties": false,
      "properties": {
        "triangles": {
          "type": "integer",
          "minimum": 0,
          "description": "Triangles of everything built at load (assets x instances, primitives, terrain, water)."
        },
        "objects": {
          "type": "integer",
          "minimum": 0,
          "description": "Scene entries: objects + primitives + lights + sounds + portals + triggers + npcs + creature individuals."
        },
        "texture_size": {
          "type": "integer",
          "minimum": 1,
          "description": "Largest texture edge in pixels (any image in any asset or file)."
        },
        "texture_bytes": {
          "type": "integer",
          "minimum": 0,
          "description": "Uncompressed RGBA bytes of all textures (w*h*4 summed)."
        },
        "lights": {
          "type": "integer",
          "minimum": 0
        },
        "package_bytes": {
          "type": "integer",
          "minimum": 0,
          "description": "Sum of all file sizes in the package."
        },
        "audio_bytes": {
          "type": "integer",
          "minimum": 0
        },
        "script_bytes": {
          "type": "integer",
          "minimum": 0
        },
        "event_fuel": {
          "type": "number",
          "minimum": 0,
          "description": "World script limit (docs/WORLD_API.md section 5); clamped by the browser."
        },
        "event_ms": {
          "type": "number",
          "minimum": 0,
          "description": "World script limit (docs/WORLD_API.md section 5); clamped by the browser."
        },
        "frame_callbacks": {
          "type": "number",
          "minimum": 0,
          "description": "World script limit (docs/WORLD_API.md section 5); clamped by the browser."
        },
        "frame_ms": {
          "type": "number",
          "minimum": 0,
          "description": "World script limit (docs/WORLD_API.md section 5); clamped by the browser."
        },
        "host_call_fuel": {
          "type": "number",
          "minimum": 0,
          "description": "World script limit (docs/WORLD_API.md section 5); clamped by the browser."
        },
        "init_fuel": {
          "type": "number",
          "minimum": 0,
          "description": "World script limit (docs/WORLD_API.md section 5); clamped by the browser."
        },
        "init_ms": {
          "type": "number",
          "minimum": 0,
          "description": "World script limit (docs/WORLD_API.md section 5); clamped by the browser."
        },
        "kv_bytes": {
          "type": "number",
          "minimum": 0,
          "description": "World script limit (docs/WORLD_API.md section 5); clamped by the browser."
        },
        "kv_key": {
          "type": "number",
          "minimum": 0,
          "description": "World script limit (docs/WORLD_API.md section 5); clamped by the browser."
        },
        "kv_value": {
          "type": "number",
          "minimum": 0,
          "description": "World script limit (docs/WORLD_API.md section 5); clamped by the browser."
        },
        "logs_per_sec": {
          "type": "number",
          "minimum": 0,
          "description": "World script limit (docs/WORLD_API.md section 5); clamped by the browser."
        },
        "max_asset_bytes": {
          "type": "number",
          "minimum": 0,
          "description": "World script limit (docs/WORLD_API.md section 5); clamped by the browser."
        },
        "max_assets": {
          "type": "number",
          "minimum": 0,
          "description": "World script limit (docs/WORLD_API.md section 5); clamped by the browser."
        },
        "max_entities": {
          "type": "number",
          "minimum": 0,
          "description": "World script limit (docs/WORLD_API.md section 5); clamped by the browser."
        },
        "max_host_calls": {
          "type": "number",
          "minimum": 0,
          "description": "World script limit (docs/WORLD_API.md section 5); clamped by the browser."
        },
        "max_memory": {
          "type": "number",
          "minimum": 0,
          "description": "World script limit (docs/WORLD_API.md section 5); clamped by the browser."
        },
        "max_message": {
          "type": "number",
          "minimum": 0,
          "description": "World script limit (docs/WORLD_API.md section 5); clamped by the browser."
        },
        "max_text": {
          "type": "number",
          "minimum": 0,
          "description": "World script limit (docs/WORLD_API.md section 5); clamped by the browser."
        },
        "max_timers": {
          "type": "number",
          "minimum": 0,
          "description": "World script limit (docs/WORLD_API.md section 5); clamped by the browser."
        },
        "max_traps": {
          "type": "number",
          "minimum": 0,
          "description": "World script limit (docs/WORLD_API.md section 5); clamped by the browser."
        },
        "max_wasm_bytes": {
          "type": "number",
          "minimum": 0,
          "description": "World script limit (docs/WORLD_API.md section 5); clamped by the browser."
        },
        "messages_per_sec": {
          "type": "number",
          "minimum": 0,
          "description": "World script limit (docs/WORLD_API.md section 5); clamped by the browser."
        },
        "notes_per_sec": {
          "type": "number",
          "minimum": 0,
          "description": "World script limit (docs/WORLD_API.md section 5); clamped by the browser."
        },
        "spawns_per_sec": {
          "type": "number",
          "minimum": 0,
          "description": "World script limit (docs/WORLD_API.md section 5); clamped by the browser."
        },
        "tick_fuel": {
          "type": "number",
          "minimum": 0,
          "description": "World script limit (docs/WORLD_API.md section 5); clamped by the browser."
        },
        "tick_hz": {
          "type": "number",
          "minimum": 0,
          "description": "World script limit (docs/WORLD_API.md section 5); clamped by the browser."
        },
        "tick_ms": {
          "type": "number",
          "minimum": 0,
          "description": "World script limit (docs/WORLD_API.md section 5); clamped by the browser."
        }
      },
      "patternProperties": {
        "^x-": {}
      }
    },
    "features": {
      "type": "array",
      "description": "Built-in browser features the world needs. A browser that lacks one refuses the world (or, for 'optional_features', ignores that part).",
      "items": {
        "$ref": "#/$defs/feature"
      },
      "uniqueItems": true
    },
    "optional_features": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/feature"
      },
      "uniqueItems": true
    },
    "scripts": {
      "type": "array",
      "description": "Sandboxed WebAssembly world scripts (phase 3). Loaded by the sandbox, never by the scene loader.",
      "items": {
        "type": "object",
        "required": [
          "path"
        ],
        "additionalProperties": false,
        "properties": {
          "path": {
            "$ref": "#/$defs/path",
            "description": "scripts/<name>.wasm"
          },
          "role": {
            "enum": [
              "host",
              "client",
              "both"
            ],
            "description": "Where it runs: on the world host (authoritative), in each visitor's browser, or both. Default both."
          },
          "entry": {
            "type": "string",
            "maxLength": 64
          }
        },
        "patternProperties": {
          "^x-": {}
        }
      }
    },
    "thumbnail": {
      "$ref": "#/$defs/path"
    },
    "license": {
      "type": "string",
      "maxLength": 200,
      "description": "SPDX id or short licence text for the world as a whole."
    },
    "credits": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "files",
          "author",
          "license"
        ],
        "additionalProperties": false,
        "properties": {
          "files": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "author": {
            "type": "string"
          },
          "license": {
            "type": "string"
          },
          "source": {
            "type": "string"
          },
          "note": {
            "type": "string"
          }
        },
        "patternProperties": {
          "^x-": {}
        }
      }
    },
    "signer": {
      "type": "object",
      "description": "Who signed the package. The claim is checked against signature.json; the browser shows the trusted name for a known key, never this claim alone.",
      "required": [
        "name",
        "key_id"
      ],
      "additionalProperties": false,
      "properties": {
        "name": {
          "type": "string",
          "maxLength": 80
        },
        "key_id": {
          "type": "string",
          "pattern": "^rsa:[0-9a-f]{32}$"
        }
      },
      "patternProperties": {
        "^x-": {}
      }
    },
    "reuse": {
      "type": "object",
      "description": "What OTHER builders may reuse from this world (docs/WORLD_FORMAT.md 5a). Default: nothing. allow: every object; objects: per-path overrides.",
      "additionalProperties": false,
      "patternProperties": {
        "^x-": {}
      },
      "properties": {
        "allow": {
          "type": "boolean"
        },
        "objects": {
          "type": "object",
          "maxProperties": 4096,
          "additionalProperties": {
            "type": "boolean"
          }
        }
      }
    },
    "reused": {
      "type": "array",
      "maxItems": 4096,
      "description": "Objects this world uses without carrying them: the browser finds them by hash on the visitor's machine (AssetLibrary).",
      "items": {
        "type": "object",
        "required": [
          "path",
          "sha256",
          "source",
          "license"
        ],
        "additionalProperties": false,
        "patternProperties": {
          "^x-": {}
        },
        "properties": {
          "path": {
            "$ref": "#/$defs/path",
            "description": "The package path scene.json uses for it (assets/<name>.glb)."
          },
          "sha256": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$"
          },
          "bytes": {
            "type": "integer",
            "minimum": 0
          },
          "license": {
            "type": "string",
            "maxLength": 200
          },
          "author": {
            "type": "string",
            "maxLength": 200
          },
          "source": {
            "type": "object",
            "required": [
              "world",
              "kind",
              "file"
            ],
            "additionalProperties": false,
            "patternProperties": {
              "^x-": {}
            },
            "properties": {
              "world": {
                "type": "string",
                "maxLength": 200
              },
              "kind": {
                "enum": [
                  "builtin",
                  "world"
                ]
              },
              "file": {
                "$ref": "#/$defs/path"
              },
              "version": {
                "type": "string",
                "maxLength": 64
              },
              "key_id": {
                "type": "string",
                "pattern": "^rsa:[0-9a-f]{32}$"
              }
            }
          }
        }
      }
    },
    "tiers": {
      "type": "object",
      "description": "hardware tiers (docs/WORLD_TIERS.md): medium/high/ultra, each with optional budgets; the package itself is the low tier; checked in detail by WorldTiers.validate"
    },
    "techniques": {
      "type": "object",
      "description": "Turn off any of the kit recipes the browser applies to every world by default (kit/recipes/techniques.json, kit: automatic), e.g. {\"instancing\": false}. Unlisted recipes stay on.",
      "additionalProperties": {
        "type": "boolean"
      }
    }
  },
  "$defs": {
    "id": {
      "type": "string",
      "pattern": "^[a-z0-9][a-z0-9_-]{0,63}$"
    },
    "path": {
      "type": "string",
      "pattern": "^(?!/)(?!.*\\.\\.)(?!.*//)[A-Za-z0-9_][A-Za-z0-9_./-]{0,199}$"
    },
    "vec3": {
      "type": "array",
      "items": {
        "type": "number"
      },
      "minItems": 3,
      "maxItems": 3
    },
    "feature": {
      "enum": [
        "sky",
        "fog",
        "sun",
        "terrain",
        "water",
        "weather",
        "objects",
        "primitives",
        "lights",
        "sounds",
        "portals",
        "triggers",
        "paths",
        "npcs",
        "creatures",
        "quests",
        "animation",
        "scripts"
      ]
    }
  }
}
