/** * Input device types enumeration * Each device type has its own input enum */ declare enum InputDeviceType { Keyboard = 0, Mouse = 1, Gamepad = 2, Touch = 3, TVRemote = 4, TextInput = 5,// For text input (captures event.key directly for input boxes, chat, etc.) Motion = 6,// Accelerometer, gyroscope, and device orientation sensors TouchZone = 7 } /** * Keyboard input enumeration * Maps keyboard keys to numeric values for efficient storage and comparison * * Based on KeyboardEvent.code standard */ declare enum KeyboardInput { KeyA = 0, KeyB = 1, KeyC = 2, KeyD = 3, KeyE = 4, KeyF = 5, KeyG = 6, KeyH = 7, KeyI = 8, KeyJ = 9, KeyK = 10, KeyL = 11, KeyM = 12, KeyN = 13, KeyO = 14, KeyP = 15, KeyQ = 16, KeyR = 17, KeyS = 18, KeyT = 19, KeyU = 20, KeyV = 21, KeyW = 22, KeyX = 23, KeyY = 24, KeyZ = 25, Digit0 = 26, Digit1 = 27, Digit2 = 28, Digit3 = 29, Digit4 = 30, Digit5 = 31, Digit6 = 32, Digit7 = 33, Digit8 = 34, Digit9 = 35, ArrowUp = 36, ArrowDown = 37, ArrowLeft = 38, ArrowRight = 39, Space = 40, Enter = 41, Escape = 42, Backspace = 43, Tab = 44, ShiftLeft = 45, ShiftRight = 46, ControlLeft = 47, ControlRight = 48, AltLeft = 49, AltRight = 50, MetaLeft = 51, MetaRight = 52, CapsLock = 53, Delete = 54, Insert = 55, Home = 56, End = 57, PageUp = 58, PageDown = 59, F1 = 60, F2 = 61, F3 = 62, F4 = 63, F5 = 64, F6 = 65, F7 = 66, F8 = 67, F9 = 68, F10 = 69, F11 = 70, F12 = 71, Minus = 72, Equal = 73, BracketLeft = 74, BracketRight = 75, Backslash = 76, Semicolon = 77, Quote = 78, Comma = 79, Period = 80, Slash = 81, Backquote = 82, Numpad0 = 91, Numpad1 = 92, Numpad2 = 93, Numpad3 = 94, Numpad4 = 95, Numpad5 = 96, Numpad6 = 97, Numpad7 = 98, Numpad8 = 99, Numpad9 = 100, NumpadAdd = 101, NumpadSubtract = 102, NumpadMultiply = 103, NumpadDivide = 104, NumpadDecimal = 105, NumpadEnter = 106, NumLock = 107, PrintScreen = 111, ScrollLock = 112, Pause = 113, ContextMenu = 114 } /** * Helper to convert KeyboardEvent.code to KeyboardInput enum */ declare function keyCodeToKeyboardInput(code: string): KeyboardInput | null; /** * Helper to convert KeyboardInput enum to KeyboardEvent.code */ declare function keyboardInputToKeyCode(input: KeyboardInput): string; /** * Mouse input enumeration * Covers buttons and axes (position, delta, wheel) */ declare enum MouseInput { LeftButton = 0, MiddleButton = 1, RightButton = 2, Button4 = 3,// Back button Button5 = 4,// Forward button PositionX = 100, PositionY = 101, DeltaX = 102, DeltaY = 103, WheelDeltaY = 104, WheelDeltaX = 105 } /** * Check if the input is a button */ declare function isMouseButton(input: MouseInput): boolean; /** * Check if the input is an axis */ declare function isMouseAxis(input: MouseInput): boolean; /** * Gamepad input enumeration * Based on the Standard Gamepad mapping (W3C specification) * * Buttons: 0-99 * Axes: 100-199 */ declare enum GamepadInput { ButtonA = 0,// South (X on PlayStation, A on Xbox) ButtonB = 1,// East (Circle on PlayStation, B on Xbox) ButtonX = 2,// West (Square on PlayStation, X on Xbox) ButtonY = 3,// North (Triangle on PlayStation, Y on Xbox) LeftShoulder = 4,// L1 / LB RightShoulder = 5,// R1 / RB LeftTrigger = 6,// L2 / LT RightTrigger = 7,// R2 / RT Select = 8,// Select / Back / Share Start = 9,// Start / Menu / Options LeftStick = 10,// L3 RightStick = 11,// R3 DPadUp = 12, DPadDown = 13, DPadLeft = 14, DPadRight = 15, Home = 16,// PS button / Xbox button / Home Touchpad = 17,// PlayStation touchpad button LeftStickX = 100, LeftStickY = 101, RightStickX = 102, RightStickY = 103, LeftTriggerAxis = 104,// Alternative analog representation RightTriggerAxis = 105 } /** * Check if the input is a button */ declare function isGamepadButton(input: GamepadInput): boolean; /** * Check if the input is an axis */ declare function isGamepadAxis(input: GamepadInput): boolean; /** * Map from standard gamepad button index to GamepadInput enum */ declare function gamepadButtonIndexToInput(index: number): GamepadInput | null; /** * Map from standard gamepad axis index to GamepadInput enum */ declare function gamepadAxisIndexToInput(index: number): GamepadInput | null; /** * Physical source for an axis * * Different types of possible sources: * - keyboard: Two keys (negative/positive) * - gamepad: Analog axis (stick/trigger) * - mouse: Mouse movement (delta X/Y or wheel) * - gyroscope: Device orientation (pitch/roll/yaw) * - touch: Virtual touch joystick */ interface AxisSource { /** Unique source ID (0-255, for compression) */ sourceId: number; /** Type of input source */ type: InputDeviceType; /** Key for -1 value (e.g., KeyboardInput.ArrowLeft) */ negativeKey?: KeyboardInput; /** Key for +1 value (e.g., KeyboardInput.ArrowRight) */ positiveKey?: KeyboardInput; /** Gamepad index (0-3) */ gamepadIndex?: number; /** Axis enum (e.g., GamepadInput.LeftStickX) */ axis?: GamepadInput; /** Mouse axis enum (e.g., MouseInput.DeltaX, MouseInput.Wheel) */ mouseAxis?: MouseInput; /** Rotation axis */ gyroAxis?: 'pitch' | 'roll' | 'yaw'; /** Virtual touch joystick ID (0-3) */ touchId?: number; /** Joystick axis */ touchAxis?: 'x' | 'y'; /** Touch zone ID (0-31) */ touchZoneId?: number; /** Zone position axis */ touchZoneAxis?: 'x' | 'y'; /** Dead zone (default: 0.0) */ deadzone?: number; /** Multiplier (default: 1.0) */ scale?: number; /** Invert axis (default: false) */ invert?: boolean; /** Sensitivity (for mouse/gyro, default: 1.0) */ sensitivity?: number; } /** * Physical source for a button * * Different types of possible sources: * - keyboard: A key * - gamepad: A button * - mouse: Mouse button * - touch: Touch button */ interface ButtonSource { /** Unique source ID (0-255, for compression) */ sourceId: number; /** Type of input source */ type: InputDeviceType; /** Key enum (e.g., KeyboardInput.Space) */ key?: KeyboardInput; /** Gamepad index (0-3) */ gamepadIndex?: number; /** Button enum (e.g., GamepadInput.A) */ button?: GamepadInput; /** Mouse button enum (e.g., MouseInput.LeftButton) */ mouseButton?: MouseInput; /** Touch button ID (0-9) */ touchButton?: number; /** Touch zone ID (0-31) */ touchZoneId?: number; } /** * Axis binding definition * * Defines how an abstract axis (e.g., "MoveHorizontal") maps to * physical input sources (keyboard, gamepad, etc.) */ interface AxisBinding { /** Unique binding ID (0-255) */ bindingId: number; /** Axis name (e.g., "MoveHorizontal", "CameraX") */ name: string; /** Minimum value (e.g., -1.0) */ min: number; /** Maximum value (e.g., +1.0) */ max: number; /** Default value (e.g., 0.0) */ defaultValue: number; /** Physical sources (values are added together) */ sources: AxisSource[]; } /** * Button binding definition * * Defines how an abstract button (e.g., "Jump") maps to * physical input sources (keyboard, gamepad, etc.) */ interface ButtonBinding { /** Unique binding ID (0-255) */ bindingId: number; /** Button name (e.g., "Jump", "Attack") */ name: string; /** Default value (e.g., false) */ defaultValue: boolean; /** Physical sources (combined with OR logic) */ sources: ButtonSource[]; } /** * Touch zone binding definition * * Defines a virtual touch zone in grid cell coordinates. * Used by the server to define touch input regions that the client * will interpret for multi-touch interaction. */ interface TouchZoneBinding { /** Zone ID (0-31) */ zoneId: number; /** Human-readable name for debugging */ name: string; /** X position in grid cells */ x: number; /** Y position in grid cells */ y: number; /** Width in grid cells */ width: number; /** Height in grid cells */ height: number; } /** * Load packet for input bindings * * This JSON packet is sent from server to client via the Load channel * to configure which inputs the client should capture and send back. * * Architecture flow: * 1. Server defines bindings (bindingId ↔ name + sources) * 2. Server generates this LoadPacket as JSON * 3. Client receives the packet and configures input mappings * 4. Client captures physical inputs and sends compressed values */ interface InputBindingLoadPacket { /** Packet type identifier */ type: 'input-binding'; /** Binding version (for future evolution) */ version: number; /** Axis bindings configuration */ axes: AxisBinding[]; /** Button bindings configuration */ buttons: ButtonBinding[]; /** Touch zone bindings configuration (optional) */ touchZones?: TouchZoneBinding[]; } /** * Touch input enumeration * Supports multi-touch with up to 10 simultaneous touches * * Each touch has an identifier (button) and position axes (X, Y) */ declare enum TouchInput { Touch0 = 0, Touch1 = 1, Touch2 = 2, Touch3 = 3, Touch4 = 4, Touch5 = 5, Touch6 = 6, Touch7 = 7, Touch8 = 8, Touch9 = 9, Touch0X = 100, Touch0Y = 101, Touch1X = 102, Touch1Y = 103, Touch2X = 104, Touch2Y = 105, Touch3X = 106, Touch3Y = 107, Touch4X = 108, Touch4Y = 109, Touch5X = 110, Touch5Y = 111, Touch6X = 112, Touch6Y = 113, Touch7X = 114, Touch7Y = 115, Touch8X = 116, Touch8Y = 117, Touch9X = 118, Touch9Y = 119, PinchScale = 200,// Pinch-to-zoom scale RotationAngle = 201,// Two-finger rotation SwipeVelocityX = 202,// Swipe velocity SwipeVelocityY = 203 } /** * Check if the input is a touch identifier (button) */ declare function isTouchButton(input: TouchInput): boolean; /** * Check if the input is a position axis */ declare function isTouchPosition(input: TouchInput): boolean; /** * Check if the input is a gesture value */ declare function isTouchGesture(input: TouchInput): boolean; /** * Get the X position axis for a touch index */ declare function getTouchXAxis(touchIndex: number): TouchInput | null; /** * Get the Y position axis for a touch index */ declare function getTouchYAxis(touchIndex: number): TouchInput | null; /** * TouchZone input enumeration * * Each zone exposes: * - A button (active/inactive) * - Two axes for last touch position inside the zone (X/Y) * * Zones are index-based (0-31) to allow static typing while remaining generic. */ declare enum TouchZoneInput { Zone0 = 0, Zone1 = 1, Zone2 = 2, Zone3 = 3, Zone4 = 4, Zone5 = 5, Zone6 = 6, Zone7 = 7, Zone8 = 8, Zone9 = 9, Zone10 = 10, Zone11 = 11, Zone12 = 12, Zone13 = 13, Zone14 = 14, Zone15 = 15, Zone16 = 16, Zone17 = 17, Zone18 = 18, Zone19 = 19, Zone20 = 20, Zone21 = 21, Zone22 = 22, Zone23 = 23, Zone24 = 24, Zone25 = 25, Zone26 = 26, Zone27 = 27, Zone28 = 28, Zone29 = 29, Zone30 = 30, Zone31 = 31, Zone0X = 100, Zone0Y = 101, Zone1X = 102, Zone1Y = 103, Zone2X = 104, Zone2Y = 105, Zone3X = 106, Zone3Y = 107, Zone4X = 108, Zone4Y = 109, Zone5X = 110, Zone5Y = 111, Zone6X = 112, Zone6Y = 113, Zone7X = 114, Zone7Y = 115, Zone8X = 116, Zone8Y = 117, Zone9X = 118, Zone9Y = 119, Zone10X = 120, Zone10Y = 121, Zone11X = 122, Zone11Y = 123, Zone12X = 124, Zone12Y = 125, Zone13X = 126, Zone13Y = 127, Zone14X = 128, Zone14Y = 129, Zone15X = 130, Zone15Y = 131, Zone16X = 132, Zone16Y = 133, Zone17X = 134, Zone17Y = 135, Zone18X = 136, Zone18Y = 137, Zone19X = 138, Zone19Y = 139, Zone20X = 140, Zone20Y = 141, Zone21X = 142, Zone21Y = 143, Zone22X = 144, Zone22Y = 145, Zone23X = 146, Zone23Y = 147, Zone24X = 148, Zone24Y = 149, Zone25X = 150, Zone25Y = 151, Zone26X = 152, Zone26Y = 153, Zone27X = 154, Zone27Y = 155, Zone28X = 156, Zone28Y = 157, Zone29X = 158, Zone29Y = 159, Zone30X = 160, Zone30Y = 161, Zone31X = 162, Zone31Y = 163 } declare function isTouchZoneButton(input: TouchZoneInput): boolean; declare function isTouchZonePosition(input: TouchZoneInput): boolean; declare function getTouchZoneXAxis(zoneId: number): TouchZoneInput | null; declare function getTouchZoneYAxis(zoneId: number): TouchZoneInput | null; /** * TV Remote input enumeration * Common buttons found on TV remotes and set-top box controllers */ declare enum TVRemoteInput { DPadUp = 0, DPadDown = 1, DPadLeft = 2, DPadRight = 3, DPadCenter = 4,// OK/Select button Play = 5, Pause = 6, PlayPause = 7,// Combined play/pause toggle Stop = 8, Rewind = 9, FastForward = 10, Previous = 11,// Previous track/channel Next = 12,// Next track/channel Record = 13, VolumeUp = 15, VolumeDown = 16, Mute = 17, ChannelUp = 18, ChannelDown = 19, Back = 20, Home = 21, Menu = 22, Info = 23, Guide = 24, Exit = 25, Red = 30, Green = 31, Yellow = 32, Blue = 33, Digit0 = 40, Digit1 = 41, Digit2 = 42, Digit3 = 43, Digit4 = 44, Digit5 = 45, Digit6 = 46, Digit7 = 47, Digit8 = 48, Digit9 = 49, Input = 50,// Switch input source Settings = 51, Subtitle = 52, Audio = 53,// Audio track selection Power = 54, PointerX = 100,// For remotes with motion control PointerY = 101, GyroX = 102,// Gyroscope data GyroY = 103, GyroZ = 104 } /** * Check if the input is a button */ declare function isTVRemoteButton(input: TVRemoteInput): boolean; /** * Check if the input is an axis (motion/pointer) */ declare function isTVRemoteAxis(input: TVRemoteInput): boolean; /** * Universal Input System Types * * Provides type-safe input handling across all device types * using numeric enums for performance and compact serialization. */ /** * Union type of all possible input enums */ type InputEnum = KeyboardInput | MouseInput | GamepadInput | TouchInput | TVRemoteInput | TouchZoneInput; /** * Generic input descriptor * Identifies any input across all device types */ interface InputDescriptor { device: InputDeviceType; input: InputEnum; } /** * Type-safe input descriptors for each device */ interface KeyboardInputDescriptor { device: InputDeviceType.Keyboard; input: KeyboardInput; } interface MouseInputDescriptor { device: InputDeviceType.Mouse; input: MouseInput; } interface GamepadInputDescriptor { device: InputDeviceType.Gamepad; input: GamepadInput; } interface TouchInputDescriptor { device: InputDeviceType.Touch; input: TouchInput; } interface TouchZoneInputDescriptor { device: InputDeviceType.TouchZone; input: TouchZoneInput; } interface TVRemoteInputDescriptor { device: InputDeviceType.TVRemote; input: TVRemoteInput; } /** * Discriminated union of all input descriptors */ type TypedInputDescriptor = KeyboardInputDescriptor | MouseInputDescriptor | GamepadInputDescriptor | TouchInputDescriptor | TVRemoteInputDescriptor | TouchZoneInputDescriptor; /** * Helper to create a typed input descriptor */ declare function createInputDescriptor(device: T, input: T extends InputDeviceType.Keyboard ? KeyboardInput : T extends InputDeviceType.Mouse ? MouseInput : T extends InputDeviceType.Gamepad ? GamepadInput : T extends InputDeviceType.Touch ? TouchInput : T extends InputDeviceType.TVRemote ? TVRemoteInput : T extends InputDeviceType.TouchZone ? TouchZoneInput : never): InputDescriptor; /** * Check if an input is a button (vs axis) */ declare function isButton(descriptor: InputDescriptor): boolean; /** * Check if an input is an axis */ declare function isAxis(descriptor: InputDescriptor): boolean; /** * Serialize input descriptor to a compact binary format * Format: [device: u8][input: u16] = 3 bytes total */ declare function serializeInputDescriptor(descriptor: InputDescriptor): Uint8Array; /** * Deserialize input descriptor from binary format */ declare function deserializeInputDescriptor(buffer: Uint8Array, offset?: number): InputDescriptor; /** * Convert input descriptor to human-readable string * Format: "DeviceType:InputName" */ declare function inputDescriptorToString(descriptor: InputDescriptor): string; /** * Parse string format back to input descriptor * Format: "DeviceType:InputName" or "devicetype:inputname" */ declare function parseInputDescriptor(str: string): InputDescriptor | null; /** * Input system interface for querying input state */ interface IInputSystem { /** Query button state (returns boolean) */ getButton(device: InputDeviceType, input: number): boolean; /** Query if button was just pressed this frame (transition false→true) */ getButtonJustPressed(device: InputDeviceType, input: number): boolean; /** Query if button was just released this frame (transition true→false) */ getButtonJustReleased(device: InputDeviceType, input: number): boolean; /** Query axis value (returns number, typically -1 to 1) */ getAxis(device: InputDeviceType, input: number): number; /** Check if left mouse button is currently pressed (optional convenience method) */ isLeftMousePressed?(): boolean; /** Start listening to events */ start(): void; /** Stop listening to events */ stop(): void; /** Reset all states */ reset(): void; /** Cleanup */ destroy(): void; /** Check if listening (optional) */ isListening?(): boolean; /** Poll transient states - called once per frame */ poll?(): void; } /** * 2D vector with immutable and in-place operations */ declare class Vector2 { x: number; y: number; constructor(x?: number, y?: number); static zero(): Vector2; static one(): Vector2; static up(): Vector2; static down(): Vector2; static left(): Vector2; static right(): Vector2; add(v: Vector2): Vector2; subtract(v: Vector2): Vector2; multiply(scalar: number): Vector2; divide(scalar: number): Vector2; length(): number; lengthSquared(): number; normalize(): Vector2; distance(v: Vector2): number; distanceSquared(v: Vector2): number; dot(v: Vector2): number; cross(v: Vector2): number; angle(): number; angleTo(v: Vector2): number; rotate(angle: number): Vector2; lerp(v: Vector2, t: number): Vector2; clone(): Vector2; equals(v: Vector2): boolean; toString(): string; toArray(): [number, number]; set(x: number, y: number): this; copy(v: Vector2): this; addInPlace(v: Vector2): this; subtractInPlace(v: Vector2): this; multiplyInPlace(scalar: number): this; divideInPlace(scalar: number): this; normalizeInPlace(): this; } /** * 3D vector with immutable and in-place operations */ declare class Vector3 { x: number; y: number; z: number; constructor(x?: number, y?: number, z?: number); static zero(): Vector3; static one(): Vector3; static up(): Vector3; static down(): Vector3; static left(): Vector3; static right(): Vector3; static forward(): Vector3; static back(): Vector3; add(v: Vector3): Vector3; subtract(v: Vector3): Vector3; multiply(scalar: number): Vector3; divide(scalar: number): Vector3; length(): number; lengthSquared(): number; normalize(): Vector3; distance(v: Vector3): number; distanceSquared(v: Vector3): number; dot(v: Vector3): number; cross(v: Vector3): Vector3; lerp(v: Vector3, t: number): Vector3; clone(): Vector3; equals(v: Vector3): boolean; toString(): string; toArray(): [number, number, number]; set(x: number, y: number, z: number): this; copy(v: Vector3): this; addInPlace(v: Vector3): this; subtractInPlace(v: Vector3): this; multiplyInPlace(scalar: number): this; divideInPlace(scalar: number): this; normalizeInPlace(): this; } /** * RGBA color (0-255 per channel) */ interface RGBColor$1 { /** Red (0-255) */ r: number; /** Green (0-255) */ g: number; /** Blue (0-255) */ b: number; /** Alpha (0-255, 0=transparent, 255=opaque) */ a: number; } /** * Rendered cell with palette indices for optimal caching */ interface RenderedCell { /** Character */ char: string; /** Foreground color index (0-255) */ fgColorIndex: number; /** Background color index (0-255) */ bgColorIndex: number; /** Foreground emission (0-255, 0=none) */ fgEmission: number; /** Background emission (0-255, 0=none) */ bgEmission: number; } /** * Per-pass render payload (multi-pass rendering) * Keeps cells unflattened so renderers can draw passes sequentially. */ interface RenderPassState { /** Pass identifier (matches Display renderPass id) */ id: number; /** Z range lower bound (0-255) */ zMin: number; /** Z range upper bound (0-255) */ zMax: number; /** Cells for this pass (length = width × height of parent render state) */ cells: RenderedCell[]; } /** * Display render state with cells and color palette */ interface RenderState { /** Display ID (matches the Display instance it was rasterized from) */ id: number; /** Width in cells */ width: number; /** Height in cells */ height: number; /** Cell array (length = width × height) */ cells: RenderedCell[]; /** Color palette (256 colors) */ palette: RGBColor$1[]; /** Optional multi-pass payloads (drawn in array order) */ passes?: RenderPassState[]; } /** * Complete user render state */ interface UserRenderState { /** User ID */ userId: string; /** User name */ userName: string; /** Current tick number */ tick: number; /** Render states for each display */ displays: RenderState[]; } /** * RGB color for palette configuration */ interface RGBColor { r: number; g: number; b: number; a: number; } /** * Renderer interface - Contract for all rendering implementations * * This is a universal interface that works in any environment (browser, Node.js, native). * Canvas element is typed as `unknown` to avoid DOM dependencies in server code. * Client code should cast to `HTMLCanvasElement` when needed. * * @example * ```ts * class TerminalGL implements IRenderer { * renderDisplayData(data: RenderState): void { } * resize(cols: number, rows: number): void { } * destroy(): void { } * getCols(): number { return this.cols; } * getRows(): number { return this.rows; } * isReady(): boolean { return this.ready; } * getCanvas(): unknown { return this.canvas; } * setBitmapFont(font, cw, ch, cellW, cellH): void { } * setPalette(palette): void { } * } * ``` */ interface IRenderer { /** * Render display data to screen (called every frame) * @param data - Cell data with palette indices */ renderDisplayData(data: RenderState): void; /** * Resize renderer dimensions * @param cols - Width in columns * @param rows - Height in rows */ resize(cols: number, rows: number): void; /** Clear display (optional) */ clear?(): void; /** Cleanup resources */ destroy(): void; /** Get width in columns */ getCols(): number; /** Get height in rows */ getRows(): number; /** Check if ready to render */ isReady(): boolean; /** * Get rendering offsets (for renderers that center content within canvas) * Optional method - only implement if renderer centers content * @returns Offset in pixels from canvas origin to rendered content */ getOffsets?(): { offsetX: number; offsetY: number; } | undefined; /** * Get canvas element (typed as unknown to avoid DOM dependencies) * Cast to HTMLCanvasElement in browser environments * @returns Canvas element or null if not available */ getCanvas(): unknown; /** * Set image font structure (allocate texture) */ setImageFontStructure?(glyphWidth: number, glyphHeight: number, cellWidth: number, cellHeight: number, atlasBlocks: 1 | 4 | 16): Promise; /** * Set image font data block */ setImageFontBlock?(blockIndex: number, data: Uint8Array): Promise; /** * Set image font (PNG atlas) for extended character rendering * @param imageData - PNG image data as Uint8Array * @param glyphWidth - Glyph width in pixels * @param glyphHeight - Glyph height in pixels * @param cellWidth - Cell width in pixels (includes spacing) * @param cellHeight - Cell height in pixels (includes spacing) * @param atlasBlocks - Number of 256-char blocks (1, 4, or 16) * @returns Promise that resolves when font is loaded * @deprecated Use setImageFontStructure and setImageFontBlock */ setImageFont?(imageData: Uint8Array, glyphWidth: number, glyphHeight: number, cellWidth: number, cellHeight: number, atlasBlocks: 1 | 4 | 16): Promise; /** * Set color palette * @param palette - Array of 256 RGB colors */ setPalette(palette: RGBColor[]): void; } /** * Color palette interface * * @example * ```ts * const palette = new VGAPalette(); * const white = palette.getColor(15); * ``` */ interface IColorPalette { /** Get color by index (returns CSS color string) */ getColor(index: number): string; /** Set color at index */ setColor(index: number, color: string): void; /** Get palette size */ getSize(): number; /** Reset to default colors (optional) */ reset?(): void; } /** * Scaling modes for pixel-perfect rendering * * Use stricter modes (Integer) for crisp pixels, or looser modes (None) * to fill more space at the cost of potential visual artifacts. */ declare enum ScalingMode { /** * No constraints - scales to fill available space. * May cause lines to appear thicker due to sub-pixel rendering. * Best for maximizing screen usage. */ None = "none", /** * Snaps to eighth increments (1.0, 1.125, 1.25, 1.375, ..., 2.0, ...). * Finest control with good visual quality for 8×8 pixel cells. */ Eighth = "eighth", /** * Snaps to quarter increments (1.0, 1.25, 1.5, 1.75, 2.0, ...). * Good balance between space usage and visual quality. */ Quarter = "quarter", /** * Snaps to half increments (1.0, 1.5, 2.0, 2.5, 3.0, ...). * Moderate balance between space usage and visual quality. */ Half = "half", /** * Integer scaling only (1x, 2x, 3x, ...). * Crisp pixels with no sub-pixel artifacts. * May leave empty space around the canvas. */ Integer = "integer", /** * Responsive mode - no scaling applied (scale = 1). * The canvas size matches exactly cols × cellWidth by rows × cellHeight. * Use with display.setSize() to dynamically add/remove cells based on viewport. * Best for responsive applications that want to maximize cell count. */ Responsive = "responsive" } /** * Numeric values for ScalingMode (for binary protocol) * These map 1:1 with ScalingMode enum values */ declare enum ScalingModeValue { None = 0, Eighth = 1, Quarter = 2, Half = 3, Integer = 4, Responsive = 5 } /** * Convert ScalingMode string enum to numeric ScalingModeValue * Used by encoders to convert API values to binary protocol */ declare function scalingModeToValue(mode: ScalingMode): ScalingModeValue; /** * Convert numeric ScalingModeValue to ScalingMode string enum * Used by decoders to convert binary protocol to API values */ declare function valueToScalingMode(value: ScalingModeValue): ScalingMode; /** * Post-processing types * @packageDocumentation */ /** * Default values for post-processing effects. * Use these to ensure consistency across the codebase. */ declare const POST_PROCESS_DEFAULTS: { readonly scanlines: { readonly opacity: 0.15; readonly pattern: "horizontal"; readonly spacing: 2; readonly thickness: 1; readonly color: { readonly r: 0; readonly g: 0; readonly b: 0; }; }; readonly ambientEffect: { readonly blur: 30; readonly scale: 1.3; readonly opacity: 0.7; }; }; /** * Scanlines effect configuration */ interface ScanlinesConfig { /** Enable/disable scanlines effect */ enabled: boolean; /** Opacity of dark lines (0-1, default 0.15) */ opacity?: number; /** * Pattern type: * - 'horizontal': 1px dark line every N rows (classic CRT) * - 'vertical': 1px dark line every N columns * - 'grid': Combines horizontal and vertical */ pattern?: 'horizontal' | 'vertical' | 'grid'; /** Line spacing in pixels (default: 2 = line every 2 pixels) */ spacing?: number; /** Line thickness in pixels (default: 1) */ thickness?: number; /** Dark line color RGB (default: black {r:0, g:0, b:0}) */ color?: { r: number; g: number; b: number; }; } /** * Ambient effect configuration * Creates a blurred glow around the terminal canvas */ interface AmbientEffectConfig { /** Enable/disable ambient effect */ enabled: boolean; /** Blur intensity in pixels (default: 30) */ blur?: number; /** Scale factor for the glow (default: 1.3) */ scale?: number; /** Opacity of the ambient effect (default: 0.7) */ opacity?: number; } /** * Post-processing configuration * Sent from Core/User to renderer via commands */ interface PostProcessConfig { /** Scanlines effect (CRT-style) */ scanlines?: ScanlinesConfig; /** Ambient effect (blurred glow around terminal) */ ambientEffect?: AmbientEffectConfig; } /** * Debug grid configuration */ interface GridConfig { /** Enable or disable grid overlay */ enabled: boolean; /** Grid line color (CSS color string, e.g., 'rgba(255,0,0,0.5)') */ color?: string; /** Grid line width in pixels (default: 1) */ lineWidth?: number; } /** * Default grid configuration values */ declare const GRID_DEFAULTS: { readonly color: "rgba(144, 24, 24, 1)"; readonly lineWidth: 1; }; /** * Post-process command types */ type PostProcessCommandType = 'set-config' | 'set-scanlines-enabled' | 'set-scanlines-opacity' | 'set-ambient-effect-enabled' | 'set-ambient-effect-blur' | 'set-ambient-effect-scale' | 'set-scaling-mode' | 'set-grid' | 'switch-palette' | 'set-cell-size'; /** * Command to update post-processing settings for a specific display * * All post-process commands are scoped to a display. * The displayId identifies which display the command applies to. */ interface PostProcessCommand { /** Command type */ type: PostProcessCommandType; /** Display ID this command applies to (0-255) - REQUIRED */ displayId: number; /** Full post-process configuration (for 'set-config' type) */ config?: PostProcessConfig; /** Enable/disable flag (for toggle commands) */ enabled?: boolean; /** Opacity value 0-1 (for opacity commands) */ opacity?: number; /** Blur value in pixels (for blur commands) */ blur?: number; /** Scale factor (for scale commands) */ scale?: number; /** Scaling mode (for 'set-scaling-mode' type) */ scalingMode?: ScalingMode; /** Grid configuration (for 'set-grid' type) */ gridConfig?: GridConfig; /** Palette slot ID (for 'switch-palette' type) */ paletteSlotId?: number; /** Cell width in pixels (for 'set-cell-size' type) */ cellWidth?: number; /** Cell height in pixels (for 'set-cell-size' type) */ cellHeight?: number; } /** * Network client interface for client-to-server communication * Implementations: Socket.IO, WebRTC, WebSocket, etc. */ /** Event handler callback */ type NetworkEventHandler = (data: T) => void; /** Bridge message handler (client-side) */ type BridgeClientHandler = (data: T) => void; /** Connection state */ declare enum NetworkState { Disconnected = 0, Connecting = 1, Connected = 2, Reconnecting = 3, Error = 4 } /** Client connection options */ interface NetworkClientOptions { /** Server URL */ url: string; /** Auto-reconnect on disconnect */ autoReconnect?: boolean; /** Reconnect delay (ms) */ reconnectDelay?: number; /** Max reconnect attempts (0=infinite) */ maxReconnectAttempts?: number; /** Connection timeout (ms) */ timeout?: number; /** Auth data */ auth?: Record; /** ICE Servers for WebRTC */ iceServers?: RTCIceServer[]; /** Debug logging */ debug?: boolean; /** Session ID (Target Game ID) */ sessionId?: string; } /** Network client interface */ interface INetworkClient { /** Current state */ readonly state: NetworkState; /** Check if connected */ isConnected(): boolean; /** Connect to server */ connect(): Promise; /** Disconnect from server */ disconnect(): void; /** Send event to server */ send(event: string, data: any): void; /** Send volatile event to server (unreliable/UDP-like where supported) */ sendVolatile?(event: string, data: any): void; /** Listen for server events */ on(event: string, handler: NetworkEventHandler): void; /** Remove event listener */ off(event: string, handler: NetworkEventHandler): void; /** Remove all listeners for event */ removeAllListeners(event?: string): void; /** Send and wait for response */ request(event: string, data: any, timeout?: number): Promise; /** Get ping to server (ms) */ getPing(): number; /** * Send data to the server through the bridge channel * Bridge bypasses UTSP protocol - for external app communication */ sendBridge?(channel: string, data: unknown): void; /** * Listen for incoming bridge messages from the server */ onBridge?(channel: string, handler: BridgeClientHandler): void; /** * Remove a bridge handler */ offBridge?(channel: string, handler: BridgeClientHandler): void; /** * Remove all bridge handlers for a channel or all channels */ removeAllBridgeHandlers?(channel?: string): void; /** Cleanup */ destroy(): void; } /** * Network server interface for server-side communication * Implementations: Socket.IO, WebRTC, WebSocket, etc. */ /** Server event handler */ type ServerEventHandler = (clientId: string, data: T) => void; /** Connection handler */ type ConnectionHandler = (clientId: string) => void; /** Disconnection handler */ type DisconnectionHandler = (clientId: string, reason: string) => void; /** Bridge message handler (server-side) */ type BridgeServerHandler = (clientId: string, data: T) => void; /** Server options */ interface NetworkServerOptions { /** Port */ port: number; /** Host (default: "0.0.0.0") */ host?: string; /** CORS config */ cors?: { origin: string | string[]; credentials?: boolean; }; /** Max connections */ maxConnections?: number; /** Ping interval (ms) */ pingInterval?: number; /** Ping timeout (ms) */ pingTimeout?: number; /** Debug logging */ debug?: boolean; /** Public Relay URL for signaling (Zero Config mode) */ signalUrl?: string; /** Session ID (if using a relay) */ sessionId?: string; } /** Signaling information for clients */ interface SignalingInfo { /** Mode: 'socketio' or 'webrtc' */ mode: 'socketio' | 'webrtc'; /** Transport: 'websocket', 'polling', or 'webrtc' */ transport: 'websocket' | 'polling' | 'webrtc'; /** Signaling Host (if direct) */ host?: string; /** Signaling Port (if direct) */ port?: number; /** Signaling Path (default: /utsp-signal) */ path?: string; /** Signal Server URL (if relay) */ signalUrl?: string; /** Session ID (if relay or identified) */ sessionId?: string; } /** Client info */ interface ClientInfo { /** Client ID */ id: string; /** Connection timestamp */ connectedAt: number; /** IP address */ address: string; /** Custom data */ data: Record; } /** Network server interface */ interface INetworkServer { /** Check if running */ isRunning(): boolean; /** Start server */ start(): Promise; /** Get signaling info for clients */ getSignalingInfo(): SignalingInfo; /** Stop server */ stop(): Promise; /** Get connected client IDs */ getClients(): string[]; /** Get client info */ getClientInfo(clientId: string): ClientInfo | null; /** Send to specific client */ sendToClient(clientId: string, event: string, data: any): void; /** Send volatile (can be dropped if congested) */ sendToClientVolatile?(clientId: string, event: string, data: any): void; /** Broadcast to all clients */ broadcast(event: string, data: any): void; /** Broadcast volatile (can be dropped) */ broadcastVolatile?(event: string, data: any): void; /** Broadcast except one client */ broadcastExcept(excludeClientId: string, event: string, data: any): void; /** Send to room */ sendToRoom(room: string, event: string, data: any): void; /** Add client to room */ joinRoom(clientId: string, room: string): void; /** Remove client from room */ leaveRoom(clientId: string, room: string): void; /** Get room clients */ getRoomClients(room: string): string[]; /** Disconnect client */ disconnectClient(clientId: string, reason?: string): void; /** Listen for events */ on(event: string, handler: ServerEventHandler): void; /** Listen for connections */ onConnect(handler: ConnectionHandler): void; /** Listen for disconnections */ onDisconnect(handler: DisconnectionHandler): void; /** Remove listener */ off(event: string, handler: ServerEventHandler): void; /** Set client custom data */ setClientData(clientId: string, key: string, value: any): void; /** Get client custom data */ getClientData(clientId: string, key: string): any; /** Get server stats */ getStats(): { connectedClients: number; totalConnections: number; uptime: number; }; /** * Send data to a client through the bridge channel * Bridge bypasses UTSP protocol - for external app communication */ sendBridge?(clientId: string, channel: string, data: unknown): void; /** * Broadcast data to all clients through the bridge channel */ broadcastBridge?(channel: string, data: unknown): void; /** * Listen for incoming bridge messages from clients */ onBridge?(channel: string, handler: BridgeServerHandler): void; /** * Remove a bridge handler */ offBridge?(channel: string, handler: BridgeServerHandler): void; /** Cleanup */ destroy(): Promise; } /** * Network message types for UTSP protocol */ /** Base message */ interface NetworkMessage { /** Message type */ type: string; /** Timestamp (client send time) */ timestamp: number; /** Sequence number (optional) */ seq?: number; } /** Client input (client→server) */ interface InputMessage extends NetworkMessage { type: 'input'; data: Uint8Array; } /** Server update (server→client) */ interface UpdateMessage extends NetworkMessage { type: 'update'; data: Uint8Array; tick: number; } /** Asset load (server→client) */ interface LoadMessage extends NetworkMessage { type: 'load'; data: Uint8Array; } /** Join game (client→server) */ interface JoinMessage extends NetworkMessage { type: 'join'; username: string; roomId?: string; token?: string; } /** Join response (server→client) */ interface JoinResponseMessage extends NetworkMessage { type: 'join_response'; success: boolean; userId?: string; roomId?: string; error?: string; } /** Leave game (client→server) */ interface LeaveMessage extends NetworkMessage { type: 'leave'; } /** Ping (latency measurement) */ interface PingMessage extends NetworkMessage { type: 'ping'; } /** Pong (ping response) */ interface PongMessage extends NetworkMessage { type: 'pong'; pingTime: number; } /** Error message */ interface ErrorMessage extends NetworkMessage { type: 'error'; code: string; message: string; } /** Chat message (example custom type) */ interface ChatMessage extends NetworkMessage { type: 'chat'; text: string; userId: string; username: string; } /** Union of all message types */ type AnyNetworkMessage = InputMessage | UpdateMessage | LoadMessage | JoinMessage | JoinResponseMessage | LeaveMessage | PingMessage | PongMessage | ErrorMessage | ChatMessage; /** Message type literals */ type MessageType = AnyNetworkMessage['type']; /** * Network transport types */ declare enum NetworkTransportType { SocketIO = "socketio", WebRTC = "webrtc" } /** * Network Event Types (Protocol Messages) * Mapped to Byte IDs for efficient binary transport. */ declare enum NetworkEvent { /** KeepAlive / Ping */ Ping = 0, /** Pong */ Pong = 1, /** Handshake / Join Request */ Join = 2, /** Join Accept/Reject */ JoinResponse = 3, /** Server Full / Kick */ SystemMessage = 4, /** Client Input (Keyboard/Mouse) -> Server (20-60 Hz) */ Input = 16, /** Server State Update (Render Orders) -> Client (20-60 Hz) */ Update = 17, /** Audio Event (Play Sound) */ Audio = 18, /** Vibration Event */ Vibration = 19, /** Initial Load (Assets, Macro Templates) */ Load = 48, /** Dynamic Asset Load */ Asset = 49 } declare function isNetworkEvent(value: number): boolean; /** * Audio types for UTSP * @packageDocumentation */ /** * Supported audio file formats */ type SoundFormat = 'mp3' | 'wav' | 'ogg' | 'webm' | 'aac'; /** * Sound loading type */ type SoundLoadType = 'file' | 'external'; /** * A single sound to load via File mode (embedded data) */ interface SoundFileEntry { /** Unique sound identifier (0-255) */ soundId: number; /** Human-readable name for playback (e.g., 'coin', 'explosion') */ name: string; /** Audio format */ format: SoundFormat; /** Raw audio data */ data: Uint8Array; } /** * A single sound to load via External mode (URL reference) */ interface SoundExternalEntry { /** Unique sound identifier (0-255) */ soundId: number; /** Human-readable name for playback */ name: string; /** Audio format */ format: SoundFormat; /** URL to fetch the audio from (CDN, external server, etc.) */ url: string; /** Expected file size in bytes (optional, for progress tracking) */ size?: number; /** Checksum for validation (optional) */ checksum?: string; } /** * Sound Load packet - File mode * Audio data is embedded in the packet and sent via UTSP */ interface SoundLoadPacket { type: 'sound'; mode: 'file'; sounds: SoundFileEntry[]; /** Total number of sounds expected (for loading progress tracking) */ totalSounds?: number; } /** * Sound External Load packet - External mode * Only URLs are sent, client downloads from external sources */ interface SoundExternalLoadPacket { type: 'sound'; mode: 'external'; sounds: SoundExternalEntry[]; /** Total number of sounds expected (for loading progress tracking) */ totalSounds?: number; } /** * Union of all sound load packet types */ type AnySoundLoadPacket = SoundLoadPacket | SoundExternalLoadPacket; /** * Audio ACK types */ type AudioAckType = 'sound-loaded' | 'sound-error' | 'playback-started' | 'playback-ended' | 'playback-error'; /** * Base interface for all audio acknowledgments */ interface AudioAckBase { /** Type of acknowledgment */ type: AudioAckType; } /** * ACK: Sound successfully loaded (file or external) */ interface SoundLoadedAck extends AudioAckBase { type: 'sound-loaded'; /** Sound ID that was loaded */ soundId: number; /** Sound name */ name: string; } /** * ACK: Sound failed to load */ interface SoundErrorAck extends AudioAckBase { type: 'sound-error'; /** Sound ID that failed */ soundId: number; /** Sound name */ name: string; /** Error message */ error: string; } /** * ACK: Sound playback started */ interface PlaybackStartedAck extends AudioAckBase { type: 'playback-started'; /** Instance ID of the playing sound */ instanceId: SoundInstanceId; /** Sound ID being played */ soundId: number; } /** * ACK: Sound playback ended (natural end, not stopped) */ interface PlaybackEndedAck extends AudioAckBase { type: 'playback-ended'; /** Instance ID that ended */ instanceId: SoundInstanceId; /** Sound ID that was playing */ soundId: number; } /** * ACK: Sound playback failed */ interface PlaybackErrorAck extends AudioAckBase { type: 'playback-error'; /** Instance ID that failed (if known) */ instanceId?: SoundInstanceId; /** Sound ID or name that was requested */ sound: number | string; /** Error message */ error: string; } /** * Union of all audio ACK types */ type AudioAck = SoundLoadedAck | SoundErrorAck | PlaybackStartedAck | PlaybackEndedAck | PlaybackErrorAck; /** * Callback type for audio ACK events on server */ type AudioAckHandler = (userId: string, ack: AudioAck) => void; /** * Unique identifier for a playing sound instance * Allows multiple instances of the same sound to play simultaneously * and be controlled independently */ type SoundInstanceId = number; /** * Command to play a sound on the client * Sent from server to trigger sound playback */ interface PlaySoundCommand { /** Sound ID or name to play */ sound: number | string; /** Unique instance ID for this playback (allows stopping specific instances) */ instanceId?: SoundInstanceId; /** Volume multiplier (0.0 to 1.0) */ volume?: number; /** Pitch/playback rate (0.5 = octave down, 2.0 = octave up) */ pitch?: number; /** Loop the sound */ loop?: boolean; /** Fade in duration in seconds (0 = no fade, default: 0) */ fadeIn?: number; /** X position for spatial audio (0-65535, 16-bit). Must be set with y. */ x?: number; /** Y position for spatial audio (0-65535, 16-bit). Must be set with x. */ y?: number; /** Low-pass filter cutoff frequency in Hz (100-25500, 0 or undefined = disabled) */ lowpass?: number; /** High-pass filter cutoff frequency in Hz (100-25500, 0 or undefined = disabled) */ highpass?: number; /** Reverb wet/dry mix (0.0-1.0, 0 or undefined = disabled) */ reverb?: number; } /** * Command to stop a sound on the client */ interface StopSoundCommand { /** * What to stop: * - SoundInstanceId (number > 0): Stop specific instance * - Sound name (string): Stop all instances of that sound * - 'all': Stop all sounds */ sound: SoundInstanceId | string | 'all'; } /** * Command to fade out a sound on the client */ interface FadeOutSoundCommand { /** Marker to identify this as a fade-out command */ fadeOut: true; /** * What to fade out: * - SoundInstanceId (number > 0): Fade out specific instance * - Sound name (string): Fade out all instances of that sound * - 'all': Fade out all sounds */ sound: SoundInstanceId | string | 'all'; /** Fade out duration in seconds */ duration: number; } /** * Command to pause a sound on the client */ interface PauseSoundCommand { /** Marker to identify this as a pause command */ pause: true; /** * What to pause: * - SoundInstanceId (number > 0): Pause specific instance * - Sound name (string): Pause all instances of that sound * - 'all': Pause all sounds */ sound: SoundInstanceId | string | 'all'; } /** * Command to resume a paused sound on the client */ interface ResumeSoundCommand { /** Marker to identify this as a resume command */ resume: true; /** * What to resume: * - SoundInstanceId (number > 0): Resume specific instance * - Sound name (string): Resume all instances of that sound * - 'all': Resume all paused sounds */ sound: SoundInstanceId | string | 'all'; } /** * Command to update audio effects on a playing sound */ interface SetSoundEffectsCommand { /** Marker to identify this as a set-effects command */ setEffects: true; /** Target instance ID */ instanceId: SoundInstanceId; /** Low-pass filter cutoff frequency in Hz (100-25500, 0 = disable) */ lowpass?: number; /** High-pass filter cutoff frequency in Hz (100-25500, 0 = disable) */ highpass?: number; /** Reverb wet/dry mix (0.0-1.0, 0 = disable) */ reverb?: number; } /** * Command to set the listener position for spatial audio */ interface SetListenerPositionCommand { type: 'set-listener-position'; /** X position (0-65535) */ x: number; /** Y position (0-65535) */ y: number; } /** * Command to configure spatial audio parameters */ interface ConfigureSpatialCommand { type: 'configure-spatial'; /** Maximum audible distance */ maxDistance?: number; /** Reference distance (full volume) */ referenceDistance?: number; /** Rolloff factor */ rolloffFactor?: number; /** Pan spread (0-1) */ panSpread?: number; } /** * Union of all audio configuration commands */ type AudioConfigCommand = SetListenerPositionCommand | ConfigureSpatialCommand; /** * Configuration for 2D spatial audio (listener position) */ interface SpatialAudioConfig { /** Listener X position (0-65535) - where the "ear" is */ listenerX: number; /** Listener Y position (0-65535) - where the "ear" is */ listenerY: number; /** Maximum audible distance (beyond this, volume = 0) */ maxDistance: number; /** Reference distance (volume = 1.0 at this distance) */ referenceDistance: number; /** Rolloff factor for distance attenuation (higher = faster falloff) */ rolloffFactor: number; /** Pan spread factor (how much X offset affects stereo pan, 0-1) */ panSpread: number; } /** * Options for playing a sound via IAudioProcessor */ interface AudioPlayOptions { /** Volume multiplier (0.0 to 1.0, default: 1.0) */ volume?: number; /** Playback rate / pitch (0.5 = octave down, 2.0 = octave up, default: 1.0) */ pitch?: number; /** Loop the sound (default: false) */ loop?: boolean; /** Fade in duration in seconds (0 = no fade, default: 0) */ fadeIn?: number; /** Spatial position for 2D positional audio */ position?: { x: number; y: number; }; /** Instance ID (provided by server in connected mode, auto-generated otherwise) */ instanceId?: number; /** Low-pass filter cutoff frequency in Hz (100-25500, 0 = disable) */ lowpass?: number; /** High-pass filter cutoff frequency in Hz (100-25500, 0 = disable) */ highpass?: number; /** Reverb wet/dry mix (0.0-1.0, 0 = disable) */ reverb?: number; } /** * Result of playing a sound */ interface AudioPlayResult { /** Unique instance ID for this playback */ instanceId: number; } /** * Spatial audio configuration options */ interface AudioSpatialOptions { /** Maximum audible distance */ maxDistance?: number; /** Reference distance (full volume) */ referenceDistance?: number; /** Rolloff factor */ rolloffFactor?: number; /** Pan spread (0-1) */ panSpread?: number; } /** * Interface for audio playback processing * * Implemented by AudioManager in @utsp/audio. * Used by User in @utsp/core to play sounds without direct dependency on AudioManager. * * This abstraction allows: * - Standalone mode: ClientRuntime injects AudioManager * - Connected mode: NetworkSync uses the same interface via User * - No circular dependency: Core → Types ← Audio * * @example * ```typescript * // In ClientRuntime * user.setAudioProcessor(audioManager); * * // In User.applyAudioCommands() * this.audioProcessor?.play('coin', { volume: 0.8 }); * ``` */ interface IAudioProcessor { /** * Play a sound by name or ID * @param sound - Sound name (string) or ID (number) * @param options - Playback options * @returns Play result with instanceId, or null if sound not found */ play(sound: string | number, options?: AudioPlayOptions): AudioPlayResult | null; /** * Stop sound(s) immediately * @param target - Instance ID (number) to stop specific instance, * or sound name (string) to stop all instances of that sound * @returns Number of instances stopped */ stop(target: number | string): number; /** * Fade out and stop sound(s) * @param target - Instance ID (number) to fade specific instance, * or sound name (string) to fade all instances of that sound, * or 'all' to fade all sounds * @param duration - Fade duration in seconds * @returns Number of instances being faded */ fadeOut(target: number | string | 'all', duration: number): number; /** * Stop all playing sounds immediately * @returns Number of instances stopped */ stopAll(): number; /** * Pause sound(s) * @param target - Instance ID (number) to pause specific instance, * or sound name (string) to pause all instances of that sound, * or 'all' to pause all sounds * @returns Number of instances paused */ pause(target: number | string | 'all'): number; /** * Resume paused sound(s) * @param target - Instance ID (number) to resume specific instance, * or sound name (string) to resume all instances of that sound, * or 'all' to resume all paused sounds * @returns Number of instances resumed */ resume(target: number | string | 'all'): number; /** * Set the listener position for spatial audio * @param x - X position (0-65535) * @param y - Y position (0-65535) */ setListenerPosition(x: number, y: number): void; /** * Configure spatial audio parameters * @param config - Spatial audio options */ configureSpatial(config: AudioSpatialOptions): void; /** * Set audio effects on a playing sound * @param instanceId - The sound instance ID * @param lowpass - Low-pass filter cutoff Hz (0 = disable) * @param highpass - High-pass filter cutoff Hz (0 = disable) * @param reverb - Reverb mix 0.0-1.0 (0 = disable) */ setEffects(instanceId: number, lowpass?: number, highpass?: number, reverb?: number): void; /** * Stop all instances of a sound by soundId (0-255) * Used when the client receives a StopSound order with targetType=SoundId * @param soundId - The sound ID to stop all instances of * @returns Number of instances stopped */ stopBySoundId(soundId: number): number; /** * Fade out all instances of a sound by soundId (0-255) * @param soundId - The sound ID to fade out all instances of * @param duration - Fade duration in seconds * @returns Number of instances being faded */ fadeOutBySoundId(soundId: number, duration: number): number; /** * Pause all instances of a sound by soundId (0-255) * @param soundId - The sound ID to pause all instances of * @returns Number of instances paused */ pauseBySoundId(soundId: number): number; /** * Resume all instances of a sound by soundId (0-255) * @param soundId - The sound ID to resume all instances of * @returns Number of instances resumed */ resumeBySoundId(soundId: number): number; } /** * Interface for loading sounds into the audio system * * Implemented by SoundBank in @utsp/audio. * Abstracts the difference between Browser (Web Audio API) and Node.js environments. * * @example * ```typescript * // File mode - embedded data * await soundLoader.loadFromData(0, 'coin', audioData); * * // External mode - URL * await soundLoader.loadFromUrl(1, 'music', 'https://cdn.example.com/music.mp3'); * ``` */ interface ISoundLoader { /** * Load a sound from binary data (File mode) * @param soundId - Unique sound identifier (0-255) * @param name - Human-readable name for playback * @param data - Raw audio data (mp3, wav, ogg, etc.) */ loadFromData(soundId: number, name: string, data: Uint8Array): Promise; /** * Load a sound from a URL (External mode) * @param soundId - Unique sound identifier (0-255) * @param name - Human-readable name for playback * @param url - URL to fetch the audio from */ loadFromUrl(soundId: number, name: string, url: string): Promise; /** * Check if a sound is loaded * @param nameOrId - Sound name or ID * @returns true if sound is loaded and ready to play */ has(nameOrId: string | number): boolean; } /** * Common interface for all UTSP Runtimes (Server, Client, Standalone). * Allows IApplication to interact with the underlying execution environment * in a type-safe way. */ interface IRuntime { /** * Get the current execution mode */ getMode(): string; /** * Check if the runtime is currently running */ isRunning(): boolean; /** * Get current tick rate (TPS) */ getTickRate(): number; /** * Set the tick rate (TPS) */ setTickRate(tickRate: number): void; /** * Disconnect a user from the game * In Server mode: Kicks the specified user. * In Client mode: Usually only applicable to the local user or ignored. * * @param userId - ID of the user to disconnect * @param reason - Optional reason for disconnection * @returns true if the disconnection was initiated */ disconnectUser(userId: string, reason?: string): boolean; /** * Get runtime statistics */ getStats(): any; /** * Shutdown the runtime */ destroy(): Promise; } /** * Metadata associated with a user when they connect to a runtime. * Includes both authentication info and client-provided preferences. */ interface UserMetadata { /** * User name (e.g. 'Player1', 'Admin') */ username: string; /** * Authentication token or object (optional) */ token?: string | Record; /** * Client-specific preferences or state (optional) */ preferences?: Record; /** * Any other context-specific data */ [key: string]: any; } /** * Application lifecycle interface for games, dashboards, signage, etc. * Supports single-user (local) and multi-user (networked) scenarios. * * @template TCore - Core type (typically Core) * @template TUser - User type (typically User) */ interface IApplication { /** * Initialize application (called once at startup, before users) * Can be async if you need to load resources. * @param runtime - Isomorphic runtime instance * @param core - Core instance */ init(runtime: IRuntime, core: TCore): void | Promise; /** * Update global logic (called every frame, runs once) (optional) * Use this for logic that doesn't depend on specific users. * @param runtime - Isomorphic runtime instance * @param core - Core instance * @param deltaTime - Time since last update (seconds) */ update?(runtime: IRuntime, core: TCore, deltaTime: number): void; /** * Initialize new user (called when user connects/joins) * @param runtime - Isomorphic runtime instance * @param core - Core instance * @param user - User instance * @param metadata - Optional user metadata (username, preferences, etc.) */ initUser(runtime: IRuntime, core: TCore, user: TUser, metadata?: UserMetadata): void; /** * Update user-specific logic (called every frame per user) * @param runtime - Isomorphic runtime instance * @param core - Core instance * @param user - User instance * @param deltaTime - Time since last update (seconds) */ updateUser(runtime: IRuntime, core: TCore, user: TUser, deltaTime: number): void; /** * Cleanup when user disconnects (optional) * @param runtime - Isomorphic runtime instance * @param core - Core instance * @param user - User instance * @param reason - Disconnect reason (optional) */ destroyUser?(runtime: IRuntime, core: TCore, user: TUser, reason?: string): void; /** * Cleanup when application shuts down (optional) * @param runtime - Runtime instance */ destroy?(runtime: IRuntime): void; /** * Commit changes after all updates (optional) * Called after update() and all updateUser() to trigger render/broadcast. * @param runtime - Isomorphic runtime instance * @param core - Core instance * @param deltaTime - Time since last update (seconds) */ onCommit?(runtime: IRuntime, core: TCore, deltaTime: number): void; /** * Handle audio acknowledgments from clients (optional, server mode only) * * Called when a client sends an audio-ack message (sound loaded, playback started/ended, error). * Useful for: * - Waiting for sounds to load before playing them * - Tracking playback state across clients * - Handling audio errors gracefully * * @param runtime - Isomorphic runtime instance * @param core - Core instance * @param user - User who sent the ACK * @param ack - The audio acknowledgment * * @example * ```typescript * onAudioAck(core, user, runtime, ack) { * if (ack.type === 'sound-loaded') { * console.log(`User ${user.id} loaded sound ${ack.name}`); * // Now safe to play this sound for this user * } else if (ack.type === 'playback-ended') { * console.log(`Sound instance ${ack.instanceId} finished`); * } * } * ``` */ onAudioAck?(runtime: IRuntime, core: TCore, user: TUser, ack: AudioAck): void; /** * Handle bridge messages from clients (optional, server mode only) * * Called when a client sends a bridge message via `networkClient.sendBridge(channel, data)`. * The Bridge Channel allows custom bidirectional communication between the server * and external client applications (React, HTML, etc.) bypassing the UTSP protocol. * * Useful for: * - Chat messages * - Custom UI commands * - Game lobbies and matchmaking * - Debug/admin commands * - Integration with external systems * * @param runtime - Isomorphic runtime instance * @param core - Core instance * @param user - User who sent the message * @param channel - The bridge channel name (e.g., 'chat', 'lobby', 'debug') * @param data - The message data (JSON parsed from client) * * @example * ```typescript * onBridgeMessage(core, user, runtime, channel, data) { * if (channel === 'chat') { * const { message } = data as { message: string }; * console.log(`[Chat] ${user.id}: ${message}`); * // Broadcast to all users or handle as needed * } else if (channel === 'ready') { * // Mark user as ready in lobby * this.readyPlayers.add(user.id); * } * } * ``` */ onBridgeMessage?(runtime: IRuntime, core: TCore, user: TUser, channel: string, data: unknown): void; /** * Handle errors during execution (optional) * @param runtime - Isomorphic runtime instance * @param core - Core instance * @param error - The error that occurred * @param context - Error context (phase, user, timestamp) * @returns true to continue, false to stop runtime */ onError?(runtime: IRuntime, core: TCore, error: Error, context: { phase: 'init' | 'update' | 'initUser' | 'updateUser' | 'destroyUser' | 'destroy'; user?: TUser; timestamp: number; }): boolean; } /** * Vibration types for tactile feedback * * Supports both mobile vibration (Navigator Vibration API) and * gamepad vibration (Gamepad API dual-motor rumble). * * @packageDocumentation */ /** * Vibration pattern: single duration or array of [vibrate, pause, vibrate, ...] */ type VibrationPattern = number | readonly number[]; /** * Command to trigger a vibration on mobile device */ interface VibrateCommand { /** Vibration pattern in milliseconds */ pattern: VibrationPattern; /** Optional intensity (0.0 to 1.0, default 1.0). Scales the pattern durations. */ intensity?: number; } /** * Command to cancel mobile vibration */ interface CancelVibrationCommand { /** Marker to identify this as a cancel command */ cancel: true; } /** * Union type for mobile vibration commands */ type MobileVibrationCommand = VibrateCommand | CancelVibrationCommand; /** * Interface for mobile vibration processor (implemented by MobileVibration class in @utsp/input) */ interface IMobileVibrationProcessor { /** Check if vibration is supported on this device */ isSupported(): boolean; /** Check if vibration is enabled */ isEnabled(): boolean; /** Trigger a vibration with the given pattern */ vibrate(pattern: VibrationPattern): boolean; /** Cancel any ongoing vibration */ cancel(): void; } /** * Mobile vibration preset names */ type MobileVibrationPreset = 'tap' | 'mediumTap' | 'heavyTap' | 'success' | 'error' | 'warning' | 'selection' | 'impactLight' | 'impactMedium' | 'impactHeavy' | 'notification'; /** * Gamepad vibration options for dual-motor controllers * * Modern gamepads have two motors: * - Strong motor (low frequency): Heavy rumble, felt in the palm * - Weak motor (high frequency): Light vibration, felt in the fingers */ interface GamepadVibrationOptions { /** Duration in milliseconds */ duration: number; /** Strong motor magnitude (0.0 - 1.0), low frequency rumble */ strongMagnitude?: number; /** Weak motor magnitude (0.0 - 1.0), high frequency vibration */ weakMagnitude?: number; /** Start delay in milliseconds (default: 0) */ startDelay?: number; } /** * Command to trigger gamepad vibration */ interface GamepadVibrateCommand { /** Gamepad index (0-3), or 'all' for all connected gamepads */ gamepadIndex: number | 'all'; /** Vibration options */ options: GamepadVibrationOptions; } /** * Command to stop gamepad vibration */ interface GamepadCancelVibrationCommand { /** Gamepad index (0-3), or 'all' for all connected gamepads */ gamepadIndex: number | 'all'; /** Marker to identify this as a cancel command */ cancel: true; } /** * Union type for gamepad vibration commands */ type GamepadVibrationCommand = GamepadVibrateCommand | GamepadCancelVibrationCommand; /** * Interface for gamepad vibration processor */ interface IGamepadVibrationProcessor { /** Check if a gamepad supports vibration */ supportsVibration(gamepadIndex: number): boolean; /** Vibrate a specific gamepad */ vibrate(gamepadIndex: number, options: GamepadVibrationOptions): Promise; /** Stop vibration on a specific gamepad */ stopVibration(gamepadIndex: number): Promise; /** Stop vibration on all gamepads */ stopAllVibrations(): Promise; } /** * Gamepad vibration preset names */ type GamepadVibrationPreset = 'tap' | 'impact' | 'heavy' | 'success' | 'error' | 'explosion' | 'engine' | 'heartbeat'; export { GRID_DEFAULTS, GamepadInput, InputDeviceType, KeyboardInput, MouseInput, NetworkEvent, NetworkState, NetworkTransportType, POST_PROCESS_DEFAULTS, ScalingMode, ScalingModeValue, TVRemoteInput, TouchInput, TouchZoneInput, Vector2, Vector3, createInputDescriptor, deserializeInputDescriptor, gamepadAxisIndexToInput, gamepadButtonIndexToInput, getTouchXAxis, getTouchYAxis, getTouchZoneXAxis, getTouchZoneYAxis, inputDescriptorToString, isAxis, isButton, isGamepadAxis, isGamepadButton, isMouseAxis, isMouseButton, isNetworkEvent, isTVRemoteAxis, isTVRemoteButton, isTouchButton, isTouchGesture, isTouchPosition, isTouchZoneButton, isTouchZonePosition, keyCodeToKeyboardInput, keyboardInputToKeyCode, parseInputDescriptor, scalingModeToValue, serializeInputDescriptor, valueToScalingMode }; export type { AmbientEffectConfig, AnyNetworkMessage, AnySoundLoadPacket, AudioAck, AudioAckBase, AudioAckHandler, AudioAckType, AudioConfigCommand, AudioPlayOptions, AudioPlayResult, AudioSpatialOptions, AxisBinding, AxisSource, BridgeClientHandler, BridgeServerHandler, ButtonBinding, ButtonSource, CancelVibrationCommand, ChatMessage, ClientInfo, ConfigureSpatialCommand, ConnectionHandler, DisconnectionHandler, ErrorMessage, FadeOutSoundCommand, GamepadCancelVibrationCommand, GamepadInputDescriptor, GamepadVibrateCommand, GamepadVibrationCommand, GamepadVibrationOptions, GamepadVibrationPreset, GridConfig, IApplication, IAudioProcessor, IColorPalette, IGamepadVibrationProcessor, IInputSystem, IMobileVibrationProcessor, INetworkClient, INetworkServer, IRenderer, IRuntime, ISoundLoader, InputBindingLoadPacket, InputDescriptor, InputEnum, InputMessage, JoinMessage, JoinResponseMessage, KeyboardInputDescriptor, LeaveMessage, LoadMessage, MessageType, MobileVibrationCommand, MobileVibrationPreset, MouseInputDescriptor, NetworkClientOptions, NetworkEventHandler, NetworkMessage, NetworkServerOptions, PauseSoundCommand, PingMessage, PlaySoundCommand, PlaybackEndedAck, PlaybackErrorAck, PlaybackStartedAck, PongMessage, PostProcessCommand, PostProcessCommandType, PostProcessConfig, RGBColor, RenderPassState, RenderState, RenderedCell, ResumeSoundCommand, ScanlinesConfig, ServerEventHandler, SetListenerPositionCommand, SetSoundEffectsCommand, SignalingInfo, SoundErrorAck, SoundExternalEntry, SoundExternalLoadPacket, SoundFileEntry, SoundFormat, SoundInstanceId, SoundLoadPacket, SoundLoadType, SoundLoadedAck, SpatialAudioConfig, StopSoundCommand, TVRemoteInputDescriptor, TouchInputDescriptor, TouchZoneBinding, TypedInputDescriptor, UpdateMessage, UserMetadata, UserRenderState, VibrateCommand, VibrationPattern };