Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
b2e8345
Added Side bar to settings panel
Blur009 Jul 2, 2026
9cb0b32
fix: settings panel formatting
Blur009 Jul 2, 2026
5047315
move advanced panel sections into dedicated sections folder
Blur009 Jul 2, 2026
e807071
move zones panel sections into dedicated sections folder
Blur009 Jul 2, 2026
64e0c58
refactor: split CadenceInput into simple/advanced sub-components
Blur009 Jul 2, 2026
f21cdc6
fix: update active background and focus ring colors for simple tab in…
Blur009 Jul 2, 2026
8a21eee
fix scroll bar appearing on tab switching
Blur009 Jul 2, 2026
12443ae
fix: top left corner of settings panel having the wrong color
Blur009 Jul 2, 2026
e1b6036
changed some wording for settings tab and moved reset buttons together
Blur009 Jul 2, 2026
7abf7b2
add ko-fi badge to settings panel
Blur009 Jul 2, 2026
2c8818a
added placeholder icons for settings page
Blur009 Jul 2, 2026
28ffbad
refactor: remove unused CSS class and clean up imports in ZonesPanel
Blur009 Jul 2, 2026
b2c5034
consolidate ts tests into one folder
Blur009 Jul 2, 2026
459a8fa
fix settings scroll fade not sticking to the bottom
Blur009 Jul 2, 2026
07cee0d
re-fix remove unused css class and clean up imports in Zones panel
Blur009 Jul 2, 2026
052db15
Replaced font with RobotoFlex for support for Tabular Enums or howeve…
Blur009 Jul 2, 2026
25a6d16
adjusted settings pannel ordering and css
Blur009 Jul 3, 2026
eb24795
Temporarily move Sequence section away from advanced section
Blur009 Jul 3, 2026
eb8b509
refurbished Advanced mode, added new Icon, moved sequence clicking to…
Blur009 Jul 8, 2026
b085764
moved startup settings to behaviour settings group
Blur009 Jul 8, 2026
d129652
Add window opacity setting
Blur009 Jul 8, 2026
348431f
Refactor cadence duration handling and improve input validation in Si…
Blur009 Jul 14, 2026
2548820
Refactor wheel step handling in sharedCadence.ts for improved readabi…
Blur009 Jul 14, 2026
80cccfb
adjusted settings page button height
Blur009 Jul 14, 2026
e95b207
Add keybinds section to settings and implement keybinding functionality
Blur009 Jul 14, 2026
b71f82e
Add per-page appearance customization and enhance settings UI
Blur009 Jul 15, 2026
e7258c0
Fix keyboard input handling and improve hotkey listener initializatio…
Blur009 Jul 15, 2026
48a3306
Add 'Stop when Complete' toggle to Click Points
Blur009 Jul 15, 2026
8d5b726
Updated visuals of Click Points to match the Advanced Panel
Blur009 Jul 15, 2026
4c1a792
Moved Process Whitelist/Blacklist to Settings
Blur009 Jul 15, 2026
f6ca68e
temp fix zones panel
Blur009 Jul 15, 2026
9db40a5
Fixed changelog Appearance
Blur009 Jul 15, 2026
f8857e0
Custom stop zone overhaul part 1
Blur009 Jul 17, 2026
52d61fd
Custom stop zone overhaul done
Blur009 Jul 17, 2026
c937917
adjusted click points spacing
Blur009 Jul 17, 2026
8b6f846
Add click point radius feature with randomization and default settings
Blur009 Jul 17, 2026
95b17b1
Added new icon theming
Blur009 Jul 18, 2026
2999693
Refactor settings toggles
Blur009 Jul 18, 2026
c887b48
Enhance UI with animations for tab icons and settings panel elements
Blur009 Jul 18, 2026
c983f35
Bump version to 3.9.0 and update changelog
Blur009 Jul 18, 2026
468968d
Add 'Remember Window Position' toggle and related functionality
Blur009 Jul 18, 2026
3099a48
crude presets system
Blur009 Jul 18, 2026
dfe7bd0
Add status bar to display clicker status and reason for stopping
Blur009 Jul 18, 2026
db2588f
Implement minimized state handling and UI updates for main window
Blur009 Jul 18, 2026
a809e5d
fix task bar and tray icon theme color not applying in release
Blur009 Jul 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@ List the exact commands you ran and the result for each one.

## Checklist

