| Crates.io | reaction |
| lib.rs | reaction |
| version | 0.2.0 |
| created_at | 2025-12-10 18:03:52.250118+00 |
| updated_at | 2025-12-30 04:12:56.631844+00 |
| description | Universal low-latency input handling for game engines |
| homepage | |
| repository | https://github.com/saptak7777/Reaction |
| max_upload_size | |
| id | 1978542 |
| size | 136,193 |
A lightweight input handling library that might actually respond to you.
Reaction is a zero-cost, action-based input library for Rust game engines. It follows the Unix philosophy (do one thing, hopefully well) and decouples your raw hardware events from your high-level game logic.
Fair Warning: This is a library component, not a game engine. It doesn't render graphics, play sound, or make your coffee. Think of it as the steering wheel and pedals of your car - useless without the rest of the car, but hard to drive without them.
[dependencies]
reaction = "0.2.0"
Space, A) to semantic actions (Jump, Fire).A and D keys) correctly cancel each other out.archetype_ecs (should work with others too).winit or sdl2)Directly query the state of devices. Useful for prototyping or debugging.
use reaction::prelude::*;
fn update(input: &AdvancedInputState) {
// Check if Space is held down
if input.keyboard.is_key_down(KeyCode::Space) {
println!("We are floating!");
}
// Check if Left Mouse Button was just pressed this frame
if input.mouse.is_button_just_pressed(MouseButton::Left) {
println!("Pew pew!");
}
}
Decouple logic from hardware using semantic actions. This is what you should be using for a real game.
use reaction::prelude::*;
// 1. Define Actions
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
enum Action {
Jump,
MoveX,
}
fn main() -> Result<()> {
// 2. Bind Inputs
let mut map = InputMap::new();
// Jump when Space is pressed
map.bind(Action::Jump, BindingConfig::new(InputBinding::Key(KeyCode::Space)))?;
// Move on X axis with Gamepad Stick
map.bind(Action::MoveX, BindingConfig::new(InputBinding::GamepadAxis(GamepadAxis::LeftStickX)))?;
// 3. Query Actions
// (Assume 'input' is populated from your window events)
let input = AdvancedInputState::new();
// Check digital action (boolean)
if map.is_active(Action::Jump, &input, None, 0.5) {
println!("Jumping!");
}
// Check analog action (float [-1.0, 1.0])
let move_speed = map.resolve(Action::MoveX, &input, None);
println!("Moving speed: {}", move_speed);
Ok(())
}
What We've Tested:
~12 ns/iter (Local Benchmark) - It's fast. Very fast.ron because we believe in types.What We Haven't Tested:
"My move inputs aren't canceling out!"
Check:
InputMap::resolve?"Mouse movement feels jittery!"
Check:
input_state.end_frame(dt)? This is critical for clearing deltas."It crashed."
Result? I told you not to do that in production.Contributions are welcome, implies you follow the [CODE_OF_CONDUCT.md].
Please ensure:
cargo test passescargo clippy is cleanLicensed under the Apache License, Version 2.0.
This library wouldn't exist without:
gilrs (for making gamepad support bearable)winit (for the raw events)