{"id":44741601,"url":"https://github.com/msobiecki/react-marauders-path","last_synced_at":"2026-04-18T22:11:01.816Z","repository":{"id":313711611,"uuid":"787439579","full_name":"msobiecki/react-marauders-path","owner":"msobiecki","description":"🎹 A lightweight, type-safe React library for handling keyboard and pointer events in a unified way","archived":false,"fork":false,"pushed_at":"2026-04-06T23:47:50.000Z","size":7613,"stargazers_count":0,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-04-07T01:22:06.163Z","etag":null,"topics":["events","hotkeys","keyboard","mouse","pointer","react","shortcuts","touch"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/msobiecki.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-04-16T14:22:41.000Z","updated_at":"2026-04-06T23:47:49.000Z","dependencies_parsed_at":"2026-02-24T21:02:02.628Z","dependency_job_id":null,"html_url":"https://github.com/msobiecki/react-marauders-path","commit_stats":null,"previous_names":["msobiecki/react-marauders-path"],"tags_count":37,"template":false,"template_full_name":null,"purl":"pkg:github/msobiecki/react-marauders-path","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/msobiecki%2Freact-marauders-path","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/msobiecki%2Freact-marauders-path/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/msobiecki%2Freact-marauders-path/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/msobiecki%2Freact-marauders-path/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/msobiecki","download_url":"https://codeload.github.com/msobiecki/react-marauders-path/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/msobiecki%2Freact-marauders-path/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31986489,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-18T20:23:30.271Z","status":"ssl_error","status_checked_at":"2026-04-18T20:23:29.375Z","response_time":103,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["events","hotkeys","keyboard","mouse","pointer","react","shortcuts","touch"],"created_at":"2026-02-15T21:05:27.743Z","updated_at":"2026-04-18T22:11:01.807Z","avatar_url":"https://github.com/msobiecki.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# react-marauders-path\n\n[![License](https://img.shields.io/badge/license-%20%20GNU%20GPLv3%20-green.svg)](https://github.com/msobiecki/react-marauders-path/blob/master/LICENSE)\n\nA lightweight, type-safe React library for handling keyboard, pointer, mouse, wheel, and gesture events including tap, double-tap, press, swipe, drag, and pinch interactions.\n\n![react-marauders-path](./docs/images/logotype.png)\n\n## Features\n\n- 🎹 **Keyboard Event Handling** - Detect single keys, key combinations, and sequences with configurable timing thresholds\n- 🖱️ **Pointer Event Handling** - Detect pointer interactions events with pointer type filtering\n- 🖱️ **Mouse Event Handling** - Detect mouse interactions through a pointer-powered mouse events with button filtering\n- 🖱️ **Mouse Wheel Event Handling** - Detect mouse wheel delta values with optional `requestAnimationFrame` batching for smoother updates\n- 👐 **Gesture Event Handling** - Detect tap, double-tap, press, swipe, drag, and pinch gestures\n  - 👆 **Tap Gesture Handling** - Detect single taps or clicks with configurable movement and duration thresholds\n  - 👆👆 **Double-Tap Gesture Handling** - Detect consecutive taps or clicks with configurable timing and position thresholds\n  - ✋ **Press Gesture Handling** - Detect press-and-hold interactions with configurable delay and movement thresholds\n  - 🖐️ **Swipe Gesture Handling** - Detect directional swipes with configurable distance, velocity, and pointer type filtering\n  - ✊ **Drag Gesture Handling** - Detect movement, deltas, duration, and start/end positions with pointer type filtering and optional `requestAnimationFrame` batching\n  - 🤏 **Pinch Gesture Handling** - Detect two-finger distance, delta, and scale with pointer type filtering and optional `requestAnimationFrame` batching\n\n## Installation\n\n```bash\nnpm install @msobiecki/react-marauders-path\n```\n\n## Quick Start\n\n### Key Event Hook\n\n#### Single Key Pattern\n\n```typescript\nimport { useKey } from '@msobiecki/react-marauders-path';\n\nfunction MyComponent() {\n  useKey('a', (event, key) =\u003e {\n    console.log(`Pressed ${key}`);\n  });\n\n  return \u003cdiv\u003ePress 'a'\u003c/div\u003e;\n}\n```\n\n#### Multiple Single Key Patterns\n\n```typescript\nuseKey([\"a\", \"b\", \"c\"], (event, key) =\u003e {\n  console.log(`Pressed ${key}`);\n});\n```\n\n#### Key Combination Pattern\n\n```typescript\nuseKey(\"a+b\", (event, key) =\u003e {\n  console.log(`Pressed ${key}`);\n});\n```\n\n#### Multiple Key Combination Patterns\n\n```typescript\nuseKey([\"a+b\", \"c+d\"], (event, key) =\u003e {\n  console.log(`Pressed ${key}`);\n});\n```\n\n#### Key Sequence Pattern\n\n```typescript\nuseKey(\"ArrowUp ArrowUp ArrowDown ArrowDown\", (event, key) =\u003e {\n  console.log(`Pressed ${key}`);\n});\n```\n\n#### Multiple Key Sequence Patterns\n\n```typescript\nuseKey(\n  [\"ArrowUp ArrowUp ArrowDown ArrowDown\", \"ArrowLeft ArrowRight\"],\n  (event, key) =\u003e {\n    console.log(`Pressed ${key}`);\n  },\n);\n```\n\n### Pointer Event Hook\n\n```typescript\nimport { usePointer, PointerEventTypes } from '@msobiecki/react-marauders-path';\n\nfunction MyComponent() {\n  usePointer((event, type, data) =\u003e {\n    console.log(`Pointer ${type} at X: ${data.x}, Y: ${data.y}`);\n  }, {\n    eventType: [PointerEventTypes.Down, PointerEventTypes.Move, PointerEventTypes.Up],\n  });\n\n  return \u003cdiv\u003eUse pointer input\u003c/div\u003e;\n}\n```\n\n### Mouse Event Hook\n\n```typescript\nimport { useMouse, MouseEventTypes, MouseButtons } from '@msobiecki/react-marauders-path';\n\nfunction MyComponent() {\n  useMouse((event, type, button, data) =\u003e {\n    console.log(`Mouse ${type} button ${button} at X: ${data.x}, Y: ${data.y}`);\n  }, {\n    eventType: [MouseEventTypes.Move, MouseEventTypes.Click, MouseEventTypes.DoubleClick],\n    eventButtons: [MouseButtons.Left],\n  });\n\n  return \u003cdiv\u003eUse mouse input\u003c/div\u003e;\n}\n```\n\n### Mouse Wheel Event Hook\n\n```typescript\nimport { useWheel } from '@msobiecki/react-marauders-path';\n\nfunction MyComponent() {\n  useWheel((event, data) =\u003e {\n    console.log(`Scrolled - X: ${data.deltaX}, Y: ${data.deltaY}`);\n  });\n\n  return \u003cdiv\u003eScroll to interact\u003c/div\u003e;\n}\n```\n\n### Gesture Event Hook\n\n```typescript\nimport { useGesture } from '@msobiecki/react-marauders-path';\n\nfunction MyComponent() {\n  useGesture('tap', (event, data) =\u003e {\n    console.log(`Tapped at X: ${data.x}, Y: ${data.y}`);\n  }, {\n    threshold: 8,\n  });\n\n  return \u003cdiv\u003eTap to interact\u003c/div\u003e;\n}\n```\n\n#### Tap Event Hook\n\n```typescript\nimport { useTap } from '@msobiecki/react-marauders-path';\n\nfunction MyComponent() {\n  useTap((event, data) =\u003e {\n    console.log(`Tapped at X: ${data.x}, Y: ${data.y}`);\n  });\n\n  return \u003cdiv\u003eTap to interact\u003c/div\u003e;\n}\n```\n\n#### Double Tap Event Hook\n\n```typescript\nimport { useDoubleTap } from '@msobiecki/react-marauders-path';\n\nfunction MyComponent() {\n  useDoubleTap((event, data) =\u003e {\n    console.log(`Double tapped at X: ${data.x}, Y: ${data.y}`);\n  });\n\n  return \u003cdiv\u003eDouble tap to interact\u003c/div\u003e;\n}\n```\n\n#### Press Event Hook\n\n```typescript\nimport { usePress } from '@msobiecki/react-marauders-path';\n\nfunction MyComponent() {\n  usePress((event, data) =\u003e {\n    console.log(`Pressed at X: ${data.x}, Y: ${data.y}`);\n  });\n\n  return \u003cdiv\u003ePress and hold to interact\u003c/div\u003e;\n}\n```\n\n#### Swipe Event Hook\n\n```typescript\nimport { useSwipe } from '@msobiecki/react-marauders-path';\n\nfunction MyComponent() {\n  useSwipe('left', (event, direction, data) =\u003e {\n    console.log(`Swiped ${direction} with velocity ${data.velocity}`);\n  });\n\n  return \u003cdiv\u003eSwipe left\u003c/div\u003e;\n}\n```\n\n#### Drag Event Hook\n\n```typescript\nimport { useDrag } from '@msobiecki/react-marauders-path';\n\nfunction MyComponent() {\n  useDrag((event, data) =\u003e {\n    console.log(`Dragged by X: ${data.deltaX}, Y: ${data.deltaY}`);\n  });\n\n  return \u003cdiv\u003eDrag to interact\u003c/div\u003e;\n}\n```\n\n#### Pinch Event Hook\n\n```typescript\nimport { usePinch } from '@msobiecki/react-marauders-path';\n\nfunction MyComponent() {\n  usePinch((event, data) =\u003e {\n    console.log(`Pinch scale: ${data.scale}, delta: ${data.delta}`);\n  });\n\n  return \u003cdiv\u003ePinch to zoom\u003c/div\u003e;\n}\n```\n\n## API\n\n### `useKey(keyEvent, callback, options?)`\n\nHook for keyboard event handling with support for single keys, combinations, and sequences.\n\n**Parameters:**\n\n- `keyEvent: string | string[]` - Single key, key combination, or key sequence to listen for\n- `callback: (event: KeyboardEvent, key: string) =\u003e void | boolean` - Called when a key event occurs\n- `options?: UseKeyOptions` - Optional configuration\n\n**Options:**\n\n```typescript\ninterface UseKeyOptions {\n  eventType?: \"keyup\" | \"keydown\"; // Default: 'keyup'\n  eventRepeat?: boolean; // Default: false\n  eventCapture?: boolean; // Default: false\n  eventOnce?: boolean; // Default: false\n  eventStopImmediatePropagation?: boolean; // Default: false\n  sequenceThreshold?: number; // Default: 1000 (ms) - Timeout between sequence keys\n  combinationThreshold?: number; // Default: 200 (ms) - Timeout between combination keys\n  container?: RefObject\u003cHTMLElement\u003e; // Default: window\n}\n```\n\n### `usePointer(callback, options?)`\n\nHook for handling pointer events with configurable event types, pointer types, and listener options.\n\n**Parameters:**\n\n- `callback: (event: PointerEvent, type: PointerEventType, data: PointerData) =\u003e void | boolean` - Called when a pointer event occurs\n- `options?: UsePointerOptions` - Optional configuration\n\n**Options:**\n\n```typescript\ninterface UsePointerOptions {\n  eventType?: PointerEventType[]; // Default: [\"pointermove\", \"pointerup\", \"pointerdown\"]\n  eventPointerTypes?: PointerEventPointerType[]; // Default: [\"touch\", \"mouse\", \"pen\"]\n  eventCapture?: boolean; // Default: false\n  eventOnce?: boolean; // Default: false\n  eventStopImmediatePropagation?: boolean; // Default: false\n  container?: RefObject\u003cHTMLElement\u003e; // Default: window\n}\n```\n\n**Pointer Data:**\n\n```typescript\ninterface PointerData {\n  x: number; // Pointer X position\n  y: number; // Pointer Y position\n}\n```\n\n### `useMouse(callback, options?)`\n\nHook for handling mouse-like events through pointer events with button filtering and synthesized click/double-click support.\n\n**Parameters:**\n\n- `callback: (event: MouseEvent, type: MouseEventType, button: MouseButton, data: MouseData) =\u003e void | boolean` - Called when a mouse event occurs\n- `options?: UseMouseOptions` - Optional configuration\n\n**Options:**\n\n```typescript\ninterface UseMouseOptions {\n  eventType?: MouseEventType[]; // Default: [\"mousemove\", \"mousedown\", \"mouseup\", \"click\", \"dblclick\"]\n  eventButtons?: MouseButton[]; // Default: [0, 1, 2]\n  eventCapture?: boolean; // Default: false\n  eventOnce?: boolean; // Default: false\n  eventStopImmediatePropagation?: boolean; // Default: false\n  container?: RefObject\u003cHTMLElement\u003e; // Default: window\n}\n```\n\n**Mouse Data:**\n\n```typescript\ninterface MouseData {\n  x: number; // Mouse X position\n  y: number; // Mouse Y position\n  button: 0 | 1 | 2 | 3 | 4; // Active mouse button\n}\n```\n\n### `useWheel(callback, options?)`\n\nHook for handling mouse wheel events with support for different delta modes and options.\n\n**Parameters:**\n\n- `callback: (event: WheelEvent, data: WheelData) =\u003e void | boolean` - Called when a wheel event occurs\n- `options?: UseWheelOptions` - Optional configuration\n\n**Options:**\n\n```typescript\ninterface UseWheelOptions {\n  eventPassive?: boolean; // Default: true\n  eventCapture?: boolean; // Default: false\n  eventOnce?: boolean; // Default: false\n  eventStopImmediatePropagation?: boolean; // Default: false\n  container?: RefObject\u003cHTMLElement\u003e; // Default: window\n  raf?: boolean; // Default: false - Use requestAnimationFrame for batching\n}\n```\n\n**Wheel Data:**\n\n```typescript\ninterface WheelData {\n  deltaX: number; // Delta X value\n  deltaY: number; // Delta Y value\n  deltaZ: number; // Delta Z value\n  deltaMode: number; // Delta mode value\n}\n```\n\n### `useGesture(gesture, callback, options?)`\n\nHook for gesture event handling that delegates to one of the low-level gesture hooks.\n\n**Parameters:**\n\n- `gesture: \"tap\" | \"doubletap\" | \"press\" | \"swipe\" | \"drag\" | \"pinch\"` - Gesture to bind (must stay the same between renders)\n- `callback` - Callback type is inferred from `gesture`\n- `options?` - Options type is inferred from `gesture`\n\n**Swipe-only option:**\n\n- `direction?: SwipeDirection` - Optional direction for `useGesture(\"swipe\", ...)`; defaults to `\"both\"`\n\n**Example:**\n\n```typescript\nuseGesture(\n  \"swipe\",\n  (event, direction, data) =\u003e {\n    console.log(direction, data.velocity);\n  },\n  {\n    direction: \"horizontal\",\n    threshold: 40,\n  },\n);\n```\n\n#### `useTap(callback, options?)`\n\nHook for handling single tap/click interactions.\n\n**Parameters:**\n\n- `callback: (event: PointerEvent, data: TapData) =\u003e void | boolean` - Called when a tap gesture is recognized\n- `options?: UseTapOptions` - Optional configuration\n\n**Options:**\n\n```typescript\ninterface UseTapOptions {\n  eventPointerTypes?: TapEventPointerType[]; // Default: [\"touch\", \"mouse\", \"pen\"]\n  eventCapture?: boolean; // Default: false\n  eventOnce?: boolean; // Default: false\n  eventStopImmediatePropagation?: boolean; // Default: false\n  threshold?: number; // Default: 8 (px) - Maximum movement allowed between pointerdown and pointerup\n  maxDuration?: number; // Default: 250 (ms) - Maximum tap duration\n  container?: RefObject\u003cHTMLElement\u003e; // Default: window\n}\n```\n\n**Tap Data:**\n\n```typescript\ninterface TapData {\n  x: number; // Tap pointerup X\n  y: number; // Tap pointerup Y\n}\n```\n\n#### `useDoubleTap(callback, options?)`\n\nHook for handling double-tap / double-click interactions.\n\n**Parameters:**\n\n- `callback: (event: PointerEvent, data: DoubleTapData) =\u003e void | boolean` - Called when a double tap is recognized\n- `options?: UseDoubleTapOptions` - Optional configuration\n\n**Options:**\n\n```typescript\ninterface UseDoubleTapOptions {\n  eventPointerTypes?: DoubleTapEventPointerType[]; // Default: [\"touch\", \"mouse\", \"pen\"]\n  eventCapture?: boolean; // Default: false\n  eventOnce?: boolean; // Default: false\n  eventStopImmediatePropagation?: boolean; // Default: false\n  delay?: number; // Default: 300 (ms) - Maximum interval between taps\n  threshold?: number; // Default: 8 (px) - Maximum distance between two tap positions\n  container?: RefObject\u003cHTMLElement\u003e; // Default: window\n}\n```\n\n**Double Tap Data:**\n\n```typescript\ninterface DoubleTapData {\n  x: number; // Tap pointerup X\n  y: number; // Tap pointerup Y\n}\n```\n\n#### `usePress(callback, options?)`\n\nHook for handling press-and-hold interactions.\n\n**Parameters:**\n\n- `callback: (event: PointerEvent, data: PressData) =\u003e void | boolean` - Called when a press delay completes\n- `options?: UsePressOptions` - Optional configuration\n\n**Options:**\n\n```typescript\ninterface UsePressOptions {\n  eventPointerTypes?: PressEventPointerType[]; // Default: [\"touch\", \"mouse\", \"pen\"]\n  eventCapture?: boolean; // Default: false\n  eventOnce?: boolean; // Default: false\n  eventStopImmediatePropagation?: boolean; // Default: false\n  delay?: number; // Default: 500 (ms) - Press-and-hold duration required\n  threshold?: number; // Default: 8 (px) - Maximum movement allowed while holding\n  container?: RefObject\u003cHTMLElement\u003e; // Default: window\n}\n```\n\n**Press Data:**\n\n```typescript\ninterface PressData {\n  x: number; // Pointerdown X at press start\n  y: number; // Pointerdown Y at press start\n}\n```\n\n#### `useSwipe(swipe, callback, options?)`\n\nHook for handling touch swipe gestures with configurable distance and velocity thresholds.\n\n**Parameters:**\n\n- `swipe: \"left\" | \"right\" | \"up\" | \"down\" | \"horizontal\" | \"vertical\" | \"both\"` - Allowed directions to listen\n- `callback: (event: PointerEvent, direction: SwipeDirection, data: SwipeData) =\u003e void | boolean` - Called when a swipe event occurs\n- `options?: UseSwipeOptions` - Optional configuration\n\n**Options:**\n\n```typescript\ninterface UseSwipeOptions {\n  eventPointerTypes?: SwipeEventPointerType[]; // Default: [\"touch\", \"mouse\", \"pen\"]\n  eventCapture?: boolean; // Default: false\n  eventOnce?: boolean; // Default: false\n  eventStopImmediatePropagation?: boolean; // Default: false\n  threshold?: number; // Default: 50 (px) - Minimum travel distance\n  velocity?: number; // Default: 0.3 (px/ms) - Minimum average speed\n  container?: RefObject\u003cHTMLElement\u003e; // Default: window\n}\n```\n\n**Swipe Data:**\n\n```typescript\ninterface SwipeData {\n  deltaX: number; // Horizontal travel\n  deltaY: number; // Vertical travel\n  velocity: number; // Average speed (distance / duration)\n  duration: number; // Swipe duration in ms\n}\n```\n\n#### `useDrag(callback, options?)`\n\nHook for handling pointer drag gestures with configurable threshold and pointer types.\n\n**Parameters:**\n\n- `callback: (event: PointerEvent, data: DragData) =\u003e void | boolean` - Called when a drag event occurs\n- `options?: UseDragOptions` - Optional configuration\n\n**Options:**\n\n```typescript\ninterface UseDragOptions {\n  eventPointerTypes?: DragEventPointerType[]; // Default: [\"touch\", \"mouse\", \"pen\"]\n  eventCapture?: boolean; // Default: false\n  eventOnce?: boolean; // Default: false\n  eventStopImmediatePropagation?: boolean; // Default: false\n  threshold?: number; // Default: 0 (px) - Minimum drag distance\n  container?: RefObject\u003cHTMLElement\u003e; // Default: window\n  raf?: boolean; // Default: false - Use requestAnimationFrame for batching\n}\n```\n\n**Drag Data:**\n\n```typescript\ninterface DragData {\n  deltaX: number; // Horizontal movement from drag start\n  deltaY: number; // Vertical movement from drag start\n  movementX: number; // Horizontal movement from previous drag event\n  movementY: number; // Vertical movement from previous drag event\n  duration: number; // Drag duration in ms\n  startX: number; // Drag start X\n  startY: number; // Drag start Y\n  endX: number; // Drag end X\n  endY: number; // Drag end Y\n}\n```\n\n#### `usePinch(callback, options?)`\n\nHook for handling two-pointer pinch gestures with distance and scale tracking.\n\n**Parameters:**\n\n- `callback: (event: PointerEvent, data: PinchData) =\u003e void | boolean` - Called when a pinch event occurs\n- `options?: UsePinchOptions` - Optional configuration\n\n**Options:**\n\n```typescript\ninterface UsePinchOptions {\n  eventPointerTypes?: PinchEventPointerType[]; // Default: [\"touch\"]\n  eventCapture?: boolean; // Default: false\n  eventOnce?: boolean; // Default: false\n  eventStopImmediatePropagation?: boolean; // Default: false\n  threshold?: number; // Default: 0 (px) - Minimum pinch distance change\n  container?: RefObject\u003cHTMLElement\u003e; // Default: window\n  raf?: boolean; // Default: false - Use requestAnimationFrame for batching\n}\n```\n\n**Pinch Data:**\n\n```typescript\ninterface PinchData {\n  distance: number; // Current distance between active pointers\n  delta: number; // Distance change since previous pinch update\n  totalDelta: number; // Distance change since pinch start\n  scale: number; // Current scale ratio (distance / startDistance)\n}\n```\n\n## Advanced Examples\n\n### Using Options for Event Type and Propagation Control\n\n```typescript\nuseKey(\n  \"Enter\",\n  (event, key) =\u003e {\n    handleSubmit();\n  },\n  {\n    eventType: \"keydown\",\n    eventStopImmediatePropagation: true,\n    container: inputRef,\n  },\n);\n```\n\n### Listening for Key Repeat\n\n```typescript\n// Allow repeated key presses to trigger callback (useful for games)\nuseKey(\n  \"ArrowUp\",\n  (event, key) =\u003e {\n    moveUp();\n  },\n  {\n    eventType: \"keydown\",\n    eventRepeat: true,\n  },\n);\n```\n\n### Custom Thresholds for Sequences and Combinations\n\n```typescript\n// Increase threshold for slower typists\nuseKey(\n  \"a b c\",\n  (event, key) =\u003e {\n    console.log(`Sequence: ${key}`);\n  },\n  {\n    sequenceThreshold: 2000, // 2 seconds between keys\n  },\n);\n\n// Increase threshold for combination keys\nuseKey(\n  \"a+b\",\n  (event, key) =\u003e {\n    console.log(`Combination: ${key}`);\n  },\n  {\n    combinationThreshold: 1000, // 1 second window for simultaneous press\n  },\n);\n```\n\n## Examples\n\n### Game Controls\n\nSee the [Cube Game Example](./examples/cube-the-game/) for a full implementation:\n\n```bash\ncd examples/cube-the-game\nnpm install\nnpm run dev\n```\n\nThis example demonstrates:\n\n- Combined mouse, touch, and keyboard input\n\n## Development\n\n### Build\n\n```bash\nnpm run build\n```\n\n### Watch Mode\n\n```bash\nnpm run dev\n```\n\n### Lint\n\n```bash\nnpm run lint\n```\n\n## License\n\nSee [LICENSE](./LICENSE) file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmsobiecki%2Freact-marauders-path","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmsobiecki%2Freact-marauders-path","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmsobiecki%2Freact-marauders-path/lists"}