I wanted the auto-scroll feature replicated in Safari without using a separate app (it works OOB in Firefox). Auto-scroll can be described as clicking and holding MMB once, then move the cursor above or below the click point to scroll continuously, with scrolling speed based on distance from that point.
It works quite well and doesn’t interfere with a normal MMB click. See screenshots for how I configured it.
auto-scroll.bttpreset (8.3 KB)
Floating menu for auto-scroll.bttpreset (38.1 KB)
Code
If you’d rather configure it yourself, here are the steps:
For MMB down, run Real JavaScript action:
async function autoscrollDownHandler() {
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
await set_number_variable({
variable_name: 'autoscroll_abort',
to: 0
});
const anchorY = Number(await get_number_variable({
variable_name: 'mouse_position_y'
})) || 0;
const deadzone = 12;
const tickMs = 8;
const smoothing = 0.20;
const maxStep = 34;
let filteredDy = 0;
let fractionalCarry = 0;
while (true) {
const abortNow = Number(await get_number_variable({
variable_name: 'autoscroll_abort'
})) || 0;
if (abortNow) break;
const currentY = Number(await get_number_variable({
variable_name: 'mouse_position_y'
})) || 0;
const rawDy = currentY - anchorY;
filteredDy = filteredDy + (rawDy - filteredDy) * smoothing;
const distance = Math.abs(filteredDy);
if (distance > deadzone) {
const effective = distance - deadzone;
let step = 0;
if (effective <= 30) {
step = effective * 0.06;
} else if (effective <= 90) {
step = 1.8 + (effective - 30) * 0.14;
} else {
step = 10.2 + (effective - 90) * 0.28;
}
step = Math.min(step, maxStep);
const signedStepFloat = filteredDy < 0 ? -step : step;
fractionalCarry += signedStepFloat;
const signedStepInt = fractionalCarry > 0
? Math.floor(fractionalCarry)
: Math.ceil(fractionalCarry);
fractionalCarry -= signedStepInt;
if (signedStepInt !== 0) {
await trigger_action({
json: JSON.stringify({
BTTPredefinedActionType: 272,
BTTPredefinedActionName: "Send Scroll Event",
BTTScrollBy: `{0,${signedStepInt}}`
}),
wait_for_reply: false
});
}
} else {
filteredDy *= 0.75;
}
await sleep(tickMs);
}
return "done";
}
For MMB up, Run Real Javascript action:
async function autoscrollUpHandler() {
await set_number_variable({
variable_name: 'autoscroll_abort',
to: 1
});
await set_string_variable({
variable_name: 'autoscroll_debug',
to: 'stopped'
});
return "done";
}
Feel free to tweak the consts to your liking.
For the floating menu (purely cosmetic), simply create an empty one and only show an auto-scroll-icon.
Screenshots:



