@aspiresys/visor 1.2.7 → 1.2.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -36,7 +36,10 @@ export declare class Visor {
36
36
  * @example
37
37
  * await visor.click("./images/save.png", 0.9);
38
38
  */
39
- click(image?: string, confidence?: number): Promise<void>;
39
+ click(image?: string, confidence?: number, offset?: {
40
+ x: number;
41
+ y: number;
42
+ }): Promise<void>;
40
43
  /**
41
44
  * Performs a right mouse click.
42
45
  *
@@ -61,7 +64,10 @@ export declare class Visor {
61
64
  * @example
62
65
  * await visor.rightClick();
63
66
  */
64
- rightClick(image?: string, confidence?: number): Promise<void>;
67
+ rightClick(image?: string, confidence?: number, offset?: {
68
+ x: number;
69
+ y: number;
70
+ }): Promise<void>;
65
71
  /**
66
72
  * Performs a double left mouse click.
67
73
  *
@@ -87,7 +93,10 @@ export declare class Visor {
87
93
  * @example
88
94
  * await visor.doubleClick();
89
95
  */
90
- doubleClick(image?: string, confidence?: number): Promise<void>;
96
+ doubleClick(image?: string, confidence?: number, offset?: {
97
+ x: number;
98
+ y: number;
99
+ }): Promise<void>;
91
100
  /**
92
101
  * Finds the best matching image on screen
93
102
  * using OpenCV template matching.
@@ -495,7 +504,10 @@ export declare class Visor {
495
504
  * @example
496
505
  * await visor.hover("menu.png");
497
506
  */
498
- hover(image: string, confidence?: number): Promise<void>;
507
+ hover(image?: string, confidence?: number, offset?: {
508
+ x: number;
509
+ y: number;
510
+ }): Promise<void>;
499
511
  /**
500
512
  * Scrolls the mouse wheel downward.
501
513
  *
package/dist/index.js CHANGED
@@ -78,7 +78,10 @@ class Visor {
78
78
  * @example
79
79
  * await visor.click("./images/save.png", 0.9);
80
80
  */
81
- async click(image, confidence = 0.8) {
81
+ async click(image, confidence = 0.8, offset = {
82
+ x: 0,
83
+ y: 0
84
+ }) {
82
85
  this.checkConfig();
83
86
  if (!image) {
84
87
  await this.mouse.click(this.Button.LEFT);
@@ -90,7 +93,7 @@ class Visor {
90
93
  throw new Error(`Image not found: ${image}`);
91
94
  }
92
95
  (0, logger_1.log)("[CV] Match found:", region);
93
- await (0, mouse_1.clickRegion)(region);
96
+ await (0, mouse_1.clickRegion)(region, offset);
94
97
  }
95
98
  /**
96
99
  * Performs a right mouse click.
@@ -116,14 +119,17 @@ class Visor {
116
119
  * @example
117
120
  * await visor.rightClick();
118
121
  */
119
- async rightClick(image, confidence = 0.8) {
122
+ async rightClick(image, confidence = 0.8, offset = {
123
+ x: 0,
124
+ y: 0
125
+ }) {
120
126
  this.checkConfig();
121
127
  if (image) {
122
128
  const region = await this.find(image, confidence);
123
129
  if (!region) {
124
130
  throw new Error(`Image not found: ${image}`);
125
131
  }
126
- await (0, mouse_1.moveToRegion)(region);
132
+ await (0, mouse_1.moveToRegion)(region, offset);
127
133
  }
128
134
  await this.mouse.click(this.Button.RIGHT);
129
135
  (0, logger_1.log)("[MOUSE] Right click completed");
@@ -153,14 +159,17 @@ class Visor {
153
159
  * @example
154
160
  * await visor.doubleClick();
155
161
  */
156
- async doubleClick(image, confidence = 0.8) {
162
+ async doubleClick(image, confidence = 0.8, offset = {
163
+ x: 0,
164
+ y: 0
165
+ }) {
157
166
  this.checkConfig();
158
167
  if (image) {
159
168
  const region = await this.find(image, confidence);
160
169
  if (!region) {
161
170
  throw new Error(`Image not found: ${image}`);
162
171
  }
163
- await (0, mouse_1.moveToRegion)(region);
172
+ await (0, mouse_1.moveToRegion)(region, offset);
164
173
  }
165
174
  await this.mouse.doubleClick(this.Button.LEFT);
166
175
  (0, logger_1.log)("[MOUSE] Double click completed");
@@ -674,13 +683,16 @@ CONF:${m.confidence.toFixed(3)}
674
683
  * @example
675
684
  * await visor.hover("menu.png");
676
685
  */
677
- async hover(image, confidence = 0.8) {
686
+ async hover(image, confidence = 0.8, offset = {
687
+ x: 0,
688
+ y: 0
689
+ }) {
678
690
  this.checkConfig();
679
691
  const region = await this.find(image, confidence);
680
692
  if (!region) {
681
693
  throw new Error(`Image not found: ${image}`);
682
694
  }
683
- await (0, mouse_1.moveToRegion)(region);
695
+ await (0, mouse_1.moveToRegion)(region, offset);
684
696
  (0, logger_1.log)("[MOUSE] Hover completed");
685
697
  }
686
698
  /**
package/dist/mouse.d.ts CHANGED
@@ -1,3 +1,9 @@
1
1
  import { Region } from "./types";
2
- export declare function moveToRegion(region: Region): Promise<void>;
3
- export declare function clickRegion(region: Region): Promise<void>;
2
+ export declare function moveToRegion(region: Region, offset?: {
3
+ x: number;
4
+ y: number;
5
+ }): Promise<void>;
6
+ export declare function clickRegion(region: Region, offset?: {
7
+ x: number;
8
+ y: number;
9
+ }): Promise<void>;
package/dist/mouse.js CHANGED
@@ -5,15 +5,21 @@ exports.clickRegion = clickRegion;
5
5
  const nut_js_1 = require("@nut-tree-fork/nut-js");
6
6
  const config_1 = require("./config");
7
7
  const logger_1 = require("./logger");
8
- async function moveToRegion(region) {
8
+ async function moveToRegion(region, offset = {
9
+ x: 0,
10
+ y: 0
11
+ }) {
9
12
  const scaleFactor = config_1.visorConfig.scaleFactor;
10
- const centerX = Math.floor((region.x + region.width / 2) / scaleFactor);
11
- const centerY = Math.floor((region.y + region.height / 2) / scaleFactor);
13
+ const centerX = Math.floor((region.x + region.width / 2 + offset.x) / scaleFactor);
14
+ const centerY = Math.floor((region.y + region.height / 2 + offset.y) / scaleFactor);
12
15
  (0, logger_1.log)("[MOUSE] Moving mouse to:", centerX, centerY);
13
16
  await nut_js_1.mouse.move([new nut_js_1.Point(centerX, centerY)]);
14
17
  }
15
- async function clickRegion(region) {
16
- await moveToRegion(region);
18
+ async function clickRegion(region, offset = {
19
+ x: 0,
20
+ y: 0
21
+ }) {
22
+ await moveToRegion(region, offset);
17
23
  await new Promise((r) => setTimeout(r, 200));
18
24
  await nut_js_1.mouse.click(nut_js_1.Button.LEFT);
19
25
  (0, logger_1.log)("[MOUSE] Left click completed");
package/dist/types.d.ts CHANGED
@@ -5,3 +5,7 @@ export interface Region {
5
5
  height: number;
6
6
  confidence: number;
7
7
  }
8
+ export interface Offset {
9
+ x: number;
10
+ y: number;
11
+ }
Binary file
@@ -9,103 +9,50 @@
9
9
  <header class="header">
10
10
  <h3>VISOR INSPECTOR</h3>
11
11
  </header>
12
-
13
12
  <section class="controls-section">
14
13
  <div class="toolbar">
15
14
  <button id="captureBtn" class="btn btn-primary">
16
- <span class="btn-icon">📸</span> Capture Screen
17
- </button>
15
+ <span class="btn-icon">📸</span> Capture Screen </button>
18
16
  <button id="saveBtn" class="btn btn-secondary">
19
- <span class="btn-icon">💾</span> Save Template
20
- </button>
17
+ <span class="btn-icon">💾</span> Save Template </button>
21
18
  <button id="loadTemplateBtn" class="btn btn-secondary">
22
- <span class="btn-icon">📂</span> Load Template
23
- </button>
19
+ <span class="btn-icon">📂</span> Load Template </button>
24
20
  <button id="testMatchBtn" class="btn btn-accent">
25
- <span class="btn-icon">✓</span> Test Match
26
- </button>
21
+ <span class="btn-icon">✓</span> Test Match </button>
27
22
  <div class="controls-grid">
28
23
  <div class="control-group">
29
24
  <div class="input-wrapper">
30
25
  <span class="input-hint">Confidence</span>
31
- <input
32
- id="confidenceInput"
33
- type="number"
34
- min="0"
35
- max="1"
36
- step="0.01"
37
- value="0.8"
38
- />
26
+ <input id="confidenceInput" type="number" min="0" max="1" step="0.01" value="0.8" />
39
27
  <span class="input-hint">(0.0 - 1.0)</span>
40
28
  </div>
41
29
  </div>
42
30
  </div>
43
31
  </div>
44
32
  </section>
45
-
46
- <section class="canvas-section">
47
- <h3 class="section-title">Current Capture</h3>
48
- <canvas id="screenCanvas" class="canvas"></canvas>
49
- </section>
50
-
33
+ <div class="capture-layout">
34
+ <div class="capture-panel">
35
+ <h3 class="section-title"> Current Capture </h3>
36
+ <canvas id="screenCanvas" class="canvas"></canvas>
37
+ </div>
38
+ <div class="result-panel">
39
+ <h3 class="section-title"> Match Result </h3>
40
+ <div id="matchResult"> No Match Tested </div>
41
+ </div>
42
+ </div>
51
43
  <section class="template-section">
52
44
  <h3 class="section-title">Template Management</h3>
53
45
  <div class="template-grid">
54
46
  <div class="template-info">
55
- <p><strong>Current Template:</strong></p>
56
- <span id="currentTemplate" class="template-status">None</span>
47
+ <p>
48
+ <strong>Current Template: </strong>
49
+ <span id="currentTemplate" class="template-status">None</span>
50
+ </p>
57
51
  </div>
58
52
  <img id="templatePreview" class="template-preview" />
59
53
  </div>
60
-
61
- <h3 class="section-title">
62
- Match Result
63
- </h3>
64
- <div id="matchStatus"
65
- class="match-status">
66
- No Match Tested
67
- </div>
68
- <div class="match-details">
69
- <div class="match-row">
70
- <span class="match-label">
71
- Confidence
72
- </span>
73
- <span id="resultConfidence"
74
- class="match-value">
75
-
76
- </span>
77
- </div>
78
- <div class="match-row">
79
- <span class="match-label">
80
- Position
81
- </span>
82
- <span class="match-value">
83
- X:
84
- <span id="resultX">—</span>
85
- |
86
-
87
- Y:
88
- <span id="resultY">—</span>
89
- </span>
90
- </div>
91
- <div class="match-row">
92
- <span class="match-label">
93
- Size
94
- </span>
95
- <span class="match-value">
96
- W:
97
- <span id="resultWidth">—</span>
98
-
99
- |
100
-
101
- H:
102
- <span id="resultHeight">—</span>
103
- </span>
104
- </div>
105
- </div>
106
54
  </section>
107
55
  </div>
108
-
109
56
  <script src="./src/renderer.js"></script>
110
57
  </body>
111
- </html>
58
+ </html>
@@ -151,24 +151,21 @@ testMatchBtn.addEventListener("click", async () => {
151
151
  );
152
152
 
153
153
  if (!result) {
154
- document.getElementById("matchStatus").textContent = "✗ Match Not Found";
155
- document.getElementById('resultConfidence').textContent = "—";
156
- document.getElementById('resultX').textContent = "—";
157
- document.getElementById('resultY').textContent = "—";
158
- document.getElementById('resultWidth').textContent = "—";
159
- document.getElementById('resultHeight').textContent = "—";
154
+ matchResult.textContent = "✗ MATCH NOT FOUND";
160
155
  return;
161
156
  }
162
- const updateMatchResults = (data) => {
163
- document.getElementById("matchStatus").textContent = "Match Found";
164
- document.getElementById('resultConfidence').textContent = data.confidence;
165
- document.getElementById('resultX').textContent = data.x;
166
- document.getElementById('resultY').textContent = data.y;
167
- document.getElementById('resultWidth').textContent = data.width;
168
- document.getElementById('resultHeight').textContent = data.height;
169
- };
157
+ matchResult.textContent = `
158
+ MATCH FOUND
170
159
 
171
- updateMatchResults(result);
160
+ Confidence:
161
+ ${result.confidence.toFixed(3)}
162
+
163
+ Location:
164
+ (${result.x}, ${result.y})
165
+
166
+ Size:
167
+ ${result.width} x ${result.height}
168
+ `;
172
169
  });
173
170
 
174
171
 
@@ -4,46 +4,51 @@
4
4
  box-sizing: border-box;
5
5
  }
6
6
 
7
- .spacer {
8
- flex: 1;
7
+ .match-summary {
8
+ margin-top: 10px;
9
9
  }
10
10
 
11
- .match-status {
12
- padding: 8px;
13
- border: 1px solid #444;
14
- border-radius: 6px;
15
- margin-bottom: 10px;
16
- font-weight: bold;
11
+ .match-metric {
12
+ text-align: center;
17
13
 
18
- }
19
- .match-details {
20
- display: flex;
21
- flex-direction: column;
22
- gap: 6px;
14
+ padding: 10px 0;
23
15
  }
24
16
 
25
- .match-row {
26
- display: flex;
27
- justify-content: space-between;
28
- padding: 4px 0;
17
+ .match-metric:last-child {
18
+ border-bottom: none;
29
19
  }
30
20
 
31
- .match-label {
32
- color: #999;
33
- font-size: 0.9em;
21
+ .metric-label {
22
+ display: block;
23
+
24
+ color: #888;
25
+
26
+ font-size: 0.75em;
27
+
28
+ text-transform: uppercase;
29
+
30
+ letter-spacing: 1px;
31
+
32
+ margin-bottom: 4px;
34
33
  }
35
34
 
36
- .match-value {
35
+ .metric-value {
36
+ display: block;
37
+
37
38
  color: #00d4ff;
38
- font-family: Consolas,
39
- monospace;
40
39
 
40
+ font-weight: 700;
41
+
42
+ font-size: 1.2em;
43
+
44
+ font-family: Consolas, monospace;
41
45
  }
42
46
 
43
47
  body {
44
48
  background: linear-gradient(135deg, #0f0f0f 0%, #1a1a2e 100%);
45
49
  color: #e0e0e0;
46
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
50
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
51
+ sans-serif;
47
52
  line-height: 1.6;
48
53
  min-height: 100vh;
49
54
  }
@@ -87,7 +92,7 @@ body {
87
92
  .section-title {
88
93
  font-size: 1.2em;
89
94
  color: #00d4ff;
90
- margin-bottom: 18px;
95
+ margin-bottom: 2px;
91
96
  margin-top: 0;
92
97
  font-weight: 600;
93
98
  display: flex;
@@ -198,7 +203,7 @@ input[type="number"] {
198
203
  background: rgba(37, 37, 38, 0.8);
199
204
  color: #00d4ff;
200
205
  border: 1px solid rgba(0, 212, 255, 0.3);
201
- padding: 10px 12px;
206
+ padding: 5px 6px;
202
207
  border-radius: 6px;
203
208
  font-size: 0.8em;
204
209
  width: 60px;
@@ -242,6 +247,7 @@ input[type="number"]:focus {
242
247
  border-radius: 12px;
243
248
  padding: 10px;
244
249
  margin-bottom: 10px;
250
+ margin-top: 10px;
245
251
  }
246
252
 
247
253
  .template-grid {
@@ -263,7 +269,7 @@ input[type="number"]:focus {
263
269
 
264
270
  .template-status {
265
271
  display: inline-block;
266
- padding: 8px 14px;
272
+ padding: 4px 7px;
267
273
  background: rgba(76, 175, 80, 0.15);
268
274
  border: 1px solid rgba(76, 175, 80, 0.3);
269
275
  border-radius: 6px;
@@ -324,7 +330,6 @@ input[type="number"]:focus {
324
330
  box-shadow: 0 4px 12px rgba(0, 212, 255, 0.15);
325
331
  }
326
332
 
327
-
328
333
  .result-label {
329
334
  color: #888;
330
335
  font-size: 0.8em;
@@ -337,7 +342,7 @@ input[type="number"]:focus {
337
342
  color: #00d4ff;
338
343
  font-weight: 700;
339
344
  font-size: 0.8em;
340
- font-family: 'Courier New', monospace;
345
+ font-family: "Courier New", monospace;
341
346
  }
342
347
 
343
348
  #matchResult {
@@ -347,7 +352,7 @@ input[type="number"]:focus {
347
352
  background: rgba(37, 37, 38, 0.6);
348
353
  border: 1px solid rgba(100, 150, 180, 0.2);
349
354
  min-height: 60px;
350
- display: flex;
355
+ display: inline-flex;
351
356
  align-items: center;
352
357
  justify-content: center;
353
358
  color: #888;
@@ -408,3 +413,35 @@ input[type="number"]:focus {
408
413
  ::-webkit-scrollbar-thumb:hover {
409
414
  background: rgba(0, 212, 255, 0.6);
410
415
  }
416
+
417
+ .capture-layout {
418
+ display: grid;
419
+ grid-template-columns: 1fr 280px;
420
+ gap: 16px;
421
+ }
422
+
423
+ .capture-panel {
424
+ flex: 1;
425
+ }
426
+
427
+ .result-panel {
428
+ width: 250px;
429
+
430
+ flex-shrink: 0;
431
+ }
432
+
433
+ #matchResult {
434
+ padding: 12px;
435
+
436
+ min-height: 157px;
437
+
438
+ background: rgba(255, 255, 255, 0.03);
439
+
440
+ border: 1px solid rgba(0, 212, 255, 0.2);
441
+
442
+ border-radius: 8px;
443
+
444
+ font-family: Consolas, monospace;
445
+
446
+ white-space: pre-line;
447
+ }
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aspiresys/visor",
3
- "version": "1.2.7",
3
+ "version": "1.2.8",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "scripts": {