UNPKG

tiny-essentials

Version:

Collection of small, essential scripts designed to be used across various projects. These simple utilities are crafted for speed, ease of use, and versatility.

981 lines (621 loc) โ€ข 27.9 kB
# ๐ŸŽฎ TinyGamepad TinyGamepad is a powerful and flexible JavaScript library designed to manage gamepad, keyboard, and mouse inputs seamlessly. It supports advanced features like input mapping, combo detection, haptic feedback, and multiple event callbacks โ€” all in a clean, easy-to-use API. Perfect for game developers and interactive apps who want precise control over input devices without hassle. --- ## ๐ŸŽฎ Type Definitions This section documents the key **types**, **structures**, and **callback signatures** used by **TinyGamepad** for handling gamepad, keyboard, and mouse inputs. --- ### ๐Ÿ”‘ `KeyStatus` Represents the **status** of a key or button. ```ts type KeyStatus = { pressed: boolean; // Whether the key is currently pressed value?: number; // Optional analog value value2?: number; // Optional secondary analog value }; ``` --- ### ๐ŸŽฏ `InputMode` Defines the available **input modes**: * `'gamepad-only'` โ†’ Only gamepad input * `'keyboard-only'` โ†’ Only keyboard input * `'both'` โ†’ Accept both gamepad and keyboard ```ts type InputMode = 'gamepad-only' | 'keyboard-only' | 'both'; ``` --- ### ๐Ÿ—บ๏ธ `MappedInputCallback` Callback fired when a **mapped logical input** (e.g., `"Jump"`, `"Shoot"`) is activated or deactivated. ```ts type MappedInputCallback = (payload: { logicalName: string; // Logical input name activeTime: number; // Time active in milliseconds comboTime: number; // Combo sequence timing }) => void; ``` --- ### โŒจ๏ธ `MappedKeyCallback` Callback fired when a **mapped key** (e.g., `"KeyA"`, `"KeyB"`) is activated or deactivated. ```ts type MappedKeyCallback = (payload: { key: string; // Physical key name activeTime: number; // Time active in milliseconds }) => void; ``` --- ### ๐Ÿ“ฆ `PayloadCallback` Generic callback for handling **input events**: ```ts type PayloadCallback = (payload: InputPayload | InputAnalogPayload) => void; ``` --- ### ๐Ÿ”Œ `ConnectionCallback` Callback for **gamepad connection events**: ```ts type ConnectionCallback = (payload: ConnectionPayload) => void; ``` --- ### ๐Ÿ•น๏ธ `InputSequenceCallback` Fired when a **registered input sequence** is fully activated: ```ts type InputSequenceCallback = (timestamp: number) => void; ``` --- ### โŒจ๏ธ `KeySequenceCallback` Fired when a **registered key sequence** is fully activated: ```ts type KeySequenceCallback = (timestamp: number) => void; ``` --- ### ๐Ÿ“š `CallbackList` Union of all possible **callback types** in the event system: ```ts type CallbackList = | ConnectionCallback | PayloadCallback | MappedInputCallback | MappedKeyCallback; ``` --- ### ๐ŸŽฎ `GamepadDeviceSource` Specific gamepad input sources: * `'gamepad-analog'` โ†’ Analog sticks / triggers * `'gamepad-button'` โ†’ Digital buttons ```ts type GamepadDeviceSource = 'gamepad-analog' | 'gamepad-button'; ``` --- ### ๐Ÿ–ฑ๏ธ `DeviceSource` All possible **physical input sources**: * `'mouse'` * `'keyboard'` * `'gamepad-analog'` * `'gamepad-button'` ```ts type DeviceSource = 'mouse' | 'keyboard' | GamepadDeviceSource; ``` --- ### ๐Ÿ“ `DeviceInputType` Describes **input interaction types**: * `'up'` โ†’ Released * `'down'` โ†’ Pressed * `'hold'` โ†’ Held * `'change'` โ†’ Value changed * `'move'` โ†’ Analog motion detected ```ts type DeviceInputType = 'up' | 'down' | 'hold' | 'change' | 'move'; ``` --- ### ๐Ÿ†™ `InputPayload` Payload structure for **digital button input events**: ```ts type InputPayload = { id: string; event?: Event; type: DeviceInputType; source: DeviceSource; key: string; isPressure: boolean; logicalName: string; value: number; value2: number; pressed: boolean; prevPressed?: boolean | null; timestamp: number; gp?: Gamepad; }; ``` --- ### ๐Ÿ“ `InputAnalogPayload` Payload structure for **analog input events**: ```ts type InputAnalogPayload = { id: string; event?: Event; type: DeviceInputType; source: DeviceSource; key: string; logicalName: string; value: number; value2: number; timestamp: number; gp?: Gamepad; }; ``` --- ### ๐Ÿ—‚๏ธ `InputEvents` Internal structure for **digital input tracking**: ```ts type InputEvents = { id: string; event?: Event; key: string; source: DeviceSource; value: number; value2: number; type: DeviceInputType; isPressure: boolean; pressed: boolean; prevPressed?: boolean | null; timestamp: number; gp?: Gamepad; }; ``` --- ### ๐ŸŽš๏ธ `InputAnalogEvents` Internal structure for **analog input tracking**: ```ts type InputAnalogEvents = { id: string; event?: Event; key: string; source: DeviceSource; value: number; value2: number; type: DeviceInputType; timestamp: number; gp?: Gamepad; }; ``` --- ### ๐Ÿ”Œ `ConnectionPayload` Payload for **gamepad connection events**: ```ts type ConnectionPayload = { id: string; timestamp: number; gp: Gamepad; }; ``` --- ### โš™๏ธ `ExportedConfig` Structure for **exporting and importing TinyGamepad configurations**: ```ts type ExportedConfig = { expectedId: string | null; // Expected gamepad ID or null ignoreIds: string[]; // IDs to ignore deadZone: number; // Analog dead zone threshold timeoutComboKeys: number; // Max time between combo inputs axisActiveSensitivity: number; // Analog movement sensitivity inputMap: [string, string | string[]][]; // Logical-to-physical mappings }; ``` --- ## ๐ŸŽฎ Constructor & Input Event Initialization ### โš™๏ธ Constructor ```js constructor({ expectedId = null, inputMode = 'both', ignoreIds = [], deadZone = 0.1, axisActiveSensitivity = 0.3, timeoutComboKeys = 500, allowMouse = false, elementBase = window, } = {}) { ... } ``` Initializes a new instance of **TinyGamepad** with customizable input behavior. #### ๐Ÿ”‘ Parameters: | Name | Type | Default | Description | | | | ----------------------- | ------------------- | -------------- | ----------------------------------------------------------------------------------- | -------- | ------------------------------------ | | `expectedId` | `string \| null` | `null` | Specific controller ID to expect; filters gamepads. | | | | `inputMode` | \`'keyboard-only' | 'gamepad-only' | 'both'\` | `'both'` | Selects input sources to listen for. | | `ignoreIds` | `string[]` | `[]` | List of device IDs to ignore during detection. | | | | `deadZone` | `number` | `0.1` | Threshold under which analog stick inputs are ignored (0 to 1). | | | | `axisActiveSensitivity` | `number` | `0.3` | Sensitivity threshold to detect meaningful analog axis movement (0 most sensitive). | | | | `timeoutComboKeys` | `number` | `500` | Time (ms) allowed between inputs in a key sequence before reset. | | | | `allowMouse` | `boolean` | `false` | Whether mouse input events should be treated as triggers. | | | | `elementBase` | `Window \| Element` | `window` | DOM element or window to bind keyboard and mouse event listeners. | | | #### ๐Ÿšจ Validation: * Throws `TypeError` or `RangeError` on invalid types or out-of-range values. * Ensures only valid configurations are accepted. #### ๐Ÿ”ฅ Behavior: * Initializes gamepad event listeners if mode includes `'gamepad-only'` or `'both'`. * Initializes keyboard and mouse listeners if mode includes `'keyboard-only'` or `'both'`. --- ## ๐ŸŽฎ Input Mapping & Sequence Management ### โณ `awaitInputMapping({ timeout, eventName, canMove })` Waits for a single input event from the user and resolves with detailed input info. Useful for input configuration screens where the user chooses a key/button to assign. #### โš™๏ธ Parameters (all optional): | Name | Type | Default | Description | | ----------- | ------- | ---------------- | -------------------------------------------------------- | | `timeout` | number | `10000` ms | How long to wait before resolving with `null` (no input) | | `eventName` | string | `'MappingInput'` | Temporary logical event name used internally | | `canMove` | boolean | `false` | Whether to accept movement inputs like mouse move | #### ๐Ÿ”„ Returns: A `Promise` that resolves with an object: ```ts { key: string | null, // Input identifier ("KeyW", "Button0", "LeftClick") source: DeviceSource | null, // Input origin: "keyboard", "mouse", "gamepad-button", "gamepad-analog" gp?: Gamepad // Gamepad object if the source is a gamepad } ``` --- ### ๐Ÿ› ๏ธ `mapInput(logicalName, physicalInput)` Maps one or multiple physical inputs to a logical input name. | Parameter | Type | Description | | --------------- | ---------------------- | --------------------------------------------------------------- | | `logicalName` | `string` | Logical input identifier (e.g. "Jump") | | `physicalInput` | `string` or `string[]` | Physical input(s) mapped (e.g. "Button1", \["KeyW", "ArrowUp"]) | --- ### โŒ `unmapInput(logicalName)` Removes the mapping for the specified logical input. | Parameter | Type | Description | | ------------- | -------- | ---------------------------------- | | `logicalName` | `string` | Logical input identifier to remove | --- ### ๐Ÿ” `hasMappedInput(logicalName): boolean` Checks if a logical input name has any physical inputs mapped. | Parameter | Type | Returns | | ------------- | -------- | ------------------------------------------- | | `logicalName` | `string` | `true` if mapping exists, otherwise `false` | --- ### ๐Ÿ“‹ `getMappedInput(logicalName): string | string[]` Gets the physical input(s) mapped to a logical input name. | Parameter | Type | Returns | | ------------- | -------- | ------------------------ | | `logicalName` | `string` | Mapped physical input(s) | --- ### ๐Ÿงน `clearMapInputs()` Clears **all** logical to physical input mappings. --- ## ๐Ÿ”— Input Sequences โ€” Logical & Physical #### โžก๏ธ `registerInputSequence(sequence, callback)` Registers a sequence of logical inputs that triggers a callback when fully held. | Parameter | Type | Description | | ---------- | ----------------------- | ----------------------------------------------------------- | | `sequence` | `string[]` | Ordered list of logical inputs (e.g., `['Jump', 'Action']`) | | `callback` | `InputSequenceCallback` | Function invoked when sequence is triggered | --- #### โŒ `unregisterInputSequence(sequence)` Removes a registered logical input sequence. --- #### ๐Ÿงน `unregisterAllInputSequences()` Removes **all** registered logical input sequences. --- #### ๐Ÿ” `hasInputSequence(sequence): boolean` Checks if a logical input sequence is registered. --- #### โžก๏ธ `registerKeySequence(sequence, callback)` Same as `registerInputSequence` but for **physical key** sequences. --- #### โŒ `unregisterKeySequence(sequence)` Unregisters a physical key sequence. --- #### ๐Ÿงน `unregisterAllKeySequences()` Removes all physical key sequences. --- #### ๐Ÿ” `hasKeySequence(sequence): boolean` Checks if a physical key sequence is registered. --- ## โณ Combo Logical Keys Management #### ๐Ÿ”„ `renewComboMapped()` Refreshes the timer that tracks the currently held combo logical keys. Useful to prevent premature combo resets when keys are still being held. --- #### โŒ `resetComboMapped()` Resets and clears all current combo keys and combo inputs, stopping timers and resetting timestamps. --- ## ๐ŸŽฏ Event Listener Methods for Input Events This section covers how to register, unregister, and manage callbacks for various input-related events. Each event type has methods for regular (`on`), one-time (`once`), prepend, and removal of callbacks (`off`). --- ### ๐Ÿ”‘ Mapped Key Events #### `onMappedKeyStart(callback)` Register callback for when a mapped key is **pressed down**. #### `onceMappedKeyStart(callback)` Register a one-time callback that triggers once when a mapped key is pressed. #### `prependMappedKeyStart(callback)` Adds a callback at the start of the callback list for mapped key start. #### `offMappedKeyStart(callback)` Removes a specific callback from mapped key start event. #### `offAllMappedKeyStart()` Removes **all** callbacks from mapped key start event. --- #### `onMappedKeyEnd(callback)` Register callback for when a mapped key is **released**. #### `onceMappedKeyEnd(callback)` One-time callback for mapped key release. #### `prependMappedKeyEnd(callback)` Prepends callback for mapped key release event. #### `offMappedKeyEnd(callback)` Removes a callback from mapped key release event. #### `offAllMappedKeyEnd()` Removes all callbacks from mapped key release event. --- ### ๐ŸŽ›๏ธ Mapped Input Events (includes buttons, analogs, sensors, etc.) #### `onMappedInputStart(callback)` Triggered when any mapped input is activated (pressed or engaged). #### `onceMappedInputStart(callback)` One-time callback for mapped input activation. #### `prependMappedInputStart(callback)` Prepends callback for mapped input start. #### `offMappedInputStart(callback)` Removes a callback from mapped input start. #### `offAllMappedInputStart()` Removes all callbacks from mapped input start. --- #### `onMappedInputEnd(callback)` Triggered when a mapped input is deactivated (released or disengaged). #### `onceMappedInputEnd(callback)` One-time callback for mapped input release. #### `prependMappedInputEnd(callback)` Prepends callback for mapped input end. #### `offMappedInputEnd(callback)` Removes a callback from mapped input end. #### `offAllMappedInputEnd()` Removes all callbacks from mapped input end. --- ### ๐Ÿงฉ Logical Input Events by Name These methods use the logical input names to manage callbacks for different stages of input: | Event Type | Description | | --------------- | ------------------------------------------------- | | `onInput` | Callback on **any** input event | | `onInputStart` | Callback when input is **pressed down** | | `onInputEnd` | Callback when input is **released** | | `onInputHold` | Callback when input is **held down** | | `onInputChange` | Callback on **value changes** (e.g. analog move) | | `onInputMove` | Callback on **movement inputs** (e.g. mouse move) | --- #### Common method patterns for logical inputs: * `on<EventType>(logicalName, callback)` Register a callback for the event. * `once<EventType>(logicalName, callback)` Register a one-time callback for the event. * `prepend<EventType>(logicalName, callback)` Add a callback to the **start** of the callback list. * `off<EventType>(logicalName, callback)` Remove a specific callback. --- #### Example: Logical Input "Jump" pressed down event ```js gamepad.onInputStart('Jump', callback); gamepad.onceInputStart('Jump', callback); gamepad.prependInputStart('Jump', callback); gamepad.offInputStart('Jump', callback); ``` --- #### Detailed List of Methods: | Method | Description | | ------------------------------------- | ----------------------------- | | `onInput(logicalName, callback)` | On any input event | | `onceInput(logicalName, callback)` | One-time on any input | | `prependInput(logicalName, callback)` | Prepend callback on any input | | `offInput(logicalName, callback)` | Remove callback on any input | | Method | Description | | ------------------------------------------ | ------------------------------ | | `onInputStart(logicalName, callback)` | On input pressed down | | `onceInputStart(logicalName, callback)` | One-time on input pressed down | | `prependInputStart(logicalName, callback)` | Prepend on input pressed down | | `offInputStart(logicalName, callback)` | Remove on input pressed down | | Method | Description | | ---------------------------------------- | -------------------------- | | `onInputEnd(logicalName, callback)` | On input released | | `onceInputEnd(logicalName, callback)` | One-time on input released | | `prependInputEnd(logicalName, callback)` | Prepend on input released | | `offInputEnd(logicalName, callback)` | Remove on input released | | Method | Description | | ----------------------------------------- | ------------------------ | | `onInputHold(logicalName, callback)` | While input is held down | | `onceInputHold(logicalName, callback)` | One-time on hold | | `prependInputHold(logicalName, callback)` | Prepend on hold | | `offInputHold(logicalName, callback)` | Remove on hold | | Method | Description | | ------------------------------------------- | ------------------------------------------- | | `onInputChange(logicalName, callback)` | On input value change (e.g., analog change) | | `onceInputChange(logicalName, callback)` | One-time on input change | | `prependInputChange(logicalName, callback)` | Prepend on input change | | `offInputChange(logicalName, callback)` | Remove on input change | | Method | Description | | ----------------------------------------- | ------------------------------------ | | `onInputMove(logicalName, callback)` | On movement input (e.g., mouse move) | | `onceInputMove(logicalName, callback)` | One-time on move | | `prependInputMove(logicalName, callback)` | Prepend on move | | `offInputMove(logicalName, callback)` | Remove on move | --- ## ๐Ÿ“‹ Callback Management for Logical Inputs These methods help you inspect and control the callbacks registered for logical inputs and their event types. --- ### ๐Ÿ” Get Registered Callbacks #### `getCalls(logicalName, type = 'all')` Returns a **shallow clone** of the callback list for a given logical input and event type. * `logicalName`: Logical input name (e.g., "Jump") * `type`: Event type filter โ€” `'all' | 'start' | 'end' | 'hold' | 'change' | 'move'` (default: `'all'`) * Returns an array of registered callback functions. --- ### โŒ Remove All Callbacks for an Input #### `offAllInputs(logicalName, type = 'all')` Removes **all callbacks** for a specific logical input and event type. * `logicalName`: Logical input name * `type`: Event type filter (same as `getCalls`) --- ### ๐Ÿ”ข Count Registered Callbacks #### `getCallSize(logicalName, type = 'all')` Returns the number of callbacks registered for the given logical input and event type. --- ## ๐ŸŽฎ Haptic Feedback (Vibration) Control --- ### โš™๏ธ Default Haptic Effect Settings * Private field storing default effect type and parameters (duration, intensity, etc.) --- ### ๐Ÿ” `get defaultHapticEffect()` Returns the current default haptic feedback effect configuration, including effect type and parameters like duration and intensity. --- ### ๐Ÿ”ง `setDefaultHapticEffect(type, params)` Sets the default haptic feedback effect for gamepad vibration. * `type`: Effect type (e.g., `'dual-rumble'`) * `params`: Effect parameters like duration, intensity --- ### ๐ŸŽต `hasHapticEffect()` Checks if the currently connected gamepad supports vibration feedback. * Returns: `true` if supported, `false` otherwise. --- ### ๐Ÿ“ณ `vibrate(params?, type?)` Triggers a vibration on the connected gamepad using either custom or default parameters. * Returns a Promise resolved when vibration completes. --- ## ๐Ÿšซ Ignoring Specific Input IDs --- ### `ignoreId(id)` Adds an input ID to the ignored list (wonโ€™t trigger events). ### `unignoreId(id)` Removes an input ID from the ignored list. --- ## ๐Ÿ”Œ Gamepad Connection Events --- ### Connection Callbacks | Method | Description | | ---------------------- | -------------------------------------- | | `onConnected(cb)` | Register callback on gamepad connected | | `onceConnected(cb)` | One-time callback on connection | | `prependConnected(cb)` | Prepend callback for connection | | `offConnected(cb)` | Remove callback from connection event | | `offAllConnected()` | Remove **all** connection callbacks | --- ### Disconnection Callbacks | Method | Description | | ------------------------- | ----------------------------------------- | | `onDisconnected(cb)` | Register callback on gamepad disconnected | | `onceDisconnected(cb)` | One-time callback on disconnection | | `prependDisconnected(cb)` | Prepend callback for disconnection | | `offDisconnected(cb)` | Remove callback from disconnection event | | `offAllDisconnected()` | Remove **all** disconnection callbacks | --- ## ๐ŸŽฎ Gamepad Info and State --- ### `hasGamepad()` Returns `true` if a gamepad is currently connected, else `false`. --- ### `getGamepad()` Returns the connected `Gamepad` instance. Throws error if none connected. --- ### Button Last State Tracking #### `hasLastButtonState(index)` Checks if there is a recorded last state for button index. #### `getLastButtonState(index)` Returns a copy of the last known state for a button index. Throws if none recorded. --- ## โš™๏ธ Configuration Export & Import --- ### ๐Ÿ’พ `exportConfig()` Exports the current TinyGamepad settings as a plain object, ready for saving or serialization. Includes: device filters, ignored IDs, input mappings, sensitivities, and timeouts. **Returns:** An object snapshot of the configuration. --- ### ๐Ÿ“ฅ `importConfig(json)` Imports and applies a configuration object or JSON string to update TinyGamepad settings. * Accepts either a JSON string or a config object. * Validates types for each property and throws if invalid. * Updates internal settings accordingly. --- ## ๐Ÿ”„ Callback Lists Getters --- ### ๐Ÿ”‘ Mapped Key Callbacks * `mappedKeyStartCalls` โ€” Gets cloned list of callbacks for `"mapped-key-start"` event. * `mappedKeyEndCalls` โ€” Gets cloned list of callbacks for `"mapped-key-end"` event. --- ### ๐Ÿ”€ Combo Keys and Inputs * `comboMappedKeys` โ€” Clone of currently held **key combo** logical inputs. * `comboMappedInputs` โ€” Clone of currently held **combo logical inputs**. --- ## ๐Ÿ“œ Input Sequence Info --- ### ๐Ÿ”ข Key Sequences * `keySequenceSize` โ€” Number of registered input sequences. * `keySequences` โ€” Clone array of all input sequence callbacks. --- ### ๐Ÿ”‘ Active Mapped Keys & Inputs * `activeMappedKeys` โ€” Clone of currently held mapped logical keys. * `activeMappedInputs` โ€” Clone of currently held mapped logical inputs. --- ## ๐Ÿ”‘ Mapped Input Callbacks * `mappedInputStartCalls` โ€” Cloned callbacks for `"mapped-input-start"`. * `mappedInputEndCalls` โ€” Cloned callbacks for `"mapped-input-end"`. --- ## ๐Ÿงฉ Input Sequences (Again) * `inputSequenceSize` โ€” Number of registered input sequences (physical/logical). * `inputSequences` โ€” Clone array of all input sequence callbacks. --- ## ๐Ÿ—บ๏ธ Logical-to-Physical Mapping Info * `mappedInputs` โ€” Shallow clone object of all logical โ†’ physical input mappings. * `mappedInputSize` โ€” Number of logical inputs currently mapped. --- ## ๐Ÿ”Œ Connection Event Callbacks * `connectedCalls` โ€” Clone of callbacks for `"connected"` event. * `disconnectedCalls` โ€” Clone of callbacks for `"disconnected"` event. --- ## ๐Ÿšซ Ignored Devices & Held Keys * `ignoredDeviceIds` โ€” Clone of currently ignored device IDs. * `heldKeys` โ€” Clone of currently held raw keys. --- ## ๐Ÿ“Š Event Counts & Sizes * `eventsSize` โ€” Total number of registered callbacks (all events). * `callSize` โ€” Number of unique event keys (types). * `connectedCallSize` โ€” Number of callbacks registered for `"connected"`. * `disconnectedCallSize` โ€” Number of callbacks registered for `"disconnected"`. * `mappedKeyStartCallSize` โ€” Callbacks count for `"mapped-key-start"`. * `mappedKeyEndCallSize` โ€” Callbacks count for `"mapped-key-end"`. * `mappedInputStartCallSize` โ€” Callbacks count for `"mapped-input-start"`. * `mappedInputEndCallSize` โ€” Callbacks count for `"mapped-input-end"`. --- ## ๐ŸŽฎ Last Button and Axis States * `lastButtonStates` โ€” Snapshot array of button statuses from last update cycle. * `lastAxes` โ€” Snapshot array of axis values (thumbsticks, triggers) from last update. --- ## ๐ŸŽ›๏ธ Input Modes and Event Targets * `inputMode` โ€” Current input mode (e.g., `'keyboard-only'`, `'gamepad-only'`, `'both'`). * `elementBase` โ€” DOM element or window used for event bindings. --- ## โฐ Timestamps & Timeouts * `timeComboInputs` โ€” Timestamp of last mapped input combo. * `timeComboKeys` โ€” Timestamp of last raw key combo. * `timeMappedInputs` โ€” Timestamp of last mapped input activity. * `timeoutComboKeys` โ€” Timeout in ms before raw key combos reset (getter/setter). --- ## ๐ŸŽš๏ธ Sensitivity & Dead Zone Settings * `axisActiveSensitivity` โ€” Sensitivity threshold for axis movement to count as "active" input (getter/setter). * `deadZone` โ€” Dead zone threshold for analog inputs (getter/setter). --- ## ๐Ÿ†” Device Identification * `expectedId` โ€” Expected device ID filter (getter/setter). --- ## ๐Ÿงน Lifecycle & Cleanup --- ### ๐Ÿ”’ `isDestroyed` **Getter** that returns whether this TinyGamepad instance has been destroyed. * **Returns:** `true` if the instance has been cleaned up and disabled; otherwise `false`. * Use this to check if the instance is still active or has been terminated. --- ### ๐Ÿ—‘๏ธ `destroy()` Cleans up and completely stops all internal input monitoring and loops. * Cancels any ongoing animation frames or loops. * Removes all event listeners (keyboard, mouse, gamepad) based on current input mode. * Resets combos and clears all internal state (maps, callbacks, keys, sequences, etc). * Marks the instance as destroyed (`isDestroyed` becomes `true`). * After calling this, the instance should no longer be used. --- โœจ **Tip:** Always call `destroy()` when you want to cleanly remove TinyGamepad and free resources, especially before discarding the instance or when switching contexts.