vs_humanize/lib.rs
1//! Pure-math input synthesis for vibesurfer's three input modes.
2//!
3//! The crate is intentionally narrow: given a start and end point,
4//! some text to type, or a scroll delta, return a sequence of
5//! discrete `Step`s tagged with relative time. The engine crate
6//! consumes that sequence and translates each step into a
7//! platform-native event (`NSEvent` on macOS, `GdkEvent` on Linux,
8//! `Input.dispatchMouseEvent` over CDP on Windows).
9//!
10//! The split keeps the math testable without WebKit and the
11//! per-platform code testable without doing humanization math. It
12//! also concentrates the realism work in one place: improving the
13//! Bezier sampler or the keystroke distribution lifts every backend
14//! at once.
15//!
16//! ## Modes
17//!
18//! | Mode | Sequence shape |
19//! |---------|-----------------------------------------------|
20//! | Human | Bezier path, Fitts arrival, digraph keys |
21//! | Careful | Single-shot dispatch, no path or per-key delay|
22//! | Robotic | Empty sequence — caller falls back to JS path |
23//!
24//! See [`InputMode`] for details.
25//!
26//! ## Determinism
27//!
28//! Every entry point takes a `seed: u64`. Same seed + same inputs
29//! produce byte-identical output. This lets tests assert exact
30//! sequences and lets the daemon persist a per-session seed so a
31//! given agent produces consistent typing patterns across runs
32//! against the same site.
33
34mod keys;
35mod mouse;
36mod rng;
37mod scroll;
38
39pub use keys::{key_sequence, Key, KeyStep, KeyStepKind};
40pub use mouse::{mouse_path, MouseButton, MouseStep, MouseStepKind, Point};
41pub use scroll::{scroll_sequence, Vec2, WheelStep};
42
43/// Which input style to synthesize.
44///
45/// `Human` produces multi-event sequences with realistic timing.
46/// `Careful` produces single-shot sequences with no behavioral
47/// synthesis but still uses the trusted-event dispatch path on the
48/// engine side. `Robotic` produces an empty sequence — the engine
49/// reads the empty vector as a signal to fall back to JS synthetic
50/// dispatch (the historical vibesurfer behavior).
51#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
52pub enum InputMode {
53 /// Bezier paths, Fitts-law arrival times, digraph-distributed
54 /// keystroke gaps, occasional typo + correction. Bounded total
55 /// duration (see per-function docs).
56 Human,
57 /// Single-shot trusted dispatch. No paths, no per-key delays. The
58 /// "instant" mode for power users who don't need detection
59 /// resistance.
60 Careful,
61 /// Empty sequence — the engine falls back to its historical
62 /// JS-synthetic event dispatch. Provided so callers don't branch
63 /// on the mode themselves; they always call into `vs-humanize`
64 /// and the empty `Vec` is the contract for "skip me."
65 Robotic,
66}