@jjlmoya/utils-tabletop 1.11.0 → 1.13.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 (35) hide show
  1. package/package.json +1 -1
  2. package/src/entries.ts +4 -0
  3. package/src/tests/locale_completeness.test.ts +1 -1
  4. package/src/tests/tool_validation.test.ts +1 -1
  5. package/src/tool/dice-roller-simulator/component.astro +116 -26
  6. package/src/tool/scatter-direction-selector/animation.ts +278 -0
  7. package/src/tool/scatter-direction-selector/bibliography.astro +16 -0
  8. package/src/tool/scatter-direction-selector/bibliography.ts +12 -0
  9. package/src/tool/scatter-direction-selector/client.ts +293 -0
  10. package/src/tool/scatter-direction-selector/component.astro +183 -0
  11. package/src/tool/scatter-direction-selector/entry.ts +59 -0
  12. package/src/tool/scatter-direction-selector/history.ts +71 -0
  13. package/src/tool/scatter-direction-selector/i18n/de.ts +143 -0
  14. package/src/tool/scatter-direction-selector/i18n/en.ts +231 -0
  15. package/src/tool/scatter-direction-selector/i18n/es.ts +143 -0
  16. package/src/tool/scatter-direction-selector/i18n/fr.ts +143 -0
  17. package/src/tool/scatter-direction-selector/i18n/id.ts +143 -0
  18. package/src/tool/scatter-direction-selector/i18n/it.ts +143 -0
  19. package/src/tool/scatter-direction-selector/i18n/ja.ts +143 -0
  20. package/src/tool/scatter-direction-selector/i18n/ko.ts +143 -0
  21. package/src/tool/scatter-direction-selector/i18n/nl.ts +143 -0
  22. package/src/tool/scatter-direction-selector/i18n/pl.ts +143 -0
  23. package/src/tool/scatter-direction-selector/i18n/pt.ts +143 -0
  24. package/src/tool/scatter-direction-selector/i18n/ru.ts +143 -0
  25. package/src/tool/scatter-direction-selector/i18n/sv.ts +143 -0
  26. package/src/tool/scatter-direction-selector/i18n/tr.ts +143 -0
  27. package/src/tool/scatter-direction-selector/i18n/zh.ts +143 -0
  28. package/src/tool/scatter-direction-selector/index.ts +10 -0
  29. package/src/tool/scatter-direction-selector/logic.test.ts +62 -0
  30. package/src/tool/scatter-direction-selector/logic.ts +52 -0
  31. package/src/tool/scatter-direction-selector/scatter-direction-selector.css +809 -0
  32. package/src/tool/scatter-direction-selector/seo.astro +16 -0
  33. package/src/tool/scatter-direction-selector/settings.ts +81 -0
  34. package/src/tool/scatter-direction-selector/sound.ts +22 -0
  35. package/src/tools.ts +2 -0
