@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 +16 -4
- package/dist/index.js +20 -8
- package/dist/matcher.d.ts +1 -0
- package/dist/matcher.js +11 -0
- package/dist/mouse.d.ts +8 -2
- package/dist/mouse.js +11 -5
- package/dist/types.d.ts +4 -0
- package/inspector/assets/capture.png +0 -0
- package/inspector/index.html +27 -66
- package/inspector/main.js +2 -2
- package/inspector/src/renderer.js +17 -13
- package/inspector/styles.css +112 -38
- package/inspector/templates/template.png +0 -0
- package/package.json +1 -1
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
3
|
-
|
|
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
|
-
|
|
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
|
Binary file
|
package/inspector/index.html
CHANGED
|
@@ -7,91 +7,52 @@
|
|
|
7
7
|
<body>
|
|
8
8
|
<div class="container">
|
|
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
|
|
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
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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
|
|
57
|
-
|
|
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.
|
|
137
|
-
const template = await visorMatcher.
|
|
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
|
-
|
|
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
|
-
|
|
157
|
-
|
|
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
|
-
|
|
163
|
+
Location:
|
|
164
|
+
(${result.x}, ${result.y})
|
|
165
|
+
|
|
166
|
+
Size:
|
|
167
|
+
${result.width} x ${result.height}
|
|
168
|
+
`;
|
|
165
169
|
});
|
|
166
170
|
|
|
167
171
|
|
package/inspector/styles.css
CHANGED
|
@@ -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,
|
|
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:
|
|
59
|
+
padding: 12px;
|
|
19
60
|
}
|
|
20
61
|
|
|
21
62
|
/* HEADER */
|
|
22
63
|
.header {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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:
|
|
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:
|
|
64
|
-
margin-bottom:
|
|
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:
|
|
71
|
-
margin-bottom:
|
|
72
|
-
|
|
115
|
+
gap: 6px;
|
|
116
|
+
margin-bottom: 8px;
|
|
117
|
+
align-items: center;
|
|
73
118
|
}
|
|
74
119
|
|
|
75
120
|
.btn {
|
|
76
|
-
padding:
|
|
121
|
+
padding: 4px 8px;
|
|
77
122
|
border: none;
|
|
78
123
|
border-radius: 8px;
|
|
79
124
|
cursor: pointer;
|
|
80
|
-
font-size:
|
|
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:
|
|
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.
|
|
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:
|
|
206
|
+
padding: 5px 6px;
|
|
162
207
|
border-radius: 6px;
|
|
163
|
-
font-size: 0.
|
|
164
|
-
width:
|
|
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:
|
|
186
|
-
margin-bottom:
|
|
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:
|
|
204
|
-
margin-bottom:
|
|
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:
|
|
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:
|
|
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:
|
|
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(
|
|
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:
|
|
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:
|
|
303
|
-
font-family:
|
|
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.
|
|
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:
|
|
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
|