@jjlmoya/utils-games-development 1.65.0 → 1.67.0
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/package.json +67 -67
- package/scripts/postinstall.mjs +27 -27
- package/src/category/GamesCategorySEO.astro +19 -19
- package/src/category/i18n/de.ts +15 -15
- package/src/category/i18n/en.ts +15 -15
- package/src/category/i18n/es.ts +15 -15
- package/src/category/i18n/fr.ts +15 -15
- package/src/category/i18n/id.ts +10 -10
- package/src/category/i18n/it.ts +10 -10
- package/src/category/i18n/ja.ts +10 -10
- package/src/category/i18n/ko.ts +10 -10
- package/src/category/i18n/nl.ts +10 -10
- package/src/category/i18n/pl.ts +10 -10
- package/src/category/i18n/pt.ts +10 -10
- package/src/category/i18n/ru.ts +10 -10
- package/src/category/i18n/sv.ts +10 -10
- package/src/category/i18n/tr.ts +10 -10
- package/src/category/i18n/zh.ts +10 -10
- package/src/category/seo.astro +15 -15
- package/src/components/PreviewNavSidebar.astro +116 -116
- package/src/components/PreviewToolbar.astro +143 -143
- package/src/data.ts +11 -11
- package/src/env.d.ts +5 -5
- package/src/index.ts +20 -20
- package/src/layouts/PreviewLayout.astro +122 -122
- package/src/pages/[locale]/[slug].astro +165 -165
- package/src/pages/[locale].astro +250 -250
- package/src/pages/index.astro +4 -4
- package/src/tests/bibliography_wellformed_export.test.ts +46 -0
- package/src/tests/category_seo_quality.test.ts +74 -0
- package/src/tests/diacritics_density.test.ts +118 -118
- package/src/tests/faq_count.test.ts +19 -19
- package/src/tests/i18n_coverage.test.ts +36 -36
- package/src/tests/inverted_punctuation.test.ts +84 -84
- package/src/tests/mocks/astro_mock.js +2 -2
- package/src/tests/no_en_dash.test.ts +70 -70
- package/src/tests/no_h1_in_components.test.ts +48 -48
- package/src/tests/pagespeed_best_practices.test.ts +198 -198
- package/src/tests/qa-test-helpers.ts +32 -32
- package/src/tests/qa_bibliography_links.test.ts +41 -41
- package/src/tests/qa_claim_evidence.test.ts +69 -69
- package/src/tests/qa_logic_reference_coverage.test.ts +46 -46
- package/src/tests/qa_runtime_i18n.test.ts +100 -100
- package/src/tests/schemas_fulfillment.test.ts +23 -23
- package/src/tests/script_density.test.ts +94 -94
- package/src/tests/seo_length.test.ts +23 -23
- package/src/tests/seo_wellformed_export.test.ts +65 -0
- package/src/tests/slug_language_code_format.test.ts +23 -23
- package/src/tests/slug_uniqueness.test.ts +80 -80
- package/src/tests/title_quality.test.ts +56 -56
- package/src/tool/audioLoopPointFinder/audio-loop-point-finder.css +322 -322
- package/src/tool/audioLoopPointFinder/client.ts +262 -262
- package/src/tool/damageFormulaLab/bibliography.astro +3 -21
- package/src/tool/damageFormulaLab/seo.astro +7 -5
- package/src/tool/gameDeltaTimeFixedTimestepLab/bibliography.astro +3 -19
- package/src/tool/hitboxHurtboxAnimator/hitbox-hurtbox-animator.css +614 -614
- package/src/tool/hitboxHurtboxAnimator/seo.astro +7 -5
- package/src/tool/saveFileEditor/component.astro +351 -351
- package/src/tool/saveFileEditor/game-save-file-editor.css +250 -250
- package/src/tool/spriteSheetPacker/app-client.ts +248 -248
- package/src/tool/spriteSheetPacker/bibliography.ts +12 -12
- package/src/tool/spriteSheetPacker/component.astro +229 -229
- package/src/tool/spriteSheetPacker/dropzone-client.ts +55 -55
- package/src/tool/spriteSheetPacker/entry.ts +28 -28
- package/src/tool/spriteSheetPacker/exporter.ts +116 -116
- package/src/tool/spriteSheetPacker/extractor-client.ts +127 -127
- package/src/tool/spriteSheetPacker/flipbook-client.ts +60 -60
- package/src/tool/spriteSheetPacker/logic.test.ts +155 -155
- package/src/tool/spriteSheetPacker/logic.ts +32 -32
- package/src/tool/spriteSheetPacker/packer-core.ts +121 -121
- package/src/tool/spriteSheetPacker/packer-ui.ts +86 -86
- package/src/tool/spriteSheetPacker/sprite-sheet-packer.css +578 -578
- package/src/tool/spriteSheetPacker/types.ts +89 -89
- package/src/tool/spriteSheetPacker/ui.ts +42 -42
- package/src/tool/steamCapsuleGenerator/index.ts +9 -9
- package/src/tool/steamCapsuleGenerator/validation.ts +14 -14
- package/src/types.ts +72 -72
|
@@ -1,229 +1,229 @@
|
|
|
1
|
-
---
|
|
2
|
-
import type { SpriteSheetPackerUI } from './ui';
|
|
3
|
-
import './sprite-sheet-packer.css';
|
|
4
|
-
|
|
5
|
-
interface Props {
|
|
6
|
-
ui: SpriteSheetPackerUI;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const { ui } = Astro.props;
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
<div class="ssp-container">
|
|
13
|
-
<div class="ssp-main-card">
|
|
14
|
-
<div class="ssp-header-tabs" role="tablist">
|
|
15
|
-
<button id="ssp-tab-packer" class="ssp-tab-btn active" role="tab" aria-selected="true" aria-controls="ssp-packer-panel">
|
|
16
|
-
{ui.packerTab}
|
|
17
|
-
</button>
|
|
18
|
-
<button id="ssp-tab-extractor" class="ssp-tab-btn" role="tab" aria-selected="false" aria-controls="ssp-extractor-panel">
|
|
19
|
-
{ui.extractorTab}
|
|
20
|
-
</button>
|
|
21
|
-
</div>
|
|
22
|
-
|
|
23
|
-
<div id="ssp-packer-panel" class="ssp-body-grid" role="tabpanel" aria-labelledby="ssp-tab-packer">
|
|
24
|
-
<div class="ssp-sidebar-section">
|
|
25
|
-
<div id="ssp-dropzone" class="ssp-dropzone">
|
|
26
|
-
<div class="ssp-drop-title">{ui.dropZoneTitle}</div>
|
|
27
|
-
<div class="ssp-drop-sub">{ui.dropZoneSubtitle}</div>
|
|
28
|
-
<input type="file" id="ssp-file-input" class="ssp-file-input" multiple accept="image/png,image/jpeg,image/webp" aria-label={ui.selectFilesButton} />
|
|
29
|
-
</div>
|
|
30
|
-
|
|
31
|
-
<div class="ssp-btn-row">
|
|
32
|
-
<button id="ssp-btn-select" class="ssp-btn ssp-btn-primary" type="button">{ui.selectFilesButton}</button>
|
|
33
|
-
<button id="ssp-btn-clear" class="ssp-btn ssp-btn-danger" type="button">{ui.clearAllButton}</button>
|
|
34
|
-
</div>
|
|
35
|
-
|
|
36
|
-
<div class="ssp-presets-row">
|
|
37
|
-
<button id="ssp-preset-pixel" class="ssp-chip-btn" type="button">{ui.presetPixelArt}</button>
|
|
38
|
-
<button id="ssp-preset-hd" class="ssp-chip-btn" type="button">{ui.presetHdUi}</button>
|
|
39
|
-
<button id="ssp-preset-mobile" class="ssp-chip-btn" type="button">{ui.presetMobile}</button>
|
|
40
|
-
</div>
|
|
41
|
-
|
|
42
|
-
<div class="ssp-controls-list">
|
|
43
|
-
<div class="ssp-control-group">
|
|
44
|
-
<label for="ssp-export-format" class="ssp-label"><span>{ui.exportFormatLabel}</span></label>
|
|
45
|
-
<select id="ssp-export-format" class="ssp-select">
|
|
46
|
-
<option value="generic-json-hash">{ui.formatGenericHash}</option>
|
|
47
|
-
<option value="generic-json-array">{ui.formatGenericArray}</option>
|
|
48
|
-
<option value="unity">{ui.formatUnity}</option>
|
|
49
|
-
<option value="godot">{ui.formatGodot}</option>
|
|
50
|
-
<option value="phaser">{ui.formatPhaser}</option>
|
|
51
|
-
<option value="css">{ui.formatCss}</option>
|
|
52
|
-
</select>
|
|
53
|
-
</div>
|
|
54
|
-
|
|
55
|
-
<div class="ssp-control-group">
|
|
56
|
-
<label for="ssp-padding" class="ssp-label">
|
|
57
|
-
<span>{ui.paddingLabel}</span>
|
|
58
|
-
<span id="ssp-padding-val">2</span>
|
|
59
|
-
</label>
|
|
60
|
-
<div class="ssp-stepper-box">
|
|
61
|
-
<button id="ssp-pad-dec" class="ssp-step-btn" type="button" aria-label="Decrease Padding">-</button>
|
|
62
|
-
<input type="range" id="ssp-padding" class="ssp-slider" min="0" max="32" value="2" aria-label={ui.paddingLabel} />
|
|
63
|
-
<button id="ssp-pad-inc" class="ssp-step-btn" type="button" aria-label="Increase Padding">+</button>
|
|
64
|
-
</div>
|
|
65
|
-
</div>
|
|
66
|
-
|
|
67
|
-
<div class="ssp-control-group">
|
|
68
|
-
<label for="ssp-extrusion" class="ssp-label">
|
|
69
|
-
<span>{ui.borderExtrusionLabel}</span>
|
|
70
|
-
<span id="ssp-extrusion-val">0</span>
|
|
71
|
-
</label>
|
|
72
|
-
<div class="ssp-stepper-box">
|
|
73
|
-
<button id="ssp-ext-dec" class="ssp-step-btn" type="button" aria-label="Decrease Extrusion">-</button>
|
|
74
|
-
<input type="range" id="ssp-extrusion" class="ssp-slider" min="0" max="8" value="0" aria-label={ui.borderExtrusionLabel} />
|
|
75
|
-
<button id="ssp-ext-inc" class="ssp-step-btn" type="button" aria-label="Increase Extrusion">+</button>
|
|
76
|
-
</div>
|
|
77
|
-
</div>
|
|
78
|
-
|
|
79
|
-
<div class="ssp-control-group">
|
|
80
|
-
<label for="ssp-max-size" class="ssp-label"><span>{ui.maxTextureSizeLabel}</span></label>
|
|
81
|
-
<select id="ssp-max-size" class="ssp-select">
|
|
82
|
-
<option value="512">512 x 512 px</option>
|
|
83
|
-
<option value="1024">1024 x 1024 px</option>
|
|
84
|
-
<option value="2048" selected>2048 x 2048 px</option>
|
|
85
|
-
<option value="4096">4096 x 4096 px</option>
|
|
86
|
-
</select>
|
|
87
|
-
</div>
|
|
88
|
-
|
|
89
|
-
<div class="ssp-toggle-group">
|
|
90
|
-
<label for="ssp-power-two" class="ssp-label">{ui.powerOfTwoLabel}</label>
|
|
91
|
-
<input type="checkbox" id="ssp-power-two" class="ssp-toggle-input" checked aria-label={ui.powerOfTwoLabel} />
|
|
92
|
-
</div>
|
|
93
|
-
</div>
|
|
94
|
-
</div>
|
|
95
|
-
|
|
96
|
-
<div class="ssp-main-section">
|
|
97
|
-
<div class="ssp-stats-grid">
|
|
98
|
-
<div class="ssp-stat-badge">
|
|
99
|
-
<div id="ssp-stat-efficiency" class="ssp-stat-val">0%</div>
|
|
100
|
-
<div class="ssp-stat-lbl">{ui.efficiencyBadge}</div>
|
|
101
|
-
</div>
|
|
102
|
-
<div class="ssp-stat-badge">
|
|
103
|
-
<div id="ssp-stat-drawcalls" class="ssp-stat-val">0</div>
|
|
104
|
-
<div class="ssp-stat-lbl">{ui.drawCallsBadge}</div>
|
|
105
|
-
</div>
|
|
106
|
-
<div class="ssp-stat-badge">
|
|
107
|
-
<div id="ssp-stat-frames" class="ssp-stat-val">0</div>
|
|
108
|
-
<div class="ssp-stat-lbl">{ui.totalFramesBadge}</div>
|
|
109
|
-
</div>
|
|
110
|
-
<div class="ssp-stat-badge">
|
|
111
|
-
<div id="ssp-stat-size" class="ssp-stat-val">0x0</div>
|
|
112
|
-
<div class="ssp-stat-lbl">{ui.textureSizeBadge}</div>
|
|
113
|
-
</div>
|
|
114
|
-
</div>
|
|
115
|
-
|
|
116
|
-
<div class="ssp-canvas-wrapper">
|
|
117
|
-
<canvas id="ssp-atlas-canvas" class="ssp-canvas" width="512" height="512" aria-label={ui.previewTitle}></canvas>
|
|
118
|
-
</div>
|
|
119
|
-
|
|
120
|
-
<div class="ssp-btn-row">
|
|
121
|
-
<button id="ssp-btn-download-zip" class="ssp-btn ssp-btn-primary" type="button">{ui.downloadZipButton}</button>
|
|
122
|
-
<button id="ssp-btn-copy-json" class="ssp-btn ssp-btn-secondary" type="button">{ui.copyJsonButton}</button>
|
|
123
|
-
<button id="ssp-btn-download-png" class="ssp-btn ssp-btn-secondary" type="button">{ui.downloadSheetPngButton}</button>
|
|
124
|
-
</div>
|
|
125
|
-
|
|
126
|
-
<div class="ssp-flipbook-box">
|
|
127
|
-
<div class="ssp-flipbook-header">{ui.flipbookTitle}</div>
|
|
128
|
-
<div class="ssp-flipbook-body">
|
|
129
|
-
<canvas id="ssp-flipbook-canvas" class="ssp-flipbook-canvas" width="128" height="128" aria-label={ui.flipbookTitle}></canvas>
|
|
130
|
-
<div class="ssp-flipbook-controls">
|
|
131
|
-
<div class="ssp-control-group">
|
|
132
|
-
<label for="ssp-fps-slider" class="ssp-label">
|
|
133
|
-
<span>{ui.flipbookFpsLabel}</span>
|
|
134
|
-
<span id="ssp-fps-val">12 FPS</span>
|
|
135
|
-
</label>
|
|
136
|
-
<input type="range" id="ssp-fps-slider" class="ssp-slider" min="1" max="60" value="12" aria-label={ui.flipbookFpsLabel} />
|
|
137
|
-
</div>
|
|
138
|
-
<div class="ssp-btn-row">
|
|
139
|
-
<button id="ssp-btn-play" class="ssp-btn ssp-btn-secondary" type="button">{ui.playAnimation}</button>
|
|
140
|
-
<button id="ssp-btn-pause" class="ssp-btn ssp-btn-secondary" type="button">{ui.pauseAnimation}</button>
|
|
141
|
-
</div>
|
|
142
|
-
</div>
|
|
143
|
-
</div>
|
|
144
|
-
</div>
|
|
145
|
-
|
|
146
|
-
<div class="ssp-code-container">
|
|
147
|
-
<div class="ssp-code-header">
|
|
148
|
-
<span class="ssp-code-title">{ui.codeSnippetTitle}</span>
|
|
149
|
-
<button id="ssp-btn-copy-code" class="ssp-copy-btn" type="button">{ui.copySnippetButton}</button>
|
|
150
|
-
</div>
|
|
151
|
-
<pre id="ssp-code-snippet" class="ssp-code-block"></pre>
|
|
152
|
-
</div>
|
|
153
|
-
</div>
|
|
154
|
-
</div>
|
|
155
|
-
|
|
156
|
-
<div id="ssp-extractor-panel" class="ssp-body-grid" role="tabpanel" aria-labelledby="ssp-tab-extractor" style="display: none;">
|
|
157
|
-
<div class="ssp-sidebar-section">
|
|
158
|
-
<div id="ssp-ext-dropzone" class="ssp-dropzone">
|
|
159
|
-
<div class="ssp-drop-title">{ui.dropZoneTitle}</div>
|
|
160
|
-
<div class="ssp-drop-sub">{ui.dropZoneSubtitle}</div>
|
|
161
|
-
<input type="file" id="ssp-ext-file-input" class="ssp-file-input" accept="image/png,image/jpeg,image/webp" aria-label={ui.selectFilesButton} />
|
|
162
|
-
</div>
|
|
163
|
-
|
|
164
|
-
<div class="ssp-controls-list">
|
|
165
|
-
<div class="ssp-control-group">
|
|
166
|
-
<label for="ssp-ext-width" class="ssp-label">{ui.frameWidthLabel}</label>
|
|
167
|
-
<div class="ssp-stepper-box">
|
|
168
|
-
<button id="ssp-fw-dec" class="ssp-step-btn" type="button" aria-label="Decrease Frame Width">-</button>
|
|
169
|
-
<input type="number" id="ssp-ext-width" class="ssp-input" value="32" min="1" aria-label={ui.frameWidthLabel} />
|
|
170
|
-
<button id="ssp-fw-inc" class="ssp-step-btn" type="button" aria-label="Increase Frame Width">+</button>
|
|
171
|
-
</div>
|
|
172
|
-
</div>
|
|
173
|
-
|
|
174
|
-
<div class="ssp-control-group">
|
|
175
|
-
<label for="ssp-ext-height" class="ssp-label">{ui.frameHeightLabel}</label>
|
|
176
|
-
<div class="ssp-stepper-box">
|
|
177
|
-
<button id="ssp-fh-dec" class="ssp-step-btn" type="button" aria-label="Decrease Frame Height">-</button>
|
|
178
|
-
<input type="number" id="ssp-ext-height" class="ssp-input" value="32" min="1" aria-label={ui.frameHeightLabel} />
|
|
179
|
-
<button id="ssp-fh-inc" class="ssp-step-btn" type="button" aria-label="Increase Frame Height">+</button>
|
|
180
|
-
</div>
|
|
181
|
-
</div>
|
|
182
|
-
|
|
183
|
-
<div class="ssp-control-group">
|
|
184
|
-
<label for="ssp-ext-margin" class="ssp-label">{ui.marginLabel}</label>
|
|
185
|
-
<div class="ssp-stepper-box">
|
|
186
|
-
<button id="ssp-mar-dec" class="ssp-step-btn" type="button" aria-label="Decrease Margin">-</button>
|
|
187
|
-
<input type="number" id="ssp-ext-margin" class="ssp-input" value="0" min="0" aria-label={ui.marginLabel} />
|
|
188
|
-
<button id="ssp-mar-inc" class="ssp-step-btn" type="button" aria-label="Increase Margin">+</button>
|
|
189
|
-
</div>
|
|
190
|
-
</div>
|
|
191
|
-
|
|
192
|
-
<div class="ssp-control-group">
|
|
193
|
-
<label for="ssp-ext-spacing" class="ssp-label">{ui.spacingLabel}</label>
|
|
194
|
-
<div class="ssp-stepper-box">
|
|
195
|
-
<button id="ssp-spc-dec" class="ssp-step-btn" type="button" aria-label="Decrease Spacing">-</button>
|
|
196
|
-
<input type="number" id="ssp-ext-spacing" class="ssp-input" value="0" min="0" aria-label={ui.spacingLabel} />
|
|
197
|
-
<button id="ssp-spc-inc" class="ssp-step-btn" type="button" aria-label="Increase Spacing">+</button>
|
|
198
|
-
</div>
|
|
199
|
-
</div>
|
|
200
|
-
</div>
|
|
201
|
-
|
|
202
|
-
<button id="ssp-btn-extract-zip" class="ssp-btn ssp-btn-primary" type="button">{ui.downloadZipButton}</button>
|
|
203
|
-
</div>
|
|
204
|
-
|
|
205
|
-
<div class="ssp-main-section">
|
|
206
|
-
<div class="ssp-stat-badge" style="align-self: flex-start;">
|
|
207
|
-
<div id="ssp-ext-count" class="ssp-stat-val">0</div>
|
|
208
|
-
<div class="ssp-stat-lbl">{ui.extractedCountLabel}</div>
|
|
209
|
-
</div>
|
|
210
|
-
<div class="ssp-canvas-wrapper">
|
|
211
|
-
<canvas id="ssp-ext-canvas" class="ssp-canvas" width="512" height="512" aria-label={ui.previewTitle}></canvas>
|
|
212
|
-
</div>
|
|
213
|
-
</div>
|
|
214
|
-
</div>
|
|
215
|
-
|
|
216
|
-
<div id="ssp-toast" class="ssp-toast">{ui.copiedToast}</div>
|
|
217
|
-
<div id="ssp-particle-container" class="ssp-particle-container"></div>
|
|
218
|
-
</div>
|
|
219
|
-
</div>
|
|
220
|
-
|
|
221
|
-
<script>
|
|
222
|
-
import { initSpriteSheetPackerApp } from './app-client';
|
|
223
|
-
|
|
224
|
-
if (document.readyState === 'loading') {
|
|
225
|
-
document.addEventListener('DOMContentLoaded', initSpriteSheetPackerApp);
|
|
226
|
-
} else {
|
|
227
|
-
initSpriteSheetPackerApp();
|
|
228
|
-
}
|
|
229
|
-
</script>
|
|
1
|
+
---
|
|
2
|
+
import type { SpriteSheetPackerUI } from './ui';
|
|
3
|
+
import './sprite-sheet-packer.css';
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
ui: SpriteSheetPackerUI;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const { ui } = Astro.props;
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
<div class="ssp-container">
|
|
13
|
+
<div class="ssp-main-card">
|
|
14
|
+
<div class="ssp-header-tabs" role="tablist">
|
|
15
|
+
<button id="ssp-tab-packer" class="ssp-tab-btn active" role="tab" aria-selected="true" aria-controls="ssp-packer-panel">
|
|
16
|
+
{ui.packerTab}
|
|
17
|
+
</button>
|
|
18
|
+
<button id="ssp-tab-extractor" class="ssp-tab-btn" role="tab" aria-selected="false" aria-controls="ssp-extractor-panel">
|
|
19
|
+
{ui.extractorTab}
|
|
20
|
+
</button>
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
<div id="ssp-packer-panel" class="ssp-body-grid" role="tabpanel" aria-labelledby="ssp-tab-packer">
|
|
24
|
+
<div class="ssp-sidebar-section">
|
|
25
|
+
<div id="ssp-dropzone" class="ssp-dropzone">
|
|
26
|
+
<div class="ssp-drop-title">{ui.dropZoneTitle}</div>
|
|
27
|
+
<div class="ssp-drop-sub">{ui.dropZoneSubtitle}</div>
|
|
28
|
+
<input type="file" id="ssp-file-input" class="ssp-file-input" multiple accept="image/png,image/jpeg,image/webp" aria-label={ui.selectFilesButton} />
|
|
29
|
+
</div>
|
|
30
|
+
|
|
31
|
+
<div class="ssp-btn-row">
|
|
32
|
+
<button id="ssp-btn-select" class="ssp-btn ssp-btn-primary" type="button">{ui.selectFilesButton}</button>
|
|
33
|
+
<button id="ssp-btn-clear" class="ssp-btn ssp-btn-danger" type="button">{ui.clearAllButton}</button>
|
|
34
|
+
</div>
|
|
35
|
+
|
|
36
|
+
<div class="ssp-presets-row">
|
|
37
|
+
<button id="ssp-preset-pixel" class="ssp-chip-btn" type="button">{ui.presetPixelArt}</button>
|
|
38
|
+
<button id="ssp-preset-hd" class="ssp-chip-btn" type="button">{ui.presetHdUi}</button>
|
|
39
|
+
<button id="ssp-preset-mobile" class="ssp-chip-btn" type="button">{ui.presetMobile}</button>
|
|
40
|
+
</div>
|
|
41
|
+
|
|
42
|
+
<div class="ssp-controls-list">
|
|
43
|
+
<div class="ssp-control-group">
|
|
44
|
+
<label for="ssp-export-format" class="ssp-label"><span>{ui.exportFormatLabel}</span></label>
|
|
45
|
+
<select id="ssp-export-format" class="ssp-select">
|
|
46
|
+
<option value="generic-json-hash">{ui.formatGenericHash}</option>
|
|
47
|
+
<option value="generic-json-array">{ui.formatGenericArray}</option>
|
|
48
|
+
<option value="unity">{ui.formatUnity}</option>
|
|
49
|
+
<option value="godot">{ui.formatGodot}</option>
|
|
50
|
+
<option value="phaser">{ui.formatPhaser}</option>
|
|
51
|
+
<option value="css">{ui.formatCss}</option>
|
|
52
|
+
</select>
|
|
53
|
+
</div>
|
|
54
|
+
|
|
55
|
+
<div class="ssp-control-group">
|
|
56
|
+
<label for="ssp-padding" class="ssp-label">
|
|
57
|
+
<span>{ui.paddingLabel}</span>
|
|
58
|
+
<span id="ssp-padding-val">2</span>
|
|
59
|
+
</label>
|
|
60
|
+
<div class="ssp-stepper-box">
|
|
61
|
+
<button id="ssp-pad-dec" class="ssp-step-btn" type="button" aria-label="Decrease Padding">-</button>
|
|
62
|
+
<input type="range" id="ssp-padding" class="ssp-slider" min="0" max="32" value="2" aria-label={ui.paddingLabel} />
|
|
63
|
+
<button id="ssp-pad-inc" class="ssp-step-btn" type="button" aria-label="Increase Padding">+</button>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
|
|
67
|
+
<div class="ssp-control-group">
|
|
68
|
+
<label for="ssp-extrusion" class="ssp-label">
|
|
69
|
+
<span>{ui.borderExtrusionLabel}</span>
|
|
70
|
+
<span id="ssp-extrusion-val">0</span>
|
|
71
|
+
</label>
|
|
72
|
+
<div class="ssp-stepper-box">
|
|
73
|
+
<button id="ssp-ext-dec" class="ssp-step-btn" type="button" aria-label="Decrease Extrusion">-</button>
|
|
74
|
+
<input type="range" id="ssp-extrusion" class="ssp-slider" min="0" max="8" value="0" aria-label={ui.borderExtrusionLabel} />
|
|
75
|
+
<button id="ssp-ext-inc" class="ssp-step-btn" type="button" aria-label="Increase Extrusion">+</button>
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
<div class="ssp-control-group">
|
|
80
|
+
<label for="ssp-max-size" class="ssp-label"><span>{ui.maxTextureSizeLabel}</span></label>
|
|
81
|
+
<select id="ssp-max-size" class="ssp-select">
|
|
82
|
+
<option value="512">512 x 512 px</option>
|
|
83
|
+
<option value="1024">1024 x 1024 px</option>
|
|
84
|
+
<option value="2048" selected>2048 x 2048 px</option>
|
|
85
|
+
<option value="4096">4096 x 4096 px</option>
|
|
86
|
+
</select>
|
|
87
|
+
</div>
|
|
88
|
+
|
|
89
|
+
<div class="ssp-toggle-group">
|
|
90
|
+
<label for="ssp-power-two" class="ssp-label">{ui.powerOfTwoLabel}</label>
|
|
91
|
+
<input type="checkbox" id="ssp-power-two" class="ssp-toggle-input" checked aria-label={ui.powerOfTwoLabel} />
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
</div>
|
|
95
|
+
|
|
96
|
+
<div class="ssp-main-section">
|
|
97
|
+
<div class="ssp-stats-grid">
|
|
98
|
+
<div class="ssp-stat-badge">
|
|
99
|
+
<div id="ssp-stat-efficiency" class="ssp-stat-val">0%</div>
|
|
100
|
+
<div class="ssp-stat-lbl">{ui.efficiencyBadge}</div>
|
|
101
|
+
</div>
|
|
102
|
+
<div class="ssp-stat-badge">
|
|
103
|
+
<div id="ssp-stat-drawcalls" class="ssp-stat-val">0</div>
|
|
104
|
+
<div class="ssp-stat-lbl">{ui.drawCallsBadge}</div>
|
|
105
|
+
</div>
|
|
106
|
+
<div class="ssp-stat-badge">
|
|
107
|
+
<div id="ssp-stat-frames" class="ssp-stat-val">0</div>
|
|
108
|
+
<div class="ssp-stat-lbl">{ui.totalFramesBadge}</div>
|
|
109
|
+
</div>
|
|
110
|
+
<div class="ssp-stat-badge">
|
|
111
|
+
<div id="ssp-stat-size" class="ssp-stat-val">0x0</div>
|
|
112
|
+
<div class="ssp-stat-lbl">{ui.textureSizeBadge}</div>
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
115
|
+
|
|
116
|
+
<div class="ssp-canvas-wrapper">
|
|
117
|
+
<canvas id="ssp-atlas-canvas" class="ssp-canvas" width="512" height="512" aria-label={ui.previewTitle}></canvas>
|
|
118
|
+
</div>
|
|
119
|
+
|
|
120
|
+
<div class="ssp-btn-row">
|
|
121
|
+
<button id="ssp-btn-download-zip" class="ssp-btn ssp-btn-primary" type="button">{ui.downloadZipButton}</button>
|
|
122
|
+
<button id="ssp-btn-copy-json" class="ssp-btn ssp-btn-secondary" type="button">{ui.copyJsonButton}</button>
|
|
123
|
+
<button id="ssp-btn-download-png" class="ssp-btn ssp-btn-secondary" type="button">{ui.downloadSheetPngButton}</button>
|
|
124
|
+
</div>
|
|
125
|
+
|
|
126
|
+
<div class="ssp-flipbook-box">
|
|
127
|
+
<div class="ssp-flipbook-header">{ui.flipbookTitle}</div>
|
|
128
|
+
<div class="ssp-flipbook-body">
|
|
129
|
+
<canvas id="ssp-flipbook-canvas" class="ssp-flipbook-canvas" width="128" height="128" aria-label={ui.flipbookTitle}></canvas>
|
|
130
|
+
<div class="ssp-flipbook-controls">
|
|
131
|
+
<div class="ssp-control-group">
|
|
132
|
+
<label for="ssp-fps-slider" class="ssp-label">
|
|
133
|
+
<span>{ui.flipbookFpsLabel}</span>
|
|
134
|
+
<span id="ssp-fps-val">12 FPS</span>
|
|
135
|
+
</label>
|
|
136
|
+
<input type="range" id="ssp-fps-slider" class="ssp-slider" min="1" max="60" value="12" aria-label={ui.flipbookFpsLabel} />
|
|
137
|
+
</div>
|
|
138
|
+
<div class="ssp-btn-row">
|
|
139
|
+
<button id="ssp-btn-play" class="ssp-btn ssp-btn-secondary" type="button">{ui.playAnimation}</button>
|
|
140
|
+
<button id="ssp-btn-pause" class="ssp-btn ssp-btn-secondary" type="button">{ui.pauseAnimation}</button>
|
|
141
|
+
</div>
|
|
142
|
+
</div>
|
|
143
|
+
</div>
|
|
144
|
+
</div>
|
|
145
|
+
|
|
146
|
+
<div class="ssp-code-container">
|
|
147
|
+
<div class="ssp-code-header">
|
|
148
|
+
<span class="ssp-code-title">{ui.codeSnippetTitle}</span>
|
|
149
|
+
<button id="ssp-btn-copy-code" class="ssp-copy-btn" type="button">{ui.copySnippetButton}</button>
|
|
150
|
+
</div>
|
|
151
|
+
<pre id="ssp-code-snippet" class="ssp-code-block"></pre>
|
|
152
|
+
</div>
|
|
153
|
+
</div>
|
|
154
|
+
</div>
|
|
155
|
+
|
|
156
|
+
<div id="ssp-extractor-panel" class="ssp-body-grid" role="tabpanel" aria-labelledby="ssp-tab-extractor" style="display: none;">
|
|
157
|
+
<div class="ssp-sidebar-section">
|
|
158
|
+
<div id="ssp-ext-dropzone" class="ssp-dropzone">
|
|
159
|
+
<div class="ssp-drop-title">{ui.dropZoneTitle}</div>
|
|
160
|
+
<div class="ssp-drop-sub">{ui.dropZoneSubtitle}</div>
|
|
161
|
+
<input type="file" id="ssp-ext-file-input" class="ssp-file-input" accept="image/png,image/jpeg,image/webp" aria-label={ui.selectFilesButton} />
|
|
162
|
+
</div>
|
|
163
|
+
|
|
164
|
+
<div class="ssp-controls-list">
|
|
165
|
+
<div class="ssp-control-group">
|
|
166
|
+
<label for="ssp-ext-width" class="ssp-label">{ui.frameWidthLabel}</label>
|
|
167
|
+
<div class="ssp-stepper-box">
|
|
168
|
+
<button id="ssp-fw-dec" class="ssp-step-btn" type="button" aria-label="Decrease Frame Width">-</button>
|
|
169
|
+
<input type="number" id="ssp-ext-width" class="ssp-input" value="32" min="1" aria-label={ui.frameWidthLabel} />
|
|
170
|
+
<button id="ssp-fw-inc" class="ssp-step-btn" type="button" aria-label="Increase Frame Width">+</button>
|
|
171
|
+
</div>
|
|
172
|
+
</div>
|
|
173
|
+
|
|
174
|
+
<div class="ssp-control-group">
|
|
175
|
+
<label for="ssp-ext-height" class="ssp-label">{ui.frameHeightLabel}</label>
|
|
176
|
+
<div class="ssp-stepper-box">
|
|
177
|
+
<button id="ssp-fh-dec" class="ssp-step-btn" type="button" aria-label="Decrease Frame Height">-</button>
|
|
178
|
+
<input type="number" id="ssp-ext-height" class="ssp-input" value="32" min="1" aria-label={ui.frameHeightLabel} />
|
|
179
|
+
<button id="ssp-fh-inc" class="ssp-step-btn" type="button" aria-label="Increase Frame Height">+</button>
|
|
180
|
+
</div>
|
|
181
|
+
</div>
|
|
182
|
+
|
|
183
|
+
<div class="ssp-control-group">
|
|
184
|
+
<label for="ssp-ext-margin" class="ssp-label">{ui.marginLabel}</label>
|
|
185
|
+
<div class="ssp-stepper-box">
|
|
186
|
+
<button id="ssp-mar-dec" class="ssp-step-btn" type="button" aria-label="Decrease Margin">-</button>
|
|
187
|
+
<input type="number" id="ssp-ext-margin" class="ssp-input" value="0" min="0" aria-label={ui.marginLabel} />
|
|
188
|
+
<button id="ssp-mar-inc" class="ssp-step-btn" type="button" aria-label="Increase Margin">+</button>
|
|
189
|
+
</div>
|
|
190
|
+
</div>
|
|
191
|
+
|
|
192
|
+
<div class="ssp-control-group">
|
|
193
|
+
<label for="ssp-ext-spacing" class="ssp-label">{ui.spacingLabel}</label>
|
|
194
|
+
<div class="ssp-stepper-box">
|
|
195
|
+
<button id="ssp-spc-dec" class="ssp-step-btn" type="button" aria-label="Decrease Spacing">-</button>
|
|
196
|
+
<input type="number" id="ssp-ext-spacing" class="ssp-input" value="0" min="0" aria-label={ui.spacingLabel} />
|
|
197
|
+
<button id="ssp-spc-inc" class="ssp-step-btn" type="button" aria-label="Increase Spacing">+</button>
|
|
198
|
+
</div>
|
|
199
|
+
</div>
|
|
200
|
+
</div>
|
|
201
|
+
|
|
202
|
+
<button id="ssp-btn-extract-zip" class="ssp-btn ssp-btn-primary" type="button">{ui.downloadZipButton}</button>
|
|
203
|
+
</div>
|
|
204
|
+
|
|
205
|
+
<div class="ssp-main-section">
|
|
206
|
+
<div class="ssp-stat-badge" style="align-self: flex-start;">
|
|
207
|
+
<div id="ssp-ext-count" class="ssp-stat-val">0</div>
|
|
208
|
+
<div class="ssp-stat-lbl">{ui.extractedCountLabel}</div>
|
|
209
|
+
</div>
|
|
210
|
+
<div class="ssp-canvas-wrapper">
|
|
211
|
+
<canvas id="ssp-ext-canvas" class="ssp-canvas" width="512" height="512" aria-label={ui.previewTitle}></canvas>
|
|
212
|
+
</div>
|
|
213
|
+
</div>
|
|
214
|
+
</div>
|
|
215
|
+
|
|
216
|
+
<div id="ssp-toast" class="ssp-toast">{ui.copiedToast}</div>
|
|
217
|
+
<div id="ssp-particle-container" class="ssp-particle-container"></div>
|
|
218
|
+
</div>
|
|
219
|
+
</div>
|
|
220
|
+
|
|
221
|
+
<script>
|
|
222
|
+
import { initSpriteSheetPackerApp } from './app-client';
|
|
223
|
+
|
|
224
|
+
if (document.readyState === 'loading') {
|
|
225
|
+
document.addEventListener('DOMContentLoaded', initSpriteSheetPackerApp);
|
|
226
|
+
} else {
|
|
227
|
+
initSpriteSheetPackerApp();
|
|
228
|
+
}
|
|
229
|
+
</script>
|
|
@@ -1,55 +1,55 @@
|
|
|
1
|
-
import { spawnParticle, type LoadedImageItem } from './packer-ui';
|
|
2
|
-
|
|
3
|
-
export function handleFilesUpload(files: File[], loadedImages: LoadedImageItem[], updatePacker: () => void): void {
|
|
4
|
-
const promises = files.map((file) => {
|
|
5
|
-
return new Promise<void>((resolve) => {
|
|
6
|
-
const img = new Image();
|
|
7
|
-
const url = URL.createObjectURL(file);
|
|
8
|
-
img.onload = () => {
|
|
9
|
-
loadedImages.push({
|
|
10
|
-
file,
|
|
11
|
-
img,
|
|
12
|
-
id: Math.random().toString(36).substring(2, 9),
|
|
13
|
-
name: file.name.replace(/\.[^/.]+$/, ''),
|
|
14
|
-
});
|
|
15
|
-
resolve();
|
|
16
|
-
};
|
|
17
|
-
img.src = url;
|
|
18
|
-
});
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
Promise.all(promises).then(() => updatePacker());
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function bindDropzone(loadedImages: LoadedImageItem[], updatePacker: () => void): void {
|
|
25
|
-
const dropzone = document.getElementById('ssp-dropzone');
|
|
26
|
-
const fileInput = document.getElementById('ssp-file-input') as HTMLInputElement | null;
|
|
27
|
-
|
|
28
|
-
document.getElementById('ssp-btn-select')?.addEventListener('click', () => fileInput?.click());
|
|
29
|
-
dropzone?.addEventListener('click', () => fileInput?.click());
|
|
30
|
-
|
|
31
|
-
dropzone?.addEventListener('dragover', (e) => {
|
|
32
|
-
e.preventDefault();
|
|
33
|
-
dropzone.classList.add('dragover');
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
dropzone?.addEventListener('dragleave', (e) => {
|
|
37
|
-
e.preventDefault();
|
|
38
|
-
dropzone.classList.remove('dragover');
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
dropzone?.addEventListener('drop', (e: DragEvent) => {
|
|
42
|
-
e.preventDefault();
|
|
43
|
-
dropzone.classList.remove('dragover');
|
|
44
|
-
if (e.dataTransfer?.files?.length) {
|
|
45
|
-
handleFilesUpload(Array.from(e.dataTransfer.files), loadedImages, updatePacker);
|
|
46
|
-
spawnParticle(e.clientX, e.clientY, 'PACKED!');
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
fileInput?.addEventListener('change', () => {
|
|
51
|
-
if (fileInput.files?.length) {
|
|
52
|
-
handleFilesUpload(Array.from(fileInput.files), loadedImages, updatePacker);
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
}
|
|
1
|
+
import { spawnParticle, type LoadedImageItem } from './packer-ui';
|
|
2
|
+
|
|
3
|
+
export function handleFilesUpload(files: File[], loadedImages: LoadedImageItem[], updatePacker: () => void): void {
|
|
4
|
+
const promises = files.map((file) => {
|
|
5
|
+
return new Promise<void>((resolve) => {
|
|
6
|
+
const img = new Image();
|
|
7
|
+
const url = URL.createObjectURL(file);
|
|
8
|
+
img.onload = () => {
|
|
9
|
+
loadedImages.push({
|
|
10
|
+
file,
|
|
11
|
+
img,
|
|
12
|
+
id: Math.random().toString(36).substring(2, 9),
|
|
13
|
+
name: file.name.replace(/\.[^/.]+$/, ''),
|
|
14
|
+
});
|
|
15
|
+
resolve();
|
|
16
|
+
};
|
|
17
|
+
img.src = url;
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
Promise.all(promises).then(() => updatePacker());
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function bindDropzone(loadedImages: LoadedImageItem[], updatePacker: () => void): void {
|
|
25
|
+
const dropzone = document.getElementById('ssp-dropzone');
|
|
26
|
+
const fileInput = document.getElementById('ssp-file-input') as HTMLInputElement | null;
|
|
27
|
+
|
|
28
|
+
document.getElementById('ssp-btn-select')?.addEventListener('click', () => fileInput?.click());
|
|
29
|
+
dropzone?.addEventListener('click', () => fileInput?.click());
|
|
30
|
+
|
|
31
|
+
dropzone?.addEventListener('dragover', (e) => {
|
|
32
|
+
e.preventDefault();
|
|
33
|
+
dropzone.classList.add('dragover');
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
dropzone?.addEventListener('dragleave', (e) => {
|
|
37
|
+
e.preventDefault();
|
|
38
|
+
dropzone.classList.remove('dragover');
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
dropzone?.addEventListener('drop', (e: DragEvent) => {
|
|
42
|
+
e.preventDefault();
|
|
43
|
+
dropzone.classList.remove('dragover');
|
|
44
|
+
if (e.dataTransfer?.files?.length) {
|
|
45
|
+
handleFilesUpload(Array.from(e.dataTransfer.files), loadedImages, updatePacker);
|
|
46
|
+
spawnParticle(e.clientX, e.clientY, 'PACKED!');
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
fileInput?.addEventListener('change', () => {
|
|
51
|
+
if (fileInput.files?.length) {
|
|
52
|
+
handleFilesUpload(Array.from(fileInput.files), loadedImages, updatePacker);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
}
|
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
import type { GamesToolEntry, ToolLocaleContent } from '../../types';
|
|
2
|
-
import type { SpriteSheetPackerUI } from './ui';
|
|
3
|
-
|
|
4
|
-
export type { SpriteSheetPackerUI };
|
|
5
|
-
|
|
6
|
-
export type SpriteSheetPackerLocaleContent = ToolLocaleContent<SpriteSheetPackerUI>;
|
|
7
|
-
|
|
8
|
-
export const spriteSheetPacker: GamesToolEntry<SpriteSheetPackerUI> = {
|
|
9
|
-
id: 'sprite-sheet-packer',
|
|
10
|
-
icons: { bg: 'mdi:gamepad-variant', fg: 'mdi:texture-box' },
|
|
11
|
-
i18n: {
|
|
12
|
-
de: () => import('./i18n/de').then((m) => m.content),
|
|
13
|
-
en: () => import('./i18n/en').then((m) => m.content),
|
|
14
|
-
es: () => import('./i18n/es').then((m) => m.content),
|
|
15
|
-
fr: () => import('./i18n/fr').then((m) => m.content),
|
|
16
|
-
id: () => import('./i18n/id').then((m) => m.content),
|
|
17
|
-
it: () => import('./i18n/it').then((m) => m.content),
|
|
18
|
-
ja: () => import('./i18n/ja').then((m) => m.content),
|
|
19
|
-
ko: () => import('./i18n/ko').then((m) => m.content),
|
|
20
|
-
nl: () => import('./i18n/nl').then((m) => m.content),
|
|
21
|
-
pl: () => import('./i18n/pl').then((m) => m.content),
|
|
22
|
-
pt: () => import('./i18n/pt').then((m) => m.content),
|
|
23
|
-
ru: () => import('./i18n/ru').then((m) => m.content),
|
|
24
|
-
sv: () => import('./i18n/sv').then((m) => m.content),
|
|
25
|
-
tr: () => import('./i18n/tr').then((m) => m.content),
|
|
26
|
-
zh: () => import('./i18n/zh').then((m) => m.content),
|
|
27
|
-
},
|
|
28
|
-
};
|
|
1
|
+
import type { GamesToolEntry, ToolLocaleContent } from '../../types';
|
|
2
|
+
import type { SpriteSheetPackerUI } from './ui';
|
|
3
|
+
|
|
4
|
+
export type { SpriteSheetPackerUI };
|
|
5
|
+
|
|
6
|
+
export type SpriteSheetPackerLocaleContent = ToolLocaleContent<SpriteSheetPackerUI>;
|
|
7
|
+
|
|
8
|
+
export const spriteSheetPacker: GamesToolEntry<SpriteSheetPackerUI> = {
|
|
9
|
+
id: 'sprite-sheet-packer',
|
|
10
|
+
icons: { bg: 'mdi:gamepad-variant', fg: 'mdi:texture-box' },
|
|
11
|
+
i18n: {
|
|
12
|
+
de: () => import('./i18n/de').then((m) => m.content),
|
|
13
|
+
en: () => import('./i18n/en').then((m) => m.content),
|
|
14
|
+
es: () => import('./i18n/es').then((m) => m.content),
|
|
15
|
+
fr: () => import('./i18n/fr').then((m) => m.content),
|
|
16
|
+
id: () => import('./i18n/id').then((m) => m.content),
|
|
17
|
+
it: () => import('./i18n/it').then((m) => m.content),
|
|
18
|
+
ja: () => import('./i18n/ja').then((m) => m.content),
|
|
19
|
+
ko: () => import('./i18n/ko').then((m) => m.content),
|
|
20
|
+
nl: () => import('./i18n/nl').then((m) => m.content),
|
|
21
|
+
pl: () => import('./i18n/pl').then((m) => m.content),
|
|
22
|
+
pt: () => import('./i18n/pt').then((m) => m.content),
|
|
23
|
+
ru: () => import('./i18n/ru').then((m) => m.content),
|
|
24
|
+
sv: () => import('./i18n/sv').then((m) => m.content),
|
|
25
|
+
tr: () => import('./i18n/tr').then((m) => m.content),
|
|
26
|
+
zh: () => import('./i18n/zh').then((m) => m.content),
|
|
27
|
+
},
|
|
28
|
+
};
|