- [ ] I ran `npm run check:all` and it passed with no errors
- [ ] I ran `npm run check` and it passed with no errors
- [ ] I kept the change focused and avoided unrelated refactors
- [ ] I updated related documentation, templates, or contributor guidance when needed
35 changes: 34 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,36 @@
# v3.9.0 - 18.07.2026 (d.m.y)
## New
- Added Hold mode in duty cycle since people couldn't figure out that 100% is the same as Holding down the mouse continuously.
- Added slider for window opacity in the appearance settings.
- Added Keybind section in settings.
- Added Keybinds for switching between all pages.(1 to 5 for simple, advanced, zones, click points, settings)
- Added the ability to customize each page individually in the appearance settings.
- Added 'Stop when Complete' toggle to Sequence clicking (which has been re-named to Click Points).
- Added the ability to have multiple custom stop zones.
- Added a radius to the click points that randomizes the click position within that radius.
- Added Task-bar icon customization in the appearance settings. The Icon now follows the theme color, and accent color on activation. You can toggle all of these options in the settings.
- Added Remember window position toggle (Settings → Behaviour → Startup) On by default.
- Added Status bar at the bottom of the window to show the current status of the clicker, and the reason for stopping if it is stopped.
## Changed
- Overhauled Advanced panel.
- Settings panel now has a side menu for easier navigation and organization of settings.
- Font switch from DM Sans to RobotoFlex to support tabular enums (e.g. numbers that don't shift when changing values).
- Lowered maximum double click CPS from 50 to 10.
- Click limit maximum increased from 10mil to 100mil.
- Changed scroll behaviour for number inputs to be: shift = 5, ctrl = 25, shift + ctrl = 100.
- Made settings icon 1px bigger because size matters and the settings icon was feeling very insecure about its 1 pixel size disadvantage. I hope it feels better now.
- Moved Process (white/black)list to the settings.
- Overhauled Custom Stop Zones.
- Zones overlay now shows a different color for disabled state of zones
- Replaced On/Off toggles with switches in the settings panel and gave them an animation cuz im fancy like that.
- Added animations to some ui elements and icons
## Fixed
- Fixed alt menu opening when the autoclicker is launched while tabbed into another app.
- Fixed simple tab button in the title bar showing the wrong background color when a custom accent color is selected.
- Fixed click points picker overlay persisting when the click points are toggled off while the overlay is open.
- Fixed click speed not being reached at high CPS. Now it turns out that i fixed it somehow on accident, but im just going to say that i fixed it on purpose because i am a genius and i am very smart and very good at programming.
- Window position and size appearing in the wrong location on launch for about 1 second, should now just appear normally.

# v3.8.3 - 28.06.2026 (d.m.y)
## Changed
- Changed max Process list title length to 35 characters to hopefully prevent ui clipping.
Expand All @@ -16,7 +49,7 @@
- Fixed program sometimes launching with a blank window.
- Fixed program crash when clicking into Zones panel.
## Info
as for some information for any devs. I have added a new command 'npm run check:all' and 'npm run fix:all' which will check and try to fix most common issues. Make sure to check out package.json for the commands. I really recommend running 'npm run check:all' before any sort of commit as it will make everyone's life easier when code is formatted consistently.
as for some information for any devs. I have added a new command 'npm run check' and 'npm run fix' which will check and try to fix most common issues. Make sure to check out package.json for the commands. I really recommend running 'npm run check' before any sort of commit as it will make everyone's life easier when code is formatted consistently.

# v3.8.1 - 23.06.2026 (d.m.y)
## Changed
Expand Down
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>blur-autoclicker</title>
</head>
Expand Down
162 changes: 125 additions & 37 deletions overlay.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
<title>Overlay</title>
<style>
@font-face {
font-family: 'DMSans';
src: url('/fonts/DMSans.ttf') format('truetype');
font-weight: 100 900;
font-family: 'RobotoFlex';
src: url('/fonts/RobotoFlex-VariableFont_wght.ttf') format('truetype');
font-weight: 200 800;
font-style: normal;
}

Expand All @@ -18,6 +18,7 @@
height: 100%;
overflow: hidden;
background: transparent !important;
font-variant-numeric: tabular-nums;
}
.overlay-layer {
position: absolute;
Expand All @@ -42,6 +43,16 @@
border-color: rgba(255, 196, 0, 0.92);
border-style: dashed;
}
.zone-pause {
background: rgba(0, 180, 255, 0.18);
border-color: rgba(0, 180, 255, 0.92);
border-style: solid;
}
.zone-start {
background: rgba(34, 197, 94, 0.18);
border-color: rgba(34, 197, 94, 0.92);
border-style: solid;
}
.zone-disabled {
background: rgba(128, 128, 128, 0.15);
border-color: rgba(128, 128, 128, 0.5);
Expand All @@ -57,7 +68,7 @@
height: 100%;
position: relative;
}
.sequence-dot {
.click-points-dot {
position: absolute;
width: 10px;
height: 10px;
Expand All @@ -66,6 +77,13 @@
box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.28), 0 6px 18px rgba(0, 0, 0, 0.35);
pointer-events: none;
}
.click-points-radius {
position: absolute;
border-radius: 50%;
border: 2px dashed;
pointer-events: none;
opacity: 0.55;
}
.overlay-prompt {
position: absolute;
max-width: 260px;
Expand All @@ -75,7 +93,7 @@
border: 1px solid rgba(255, 255, 255, 0.14);
box-shadow: 0 12px 34px rgba(0, 0, 0, 0.36);
color: rgba(255, 255, 255, 0.92);
font: 600 13px/1.32 "DMSans", "Segoe UI", sans-serif;
font: 600 13px/1.32 "RobotoFlex", "Segoe UI", sans-serif;
pointer-events: none;
opacity: 0;
transform: translate(18px, 18px);
Expand All @@ -95,6 +113,24 @@
border-color: rgba(34, 197, 94, 0.95);
border-style: dashed;
}
.zone--labeled {
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
}
.zone-label {
font-family: "RobotoFlex", sans-serif;
font-size: 10rem;
font-weight: 800;
line-height: 1;
user-select: none;
}
.zone-custom .zone-label { color: rgba(255, 196, 0, 0.55); }
.zone-pause .zone-label { color: rgba(0, 180, 255, 0.55); }
.zone-start .zone-label { color: rgba(34, 197, 94, 0.55); }
.zone-disabled .zone-label { color: rgba(128, 128, 128, 0.55); }

