@jjlmoya/utils-games-development 1.61.0 → 1.63.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 (72) hide show
  1. package/package.json +1 -1
  2. package/src/category/index.ts +3 -1
  3. package/src/entries.ts +5 -1
  4. package/src/index.ts +2 -0
  5. package/src/tests/locale_completeness.test.ts +2 -2
  6. package/src/tests/tool_validation.test.ts +2 -2
  7. package/src/tool/gameUIAccessibilityTester/bibliography.astro +6 -0
  8. package/src/tool/gameUIAccessibilityTester/bibliography.ts +10 -0
  9. package/src/tool/gameUIAccessibilityTester/component.astro +210 -0
  10. package/src/tool/gameUIAccessibilityTester/controller-actions.ts +92 -0
  11. package/src/tool/gameUIAccessibilityTester/controller.ts +237 -0
  12. package/src/tool/gameUIAccessibilityTester/dom-views.ts +193 -0
  13. package/src/tool/gameUIAccessibilityTester/entry.ts +28 -0
  14. package/src/tool/gameUIAccessibilityTester/evaluator.ts +43 -0
  15. package/src/tool/gameUIAccessibilityTester/game-ui-accessibility-stress-tester.css +982 -0
  16. package/src/tool/gameUIAccessibilityTester/i18n/de.ts +203 -0
  17. package/src/tool/gameUIAccessibilityTester/i18n/en.ts +199 -0
  18. package/src/tool/gameUIAccessibilityTester/i18n/es.ts +203 -0
  19. package/src/tool/gameUIAccessibilityTester/i18n/fr.ts +203 -0
  20. package/src/tool/gameUIAccessibilityTester/i18n/id.ts +203 -0
  21. package/src/tool/gameUIAccessibilityTester/i18n/it.ts +203 -0
  22. package/src/tool/gameUIAccessibilityTester/i18n/ja.ts +203 -0
  23. package/src/tool/gameUIAccessibilityTester/i18n/ko.ts +203 -0
  24. package/src/tool/gameUIAccessibilityTester/i18n/nl.ts +203 -0
  25. package/src/tool/gameUIAccessibilityTester/i18n/pl.ts +203 -0
  26. package/src/tool/gameUIAccessibilityTester/i18n/pt.ts +203 -0
  27. package/src/tool/gameUIAccessibilityTester/i18n/ru.ts +203 -0
  28. package/src/tool/gameUIAccessibilityTester/i18n/sv.ts +203 -0
  29. package/src/tool/gameUIAccessibilityTester/i18n/tr.ts +203 -0
  30. package/src/tool/gameUIAccessibilityTester/i18n/zh.ts +203 -0
  31. package/src/tool/gameUIAccessibilityTester/index.ts +11 -0
  32. package/src/tool/gameUIAccessibilityTester/logic.test.ts +57 -0
  33. package/src/tool/gameUIAccessibilityTester/logic.ts +157 -0
  34. package/src/tool/gameUIAccessibilityTester/report.ts +59 -0
  35. package/src/tool/gameUIAccessibilityTester/seo.astro +15 -0
  36. package/src/tool/gameUIAccessibilityTester/storage.ts +34 -0
  37. package/src/tool/gameUIAccessibilityTester/ui.ts +80 -0
  38. package/src/tool/hitboxHurtboxAnimator/bibliography.astro +12 -0
  39. package/src/tool/hitboxHurtboxAnimator/bibliography.ts +10 -0
  40. package/src/tool/hitboxHurtboxAnimator/canvas-interactions.ts +59 -0
  41. package/src/tool/hitboxHurtboxAnimator/canvas-metrics.ts +8 -0
  42. package/src/tool/hitboxHurtboxAnimator/component.astro +148 -0
  43. package/src/tool/hitboxHurtboxAnimator/controller.ts +247 -0
  44. package/src/tool/hitboxHurtboxAnimator/dom-views.ts +194 -0
  45. package/src/tool/hitboxHurtboxAnimator/editor-state.ts +19 -0
  46. package/src/tool/hitboxHurtboxAnimator/entry.ts +28 -0
  47. package/src/tool/hitboxHurtboxAnimator/evaluator.ts +15 -0
  48. package/src/tool/hitboxHurtboxAnimator/file-io.ts +82 -0
  49. package/src/tool/hitboxHurtboxAnimator/hitbox-hurtbox-animator.css +614 -0
  50. package/src/tool/hitboxHurtboxAnimator/i18n/de.ts +195 -0
  51. package/src/tool/hitboxHurtboxAnimator/i18n/en.ts +191 -0
  52. package/src/tool/hitboxHurtboxAnimator/i18n/es.ts +195 -0
  53. package/src/tool/hitboxHurtboxAnimator/i18n/fr.ts +195 -0
  54. package/src/tool/hitboxHurtboxAnimator/i18n/id.ts +195 -0
  55. package/src/tool/hitboxHurtboxAnimator/i18n/it.ts +195 -0
  56. package/src/tool/hitboxHurtboxAnimator/i18n/ja.ts +195 -0
  57. package/src/tool/hitboxHurtboxAnimator/i18n/ko.ts +195 -0
  58. package/src/tool/hitboxHurtboxAnimator/i18n/nl.ts +195 -0
  59. package/src/tool/hitboxHurtboxAnimator/i18n/pl.ts +195 -0
  60. package/src/tool/hitboxHurtboxAnimator/i18n/pt.ts +195 -0
  61. package/src/tool/hitboxHurtboxAnimator/i18n/ru.ts +195 -0
  62. package/src/tool/hitboxHurtboxAnimator/i18n/sv.ts +195 -0
  63. package/src/tool/hitboxHurtboxAnimator/i18n/tr.ts +195 -0
  64. package/src/tool/hitboxHurtboxAnimator/i18n/zh.ts +195 -0
  65. package/src/tool/hitboxHurtboxAnimator/index.ts +11 -0
  66. package/src/tool/hitboxHurtboxAnimator/logic.test.ts +97 -0
  67. package/src/tool/hitboxHurtboxAnimator/logic.ts +173 -0
  68. package/src/tool/hitboxHurtboxAnimator/project-actions.ts +128 -0
  69. package/src/tool/hitboxHurtboxAnimator/seo.astro +13 -0
  70. package/src/tool/hitboxHurtboxAnimator/storage.ts +27 -0
  71. package/src/tool/hitboxHurtboxAnimator/ui.ts +70 -0
  72. package/src/tools.ts +4 -0
