Skip to main content
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.
What it keeps and changes:
  • 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.
Apply it last and play the result at speed 1: a later 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^53
  • the profile needs 256 ms of mouse movement with no pause of 50 ms or more
  • the profile must be a 1 kHz recording: some milliseconds hold more than one move
  • the profile must be a recording: its moves are whole counts
  • the profile has no mouse movement
  • more than 10 minutes of mouse movement to render (a pause counts up to 50 ms)
This script resamples a short pattern every 1 ms, humanizes it once at load with seed 7, and plays the result on F6:

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.
What it keeps:
  • 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.
A move over time is a one-move macro: 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: