/** * BrowserClient - Main orchestrator for browser-based IF games * * Wires together all managers (save, theme, dialog, menu, input, display) * and provides a simple API for story entry points. */ import type { GameEngine } from '@sharpee/engine'; import type { WorldModel } from '@sharpee/world-model'; import type { ISaveRestoreHooks } from '@sharpee/core'; import type { ClientCapabilities } from '@sharpee/if-domain'; import { type IRenderer } from '@sharpee/channel-service'; import type { BrowserClientConfig, BrowserClientInterface, DOMElements } from './types'; import { AudioManager } from './audio/AudioManager'; /** * Default `ClientCapabilities` profile for the browser surface — full * graphical capabilities so every standard + media channel appears in * the per-client manifest. Authors override per `BrowserClientConfig. * clientCapabilities` for specialized surfaces (text-only kiosks, etc.). */ export declare const BROWSER_CAPABILITIES: ClientCapabilities; export declare class BrowserClient implements BrowserClientInterface { private config; private themeManager; private saveManager; private dialogManager; private menuManager; private inputManager; private textDisplay; private statusLine; private audioManager; private engine; private world; private currentTurn; private currentScore; private turnOffset; /** * The `ISaveData` produced by the engine for the in-flight save * request. Set by `onSaveRequested` while the save dialog is open; * cleared in the hook's `finally`. Reused by `performSave` so the * persisted blob matches what the engine actually serialized for * this request, not whatever the world looked like by the time the * dialog returned. */ private pendingEngineSave; private elements; /** * ADR-165 channel renderer host. Constructed in `connectEngine()` * to drive the visible DOM via channel:manifest / channel:packet * (R5-C — primary rendering path). */ private channelRenderer?; private channelLayout?; constructor(config: BrowserClientConfig); /** * Initialize the browser client with DOM elements. * Call after DOMContentLoaded. */ initialize(elements: DOMElements): void; /** * Connect to game engine and set up event handlers. * Call after creating the engine. */ connectEngine(engine: GameEngine, world: WorldModel): void; /** * Append a platform-signal message to the main slot. Mirrors the * `mainChannelRenderer`'s DOM shape (`

` with * `pre-line` whitespace) plus a `system-message` class for theme * styling. Used for save/restore feedback strings that aren't * routed through the engine's text-service block production. * * Falls back to no-op if the channel layout hasn't been initialized * (engine not yet started). */ private appendSystemMessage; /** * Build the ADR-165 channel renderer wired to the host page's * existing DOM elements (R5-C cutover). * * The host page provides three slots directly (`textContent`, * `statusLocation`, `statusScore`, `commandInput`). The remaining * slots needed by the platform-default renderers (notify, media, * meta, separate prompt label, separate turn element) are mounted * as hidden children of the existing main window. * * Score / turn override: the host page typically has a single * combined `Score: X | Turns: Y` element. After * `registerDefaultBrowserRenderers` we replace the platform-default * `score` and `turn` renderers with composites that update the * combined element. Stories that supply two separate elements get * the platform default by overriding back. * * Hotspot commands route through `engine.executeTurn` so UI * gestures synthesize typed-equivalent commands per ADR-163 §10. * * Auto-save migrates here from the legacy `text:output` listener: * `channel:packet` fires on every turn boundary (including idle * turns), so this is the single dependable signal. */ private setupChannelRenderer; /** * Build a `BrowserDefaultLayout` from the existing host elements, * synthesizing hidden children for slots the host page doesn't * provide. Lets the platform-default renderers run against the * same DOM the legacy path used. */ private adaptHostLayout; /** * True when channel-debug logging is enabled. Three opt-in paths * (any one is sufficient): * 1. `BrowserClientConfig.debugChannels: true` * 2. URL query string `?debug-channels=1` (or any truthy value) * 3. `localStorage['sharpee-debug-channels']` set to a truthy value * * Lets authors flip on/off without rebuilding — useful when * inspecting an installed bundle's per-turn channel emissions. */ private shouldDebugChannels; /** * Render the combined `Score: X | Turns: Y` string into the host * page's combined status element. The host's traditional layout * uses one element; the score and turn channel renderers feed this * function rather than writing directly. */ private renderCombinedStatus; /** * Start the game (check for autosave, show initial look) */ start(): Promise; /** * Execute a command */ executeCommand(command: string): Promise; /** * Get ISaveRestoreHooks for engine registration */ getSaveRestoreHooks(): ISaveRestoreHooks; private handleSave; private handleRestore; /** * Show the restore dialog, load the envelope, apply the engine save, * and update browser-side UI. Returns true on success, false if the * user cancelled or no save was found. Used by both the menu path * and the engine-event hook path so they share identical timing. * * The order is deliberate: the engine save is applied to the world * BEFORE any UI update so that {@link updateStatusLine} (which reads * the player's containing room from the world) sees the post-restore * state. */ private runRestoreDialog; private handleRestart; private handleQuit; displayText(text: string): void; displayCommand(command: string): void; clearScreen(): void; getWorld(): WorldModel; getCurrentTurn(): number; getCurrentScore(): number; /** * The ADR-165 channel renderer this client drives. Stories register * additional renderers (typically for story-defined channels like * `ambient:` or custom event channels) by calling * `renderer.registerRenderer(...)` on the returned instance. * * Available after `connectEngine()` returns and before * `start()` is called — that window is when the default platform * renderers are registered but no `channel:packet` has fired yet. * Throws if called before `connectEngine()` (the renderer doesn't * exist yet). */ getChannelRenderer(): IRenderer; /** * The shared `AudioManager` instance the platform-default audio * renderers (`sound`, `music`, `ambient:*`) delegate to. Stories * registering a custom `ambient:` renderer pass this instance * to `createAmbientChannelRenderer(audio, id)` so playback shares * one Web Audio context. */ getAudioManager(): AudioManager; /** * Call into the engine's save serializer. The engine produces a * complete `ISaveData` carrying the world's full runtime state via * the gzipped `worldSnapshot` field. Used by every save path * (interactive, autosave, startup). * * The cast bypasses the engine's `private` modifier on this method; * the platform-browser host needs both interactive (hook-driven) and * non-interactive (autosave / startup-restore) save paths, and the * public hook flow only covers the interactive case. Mirrors the * pattern used by the engine's own test suite. */ private engineCreateSave; /** Apply an engine save to the live world via `WorldModel.loadJSON`. */ private engineApplySave; private performSave; private getSaveContext; private updateStatusLine; private syncScoreFromWorld; } //# sourceMappingURL=BrowserClient.d.ts.map