@jjlmoya/utils-games-development 1.46.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.
Files changed (84) hide show
  1. package/package.json +67 -0
  2. package/scripts/postinstall.mjs +27 -0
  3. package/src/category/GamesCategorySEO.astro +19 -0
  4. package/src/category/i18n/de.ts +15 -0
  5. package/src/category/i18n/en.ts +15 -0
  6. package/src/category/i18n/es.ts +15 -0
  7. package/src/category/i18n/fr.ts +15 -0
  8. package/src/category/i18n/id.ts +10 -0
  9. package/src/category/i18n/it.ts +10 -0
  10. package/src/category/i18n/ja.ts +10 -0
  11. package/src/category/i18n/ko.ts +10 -0
  12. package/src/category/i18n/nl.ts +10 -0
  13. package/src/category/i18n/pl.ts +10 -0
  14. package/src/category/i18n/pt.ts +10 -0
  15. package/src/category/i18n/ru.ts +10 -0
  16. package/src/category/i18n/sv.ts +10 -0
  17. package/src/category/i18n/tr.ts +10 -0
  18. package/src/category/i18n/zh.ts +10 -0
  19. package/src/category/index.ts +24 -0
  20. package/src/category/seo.astro +15 -0
  21. package/src/components/PreviewNavSidebar.astro +116 -0
  22. package/src/components/PreviewToolbar.astro +143 -0
  23. package/src/data.ts +11 -0
  24. package/src/entries.ts +5 -0
  25. package/src/env.d.ts +5 -0
  26. package/src/index.ts +21 -0
  27. package/src/layouts/PreviewLayout.astro +122 -0
  28. package/src/pages/[locale]/[slug].astro +165 -0
  29. package/src/pages/[locale].astro +251 -0
  30. package/src/pages/index.astro +4 -0
  31. package/src/tests/diacritics_density.test.ts +118 -0
  32. package/src/tests/faq_count.test.ts +19 -0
  33. package/src/tests/i18n_coverage.test.ts +36 -0
  34. package/src/tests/inverted_punctuation.test.ts +84 -0
  35. package/src/tests/locale_completeness.test.ts +27 -0
  36. package/src/tests/mocks/astro_mock.js +2 -0
  37. package/src/tests/no_en_dash.test.ts +70 -0
  38. package/src/tests/no_h1_in_components.test.ts +48 -0
  39. package/src/tests/pagespeed_best_practices.test.ts +198 -0
  40. package/src/tests/qa-test-helpers.ts +32 -0
  41. package/src/tests/qa_bibliography_links.test.ts +41 -0
  42. package/src/tests/qa_claim_evidence.test.ts +69 -0
  43. package/src/tests/qa_logic_reference_coverage.test.ts +46 -0
  44. package/src/tests/qa_runtime_i18n.test.ts +100 -0
  45. package/src/tests/schemas_fulfillment.test.ts +23 -0
  46. package/src/tests/script_density.test.ts +94 -0
  47. package/src/tests/seo_length.test.ts +23 -0
  48. package/src/tests/slug_language_code_format.test.ts +23 -0
  49. package/src/tests/slug_uniqueness.test.ts +81 -0
  50. package/src/tests/title_quality.test.ts +56 -0
  51. package/src/tests/tool_validation.test.ts +17 -0
  52. package/src/tool/steamCapsuleGenerator/bibliography.astro +6 -0
  53. package/src/tool/steamCapsuleGenerator/bibliography.ts +6 -0
  54. package/src/tool/steamCapsuleGenerator/component.astro +289 -0
  55. package/src/tool/steamCapsuleGenerator/components/SteamLibraryGridMockup.astro +51 -0
  56. package/src/tool/steamCapsuleGenerator/components/SteamLibraryMockup.astro +64 -0
  57. package/src/tool/steamCapsuleGenerator/components/SteamMasterControls.astro +2 -0
  58. package/src/tool/steamCapsuleGenerator/components/SteamStoreMockup.astro +90 -0
  59. package/src/tool/steamCapsuleGenerator/entry.ts +28 -0
  60. package/src/tool/steamCapsuleGenerator/i18n/de.ts +144 -0
  61. package/src/tool/steamCapsuleGenerator/i18n/en.ts +243 -0
  62. package/src/tool/steamCapsuleGenerator/i18n/es.ts +243 -0
  63. package/src/tool/steamCapsuleGenerator/i18n/fr.ts +165 -0
  64. package/src/tool/steamCapsuleGenerator/i18n/id.ts +144 -0
  65. package/src/tool/steamCapsuleGenerator/i18n/it.ts +144 -0
  66. package/src/tool/steamCapsuleGenerator/i18n/ja.ts +144 -0
  67. package/src/tool/steamCapsuleGenerator/i18n/ko.ts +144 -0
  68. package/src/tool/steamCapsuleGenerator/i18n/nl.ts +144 -0
  69. package/src/tool/steamCapsuleGenerator/i18n/pl.ts +144 -0
  70. package/src/tool/steamCapsuleGenerator/i18n/pt.ts +144 -0
  71. package/src/tool/steamCapsuleGenerator/i18n/ru.ts +144 -0
  72. package/src/tool/steamCapsuleGenerator/i18n/shared.ts +46 -0
  73. package/src/tool/steamCapsuleGenerator/i18n/sv.ts +144 -0
  74. package/src/tool/steamCapsuleGenerator/i18n/tr.ts +144 -0
  75. package/src/tool/steamCapsuleGenerator/i18n/zh.ts +144 -0
  76. package/src/tool/steamCapsuleGenerator/index.ts +9 -0
  77. package/src/tool/steamCapsuleGenerator/logic.test.ts +72 -0
  78. package/src/tool/steamCapsuleGenerator/logic.ts +259 -0
  79. package/src/tool/steamCapsuleGenerator/seo.astro +15 -0
  80. package/src/tool/steamCapsuleGenerator/steam-capsule-generator.css +697 -0
  81. package/src/tool/steamCapsuleGenerator/ui.ts +23 -0
  82. package/src/tool/steamCapsuleGenerator/validation.ts +22 -0
  83. package/src/tools.ts +8 -0
  84. package/src/types.ts +72 -0
