[
  {
    "bnoUsage": "heavy",
    "cite": "rendering.md#sprite-rendering",
    "feature": "Sprite rendering with origin point + bounding box + collision mask (GM `sprite_index`/`mask_index`/`originX`/`originY`/`bbox*`)",
    "rowId": "MX-RENDER-01",
    "scores": {
      "phaser-3.90": {
        "grade": "native",
        "note": "Phaser.GameObjects.Sprite supports setOrigin / setBoundingBox; Body matches mask via Arcade or Matter physics."
      },
      "phaser-4.1": {
        "grade": "native",
        "note": "Same Sprite/Origin API as v3 per migration guide; rendering pipeline rewritten but GameObjects.Sprite contract is compatible."
      },
      "pixi-8.18": {
        "grade": "manual",
        "note": "Pixi.Sprite has anchor (~origin); collision mask requires manual integration (no built-in physics)."
      }
    },
    "subsystem": "rendering",
    "weight": 5
  },
  {
    "bnoUsage": "heavy",
    "cite": "rendering.md#tile-backgrounds",
    "feature": "Tile-background drawing with offset/separation (GM background-as-tileset; rooms use tiles)",
    "rowId": "MX-RENDER-02",
    "scores": {
      "phaser-3.90": {
        "grade": "native",
        "note": "Phaser.Tilemaps supports tile margins/spacing; staticTilemapLayer is the direct GM-tile equivalent."
      },
      "phaser-4.1": {
        "grade": "native",
        "note": "Tilemap API preserved; rendering path improved per migration guide."
      },
      "pixi-8.18": {
        "grade": "plugin",
        "note": "@pixi/tilemap@5.0.2 ships first-class tilemap rendering; not core Pixi but well-maintained."
      }
    },
    "subsystem": "rendering",
    "weight": 4
  },
  {
    "bnoUsage": "heavy",
    "cite": "rendering.md#depth-ordering",
    "feature": "Per-instance integer depth ordering (GM `depth` int32; lower draws on top)",
    "rowId": "MX-RENDER-03",
    "scores": {
      "phaser-3.90": {
        "grade": "native",
        "note": "GameObject.setDepth(n) is a direct API match; Phaser sorts the display list by depth."
      },
      "phaser-4.1": {
        "grade": "native",
        "note": "setDepth API preserved."
      },
      "pixi-8.18": {
        "grade": "manual",
        "note": "Pixi children render in array order; integer depth requires manual zIndex + sortableChildren or a custom container layer."
      }
    },
    "subsystem": "rendering",
    "weight": 4
  },
  {
    "bnoUsage": "heavy",
    "cite": "rendering.md#draw-set-font",
    "feature": "Custom-font text rendering (GM `draw_set_font` + `draw_text`; resolved action 523/525 — OCRA + Fixedsys)",
    "rowId": "MX-RENDER-04",
    "scores": {
      "phaser-3.90": {
        "grade": "native",
        "note": "BitmapText (sprite-strip) + Phaser.GameObjects.Text both supported; AST-03 produces BitmapText atlases for OCRA/Fixedsys."
      },
      "phaser-4.1": {
        "grade": "native",
        "note": "BitmapText/Text APIs preserved."
      },
      "pixi-8.18": {
        "grade": "native",
        "note": "Pixi.BitmapText + Pixi.Text both supported; @pixi/text-bitmap is core in Pixi 8."
      }
    },
    "subsystem": "rendering",
    "weight": 4
  },
  {
    "bnoUsage": "light",
    "cite": "rendering.md#draw-sprite-ext",
    "feature": "Color tinting + blend modes (GM `draw_sprite_ext` blend / alpha args)",
    "rowId": "MX-RENDER-05",
    "scores": {
      "phaser-3.90": {
        "grade": "native",
        "note": "GameObject.setTint + setBlendMode (NORMAL/ADD/SCREEN/MULTIPLY etc.) cover GM's standard blend set."
      },
      "phaser-4.1": {
        "grade": "native",
        "note": "Tint + blend modes preserved."
      },
      "pixi-8.18": {
        "grade": "native",
        "note": "Pixi.Sprite.tint + blendMode are first-class; broader blend mode coverage than GM's set."
      }
    },
    "subsystem": "rendering",
    "weight": 3
  },
  {
    "bnoUsage": "light",
    "cite": "rendering.md#surfaces",
    "feature": "Surface / render-texture (GM `surface_create`/`surface_set_target`)",
    "rowId": "MX-RENDER-06",
    "scores": {
      "phaser-3.90": {
        "grade": "native",
        "note": "Phaser.GameObjects.RenderTexture maps directly; verify usage frequency in BNO before deciding whether worth weight bump."
      },
      "phaser-4.1": {
        "grade": "native",
        "note": "RenderTexture preserved with improved batching per migration guide."
      },
      "pixi-8.18": {
        "grade": "native",
        "note": "Pixi.RenderTexture is core; arguably cleaner than Phaser's wrapper."
      }
    },
    "subsystem": "rendering",
    "weight": 2
  },
  {
    "bnoUsage": "heavy",
    "cite": "input.md#keyboard-events",
    "feature": "Per-key keyboard event handling (GM Keyboard-N events on object 0042-player)",
    "rowId": "MX-INPUT-01",
    "scores": {
      "phaser-3.90": {
        "grade": "native",
        "note": "Phaser.Input.Keyboard.on('keydown-W' etc.) + addKey().isDown polling cover both GM idioms."
      },
      "phaser-4.1": {
        "grade": "native",
        "note": "Keyboard input API preserved."
      },
      "pixi-8.18": {
        "grade": "manual",
        "note": "Pixi has no input layer; wire to DOM keydown/keyup directly or pull a small input lib (e.g. ipixi-input)."
      }
    },
    "subsystem": "input",
    "weight": 5
  },
  {
    "bnoUsage": "heavy",
    "cite": "input.md#key-pressed-vs-held-vs-released",
    "feature": "Key-press vs key-held vs key-release distinction (GM KeyPress-N / Keyboard-N / KeyRelease-N)",
    "rowId": "MX-INPUT-02",
    "scores": {
      "phaser-3.90": {
        "grade": "native",
        "note": "Phaser.Input.Keyboard.JustDown() / isDown / JustUp() helpers map 1:1 to GM's three event categories."
      },
      "phaser-4.1": {
        "grade": "native",
        "note": "JustDown/JustUp helpers preserved."
      },
      "pixi-8.18": {
        "grade": "manual",
        "note": "DOM keydown auto-repeats by default; one-shot \"just-pressed\" detection requires manual repeat-suppression bookkeeping."
      }
    },
    "subsystem": "input",
    "weight": 4
  },
  {
    "bnoUsage": "light",
    "cite": "input.md#mouse",
    "feature": "Mouse input (verify usage; some menus may rely on click)",
    "rowId": "MX-INPUT-03",
    "scores": {
      "phaser-3.90": {
        "grade": "native",
        "note": "Phaser.Input.Pointer + interactive objects cover hit-testing on canvas-rendered UI."
      },
      "phaser-4.1": {
        "grade": "native",
        "note": "Pointer input API preserved."
      },
      "pixi-8.18": {
        "grade": "native",
        "note": "Pixi 8 InteractionManager (eventMode='static') matches Phaser-level hit-testing."
      }
    },
    "subsystem": "input",
    "weight": 2
  },
  {
    "bnoUsage": "heavy",
    "cite": "collision.md#per-object-collision-events",
    "feature": "Per-object Collision events with target object filter (movement vs walls)",
    "rowId": "MX-COLLIDE-01",
    "scores": {
      "phaser-3.90": {
        "grade": "native",
        "note": "Phaser.Physics.Arcade.collider(spriteA, spriteB, callback) is a 1:1 GM Collision-event analog."
      },
      "phaser-4.1": {
        "grade": "native",
        "note": "Arcade physics preserved with API additions."
      },
      "pixi-8.18": {
        "grade": "manual",
        "note": "Pixi has no physics layer; would require manual bbox checks per frame or pull matter.js + glue code."
      }
    },
    "subsystem": "collision",
    "weight": 5
  },
  {
    "bnoUsage": "heavy",
    "cite": "collision.md#runtime-queries",
    "feature": "`collision_rectangle` / `collision_line` / `place_meeting` runtime queries",
    "rowId": "MX-COLLIDE-02",
    "scores": {
      "phaser-3.90": {
        "grade": "native",
        "note": "Phaser.Physics.Arcade.overlap (one-shot) + Phaser.Geom.Intersects helpers cover the GM collision-query trio."
      },
      "phaser-4.1": {
        "grade": "native",
        "note": "Arcade overlap + Geom helpers preserved."
      },
      "pixi-8.18": {
        "grade": "manual",
        "note": "Hand-rolled rectangle/line intersection or pull a third-party 2D collision lib."
      }
    },
    "subsystem": "collision",
    "weight": 4
  },
  {
    "bnoUsage": "light",
    "cite": "collision.md#precise-masks",
    "feature": "Precise per-pixel collision masks (sprite `precise: true`)",
    "rowId": "MX-COLLIDE-03",
    "scores": {
      "phaser-3.90": {
        "grade": "plugin",
        "note": "Arcade physics is AABB; pixel-precise needs `phaser-pixel-perfect-collision` plugin OR custom mask integration. Verify BNO usage frequency before bumping weight."
      },
      "phaser-4.1": {
        "grade": "plugin",
        "note": "Same plugin landscape as v3 (rendering rewrite did not change physics layers)."
      },
      "pixi-8.18": {
        "grade": "manual",
        "note": "Pixi has no built-in collision; pixel-perfect masks require manual texture-pixel sampling."
      }
    },
    "subsystem": "collision",
    "weight": 2
  },
  {
    "bnoUsage": "heavy",
    "cite": "animation.md#image-speed-and-frames",
    "feature": "Animated sprite frames with per-frame `image_speed` interpolation",
    "rowId": "MX-ANIM-01",
    "scores": {
      "phaser-3.90": {
        "grade": "native",
        "note": "Phaser.Animations.AnimationManager + Sprite.anims.play() cover frame-stepping with frameRate."
      },
      "phaser-4.1": {
        "grade": "native",
        "note": "Animations preserved."
      },
      "pixi-8.18": {
        "grade": "native",
        "note": "Pixi.AnimatedSprite covers frame stepping; arguably simpler API than Phaser's Animations."
      }
    },
    "subsystem": "animation",
    "weight": 4
  },
  {
    "bnoUsage": "heavy",
    "cite": "animation.md#sprite-swap",
    "feature": "Sprite-swap animation (`sprite_index = X` mid-flight) — Hexport state machine on player",
    "rowId": "MX-ANIM-02",
    "scores": {
      "phaser-3.90": {
        "grade": "native",
        "note": "Sprite.setTexture(key) swaps texture without recreating the GameObject; matches GM idiom."
      },
      "phaser-4.1": {
        "grade": "native",
        "note": "setTexture preserved."
      },
      "pixi-8.18": {
        "grade": "native",
        "note": "Pixi.Sprite.texture = newTexture is the same idiom; simpler than Phaser's anim manager."
      }
    },
    "subsystem": "animation",
    "weight": 4
  },
  {
    "bnoUsage": "heavy",
    "cite": "scene-room-model.md#room-model",
    "feature": "Room model with size, view, view-port, view-following (16 rooms catalogued)",
    "rowId": "MX-SCENE-01",
    "scores": {
      "phaser-3.90": {
        "grade": "native",
        "note": "Phaser.Scene + cameras.main.startFollow(target) is a near-1:1 GM Room+View analog."
      },
      "phaser-4.1": {
        "grade": "native",
        "note": "Scene + Camera APIs preserved."
      },
      "pixi-8.18": {
        "grade": "manual",
        "note": "Pixi has no Scene/Room model; build a Container hierarchy + manual camera math + custom scene loader."
      }
    },
    "subsystem": "scene-room-model",
    "weight": 5
  },
  {
    "bnoUsage": "heavy",
    "cite": "scene-room-model.md#room-transitions",
    "feature": "Room transitions (`room_goto` / `room_restart` / `room_next` / `room_previous`)",
    "rowId": "MX-SCENE-02",
    "scores": {
      "phaser-3.90": {
        "grade": "native",
        "note": "scene.start(key) / scene.restart() / SceneManager.add+start cover the GM room-goto vocabulary 1:1."
      },
      "phaser-4.1": {
        "grade": "native",
        "note": "Scene transitions preserved."
      },
      "pixi-8.18": {
        "grade": "manual",
        "note": "Build a SceneManager wrapper to swap Containers + reset state; not built-in."
      }
    },
    "subsystem": "scene-room-model",
    "weight": 4
  },
  {
    "bnoUsage": "light",
    "cite": "scene-room-model.md#creation-code",
    "feature": "Per-room creation code + per-instance creation code",
    "rowId": "MX-SCENE-03",
    "scores": {
      "phaser-3.90": {
        "grade": "native",
        "note": "Scene.create() + per-GameObject onCreate hooks via factory methods cover both GM creation-code slots."
      },
      "phaser-4.1": {
        "grade": "native",
        "note": "Scene lifecycle preserved."
      },
      "pixi-8.18": {
        "grade": "manual",
        "note": "Application + Container init patterns work but are convention, not framework."
      }
    },
    "subsystem": "scene-room-model",
    "weight": 3
  },
  {
    "bnoUsage": "none",
    "cite": "audio.md#no-embedded-audio",
    "feature": "WAV / MIDI / MP3 playback (NO embedded audio in client-5-8 per Plan 02-05 finding)",
    "rowId": "MX-AUDIO-01",
    "scores": {
      "phaser-3.90": {
        "grade": "native",
        "note": "Phaser.Sound.WebAudio supports WAV/OGG/MP3 natively; MIDI needs AST-02 conversion to OGG (Phase 7)."
      },
      "phaser-4.1": {
        "grade": "native",
        "note": "Sound API preserved."
      },
      "pixi-8.18": {
        "grade": "plugin",
        "note": "Pixi has no audio layer; pair with howler@2.2.4 (STACK.md fallback) for native browser audio."
      }
    },
    "subsystem": "audio",
    "weight": 1
  },
  {
    "bnoUsage": "light",
    "cite": "save-load.md#client-side-save",
    "feature": "Client-side state save/load (Settings.bno via file_text_*; server saves are Phase 3)",
    "rowId": "MX-SAVE-01",
    "scores": {
      "phaser-3.90": {
        "grade": "native",
        "note": "Engine-agnostic — localStorage / IndexedDB are browser APIs; both engines run on the same browser host."
      },
      "phaser-4.1": {
        "grade": "native",
        "note": "Engine-agnostic; same as v3."
      },
      "pixi-8.18": {
        "grade": "native",
        "note": "Engine-agnostic; same browser persistence APIs."
      }
    },
    "subsystem": "save-load",
    "weight": 1
  },
  {
    "bnoUsage": "heavy",
    "cite": "ui-and-menus.md#dom-overlay-vs-canvas",
    "feature": "DOM-overlay UI vs canvas UI compatibility (chat HUD, Main_Menu, Online_Lobby, Settings_Menu, Online_Command_Screen)",
    "rowId": "MX-UI-01",
    "scores": {
      "phaser-3.90": {
        "grade": "native",
        "note": "Phaser.GameObjects.DOMElement + parent canvas in same DOM container; chat HUD as a textarea overlay is the documented pattern."
      },
      "phaser-4.1": {
        "grade": "native",
        "note": "DOMElement preserved per migration guide."
      },
      "pixi-8.18": {
        "grade": "native",
        "note": "Pixi runs on a canvas in the DOM; HTML/CSS chat HUD overlay is identical to Phaser's setup. Canvas-rendered UI uses Pixi.Text + interactive Containers."
      }
    },
    "subsystem": "ui-and-menus",
    "weight": 4
  },
  {
    "bnoUsage": "heavy",
    "cite": "client-networking.md#39dll-wrapper",
    "feature": "WebSocket client integration (Phase 6 uses Colyseus client; engine-agnostic)",
    "rowId": "MX-NET-01",
    "scores": {
      "phaser-3.90": {
        "grade": "native",
        "note": "Engine-agnostic — Colyseus.js client runs on bare browser WebSocket; both engines integrate identically."
      },
      "phaser-4.1": {
        "grade": "native",
        "note": "Engine-agnostic; same."
      },
      "pixi-8.18": {
        "grade": "native",
        "note": "Engine-agnostic; same."
      }
    },
    "subsystem": "client-networking",
    "weight": 2
  }
]