@keyframes fadeOut {
0% { opacity: 1; }
70% { opacity: 1; }
Expand All @@ -103,12 +139,13 @@
.fade-out {
animation: fadeOut 5s ease forwards;
}

</style>
</head>
<body>
<div id="overlay-container">
<div id="zone-layer" class="overlay-layer"></div>
<div id="sequence-layer" class="overlay-layer"></div>
<div id="click-points-layer" class="overlay-layer"></div>
<div id="pick-prompt" class="overlay-prompt">
Right click to add point.
<span>Shift + right click to add multiple.</span>
Expand All @@ -124,11 +161,13 @@

<script>
const zoneLayer = document.getElementById('zone-layer');
const sequenceLayer = document.getElementById('sequence-layer');
const clickPointsLayer = document.getElementById('click-points-layer');
const pickPrompt = document.getElementById('pick-prompt');
const stopZonePrompt = document.getElementById('stop-zone-prompt');
let pickModeActive = false;
let stopZonePickModeActive = false;
let zoneFadeAnim = null;
let hasFadedIn = false;

function setupTauriListener() {
if (!window.__TAURI__ || !window.__TAURI__.event) {
Expand All @@ -143,18 +182,21 @@

window.__TAURI__.event.listen('clear-zones', () => {
zoneLayer.innerHTML = '';
zoneLayer.classList.remove('fade-out');
if (zoneFadeAnim) {
zoneFadeAnim.cancel();
zoneFadeAnim = null;
}
});

window.__TAURI__.event.listen('sequence-points-data', (event) => {
renderSequencePoints(event.payload);
window.__TAURI__.event.listen('click-points-data', (event) => {
renderClickPoints(event.payload);
});

window.__TAURI__.event.listen('sequence-pick-mode', (event) => {
window.__TAURI__.event.listen('click-pick-mode', (event) => {
setPickMode(Boolean(event.payload && event.payload.active));
});

window.__TAURI__.event.listen('sequence-pick-cursor', (event) => {
window.__TAURI__.event.listen('click-pick-cursor', (event) => {
updatePickPrompt(event.payload);
});

Expand All @@ -175,14 +217,24 @@

function renderZones(data) {
zoneLayer.innerHTML = '';
zoneLayer.classList.remove('fade-out');
void zoneLayer.offsetWidth;
if (!stopZonePickModeActive) {
zoneLayer.classList.add('fade-out');
if (zoneFadeAnim) {
if (zoneFadeAnim.playState === 'finished') {
hasFadedIn = false;
}
zoneFadeAnim.cancel();
zoneFadeAnim = null;
}

if (!data) return;

if (!stopZonePickModeActive) {
zoneFadeAnim = zoneLayer.animate([
{ opacity: 1 },
{ opacity: 1, offset: 0.5 },
{ opacity: 0 }
], { duration: 3000, easing: 'ease', fill: 'forwards' });
}

const sw = data.screenWidth;
const sh = data.screenHeight;
const monitors = Array.isArray(data.monitors) && data.monitors.length > 0
Expand All @@ -193,19 +245,28 @@
addZone(monitor.x, monitor.y, monitor.width, monitor.height, 'zone-monitor');
}

if (data.customStopZoneEnabled && data.customStopZone) {
addZone(
data.customStopZone.x,
data.customStopZone.y,
data.customStopZone.width,
data.customStopZone.height,
'zone-custom'
);
if (Array.isArray(data.stopZones)) {
const disabled = data.stopZonesEnabled === false;
data.stopZones.forEach((zone, index) => {
let cls = 'zone-custom';
if (zone.action === 'pause') cls = 'zone-pause';
else if (zone.action === 'start') cls = 'zone-start';
if (disabled) cls += ' zone-disabled';
addZone(zone.x, zone.y, zone.width, zone.height, cls, String(index + 1));
});
}

for (const monitor of monitors) {
renderMonitorZones(monitor, data);
}

if (!hasFadedIn) {
hasFadedIn = true;
zoneLayer.animate([
{ opacity: 0 },
{ opacity: 1 }
], { duration: 250, easing: 'ease' });
}
}

function renderMonitorZones(monitor, data) {
Expand Down Expand Up @@ -271,7 +332,7 @@
}
}

function addZone(x, y, w, h, cls) {
function addZone(x, y, w, h, cls, label) {
const scale = window.devicePixelRatio || 1;
x = x / scale;
y = y / scale;
Expand All @@ -285,6 +346,16 @@
div.style.top = y + 'px';
div.style.width = w + 'px';
div.style.height = h + 'px';
if (label !== undefined) {
div.classList.add('zone--labeled');
const span = document.createElement('span');
span.className = 'zone-label';
span.textContent = label;
const maxPx = 160;
const fitPx = Math.min(w, h) * 0.65 / (1 + Math.max(0, label.length - 1) * 0.2);
span.style.fontSize = Math.min(fitPx, maxPx) + 'px';
div.appendChild(span);
}
zoneLayer.appendChild(div);
return div;
}
Expand Down Expand Up @@ -315,31 +386,45 @@
stopZonePrompt.classList.remove('active');
}

function renderSequencePoints(data) {
sequenceLayer.innerHTML = '';
sequenceLayer.classList.remove('fade-out');
function renderClickPoints(data) {
clickPointsLayer.innerHTML = '';
clickPointsLayer.classList.remove('fade-out');

if (!data || !Array.isArray(data.points)) return;

for (let index = 0; index < data.points.length; index += 1) {
const point = data.points[index];
addSequenceDot(point, index);
addClickPointDot(point, index);
}

if (!data.persistent && !pickModeActive) {
void sequenceLayer.offsetWidth;
sequenceLayer.classList.add('fade-out');
void clickPointsLayer.offsetWidth;
clickPointsLayer.classList.add('fade-out');
}
}

function addSequenceDot(point, index) {
function addClickPointDot(point, index) {
const scale = window.devicePixelRatio || 1;
const color = stableDotColor(point, index);

if (point.radius > 0) {
const circle = document.createElement('div');
circle.className = 'click-points-radius';
const diameter = (point.radius / scale) * 2;
circle.style.width = diameter + 'px';
circle.style.height = diameter + 'px';
circle.style.left = (point.x / scale - point.radius / scale) + 'px';
circle.style.top = (point.y / scale - point.radius / scale) + 'px';
circle.style.borderColor = color;
clickPointsLayer.appendChild(circle);
}

const dot = document.createElement('div');
dot.className = 'sequence-dot';
dot.className = 'click-points-dot';
dot.style.left = (point.x / scale - 5) + 'px';
dot.style.top = (point.y / scale - 5) + 'px';
dot.style.background = stableDotColor(point, index);
sequenceLayer.appendChild(dot);
dot.style.background = color;
clickPointsLayer.appendChild(dot);
}

function stableDotColor(point, index) {
Expand All @@ -358,15 +443,18 @@
pickModeActive = active;
pickPrompt.classList.toggle('active', active);
if (active) {
sequenceLayer.classList.remove('fade-out');
clickPointsLayer.classList.remove('fade-out');
}
}

function setStopZonePickMode(active) {
stopZonePickModeActive = active;
stopZonePrompt.classList.toggle('active', active);
if (active) {
zoneLayer.classList.remove('fade-out');
if (zoneFadeAnim) {
zoneFadeAnim.cancel();
zoneFadeAnim = null;
}
} else {
clearStopZonePreview();
}
Expand Down
Loading
Loading