{
  "version": "0.1.0",
  "runtime": "Tissue Preview Runtime",
  "contextRules": [
    "ctx is Tissue Runtime Context passed into script lifecycle methods.",
    "ctx is not Phaser and must not be extended by guessing APIs.",
    "Only APIs listed in this manifest are supported.",
    "dt is seconds.",
    "Use this.elapsed += dt instead of ctx.now/time/clock.",
    "Use ctx.state for shared state between scripts."
  ],
  "ctx": {
    "self": { "kind": "property", "description": "Current editor GameObject data." },
    "gameObject": { "kind": "property", "description": "Current Phaser GameObject." },
    "project": { "kind": "property", "description": "Current project data." },
    "state": { "kind": "property", "description": "Shared scene state object." },
    "instantiatePrefab": {
      "signature": "ctx.instantiatePrefab(name: string, x: number, y: number): PrefabInstance",
      "returns": "PrefabInstance | undefined",
      "rules": ["Prefab name must exist.", "Use the returned handle for spawned instances.", "Do not move repeated prefab instances by hard-coded names."],
      "example": "const pipe = ctx.instantiatePrefab('PipePair', x, y); if (pipe) pipe.setPosition(x, y);"
    },
    "bounds": { "signature": "ctx.bounds(): Bounds", "returns": "Bounds", "rules": ["Returns current object display/collider bounds where available."] },
    "overlaps": { "signature": "ctx.overlaps(target: string | SceneObject): boolean", "returns": "boolean", "rules": ["Target must exist.", "Prefer ctx.collider APIs for collider-based gameplay."] }
  },
  "namespaces": {
    "transform": {
      "setPosition": { "signature": "ctx.transform.setPosition(x: number, y: number): void", "rules": ["Use world/editor coordinates."] },
      "setRotation": { "signature": "ctx.transform.setRotation(radians: number): void", "rules": ["Rotation is radians, not degrees."] },
      "setText": { "signature": "ctx.transform.setText(text: string): void", "rules": ["Current object should have text rendering capability."] }
    },
    "node": {
      "show": { "signature": "ctx.node.show(): void" },
      "hide": { "signature": "ctx.node.hide(): void" },
      "destroy": { "signature": "ctx.node.destroy(): void" }
    },
    "input": {
      "onPointerDown": { "signature": "ctx.input.onPointerDown(fn: Function): void", "rules": ["Scene/global pointer. Auto-cleaned on preview close."] },
      "onObjectPointerDown": { "signature": "ctx.input.onObjectPointerDown(fn: Function): void", "rules": ["Current object pointer. Auto-cleaned on preview close."] },
      "onKeyDown": { "signature": "ctx.input.onKeyDown(key: string, fn: Function): void", "rules": ["Use keys like 'SPACE'. Auto-cleaned on preview close."] }
    },
    "sceneObjects": {
      "setPositionByName": { "signature": "ctx.sceneObjects.setPositionByName(name: string, x: number, y: number): void", "rules": ["Target scene object must exist."] },
      "destroyByName": { "signature": "ctx.sceneObjects.destroyByName(name: string): void", "rules": ["Target scene object must exist."] },
      "setTextByName": { "signature": "ctx.sceneObjects.setTextByName(name: string, text: string): void", "rules": ["Target scene object must exist and should be text-like."] },
      "showByName": { "signature": "ctx.sceneObjects.showByName(name: string): void", "rules": ["Target scene object must exist."] },
      "hideByName": { "signature": "ctx.sceneObjects.hideByName(name: string): void", "rules": ["Target scene object must exist."] }
    },
    "collider": {
      "bounds": { "signature": "ctx.collider.bounds(): Bounds", "returns": "Bounds", "rules": ["Current object must have Collider."] },
      "overlaps": { "signature": "ctx.collider.overlaps(target: string | SceneObject): boolean", "returns": "boolean", "rules": ["Current object must have Collider.", "Target must exist and should have Collider.", "Not recommended for many repeated prefab instances."] },
      "overlapsAll": { "signature": "ctx.collider.overlapsAll(names: string[]): SceneObject[]", "returns": "SceneObject[]", "rules": ["Every name must exist.", "Returns an array; check .length > 0.", "Use for a small fixed list of targets."] },
      "overlapsGroup": { "signature": "ctx.collider.overlapsGroup(tag: string): SceneObject[]", "returns": "SceneObject[]", "rules": ["At least one scene object or prefab child must have the tag.", "Returns an array; check .length > 0.", "Do not use the returned array as a boolean directly.", "Prefer for repeated prefab collisions such as pipes/enemies/bullets."], "example": "if (ctx.collider.overlapsGroup('pipe').length > 0) { ctx.state.dead = true; }" }
    },
    "lifecycle": {
      "addCleanup": { "signature": "ctx.lifecycle.addCleanup(fn: Function): void", "rules": ["Use for manual event cleanup when needed."] }
    }
  },
  "legacyApiAliases": ["hide", "show", "destroy", "setPosition", "setRotation", "setText", "onPointerDown", "onObjectPointerDown", "onKeyDown", "bounds", "overlaps", "instantiatePrefab", "setPositionByName", "destroyByName", "setTextByName", "showByName", "hideByName"],
  "forbidden": {
    "ctx": ["now", "time", "clock", "onPointerDown"],
    "notes": ["There is no ctx.now/ctx.time/ctx.clock. Use update(ctx, dt) and accumulate elapsed time on this or ctx.state.", "Never call ctx.onPointerDown; use onPointerDown(ctx) lifecycle or ctx.input.onPointerDown(fn)."]
  }
}
