📌 Game Pinning Architecture

A comprehensive cheat-sheet on how Funday’s persistent “Game Tabs” and global mounting architecture handles both iFrames and Native Svelte components to provide a glitch-free, persistent, zero-duplication experience.

✨ Core Principles

🎮 Unified Viewport Pool All games—whether nested completely in an iFrame or imported dynamically as a Native Svelte chunk—are mounted globally in the root layout’s ViewportPool. This ensures zero unmounting upon navigation.

🚀 Ephemeral GameViewport The <GameViewport> component is not responsible for loading or mounting any games anymore! It functions strictly as a message router and a skeletal CSS boundary. The actual game overlaps it from the overarching ViewportPool.

🏛️ The Stack & Flow

1. openGamesStore.svelte.ts (The Source of Truth)

Holds the canonical state for all active and pinned games.

  • poolGames (derived): Returns all active games that the global pool needs to keep alive in the background (native & iframe combined).
  • Pinning: Flips the isPinned flag safely. No more arbitrary exclusions against svelte-component.

2. ViewportPool.svelte (The Global Host)

Lives at the root layout level, rendering elements statically in absolute/pointer-events-none mode so they hover globally over the app.

  • IFrames: <iframe src="..."> bounds are preserved natively.
  • Native Svelte: Spans the <NativeGameHost> internally via an {#if} block matching the integrationType.

3. NativeGameHost.svelte (Native Session Wrapper)

Provides the lifecycle container for Native games like Battleships.

  • Imports the chunk from game.entryPoint.
  • Ingests the user session and handles deep prop-drilling into the dynamically loaded chunk.
  • Directly subscribes to nativeMessageBus and publishes to hostMessageBus.

4. nativeBridge.ts (The Decoupler)

Eliminated local variables bindings!

  • nativeMessageBus: Platform -> Native Game
  • hostMessageBus: Native Game -> Platform Allows ephemeral GameViewports to drop in/out of the DOM but instantly reconnect their inputs/outputs to the globally pinned native components.

🛠️ Communication Bridges

IFrames: Utilize the exact same postMessage Bridge (createHostBridge). The listener connects dynamically when the ephemeral GameViewport appears inside the page route by targeting the pre-existing iframe in the pool.

Native Mounts: Utilize nativeMessageBus to push actions from the Platform (like chat messages or vote executions) to the persistently mounted NativeGameHost, which then trickles the update into the isolated game component.

🔧 Extending the Architecture

If you want to add a new integration type or heavily rely on a local engine (e.g. Phaser purely embedded natively):

  1. Never manually mount it in GameViewport.
  2. Add a conditional block for the new integration inside ViewportPool.
  3. Scaffold a wrapper similar to NativeGameHost to control the specific engine’s memory cleanup on full termination.
  4. Bridge the input/outputs to the global native bus logic.

Ask Docs

AI assistant to help answer questions about the documentation. Answers are read-only and cite docs/source.

Hi! How can I help you with the documentation today? Answers are read-only and cite docs/source.

Ctrl+Enter to send