@@ -0,0 +1,289 @@
1
+ ---
2
+ import type { SteamCapsuleGeneratorUI } from './ui';
3
+ import SteamStoreMockup from './components/SteamStoreMockup.astro';
4
+ import SteamLibraryMockup from './components/SteamLibraryMockup.astro';
5
+ import SteamLibraryGridMockup from './components/SteamLibraryGridMockup.astro';
6
+ import './steam-capsule-generator.css';
7
+
8
+ interface Props {
9
+ ui: SteamCapsuleGeneratorUI;
10
+ }
11
+
12
+ const { ui: t } = Astro.props;
13
+ ---
14
+
15
+ <div class="steam-tool-container" id="steam-capsule-tool">
16
+ <div class="steam-unified-card">
17
+ <div class="steam-compact-bar">
18
+ <div class="steam-mode-tabs" role="tablist" aria-label="Steam Preview Modes">
19
+ <button type="button" class="steam-tab-btn active" id="tab-store" role="tab" aria-selected="true" data-tab="store">
20
+ {t.storePreviewTab}
21
+ </button>
22
+ <button type="button" class="steam-tab-btn" id="tab-library" role="tab" aria-selected="false" data-tab="library">
23
+ {t.libraryPreviewTab}
24
+ </button>
25
+ <button type="button" class="steam-tab-btn" id="tab-assets" role="tab" aria-selected="false" data-tab="assets">
26
+ {t.allAssetsTab}
27
+ </button>
28
+ </div>
29
+
30
+ <div class="steam-preset-chips">
31
+ <span class="preset-label">{t.minimumSize}</span>
32
+ <button type="button" class="preset-chip active" data-preset="gamebob">GameBob Crunch</button>
33
+ <button type="button" class="preset-chip" data-preset="retro">Pixel RPG</button>
34
+ <button type="button" class="preset-chip" data-preset="cyber">Cyberpunk AAA</button>
35
+ </div>
36
+
37
+ <div class="steam-inline-sliders">
38
+ <div class="slider-item">
39
+ <label for="focus-x-slider">{t.horizontalFocus}</label>
40
+ <input type="range" id="focus-x-slider" class="steam-range-input" min="0" max="100" value="50" aria-label={t.horizontalFocus} />
41
+ </div>
42
+ <div class="slider-item">
43
+ <label for="focus-y-slider">{t.verticalFocus}</label>
44
+ <input type="range" id="focus-y-slider" class="steam-range-input" min="0" max="100" value="50" aria-label={t.verticalFocus} />
45
+ </div>
46
+ <div class="slider-item">
47
+ <label for="zoom-slider">{t.zoomLevel}</label>
48
+ <input type="range" id="zoom-slider" class="steam-range-input" min="100" max="250" value="100" aria-label={t.zoomLevel} />
49
+ </div>
50
+ </div>
51
+
52
+ <div class="steam-quick-actions">
53
+ <button type="button" class="preset-chip" id="steam-reset-btn">{t.resetFocus}</button>
54
+ <label for="toggle-safe-zones" class="steam-toggle-label">
55
+ <input type="checkbox" id="toggle-safe-zones" class="steam-toggle-checkbox" checked />
56
+ {t.toggleSafeZones}
57
+ </label>
58
+ <button type="button" class="steam-btn-primary" id="steam-choose-btn">{t.chooseFile}</button>
59
+ <button type="button" class="steam-btn-primary download-zip-highlight" id="steam-zip-download-btn">{t.downloadZip}</button>
60
+ </div>
61
+
62
+ <input type="file" id="steam-image-input" class="steam-upload-input" accept="image/png,image/jpeg,image/webp" aria-label={t.uploadTitle} />
63
+ <span style="display: none;">{t.uploadHint} {t.toggleSteamOverlay}</span>
64
+ </div>
65
+
66
+ <div class="steam-preview-viewport">
67
+ <div id="panel-store" class="steam-preview-panel">
68
+ <SteamStoreMockup ui={t} />
69
+ </div>
70
+
71
+ <div id="panel-library" class="steam-preview-panel" style="display: none;">
72
+ <SteamLibraryMockup ui={t} />
73
+ <div style="margin-top: 1.25rem;">
74
+ <SteamLibraryGridMockup ui={t} />
75
+ </div>
76
+ </div>
77
+
78
+ <div id="panel-assets" class="steam-preview-panel" style="display: none;">
79
+ <div class="steam-assets-grid">
80
+ <div class="steam-asset-item">
81
+ <div class="steam-asset-info">
82
+ <span class="steam-asset-title">{t.headerCapsule}</span>
83
+ <span class="steam-asset-badge">920x430</span>
84
+ </div>
85
+ <div class="steam-asset-preview-box">
86
+ <canvas id="canvas-header-capsule-grid" width="920" height="430" aria-label={t.headerCapsule}></canvas>
87
+ </div>
88
+ </div>
89
+
90
+ <div class="steam-asset-item">
91
+ <div class="steam-asset-info">
92
+ <span class="steam-asset-title">{t.smallCapsule}</span>
93
+ <span class="steam-asset-badge">462x174</span>
94
+ </div>
95
+ <div class="steam-asset-preview-box">
96
+ <canvas id="canvas-small-capsule-grid" width="462" height="174" aria-label={t.smallCapsule}></canvas>
97
+ </div>
98
+ </div>
99
+
100
+ <div class="steam-asset-item">
101
+ <div class="steam-asset-info">
102
+ <span class="steam-asset-title">{t.verticalCapsule}</span>
103
+ <span class="steam-asset-badge">600x900</span>
104
+ </div>
105
+ <div class="steam-asset-preview-box">
106
+ <canvas id="canvas-vertical-capsule-grid" width="600" height="900" aria-label={t.verticalCapsule}></canvas>
107
+ </div>
108
+ </div>
109
+
110
+ <div class="steam-asset-item">
111
+ <div class="steam-asset-info">
112
+ <span class="steam-asset-title">{t.communityIcon}</span>
113
+ <span class="steam-asset-badge">184x184</span>
114
+ </div>
115
+ <div class="steam-asset-preview-box">
116
+ <canvas id="canvas-community-icon" width="184" height="184" aria-label={t.communityIcon}></canvas>
117
+ </div>
118
+ </div>
119
+ </div>
120
+ </div>
121
+ </div>
122
+ </div>
123
+ </div>
124
+
125
+ <script>
126
+ import JSZip from 'jszip';
127
+ import { calculateCropBounds, loadStateFromStorage } from './logic';
128
+
129
+ function createPlaceholder(): HTMLImageElement {
130
+ const cvs = document.createElement('canvas');
131
+ cvs.width = 1920;
132
+ cvs.height = 1080;
133
+ const ctx = cvs.getContext('2d')!;
134
+ ctx.fillStyle = '#101822';
135
+ ctx.fillRect(0, 0, 1920, 1080);
136
+ ctx.fillStyle = '#66c0f4';
137
+ ctx.font = 'bold 56px sans-serif';
138
+ ctx.textAlign = 'center';
139
+ ctx.textBaseline = 'middle';
140
+ ctx.fillText('GAMEBOB STUDIOS KEY VISUAL', 960, 480);
141
+ const img = new Image();
142
+ img.src = cvs.toDataURL('image/png');
143
+ return img;
144
+ }
145
+
146
+ function setupTabs(root: HTMLElement) {
147
+ root.querySelectorAll('.steam-tab-btn').forEach((btn) => {
148
+ btn.addEventListener('click', () => {
149
+ root.querySelectorAll('.steam-tab-btn').forEach((b) => b.classList.remove('active'));
150
+ btn.classList.add('active');
151
+ const target = btn.getAttribute('data-tab');
152
+ root.querySelectorAll('.steam-preview-panel').forEach((p) => {
153
+ (p as HTMLElement).style.display = p.id === `panel-${target}` ? 'block' : 'none';
154
+ });
155
+ });
156
+ });
157
+ }
158
+
159
+ function setupZipDownload(btn: HTMLElement | null) {
160
+ if (!btn) return;
161
+ btn.addEventListener('click', async () => {
162
+ const zip = new JSZip();
163
+ const list = [
164
+ { id: 'canvas-main-capsule', name: 'main_capsule_1232x706.png' },
165
+ { id: 'canvas-header-capsule', name: 'header_capsule_920x430.png' },
166
+ { id: 'canvas-vertical-capsule', name: 'vertical_library_capsule_600x900.png' },
167
+ { id: 'canvas-library-hero', name: 'library_hero_3840x1240.png' },
168
+ { id: 'canvas-community-icon', name: 'community_icon_184x184.png' }
169
+ ];
170
+ for (const item of list) {
171
+ const cvs = document.getElementById(item.id) as HTMLCanvasElement;
172
+ if (cvs) zip.file(item.name, cvs.toDataURL('image/png').replace(/^data:image\/png;base64,/, ''), { base64: true });
173
+ }
174
+ const blob = await zip.generateAsync({ type: 'blob' });
175
+ const a = document.createElement('a');
176
+ a.href = URL.createObjectURL(blob);
177
+ a.download = 'steam_capsules_package.zip';
178
+ a.click();
179
+ });
180
+ }
181
+
182
+ interface DrawConfig {
183
+ id: string;
184
+ w: number;
185
+ h: number;
186
+ img: HTMLImageElement;
187
+ fx: number;
188
+ fy: number;
189
+ zoom: number;
190
+ }
191
+
192
+ function drawCanvas(cfg: DrawConfig) {
193
+ const cvs = document.getElementById(cfg.id) as HTMLCanvasElement;
194
+ if (!cvs || !cfg.img) return;
195
+ const ctx = cvs.getContext('2d');
196
+ if (!ctx) return;
197
+ const b = calculateCropBounds({ srcWidth: cfg.img.width, srcHeight: cfg.img.height, targetWidth: cfg.w, targetHeight: cfg.h, focusX: cfg.fx, focusY: cfg.fy, zoom: cfg.zoom });
198
+ ctx.clearRect(0, 0, cfg.w, cfg.h);
199
+ ctx.drawImage(cfg.img, b.sx, b.sy, b.sWidth, b.sHeight, 0, 0, cfg.w, cfg.h);
200
+ }
201
+
202
+ function renderCanvasesBatch(img: HTMLImageElement, fx: number, fy: number, zoom: number) {
203
+ const draw = (id: string, w: number, h: number) => drawCanvas({ id, w, h, img, fx, fy, zoom });
204
+ draw('canvas-main-capsule', 1232, 706);
205
+ draw('canvas-library-hero', 3840, 1240);
206
+ draw('canvas-header-capsule', 920, 430);
207
+ draw('canvas-header-capsule-grid', 920, 430);
208
+ draw('canvas-small-capsule-grid', 462, 174);
209
+ draw('canvas-vertical-capsule', 600, 900);
210
+ draw('canvas-vertical-capsule-grid', 600, 900);
211
+ draw('canvas-community-icon', 184, 184);
212
+ }
213
+
214
+ function bindUploader(chooseBtn: HTMLElement | null, fileInput: HTMLInputElement | null, root: HTMLElement, onImage: (img: HTMLImageElement) => void) {
215
+ if (chooseBtn && fileInput) chooseBtn.addEventListener('click', () => fileInput.click());
216
+ root.querySelectorAll('.diegetic-upload-trigger').forEach((t) => t.addEventListener('click', () => fileInput?.click()));
217
+ if (fileInput) {
218
+ fileInput.addEventListener('change', (e) => {
219
+ const file = (e.target as HTMLInputElement).files?.[0];
220
+ if (!file) return;
221
+ const reader = new FileReader();
222
+ reader.onload = (evt) => {
223
+ if (!evt.target?.result) return;
224
+ const img = new Image();
225
+ img.onload = () => onImage(img);
226
+ img.src = evt.target.result as string;
227
+ };
228
+ reader.readAsDataURL(file);
229
+ });
230
+ }
231
+ }
232
+
233
+ function setupControls(fx: HTMLInputElement | null, fy: HTMLInputElement | null, zoom: HTMLInputElement | null, renderFn: () => void) {
234
+ const resetBtn = document.getElementById('steam-reset-btn');
235
+ if (resetBtn) {
236
+ resetBtn.addEventListener('click', () => {
237
+ if (fx) fx.value = '50';
238
+ if (fy) fy.value = '50';
239
+ if (zoom) zoom.value = '100';
240
+ renderFn();
241
+ });
242
+ }
243
+ }
244
+
245
+ function loadInitialSliders(fx: HTMLInputElement | null, fy: HTMLInputElement | null, zoom: HTMLInputElement | null) {
246
+ const state = loadStateFromStorage();
247
+ if (fx) fx.value = String(state.focalPoint.x * 100);
248
+ if (fy) fy.value = String(state.focalPoint.y * 100);
249
+ if (zoom) zoom.value = String(state.focalPoint.zoom * 100);
250
+ }
251
+
252
+ function initApp(root: HTMLElement) {
253
+ const fxSlider = document.getElementById('focus-x-slider') as HTMLInputElement;
254
+ const fySlider = document.getElementById('focus-y-slider') as HTMLInputElement;
255
+ const zoomSlider = document.getElementById('zoom-slider') as HTMLInputElement;
256
+ const safeZonesToggle = document.getElementById('toggle-safe-zones') as HTMLInputElement;
257
+
258
+ loadInitialSliders(fxSlider, fySlider, zoomSlider);
259
+ let sourceImg: HTMLImageElement = createPlaceholder();
260
+
261
+ const renderAll = () => {
262
+ if (!root) return;
263
+ const fx = fxSlider ? Number(fxSlider.value) / 100 : 0.5;
264
+ const fy = fySlider ? Number(fySlider.value) / 100 : 0.5;
265
+ const zoom = zoomSlider ? Number(zoomSlider.value) / 100 : 1;
266
+ renderCanvasesBatch(sourceImg, fx, fy, zoom);
267
+ const show = safeZonesToggle ? safeZonesToggle.checked : true;
268
+ root.querySelectorAll('.steam-safe-overlay').forEach((el) => {
269
+ (el as HTMLElement).style.display = show ? 'flex' : 'none';
270
+ });
271
+ };
272
+
273
+ sourceImg.onload = () => renderAll();
274
+ bindUploader(document.getElementById('steam-choose-btn'), document.getElementById('steam-image-input') as HTMLInputElement, root, (img) => {
275
+ sourceImg = img;
276
+ renderAll();
277
+ });
278
+
279
+ setupControls(fxSlider, fySlider, zoomSlider, renderAll);
280
+ [fxSlider, fySlider, zoomSlider, safeZonesToggle].forEach((c) => c?.addEventListener('input', renderAll));
281
+ setupTabs(root);
282
+ setupZipDownload(document.getElementById('steam-zip-download-btn'));
283
+ }
284
+
285
+ document.addEventListener('DOMContentLoaded', () => {
286
+ const root = document.getElementById('steam-capsule-tool');
287
+ if (root) initApp(root);
288
+ });
289
+ </script>
@@ -0,0 +1,51 @@
1
+ ---
2
+ import type { SteamCapsuleGeneratorUI } from '../ui';
3
+
4
+ interface Props {
5
+ ui: SteamCapsuleGeneratorUI;
6
+ }
7
+
8
+ const { ui: t } = Astro.props;
9
+ ---
10
+
11
+ <div class="steam-grid-mockup-frame">
12
+ <div class="steam-grid-header">
13
+ <span class="steam-grid-title">ALL GAMES (42)</span>
14
+ <div class="steam-grid-search-bar">
15
+ <input type="text" placeholder="Search by name" readonly value="Super Crunch Bros: GameBob Edition" id="library-grid-search-input" aria-label="Search games" />
16
+ </div>
17
+ </div>
18
+
19
+ <div class="steam-grid-tiles-container">
20
+ <div class="steam-grid-card active-card diegetic-upload-trigger" id="vertical-capsule-trigger" tabindex="0" role="button" aria-label="Click to upload vertical capsule art">
21
+ <div class="steam-grid-card-canvas-box">
22
+ <canvas id="canvas-vertical-capsule" width="600" height="900" aria-label={t.verticalCapsule}></canvas>
23
+ <div class="diegetic-overlay-hint">Click to Upload Vertical Art</div>
24
+ <div class="steam-safe-overlay" id="safe-vertical-capsule" style="left: 0; bottom: 0; width: 100%; height: 20%;">
25
+ {t.safeZone}
26
+ </div>
27
+ <div class="steam-grid-play-hover-overlay">
28
+ <svg width="48" height="48" viewBox="0 0 24 24" fill="#ffffff">
29
+ <path d="M8 5v14l11-7z"/>
30
+ </svg>
31
+ </div>
32
+ </div>
33
+ <div class="steam-grid-card-title" id="editable-grid-card-title" contenteditable="true" aria-label="Grid Game Title">Super Crunch Bros: GameBob Edition</div>
34
+ </div>
35
+
36
+ <div class="steam-grid-card placeholder-card">
37
+ <div class="steam-grid-card-canvas-box placeholder-box"></div>
38
+ <div class="steam-grid-card-title">Cyberpunk 2077</div>
39
+ </div>
40
+
41
+ <div class="steam-grid-card placeholder-card">
42
+ <div class="steam-grid-card-canvas-box placeholder-box"></div>
43
+ <div class="steam-grid-card-title">Hades II</div>
44
+ </div>
45
+
46
+ <div class="steam-grid-card placeholder-card">
47
+ <div class="steam-grid-card-canvas-box placeholder-box"></div>
48
+ <div class="steam-grid-card-title">Hollow Knight</div>
49
+ </div>
50
+ </div>
51
+ </div>
@@ -0,0 +1,64 @@
1
+ ---
2
+ import type { SteamCapsuleGeneratorUI } from '../ui';
3
+
4
+ interface Props {
5
+ ui: SteamCapsuleGeneratorUI;
6
+ }
7
+
8
+ const { ui: t } = Astro.props;
9
+ ---
10
+
11
+ <div class="steam-library-mockup-frame">
12
+ <div class="steam-client-topbar">
13
+ <div class="steam-client-menu">
14
+ <span>Steam</span>
15
+ <span>View</span>
16
+ <span>Friends</span>
17
+ <span>Games</span>
18
+ <span>Help</span>
19
+ </div>
20
+ <div class="steam-client-window-controls">
21
+ <span>_</span>
22
+ <span>[ ]</span>
23
+ <span>X</span>
24
+ </div>
25
+ </div>
26
+
27
+ <div class="steam-library-hero-viewport diegetic-upload-trigger" id="library-hero-trigger" tabindex="0" role="button" aria-label="Click to upload library hero banner">
28
+ <canvas id="canvas-library-hero" width="3840" height="1240" aria-label={t.libraryHero}></canvas>
29
+ <div class="diegetic-overlay-hint">Click to Upload Library Hero Artwork</div>
30
+
31
+ <div class="steam-library-hero-gradient-overlay"></div>
32
+
33
+ <div class="steam-library-logo-container" id="library-logo-box">
34
+ <div class="steam-library-title-fallback" id="editable-library-title" contenteditable="true" aria-label="Library Title">Super Crunch Bros: GameBob Edition</div>
35
+ <div class="steam-safe-overlay" id="safe-library-hero" style="left: 0; top: 0; width: 100%; height: 100%;">
36
+ {t.safeZone}
37
+ </div>
38
+ </div>
39
+ </div>
40
+
41
+ <div class="steam-library-action-bar">
42
+ <button type="button" class="steam-play-button">
43
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
44
+ <path d="M8 5v14l11-7z"/>
45
+ </svg>
46
+ <span>PLAY</span>
47
+ </button>
48
+
49
+ <div class="steam-library-stat-item">
50
+ <span class="stat-label">LAST PLAYED</span>
51
+ <span class="stat-value">Today</span>
52
+ </div>
53
+
54
+ <div class="steam-library-stat-item">
55
+ <span class="stat-label">TIME PLAYED</span>
56
+ <span class="stat-value">99.9 hrs</span>
57
+ </div>
58
+
59
+ <div class="steam-library-stat-item">
60
+ <span class="stat-label">ACHIEVEMENTS</span>
61
+ <span class="stat-value">42 / 42</span>
62
+ </div>
63
+ </div>
64
+ </div>
@@ -0,0 +1,90 @@
1
+ ---
2
+ import type { SteamCapsuleGeneratorUI } from '../ui';
3
+
4
+ interface Props {
5
+ ui: SteamCapsuleGeneratorUI;
6
+ }
7
+
8
+ const { ui: t } = Astro.props;
9
+ ---
10
+
11
+ <div class="steam-store-mockup-frame">
12
+ <div class="steam-store-header-nav">
13
+ <div class="steam-logo-text">
14
+ <span class="steam-logo-icon">STEAM</span>
15
+ <span>STORE</span>
16
+ </div>
17
+ <div class="steam-nav-links">
18
+ <span class="active">Your Store</span>
19
+ <span>New & Noteworthy</span>
20
+ <span>Categories</span>
21
+ <span>Points Shop</span>
22
+ <span>News</span>
23
+ <span>Labs</span>
24
+ </div>
25
+ </div>
26
+
27
+ <div class="steam-store-hero-row">
28
+ <div class="steam-main-capsule-container diegetic-upload-trigger" id="main-capsule-trigger" tabindex="0" role="button" aria-label="Click to upload main capsule art">
29
+ <div class="steam-main-capsule-canvas-box">
30
+ <canvas id="canvas-main-capsule" width="1232" height="706" aria-label={t.mainCapsule}></canvas>
31
+ <div class="diegetic-overlay-hint">Click to Upload Main Artwork</div>
32
+ </div>
33
+
34
+ <div class="steam-store-price-badge">
35
+ <div class="discount-tag">-50%</div>
36
+ <div class="price-box">
37
+ <span class="original-price">$29.99</span>
38
+ <span class="final-price">$14.99</span>
39
+ </div>
40
+ </div>
41
+
42
+ <div class="steam-safe-overlay" id="safe-main-capsule" style="right: 0; bottom: 0; width: 40%; height: 25%;">
43
+ {t.safeZone}
44
+ </div>
45
+ </div>
46
+
47
+ <div class="steam-store-sidebar-panel">
48
+ <div class="steam-game-title-input" id="editable-game-title" contenteditable="true" aria-label="Game Title">Super Crunch Bros: GameBob Edition</div>
49
+ <div class="steam-game-desc-input" id="editable-game-desc" contenteditable="true" aria-label="Game Description">
50
+ An epic high-octane indie platformer action adventure. Battle through procedural retro worlds and customize your capsules live for Steamworks publication.
51
+ </div>
52
+
53
+ <div class="steam-header-capsule-box diegetic-upload-trigger" id="header-capsule-trigger" tabindex="0" role="button" aria-label="Click to upload header capsule art">
54
+ <canvas id="canvas-header-capsule" width="920" height="430" aria-label={t.headerCapsule}></canvas>
55
+ <div class="diegetic-overlay-hint">Click to Upload Header Capsule</div>
56
+
57
+ <div class="steam-discount-badge" id="store-discount-overlay">
58
+ <div class="steam-discount-pct" id="editable-discount-pct" contenteditable="true">-50%</div>
59
+ <div class="steam-discount-prices">
60
+ <span style="text-decoration: line-through; opacity: 0.6;" id="editable-orig-price" contenteditable="true">$29.99</span>
61
+ <span class="final-price" id="editable-final-price" contenteditable="true">$14.99</span>
62
+ </div>
63
+ </div>
64
+
65
+ <div class="steam-safe-overlay" id="safe-header-capsule" style="right: 0; bottom: 0; width: 45%; height: 30%;">
66
+ {t.safeZone}
67
+ </div>
68
+ </div>
69
+
70
+ <div class="steam-store-meta-grid">
71
+ <div class="meta-row">
72
+ <span class="meta-label">REVIEWS:</span>
73
+ <span class="meta-value">Very Positive (1,337)</span>
74
+ </div>
75
+ <div class="meta-row">
76
+ <span class="meta-label">RELEASE DATE:</span>
77
+ <span class="meta-value">Available Now</span>
78
+ </div>
79
+ <div class="meta-row">
80
+ <span class="meta-label">DEVELOPER:</span>
81
+ <span class="meta-value" id="editable-developer" contenteditable="true">GameBob Studios</span>
82
+ </div>
83
+ <div class="meta-row">
84
+ <span class="meta-label">PUBLISHER:</span>
85
+ <span class="meta-value" id="editable-publisher" contenteditable="true">GameBob Publishing</span>
86
+ </div>
87
+ </div>
88
+ </div>
89
+ </div>
90
+ </div>
@@ -0,0 +1,28 @@
1
+ import type { GamesToolEntry, ToolLocaleContent } from '../../types';
2
+ import type { SteamCapsuleGeneratorUI } from './ui';
3
+
4
+ export type { SteamCapsuleGeneratorUI };
5
+
6
+ export type SteamCapsuleGeneratorLocaleContent = ToolLocaleContent<SteamCapsuleGeneratorUI>;
7
+
8
+ export const steamCapsuleGenerator: GamesToolEntry<SteamCapsuleGeneratorUI> = {
9
+ id: 'steam-capsule-generator',
10
+ icons: { bg: 'mdi:gamepad-variant', fg: 'mdi:image-multiple' },
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
+ };
@@ -0,0 +1,144 @@
1
+ import type { ToolLocaleContent } from '../../../types';
2
+ import type { SteamCapsuleGeneratorUI } from '../ui';
3
+ import { bibliographyEntries } from '../bibliography';
4
+
5
+ export const content: ToolLocaleContent<SteamCapsuleGeneratorUI> = {
6
+ slug: 'steam-kapsel-generator',
7
+ title: 'Steam Kapsel und Grafik Vorschau Generator',
8
+ description: 'Erstellen, beschneiden und prüfen Sie offizielle Steam Shop Kapseln und Bibliothek Grafiken mit Live Vorschau und Sicherheitszonen.',
9
+ ui: {
10
+ uploadTitle: 'Spielgrafik Hochladen',
11
+ uploadHint: 'Laden Sie ein hochauflösendes Banner hoch (empfohlen 3840x1240 px oder größer).',
12
+ chooseFile: 'Datei Auswählen',
13
+ minimumSize: 'Empfohlene Mindestgröße: 1920x1080 px',
14
+ horizontalFocus: 'Horizontaler Fokus (X)',
15
+ verticalFocus: 'Vertikaler Fokus (Y)',
16
+ zoomLevel: 'Zoomstufe',
17
+ resetFocus: 'Fokus Zentrieren',
18
+ safeZone: 'Sicherheitszone',
19
+ downloadZip: 'Alle Assets Herunterladen (ZIP)',
20
+ headerCapsule: 'Header Kapsel (460x215 / HD 920x430)',
21
+ smallCapsule: 'Kleine Kapsel (231x87 / HD 462x174)',
22
+ mainCapsule: 'Haupt Kapsel (616x353 / HD 1232x706)',
23
+ verticalCapsule: 'Vertikale Bibliotheks Kapsel (300x450 / HD 600x900)',
24
+ libraryHero: 'Bibliotheks Banner (1920x620 / HD 3840x1240)',
25
+ communityIcon: 'Community App Icon (32x32 / HD 184x184)',
26
+ storePreviewTab: 'Steam Shop Vorschau',
27
+ libraryPreviewTab: 'Steam Bibliothek Vorschau',
28
+ allAssetsTab: 'Alle Asset Größen',
29
+ toggleSafeZones: 'Sicherheitszonen',
30
+ toggleSteamOverlay: 'Steam Oberfläche'
31
+ },
32
+ seo: [
33
+ {
34
+ type: 'title',
35
+ level: 2,
36
+ text: 'Steam Grafik Kapsel Spezifikationen und Richtlinien'
37
+ },
38
+ {
39
+ type: 'paragraph',
40
+ html: 'Steam Shopseiten und Bibliotheksansichten nutzen standardisierte Grafik Kapseln für die optimale Darstellung auf verschiedenen Bildschirmen.'
41
+ },
42
+ {
43
+ type: 'stats',
44
+ columns: 4,
45
+ items: [
46
+ { label: 'Shop Header HD Auflösung', value: '920 x 430 px' },
47
+ { label: 'Bibliothek Kapsel Verhältnis', value: '2:3 Vertikal' },
48
+ { label: 'Bibliothek Hero Maximale Res', value: '3840 x 1240 px' },
49
+ { label: 'Community Icon Größe', value: '184 x 184 px' }
50
+ ]
51
+ },
52
+ {
53
+ type: 'table',
54
+ headers: ['Asset Typ', 'Standardgröße (px)', 'HD Zielgröße (px)', 'Seitenverhältnis', 'Format'],
55
+ rows: [
56
+ ['Header Kapsel', '460 x 215', '920 x 430', '2.14:1', 'JPG / PNG'],
57
+ ['Kleine Kapsel', '231 x 87', '462 x 174', '2.65:1', 'JPG / PNG'],
58
+ ['Haupt Kapsel', '616 x 353', '1232 x 706', '1.74:1', 'JPG / PNG'],
59
+ ['Vertikale Kapsel', '300 x 450', '600 x 900', '2:3', 'JPG / PNG'],
60
+ ['Bibliotheks Banner', '1920 x 620', '3840 x 1240', '3.1:1', 'JPG / PNG'],
61
+ ['Bibliotheks Logo', '1280 x 720', '1280 x 720', '16:9', 'Transparentes PNG'],
62
+ ['Community Icon', '32 x 32', '184 x 184', '1:1', 'PNG']
63
+ ]
64
+ },
65
+ {
66
+ type: 'tip',
67
+ title: 'Strategie für Sicherheitszonen',
68
+ html: 'Halten Sie alle wichtigen Logos und Gesichter im oberen linken Drittel des Bildes.'
69
+ },
70
+ {
71
+ type: 'proscons',
72
+ title: 'Arbeitsablauf Bewertung',
73
+ items: [
74
+ {
75
+ pro: 'Sofortige Erstellung aller erforderlichen Steam Asset Größen',
76
+ con: 'Komplexe Motive benötigen eventuell getrennte Ebenen'
77
+ }
78
+ ]
79
+ },
80
+ {
81
+ type: 'glossary',
82
+ items: [
83
+ {
84
+ term: 'Kapsel',
85
+ definition: 'Standardbegriff von Valve für werbliche Bildcontainer.'
86
+ }
87
+ ]
88
+ }
89
+ ],
90
+ faqTitle: 'Häufig gestellte Fragen zu Steam Assets',
91
+ faq: [
92
+ {
93
+ question: 'Welches Dateiformat sollte ich für Steam Kapseln nutzen?',
94
+ answer: 'Steam akzeptiert JPG oder PNG für Hauptkapseln.'
95
+ }
96
+ ],
97
+ howTo: [
98
+ {
99
+ name: 'Hochauflösende Grafik Hochladen',
100
+ text: 'Wählen Sie eine hochauflösende Grafik mit dem Uploader aus.'
101
+ }
102
+ ],
103
+ schemas: [
104
+ {
105
+ '@context': 'https://schema.org',
106
+ '@type': 'SoftwareApplication',
107
+ name: 'Steam Kapsel und Grafik Vorschau Generator',
108
+ applicationCategory: 'DeveloperApplication',
109
+ operatingSystem: 'Any',
110
+ offers: {
111
+ '@type': 'Offer',
112
+ price: '0',
113
+ priceCurrency: 'EUR'
114
+ }
115
+ },
116
+ {
117
+ '@context': 'https://schema.org',
118
+ '@type': 'FAQPage',
119
+ mainEntity: [
120
+ {
121
+ '@type': 'Question',
122
+ name: 'Welches Dateiformat sollte ich für Steam Kapseln nutzen?',
123
+ acceptedAnswer: {
124
+ '@type': 'Answer',
125
+ text: 'Steam akzeptiert JPG oder PNG für Hauptkapseln.'
126
+ }
127
+ }
128
+ ]
129
+ },
130
+ {
131
+ '@context': 'https://schema.org',
132
+ '@type': 'HowTo',
133
+ name: 'So erstellen Sie Steam Kapseln',
134
+ step: [
135
+ {
136
+ '@type': 'HowToStep',
137
+ name: 'Hochauflösende Grafik Hochladen',
138
+ text: 'Wählen Sie eine hochauflösende Grafik aus.'
139
+ }
140
+ ]
141
+ }
142
+ ],
143
+ bibliography: bibliographyEntries
144
+ };