@jjlmoya/utils-tabletop 1.10.0 → 1.12.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 (76) hide show
  1. package/package.json +1 -1
  2. package/src/entries.ts +8 -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/decision-wheel/client.ts +2 -0
  6. package/src/tool/decision-wheel/components/SegmentEditor.astro +1 -1
  7. package/src/tool/decision-wheel/decision-wheel.css +23 -7
  8. package/src/tool/dice-roller-simulator/component.astro +116 -26
  9. package/src/tool/hidden-role-dealer/bibliography.astro +16 -0
  10. package/src/tool/hidden-role-dealer/bibliography.ts +12 -0
  11. package/src/tool/hidden-role-dealer/client.ts +265 -0
  12. package/src/tool/hidden-role-dealer/component.astro +184 -0
  13. package/src/tool/hidden-role-dealer/entry.ts +145 -0
  14. package/src/tool/hidden-role-dealer/hidden-role-dealer.css +604 -0
  15. package/src/tool/hidden-role-dealer/i18n/de.ts +195 -0
  16. package/src/tool/hidden-role-dealer/i18n/en.ts +279 -0
  17. package/src/tool/hidden-role-dealer/i18n/es.ts +279 -0
  18. package/src/tool/hidden-role-dealer/i18n/fr.ts +215 -0
  19. package/src/tool/hidden-role-dealer/i18n/id.ts +191 -0
  20. package/src/tool/hidden-role-dealer/i18n/it.ts +191 -0
  21. package/src/tool/hidden-role-dealer/i18n/ja.ts +191 -0
  22. package/src/tool/hidden-role-dealer/i18n/ko.ts +191 -0
  23. package/src/tool/hidden-role-dealer/i18n/nl.ts +191 -0
  24. package/src/tool/hidden-role-dealer/i18n/pl.ts +191 -0
  25. package/src/tool/hidden-role-dealer/i18n/pt.ts +191 -0
  26. package/src/tool/hidden-role-dealer/i18n/ru.ts +191 -0
  27. package/src/tool/hidden-role-dealer/i18n/sv.ts +191 -0
  28. package/src/tool/hidden-role-dealer/i18n/tr.ts +191 -0
  29. package/src/tool/hidden-role-dealer/i18n/zh.ts +191 -0
  30. package/src/tool/hidden-role-dealer/index.ts +10 -0
  31. package/src/tool/hidden-role-dealer/logic.test.ts +99 -0
  32. package/src/tool/hidden-role-dealer/logic.ts +134 -0
  33. package/src/tool/hidden-role-dealer/modules/custom-role-manager.ts +35 -0
  34. package/src/tool/hidden-role-dealer/modules/dealer-logic.ts +73 -0
  35. package/src/tool/hidden-role-dealer/modules/hold-controller.ts +38 -0
  36. package/src/tool/hidden-role-dealer/modules/particle-effects.ts +40 -0
  37. package/src/tool/hidden-role-dealer/modules/player-manager.ts +44 -0
  38. package/src/tool/hidden-role-dealer/modules/presets.ts +46 -0
  39. package/src/tool/hidden-role-dealer/modules/setup-handlers.ts +34 -0
  40. package/src/tool/hidden-role-dealer/modules/storage.ts +23 -0
  41. package/src/tool/hidden-role-dealer/modules/utils.ts +18 -0
  42. package/src/tool/hidden-role-dealer/modules/wizard-html.ts +161 -0
  43. package/src/tool/hidden-role-dealer/modules/wizard-renderer.ts +161 -0
  44. package/src/tool/hidden-role-dealer/modules/writer-handler.ts +70 -0
  45. package/src/tool/hidden-role-dealer/seo.astro +16 -0
  46. package/src/tool/hidden-role-dealer/types.ts +31 -0
  47. package/src/tool/scatter-direction-selector/animation.ts +278 -0
  48. package/src/tool/scatter-direction-selector/bibliography.astro +16 -0
  49. package/src/tool/scatter-direction-selector/bibliography.ts +12 -0
  50. package/src/tool/scatter-direction-selector/client.ts +296 -0
  51. package/src/tool/scatter-direction-selector/component.astro +184 -0
  52. package/src/tool/scatter-direction-selector/entry.ts +59 -0
  53. package/src/tool/scatter-direction-selector/history.ts +71 -0
  54. package/src/tool/scatter-direction-selector/i18n/de.ts +143 -0
  55. package/src/tool/scatter-direction-selector/i18n/en.ts +231 -0
  56. package/src/tool/scatter-direction-selector/i18n/es.ts +143 -0
  57. package/src/tool/scatter-direction-selector/i18n/fr.ts +143 -0
  58. package/src/tool/scatter-direction-selector/i18n/id.ts +143 -0
  59. package/src/tool/scatter-direction-selector/i18n/it.ts +143 -0
  60. package/src/tool/scatter-direction-selector/i18n/ja.ts +143 -0
  61. package/src/tool/scatter-direction-selector/i18n/ko.ts +143 -0
  62. package/src/tool/scatter-direction-selector/i18n/nl.ts +143 -0
  63. package/src/tool/scatter-direction-selector/i18n/pl.ts +143 -0
  64. package/src/tool/scatter-direction-selector/i18n/pt.ts +143 -0
  65. package/src/tool/scatter-direction-selector/i18n/ru.ts +143 -0
  66. package/src/tool/scatter-direction-selector/i18n/sv.ts +143 -0
  67. package/src/tool/scatter-direction-selector/i18n/tr.ts +143 -0
  68. package/src/tool/scatter-direction-selector/i18n/zh.ts +143 -0
  69. package/src/tool/scatter-direction-selector/index.ts +10 -0
  70. package/src/tool/scatter-direction-selector/logic.test.ts +62 -0
  71. package/src/tool/scatter-direction-selector/logic.ts +52 -0
  72. package/src/tool/scatter-direction-selector/scatter-direction-selector.css +794 -0
  73. package/src/tool/scatter-direction-selector/seo.astro +16 -0
  74. package/src/tool/scatter-direction-selector/settings.ts +81 -0
  75. package/src/tool/scatter-direction-selector/sound.ts +22 -0
  76. package/src/tools.ts +4 -0