@@ -0,0 +1,195 @@
1
+ import type { FAQPage, HowTo, SoftwareApplication, WithContext } from 'schema-dts';
2
+ import type { ToolLocaleContent } from '../../../types';
3
+ import type { HitboxHurtboxAnimatorUI } from '../ui';
4
+ import { bibliographyEntries } from '../bibliography';
5
+
6
+ const slug = 'animera-hitbox-och-hurtbox-sprites';
7
+ const title = 'Animera Hitbox och Hurtbox för Sprites';
8
+ const description = 'Rita kollisionslager på varje bildruta av din sprite, förhandsgranska rörelser med lökpapper (onion skin), redigera exakta pixelkoordinater och exportera JSON.';
9
+
10
+ const faq = [
11
+ {
12
+ question: 'Vad är skillnaden mellan en hitbox och en hurtbox?',
13
+ answer: 'En hitbox definierar det område som utdelar en attack, medan en hurtbox definierar det område som kan ta emot skada. Pushboxes håller karaktärer på avstånd och grabboxes sätter räckvidden för grepp.',
14
+ },
15
+ {
16
+ question: 'Lämnar mina spritefiler webbläsaren?',
17
+ answer: 'Nej. Bilderna bearbetas och exporteras helt i din webbläsare. Endast redigeringsinställningar sparas lokalt.',
18
+ },
19
+ {
20
+ question: 'Vilket koordinatsystem använder JSON-exporten?',
21
+ answer: 'Varje bildruta mäter sina pixelkoordinater från det övre vänstra hörnet. Måtten för bredd och höjd lagrar positiva värden tillsammans med sin egen fästpunkt (pivot).',
22
+ },
23
+ {
24
+ question: 'Kan jag redigera både spritesheets och enskilda bildrutor?',
25
+ answer: 'Ja. Du kan ladda ett PNG- eller WebP-spritesheet genom att ange rader och kolumner, eller välja flera sorterade filer.',
26
+ },
27
+ {
28
+ question: 'Fungerar exporten direkt i alla spelmotorer?',
29
+ answer: 'JSON-formatet är neutralt. Det sparar bildruteramarna, fästpunkter och geometriska lager utan att tvinga fram en specifik spelmotorstruktur.',
30
+ },
31
+ ];
32
+
33
+ const howTo = [
34
+ { name: 'Ladda grafik', text: 'Välj ett PNG/WebP-spritesheet eller sorterade bildfiler. Bearbetningen sker lokalt på din enhet.' },
35
+ { name: 'Ställ in bildrutor', text: 'Ange antal rader och kolumner och kontrollera beskärningen i tidslinjen.' },
36
+ { name: 'Rita kollisionslager', text: 'Välj ett hitbox-, hurtbox-, pushbox- eller sensorlager och rita en rektangel eller cirkel.' },
37
+ { name: 'Finjustera rörelse', text: 'Redigera exakta koordinater, kopiera former till närliggande bildrutor och använd lökpapper för att jämföra.' },
38
+ { name: 'Exportera projektet', text: 'Ladda ner den neutrala JSON-filen och en PNG-kontaktkarta. Spara originalbilderna tillsammans med JSON-filen.' },
39
+ ];
40
+
41
+ const softwareApplication: WithContext<SoftwareApplication> = {
42
+ '@context': 'https://schema.org',
43
+ '@type': 'SoftwareApplication',
44
+ name: title,
45
+ applicationCategory: 'DeveloperApplication',
46
+ operatingSystem: 'Any',
47
+ };
48
+
49
+ const faqPage: WithContext<FAQPage> = {
50
+ '@context': 'https://schema.org',
51
+ '@type': 'FAQPage',
52
+ mainEntity: faq.map((item) => ({
53
+ '@type': 'Question',
54
+ name: item.question,
55
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
56
+ })),
57
+ };
58
+
59
+ const howToSchema: WithContext<HowTo> = {
60
+ '@context': 'https://schema.org',
61
+ '@type': 'HowTo',
62
+ name: title,
63
+ step: howTo.map((step) => ({ '@type': 'HowToStep', name: step.name, text: step.text })),
64
+ };
65
+
66
+ export const content: ToolLocaleContent<HitboxHurtboxAnimatorUI> = {
67
+ slug,
68
+ title,
69
+ description,
70
+ ui: {
71
+ onboarding: 'Ladda en animering, bekräfta bildrutebeskärningen och rita områden för attack, skada eller fysikkollision.',
72
+ privacyNote: 'Lokal animeringsarbetsbänk. Bilder laddas inte upp.',
73
+ loadSprite: 'Placera grafik på arbetsbänken',
74
+ loadHint: 'Välj ett spritesheet eller flera sorterade PNG/WebP-bilder.',
75
+ chooseImages: 'Välj bildfiler',
76
+ slicingTitle: 'Bildrutebeskärning',
77
+ rowsLabel: 'Rader',
78
+ columnsLabel: 'Kolumner',
79
+ applySlicing: 'Beskär',
80
+ playbackTitle: 'Rörelsevisning',
81
+ previousFrame: 'Föregående bildruta',
82
+ play: 'Spela upp',
83
+ pause: 'Pausa',
84
+ nextFrame: 'Nästa bildruta',
85
+ fpsLabel: 'Bildrutor per sekund',
86
+ onionPrevious: 'Föregående lökpapper',
87
+ onionNext: 'Nästa lökpapper',
88
+ layerTitle: 'Kollisionslager',
89
+ typeHitbox: 'Hitbox',
90
+ typeHurtbox: 'Hurtbox',
91
+ typePushbox: 'Pushbox',
92
+ typeGrabbox: 'Grabbox',
93
+ typeSensor: 'Sensor',
94
+ typeCustom: 'Anpassad',
95
+ shapeRectangle: 'Rektangel',
96
+ shapeCircle: 'Cirkel',
97
+ drawShape: 'Rita',
98
+ selectShape: 'Välj',
99
+ stageLabel: 'Arbetsyta',
100
+ emptyStage: 'Ladda bilder för att börja rita kollisionslager.',
101
+ frameReadout: 'Bildruta {current} av {total}',
102
+ timelineTitle: 'Bildruterad',
103
+ inspectorTitle: 'Forminspektör',
104
+ noSelection: 'Välj en form för att redigera dess exakta koordinater.',
105
+ nameLabel: 'Lagernamn',
106
+ xLabel: 'X i pixlar',
107
+ yLabel: 'Y i pixlar',
108
+ widthLabel: 'Bredd i pixlar',
109
+ heightLabel: 'Höjd i pixlar',
110
+ radiusLabel: 'Radie i pixlar',
111
+ duplicateShape: 'Duplicera',
112
+ mirrorShape: 'Spegelvänd horisontellt',
113
+ deleteShape: 'Ta bort form',
114
+ copyPrevious: 'Kopiera föregående bildruta hit',
115
+ copyAll: 'Kopiera denna bildruta till alla',
116
+ pivotTitle: 'Bildrutefästpunkt (Pivot)',
117
+ pivotXLabel: 'Fästpunkt X',
118
+ pivotYLabel: 'Fästpunkt Y',
119
+ exportTitle: 'Exportera projekt',
120
+ exportJson: 'Ladda ner JSON',
121
+ importJson: 'Importera JSON',
122
+ exportContactSheet: 'Ladda ner kontaktkarta',
123
+ resetProject: 'Rensa lager',
124
+ undo: 'Ångra',
125
+ redo: 'Gör om',
126
+ statusReady: 'Arbetsbänken är redo.',
127
+ statusImageLoaded: '{count} bildfiler laddade.',
128
+ statusShapeCreated: 'Ny kollisionsform tillagd.',
129
+ statusShapeUpdated: 'Form uppdaterad.',
130
+ statusImported: 'Projekt importerat.',
131
+ statusExported: 'Export redo.',
132
+ statusError: 'Kunde inte läsa filen.',
133
+ framesBadge: '{count} bildrutor',
134
+ shapesBadge: '{count} former',
135
+ coverageBadge: '{percent}% täckt',
136
+ coordinatesNote: 'Koordinater mäter från det övre vänstra hörnet av varje bildruta (0,0).',
137
+ localOnlyDisclosure: 'JSON-filen sparar bildnamn, fästpunkter och former utan att innehålla bildpixlar.',
138
+ limitationDisclosure: 'Lagren definierar geometriska designområden. Testa beteendet i din spelmotor.',
139
+ },
140
+ seo: [
141
+ {
142
+ type: 'title',
143
+ level: 2,
144
+ text: 'Designa hitboxes och hurtboxes anpassade efter rörelsen',
145
+ },
146
+ {
147
+ type: 'paragraph',
148
+ html: 'Att ställa in kollisioner blir svårt när varje bildruta analyseras separat. Denna redigerare samlar spritens bild, kollisionslager, lökpapper och tidslinjen för att säkerställa att rörelsen flyter jämnt.',
149
+ },
150
+ {
151
+ type: 'title',
152
+ level: 2,
153
+ text: 'Välj varje kollisionslager utefter dess funktion i spelet',
154
+ },
155
+ {
156
+ type: 'table',
157
+ headers: ['Lager', 'Huvudfunktion', 'Att kontrollera'],
158
+ rows: [
159
+ ['Hitbox', 'Område som utdelar en attack eller effekt', 'Visas den endast under de aktiva bildrutorna?'],
160
+ ['Hurtbox', 'Område som tar emot skada', 'Följer den karaktärens kropp utan onödiga luckor?'],
161
+ ['Pushbox', 'Fysisk kollisionsyta mellan karaktärer', 'Håller den sig stabil för att undvika hack i rörelsen?'],
162
+ ['Grabbox', 'Räckvidd för att påbörja ett grepp', 'Stämmer tajmingen med den visuella animeringen?'],
163
+ ['Sensor', 'Detekteringsyta för interaktioner', 'Är lagernamnet tillräckligt tydligt?'],
164
+ ],
165
+ },
166
+ {
167
+ type: 'title',
168
+ level: 2,
169
+ text: 'Förstå och tillämpa koordinatsystemet',
170
+ },
171
+ {
172
+ type: 'paragraph',
173
+ html: 'Det exporterade projektet mäter X och Y från det övre vänstra hörnet av varje beskuren bildruta. Bredden och höjden anges i positiva pixelvärden.',
174
+ },
175
+ {
176
+ type: 'tip',
177
+ title: 'Kontrollera hela animeringssekvensen',
178
+ html: 'Spela upp hela animeringen efter att ha ändrat en bildruta för att säkerställa att rörelsen känns prirodlig.',
179
+ },
180
+ {
181
+ type: 'title',
182
+ level: 2,
183
+ text: 'Använd kontaktkartan i teamets arbete',
184
+ },
185
+ {
186
+ type: 'paragraph',
187
+ html: 'PNG-kontaktkartan visar alla bildrutor och deras färglager på en och samma bild, vilket underlättar kommunikationen mellan grafiker och programmerare.',
188
+ },
189
+ ],
190
+ faq,
191
+ bibliographyTitle: 'Referenser för kollisionsdesign',
192
+ bibliography: bibliographyEntries,
193
+ howTo,
194
+ schemas: [softwareApplication, faqPage, howToSchema],
195
+ };
@@ -0,0 +1,195 @@
1
+ import type { FAQPage, HowTo, SoftwareApplication, WithContext } from 'schema-dts';
2
+ import type { ToolLocaleContent } from '../../../types';
3
+ import type { HitboxHurtboxAnimatorUI } from '../ui';
4
+ import { bibliographyEntries } from '../bibliography';
5
+
6
+ const slug = 'oyun-sprite-hitbox-ve-hurtbox-animatoru';
7
+ const title = 'Oyun Sprite Hitbox ve Hurtbox Animatörü';
8
+ const description = 'Her sprite karesinde çarpışma katmanları çizin, soğan zarı (onion skin) ile hareketleri önizleyin, piksel koordinatlarını düzenleyin ve nötr JSON aktarın.';
9
+
10
+ const faq = [
11
+ {
12
+ question: 'Hitbox ile hurtbox arasındaki fark nedir?',
13
+ answer: 'Hitbox bir saldırının etki alanını, hurtbox ise hasar alabilen vücut alanını tanımlar. Pushbox karakterler arası mesafeyi korur, grabbox ise yakalama menzilini belirler.',
14
+ },
15
+ {
16
+ question: 'Sprite dosyalarım sunucuya yükleniyor mu?',
17
+ answer: 'Hayır. Görseller tamamen tarayıcınızın içinde işlenir ve aktarılır. Yalnızca düzenleyici tercihleri yerel depolamada saklanır.',
18
+ },
19
+ {
20
+ question: 'JSON aktarımı hangi koordinat sistemini kullanır?',
21
+ answer: 'Her kare piksel koordinatlarını sol üst köşeden itibaren ölçer. Genişlik ve yükseklik değerleri kendi merkez noktaları (pivot) ile pozitif değerler olarak saklanır.',
22
+ },
23
+ {
24
+ question: 'Hem sprite levhalarını hem de tekil kareleri düzenleyebilir miyim?',
25
+ answer: 'Evet. Satır ve sütun sayılarını girerek bir PNG veya WebP sprite levhası yükleyebilir ya da sıralı tekil görseller seçebilirsiniz.',
26
+ },
27
+ {
28
+ question: 'Aktarılan JSON tüm oyun motorlarında doğrudan çalışır mı?',
29
+ answer: 'JSON formatı nötrdür. Belirli bir motor yapısını zorlamadan kare çerçevelerini, merkez noktalarını ve geometrik katmanları kaydeder.',
30
+ },
31
+ ];
32
+
33
+ const howTo = [
34
+ { name: 'Grafik yükleyin', text: 'Bir PNG/WebP sprite levhası veya sıralı görseller seçin. Tüm işlemler cihazınızda yerel olarak gerçekleşir.' },
35
+ { name: 'Kareleri belirleyin', text: 'Sprite levhası için satır ve sütun sayılarını girin ve zaman çizelgesindeki kare kesimlerini kontrol edin.' },
36
+ { name: 'Çarpışma katmanları çizin', text: 'Hitbox, hurtbox, pushbox veya sensör katmanını seçip dikdörtgen veya daire çizin.' },
37
+ { name: 'Hareketi ayarlayın', text: 'Hassas koordinatları düzenleyin, şekilleri komşu karelere kopyalayın ve soğan zarı ile hareketleri karşılaştırın.' },
38
+ { name: 'Projeyi aktarın', text: 'Nötr JSON dosyasını ve PNG temas levhasını indirin. Orijinal görselleri JSON ile birlikte saklayın.' },
39
+ ];
40
+
41
+ const softwareApplication: WithContext<SoftwareApplication> = {
42
+ '@context': 'https://schema.org',
43
+ '@type': 'SoftwareApplication',
44
+ name: title,
45
+ applicationCategory: 'DeveloperApplication',
46
+ operatingSystem: 'Any',
47
+ };
48
+
49
+ const faqPage: WithContext<FAQPage> = {
50
+ '@context': 'https://schema.org',
51
+ '@type': 'FAQPage',
52
+ mainEntity: faq.map((item) => ({
53
+ '@type': 'Question',
54
+ name: item.question,
55
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
56
+ })),
57
+ };
58
+
59
+ const howToSchema: WithContext<HowTo> = {
60
+ '@context': 'https://schema.org',
61
+ '@type': 'HowTo',
62
+ name: title,
63
+ step: howTo.map((step) => ({ '@type': 'HowToStep', name: step.name, text: step.text })),
64
+ };
65
+
66
+ export const content: ToolLocaleContent<HitboxHurtboxAnimatorUI> = {
67
+ slug,
68
+ title,
69
+ description,
70
+ ui: {
71
+ onboarding: 'Bir animasyon yükleyin, kare kesimlerini onaylayın ve saldırı, hasar veya fiziksel çarpışma alanlarını çizin.',
72
+ privacyNote: 'Yerel animasyon çalışma masası. Görseller sunucuya yüklenmez.',
73
+ loadSprite: 'Grafikleri çalışma masasına yerleştirin',
74
+ loadHint: 'Bir sprite levhası veya sıralı PNG/WebP görselleri seçin.',
75
+ chooseImages: 'Görselleri seç',
76
+ slicingTitle: 'Kare kesimi',
77
+ rowsLabel: 'Satırlar',
78
+ columnsLabel: 'Sütunlar',
79
+ applySlicing: 'Kes',
80
+ playbackTitle: 'Hareket önizlemesi',
81
+ previousFrame: 'Önceki kare',
82
+ play: 'Oynat',
83
+ pause: 'Duraklat',
84
+ nextFrame: 'Sonraki kare',
85
+ fpsLabel: 'Saniyedeki kare sayısı',
86
+ onionPrevious: 'Önceki katman',
87
+ onionNext: 'Sonraki katman',
88
+ layerTitle: 'Çarpışma katmanları',
89
+ typeHitbox: 'Hitbox',
90
+ typeHurtbox: 'Hurtbox',
91
+ typePushbox: 'Pushbox',
92
+ typeGrabbox: 'Grabbox',
93
+ typeSensor: 'Sensör',
94
+ typeCustom: 'Özel',
95
+ shapeRectangle: 'Dikdörtgen',
96
+ shapeCircle: 'Daire',
97
+ drawShape: 'Çiz',
98
+ selectShape: 'Seç',
99
+ stageLabel: 'Çalışma alanı',
100
+ emptyStage: 'Çarpışma katmanları çizmek için görseller yükleyin.',
101
+ frameReadout: 'Kare {current} / {total}',
102
+ timelineTitle: 'Kare şeridi',
103
+ inspectorTitle: 'Şekil denetleyicisi',
104
+ noSelection: 'Hassas koordinatları düzenlemek için bir şekil seçin.',
105
+ nameLabel: 'Katman adı',
106
+ xLabel: 'Piksel cinsinden X',
107
+ yLabel: 'Piksel cinsinden Y',
108
+ widthLabel: 'Piksel cinsinden Genişlik',
109
+ heightLabel: 'Piksel cinsinden Yükseklik',
110
+ radiusLabel: 'Piksel cinsinden Yarıçap',
111
+ duplicateShape: 'Çoğalt',
112
+ mirrorShape: 'Yatay yansıt',
113
+ deleteShape: 'Şekli sil',
114
+ copyPrevious: 'Önceki kareyi buraya kopyala',
115
+ copyAll: 'Bu kareyi tümüne kopyala',
116
+ pivotTitle: 'Kare merkez noktası (Pivot)',
117
+ pivotXLabel: 'Pivot X',
118
+ pivotYLabel: 'Pivot Y',
119
+ exportTitle: 'Projeyi aktar',
120
+ exportJson: 'JSON İndir',
121
+ importJson: 'JSON İçe Aktar',
122
+ exportContactSheet: 'Temas levhasını indir',
123
+ resetProject: 'Katmanları sıfırla',
124
+ undo: 'Geri al',
125
+ redo: 'Yinele',
126
+ statusReady: 'Çalışma masası hazır.',
127
+ statusImageLoaded: '{count} görsel dosyası yüklendi.',
128
+ statusShapeCreated: 'Yeni çarpışma şekli eklendi.',
129
+ statusShapeUpdated: 'Şekil güncellendi.',
130
+ statusImported: 'Proje içe aktarıldı.',
131
+ statusExported: 'Dışa aktarım hazır.',
132
+ statusError: 'Seçilen dosya okunamadı.',
133
+ framesBadge: '{count} kare',
134
+ shapesBadge: '{count} şekil',
135
+ coverageBadge: '%{percent} kapsama',
136
+ coordinatesNote: 'Koordinatlar her karenin sol üst köşesini (0,0) başlangıç kabul eder.',
137
+ localOnlyDisclosure: 'JSON dosyası dosya adlarını, merkez noktalarını ve şekilleri piksel verisi içermeden saklar.',
138
+ limitationDisclosure: 'Katmanlar tasarım alanlarını tanımlar. Davranışları oyun motorunuzda test edin.',
139
+ },
140
+ seo: [
141
+ {
142
+ type: 'title',
143
+ level: 2,
144
+ text: 'Sprite hareketine uygun hitbox ve hurtbox alanları tasarlayın',
145
+ },
146
+ {
147
+ type: 'paragraph',
148
+ html: 'Her kare tek başına incelendiğinde çarpışma ayarları zorlaşır. Bu düzenleyici sprite görselini, çarpışma katmanlarını, soğan zarını ve zaman çizelgesini bir arada sunar.',
149
+ },
150
+ {
151
+ type: 'title',
152
+ level: 2,
153
+ text: 'Çarpışma katmanlarını oyun işlevine göre seçin',
154
+ },
155
+ {
156
+ type: 'table',
157
+ headers: ['Katman', 'Ana İşlev', 'Kontrol Noktası'],
158
+ rows: [
159
+ ['Hitbox', 'Saldırı veya etki oluşturan alan', 'Sadece aktif karelerde mi görünüyor?'],
160
+ ['Hurtbox', 'Hasar alan gövde alanı', 'Karakter formunu boşluk bırakmadan takip ediyor mu?'],
161
+ ['Pushbox', 'Karakterler arası fiziksel çarpışma alanı', 'Sarsıntıları önlemek için sabit duruyor mu?'],
162
+ ['Grabbox', 'Yakalama hamlesi menzili', 'Zamanlama görsel animasyonla eşleşiyor mu?'],
163
+ ['Sensor', 'Etkileşim algılama alanı', 'Katman adı net bir şekilde tanımlanmış mı?'],
164
+ ],
165
+ },
166
+ {
167
+ type: 'title',
168
+ level: 2,
169
+ text: 'Koordinat sistemini anlama ve uygulama',
170
+ },
171
+ {
172
+ type: 'paragraph',
173
+ html: 'Aktarılan proje X ve Y koordinatlarını her kesilen karenin sol üst köşesinden itibaren ölçer. Genişlik ve yükseklik pozitif piksel değerleridir.',
174
+ },
175
+ {
176
+ type: 'tip',
177
+ title: 'Tüm animasyon dizilimini kontrol edin',
178
+ html: 'Bir kareyi düzenledikten sonra animasyonu tam olarak oynatarak hareket akışını doğrulayın.',
179
+ },
180
+ {
181
+ type: 'title',
182
+ level: 2,
183
+ text: 'Temas levhasını ekip çalışmasında kullanın',
184
+ },
185
+ {
186
+ type: 'paragraph',
187
+ html: 'PNG temas levhası tüm kareleri ve katmanlarını tek bir görselde göstererek yazılımcılar ve çizerler arasındaki iletişimi kolaylaştırır.',
188
+ },
189
+ ],
190
+ faq,
191
+ bibliographyTitle: 'Çarpışma tasarımı referansları',
192
+ bibliography: bibliographyEntries,
193
+ howTo,
194
+ schemas: [softwareApplication, faqPage, howToSchema],
195
+ };
@@ -0,0 +1,195 @@
1
+ import type { FAQPage, HowTo, SoftwareApplication, WithContext } from 'schema-dts';
2
+ import type { ToolLocaleContent } from '../../../types';
3
+ import type { HitboxHurtboxAnimatorUI } from '../ui';
4
+ import { bibliographyEntries } from '../bibliography';
5
+
6
+ const slug = 'hitbox-hurtbox-animator';
7
+ const title = '像素动画 Hitbox 与 Hurtbox 帧编辑器';
8
+ const description = '在精灵动画每帧上绘制碰撞判定图层,通过洋葱皮预阅动作连贯性,精确编辑像素坐标并导出引擎中立的 JSON 项目。';
9
+
10
+ const faq = [
11
+ {
12
+ question: 'Hitbox(攻击框)与 Hurtbox(受击框)有什么区别?',
13
+ answer: 'Hitbox 通常用于判定发起攻击或产生作用的区域,而 Hurtbox 用于定义可以接收该攻击的受击区域。Pushbox 用于保持角色间距,Grabbox 用于判定投掷范围,Sensor 用于触发检测。',
14
+ },
15
+ {
16
+ question: '我的精灵图文件会被上传到服务器吗?',
17
+ answer: '不会。图像的解码、裁切、绘制和导出完全在您的浏览器本地完成。本地仅保存播放速度、洋葱皮开关等编辑偏好。',
18
+ },
19
+ {
20
+ question: '导出的 JSON 使用什么坐标系?',
21
+ answer: '每一帧均以该帧裁切矩形的左上角为原点 (0,0) 测量像素坐标。矩形与圆形碰撞框保存非负的 x、y、宽度和高度值,并记录每帧自有的轴心点 (Pivot)。',
22
+ },
23
+ {
24
+ question: '我可以同时编辑雪碧图(Sprite Sheet)和单帧图片序列吗?',
25
+ answer: '可以。您可以载入一张 PNG 或 WebP 雪碧图并设置行列数进行等分裁切,也可以选择多张有序的单帧图片序列。',
26
+ },
27
+ {
28
+ question: '导出的数据可以直接在所有游戏引擎中使用吗?',
29
+ answer: 'JSON 数据保持引擎中立。它记录了帧切片、轴心点、语义图层名称及几何形状,不强制绑定具体引擎。请在项目解析器中根据引擎的坐标原点与缩放规则进行转换。',
30
+ },
31
+ ];
32
+
33
+ const howTo = [
34
+ { name: '载入动画素材', text: '选择一张 PNG 或 WebP 雪碧图,或选择多张有序单帧图片。所有图像处理均在本地进行。' },
35
+ { name: '设定帧切片', text: '如为等分雪碧图,请输入行数与列数。逐帧检查胶片条,确认每个切片均精准包含单帧画面。' },
36
+ { name: '绘制语义碰撞图层', text: '选择攻击框、受击框、推挤框、抓取框或传感器图层,在当前帧画面上拖拽绘制矩形或圆形。' },
37
+ { name: '精细化调整动作', text: '选中形状以修改精准像素坐标,复制形状至相邻帧,并开启洋葱皮图层比较前后帧动作。' },
38
+ { name: '导出可复现数据', text: '下载引擎中立的 JSON 项目文件与 PNG 印花列印图。请妥善保存原始图片。' },
39
+ ];
40
+
41
+ const softwareApplication: WithContext<SoftwareApplication> = {
42
+ '@context': 'https://schema.org',
43
+ '@type': 'SoftwareApplication',
44
+ name: title,
45
+ applicationCategory: 'DeveloperApplication',
46
+ operatingSystem: 'Any',
47
+ };
48
+
49
+ const faqPage: WithContext<FAQPage> = {
50
+ '@context': 'https://schema.org',
51
+ '@type': 'FAQPage',
52
+ mainEntity: faq.map((item) => ({
53
+ '@type': 'Question',
54
+ name: item.question,
55
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
56
+ })),
57
+ };
58
+
59
+ const howToSchema: WithContext<HowTo> = {
60
+ '@context': 'https://schema.org',
61
+ '@type': 'HowTo',
62
+ name: title,
63
+ step: howTo.map((step) => ({ '@type': 'HowToStep', name: step.name, text: step.text })),
64
+ };
65
+
66
+ export const content: ToolLocaleContent<HitboxHurtboxAnimatorUI> = {
67
+ slug,
68
+ title,
69
+ description,
70
+ ui: {
71
+ onboarding: '载入动画素材,确认切片划分,然后绘制判定攻击、受击、物理挤压、抓取或检测的碰撞区域。',
72
+ privacyNote: '本地动画工作台,图像不会上传至服务器。',
73
+ loadSprite: '将动画素材放置于工作台',
74
+ loadHint: '选择一张等分雪碧图或多张有序的 PNG、WebP 帧图片。',
75
+ chooseImages: '选择精灵图像',
76
+ slicingTitle: '帧切片划分',
77
+ rowsLabel: '行数',
78
+ columnsLabel: '列数',
79
+ applySlicing: '执行切片',
80
+ playbackTitle: '动作播放预览',
81
+ previousFrame: '上一帧',
82
+ play: '播放',
83
+ pause: '暂停',
84
+ nextFrame: '下一帧',
85
+ fpsLabel: '每秒帧数 (FPS)',
86
+ onionPrevious: '上一帧洋葱皮',
87
+ onionNext: '下一帧洋葱皮',
88
+ layerTitle: '碰撞图层绘制',
89
+ typeHitbox: 'Hitbox (攻击框)',
90
+ typeHurtbox: 'Hurtbox (受击框)',
91
+ typePushbox: 'Pushbox (推挤框)',
92
+ typeGrabbox: 'Grabbox (抓取框)',
93
+ typeSensor: 'Sensor (传感器)',
94
+ typeCustom: '自定义图层',
95
+ shapeRectangle: '矩形',
96
+ shapeCircle: '圆形',
97
+ drawShape: '绘制',
98
+ selectShape: '选择',
99
+ stageLabel: '动画工作台',
100
+ emptyStage: '请载入精灵素材以显示帧画面并开始绘制碰撞图层。',
101
+ frameReadout: '第 {current} 帧 / 共 {total} 帧',
102
+ timelineTitle: '碰撞时间胶片',
103
+ inspectorTitle: '选中形状属性',
104
+ noSelection: '切换至选择模式并点击某一形状,以修改其精准坐标与尺寸。',
105
+ nameLabel: '图层名称',
106
+ xLabel: 'X 坐标 (像素)',
107
+ yLabel: 'Y 坐标 (像素)',
108
+ widthLabel: '宽度 (像素)',
109
+ heightLabel: '高度 (像素)',
110
+ radiusLabel: '半径 (像素)',
111
+ duplicateShape: '创建副本',
112
+ mirrorShape: '水平镜像翻转',
113
+ deleteShape: '删除选中形状',
114
+ copyPrevious: '复制上一帧碰撞至当前帧',
115
+ copyAll: '应用当前帧碰撞至所有帧',
116
+ pivotTitle: '帧轴心点 (Pivot)',
117
+ pivotXLabel: '轴心点 X',
118
+ pivotYLabel: '轴心点 Y',
119
+ exportTitle: '导出动画项目',
120
+ exportJson: '下载 JSON 文件',
121
+ importJson: '导入 JSON 文件',
122
+ exportContactSheet: '下载印花对比图',
123
+ resetProject: '清空碰撞图层',
124
+ undo: '撤销',
125
+ redo: '重做',
126
+ statusReady: '动画工作台已就绪。',
127
+ statusImageLoaded: '已在本地载入 {count} 个图像文件。',
128
+ statusShapeCreated: '已为当前帧添加新的碰撞形状。',
129
+ statusShapeUpdated: '碰撞形状属性已更新。',
130
+ statusImported: '已导入碰撞项目文件。',
131
+ statusExported: '导出项目文件已生成。',
132
+ statusError: '无法读取所选文件,请确认格式是否正确。',
133
+ framesBadge: '{count} 帧',
134
+ shapesBadge: '{count} 个形状',
135
+ coverageBadge: '覆盖率 {percent}%',
136
+ coordinatesNote: '坐标系以每帧裁切图像的左上角为原点 (0,0)。',
137
+ localOnlyDisclosure: 'JSON 文件仅记录图像文件名、切片、轴心点及碰撞几何数据,不内嵌像素数据。',
138
+ limitationDisclosure: '碰撞图层用于定义几何设计。请在游戏引擎中进行最终行为测试。',
139
+ },
140
+ seo: [
141
+ {
142
+ type: 'title',
143
+ level: 2,
144
+ text: '围绕动画动作本身设计 Hitbox 与 Hurtbox',
145
+ },
146
+ {
147
+ type: 'paragraph',
148
+ html: '如果将每一帧孤立来看,碰撞框的设置会变得十分困难。本编辑器将精灵画面、语义碰撞图层、洋葱皮参考及时间胶片条结合在一起,让您能清晰查看攻击判定何时生效、受击区域如何贴合角色形体。',
149
+ },
150
+ {
151
+ type: 'title',
152
+ level: 2,
153
+ text: '根据玩法职责选择碰撞图层',
154
+ },
155
+ {
156
+ type: 'table',
157
+ headers: ['图层类型', '典型职责', '审查要点'],
158
+ rows: [
159
+ ['Hitbox (攻击框)', '产生攻击判定或伤害作用的区域', '是否仅在预期的有效判定帧中出现?'],
160
+ ['Hurtbox (受击框)', '接收攻击或承受伤害的受击区域', '是否顺应角色形体轮廓且无不合理缝隙?'],
161
+ ['Pushbox (推挤框)', '防止角色实体相互穿模挤压的物理区域', '尺寸是否足够稳定以避免画面抖动?'],
162
+ ['Grabbox (抓取框)', '触发投掷或抓取判定的作用范围', '判定时间与范围是否匹配视觉动作提示?'],
163
+ ['Sensor (传感器)', '用于边缘检测、交互或触发器的探测区域', '图层名称是否具备清晰的语义?'],
164
+ ],
165
+ },
166
+ {
167
+ type: 'title',
168
+ level: 2,
169
+ text: '理解并应用统一的坐标契约',
170
+ },
171
+ {
172
+ type: 'paragraph',
173
+ html: '导出的项目文件以每个裁切帧的左上角为 X 与 Y 的坐标原点。宽度与高度均为非负像素尺寸,轴心点亦使用相同的局部坐标系。这保证了保存与导入循环的可复现性。',
174
+ },
175
+ {
176
+ type: 'tip',
177
+ title: '综合审查起手、前摇、判定与收招过程',
178
+ html: '修改单帧后,请完整播放整段动作。开启前后帧洋葱皮可帮助您判断动作连贯性,避免碰撞框发生突兀跳跃。',
179
+ },
180
+ {
181
+ type: 'title',
182
+ level: 2,
183
+ text: '将印花对比图作为团队沟通的审查产物',
184
+ },
185
+ {
186
+ type: 'paragraph',
187
+ html: '生成的 PNG 印花对比图能在单张画面上直观展示所有帧及其叠加的彩色碰撞图层,非常适合与美术、策划及程序团队讨论战斗打击感与判定时间。',
188
+ },
189
+ ],
190
+ faq,
191
+ bibliographyTitle: '碰撞框设计与判定参考资料',
192
+ bibliography: bibliographyEntries,
193
+ howTo,
194
+ schemas: [softwareApplication, faqPage, howToSchema],
195
+ };
@@ -0,0 +1,11 @@
1
+ import type { ToolDefinition } from '../../types';
2
+ import { hitboxHurtboxAnimator } from './entry';
3
+
4
+ export * from './entry';
5
+
6
+ export const HITBOX_HURTBOX_ANIMATOR_TOOL: ToolDefinition = {
7
+ entry: hitboxHurtboxAnimator,
8
+ Component: () => import('./component.astro'),
9
+ SEOComponent: () => import('./seo.astro'),
10
+ BibliographyComponent: () => import('./bibliography.astro'),
11
+ };