@aspiresys/visor 1.2.6 → 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/matcher.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { Region } from "./types";
2
2
  export declare function loadTemplate(path: string): Promise<any>;
3
+ export declare function loadScreen(path: string): Promise<any>;
3
4
  export declare function matchTemplate(screen: any, template: any, confidence?: number): Region | null;
4
5
  export declare function findAllMatches(screen: any, template: any, confidence?: number): Region[];
package/dist/matcher.js CHANGED
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.loadTemplate = loadTemplate;
7
+ exports.loadScreen = loadScreen;
7
8
  exports.matchTemplate = matchTemplate;
8
9
  exports.findAllMatches = findAllMatches;
9
10
  const fs_1 = __importDefault(require("fs"));
@@ -27,6 +28,16 @@ async function loadTemplate(path) {
27
28
  templateCache.set(path, template);
28
29
  return template.clone();
29
30
  }
31
+ async function loadScreen(path) {
32
+ (0, logger_1.log)(`[SCREEN] Loading: ${path}`);
33
+ const buffer = fs_1.default.readFileSync(path);
34
+ const png = pngjs_1.PNG.sync.read(buffer);
35
+ return cv.matFromImageData({
36
+ data: png.data,
37
+ width: png.width,
38
+ height: png.height,
39
+ });
40
+ }
30
41
  function resizeTemplate(template, scale) {
31
42
  const resized = new cv.Mat();
32
43
  const newWidth = Math.max(1, Math.floor(template.cols * scale));
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
@@ -7,91 +7,52 @@
7
7
  <body>
8
8
  <div class="container">
9
9
  <header class="header">
10
- <h1>VISOR INSPECTOR</h1>
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
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>
27
- </div>
28
-
29
- <div class="controls-grid">
30
- <div class="control-group">
31
- <label for="confidenceInput">Confidence Threshold</label>
32
- <div class="input-wrapper">
33
- <input
34
- id="confidenceInput"
35
- type="number"
36
- min="0"
37
- max="1"
38
- step="0.01"
39
- value="0.8"
40
- />
41
- <span class="input-hint">(0.0 - 1.0)</span>
21
+ <span class="btn-icon">✓</span> Test Match </button>
22
+ <div class="controls-grid">
23
+ <div class="control-group">
24
+ <div class="input-wrapper">
25
+ <span class="input-hint">Confidence</span>
26
+ <input id="confidenceInput" type="number" min="0" max="1" step="0.01" value="0.8" />
27
+ <span class="input-hint">(0.0 - 1.0)</span>
28
+ </div>
42
29
  </div>
43
30
  </div>
44
31
  </div>
45
32
  </section>
46
-
47
- <section class="canvas-section">
48
- <h3 class="section-title">Screen Capture</h3>
49
- <canvas id="screenCanvas" class="canvas"></canvas>
50
- </section>
51
-
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>
52
43
  <section class="template-section">
53
44
  <h3 class="section-title">Template Management</h3>
54
45
  <div class="template-grid">
55
46
  <div class="template-info">
56
- <p><strong>Current Template:</strong></p>
57
- <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>
58
51
  </div>
59
52
  <img id="templatePreview" class="template-preview" />
60
53
  </div>
61
54
  </section>
62
-
63
- <section class="results-section">
64
- <h3 class="section-title">Match Results</h3>
65
- <div class="results-grid">
66
- <div class="result-card">
67
- <span class="result-icon">📊</span>
68
- <span class="result-label">Confidence</span>
69
- <span id="resultConfidence" class="result-value">—</span>
70
- </div>
71
- <div class="result-card">
72
- <span class="result-icon">📍</span>
73
- <span class="result-label">X</span>
74
- <span id="resultX" class="result-value">—</span>
75
- </div>
76
- <div class="result-card">
77
- <span class="result-icon">⬆</span>
78
- <span class="result-label">Y</span>
79
- <span id="resultY" class="result-value">—</span>
80
- </div>
81
- <div class="result-card">
82
- <span class="result-icon">↔</span>
83
- <span class="result-label">Width</span>
84
- <span id="resultWidth" class="result-value">—</span>
85
- </div>
86
- <div class="result-card">
87
- <span class="result-icon">↕</span>
88
- <span class="result-label">Height</span>
89
- <span id="resultHeight" class="result-value">—</span>
90
- </div>
91
- </div>
92
- </section>
93
55
  </div>
94
-
95
56
  <script src="./src/renderer.js"></script>
96
57
  </body>
97
- </html>
58
+ </html>
package/inspector/main.js CHANGED
@@ -133,8 +133,8 @@ ipcMain.handle("test-match",
133
133
  async (event, data) => {
134
134
  console.log("Test Match IPC", data);
135
135
  const capturePath = path.join(__dirname, "assets", "capture.png");
136
- const screen = await visorMatcher.loadTemplate(capturePath);
137
- const template = await visorMatcher.loadTemplate(data.templatePath);
136
+ const screen = await visorMatcher.loadScreen(capturePath);
137
+ const template = await visorMatcher.loadScreen(data.templatePath);
138
138
  const result = visorMatcher
139
139
  .matchTemplate(
140
140
  screen,
@@ -71,6 +71,8 @@ canvas.addEventListener("mousemove",
71
71
  canvas.width,
72
72
  canvas.height
73
73
  );
74
+ ctx.strokeStyle = "red";
75
+ ctx.lineWidth = 2;
74
76
  ctx.strokeRect(
75
77
  displayStartX,
76
78
  displayStartY,
@@ -143,25 +145,27 @@ testMatchBtn.addEventListener("click", async () => {
143
145
  templatePath: selectedTemplatePath,
144
146
  confidence: confidence
145
147
  });
148
+ console.log(
149
+ "Match Result:",
150
+ result
151
+ );
146
152
 
147
153
  if (!result) {
148
- document.getElementById('resultConfidence').textContent = "";
149
- document.getElementById('resultX').textContent = "—";
150
- document.getElementById('resultY').textContent = "—";
151
- document.getElementById('resultWidth').textContent = "—";
152
- document.getElementById('resultHeight').textContent = "—";
154
+ matchResult.textContent = "✗ MATCH NOT FOUND";
153
155
  return;
154
156
  }
157
+ matchResult.textContent = `
158
+ ✓ MATCH FOUND
155
159
 
156
- const updateMatchResults = (data) => {
157
- document.getElementById('resultConfidence').textContent = data.confidence;
158
- document.getElementById('resultX').textContent = data.x;
159
- document.getElementById('resultY').textContent = data.y;
160
- document.getElementById('resultWidth').textContent = data.width;
161
- document.getElementById('resultHeight').textContent = data.height;
162
- };
160
+ Confidence:
161
+ ${result.confidence.toFixed(3)}
163
162
 
164
- updateMatchResults(result);
163
+ Location:
164
+ (${result.x}, ${result.y})
165
+
166
+ Size:
167
+ ${result.width} x ${result.height}
168
+ `;
165
169
  });
166
170
 
167
171
 
@@ -4,10 +4,51 @@
4
4
  box-sizing: border-box;
5
5
  }
6
6
 
7
+ .match-summary {
8
+ margin-top: 10px;
9
+ }
10
+
11
+ .match-metric {
12
+ text-align: center;
13
+
14
+ padding: 10px 0;
15
+ }
16
+
17
+ .match-metric:last-child {
18
+ border-bottom: none;
19
+ }
20
+
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;
33
+ }
34
+
35
+ .metric-value {
36
+ display: block;
37
+
38
+ color: #00d4ff;
39
+
40
+ font-weight: 700;
41
+
42
+ font-size: 1.2em;
43
+
44
+ font-family: Consolas, monospace;
45
+ }
46
+
7
47
  body {
8
48
  background: linear-gradient(135deg, #0f0f0f 0%, #1a1a2e 100%);
9
49
  color: #e0e0e0;
10
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
50
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto",
51
+ sans-serif;
11
52
  line-height: 1.6;
12
53
  min-height: 100vh;
13
54
  }
@@ -15,15 +56,19 @@ body {
15
56
  .container {
16
57
  max-width: 1200px;
17
58
  margin: 0 auto;
18
- padding: 30px 20px;
59
+ padding: 12px;
19
60
  }
20
61
 
21
62
  /* HEADER */
22
63
  .header {
23
- text-align: center;
24
- margin-bottom: 40px;
25
- border-bottom: 2px solid #00d4ff;
26
- padding-bottom: 25px;
64
+ margin-bottom: 10px;
65
+ border-bottom: 1px solid #00d4ff;
66
+ padding-bottom: 6px;
67
+ }
68
+
69
+ .header h3 {
70
+ font-size: 16px;
71
+ color: #00d4ff;
27
72
  }
28
73
 
29
74
  .header h1 {
@@ -47,7 +92,7 @@ body {
47
92
  .section-title {
48
93
  font-size: 1.2em;
49
94
  color: #00d4ff;
50
- margin-bottom: 18px;
95
+ margin-bottom: 2px;
51
96
  margin-top: 0;
52
97
  font-weight: 600;
53
98
  display: flex;
@@ -60,29 +105,29 @@ body {
60
105
  background: rgba(255, 255, 255, 0.03);
61
106
  border: 1px solid rgba(0, 212, 255, 0.2);
62
107
  border-radius: 12px;
63
- padding: 25px;
64
- margin-bottom: 30px;
108
+ padding: 10px;
109
+ margin-bottom: 15px;
65
110
  backdrop-filter: blur(10px);
66
111
  }
67
112
 
68
113
  .toolbar {
69
114
  display: flex;
70
- gap: 12px;
71
- margin-bottom: 20px;
72
- flex-wrap: wrap;
115
+ gap: 6px;
116
+ margin-bottom: 8px;
117
+ align-items: center;
73
118
  }
74
119
 
75
120
  .btn {
76
- padding: 10px 18px;
121
+ padding: 4px 8px;
77
122
  border: none;
78
123
  border-radius: 8px;
79
124
  cursor: pointer;
80
- font-size: 0.95em;
125
+ font-size: 12px;
81
126
  font-weight: 500;
82
127
  transition: all 0.3s ease;
83
128
  display: flex;
84
129
  align-items: center;
85
- gap: 6px;
130
+ gap: 3px;
86
131
  white-space: nowrap;
87
132
  }
88
133
 
@@ -143,7 +188,7 @@ body {
143
188
  }
144
189
 
145
190
  .control-group label {
146
- font-size: 0.95em;
191
+ font-size: 0.8em;
147
192
  color: #b0b0b0;
148
193
  font-weight: 500;
149
194
  }
@@ -158,10 +203,10 @@ input[type="number"] {
158
203
  background: rgba(37, 37, 38, 0.8);
159
204
  color: #00d4ff;
160
205
  border: 1px solid rgba(0, 212, 255, 0.3);
161
- padding: 10px 12px;
206
+ padding: 5px 6px;
162
207
  border-radius: 6px;
163
- font-size: 0.95em;
164
- width: 120px;
208
+ font-size: 0.8em;
209
+ width: 60px;
165
210
  transition: all 0.3s ease;
166
211
  }
167
212
 
@@ -182,8 +227,8 @@ input[type="number"]:focus {
182
227
  background: rgba(255, 255, 255, 0.02);
183
228
  border: 1px solid rgba(0, 212, 255, 0.2);
184
229
  border-radius: 12px;
185
- padding: 20px;
186
- margin-bottom: 30px;
230
+ padding: 10px;
231
+ margin-bottom: 10px;
187
232
  }
188
233
 
189
234
  .canvas {
@@ -200,8 +245,9 @@ input[type="number"]:focus {
200
245
  background: rgba(255, 255, 255, 0.02);
201
246
  border: 1px solid rgba(0, 212, 255, 0.2);
202
247
  border-radius: 12px;
203
- padding: 20px;
204
- margin-bottom: 30px;
248
+ padding: 10px;
249
+ margin-bottom: 10px;
250
+ margin-top: 10px;
205
251
  }
206
252
 
207
253
  .template-grid {
@@ -223,7 +269,7 @@ input[type="number"]:focus {
223
269
 
224
270
  .template-status {
225
271
  display: inline-block;
226
- padding: 8px 14px;
272
+ padding: 4px 7px;
227
273
  background: rgba(76, 175, 80, 0.15);
228
274
  border: 1px solid rgba(76, 175, 80, 0.3);
229
275
  border-radius: 6px;
@@ -237,7 +283,7 @@ input[type="number"]:focus {
237
283
  border-radius: 8px;
238
284
  max-width: 100%;
239
285
  height: auto;
240
- max-height: 300px;
286
+ max-height: 150px;
241
287
  object-fit: contain;
242
288
  background: #0a0a0a;
243
289
  box-shadow: 0 0 20px rgba(0, 212, 255, 0.1);
@@ -253,22 +299,22 @@ input[type="number"]:focus {
253
299
  background: rgba(255, 255, 255, 0.02);
254
300
  border: 1px solid rgba(0, 212, 255, 0.2);
255
301
  border-radius: 12px;
256
- padding: 20px;
302
+ padding: 10px;
257
303
  }
258
304
 
259
305
  /* RESULTS GRID */
260
306
  .results-grid {
261
307
  display: grid;
262
- grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
308
+ grid-template-columns: repeat(auto-fit, minmax(80px, 1fr));
263
309
  gap: 12px;
264
- margin-top: 15px;
265
310
  }
266
311
 
267
312
  .result-card {
268
313
  background: rgba(0, 212, 255, 0.08);
269
314
  border: 1px solid rgba(0, 212, 255, 0.3);
270
315
  border-radius: 8px;
271
- padding: 12px;
316
+ padding: 4px;
317
+ min-height: 50px;
272
318
  display: flex;
273
319
  flex-direction: column;
274
320
  align-items: center;
@@ -284,10 +330,6 @@ input[type="number"]:focus {
284
330
  box-shadow: 0 4px 12px rgba(0, 212, 255, 0.15);
285
331
  }
286
332
 
287
- .result-icon {
288
- font-size: 1.3em;
289
- }
290
-
291
333
  .result-label {
292
334
  color: #888;
293
335
  font-size: 0.8em;
@@ -299,8 +341,8 @@ input[type="number"]:focus {
299
341
  .result-value {
300
342
  color: #00d4ff;
301
343
  font-weight: 700;
302
- font-size: 1em;
303
- font-family: 'Courier New', monospace;
344
+ font-size: 0.8em;
345
+ font-family: "Courier New", monospace;
304
346
  }
305
347
 
306
348
  #matchResult {
@@ -310,11 +352,11 @@ input[type="number"]:focus {
310
352
  background: rgba(37, 37, 38, 0.6);
311
353
  border: 1px solid rgba(100, 150, 180, 0.2);
312
354
  min-height: 60px;
313
- display: flex;
355
+ display: inline-flex;
314
356
  align-items: center;
315
357
  justify-content: center;
316
358
  color: #888;
317
- font-size: 0.95em;
359
+ font-size: 0.8em;
318
360
  }
319
361
 
320
362
  #matchResult:not(:empty) {
@@ -326,7 +368,7 @@ input[type="number"]:focus {
326
368
  /* RESPONSIVE */
327
369
  @media (max-width: 768px) {
328
370
  .container {
329
- padding: 20px 15px;
371
+ padding: 12px;
330
372
  }
331
373
 
332
374
  .header h1 {
@@ -371,3 +413,35 @@ input[type="number"]:focus {
371
413
  ::-webkit-scrollbar-thumb:hover {
372
414
  background: rgba(0, 212, 255, 0.6);
373
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.6",
3
+ "version": "1.2.8",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "scripts": {