Repository navigation
Expand file tree
/
Copy pathindex.html
More file actions
405 lines (400 loc) · 24.7 KB
/
Copy pathindex.html
File metadata and controls
405 lines (400 loc) · 24.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
<!DOCTYPE html>
<html lang="en">
<head>
<script>
// Apply theme before first paint to avoid a flash
(function () {
try {
var saved = localStorage.getItem('theme');
var theme = saved === 'light' || saved === 'dark'
? saved
: (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
document.documentElement.setAttribute('data-theme', theme);
} catch (_) {
document.documentElement.setAttribute('data-theme', 'light');
}
})();
</script>
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-CB6GTLS93M"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-CB6GTLS93M');
</script>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta name="theme-color" content="#efe6d3" media="(prefers-color-scheme: light)">
<meta name="theme-color" content="#16120e" media="(prefers-color-scheme: dark)">
<title>Screenshot Stitcher</title>
<meta property="og:title" content="Screenshot Stitcher">
<meta property="og:type" content="article">
<meta property="og:site_name" content="Screenshot Stitcher">
<meta property="og:description" content="Stitch together scrolling screenshots of factor and skill lists from Uma Musume.">
<meta property="og:url" content="https://daftuyda.github.io/stitcher">
<meta property="og:image" content="https://daftuyda.github.io/stitcher/img/header.jpg">
<meta name="twitter:site" content="@maybevoidyt">
<meta name="twitter:card" content="photo">
<!-- favicon -->
<link rel="icon" href="./favicon.ico" sizes="32x32"><!-- 32×32 -->
<link rel="icon" href="./img/favicon/icon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="./img/favicon/apple-touch-icon.png"><!-- 180×180 -->
<link rel="manifest" href="./img/favicon/manifest.webmanifest">
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<!-- CSS -->
<link rel="stylesheet" href="./css/reset.css" type="text/css">
<link rel="stylesheet" href="./css/common.css" type="text/css">
<link rel="stylesheet" href="./css/base.css" type="text/css">
<script src="https://unpkg.com/tesseract.js@4.1.1/dist/tesseract.min.js"></script>
</head>
<body class="body">
<!-- Loading screen -->
<div id="loading" class="hidden">
<div class="sk-fading-circle">
<div class="sk-circle1 sk-circle"></div>
<div class="sk-circle2 sk-circle"></div>
<div class="sk-circle3 sk-circle"></div>
<div class="sk-circle4 sk-circle"></div>
<div class="sk-circle5 sk-circle"></div>
<div class="sk-circle6 sk-circle"></div>
<div class="sk-circle7 sk-circle"></div>
<div class="sk-circle8 sk-circle"></div>
<div class="sk-circle9 sk-circle"></div>
<div class="sk-circle10 sk-circle"></div>
<div class="sk-circle11 sk-circle"></div>
<div class="sk-circle12 sk-circle"></div>
</div>
<div id="percentage" class="">100%</div>
</div>
<header id="pageHeader">
<div class="masthead">
<div class="logo">
<h1>Screenshot Stitcher</h1>
</div>
<button class="theme-toggle" type="button" id="themeToggle" aria-label="Toggle color theme">
<svg class="glyph glyph-dark" aria-hidden="true" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>
<svg class="glyph glyph-light" aria-hidden="true" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41"/></svg>
<span class="theme-toggle-label">Theme</span>
</button>
</div>
</header>
<div class="toolbar">
<div id="errMsg" class="message hidden"></div>
<div id="normalMsg" class="message hidden"></div>
</div>
<div class="wrapper">
<article id="detail">
<section id="top">
<form method="post" enctype="multipart/form-data">
<div id="dragDropArea">
<div class="drag-drop-inside">
<p class="drag-drop-info">Drop files here</p>
<p></p>
<p class="drag-drop-buttons">
or <input id="fileInput" type="file" accept="image/*" multiple="multiple" value="Choose files" name="photo" onChange="photoPreview(event)">
</p>
<p id="uiUploadFromClipboard">or <button type="button" id="btnUploadFromClipboard">Paste from clipboard</button></p>
<p>* Manually cropped screenshots are not supported. On PC, please use a feature that captures the Uma Musume window automatically, such as Alt+PrintScreen.</p>
</div>
</div>
<div id="PreAlert">
</div>
<div id="previewArea">
<div class="container">
<!-- <div class="containerItem"><div class="functionWrap"><div class="icon--cross"></div></div><img class="previewImage" src="./img/ss/01803.png"></div> -->
</div>
</div>
<div id="formOption">
<div class="formItem">
<!-- <label>Options</label> -->
<div class="inputWrap">
<ul>
<li>
<div class="considerWrap">
<input type="checkbox" class="checkInput" id="showHeader" checked>
<label class="checkLabel" for="showHeader">Show header</label>
</div>
</li>
<li>
<div class="considerWrap">
<input type="checkbox" class="checkInput" id="showSkillIcon">
<label class="checkLabel" for="showSkillIcon">Add skill icons to factors (β)</label>
</div>
</li>
<!-- <li>
<div class="considerWrap">
<input type="checkbox" class="checkInput" id="considerEquips">
<label class="checkLabel" for="considerEquips">Close button</label>
</div>
</li> -->
</ul>
</div>
</div>
</div>
<div class="buttonArea">
<button id="btnSubmit" type="button" class="btn disable cvNotReady imgNotReady" name="submit" value="Generate" onclick="generatePhoto();return false;">Generate</button>
<button id="btnReset" type="button" class="btn disable weak imgNotReady" name="cancel" value="Reset" onclick="resetPhoto();return false;">Reset</button>
</div>
</form>
</section>
<hr>
<section id="overview">
<div id="SaveBtnArea" class="buttonArea hidden">
<button id="btnSaveJPG" class="btn weak" value="Save as JPG" onclick="SaveOriginal(document.getElementById('canvasOutput'), 'jpg');return false;">Save as JPG</button>
<button id="btnSavePNG" class="btn weak" value="Save as PNG" onclick="SaveOriginal(document.getElementById('canvasOutput'), 'png');return false;">Save as PNG</button>
<button id="btnSaveClipBoard" class="btn weak" value="Copy to 📋" onclick="SaveToClipBoard(document.getElementById('canvasOutput'));return false;">Copy to 📋</button>
</div>
<p id="outputAreaText" class="overviewTitle">Result will appear here</p>
<p id="toggleSizeText" class="overviewTitle hidden">Tap the image to toggle display size</p>
<img id="outputImage" class="hidden" src="">
<div id="overviewOCRResult" class="hidden">
<div class="editormd-preview-container">
<p class="overviewSubTitle">・Help us improve detection accuracy</p>
<p>We're collecting misdetected factor name patterns to improve the skill icon feature.<br>
Please copy the detection results from the text box below and report them on <a href="https://github.com/daftuyda/Stitcher/issues" target="_blank" rel="noopener">GitHub Issues</a>.<br>
Your contribution helps us support more receipt factors.</p>
</div>
<textarea id="outputOCRResult" cols="50" rows="3" onclick="this.select()"></textarea>
</div>
</section>
<hr>
<section id="howto">
<details class="collapsible" open>
<summary><h3>How to use</h3></summary>
<div class="markdown-body editormd-preview-container" id="memo_text">
<p><b>1. Take your screenshots</b><br>
・Scroll through the screen and take screenshots as you go.<br>
・Each screenshot should overlap the next by at least two rows.<br>
・Make sure nothing outside the game window is captured (notifications, taskbars, etc).<br>
・Most scrollable screens are supported, including factor / skill / inheritance / training tabs, finish-order tables, score info, entry lists, and support card lists.</p>
<p><b>2. Load the screenshots</b><br>
・Drag and drop, choose files, or paste from the clipboard (Ctrl+V).<br>
・Drag the previews to reorder them; click one to see it full-size.<br>
・You can load multiple characters at once.<br>
・Tap the ✕ on a preview to remove it.</p>
<p><b>3. Tap Generate</b><br>
・Takes anywhere from instant to a few seconds depending on how many images you loaded.</p>
<p><b>4. Save the result</b><br>
・Tap the output image to switch between full size and fit-to-width.<br>
・Use the JPG / PNG / 📋 buttons to save.<br>
・On iOS, long-press the image to save it to your photo library.<br>
・Reset clears everything so you can start over.</p>
<p><b>Optional: skill icons (β)</b><br>
・Adds a small skill icon next to each factor.<br>
・Stat-boosting factors (e.g. scenario factors) show a blue icon.<br>
・If the factor name can't be read clearly, [?] shows instead.<br>
・Higher-resolution screenshots give better results — at least 1500px tall is recommended.<br>
・Skill data provided by <a href="https://ウマ娘.攻略.tools/" target="_blank" rel="noopener">U-tools</a>.</p>
</div>
</details>
</section>
<hr>
<section id="updateLog">
<details class="collapsible">
<summary><h3>Update history</h3></summary>
<div class="markdown-body editormd-preview-container">
<p>
Ver1.0: Initial release<br>
Ver1.01: Fixed adjacent-image detection logic<br>
Ver1.02: Added output display size toggle; fixed behavior when multiple close buttons are detected<br>
Ver1.1: Added support for loading from clipboard and copying result to clipboard<br>
Ver1.11: Improved behavior when loading many or high-resolution images<br>
Ver1.12: Fixed so stitching works even when content below the close button isn't visible<br>
Ver1.13: Fixed the result background color not being set<br>
Ver1.2: Added processing progress indicator<br>
Ver1.3: Added header display option; hides scrollbar<br>
Ver1.4: Added support for some non-standard layouts (e.g. other users' Uma Musume)<br>
Ver1.41: Added support for the wide-format images from the Google Play Games version<br>
Ver1.42: Fixed distorted output when loading images of different layouts together<br>
Ver1.43: Tweaked stitching to reduce visible seams<br>
Ver1.44: Provisional support for slightly darker screenshots<br>
Ver1.45: When some images can't be positioned, they're now appended to the end<br>
Ver1.5: Reduced misalignment during stitching<br>
Ver1.51: Tweaked detection so faint close-button outlines are still recognized<br>
Ver1.6: Added Ctrl+V to paste from 📋<br>
Ver1.61: Made close-button detection more robust<br>
Ver1.62: Internal logic tweaks for upcoming features; adjusted adjacency thresholds<br>
Ver2.0: Added skill icon display feature (β). Thanks to <a href="https://ウマ娘.攻略.tools/" target="_blank" rel="noopener">U-tools</a>!<br>
Ver2.01: Fine-tuned close-button detection threshold<br>
Ver2.02: Fixed missing icon for Lucky Seven factor<br>
Ver2.1: Added support for finish-order table, Champions Meet score info, and entry list screens<br>
Ver2.11: Added support for race detail screen<br>
Ver3.0: Added support for most scrollable screens<br>
Ver3.1: Added horizontal layout for Champions Meet bulletins<br>
Ver3.11: Improved stitching for screens with bottom-pinned buttons (e.g. Uma Musume list)<br>
Ver3.12: Same Uma Musume on different tabs now placed side-by-side<br>
Ver3.2: For certain layouts, ordering is now determined from the scrollbar position<br>
Ver3.21: Disabled scrollbar-based ordering when scrollbar lengths differ; fixed inconsistent results based on load order; misc fixes<br>
Ver3.22: Updated factor-name position detection<br>
Ver3.23: Skip skill-icon processing on non-factor screens<br>
Ver3.24: Stopped adding ? to blue/red/green factors<br>
Ver3.25: Now errors out before running if findLastIndex isn't available<br>
Ver3.26: Added favicon<br>
Ver3.31: Provisional Steam version support<br>
Ver3.32: Fixed cases where left/right were trimmed too aggressively<br>
Ver3.33: Fixed cases where generic stitching didn't work well<br>
Ver4.01: Translated the site to English<br>
Ver4.02: Fixed the "your browser is too old" warning so it actually shows up when it should<br>
Ver4.03: Internal code cleanup — no change to how the site behaves<br>
Ver4.04: Removed an accidental duplicate setting<br>
Ver4.05: The "stitched by scrollbar position" notice no longer flashes multiple times in a row<br>
Ver4.06: Reduced memory used while figuring out the scroll area<br>
Ver4.07: Reduced memory used while handling unfamiliar screen layouts<br>
Ver4.08: Reduced memory used while resizing and joining images<br>
Ver4.09: Reduced memory used while picking out colored pixels<br>
Ver4.10: Reduced memory used while identifying which screen each screenshot is from<br>
Ver4.11: Reduced memory used while slicing each screenshot into parts<br>
Ver4.12: Fixed a potential crash from cleaning up the same memory twice<br>
Ver4.13: Fixed broken skill-icon detection caused by a memory bug<br>
Ver4.14: Stitching is much faster on large screenshots — replaced slow pixel-by-pixel scanning with bulk reads<br>
Ver4.15: Repeat runs are faster — reference images are now loaded once per visit instead of once per screenshot<br>
Ver4.16: Skill-icon detection is faster — the factor template no longer reloads on every factor<br>
Ver4.17: Grouping screenshots by character is faster — comparison data is reused across pairs<br>
Ver4.18: Skill-icon mode starts almost instantly on later runs instead of reloading the Japanese OCR model every time<br>
Ver4.19: Status messages no longer vanish early when a new one appears right after<br>
Ver4.20: The loading spinner no longer gets stuck if an image fails to load<br>
Ver4.21: Fixed a potential crash when stitching certain layouts that don't have a header<br>
Ver4.22: If stitching fails partway through, the next attempt is no longer affected by leftover state<br>
Ver4.23: Removed an unused setting that was disabled anyway<br>
Ver4.24: Removed about 200 lines of dead code<br>
Ver4.25: Layout matching with masks is faster — fewer redundant color conversions per comparison<br>
Ver4.26: Reset no longer reloads the page — keeps OpenCV, the Japanese OCR model, and templates in memory so the next Generate is fast<br>
Ver4.27: PC/Steam screenshots stitch better — tighter crop, more reliable overlap detection<br>
Ver4.28: Stopped misaligning screenshots that only share a section header but no actual content<br>
Ver4.29: Unmatched screenshots now keep your load order instead of always going to the bottom<br>
Ver4.30: Tighter check on PC/Steam matches to avoid wrong alignments from list rows that look similar but aren't<br>
Ver4.31: No more duplicate rows at the seam between two screenshots<br>
Ver4.32: Drag preview thumbnails to reorder them, or click one to see it full-size<br>
Ver4.33: Fixed PC/Steam overlap detection<br>
</p>
</div>
</details>
</section>
<hr>
</article>
</div>
<footer>
<p class="resources">Feedback:
<a href="https://github.com/daftuyda/Stitcher/issues" target="_blank" rel="noopener">GitHub Issues</a>
</p>
<p class="resources">Icons by:
<a href="https://twitter.com/38_3so" target="_blank" rel="noopener">@38_3so</a>
</p>
<p class="resources">Support the original creator:
<a href="https://www.amazon.jp/hz/wishlist/ls/1EJOGGP8S1TS6?ref_=wl_share" target="_blank" rel="noopener">Wishlist</a>
</p>
</footer>
<script src="./js/dict_skills.js"></script>
<script src="./js/regexps.js"></script>
<script src="./js/receipt_factor.js"></script>
<script src="./js/base.js"></script>
<script src="./js/shortcut.js"></script>
<script async src="./js/opencv.js" onload="onOpenCvReady();" type="text/javascript"></script>
<div class="hidden">
<img id="tmplClose" src="./img/tmpl_close.png">
<img id="tmplGrowthRate" src="./img/tmpl_growth_rate.png">
<img id="tmplRegisterPartner" src="./img/tmpl_register_partner.png">
<img id="tmplUnregisterPartner" src="./img/tmpl_unregister_partner.png">
<img id="tmpl1Factor" src="./img/tmpl_1factor.png">
<img id="tmplFactorDisc" src="./img/tmpl_factor_disc.png">
<img id="tmplHeaderTextResultTable" src="./img/tmpl_header_text_result_table.png">
<img id="tmplHeaderTextUmaDetail" src="./img/tmpl_header_text_uma_detail.png">
<img id="tmplHeaderTextScoreInfo" src="./img/tmpl_header_text_score_info.png">
<img id="tmplHeaderTextScoreDetail" src="./img/tmpl_header_text_score_detail.png">
<img id="tmplHeaderTextField" src="./img/tmpl_header_text_field.png">
<img id="tmplHeaderTextRaceDetail" src="./img/tmpl_header_text_race_detail.png">
<img id="tmplHeaderTextGougai" src="./img/tmpl_header_text_gougai.png">
<div id="tmpCanvasScrolls"></div>
<div id="tmpSkillIcons">
<img id="skillIcon10011" src="./img/skill_icons/10011.webp">
<img id="skillIcon10012" src="./img/skill_icons/10012.webp">
<img id="skillIcon10013" src="./img/skill_icons/10013.webp">
<img id="skillIcon10014" src="./img/skill_icons/10014.webp">
<img id="skillIcon10016" src="./img/skill_icons/10016.webp">
<img id="skillIcon10021" src="./img/skill_icons/10021.webp">
<img id="skillIcon10022" src="./img/skill_icons/10022.webp">
<img id="skillIcon10023" src="./img/skill_icons/10023.webp">
<img id="skillIcon10024" src="./img/skill_icons/10024.webp">
<img id="skillIcon10026" src="./img/skill_icons/10026.webp">
<img id="skillIcon10031" src="./img/skill_icons/10031.webp">
<img id="skillIcon10032" src="./img/skill_icons/10032.webp">
<img id="skillIcon10033" src="./img/skill_icons/10033.webp">
<img id="skillIcon10034" src="./img/skill_icons/10034.webp">
<img id="skillIcon10036" src="./img/skill_icons/10036.webp">
<img id="skillIcon10041" src="./img/skill_icons/10041.webp">
<img id="skillIcon10042" src="./img/skill_icons/10042.webp">
<img id="skillIcon10043" src="./img/skill_icons/10043.webp">
<img id="skillIcon10044" src="./img/skill_icons/10044.webp">
<img id="skillIcon10046" src="./img/skill_icons/10046.webp">
<img id="skillIcon10051" src="./img/skill_icons/10051.webp">
<img id="skillIcon10052" src="./img/skill_icons/10052.webp">
<img id="skillIcon10053" src="./img/skill_icons/10053.webp">
<img id="skillIcon10054" src="./img/skill_icons/10054.webp">
<img id="skillIcon10056" src="./img/skill_icons/10056.webp">
<img id="skillIcon10061" src="./img/skill_icons/10061.webp">
<img id="skillIcon20011" src="./img/skill_icons/20011.webp">
<img id="skillIcon20012" src="./img/skill_icons/20012.webp">
<img id="skillIcon20013" src="./img/skill_icons/20013.webp">
<img id="skillIcon20014" src="./img/skill_icons/20014.webp">
<img id="skillIcon20015" src="./img/skill_icons/20015.webp">
<img id="skillIcon20016" src="./img/skill_icons/20016.webp">
<img id="skillIcon20021" src="./img/skill_icons/20021.webp">
<img id="skillIcon20024" src="./img/skill_icons/20024.webp">
<img id="skillIcon20041" src="./img/skill_icons/20041.webp">
<img id="skillIcon20044" src="./img/skill_icons/20044.webp">
<img id="skillIcon20051" src="./img/skill_icons/20051.webp">
<img id="skillIcon20061" src="./img/skill_icons/20061.webp">
<img id="skillIcon20064" src="./img/skill_icons/20064.webp">
<img id="skillIcon20091" src="./img/skill_icons/20091.webp">
<img id="skillIcon20101" src="./img/skill_icons/20101.webp">
<img id="skillIcon20111" src="./img/skill_icons/20111.webp">
<img id="skillIcon20121" src="./img/skill_icons/20121.webp">
<img id="skillIcon20131" src="./img/skill_icons/20131.webp">
<img id="skillIcon20141" src="./img/skill_icons/20141.webp">
<img id="skillIcon20151" src="./img/skill_icons/20151.webp">
<img id="skillIcon20161" src="./img/skill_icons/20161.webp">
<img id="skillIcon20171" src="./img/skill_icons/20171.webp">
<img id="skillIcon20181" src="./img/skill_icons/20181.webp">
<img id="skillIcon20191" src="./img/skill_icons/20191.webp">
<img id="skillIcon20201" src="./img/skill_icons/20201.webp">
<img id="skillIcon20202" src="./img/skill_icons/20202.webp">
<img id="skillIcon20211" src="./img/skill_icons/20211.webp">
<img id="skillIcon20212" src="./img/skill_icons/20212.webp">
<img id="skillIcon20221" src="./img/skill_icons/20221.webp">
<img id="skillIcon20241" src="./img/skill_icons/20241.webp">
<img id="skillIcon20261" src="./img/skill_icons/20261.webp">
<img id="skillIcon30011" src="./img/skill_icons/30011.webp">
<img id="skillIcon30021" src="./img/skill_icons/30021.webp">
<img id="skillIcon30041" src="./img/skill_icons/30041.webp">
<img id="skillIcon30051" src="./img/skill_icons/30051.webp">
<img id="skillIcon30071" src="./img/skill_icons/30071.webp">
<img id="skillIcon3001111" src="./img/skill_icons/3001111.webp">
<img id="skillIcon3001121" src="./img/skill_icons/3001121.webp">
<img id="skillIcon3001131" src="./img/skill_icons/3001131.webp">
<img id="skillIcon3001141" src="./img/skill_icons/3001141.webp">
<img id="skillIcon3001151" src="./img/skill_icons/3001151.webp">
<img id="skillIcon3001191" src="./img/skill_icons/3001191.webp">
<img id="skillIcon3002121" src="./img/skill_icons/3002131.webp">
<img id="skillIcon3002131" src="./img/skill_icons/3002131.webp">
<img id="skillIcon3002141" src="./img/skill_icons/3002141.webp">
<img id="skillIcon3002151" src="./img/skill_icons/3002151.webp">
<img id="skillIcon3002191" src="./img/skill_icons/3002191.webp">
<img id="skillIcon3003131" src="./img/skill_icons/3003131.webp">
<img id="skillIcon3003141" src="./img/skill_icons/3003141.webp">
<img id="skillIcon3003151" src="./img/skill_icons/3003151.webp">
<img id="skillIcon3003191" src="./img/skill_icons/3003191.webp">
<img id="skillIcon3004141" src="./img/skill_icons/3004141.webp">
<img id="skillIcon3004151" src="./img/skill_icons/3004151.webp">
<img id="skillIcon3004191" src="./img/skill_icons/3004191.webp">
<img id="skillIcon3005151" src="./img/skill_icons/3005151.webp">
<img id="skillIcon3005191" src="./img/skill_icons/3005191.webp">
<img id="skillIcon3009191" src="./img/skill_icons/3009191.webp">
<img id="skillIconUnknown" src="./img/skill_icons/unknown.webp">
</div>
</div>
</body>
</html>