UNPKG

@utsp/types

Version:

Type definitions and interfaces for UTSP (Universal Text Stream Protocol)

1,489 lines (1,464 loc) 44.4 kB
/** * 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 } /** * 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'; /** 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; } /** * 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[]; } /** * 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 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; /** * 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; /** * 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 TVRemoteInputDescriptor { device: InputDeviceType.TVRemote; input: TVRemoteInput; } /** * Discriminated union of all input descriptors */ type TypedInputDescriptor = KeyboardInputDescriptor | MouseInputDescriptor | GamepadInputDescriptor | TouchInputDescriptor | TVRemoteInputDescriptor; /** * Helper to create a typed input descriptor */ declare function createInputDescriptor<T extends InputDeviceType>(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 : 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; /** 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; } /** * Display render state with cells and color palette */ interface RenderState { /** Width in cells */ width: number; /** Height in cells */ height: number; /** Cell array (length = width × height) */ cells: RenderedCell[]; /** Color palette (256 colors) */ palette: RGBColor$1[]; } /** * 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 bitmap font for character rendering * @param font - Map of character codes to bitmap data (Uint8Array per character) * @param charWidth - Character width in pixels * @param charHeight - Character height in pixels * @param cellWidth - Cell width in pixels (includes spacing) * @param cellHeight - Cell height in pixels (includes spacing) */ setBitmapFont(font: Map<number, Uint8Array>, charWidth: number, charHeight: number, cellWidth: number, cellHeight: number): void; /** * 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; } /** * Network client interface for client-to-server communication * Implementations: Socket.IO, WebRTC, WebSocket, etc. */ /** Event handler callback */ type NetworkEventHandler<T = any> = (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<string, any>; /** Debug logging */ debug?: boolean; } /** Network client interface */ interface INetworkClient { /** Current state */ readonly state: NetworkState; /** Check if connected */ isConnected(): boolean; /** Connect to server */ connect(): Promise<void>; /** Disconnect from server */ disconnect(): void; /** Send event to server */ send(event: string, data: any): void; /** Listen for server events */ on<T = any>(event: string, handler: NetworkEventHandler<T>): void; /** Remove event listener */ off<T = any>(event: string, handler: NetworkEventHandler<T>): void; /** Remove all listeners for event */ removeAllListeners(event?: string): void; /** Send and wait for response */ request<T = any>(event: string, data: any, timeout?: number): Promise<T>; /** Get ping to server (ms) */ getPing(): number; /** Cleanup */ destroy(): void; } /** * Network server interface for server-side communication * Implementations: Socket.IO, WebRTC, WebSocket, etc. */ /** Server event handler */ type ServerEventHandler<T = any> = (clientId: string, data: T) => void; /** Connection handler */ type ConnectionHandler = (clientId: string) => void; /** Disconnection handler */ type DisconnectionHandler = (clientId: string, reason: string) => 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; } /** Client info */ interface ClientInfo { /** Client ID */ id: string; /** Connection timestamp */ connectedAt: number; /** IP address */ address: string; /** Custom data */ data: Record<string, any>; } /** Network server interface */ interface INetworkServer { /** Check if running */ isRunning(): boolean; /** Start server */ start(): Promise<void>; /** Stop server */ stop(): Promise<void>; /** 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<T = any>(event: string, handler: ServerEventHandler<T>): void; /** Listen for connections */ onConnect(handler: ConnectionHandler): void; /** Listen for disconnections */ onDisconnect(handler: DisconnectionHandler): void; /** Remove listener */ off<T = any>(event: string, handler: ServerEventHandler<T>): 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; }; /** Cleanup */ destroy(): Promise<void>; } /** * 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']; /** * 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) * @template TRuntime - Runtime type (optional) */ interface IApplication<TCore = any, TUser = any, TRuntime = unknown> { /** * Initialize application (called once at startup, before users) * Can be async if you need to load resources. * @param core - Core instance * @param runtime - Runtime instance (optional) */ init(core: TCore, runtime?: TRuntime): void | Promise<void>; /** * Update global logic (called every frame, runs once) * @param core - Core instance * @param deltaTime - Time since last update (seconds) */ update(core: TCore, deltaTime: number): void; /** * Initialize new user (called when user connects/joins) * @param core - Core instance * @param user - User instance * @param metadata - Optional user metadata (username, preferences, etc.) */ initUser(core: TCore, user: TUser, metadata?: UserMetadata): void; /** * Update user-specific logic (called every frame per user) * @param core - Core instance * @param user - User instance * @param deltaTime - Time since last update (seconds) */ updateUser(core: TCore, user: TUser, deltaTime: number): void; /** * Cleanup when user disconnects (optional) * @param core - Core instance * @param user - User instance * @param reason - Disconnect reason (optional) */ destroyUser?(core: TCore, user: TUser, reason?: string): void; /** * Cleanup when application shuts down (optional) */ destroy?(): void; /** * Commit changes after all updates (optional) * Called after update() and all updateUser() to trigger render/broadcast. * @param core - Core instance * @param deltaTime - Time since last update (seconds) */ onCommit?(core: TCore, deltaTime: number): void; /** * Handle errors during execution (optional) * @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?(core: TCore, error: Error, context: { phase: 'init' | 'update' | 'initUser' | 'updateUser' | 'destroyUser' | 'destroy'; user?: TUser; timestamp: number; }): boolean; } /** * User metadata for initUser */ interface UserMetadata { /** Display name */ username?: string; /** Avatar/skin ID */ avatar?: string | number; /** Team/faction */ team?: string | number; /** Color preference */ color?: number; /** Theme preference */ theme?: string; /** Auth token */ token?: string; /** Custom data */ [key: string]: unknown; } /** * 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[]; } /** * Sound External Load packet - External mode * Only URLs are sent, client downloads from external sources */ interface SoundExternalLoadPacket { type: 'sound'; mode: 'external'; sounds: SoundExternalEntry[]; } /** * Union of all sound load packet types */ type AnySoundLoadPacket = SoundLoadPacket | SoundExternalLoadPacket; /** * Client acknowledgment that an external sound was loaded * Sent after successfully downloading and decoding an external sound */ interface SoundLoadedAck { /** Sound ID that was loaded */ soundId: number; /** Loading status */ status: 'loaded' | 'error'; /** Error message if status is 'error' */ error?: string; } /** * 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; /** Spatial position (if set, enables 2D positional audio) */ position?: { /** X position (0-65535, 16-bit) */ x: number; /** Y position (0-65535, 16-bit) */ y: 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 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; } /** * 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; } /** * 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<void>; /** * 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<void>; /** * 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; } export { GamepadInput, InputDeviceType, KeyboardInput, MouseInput, NetworkState, TVRemoteInput, TouchInput, Vector2, Vector3, createInputDescriptor, deserializeInputDescriptor, gamepadAxisIndexToInput, gamepadButtonIndexToInput, getTouchXAxis, getTouchYAxis, inputDescriptorToString, isAxis, isButton, isGamepadAxis, isGamepadButton, isMouseAxis, isMouseButton, isTVRemoteAxis, isTVRemoteButton, isTouchButton, isTouchGesture, isTouchPosition, keyCodeToKeyboardInput, keyboardInputToKeyCode, parseInputDescriptor, serializeInputDescriptor }; export type { AnyNetworkMessage, AnySoundLoadPacket, AudioConfigCommand, AudioPlayOptions, AudioPlayResult, AudioSpatialOptions, AxisBinding, AxisSource, ButtonBinding, ButtonSource, ChatMessage, ClientInfo, ConfigureSpatialCommand, ConnectionHandler, DisconnectionHandler, ErrorMessage, FadeOutSoundCommand, GamepadInputDescriptor, IApplication, IAudioProcessor, IColorPalette, IInputSystem, INetworkClient, INetworkServer, IRenderer, ISoundLoader, InputBindingLoadPacket, InputDescriptor, InputEnum, InputMessage, JoinMessage, JoinResponseMessage, KeyboardInputDescriptor, LeaveMessage, LoadMessage, MessageType, MouseInputDescriptor, NetworkClientOptions, NetworkEventHandler, NetworkMessage, NetworkServerOptions, PauseSoundCommand, PingMessage, PlaySoundCommand, PongMessage, RGBColor, RenderState, RenderedCell, ResumeSoundCommand, ServerEventHandler, SetListenerPositionCommand, SoundExternalEntry, SoundExternalLoadPacket, SoundFileEntry, SoundFormat, SoundInstanceId, SoundLoadPacket, SoundLoadType, SoundLoadedAck, SpatialAudioConfig, StopSoundCommand, TVRemoteInputDescriptor, TouchInputDescriptor, TypedInputDescriptor, UpdateMessage, UserMetadata, UserRenderState };