Play a Microsoft MakeCode Arcade game side-by-side with your Copilot Studio agent, embedded in Microsoft 365 Copilot.
Status: π§ͺ design only β no code yet. Sister project of MCSMCPapps, which provides the launcher pattern this project reuses.
Inside the M365 Copilot pane, half the screen is a playable game; the other half is a chat with a Copilot Studio agent that plays the game with you β as opponent, coach, narrator, or commentator.
- Demonstrates the side-by-side widget capability of the MCP UI Apps pattern with a high-WOW use case.
- Shows event-driven coordination between a real-time UI and a CS topic β every move is an event activity.
- Exposes the limits gracefully β turn-based games work great; real-time twitch games stretch the architecture; perfect for showing "why this pattern, not Bot Framework Web Chat."
- Educational: makers see a concrete pattern for any UI that has state (a calculator, a CAD viewer, a Kanban board) by following the game-state mental model.
M365 Copilot pane
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Declarative Agent (manifest only) β
β ββ openArcadeVsAgent β MCP server returns UI widget β
β β
β Widget renderer host (Microsoft-managed iframe sandbox) β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
β β Static Web App (Azure) β β
β β ββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββ β β
β β β MakeCode Arcade game β Chat with Copilot Studio agent β β β
β β β (iframe at β (this side reuses MCSMCPapps β β β
β β β arcade.makecode.com) β WebChat β auth, transport, β β β
β β β β rendering) β β β
β β β postMessage bridge ββββββΌβββββΊ event activities to/from β β β
β β β β CS via Direct Engine β β β
β β ββββββββββββββββββββββββββββ΄ββββββββββββββββββββββββββββββββββ β β
β ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
The key insight: MakeCode Arcade games can be embedded as an iframe and they expose a postMessage API. We use that to forward player actions to CS as event activities, and apply CS's responses back into the game.
| Game | Player control | CS role | Pace | Feasibility |
|---|---|---|---|---|
| Tic-tac-toe | Click cell | Pick best move; trash-talk | Turn-based, untimed | β trivial β perfect for v1 |
| Connect-4 | Click column | Solve 1-2 turns ahead | Turn-based | β easy |
| Hangman / Wordle-like | Type letter | Pick word; give hints | Turn-based | β easy; mostly text |
| Battleship | Click grid | Track shots, fire back | Turn-based | β³ medium |
| Snake (compete) | Arrows | Drive a second snake | 5β10 fps | β³ medium β CS latency matters |
| Pong | Mouse / arrows | Move CPU paddle | 30 fps | |
| Platformer co-op | Arrows | Control another character | 30+ fps | β won't work in v1 |
| Quiz/trivia | Pick answer | Generate questions; score | Untimed | β trivial |
| Text adventure | Type | Narrate, decide outcomes | Untimed | β trivial |
| Werewolf / social-deduction | Pick role | Play multiple characters | Turn-based | β³ medium |
v1 recommendation: tic-tac-toe. Smallest possible thing that demonstrates the loop. Ship that, then escalate.
| Event name | When | Payload |
|---|---|---|
game.start |
Player presses Start | { gameId, mode, difficulty } |
game.playerMove |
Player makes a move | { moveId, type, position, gameStateHash } |
game.stateUpdate |
Game state changes (score, lives, level) | { score, lives, level, ... } |
game.over |
Game ends | { winner, finalScore, durationSec } |
game.requestHint |
Player asks for help | { context } |
| Event name | When | Payload |
|---|---|---|
game.agentMove |
Topic decides on a move | { moveId, type, position, comment } |
game.commentary |
Bot comments on the action | { text, mood: 'happy' | 'tense' | 'taunt' } |
game.adjustDifficulty |
Bot detects player frustration | { newDifficulty } |
game.injectPowerUp |
Topic's narrative decision | { powerUpId, position } |
game.endNow |
Force end (timeout, rage quit handling) | { reason } |
The game treats game.agentMove as the agent's input β same as the player pressing a key.
| Topic | Trigger | Behavior |
|---|---|---|
| OnStart | game.start event |
Greet the player; ask for difficulty if not set; remember gameId. |
| PlayMove | game.playerMove event |
Compute opponent's response (LLM-driven for trash-talk; algorithmic for the actual move). Emit game.agentMove. |
| Commentate | game.stateUpdate event |
Optional β emit game.commentary with personality. |
| CelebrateOrConsole | game.over event |
Personalized end-of-game line. Offer rematch (suggested-action button). |
| Hint | game.requestHint event |
Generate a hint based on current state. |
MakeCode Arcade games can be loaded by URL like https://arcade.makecode.com/--run?id=<game-id>. They run in an iframe and post messages to the parent.
Pros: zero game development; pick from thousands of existing games; visual is fun. Cons: the postMessage API is documented but limited; we're at the mercy of what MakeCode exposes; mostly outbound (game tells parent what happened) rather than inbound (parent telling game what to do).
Verdict: good for observation-only integrations (CS narrates), tough for bidirectional (CS plays back).
Use the MakeCode Arcade editor to design the visual, but export the JS and run it inside our own iframe with a custom event bus. Lets us inject moves freely.
Pros: game looks great; full control of communication. Cons: moderate engineering; need to maintain the runtime as MakeCode evolves.
Verdict: good middle ground for v2.
Plain canvas / DOM / Phaser game with our own renderer.
Pros: total control; perfect bidirectional comms. Cons: doesn't really showcase MakeCode anymore; loses the "kid-built games + adult-built AI" charm.
Verdict: only if MakeCode integration becomes a wall.
v1 plan: Option A β pick a tic-tac-toe MakeCode share ID, observe what postMessage events it emits, see if the CS-driven move can be injected via simulated input or a forked runtime.
Same as MCSMCPapps:
- MCP server: anonymous in dev
- Widget: SWA hosted on Azure
- Chat side: Entra SSO via MSAL silent for the user
- Topic talks Direct Engine via the M365 Agents SDK
The game iframe doesn't need its own auth β it inherits the parent's MSAL token if it ever needs to call something authenticated.
- Demoability for non-developers. A maker can clone a tic-tac-toe MakeCode project, edit it visually in 10 minutes, and the agent works against their custom version unchanged.
- Microsoft alignment. Showcases two Microsoft platforms cooperating (MakeCode + Copilot Studio + M365 Copilot).
- Education angle. Easy to extend into "kids design a game; AI plays it as opponent" β strong story.
- Variety. Hundreds of game genres pre-built; no need to recreate them.
ArcadeVsAgent/
βββ docs/
β βββ ARCHITECTURE.md (the diagram + flow above, expanded)
β βββ EVENT-CONTRACT.md (full event schemas for CS β game)
β βββ MAKECODE-INTEGRATION.md (postMessage probe results, runtime fork plan)
β βββ DEMO-SCRIPT.md (10-min demo flow when shipped)
βββ game/ (the game iframe β Option A or B)
β βββ src/
β βββ public/index.html
β βββ package.json
βββ mcp-server/ (single tool: openArcadeVsAgent)
β βββ (mirrors MCSMCPapps shape)
βββ declarative-agent/ (DA manifest + Agents Toolkit project)
β βββ (mirrors MCSMCPapps shape)
βββ infra/
β βββ main.bicep (SWA + App Service)
βββ README.md (this file)
βββ LICENSE
βββ SECURITY.md
| Phase | Deliverable |
|---|---|
| 0 | Probe MakeCode Arcade postMessage API; pick game; document what's possible |
| 1 | Static side-by-side iframe layout; placeholder game; fake events |
| 2 | Real CS topic that plays tic-tac-toe; full event round-trip |
| 3 | Personality / commentary layer; suggested-action rematch button |
| 4 | Difficulty adaptation based on player win-rate |
| 5 | Add a second game; refactor to a Game interface |
| 6 | (stretch) Voice commentary via browser TTS |
| 7 | (stretch) Multiplayer: two M365 users + agent referee |
- The MCP-server-backed UI widget pattern (verbatim)
- The Static Web App + Azure App Service infra
- The Entra SSO + Power Platform API auth flow
- The M365 Agents Toolkit DA scaffolding
- The CSP allowlist for the widget renderer host
- The Wave-2 SDK transport (
@microsoft/agents-copilotstudio-client)
- The widget HTML is a 2-pane layout instead of a single chat
- The game iframe needs its own postMessage protocol bridged to CS events
- CS topic logic models a state machine for the game, not just a Q&A
- The chat side can be smaller (sidebar) since the game takes most of the visual
- Can MakeCode Arcade games receive synthetic input via postMessage? (need to probe)
- What's the right primitive on the CS side for fast turn-by-turn play β a topic or a Power Automate flow? (latency probably matters)
- How do we handle network blips during a real-time game?
- Do we persist game state across sessions? (probably yes β scoreboard / streak idea)
- Does the agent ever take initiative (start a game) or only respond? (initiative would require proactive β out of scope)
- Microsoft MakeCode Arcade
- MakeCode embed/iframe API
- Sister project: MCSMCPapps β the launcher pattern
- MCS Wave-2 + UI widgets reference