@aspiresys/visor 1.2.5 → 1.2.7
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/matcher.d.ts +1 -0
- package/dist/matcher.js +11 -0
- package/inspector/index.html +101 -19
- package/inspector/main.js +2 -2
- package/inspector/src/renderer.js +44 -42
- package/inspector/styles.css +391 -34
- package/package.json +1 -1
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/inspector/index.html
CHANGED
|
@@ -5,25 +5,107 @@
|
|
|
5
5
|
<link rel="stylesheet" href="styles.css" />
|
|
6
6
|
</head>
|
|
7
7
|
<body>
|
|
8
|
-
<
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
<
|
|
14
|
-
|
|
8
|
+
<div class="container">
|
|
9
|
+
<header class="header">
|
|
10
|
+
<h3>VISOR INSPECTOR</h3>
|
|
11
|
+
</header>
|
|
12
|
+
|
|
13
|
+
<section class="controls-section">
|
|
14
|
+
<div class="toolbar">
|
|
15
|
+
<button id="captureBtn" class="btn btn-primary">
|
|
16
|
+
<span class="btn-icon">📸</span> Capture Screen
|
|
17
|
+
</button>
|
|
18
|
+
<button id="saveBtn" class="btn btn-secondary">
|
|
19
|
+
<span class="btn-icon">💾</span> Save Template
|
|
20
|
+
</button>
|
|
21
|
+
<button id="loadTemplateBtn" class="btn btn-secondary">
|
|
22
|
+
<span class="btn-icon">📂</span> Load Template
|
|
23
|
+
</button>
|
|
24
|
+
<button id="testMatchBtn" class="btn btn-accent">
|
|
25
|
+
<span class="btn-icon">✓</span> Test Match
|
|
26
|
+
</button>
|
|
27
|
+
<div class="controls-grid">
|
|
28
|
+
<div class="control-group">
|
|
29
|
+
<div class="input-wrapper">
|
|
30
|
+
<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
|
+
/>
|
|
39
|
+
<span class="input-hint">(0.0 - 1.0)</span>
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
</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
|
+
|
|
51
|
+
<section class="template-section">
|
|
52
|
+
<h3 class="section-title">Template Management</h3>
|
|
53
|
+
<div class="template-grid">
|
|
54
|
+
<div class="template-info">
|
|
55
|
+
<p><strong>Current Template:</strong></p>
|
|
56
|
+
<span id="currentTemplate" class="template-status">None</span>
|
|
57
|
+
</div>
|
|
58
|
+
<img id="templatePreview" class="template-preview" />
|
|
59
|
+
</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
|
+
</section>
|
|
15
107
|
</div>
|
|
16
|
-
|
|
17
|
-
<input id="confidenceInput" type="number" min="0" max="1" step="0.01" value="0.8" />
|
|
18
|
-
<br>
|
|
19
|
-
<br>
|
|
20
|
-
<canvas id="screenCanvas"></canvas>
|
|
21
|
-
<hr>
|
|
22
|
-
<h3> Template </h3>
|
|
23
|
-
<div> Current Template: <span id="currentTemplate"> None </span>
|
|
24
|
-
</div>
|
|
25
|
-
<img id="templatePreview" width="300" />
|
|
26
|
-
<div id="matchResult"></div>
|
|
108
|
+
|
|
27
109
|
<script src="./src/renderer.js"></script>
|
|
28
110
|
</body>
|
|
29
|
-
</html>
|
|
111
|
+
</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,
|
|
@@ -127,48 +129,48 @@ saveBtn.addEventListener("click",
|
|
|
127
129
|
}
|
|
128
130
|
);
|
|
129
131
|
|
|
130
|
-
testMatchBtn.addEventListener("click",
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
132
|
+
testMatchBtn.addEventListener("click", async () => {
|
|
133
|
+
if (!selectedTemplatePath) {
|
|
134
|
+
alert("Please load or save a template first.");
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const confidence = parseFloat(confidenceInput.value);
|
|
139
|
+
if (isNaN(confidence) || confidence < 0 || confidence > 1) {
|
|
140
|
+
alert("Confidence must be between 0 and 1");
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const result = await window.visor.testMatch({
|
|
145
|
+
templatePath: selectedTemplatePath,
|
|
146
|
+
confidence: confidence
|
|
147
|
+
});
|
|
148
|
+
console.log(
|
|
149
|
+
"Match Result:",
|
|
150
|
+
result
|
|
151
|
+
);
|
|
152
|
+
|
|
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 = "—";
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
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
|
+
};
|
|
170
|
+
|
|
171
|
+
updateMatchResults(result);
|
|
172
|
+
});
|
|
173
|
+
|
|
172
174
|
|
|
173
175
|
loadTemplateBtn.addEventListener("click",
|
|
174
176
|
async () => {
|
package/inspector/styles.css
CHANGED
|
@@ -1,53 +1,410 @@
|
|
|
1
|
+
* {
|
|
2
|
+
margin: 0;
|
|
3
|
+
padding: 0;
|
|
4
|
+
box-sizing: border-box;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.spacer {
|
|
8
|
+
flex: 1;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.match-status {
|
|
12
|
+
padding: 8px;
|
|
13
|
+
border: 1px solid #444;
|
|
14
|
+
border-radius: 6px;
|
|
15
|
+
margin-bottom: 10px;
|
|
16
|
+
font-weight: bold;
|
|
17
|
+
|
|
18
|
+
}
|
|
19
|
+
.match-details {
|
|
20
|
+
display: flex;
|
|
21
|
+
flex-direction: column;
|
|
22
|
+
gap: 6px;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.match-row {
|
|
26
|
+
display: flex;
|
|
27
|
+
justify-content: space-between;
|
|
28
|
+
padding: 4px 0;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
.match-label {
|
|
32
|
+
color: #999;
|
|
33
|
+
font-size: 0.9em;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.match-value {
|
|
37
|
+
color: #00d4ff;
|
|
38
|
+
font-family: Consolas,
|
|
39
|
+
monospace;
|
|
40
|
+
|
|
41
|
+
}
|
|
42
|
+
|
|
1
43
|
body {
|
|
2
|
-
background: #
|
|
3
|
-
color: #
|
|
4
|
-
font-family: Segoe UI, sans-serif;
|
|
5
|
-
|
|
44
|
+
background: linear-gradient(135deg, #0f0f0f 0%, #1a1a2e 100%);
|
|
45
|
+
color: #e0e0e0;
|
|
46
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', sans-serif;
|
|
47
|
+
line-height: 1.6;
|
|
48
|
+
min-height: 100vh;
|
|
6
49
|
}
|
|
7
50
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
padding
|
|
51
|
+
.container {
|
|
52
|
+
max-width: 1200px;
|
|
53
|
+
margin: 0 auto;
|
|
54
|
+
padding: 12px;
|
|
12
55
|
}
|
|
13
56
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
border: 1px solid #
|
|
18
|
-
padding:
|
|
19
|
-
margin-right: 8px;
|
|
20
|
-
cursor: pointer;
|
|
57
|
+
/* HEADER */
|
|
58
|
+
.header {
|
|
59
|
+
margin-bottom: 10px;
|
|
60
|
+
border-bottom: 1px solid #00d4ff;
|
|
61
|
+
padding-bottom: 6px;
|
|
21
62
|
}
|
|
22
63
|
|
|
23
|
-
|
|
24
|
-
|
|
64
|
+
.header h3 {
|
|
65
|
+
font-size: 16px;
|
|
66
|
+
color: #00d4ff;
|
|
25
67
|
}
|
|
26
68
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
69
|
+
.header h1 {
|
|
70
|
+
font-size: 2.5em;
|
|
71
|
+
background: linear-gradient(135deg, #00d4ff, #0099cc);
|
|
72
|
+
-webkit-background-clip: text;
|
|
73
|
+
-webkit-text-fill-color: transparent;
|
|
74
|
+
background-clip: text;
|
|
75
|
+
margin-bottom: 8px;
|
|
76
|
+
font-weight: 700;
|
|
32
77
|
}
|
|
33
78
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
79
|
+
.header .subtitle {
|
|
80
|
+
color: #888;
|
|
81
|
+
font-size: 0.95em;
|
|
82
|
+
font-weight: 300;
|
|
83
|
+
letter-spacing: 0.5px;
|
|
37
84
|
}
|
|
38
85
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
86
|
+
/* SECTIONS */
|
|
87
|
+
.section-title {
|
|
88
|
+
font-size: 1.2em;
|
|
89
|
+
color: #00d4ff;
|
|
90
|
+
margin-bottom: 18px;
|
|
91
|
+
margin-top: 0;
|
|
92
|
+
font-weight: 600;
|
|
93
|
+
display: flex;
|
|
94
|
+
align-items: center;
|
|
95
|
+
gap: 8px;
|
|
42
96
|
}
|
|
43
97
|
|
|
44
|
-
|
|
45
|
-
|
|
98
|
+
/* CONTROLS SECTION */
|
|
99
|
+
.controls-section {
|
|
100
|
+
background: rgba(255, 255, 255, 0.03);
|
|
101
|
+
border: 1px solid rgba(0, 212, 255, 0.2);
|
|
102
|
+
border-radius: 12px;
|
|
46
103
|
padding: 10px;
|
|
47
|
-
|
|
48
|
-
|
|
104
|
+
margin-bottom: 15px;
|
|
105
|
+
backdrop-filter: blur(10px);
|
|
49
106
|
}
|
|
50
107
|
|
|
51
108
|
.toolbar {
|
|
52
|
-
|
|
53
|
-
|
|
109
|
+
display: flex;
|
|
110
|
+
gap: 6px;
|
|
111
|
+
margin-bottom: 8px;
|
|
112
|
+
align-items: center;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.btn {
|
|
116
|
+
padding: 4px 8px;
|
|
117
|
+
border: none;
|
|
118
|
+
border-radius: 8px;
|
|
119
|
+
cursor: pointer;
|
|
120
|
+
font-size: 12px;
|
|
121
|
+
font-weight: 500;
|
|
122
|
+
transition: all 0.3s ease;
|
|
123
|
+
display: flex;
|
|
124
|
+
align-items: center;
|
|
125
|
+
gap: 3px;
|
|
126
|
+
white-space: nowrap;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.btn-icon {
|
|
130
|
+
font-size: 1.1em;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.btn-primary {
|
|
134
|
+
background: linear-gradient(135deg, #00d4ff, #0099cc);
|
|
135
|
+
color: #000;
|
|
136
|
+
font-weight: 600;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.btn-primary:hover {
|
|
140
|
+
transform: translateY(-2px);
|
|
141
|
+
box-shadow: 0 8px 20px rgba(0, 212, 255, 0.4);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.btn-primary:active {
|
|
145
|
+
transform: translateY(0);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.btn-secondary {
|
|
149
|
+
background: rgba(100, 150, 180, 0.2);
|
|
150
|
+
color: #e0e0e0;
|
|
151
|
+
border: 1px solid rgba(0, 212, 255, 0.3);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.btn-secondary:hover {
|
|
155
|
+
background: rgba(100, 150, 180, 0.3);
|
|
156
|
+
border-color: rgba(0, 212, 255, 0.6);
|
|
157
|
+
transform: translateY(-2px);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.btn-accent {
|
|
161
|
+
background: rgba(76, 175, 80, 0.2);
|
|
162
|
+
color: #4caf50;
|
|
163
|
+
border: 1px solid rgba(76, 175, 80, 0.5);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.btn-accent:hover {
|
|
167
|
+
background: rgba(76, 175, 80, 0.3);
|
|
168
|
+
border-color: #4caf50;
|
|
169
|
+
transform: translateY(-2px);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/* CONTROLS GRID */
|
|
173
|
+
.controls-grid {
|
|
174
|
+
display: grid;
|
|
175
|
+
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
|
176
|
+
gap: 20px;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.control-group {
|
|
180
|
+
display: flex;
|
|
181
|
+
flex-direction: column;
|
|
182
|
+
gap: 8px;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.control-group label {
|
|
186
|
+
font-size: 0.8em;
|
|
187
|
+
color: #b0b0b0;
|
|
188
|
+
font-weight: 500;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.input-wrapper {
|
|
192
|
+
display: flex;
|
|
193
|
+
align-items: center;
|
|
194
|
+
gap: 10px;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
input[type="number"] {
|
|
198
|
+
background: rgba(37, 37, 38, 0.8);
|
|
199
|
+
color: #00d4ff;
|
|
200
|
+
border: 1px solid rgba(0, 212, 255, 0.3);
|
|
201
|
+
padding: 10px 12px;
|
|
202
|
+
border-radius: 6px;
|
|
203
|
+
font-size: 0.8em;
|
|
204
|
+
width: 60px;
|
|
205
|
+
transition: all 0.3s ease;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
input[type="number"]:focus {
|
|
209
|
+
outline: none;
|
|
210
|
+
border-color: #00d4ff;
|
|
211
|
+
box-shadow: 0 0 12px rgba(0, 212, 255, 0.2);
|
|
212
|
+
background: rgba(37, 37, 38, 1);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
.input-hint {
|
|
216
|
+
color: #666;
|
|
217
|
+
font-size: 0.85em;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/* CANVAS SECTION */
|
|
221
|
+
.canvas-section {
|
|
222
|
+
background: rgba(255, 255, 255, 0.02);
|
|
223
|
+
border: 1px solid rgba(0, 212, 255, 0.2);
|
|
224
|
+
border-radius: 12px;
|
|
225
|
+
padding: 10px;
|
|
226
|
+
margin-bottom: 10px;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.canvas {
|
|
230
|
+
border: 2px solid #00d4ff;
|
|
231
|
+
border-radius: 8px;
|
|
232
|
+
background: #0a0a0a;
|
|
233
|
+
display: block;
|
|
234
|
+
margin-top: 15px;
|
|
235
|
+
box-shadow: 0 0 20px rgba(0, 212, 255, 0.1);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/* TEMPLATE SECTION */
|
|
239
|
+
.template-section {
|
|
240
|
+
background: rgba(255, 255, 255, 0.02);
|
|
241
|
+
border: 1px solid rgba(0, 212, 255, 0.2);
|
|
242
|
+
border-radius: 12px;
|
|
243
|
+
padding: 10px;
|
|
244
|
+
margin-bottom: 10px;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
.template-grid {
|
|
248
|
+
display: grid;
|
|
249
|
+
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
250
|
+
gap: 20px;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
.template-info {
|
|
254
|
+
display: flex;
|
|
255
|
+
flex-direction: column;
|
|
256
|
+
gap: 10px;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.template-info p {
|
|
260
|
+
font-size: 0.95em;
|
|
261
|
+
color: #b0b0b0;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
.template-status {
|
|
265
|
+
display: inline-block;
|
|
266
|
+
padding: 8px 14px;
|
|
267
|
+
background: rgba(76, 175, 80, 0.15);
|
|
268
|
+
border: 1px solid rgba(76, 175, 80, 0.3);
|
|
269
|
+
border-radius: 6px;
|
|
270
|
+
color: #4caf50;
|
|
271
|
+
font-weight: 500;
|
|
272
|
+
width: fit-content;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
.template-preview {
|
|
276
|
+
border: 2px solid #00d4ff;
|
|
277
|
+
border-radius: 8px;
|
|
278
|
+
max-width: 100%;
|
|
279
|
+
height: auto;
|
|
280
|
+
max-height: 150px;
|
|
281
|
+
object-fit: contain;
|
|
282
|
+
background: #0a0a0a;
|
|
283
|
+
box-shadow: 0 0 20px rgba(0, 212, 255, 0.1);
|
|
284
|
+
display: none;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
.template-preview[src]:not([src=""]) {
|
|
288
|
+
display: block;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/* RESULTS SECTION */
|
|
292
|
+
.results-section {
|
|
293
|
+
background: rgba(255, 255, 255, 0.02);
|
|
294
|
+
border: 1px solid rgba(0, 212, 255, 0.2);
|
|
295
|
+
border-radius: 12px;
|
|
296
|
+
padding: 10px;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/* RESULTS GRID */
|
|
300
|
+
.results-grid {
|
|
301
|
+
display: grid;
|
|
302
|
+
grid-template-columns: repeat(auto-fit, minmax(80px, 1fr));
|
|
303
|
+
gap: 12px;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
.result-card {
|
|
307
|
+
background: rgba(0, 212, 255, 0.08);
|
|
308
|
+
border: 1px solid rgba(0, 212, 255, 0.3);
|
|
309
|
+
border-radius: 8px;
|
|
310
|
+
padding: 4px;
|
|
311
|
+
min-height: 50px;
|
|
312
|
+
display: flex;
|
|
313
|
+
flex-direction: column;
|
|
314
|
+
align-items: center;
|
|
315
|
+
gap: 6px;
|
|
316
|
+
transition: all 0.3s ease;
|
|
317
|
+
text-align: center;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
.result-card:hover {
|
|
321
|
+
background: rgba(0, 212, 255, 0.12);
|
|
322
|
+
border-color: rgba(0, 212, 255, 0.5);
|
|
323
|
+
transform: translateY(-2px);
|
|
324
|
+
box-shadow: 0 4px 12px rgba(0, 212, 255, 0.15);
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
.result-label {
|
|
329
|
+
color: #888;
|
|
330
|
+
font-size: 0.8em;
|
|
331
|
+
font-weight: 500;
|
|
332
|
+
text-transform: uppercase;
|
|
333
|
+
letter-spacing: 0.5px;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
.result-value {
|
|
337
|
+
color: #00d4ff;
|
|
338
|
+
font-weight: 700;
|
|
339
|
+
font-size: 0.8em;
|
|
340
|
+
font-family: 'Courier New', monospace;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
#matchResult {
|
|
344
|
+
margin-top: 15px;
|
|
345
|
+
padding: 15px;
|
|
346
|
+
border-radius: 8px;
|
|
347
|
+
background: rgba(37, 37, 38, 0.6);
|
|
348
|
+
border: 1px solid rgba(100, 150, 180, 0.2);
|
|
349
|
+
min-height: 60px;
|
|
350
|
+
display: flex;
|
|
351
|
+
align-items: center;
|
|
352
|
+
justify-content: center;
|
|
353
|
+
color: #888;
|
|
354
|
+
font-size: 0.8em;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
#matchResult:not(:empty) {
|
|
358
|
+
background: rgba(76, 175, 80, 0.1);
|
|
359
|
+
border-color: rgba(76, 175, 80, 0.3);
|
|
360
|
+
color: #e0e0e0;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/* RESPONSIVE */
|
|
364
|
+
@media (max-width: 768px) {
|
|
365
|
+
.container {
|
|
366
|
+
padding: 12px;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
.header h1 {
|
|
370
|
+
font-size: 1.8em;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
.toolbar {
|
|
374
|
+
flex-direction: column;
|
|
375
|
+
gap: 10px;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
.btn {
|
|
379
|
+
width: 100%;
|
|
380
|
+
justify-content: center;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
.controls-grid {
|
|
384
|
+
grid-template-columns: 1fr;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
.template-grid {
|
|
388
|
+
grid-template-columns: 1fr;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/* SCROLLBAR STYLING */
|
|
393
|
+
::-webkit-scrollbar {
|
|
394
|
+
width: 8px;
|
|
395
|
+
height: 8px;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
::-webkit-scrollbar-track {
|
|
399
|
+
background: rgba(37, 37, 38, 0.5);
|
|
400
|
+
border-radius: 10px;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
::-webkit-scrollbar-thumb {
|
|
404
|
+
background: rgba(0, 212, 255, 0.4);
|
|
405
|
+
border-radius: 10px;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
::-webkit-scrollbar-thumb:hover {
|
|
409
|
+
background: rgba(0, 212, 255, 0.6);
|
|
410
|
+
}
|