UNPKG

@utsp/runtime-client

Version:

UTSP Runtime Client - Local and multi-user client runtime

268 lines (262 loc) 9.19 kB
import { AudioManager } from '@utsp/audio'; export { AudioManager, AudioManagerOptions, ToneOptions } from '@utsp/audio'; import { IApplication } from '@utsp/types'; export { IApplication } from '@utsp/types'; import { AutoplayOverlayOptions } from '@utsp/render'; /** * Runtime Client Types and Options */ /** * Client runtime mode */ type ClientRuntimeMode = 'local' | 'connected'; /** * Renderer type to use */ declare enum RendererType { /** WebGL2 renderer - Optimized WebGL 1.0 with GPU palette, instanced rendering (default, recommended) */ TerminalGL = "webgl", /** Canvas 2D renderer - CPU fallback with ImageData optimization for benchmarks */ Terminal2D = "terminal2d" } /** * Render mode for ClientRuntime */ type RenderMode = /** Continuous rendering at max FPS (default) - requestAnimationFrame loop */ 'continuous' /** On-demand rendering - only renders when explicitly requested via requestRender() */ | 'on-demand'; /** * Base client runtime options */ interface BaseClientRuntimeOptions { /** Application instance */ application: IApplication; /** Container HTML element for rendering */ container: HTMLElement; /** Enable debug logging */ debug?: boolean; /** Initial display width in columns (default: 80). Can be overridden by IApplication via Display */ width?: number; /** Initial display height in rows (default: 25). Can be overridden by IApplication via Display */ height?: number; /** Renderer type (default: Auto) */ renderer?: RendererType; /** Mobile/Touch input configuration */ mobileInputConfig?: { /** Prevent default touch behavior (scroll, zoom). Default: true for canvas, false for page */ preventDefault?: boolean; /** Use passive event listeners for better scroll performance. Default: false */ passive?: boolean; /** Maximum simultaneous touches. Default: 10 */ maxTouches?: number; }; /** Show debug grid to visualize cell boundaries (default: false) */ showGrid?: boolean; /** Enable ImageData rendering for Canvas 2D (default: true). Provides pixel-perfect rendering with no gaps between cells. 10-20× faster than fillRect. Only for Terminal2D renderer with bitmap fonts. */ useImageDataRendering?: boolean; /** Render mode: 'continuous' (default) renders at max FPS, 'on-demand' only renders when explicitly requested. When tickRate is 0, automatically switches to 'on-demand'. */ renderMode?: RenderMode; /** Tick rate in ticks per second (default: 30). Set to 0 to disable update loop (only init/initUser, no update/updateUser). When set to 0, automatically enables 'on-demand' render mode. */ tickRate?: number; /** Capture input events to prevent default browser behavior (Tab, arrows, etc.). Default: false. When true, preventDefault() and stopPropagation() are called on keyboard and mouse events to keep focus in the terminal. All F keys (F1-F12) and Ctrl/Cmd shortcuts are automatically excluded. */ captureInput?: boolean; /** Enable input handling (keyboard, mouse, touch, gamepad). Default: true. When false, no input listeners are created - useful for display-only clients in documentation pages where you want to scroll freely without the client intercepting events. */ inputEnabled?: boolean; /** * Autoplay mode. Default: true. * * - `true`: Application starts immediately (current behavior) * - `false`: Displays a "Click to Start" button overlay. Application only starts after user interaction. * * Useful for: * - Audio APIs that require user interaction before playing * - Preventing automatic resource consumption * - Better UX on mobile where autoplay may not be desired * * @example * ```typescript * const runtime = new ClientRuntime({ * mode: 'local', * application: myApp, * container: document.getElementById('app'), * autoplay: false, // Show "Click to Start" button * autoplayOptions: { * buttonText: 'Click to Play', * buttonColor: '#00ff00' * } * }); * ``` */ autoplay?: boolean; /** * Autoplay overlay customization options. * Only used when `autoplay: false`. */ autoplayOptions?: Omit<AutoplayOverlayOptions, 'onStart'>; } /** * Local mode options (standalone, no network) */ interface LocalModeOptions extends BaseClientRuntimeOptions { /** Runtime mode */ mode: 'local'; /** User ID (default: 'local') */ userId?: string; /** User name (default: 'User') */ username?: string; } /** * Connected mode options (multiplayer) */ interface ConnectedModeOptions extends BaseClientRuntimeOptions { /** Runtime mode */ mode: 'connected'; /** Server URL (e.g., 'ws://localhost:3000') */ serverUrl: string; /** User name */ username?: string; /** Auto-reconnect on disconnect */ autoReconnect?: boolean; /** Authentication token */ token?: string; } /** * Union type of client runtime options */ type ClientRuntimeOptions = LocalModeOptions | ConnectedModeOptions; /** * Performance timing for a single frame */ interface FrameTiming { /** Time spent in Core tick (ms) */ coreTime: number; /** Time spent in Renderer (ms) */ renderTime: number; /** Total frame time (ms) */ totalTime: number; } /** * Client runtime statistics */ interface ClientRuntimeStats { /** Runtime mode */ mode: ClientRuntimeMode; /** Is runtime currently running */ running: boolean; /** Number of users (1 for local, multiple for connected) */ userCount: number; /** Current FPS */ fps: number; /** Uptime in milliseconds */ uptime: number; /** Total frames processed */ totalFrames: number; /** Network latency in ms (connected mode only) */ latency?: number; /** Last frame timing breakdown */ lastFrameTiming?: FrameTiming; /** Average frame timing over last 60 frames */ avgFrameTiming?: FrameTiming; } /** * Client Runtime * * Unified client runtime supporting both local and connected modes. */ declare class ClientRuntime { private core; private rendererManager; private rendererType; private input; private networkSync; private options; private running; private startTime; private lastTimestamp; private userId; private mode; private visibilityChangeHandler?; private tickRate; private accumulatedTime; private readonly FRAME_TIME_MIN; private lastRenderTimestamp; private rafId; private performanceMonitor; private renderMode; private renderRequested; private autoplayOverlay; private autoplay; private audioManager; constructor(options: ClientRuntimeOptions); getMode(): ClientRuntimeMode; getRendererType(): RendererType; isRunning(): boolean; private createRenderer; setTickRate(tickRate: number): void; setRenderMode(mode: 'continuous' | 'on-demand'): void; setMaxFPS(fps: number): void; getTickRate(): number; /** * Request a render in on-demand mode. * Has no effect in continuous mode (renders automatically). * * @example * ```typescript * // On-demand mode: render only when needed * const runtime = new ClientRuntime({ * mode: 'local', * renderMode: 'on-demand', * tickRate: 0, // Disable update loop * application: myApp, * container: document.getElementById('app') * }); * * await runtime.start(); * * // Manually request render after changing something * core.getUser('local').setCell(0, 0, '@', 1, 0); * runtime.requestRender(); // Trigger render * ``` */ requestRender(): void; start(): Promise<void>; stop(): Promise<void>; getStats(): ClientRuntimeStats; destroy(): Promise<void>; private createLocalUser; /** * Load sounds from Core's SoundRegistry into AudioManager's SoundBank * Used in standalone mode to transfer sounds registered via core.loadSound() * @private */ private loadSoundsFromRegistry; private mainLoop; private collectAndApplyInput; private collectAndSendInput; private render; /** * Handle palette change from Core * Converts Core palette Map to RGBColor array and updates renderer */ private onCorePaletteChanged; /** * Handle bitmap font change from Core * Loads the font from registry and updates renderer */ private onCoreBitmapFontChanged; /** * Get the AudioManager instance * Returns null before start() is called */ getAudioManager(): InstanceType<typeof AudioManager> | null; /** * Get the AudioContext instance (convenience method) * Returns null if AudioManager not initialized */ getAudioContext(): AudioContext | null; private log; } export { ClientRuntime, RendererType }; export type { BaseClientRuntimeOptions, ClientRuntimeMode, ClientRuntimeOptions, ClientRuntimeStats, ConnectedModeOptions, FrameTiming, LocalModeOptions, RenderMode };