---
title: "Input mapping actions bindings keyboard mouse gamepad touch"
description: "Whenever the player needs to control something. All input flows through ONE `InputProfileComponent` per controllable entity. Movement, jump, fire, and look are just actions in its `actions` array."
engineVersion: v1.0.234
date: 2026-09-28
license: "(c) Gessa, proprietary. Cite with attribution to https://gessa.ai/docs/. Terms: https://gessa.ai/terms/."
canonical: https://gessa.ai/docs/knowledge/playbooks/input-mapping-actions-bindings/
---

# Input mapping actions bindings keyboard mouse gamepad touch

## When to use

Whenever the player needs to control something. All input flows through ONE
`InputProfileComponent` per controllable entity. Movement, jump, fire, and look
are just actions in its `actions` array.

## The recipe

1. Attach `InputProfileComponent` with `project_add_component`
   (`project.entity.component.set`):
   `{ "type":"InputProfileComponent", "version":1, "actions":[ ... ] }`.
2. Each action object needs: `key` (stable id), `valueType` (one of `boolean`,
   `float`, `vector1d`, `vector2d`, `vector3d`, `world_target`, `screen2d`,
   `trigger`, `composite`), `contexts` (for example `["gameplay"]`),
   `triggers`, `processors`, `policy`, `prediction`, and `bindings`.
3. `policy.effectSystem` routes the action: `movement`, `action`, `script`, or
   `look`. Set `movement` for WASD, `look` for mouselook (add the `policy.look`
   block), `action` for verbs (fire, interact).
4. `prediction.mode` is `client_predicted` (responsive movement),
   `client_only` (look), or `server_authoritative` (anti-cheat verbs).
5. A binding maps sources to the action:
   `{ "id":"binding.move.wasd", "sources":[{ "device":"keyboard",
   "control":"KeyW", "event":"down", "modifiers":[] }, ...],
   "triggerOverrides":[], "processors":[], "priority":0 }`.
   Valid devices: `keyboard`, `mouse`, `gamepad`, `touch`, `xr`. Valid events:
   `down`, `up`, `press`, `move`, `axis`, `sample`.
6. For a jump button, add a `boolean` action with a `keyboard` `Space` `down`
   binding. For gamepad, add a second binding with `device:"gamepad"`. For
   mobile, add a `touch` binding to the same action; one action, many devices.
7. Shape raw input with `processors[].kind`: `deadzone`, `curve`, `invert`,
   `sensitivity`, `clamp`, `normalize`, `axisComposition`, `stickComposition`,
   `threshold`, `quantize`. Shape timing with `triggers[].kind`: `pressed`,
   `released`, `held`, `tap`, `doubleTap`, `hold`, `chord`, `continuous`,
   `continuous_delta`, `step`, `cancel`.

## Pitfalls

- Trigger and processor `parameters` are discriminated by `kind`. A `hold`
  trigger needs `parameters.durationMs` (1..60000); a `curve` processor needs
  `scale`/`exponent`. Mismatched parameters are rejected; you cannot edit one
  leaf at a time and stay valid.
- `policy.look.sensitivityDeg` is clamped 0.001..45 and pitch bounds -89..89.
- `version` is readonly to most surfaces; keep it 1 unless you are migrating.
- The removed `InputActionDeclarationComponent`, `InputBindingSetComponent`, and
  `InputContextStackComponent` all fold into this one component; never author
  them.

## Verify

- `engine_get_component_schema` on `InputProfileComponent` for projected field
  contracts before writing a binding. Device-dependent control checks live in
  `InputSourceSpecSchema` in `packages/ecs/src/index.ts`; use the native mouse
  binding shown in the first-person-controls playbook for look input.
- `simulation_run` to confirm the action fires on the mapped control.
