rb.math draws random numbers and reshapes macros. A script reaches for it to
vary a macro between plays, to smooth or resample its mouse path, or to give the
path the timing of a recorded mouse with rb.math.humanize.
This script plays a short mouse pattern on F6, a little larger or smaller and a
little faster or slower each time, as a path resampled every 5 ms:
Every transform returns a new table.
interpolate keeps only movement: clicks,
keys, scrolls and sleeps are dropped, and the total duration and end position are
kept. mode = "linear" draws straight segments; anything else, the default,
follows a curve.
spline leaves a list with fewer than 4 moves, or a tension of 0 or less,
unchanged. An interval_ms or target_ms of 0 returns the list unchanged, and
so does time_comp on a list whose delays add up to 0. Every action needs a
delay, or the call raises. gaussian also raises when mean is not finite.
rb.math.humanize
Needs:min_sdk=3.16.0.
Runs the ABCurves Renderer over the
moves as one stream. A smooth path, such as rb.math.interpolate(macro, 1),
comes back as whole-count reports with the timing of a recorded mouse.
options.profile: a 1 kHz recording that sets the Renderer’s starting state. Its first 256 ms of movement with no pause of 50 ms or more are used. Without one, a bundled sample from the ABCurves dataset is used.options.seed: a whole number from 0 to 2^53. The same profile and seed give the same result on the same platform; without a seed, every call differs.
- The total displacement is the original’s, rounded.
- Every other action keeps its time. The cursor when it fires can be a few counts from where the original put it, more during a fast flick, because the Renderer releases counts on its own schedule.
- At most one report goes out per millisecond, so a take recorded faster than 1 kHz comes back at 1 kHz.
- The take may end up to 17 ms after its last move while the last counts are released.
scale, or another speed,
changes the reports it produced.
Errors, each starting Math.Humanize: :
seed (<seed>) must be a whole number from 0 to 2^53the profile needs 256 ms of mouse movement with no pause of 50 ms or morethe profile must be a 1 kHz recording: some milliseconds hold more than one movethe profile must be a recording: its moves are whole countsthe profile has no mouse movementmore than 10 minutes of mouse movement to render (a pause counts up to 50 ms)
rb.math.glide
Needs:min_sdk=3.17.0.
Shapes the speed of the mouse movement so it changes smoothly instead of staying
constant inside each move. Every move still ends at its own point at its own
time, and the path never passes a point and comes back.
- Consecutive moves are shaped as one stroke that starts and ends at rest. A sleep or gap, a move of 0 with a delay, a move with no delay, or a mouse button going down or up ends the stroke. A single move can hold still for part of its time, as a hand does.
options.seed: a whole number from 0 to 2^53 that picks the profiles. The same seed gives the same result; without one, every call differs.
- The cursor is on each move’s end point, rounded to whole counts, when that move ends.
- The total displacement is the original’s, rounded. Every other action keeps its time, and at the same time it stays in the order it was written.
- A move with a delay of 0 stays one jump.
rb.macro.play(rb.math.glide({ { x = 120, y = -40, delay = 300 } })) moves 120 counts right and 40 up over 300 ms, and
rb.hid.move stays a single report.
For the Renderer’s timing as well, apply rb.math.humanize after it. The
result can then pass a point by a count or two before settling; the total stays
exact.
Errors, each starting Math.Glide: : seed (<seed>) must be a whole number from 0 to 2^53 and more than 10 minutes of mouse movement to shape.
This script glides a short pattern, applies rb.math.humanize after it, and
plays the result on F6: