iframe Embedding in milaidy
LTCG is embedded as an iframe within the milaidy Electron app.
Architecture
code
milaidy (Electron)
├── Main Process
│ └── BrowserWindow
└── Renderer Process
└── <iframe src="https://lunchtable.app/play" />
└── LTCG Game Client (React Router 7)
Embedding Approach
Game Client Side
The LTCG frontend must:
- •Detect iframe context:
window.self !== window.top - •Adapt UI for embedded mode (no header/nav, fullscreen game)
- •Communicate with parent via
postMessage - •Handle wallet connection from parent app
iframe Detection Hook
typescript
function useIframeMode() {
const isEmbedded = typeof window !== "undefined" && window.self !== window.top;
return { isEmbedded };
}
Route for Embedded Mode
code
/embed/play # Embedded game view (no chrome) /embed/stream/:id # Embedded stream viewer /embed/spectate/:id # Embedded spectator view
PostMessage Protocol
typescript
// Game -> Parent (milaidy)
type GameToParent =
| { type: "GAME_READY" }
| { type: "MATCH_STARTED"; matchId: string }
| { type: "MATCH_ENDED"; result: "win" | "loss" | "draw" }
| { type: "REQUEST_WALLET" }
| { type: "GAME_STATE"; state: PlayerView };
// Parent -> Game
type ParentToGame =
| { type: "WALLET_CONNECTED"; address: string; chain: string }
| { type: "USER_AUTH"; token: string }
| { type: "START_MATCH"; mode: "story" | "pvp" }
| { type: "THEME_OVERRIDE"; theme: Record<string, string> };
Security
- •Validate
event.originon all message handlers - •Never trust data from parent without validation
- •Use CSP headers to restrict embedding sources
typescript
window.addEventListener("message", (event) => {
// Validate origin
const allowedOrigins = ["electron://milaidy", "https://milaidy.app"];
if (!allowedOrigins.includes(event.origin)) return;
// Handle message
switch (event.data.type) {
case "WALLET_CONNECTED":
handleWalletConnection(event.data);
break;
}
});
Stream Embedding
retake.tv streams are embedded via iframe within the game client:
tsx
function StreamViewer({ streamId }: { streamId: string }) {
return (
<iframe
src={`https://retake.tv/embed/${streamId}`}
className="w-full aspect-video border-0"
allow="autoplay; fullscreen"
/>
);
}
Responsive Considerations
- •Game board must work at various iframe sizes
- •Minimum width: 320px (mobile)
- •Target: 800x600 for desktop embedding
- •Use
ResizeObserveror container queries for adaptive layouts