@@ -0,0 +1,16 @@
1
+ ---
2
+ import { SEORenderer } from '@jjlmoya/utils-shared';
3
+ import { scatterDirectionSelector } from './index';
4
+ import type { KnownLocale } from '../../types';
5
+
6
+ interface Props {
7
+ locale?: KnownLocale;
8
+ }
9
+
10
+ const { locale = 'en' } = Astro.props;
11
+ const loader = scatterDirectionSelector.i18n[locale] || scatterDirectionSelector.i18n.en;
12
+ const content = await loader?.();
13
+ if (!content) return null;
14
+ ---
15
+
16
+ {content.seo?.length > 0 && <SEORenderer content={{ locale, sections: content.seo }} />}
@@ -0,0 +1,81 @@
1
+ export class SettingsBinder {
2
+ private sectorsCount: number = 8;
3
+ private diceType: string = 'd6';
4
+ private maxCustomDist: number = 12;
5
+ private hitChance: number = 33;
6
+ private windDriftMode: boolean = false;
7
+
8
+ onSectorsChange: ((count: number) => void) | null = null;
9
+ onModeChange: ((wind: boolean) => void) | null = null;
10
+ onDiceChange: ((dice: string) => void) | null = null;
11
+ onCustomMaxChange: ((max: number) => void) | null = null;
12
+ onHitChanceChange: ((chance: number) => void) | null = null;
13
+
14
+ getSectors(): number { return this.sectorsCount; }
15
+ getDice(): string { return this.diceType; }
16
+ getMode(): boolean { return this.windDriftMode; }
17
+ getMaxDist(): number { return this.maxCustomDist; }
18
+ getHitChance(): number { return this.hitChance; }
19
+
20
+ bind(root: HTMLElement): void {
21
+ this.bindSectorToggle(root);
22
+ this.bindModeToggle(root);
23
+ this.bindDiceSelect(root);
24
+ this.bindCustomMax(root);
25
+ this.bindHitChance(root);
26
+ }
27
+
28
+ private bindSectorToggle(root: HTMLElement): void {
29
+ const btns = root.querySelectorAll('[data-sectors]');
30
+ btns.forEach((btn) => {
31
+ btn.addEventListener('click', () => {
32
+ btns.forEach((b) => b.classList.remove('active'));
33
+ btn.classList.add('active');
34
+ this.sectorsCount = parseInt(btn.getAttribute('data-sectors') || '8', 10);
35
+ this.onSectorsChange?.(this.sectorsCount);
36
+ });
37
+ });
38
+ }
39
+
40
+ private bindModeToggle(root: HTMLElement): void {
41
+ const btns = root.querySelectorAll('[data-mode]');
42
+ const hint = root.querySelector('#sds-wind-hint') as HTMLElement;
43
+ btns.forEach((btn) => {
44
+ btn.addEventListener('click', () => {
45
+ btns.forEach((b) => b.classList.remove('active'));
46
+ btn.classList.add('active');
47
+ this.windDriftMode = btn.getAttribute('data-mode') === 'wind';
48
+ hint.style.display = this.windDriftMode ? 'block' : 'none';
49
+ this.onModeChange?.(this.windDriftMode);
50
+ });
51
+ });
52
+ }
53
+
54
+ private bindDiceSelect(root: HTMLElement): void {
55
+ const select = root.querySelector('#sds-dice-select') as HTMLSelectElement;
56
+ select.addEventListener('change', () => {
57
+ this.diceType = select.value;
58
+ const wrap = root.querySelector('#sds-custom-dist-wrapper') as HTMLElement;
59
+ wrap.style.display = this.diceType === 'custom' ? 'block' : 'none';
60
+ this.onDiceChange?.(this.diceType);
61
+ });
62
+ }
63
+
64
+ private bindCustomMax(root: HTMLElement): void {
65
+ const input = root.querySelector('#sds-custom-max') as HTMLInputElement;
66
+ input.addEventListener('input', () => {
67
+ this.maxCustomDist = Math.max(1, parseInt(input.value, 10) || 12);
68
+ this.onCustomMaxChange?.(this.maxCustomDist);
69
+ });
70
+ }
71
+
72
+ private bindHitChance(root: HTMLElement): void {
73
+ const input = root.querySelector('#sds-hit-chance') as HTMLInputElement;
74
+ const display = root.querySelector('#sds-hit-chance-val') as HTMLElement;
75
+ input.addEventListener('input', () => {
76
+ this.hitChance = parseInt(input.value, 10);
77
+ display.textContent = `${this.hitChance}%`;
78
+ this.onHitChanceChange?.(this.hitChance);
79
+ });
80
+ }
81
+ }
@@ -0,0 +1,22 @@
1
+ export class SoundManager {
2
+ private ctx: AudioContext | null = null;
3
+ enabled: boolean = true;
4
+
5
+ play(freq: number, type: OscillatorType, dur: number): void {
6
+ if (!this.enabled) return;
7
+ const ACtor = (window.AudioContext || (window as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext) as typeof AudioContext;
8
+ if (!this.ctx) this.ctx = new ACtor();
9
+ if (this.ctx.state === 'suspended') this.ctx.resume();
10
+
11
+ const osc = this.ctx.createOscillator();
12
+ const gain = this.ctx.createGain();
13
+ osc.connect(gain);
14
+ gain.connect(this.ctx.destination);
15
+ osc.type = type;
16
+ osc.frequency.setValueAtTime(freq, this.ctx.currentTime);
17
+ gain.gain.setValueAtTime(0.08, this.ctx.currentTime);
18
+ gain.gain.exponentialRampToValueAtTime(0.001, this.ctx.currentTime + dur);
19
+ osc.start();
20
+ osc.stop(this.ctx.currentTime + dur);
21
+ }
22
+ }
package/src/tools.ts CHANGED
@@ -9,6 +9,8 @@ import { FANTASY_RUNES_TRANSLATOR_TOOL } from './tool/fantasy-runes-translator';
9
9
  import { DECISION_WHEEL_TOOL } from './tool/decision-wheel';
10
10
  import { INVESTIGATION_BOARD_TOOL } from './tool/investigation-board';
11
11
  import { LUNAR_TIDE_TRACKER_TOOL } from './tool/lunar-tide-tracker';
12
+ import { HIDDEN_ROLE_DEALER_TOOL } from './tool/hidden-role-dealer';
13
+ import { SCATTER_DIRECTION_SELECTOR_TOOL } from './tool/scatter-direction-selector';
12
14
 
13
15
  export const ALL_TOOLS: ToolDefinition[] = [
14
16
  DICE_ROLLER_SIMULATOR_TOOL,
@@ -20,5 +22,7 @@ export const ALL_TOOLS: ToolDefinition[] = [
20
22
  DECISION_WHEEL_TOOL,
21
23
  INVESTIGATION_BOARD_TOOL,
22
24
  LUNAR_TIDE_TRACKER_TOOL,
25
+ HIDDEN_ROLE_DEALER_TOOL,
26
+ SCATTER_DIRECTION_SELECTOR_TOOL,
23
27
  ];
24
28