Veck.io Movement Tracker & Auto-Lock

Detects movement and draws red boxes, right-click to lock onto targets

Size

11.8 KB

Version

1.0.1

Created

Mar 19, 2026

Updated

28 days ago

1// ==UserScript==
2// @name		Veck.io Movement Tracker & Auto-Lock
3// @description		Detects movement and draws red boxes, right-click to lock onto targets
4// @version		1.0.1
5// @match		https://*.veck.io/*
6// @icon		https://veck.io/favicon/favicon.ico
7// ==/UserScript==
8(function() {
9    'use strict';
10
11    console.log('Movement Tracker & Auto-Lock initialized');
12
13    let canvas, ctx;
14    let overlayCanvas;
15    let previousFrame = null;
16    let detectedMovements = [];
17    let lockedTarget = null;
18    let isLocked = false;
19
20    // Configuration
21    const config = {
22        sensitivity: 30, // Movement detection sensitivity (lower = more sensitive)
23        minArea: 100, // Minimum area to consider as movement
24        boxColor: 'rgba(255, 0, 0, 0.8)', // Red box color
25        boxWidth: 3,
26        scanInterval: 50, // Scan every 50ms
27        lockColor: 'rgba(0, 255, 0, 0.8)' // Green for locked target
28    };
29
30    function init() {
31        // Wait for the game canvas to be ready
32        const gameCanvas = document.querySelector('#unity-canvas');
33        if (!gameCanvas) {
34            console.log('Game canvas not found, retrying...');
35            setTimeout(init, 1000);
36            return;
37        }
38
39        canvas = gameCanvas;
40        console.log('Game canvas found:', canvas);
41
42        // Create overlay canvas for drawing boxes
43        createOverlayCanvas();
44
45        // Start movement detection
46        startMovementDetection();
47
48        // Add right-click handler for locking
49        setupLockHandler();
50
51        console.log('Movement tracker fully initialized');
52    }
53
54    function createOverlayCanvas() {
55        overlayCanvas = document.createElement('canvas');
56        overlayCanvas.id = 'movement-overlay';
57        overlayCanvas.style.position = 'absolute';
58        overlayCanvas.style.top = '0';
59        overlayCanvas.style.left = '0';
60        overlayCanvas.style.pointerEvents = 'none';
61        overlayCanvas.style.zIndex = '9999';
62        
63        // Match game canvas size
64        const updateSize = () => {
65            const rect = canvas.getBoundingClientRect();
66            overlayCanvas.width = rect.width;
67            overlayCanvas.height = rect.height;
68            overlayCanvas.style.width = rect.width + 'px';
69            overlayCanvas.style.height = rect.height + 'px';
70            overlayCanvas.style.top = rect.top + 'px';
71            overlayCanvas.style.left = rect.left + 'px';
72        };
73
74        updateSize();
75        window.addEventListener('resize', updateSize);
76        
77        document.body.appendChild(overlayCanvas);
78        ctx = overlayCanvas.getContext('2d');
79        console.log('Overlay canvas created');
80    }
81
82    function startMovementDetection() {
83        const tempCanvas = document.createElement('canvas');
84        const tempCtx = tempCanvas.getContext('2d');
85
86        setInterval(() => {
87            if (!canvas || !ctx) return;
88
89            try {
90                // Set temp canvas size to match game canvas
91                tempCanvas.width = canvas.width;
92                tempCanvas.height = canvas.height;
93
94                // Capture current frame
95                tempCtx.drawImage(canvas, 0, 0);
96                const currentFrame = tempCtx.getImageData(0, 0, tempCanvas.width, tempCanvas.height);
97
98                if (previousFrame) {
99                    // Detect movement between frames
100                    detectedMovements = detectMovement(previousFrame, currentFrame, tempCanvas.width, tempCanvas.height);
101                    
102                    // Draw boxes on overlay
103                    drawMovementBoxes();
104                }
105
106                previousFrame = currentFrame;
107            } catch (e) {
108                // Canvas might be tainted or not accessible
109                console.error('Error capturing frame:', e);
110            }
111        }, config.scanInterval);
112    }
113
114    function detectMovement(prevFrame, currFrame, width, height) {
115        const movements = [];
116        const diffData = [];
117        const blockSize = 16; // Check in blocks for performance
118
119        // Create difference map
120        for (let y = 0; y < height; y += blockSize) {
121            for (let x = 0; x < width; x += blockSize) {
122                let diff = 0;
123                let count = 0;
124
125                // Sample block
126                for (let by = 0; by < blockSize && y + by < height; by++) {
127                    for (let bx = 0; bx < blockSize && x + bx < width; bx++) {
128                        const i = ((y + by) * width + (x + bx)) * 4;
129                        const rDiff = Math.abs(prevFrame.data[i] - currFrame.data[i]);
130                        const gDiff = Math.abs(prevFrame.data[i + 1] - currFrame.data[i + 1]);
131                        const bDiff = Math.abs(prevFrame.data[i + 2] - currFrame.data[i + 2]);
132                        diff += (rDiff + gDiff + bDiff) / 3;
133                        count++;
134                    }
135                }
136
137                const avgDiff = diff / count;
138                if (avgDiff > config.sensitivity) {
139                    diffData.push({ x, y, diff: avgDiff });
140                }
141            }
142        }
143
144        // Group nearby movement blocks into regions
145        const regions = groupMovementRegions(diffData, blockSize);
146        
147        return regions.filter(r => r.area > config.minArea);
148    }
149
150    function groupMovementRegions(blocks, blockSize) {
151        if (blocks.length === 0) return [];
152
153        const regions = [];
154        const visited = new Set();
155
156        blocks.forEach((block, idx) => {
157            if (visited.has(idx)) return;
158
159            const region = {
160                minX: block.x,
161                minY: block.y,
162                maxX: block.x + blockSize,
163                maxY: block.y + blockSize,
164                blocks: [block]
165            };
166
167            // Find connected blocks
168            const queue = [idx];
169            visited.add(idx);
170
171            while (queue.length > 0) {
172                const currentIdx = queue.shift();
173                const current = blocks[currentIdx];
174
175                blocks.forEach((other, otherIdx) => {
176                    if (visited.has(otherIdx)) return;
177
178                    const distance = Math.sqrt(
179                        Math.pow(current.x - other.x, 2) + 
180                        Math.pow(current.y - other.y, 2)
181                    );
182
183                    if (distance < blockSize * 3) {
184                        visited.add(otherIdx);
185                        queue.push(otherIdx);
186                        region.blocks.push(other);
187                        region.minX = Math.min(region.minX, other.x);
188                        region.minY = Math.min(region.minY, other.y);
189                        region.maxX = Math.max(region.maxX, other.x + blockSize);
190                        region.maxY = Math.max(region.maxY, other.y + blockSize);
191                    }
192                });
193            }
194
195            region.width = region.maxX - region.minX;
196            region.height = region.maxY - region.minY;
197            region.area = region.width * region.height;
198            region.centerX = region.minX + region.width / 2;
199            region.centerY = region.minY + region.height / 2;
200
201            regions.push(region);
202        });
203
204        return regions;
205    }
206
207    function drawMovementBoxes() {
208        if (!ctx || !overlayCanvas) return;
209
210        // Clear overlay
211        ctx.clearRect(0, 0, overlayCanvas.width, overlayCanvas.height);
212
213        // Scale factor between game canvas and overlay
214        const scaleX = overlayCanvas.width / canvas.width;
215        const scaleY = overlayCanvas.height / canvas.height;
216
217        // Draw boxes around detected movements
218        detectedMovements.forEach((movement, idx) => {
219            const x = movement.minX * scaleX;
220            const y = movement.minY * scaleY;
221            const w = movement.width * scaleX;
222            const h = movement.height * scaleY;
223
224            // Check if this is the locked target
225            const isLockedTarget = isLocked && lockedTarget && 
226                Math.abs(lockedTarget.centerX - movement.centerX) < 50 &&
227                Math.abs(lockedTarget.centerY - movement.centerY) < 50;
228
229            ctx.strokeStyle = isLockedTarget ? config.lockColor : config.boxColor;
230            ctx.lineWidth = config.boxWidth;
231            ctx.strokeRect(x, y, w, h);
232
233            // Draw center dot
234            ctx.fillStyle = isLockedTarget ? config.lockColor : config.boxColor;
235            ctx.beginPath();
236            ctx.arc(x + w/2, y + h/2, 4, 0, Math.PI * 2);
237            ctx.fill();
238
239            // Update locked target position
240            if (isLockedTarget) {
241                lockedTarget = movement;
242            }
243        });
244
245        // If locked, draw crosshair on target
246        if (isLocked && lockedTarget) {
247            const x = lockedTarget.centerX * scaleX;
248            const y = lockedTarget.centerY * scaleY;
249            
250            ctx.strokeStyle = config.lockColor;
251            ctx.lineWidth = 2;
252            
253            // Draw crosshair
254            ctx.beginPath();
255            ctx.moveTo(x - 20, y);
256            ctx.lineTo(x + 20, y);
257            ctx.moveTo(x, y - 20);
258            ctx.lineTo(x, y + 20);
259            ctx.stroke();
260
261            // Draw lock indicator
262            ctx.fillStyle = config.lockColor;
263            ctx.font = 'bold 14px Arial';
264            ctx.fillText('LOCKED', x + 25, y - 10);
265        }
266    }
267
268    function setupLockHandler() {
269        document.addEventListener('contextmenu', (e) => {
270            // Get click position relative to canvas
271            const rect = canvas.getBoundingClientRect();
272            const clickX = (e.clientX - rect.left) * (canvas.width / rect.width);
273            const clickY = (e.clientY - rect.top) * (canvas.height / rect.height);
274
275            // Find closest movement to click
276            let closestMovement = null;
277            let closestDistance = Infinity;
278
279            detectedMovements.forEach(movement => {
280                const distance = Math.sqrt(
281                    Math.pow(movement.centerX - clickX, 2) + 
282                    Math.pow(movement.centerY - clickY, 2)
283                );
284
285                if (distance < closestDistance && distance < 200) {
286                    closestDistance = distance;
287                    closestMovement = movement;
288                }
289            });
290
291            if (closestMovement) {
292                // Lock onto target
293                lockedTarget = closestMovement;
294                isLocked = true;
295                console.log('Locked onto target at:', lockedTarget.centerX, lockedTarget.centerY);
296                
297                // Auto-aim towards target (move mouse to target)
298                aimAtTarget();
299                
300                e.preventDefault();
301            } else if (isLocked) {
302                // Unlock if right-clicking away from targets
303                isLocked = false;
304                lockedTarget = null;
305                console.log('Target unlocked');
306                e.preventDefault();
307            }
308        });
309
310        // Optional: Auto-track locked target
311        setInterval(() => {
312            if (isLocked && lockedTarget) {
313                aimAtTarget();
314            }
315        }, 100);
316    }
317
318    function aimAtTarget() {
319        if (!lockedTarget) return;
320
321        const rect = canvas.getBoundingClientRect();
322        const targetScreenX = rect.left + (lockedTarget.centerX * rect.width / canvas.width);
323        const targetScreenY = rect.top + (lockedTarget.centerY * rect.height / canvas.height);
324
325        // Create mouse move event to aim at target
326        const mouseMoveEvent = new MouseEvent('mousemove', {
327            view: window,
328            bubbles: true,
329            cancelable: true,
330            clientX: targetScreenX,
331            clientY: targetScreenY
332        });
333
334        canvas.dispatchEvent(mouseMoveEvent);
335    }
336
337    // Start when page loads
338    if (document.readyState === 'loading') {
339        document.addEventListener('DOMContentLoaded', init);
340    } else {
341        init();
342    }
343
344})();