@@ -0,0 +1,143 @@
1
+ import { bibliography } from '../bibliography';
2
+ import type { ScatterSelectorLocaleContent } from '../entry';
3
+
4
+ const ui = {
5
+ title: 'Выбор Направления Разброса',
6
+ setupTitle: 'Настройки Разброса',
7
+ sectorsLabel: 'Секторы Компаса',
8
+ sectors8: '8 Направлений',
9
+ sectors12: '12 Направлений (Циферблат)',
10
+ diceLabel: 'Бросок Дистанции Отклонения',
11
+ diceD6: '1D6 Дюймов',
12
+ dice2D6: '2D6 Дюймов',
13
+ diceD10: '1D10 Дюймов',
14
+ diceCustom: 'Свой Диапазон',
15
+ customMaxLabel: 'Максимальная Дистанция',
16
+ hitChanceLabel: 'Вероятность Прямого Попадания (%)',
17
+ rollButton: 'Бросить Разброс',
18
+ hitResult: 'Прямое Попадание!',
19
+ scatterResult: 'Разброс!',
20
+ distanceLabel: 'Дистанция',
21
+ angleLabel: 'Угол',
22
+ dragHint: 'Перетащите компас, чтобы вручную задать направление ветра',
23
+ historyTitle: 'Последние Броски',
24
+ clearHistory: 'Очистить Историю',
25
+ presetTitle: 'Пресеты для Варгеймов',
26
+ soundOn: 'Звук Включён',
27
+ soundOff: 'Звук Выключен',
28
+ guideStep1: 'Перетащите компас, чтобы совместить его с ориентацией вашего стола',
29
+ guideStep2: 'Выберите секторы, кости и вероятность прямого попадания',
30
+ guideStep3: 'Центр = ваша цель. Зелёное свечение означает, что снаряд попал точно туда',
31
+ guideStep3Scatter: 'Стрелка = направление отклонения. Передвиньте выстрел из центра на столько дюймов вдоль стрелки',
32
+ scatterModeLabel: 'Направление Разброса',
33
+ scatterModeRandom: 'Случайное',
34
+ scatterModeWind: 'Дрейф Ветра',
35
+ scatterModeWindHint: 'Стрелка всегда следует за компасом - случайна только дистанция',
36
+ };
37
+
38
+ const faq = [
39
+ {
40
+ question: 'Как работает Выбор Направления Разброса?',
41
+ answer: 'Инструмент вычисляет случайный угол (0-359 градусов) и дистанцию на основе выбранной конфигурации костей. Также симулируется кость разброса с проверкой прямого попадания.',
42
+ },
43
+ {
44
+ question: 'Могу ли я изменить формат секторов?',
45
+ answer: 'Да, вы можете переключаться между 8-направленными кардинальными секторами и 12-направленными секторами в формате циферблата.',
46
+ },
47
+ {
48
+ question: 'Что такое вероятность прямого попадания?',
49
+ answer: 'Это шанс того, что снаряд приземлится точно в цель без какого-либо отклонения, симулируя результат «Попадание» на стандартной кости разброса.',
50
+ },
51
+ {
52
+ question: 'Совместимо ли это с Warhammer или Bolt Action?',
53
+ answer: 'Да, инструмент поддерживает стандартные 8-направленные шаблоны и 12-направленные часовые ориентиры, используемые в большинстве тактических варгеймов и миниатюрных правил.',
54
+ },
55
+ {
56
+ question: 'Как визуально отображается дистанция разброса?',
57
+ answer: 'Дистанция в дюймах появляется в виде всплывающей метки в точке попадания, расположенной вдоль направления отклонения. Красная стрелка компаса также фиксируется на итоговом угле для быстрого выравнивания шаблона.',
58
+ },
59
+ {
60
+ question: 'Могу ли я отключить анимацию для более быстрых результатов?',
61
+ answer: 'Анимация длится примерно две секунды, после чего финальный результат отображается в центре, а стрелка компаса фиксируется. В настоящее время нет возможности пропуска, но задержка соответствует темпу броска физических костей.',
62
+ },
63
+ ];
64
+
65
+ const howTo = [
66
+ {
67
+ name: 'Настройте Правила',
68
+ text: 'Выберите секторы компаса, задайте кость дистанции и отрегулируйте вероятность прямого попадания.',
69
+ },
70
+ {
71
+ name: 'Бросайте или Перетаскивайте',
72
+ text: 'Нажмите Бросить Разброс, чтобы симулировать отклонение, или перетащите колесо компаса для ручной регулировки направления.',
73
+ },
74
+ {
75
+ name: 'Прочитайте Результат',
76
+ text: 'Проверьте центральный дисплей и векторную стрелку, чтобы узнать точную дистанцию, угол и направление разброса.',
77
+ },
78
+ {
79
+ name: 'Наблюдайте Траекторию',
80
+ text: 'После броска смотрите, как анимированный снаряд движется по компасу. Пунктирная линия показывает путь отклонения, а точка попадания отображает дистанцию в дюймах.',
81
+ },
82
+ {
83
+ name: 'Интерпретируйте Результат',
84
+ text: 'Зелёный импульс с надписью «DIRECT HIT» означает нулевое отклонение. Красная вспышка с меткой дистанции означает, что выстрел разбросался - поместите шаблон на это расстояние от цели в направлении стрелки.',
85
+ },
86
+ ];
87
+
88
+ export const content: ScatterSelectorLocaleContent = {
89
+ slug: 'vybor-napravleniya-razbrosa',
90
+ title: 'Выбор Направления Разброса: Тактический Компас для Миниатюрных Варгеймов',
91
+ description: 'Определяйте случайные отклонения, дрейф ветра и направления разброса для миниатюрных варгеймов с помощью тактильного 3D-компаса.',
92
+ ui,
93
+ seo: [
94
+ { type: 'title', text: 'Интерактивный Компас Разброса с Анимацией Снаряда в Реальном Времени', level: 2 },
95
+ { type: 'paragraph', html: 'Выбор Направления Разброса выходит за рамки статической генерации чисел, отображая анимированную траекторию снаряда прямо на наложении компаса. Когда вы нажимаете Бросить Разброс, светящийся снаряд движется от центра вдоль угла отклонения, оставляя пунктирный след и взрываясь частицами в точке попадания.' },
96
+ { type: 'stats', items: [
97
+ { value: '2', label: 'Системы Секторов', icon: 'mdi:compass-rose' },
98
+ { value: '4', label: 'Пресеты Костей', icon: 'mdi:dice-d6' },
99
+ { value: '0-100%', label: 'Диапазон Вероятности Попадания', icon: 'mdi:target' },
100
+ { value: '10', label: 'История Последних Бросков', icon: 'mdi:history' },
101
+ ], columns: 4 },
102
+ { type: 'title', text: 'Как Анимация Траектории Улучшает Принятие Решений в Варгеймах', level: 3 },
103
+ { type: 'paragraph', html: 'Традиционные инструменты отображают числовой угол и дистанцию, заставляя игроков мысленно визуализировать смещение на столе. Анимированная траектория устраняет этот разрыв, рисуя точный путь полёта от точки прицеливания до зоны приземления разброса.' },
104
+ { type: 'diagnostic', variant: 'success', title: 'Прямое Попадание', html: 'Когда бросок превышает вероятность попадания, центр компаса взрывается пульсирующими зелёными кольцами и анимацией текста «DIRECT HIT». Снаряд возвращается в центр, подтверждая идеальное попадание без отклонения.' },
105
+ { type: 'diagnostic', variant: 'error', title: 'Разброс', html: 'При результате разброса снаряд следует пунктирной траектории к точке приземления. Взрыв частиц, светящийся маркер и дистанция в дюймах (напр. <strong>5"</strong>) появляются в месте попадания.' },
106
+ { type: 'tip', title: 'Совет: Использование Режима Дрейфа Ветра', html: 'Включите Дрейф Ветра, чтобы зафиксировать направление разброса на вручную повёрнутый угол компаса. Это симулирует преобладающий ветер или фиксированный вектор смещения - идеально для неуправляемых ракет, газовых облаков или неудачных телепортаций.' },
107
+ ],
108
+ faq,
109
+ bibliography,
110
+ howTo,
111
+ schemas: [
112
+ {
113
+ '@context': 'https://schema.org',
114
+ '@type': 'FAQPage',
115
+ 'mainEntity': faq.map((f) => ({
116
+ '@type': 'Question',
117
+ 'name': f.question,
118
+ 'acceptedAnswer': {
119
+ '@type': 'Answer',
120
+ 'text': f.answer,
121
+ },
122
+ })),
123
+ },
124
+ {
125
+ '@context': 'https://schema.org',
126
+ '@type': 'SoftwareApplication',
127
+ 'name': 'Выбор Направления Разброса',
128
+ 'operatingSystem': 'All',
129
+ 'applicationCategory': 'UtilitiesApplication',
130
+ 'browserRequirements': 'Requires HTML5. Requires JavaScript.',
131
+ },
132
+ {
133
+ '@context': 'https://schema.org',
134
+ '@type': 'HowTo',
135
+ 'name': 'Как использовать Выбор Направления Разброса',
136
+ 'step': howTo.map((h) => ({
137
+ '@type': 'HowToStep',
138
+ 'name': h.name,
139
+ 'text': h.text,
140
+ })),
141
+ },
142
+ ],
143
+ };
@@ -0,0 +1,143 @@
1
+ import { bibliography } from '../bibliography';
2
+ import type { ScatterSelectorLocaleContent } from '../entry';
3
+
4
+ const ui = {
5
+ title: 'Spridningsriktningsväljare',
6
+ setupTitle: 'Spridningsinställningar',
7
+ sectorsLabel: 'Kompasssektorer',
8
+ sectors8: '8 Riktningar',
9
+ sectors12: '12 Riktningar (Klocka)',
10
+ diceLabel: 'Avvikelseavstånd Kast',
11
+ diceD6: '1T6 Tum',
12
+ dice2D6: '2T6 Tum',
13
+ diceD10: '1T10 Tum',
14
+ diceCustom: 'Anpassat Intervall',
15
+ customMaxLabel: 'Maximalt Avstånd',
16
+ hitChanceLabel: 'Direktträff Sannolikhet (%)',
17
+ rollButton: 'Kasta Spridning',
18
+ hitResult: 'Direktträff!',
19
+ scatterResult: 'Spridning!',
20
+ distanceLabel: 'Avstånd',
21
+ angleLabel: 'Vinkel',
22
+ dragHint: 'Dra kompassen för att ställa in vindriktningen manuellt',
23
+ historyTitle: 'Senaste Kast',
24
+ clearHistory: 'Rensa Historik',
25
+ presetTitle: 'Wargaming Förinställningar',
26
+ soundOn: 'Ljud På',
27
+ soundOff: 'Ljud Av',
28
+ guideStep1: 'Dra kompassen så att den matchar din bordsorientering',
29
+ guideStep2: 'Välj sektorer, tärningar och direkt träff chans',
30
+ guideStep3: 'Mitten = ditt mål. Grönt sken betyder att det landade precis där',
31
+ guideStep3Scatter: 'Pil = avvikelseriktning. Flytta skottet från mitten så många tum längs pilen',
32
+ scatterModeLabel: 'Spridningsriktning',
33
+ scatterModeRandom: 'Slumpmässig',
34
+ scatterModeWind: 'Vinddrift',
35
+ scatterModeWindHint: 'Pilen följer alltid kompassen - bara avståndet är slumpmässigt',
36
+ };
37
+
38
+ const faq = [
39
+ {
40
+ question: 'Hur fungerar Spridningsriktningsväljaren?',
41
+ answer: 'Den beräknar en slumpmässig vinkel (0-359 grader) och ett avstånd baserat på vald tärningskonfiguration. Den simulerar också en spridningstärning och kontrollerar om det blir en direktträff.',
42
+ },
43
+ {
44
+ question: 'Kan jag ändra sektorformatet?',
45
+ answer: 'Ja, du kan växla mellan 8-riktnings kardinalsektorer och 12-riktnings klocksektorer.',
46
+ },
47
+ {
48
+ question: 'Vad är direktträff sannolikheten?',
49
+ answer: 'Den representerar chansen att projektilen landar precis där du siktade, utan någon avvikelse eller spridning. Detta simulerar ett "Träff"-resultat på en vanlig spridningstärning.',
50
+ },
51
+ {
52
+ question: 'Är detta kompatibelt med Warhammer eller Bolt Action?',
53
+ answer: 'Ja, den stöder vanliga 8-riktnings mallar och 12-riktnings klockutriktningar som används i de flesta taktiska krigsspel och miniatyrregler.',
54
+ },
55
+ {
56
+ question: 'Vad visar projektilbananimationen?',
57
+ answer: 'Ett lysande projektil färdas från kompassens mitt till spridningslandningsplatsen och lämnar ett streckat spår efter sig. Vid en direktträff stannar projektilen i mitten och expanderande gröna ringar pulserar utåt.',
58
+ },
59
+ {
60
+ question: 'Hur visas spridningsavståndet visuellt?',
61
+ answer: 'Avståndet i tum visas som en flytande etikett vid nedslagspunkten, placerad längs avvikelseriktningen. Den röda kompasspilen låses också till den slutliga vinkeln för snabb mallutriktning.',
62
+ },
63
+ ];
64
+
65
+ const howTo = [
66
+ {
67
+ name: 'Konfigurera Regler',
68
+ text: 'Välj kompasssektorer, välj en avståndstärning och justera direktträff sannolikheten.',
69
+ },
70
+ {
71
+ name: 'Kasta eller Dra',
72
+ text: 'Klicka på Kasta Spridning för att simulera avvikelsen, eller dra i kompasshjulet för att justera riktningen manuellt.',
73
+ },
74
+ {
75
+ name: 'Läs Utfallet',
76
+ text: 'Kontrollera den centrala displayen och vektorpilen för att hitta det exakta avståndet, vinkeln och riktningen för spridningen.',
77
+ },
78
+ {
79
+ name: 'Observera Banan',
80
+ text: 'Efter kastet, observera det animerade projektilen färdas över kompassen. Det streckade spåret visar avvikelsevägen och nedslagspunkten visar avståndet i tum.',
81
+ },
82
+ {
83
+ name: 'Tolka Resultatet',
84
+ text: 'En grön puls med "DIRECT HIT" betyder ingen avvikelse. En röd explosion med en avståndsetikett betyder att skottet spreds - placera din mall så många tum från målet i pilens riktning.',
85
+ },
86
+ ];
87
+
88
+ export const content: ScatterSelectorLocaleContent = {
89
+ slug: 'spridningsriktningsvaljare',
90
+ title: 'Spridningsriktningsväljare: Taktisk Kompass för Bordsspel Wargaming',
91
+ description: 'Bestäm slumpmässiga avvikelser, vinddrift och spridningsriktningar för miniatyr krigsspel med en taktil 3D-kompass.',
92
+ ui,
93
+ seo: [
94
+ { type: 'title', text: 'Interaktiv Spridningskompass med Realtids Projektilanimation', level: 2 },
95
+ { type: 'paragraph', html: 'Spridningsriktningsväljaren går bortom statisk nummergenerering genom att rendera en animerad projektilbana direkt på kompassöverlägget. När du klickar på Kasta Spridning färdas ett lysande projektil från mitten längs avvikelsevinkeln, lämnar ett streckat spår och brister i partiklar vid nedslagspunkten.' },
96
+ { type: 'stats', items: [
97
+ { value: '2', label: 'Sektorsystem', icon: 'mdi:compass-rose' },
98
+ { value: '4', label: 'Tärnings Förinställningar', icon: 'mdi:dice-d6' },
99
+ { value: '0-100%', label: 'Träff Sannolikhetsintervall', icon: 'mdi:target' },
100
+ { value: '10', label: 'Senaste Kast Historik', icon: 'mdi:history' },
101
+ ], columns: 4 },
102
+ { type: 'title', text: 'Hur Bananimationen Förbättrar Beslutsfattande vid Wargaming', level: 3 },
103
+ { type: 'paragraph', html: 'Traditionella spridningsverktyg visar en numerisk vinkel och ett avstånd, vilket tvingar spelare att mentalt visualisera förskjutningen på bordet. Den animerade banan överbryggar detta gap genom att rita den exakta flygvägen från siktningspunkten till spridningslandningszonen.' },
104
+ { type: 'diagnostic', variant: 'success', title: 'Direktträff', html: 'När kastet slår träffsannolikheten, briserar kompassens mitt med pulserande gröna ringar och en "DIRECT HIT" textanimation. Projektilet återvänder till mitten och bekräftar en perfekt träff utan avvikelse.' },
105
+ { type: 'diagnostic', variant: 'error', title: 'Spridning', html: 'Vid ett spridningsresultat följer projektilen en streckad bana till sin landningsplats. En partikelexplosion, en lysande markör och avståndet i tum (t.ex. <strong>5"</strong>) visas på landningsplatsen.' },
106
+ { type: 'tip', title: 'Proffstips: Använd Vinddrift Läge', html: 'Aktivera Vinddrift för att låsa spridningsriktningen till din manuellt roterade kompassvinkel. Simulerar en rådande vind eller en fast förskjutningsvektor - idealisk för ostyrda raketer, gasmoln eller misslyckade teleporteringar.' },
107
+ ],
108
+ faq,
109
+ bibliography,
110
+ howTo,
111
+ schemas: [
112
+ {
113
+ '@context': 'https://schema.org',
114
+ '@type': 'FAQPage',
115
+ 'mainEntity': faq.map((f) => ({
116
+ '@type': 'Question',
117
+ 'name': f.question,
118
+ 'acceptedAnswer': {
119
+ '@type': 'Answer',
120
+ 'text': f.answer,
121
+ },
122
+ })),
123
+ },
124
+ {
125
+ '@context': 'https://schema.org',
126
+ '@type': 'SoftwareApplication',
127
+ 'name': 'Spridningsriktningsväljare',
128
+ 'operatingSystem': 'All',
129
+ 'applicationCategory': 'UtilitiesApplication',
130
+ 'browserRequirements': 'Requires HTML5. Requires JavaScript.',
131
+ },
132
+ {
133
+ '@context': 'https://schema.org',
134
+ '@type': 'HowTo',
135
+ 'name': 'Hur du använder Spridningsriktningsväljaren',
136
+ 'step': howTo.map((h) => ({
137
+ '@type': 'HowToStep',
138
+ 'name': h.name,
139
+ 'text': h.text,
140
+ })),
141
+ },
142
+ ],
143
+ };
@@ -0,0 +1,143 @@
1
+ import { bibliography } from '../bibliography';
2
+ import type { ScatterSelectorLocaleContent } from '../entry';
3
+
4
+ const ui = {
5
+ title: 'Sapma Yönü Seçici',
6
+ setupTitle: 'Sapma Ayarları',
7
+ sectorsLabel: 'Pusula Sektörleri',
8
+ sectors8: '8 Yön',
9
+ sectors12: '12 Yön (Saat)',
10
+ diceLabel: 'Sapma Mesafesi Zarı',
11
+ diceD6: '1D6 İnç',
12
+ dice2D6: '2D6 İnç',
13
+ diceD10: '1D10 İnç',
14
+ diceCustom: 'Özel Aralık',
15
+ customMaxLabel: 'Maksimum Mesafe',
16
+ hitChanceLabel: 'Doğrudan İsabet Olasılığı (%)',
17
+ rollButton: 'Sapma Atışı Yap',
18
+ hitResult: 'Doğrudan İsabet!',
19
+ scatterResult: 'Sapma!',
20
+ distanceLabel: 'Mesafe',
21
+ angleLabel: 'Açı',
22
+ dragHint: 'Rüzgar yönünü elle ayarlamak için pusulayı sürükleyin',
23
+ historyTitle: 'Son Atışlar',
24
+ clearHistory: 'Geçmişi Temizle',
25
+ presetTitle: 'Savaş Oyunu Hazır Ayarları',
26
+ soundOn: 'Ses Açık',
27
+ soundOff: 'Ses Kapalı',
28
+ guideStep1: 'Pusulayı masa yönünüze uyacak şekilde sürükleyin',
29
+ guideStep2: 'Sektörleri, zarları ve doğrudan isabet şansını seçin',
30
+ guideStep3: 'Merkez = hedefiniz. Yeşil parlama tam isabet anlamına gelir',
31
+ guideStep3Scatter: 'Ok = sapma yönü. Atışı merkezden o kadar inç ok yönünde hareket ettirin',
32
+ scatterModeLabel: 'Sapma Yönü',
33
+ scatterModeRandom: 'Rastgele',
34
+ scatterModeWind: 'Rüzgar Sürüklenmesi',
35
+ scatterModeWindHint: 'Ok her zaman pusulayı takip eder - yalnızca mesafe rastgeledir',
36
+ };
37
+
38
+ const faq = [
39
+ {
40
+ question: 'Sapma Yönü Seçici nasıl çalışır?',
41
+ answer: 'Seçilen zar yapılandırmasına göre rastgele bir açı (0-359 derece) ve mesafe hesaplar. Ayrıca bir sapma zarını simüle ederek doğrudan isabetleri kontrol eder.',
42
+ },
43
+ {
44
+ question: 'Sektör formatını değiştirebilir miyim?',
45
+ answer: 'Evet, 8 yönlü ana yön sektörleri ile 12 yönlü saat kadranı sektörleri arasında geçiş yapabilirsiniz.',
46
+ },
47
+ {
48
+ question: 'Doğrudan isabet olasılığı nedir?',
49
+ answer: 'Merminin hedeflenen noktaya herhangi bir sapma olmadan tam olarak düşme şansını temsil eder ve standart bir sapma zarında «İsabet» sonucunu simüle eder.',
50
+ },
51
+ {
52
+ question: 'Bu araç Warhammer veya Bolt Action ile uyumlu mu?',
53
+ answer: 'Evet, çoğu taktik savaş oyunu ve minyatür kural setinde kullanılan standart 8 yönlü şablonları ve 12 yönlü saat hizalamalarını destekler.',
54
+ },
55
+ {
56
+ question: 'Sapma mesafesi görsel olarak nasıl gösterilir?',
57
+ answer: 'İnç cinsinden mesafe, çarpma noktasında sapma yönü boyunca konumlanmış bir etiket olarak görünür. Kırmızı pusula oku da hızlı şablon hizalaması için son açıya kilitlenir.',
58
+ },
59
+ {
60
+ question: 'Daha hızlı sonuç almak için animasyonu devre dışı bırakabilir miyim?',
61
+ answer: 'Animasyon yaklaşık iki saniye sürer, ardından nihai sonuç merkezde görüntülenir ve pusula oku kilitlenir. Şu anda atlama seçeneği yoktur, ancak gecikme fiziksel zar atma temposuna uyacak şekilde tasarlanmıştır.',
62
+ },
63
+ ];
64
+
65
+ const howTo = [
66
+ {
67
+ name: 'Kuralları Yapılandırın',
68
+ text: 'Pusula sektörlerini seçin, bir mesafe zarı ön ayarı belirleyin ve doğrudan isabet şansını ayarlayın.',
69
+ },
70
+ {
71
+ name: 'Atın veya Sürükleyin',
72
+ text: 'Sapmayı simüle etmek için Sapma Atışı Yap düğmesine tıklayın veya yönü elle ayarlamak için pusula çarkını sürükleyin.',
73
+ },
74
+ {
75
+ name: 'Sonucu Okuyun',
76
+ text: 'Merkez ekranı ve vektör okunu kontrol ederek sapmanın tam mesafesini, açısını ve yönünü bulun.',
77
+ },
78
+ {
79
+ name: 'Yörüngeyi İzleyin',
80
+ text: 'Atıştan sonra animasyonlu merminin pusula üzerinde hareket etmesini izleyin. Kesik çizgi sapma yolunu gösterir ve çarpma noktası mesafeyi inç cinsinden görüntüler.',
81
+ },
82
+ {
83
+ name: 'Sonucu Yorumlayın',
84
+ text: '«DIRECT HIT» yazısıyla birlikte yeşil bir darbe sıfır sapma anlamına gelir. Mesafe etiketiyle birlikte kırmızı bir patlama, atışın saptığı anlamına gelir - şablonunuzu hedeften bu kadar inç uzağa, ok yönünde yerleştirin.',
85
+ },
86
+ ];
87
+
88
+ export const content: ScatterSelectorLocaleContent = {
89
+ slug: 'sapma-yonu-secici',
90
+ title: 'Sapma Yönü Seçici: Minyatür Savaş Oyunları için Pusula',
91
+ description: 'Minyatür savaş oyunları için 3B dokunsal bir pusula kullanarak rastgele sapmaları, rüzgar sürüklenmesini ve dağılım yönlerini belirleyin.',
92
+ ui,
93
+ seo: [
94
+ { type: 'title', text: 'Gerçek Zamanlı Mermi Animasyonlu Etkileşimli Sapma Pusulası', level: 2 },
95
+ { type: 'paragraph', html: 'Sapma Yönü Seçici, statik sayı üretiminin ötesine geçerek pusula katmanı üzerinde animasyonlu bir mermi yörüngesi oluşturur. Sapma Atışı Yap düğmesine tıkladığınızda, parlayan bir mermi merkezden sapma açısı boyunca ilerler, kesik bir iz bırakır ve çarpma noktasında parçacıklara ayrılır.' },
96
+ { type: 'stats', items: [
97
+ { value: '2', label: 'Sektör Sistemi', icon: 'mdi:compass-rose' },
98
+ { value: '4', label: 'Zar Hazır Ayarları', icon: 'mdi:dice-d6' },
99
+ { value: '0-100%', label: 'İsabet Olasılığı Aralığı', icon: 'mdi:target' },
100
+ { value: '10', label: 'Son Atış Geçmişi', icon: 'mdi:history' },
101
+ ], columns: 4 },
102
+ { type: 'title', text: 'Yörünge Animasyonu Savaş Oyunu Kararlarını Nasıl İyileştirir', level: 3 },
103
+ { type: 'paragraph', html: 'Geleneksel sapma araçları sayısal bir açı ve mesafe görüntüleyerek oyuncuların masadaki kaymayı zihinsel olarak canlandırmasını zorunlu kılar. Animasyonlu yörünge, nişan noktasından sapma iniş bölgesine kadar tam uçuş yolunu çizerek bu boşluğu kapatır.' },
104
+ { type: 'diagnostic', variant: 'success', title: 'Doğrudan İsabet', html: 'Atış isabet olasılığını geçtiğinde, pusula merkezi titreşen yeşil halkalar ve «DIRECT HIT» metin animasyonu ile aydınlanır. Mermi merkeze dönerek sıfır sapma ile mükemmel isabeti onaylar.' },
105
+ { type: 'diagnostic', variant: 'error', title: 'Sapma', html: 'Sapma sonucunda mermi, iniş noktasına kadar kesik bir yörünge izler. Bir parçacık patlaması, parlayan bir işaret ve inç cinsinden mesafe (örn. <strong>5"</strong>) çarpma noktasında belirir.' },
106
+ { type: 'tip', title: 'İpucu: Rüzgar Sürüklenmesi Modunu Kullanma', html: 'Sapma yönünü elle döndürdüğünüz pusula açısına kilitlemek için Rüzgar Sürüklenmesini açın. Bu, baskın bir rüzgarı veya sabit bir yer değiştirme vektörünü simüle eder - güdümsüz roketler, gaz bulutları veya başarısız teleportasyonlar için idealdir.' },
107
+ ],
108
+ faq,
109
+ bibliography,
110
+ howTo,
111
+ schemas: [
112
+ {
113
+ '@context': 'https://schema.org',
114
+ '@type': 'FAQPage',
115
+ 'mainEntity': faq.map((f) => ({
116
+ '@type': 'Question',
117
+ 'name': f.question,
118
+ 'acceptedAnswer': {
119
+ '@type': 'Answer',
120
+ 'text': f.answer,
121
+ },
122
+ })),
123
+ },
124
+ {
125
+ '@context': 'https://schema.org',
126
+ '@type': 'SoftwareApplication',
127
+ 'name': 'Sapma Yönü Seçici',
128
+ 'operatingSystem': 'All',
129
+ 'applicationCategory': 'UtilitiesApplication',
130
+ 'browserRequirements': 'Requires HTML5. Requires JavaScript.',
131
+ },
132
+ {
133
+ '@context': 'https://schema.org',
134
+ '@type': 'HowTo',
135
+ 'name': 'Sapma Yönü Seçici nasıl kullanılır',
136
+ 'step': howTo.map((h) => ({
137
+ '@type': 'HowToStep',
138
+ 'name': h.name,
139
+ 'text': h.text,
140
+ })),
141
+ },
142
+ ],
143
+ };
@@ -0,0 +1,143 @@
1
+ import { bibliography } from '../bibliography';
2
+ import type { ScatterSelectorLocaleContent } from '../entry';
3
+
4
+ const ui = {
5
+ title: '散布方向选择器',
6
+ setupTitle: '散布设置',
7
+ sectorsLabel: '罗盘扇区',
8
+ sectors8: '8方向',
9
+ sectors12: '12方向(时钟)',
10
+ diceLabel: '偏差距离掷骰',
11
+ diceD6: '1D6 英寸',
12
+ dice2D6: '2D6 英寸',
13
+ diceD10: '1D10 英寸',
14
+ diceCustom: '自定义范围',
15
+ customMaxLabel: '最大距离',
16
+ hitChanceLabel: '直接命中概率(%)',
17
+ rollButton: '掷骰散布',
18
+ hitResult: '直接命中!',
19
+ scatterResult: '散布!',
20
+ distanceLabel: '距离',
21
+ angleLabel: '角度',
22
+ dragHint: '拖动罗盘手动设置风向',
23
+ historyTitle: '最近掷骰',
24
+ clearHistory: '清除历史',
25
+ presetTitle: '战棋预设',
26
+ soundOn: '音效开',
27
+ soundOff: '音效关',
28
+ guideStep1: '拖动罗盘以匹配您的桌面方向',
29
+ guideStep2: '选择扇区、骰子和直接命中概率',
30
+ guideStep3: '中心 = 您的目标。绿色光晕表示它准确落在了那里',
31
+ guideStep3Scatter: '箭头 = 偏差方向。从中心沿箭头方向移动相应的英寸数',
32
+ scatterModeLabel: '散布方向',
33
+ scatterModeRandom: '随机',
34
+ scatterModeWind: '风偏',
35
+ scatterModeWindHint: '箭头始终跟随罗盘 - 仅距离为随机',
36
+ };
37
+
38
+ const faq = [
39
+ {
40
+ question: '散布方向选择器如何工作?',
41
+ answer: '它根据选定的骰子配置计算随机角度(0-359度)和距离。同时模拟散布骰子,检查是否直接命中。',
42
+ },
43
+ {
44
+ question: '我可以更改扇区格式吗?',
45
+ answer: '可以,您可以在8方向基本扇区和12方向钟面扇区之间切换。',
46
+ },
47
+ {
48
+ question: '什么是直接命中概率?',
49
+ answer: '它代表抛射物精确命中目标而无任何偏差的概率,模拟标准散布骰子上的"命中"结果。',
50
+ },
51
+ {
52
+ question: '这与Warhammer或Bolt Action兼容吗?',
53
+ answer: '是的,它支持大多数战术战棋和微缩模型规则集中使用的标准8方向模板和12方向时钟对齐方式。',
54
+ },
55
+ {
56
+ question: '散布距离在视觉上如何显示?',
57
+ answer: '距离(英寸)作为浮动标签出现在撞击点,沿偏差方向定位。红色罗盘箭头也会锁定到最终角度,便于快速对齐模板。',
58
+ },
59
+ {
60
+ question: '我可以禁用动画以更快获得结果吗?',
61
+ answer: '动画持续约两秒,之后最终结果显示在中央,罗盘箭头锁定。目前没有跳过选项,但该延迟设计为与掷物理骰子的节奏相匹配。',
62
+ },
63
+ ];
64
+
65
+ const howTo = [
66
+ {
67
+ name: '配置规则',
68
+ text: '选择罗盘扇区,选择距离骰子预设,调整直接命中概率。',
69
+ },
70
+ {
71
+ name: '掷骰或拖动',
72
+ text: '单击"掷骰散布"模拟偏差,或拖动罗盘滚轮手动调整方向。',
73
+ },
74
+ {
75
+ name: '读取结果',
76
+ text: '查看中央显示和矢量箭头,了解散布的确切距离、角度和方向。',
77
+ },
78
+ {
79
+ name: '观察轨迹',
80
+ text: '掷骰后,观察动画抛射物穿越罗盘。虚线轨迹显示偏差路径,撞击点显示距离(英寸)。',
81
+ },
82
+ {
83
+ name: '解读结果',
84
+ text: '绿色脉冲和"DIRECT HIT"表示零偏差。带有距离标签的红色爆炸表示散布 - 将模板从目标沿箭头方向放置相应的英寸数。',
85
+ },
86
+ ];
87
+
88
+ export const content: ScatterSelectorLocaleContent = {
89
+ slug: 'scatter-direction-selector',
90
+ title: '散布方向选择器: 桌面战棋罗盘',
91
+ description: '使用3D触觉罗盘,为微缩模型战棋确定随机偏差、风偏和散布方向。',
92
+ ui,
93
+ seo: [
94
+ { type: 'title', text: '带有实时抛射物动画的交互式散布罗盘', level: 2 },
95
+ { type: 'paragraph', html: '散布方向选择器超越了静态数字生成,直接在罗盘覆盖层上渲染动画抛射物轨迹。当您单击"掷骰散布"时,发光的抛射物从中心沿偏差角度移动,留下虚线轨迹并在撞击点爆裂成粒子。' },
96
+ { type: 'stats', items: [
97
+ { value: '2', label: '扇区系统', icon: 'mdi:compass-rose' },
98
+ { value: '4', label: '骰子预设', icon: 'mdi:dice-d6' },
99
+ { value: '0-100%', label: '命中概率范围', icon: 'mdi:target' },
100
+ { value: '10', label: '最近掷骰历史', icon: 'mdi:history' },
101
+ ], columns: 4 },
102
+ { type: 'title', text: '轨迹动画如何提升战棋决策能力', level: 3 },
103
+ { type: 'paragraph', html: '传统的散布工具显示数字角度和距离,迫使玩家在脑海中想象桌面上的偏移量。动画轨迹通过绘制从瞄准点到散布着陆区的精确飞行路径,弥合了这一差距。' },
104
+ { type: 'diagnostic', variant: 'success', title: '直接命中', html: '当掷骰超过命中概率时,罗盘中心会爆发脉动的绿色光环和"DIRECT HIT"文字动画。抛射物返回中心,确认完美命中且零偏差。' },
105
+ { type: 'diagnostic', variant: 'error', title: '散布', html: '在散布结果中,抛射物沿虚线轨迹移动到着陆点。粒子爆炸、发光标记和距离(英寸)(例如 <strong>5"</strong>)出现在撞击位置。' },
106
+ { type: 'tip', title: '专业提示: 使用风偏模式', html: '启用风偏可将散布方向锁定到您手动旋转的罗盘角度。这模拟了盛行风或固定位移矢量 - 非常适合无制导火箭、毒气云或传送事故。' },
107
+ ],
108
+ faq,
109
+ bibliography,
110
+ howTo,
111
+ schemas: [
112
+ {
113
+ '@context': 'https://schema.org',
114
+ '@type': 'FAQPage',
115
+ 'mainEntity': faq.map((f) => ({
116
+ '@type': 'Question',
117
+ 'name': f.question,
118
+ 'acceptedAnswer': {
119
+ '@type': 'Answer',
120
+ 'text': f.answer,
121
+ },
122
+ })),
123
+ },
124
+ {
125
+ '@context': 'https://schema.org',
126
+ '@type': 'SoftwareApplication',
127
+ 'name': '散布方向选择器',
128
+ 'operatingSystem': 'All',
129
+ 'applicationCategory': 'UtilitiesApplication',
130
+ 'browserRequirements': 'Requires HTML5. Requires JavaScript.',
131
+ },
132
+ {
133
+ '@context': 'https://schema.org',
134
+ '@type': 'HowTo',
135
+ 'name': '如何使用散布方向选择器',
136
+ 'step': howTo.map((h) => ({
137
+ '@type': 'HowToStep',
138
+ 'name': h.name,
139
+ 'text': h.text,
140
+ })),
141
+ },
142
+ ],
143
+ };
@@ -0,0 +1,10 @@
1
+ import type { ToolDefinition } from '../../types';
2
+ import { scatterDirectionSelector } from './entry';
3
+ export * from './entry';
4
+
5
+ export const SCATTER_DIRECTION_SELECTOR_TOOL: ToolDefinition = {
6
+ entry: scatterDirectionSelector,
7
+ Component: () => import('./component.astro'),
8
+ SEOComponent: () => import('./seo.astro'),
9
+ BibliographyComponent: () => import('./bibliography.astro'),
10
+ };
@@ -0,0 +1,62 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { calculateDistance, rollScatter, getSectorIndex } from './logic';
3
+
4
+ describe('ScatterDirectionSelector Logic', () => {
5
+ describe('calculateDistance', () => {
6
+ it('returns a number within the expected D6 range', () => {
7
+ const config = { diceType: 'd6' as const, customMax: 6, hitChance: 33 };
8
+ const dist = calculateDistance(config);
9
+ expect(dist).toBeGreaterThanOrEqual(1);
10
+ expect(dist).toBeLessThanOrEqual(6);
11
+ });
12
+
13
+ it('returns a number within the expected 2D6 range', () => {
14
+ const config = { diceType: '2d6' as const, customMax: 12, hitChance: 33 };
15
+ const dist = calculateDistance(config);
16
+ expect(dist).toBeGreaterThanOrEqual(2);
17
+ expect(dist).toBeLessThanOrEqual(12);
18
+ });
19
+
20
+ it('returns a number within the custom range', () => {
21
+ const config = { diceType: 'custom' as const, customMax: 20, hitChance: 33 };
22
+ const dist = calculateDistance(config);
23
+ expect(dist).toBeGreaterThanOrEqual(1);
24
+ expect(dist).toBeLessThanOrEqual(20);
25
+ });
26
+ });
27
+
28
+ describe('rollScatter', () => {
29
+ it('returns isHit as true when hitChance is 100', () => {
30
+ const config = { diceType: 'd6' as const, customMax: 6, hitChance: 100 };
31
+ const res = rollScatter(config);
32
+ expect(res.isHit).toBe(true);
33
+ expect(res.distance).toBe(0);
34
+ });
35
+
36
+ it('returns isHit as false and positive distance when hitChance is 0', () => {
37
+ const config = { diceType: 'd6' as const, customMax: 6, hitChance: 0 };
38
+ const res = rollScatter(config);
39
+ expect(res.isHit).toBe(false);
40
+ expect(res.distance).toBeGreaterThanOrEqual(1);
41
+ expect(res.angle).toBeGreaterThanOrEqual(0);
42
+ expect(res.angle).toBeLessThan(360);
43
+ });
44
+ });
45
+
46
+ describe('getSectorIndex', () => {
47
+ it('correctly maps 0 degrees to sector index 0', () => {
48
+ const idx8 = getSectorIndex(0, 8);
49
+ expect(idx8).toBe(0);
50
+
51
+ const idx12 = getSectorIndex(0, 12);
52
+ expect(idx12).toBe(0);
53
+ });
54
+
55
+ it('maps angles correctly within sectors boundary', () => {
56
+ expect(getSectorIndex(45, 8)).toBe(1);
57
+ expect(getSectorIndex(90, 8)).toBe(2);
58
+ expect(getSectorIndex(180, 8)).toBe(4);
59
+ expect(getSectorIndex(270, 8)).toBe(6);
60
+ });
61
+ });
62
+ });