@jjlmoya/utils-creative 1.5.0 → 1.7.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 (32) hide show
  1. package/package.json +62 -62
  2. package/src/tests/locale_completeness.test.ts +2 -2
  3. package/src/tests/schemas_fulfillment.test.ts +23 -0
  4. package/src/tests/title_quality.test.ts +55 -0
  5. package/src/tests/tool_validation.test.ts +2 -2
  6. package/src/tool/bead-pattern-generator/component.astro +29 -21
  7. package/src/tool/bead-pattern-generator/i18n/en.ts +73 -19
  8. package/src/tool/bead-pattern-generator/i18n/es.ts +73 -19
  9. package/src/tool/bead-pattern-generator/i18n/fr.ts +73 -19
  10. package/src/tool/bead-pattern-generator/index.ts +14 -2
  11. package/src/tool/dice-roller/component.astro +42 -30
  12. package/src/tool/dice-roller/i18n/en.ts +84 -33
  13. package/src/tool/dice-roller/i18n/es.ts +84 -33
  14. package/src/tool/dice-roller/i18n/fr.ts +84 -33
  15. package/src/tool/dice-roller/index.ts +9 -0
  16. package/src/tool/excuse-generator/i18n/en.ts +60 -18
  17. package/src/tool/excuse-generator/i18n/es.ts +60 -18
  18. package/src/tool/excuse-generator/i18n/fr.ts +60 -18
  19. package/src/tool/fortune-cookie/component.astro +27 -16
  20. package/src/tool/fortune-cookie/i18n/en.ts +60 -18
  21. package/src/tool/fortune-cookie/i18n/es.ts +60 -18
  22. package/src/tool/fortune-cookie/i18n/fr.ts +60 -18
  23. package/src/tool/synesthesia-painter/component.astro +5 -5
  24. package/src/tool/synesthesia-painter/i18n/en.ts +74 -32
  25. package/src/tool/synesthesia-painter/i18n/es.ts +74 -32
  26. package/src/tool/synesthesia-painter/i18n/fr.ts +74 -32
  27. package/src/tool/zalgo-generator/component.astro +29 -18
  28. package/src/tool/zalgo-generator/i18n/en.ts +70 -17
  29. package/src/tool/zalgo-generator/i18n/es.ts +70 -17
  30. package/src/tool/zalgo-generator/i18n/fr.ts +70 -17
  31. package/src/tool/zalgo-generator/index.ts +11 -0
  32. package/src/tools.ts +14 -1
@@ -1,18 +1,82 @@
1
+ import type { WithContext, FAQPage, HowTo, SoftwareApplication } from 'schema-dts';
1
2
  import type { BeadPatternGeneratorLocaleContent } from '../index';
2
3
 
4
+ const slug = 'generateur-de-modeles-de-perles';
5
+ const title = 'Générateur de Modèles';
6
+ const description = 'Créez du pixel art et des schémas de perles pour Miyuki ou Hama à partir de vos photos. Algorithme de quantification de couleurs, mode vision tunnel et export ZIP.';
7
+
8
+ const faq: BeadPatternGeneratorLocaleContent['faq'] = [
9
+ { question: 'Qu\'est-ce que la quantification de couleurs dans les modèles ?', answer: 'C\'est le processus de réduction des milliers de couleurs d\'une photo à quelques-unes seulement qui correspondent aux couleurs réelles des perles disponibles (ex: Miyuki ou Hama). Nous utilisons des algorithmes intelligents pour maintenir la ressemblance visuelle avec la palette minimale possible.' },
10
+ { question: 'Puis-je utiliser ce modèle pour le point de croix ?', answer: 'Oui, le générateur crée un diagramme de grille parfaitement compatible avec le point de croix. Il vous suffit de choisir une taille de grille correspondant à votre tissu (Aïda 14, 18, etc.).' },
11
+ { question: 'Quelle est la différence entre les perles Miyuki et Hama ?', answer: 'Les perles Miyuki Delica sont de très petites perles de verre précises pour la bijouterie. Les perles Hama sont en plastique et se fusionnent au fer à repasser. Notre outil vous permet d\'ajuster le rapport d\'aspect pour que le modèle ne se déforme pas selon le matériau utilisé.' },
12
+ { question: 'Comment fonctionne l\'algorithme de tramage (dithering) ?', answer: 'Le tramage crée l\'illusion d\'un plus grand nombre de couleurs en mélangeant des pixels de différentes couleurs dans des motifs espacés. Cela aide les dégradés de couleurs à paraître plus fluides, même avec une palette de perles limitée.' },
13
+ ];
14
+
15
+ const howTo: BeadPatternGeneratorLocaleContent['howTo'] = [
16
+ { name: 'Charger une image claire', text: 'Sélectionnez une photo avec un bon contraste et peu de petits détails pour que le modèle soit plus facile à suivre.' },
17
+ { name: 'Ajuster la taille de la grille', text: 'Définissez la largeur et la hauteur en perles de votre pièce finale. Plus il y a de perles, plus il y a de détails, mais plus c\'est difficile.' },
18
+ { name: 'Optimiser la palette de couleurs', text: 'Réduisez le nombre de couleurs jusqu\'à ce qu\'elles correspondent aux perles dont vous disposez dans votre kit de loisirs créatifs.' },
19
+ { name: 'Exporter le schéma guide', text: 'Générez le modèle final avec les codes de couleur à utiliser comme référence lors de l\'assemblage de vos perles sur la plaque ou le fil.' },
20
+ ];
21
+
22
+ const faqSchema: WithContext<FAQPage> = {
23
+ '@context': 'https://schema.org',
24
+ '@type': 'FAQPage',
25
+ mainEntity: faq.map((item) => ({
26
+ '@type': 'Question',
27
+ name: item.question,
28
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
29
+ })),
30
+ };
31
+
32
+ const howToSchema: WithContext<HowTo> = {
33
+ '@context': 'https://schema.org',
34
+ '@type': 'HowTo',
35
+ name: title,
36
+ description,
37
+ step: howTo.map((step) => ({
38
+ '@type': 'HowToStep',
39
+ name: step.name,
40
+ text: step.text,
41
+ })),
42
+ };
43
+
44
+ const appSchema: WithContext<SoftwareApplication> = {
45
+ '@context': 'https://schema.org',
46
+ '@type': 'SoftwareApplication',
47
+ name: title,
48
+ description,
49
+ applicationCategory: 'UtilitiesApplication',
50
+ operatingSystem: 'Web',
51
+ offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' },
52
+ inLanguage: 'fr',
53
+ };
54
+
3
55
  export const content: BeadPatternGeneratorLocaleContent = {
4
- slug: 'generateur-de-modeles-de-perles',
5
- title: 'Générateur de Modèles',
6
- description: 'Créez du pixel art et des schémas de perles pour Miyuki ou Hama à partir de vos photos. Algorithme de quantification de couleurs, mode vision tunnel et export ZIP.',
56
+ slug,
57
+ title,
58
+ description,
7
59
  faqTitle: 'Questions Fréquemment Posées',
8
60
  bibliographyTitle: 'Bibliographie de l\'Artisan',
9
61
  ui: {
10
- title: 'Générateur de Modèles',
62
+ title: 'Laboratoire de Modèles',
63
+ subtitle: 'Ingénierie chromatique pour vos mains',
11
64
  description: 'De la photo au schéma de perles.',
65
+ gridSizeLabel: 'Taille (Largeur)',
66
+ colorCountLabel: 'Couleurs',
67
+ optionsLabel: 'Options',
68
+ rulersLabel: 'Règles',
69
+ symbolsTooltip: 'Motif Surprise',
70
+ symbolsLabel: 'Symboles',
71
+ downloadBtn: 'Télécharger',
72
+ uploadTitle: 'Chargez Votre Vision',
73
+ uploadSubtitle: 'et laissez la magie numérique opérer',
74
+ paletteTitle: 'ADN Chromatique',
75
+ reuploadBtn: 'Changer l\'Image',
76
+ tunnelVisionTitle: 'Vision de Tunnel',
77
+ tunnelVisionSubtitle: 'Votre assistant de précision rangée par rangée.',
12
78
  uploadLabel: 'Chargez votre photo',
13
- gridSizeLabel: 'Taille de grille (perles)',
14
79
  pixelateBtn: 'Générer le Modèle',
15
- downloadBtn: 'Télécharger le Schéma',
16
80
  faqTitle: 'FAQ',
17
81
  bibliographyTitle: 'Références'
18
82
  },
@@ -40,22 +104,12 @@ export const content: BeadPatternGeneratorLocaleContent = {
40
104
  ], columns: 4 },
41
105
  { type: 'paragraph', html: 'À l\'ère des écrans éphémères, créer quelque chose de physique est un acte révolutionnaire. Cet outil ne cherche pas à automatiser l\'art, mais à <strong>donner du pouvoir à l\'artisan</strong>. Nous vous offrons la précision informatique pour que vos mains puissent bâtir des héritages durables.' },
42
106
  ],
43
- faq: [
44
- { question: 'Qu\'est-ce que la quantification de couleurs dans les modèles ?', answer: 'C\'est le processus de réduction des milliers de couleurs d\'une photo à quelques-unes seulement qui correspondent aux couleurs réelles des perles disponibles (ex: Miyuki ou Hama). Nous utilisons des algorithmes intelligents pour maintenir la ressemblance visuelle avec la palette minimale possible.' },
45
- { question: 'Puis-je utiliser ce modèle pour le point de croix ?', answer: 'Oui, le générateur crée un diagramme de grille parfaitement compatible avec le point de croix. Il vous suffit de choisir une taille de grille correspondant à votre tissu (Aïda 14, 18, etc.).' },
46
- { question: 'Quelle est la différence entre les perles Miyuki et Hama ?', answer: 'Les perles Miyuki Delica sont de très petites perles de verre précises pour la bijouterie. Les perles Hama sont en plastique et se fusionnent au fer à repasser. Notre outil vous permet d\'ajuster le rapport d\'aspect pour que le modèle ne se déforme pas selon le matériau utilisé.' },
47
- { question: 'Comment fonctionne l\'algorithme de tramage (dithering) ?', answer: 'Le tramage crée l\'illusion d\'un plus grand nombre de couleurs en mélangeant des pixels de différentes couleurs dans des motifs espacés. Cela aide les dégradés de couleurs à paraître plus fluides, même avec une palette de perles limitée.' },
48
- ],
107
+ faq,
49
108
  bibliography: [
50
109
  { name: 'Scikit-Image: Quantification de couleurs utilisant K-Means', url: 'https://scikit-learn.org/0.23/auto_examples/cluster/plot_color_quantization.html' },
51
110
  { name: 'Spécifications des Perles Miyuki Delica', url: 'https://www.miyuki-beads.co.jp/english/seedbeads/delica.html' },
52
111
  { name: 'Visgraf Lab: Algorithmes de Tramage (Dithering)', url: 'https://www.visgraf.impa.br/Courses/ip00/proj/Dithering1/floyd_steinberg_dithering.html' },
53
112
  ],
54
- howTo: [
55
- { name: 'Charger une image claire', text: 'Sélectionnez une photo avec un bon contraste et peu de petits détails pour que le modèle soit plus facile à suivre.' },
56
- { name: 'Ajuster la taille de la grille', text: 'Définissez la largeur et la hauteur en perles de votre pièce finale. Plus il y a de perles, plus il y a de détails, mais plus c\'est difficile.' },
57
- { name: 'Optimiser la palette de couleurs', text: 'Réduisez le nombre de couleurs jusqu\'à ce qu\'elles correspondent aux perles dont vous disposez dans votre kit de loisirs créatifs.' },
58
- { name: 'Exporter le schéma guide', text: 'Générez le modèle final avec les codes de couleur à utiliser comme référence lors de l\'assemblage de vos perles sur la plaque ou le fil.' },
59
- ],
60
- schemas: []
113
+ howTo,
114
+ schemas: [faqSchema as any, howToSchema as any, appSchema],
61
115
  };
@@ -7,10 +7,22 @@ export interface BeadPatternGeneratorUI {
7
7
  [key: string]: string;
8
8
  title: string;
9
9
  description: string;
10
- uploadLabel: string;
10
+ subtitle: string;
11
11
  gridSizeLabel: string;
12
- pixelateBtn: string;
12
+ colorCountLabel: string;
13
+ optionsLabel: string;
14
+ rulersLabel: string;
15
+ symbolsTooltip: string;
16
+ symbolsLabel: string;
13
17
  downloadBtn: string;
18
+ uploadTitle: string;
19
+ uploadSubtitle: string;
20
+ paletteTitle: string;
21
+ reuploadBtn: string;
22
+ tunnelVisionTitle: string;
23
+ tunnelVisionSubtitle: string;
24
+ uploadLabel: string;
25
+ pixelateBtn: string;
14
26
  faqTitle: string;
15
27
  bibliographyTitle: string;
16
28
  }
@@ -1,11 +1,18 @@
1
1
  ---
2
+ import type { DiceRollerUI } from './index';
3
+
4
+ interface Props {
5
+ ui: DiceRollerUI;
6
+ }
7
+
8
+ const { ui } = Astro.props;
2
9
  ---
3
10
 
4
- <div id="dice-roller-root" class="dr-root">
11
+ <div id="dice-roller-root" class="dr-root" data-ui={JSON.stringify(ui)}>
5
12
  <div class="dr-panel">
6
13
 
7
14
  <div class="dr-selector">
8
- <p class="dr-label">Añadir dados a la bolsa</p>
15
+ <p class="dr-label">{ui.addDiceLabel}</p>
9
16
  <div class="dr-dice-grid">
10
17
  <button class="dr-die-btn" data-sides="4">d4</button>
11
18
  <button class="dr-die-btn" data-sides="6">d6</button>
@@ -19,16 +26,16 @@
19
26
 
20
27
  <div class="dr-pool-section">
21
28
  <div class="dr-pool-header">
22
- <p class="dr-label">Bolsa de dados</p>
23
- <button id="dr-clear-pool" class="dr-clear-btn">Vaciar</button>
29
+ <p class="dr-label">{ui.bagLabel}</p>
30
+ <button id="dr-clear-pool" class="dr-clear-btn">{ui.emptyBagBtn}</button>
24
31
  </div>
25
32
  <div id="dr-pool" class="dr-pool-display">
26
- <span class="dr-pool-empty">Haz clic en los dados para añadirlos</span>
33
+ <span class="dr-pool-empty">{ui.emptyBagText}</span>
27
34
  </div>
28
35
  </div>
29
36
 
30
37
  <div class="dr-modifier-section">
31
- <label class="dr-label" for="dr-modifier">Modificador</label>
38
+ <label class="dr-label" for="dr-modifier">{ui.modifierLabel}</label>
32
39
  <div class="dr-modifier-controls">
33
40
  <button id="dr-mod-dec" class="dr-mod-btn">−</button>
34
41
  <span id="dr-modifier-val" class="dr-modifier-display">0</span>
@@ -37,7 +44,7 @@
37
44
  </div>
38
45
 
39
46
  <button id="dr-roll-btn" class="dr-roll-btn" disabled>
40
- <span id="dr-roll-text">Lanzar dados</span>
47
+ <span id="dr-roll-text">{ui.rollBtn}</span>
41
48
  </button>
42
49
 
43
50
  </div>
@@ -46,11 +53,11 @@
46
53
 
47
54
  <div class="dr-result-card" id="dr-result-card">
48
55
  <div class="dr-result-empty" id="dr-result-empty">
49
- <p>Añade dados y lanza</p>
56
+ <p>{ui.preRollText}</p>
50
57
  </div>
51
58
  <div class="dr-result-content" id="dr-result-content" style="display:none">
52
59
  <div class="dr-total-area">
53
- <span class="dr-total-label">Total</span>
60
+ <span class="dr-total-label">{ui.totalLabel}</span>
54
61
  <span id="dr-total" class="dr-total-val">0</span>
55
62
  <span id="dr-roll-expr" class="dr-roll-expr"></span>
56
63
  </div>
@@ -60,11 +67,11 @@
60
67
 
61
68
  <div class="dr-history-section">
62
69
  <div class="dr-history-header">
63
- <span class="dr-label">Historial</span>
64
- <button id="dr-clear-history" class="dr-clear-btn">Limpiar</button>
70
+ <span class="dr-label">{ui.historyLabel}</span>
71
+ <button id="dr-clear-history" class="dr-clear-btn">{ui.clearHistoryBtn}</button>
65
72
  </div>
66
73
  <div id="dr-history-list" class="dr-history-list">
67
- <p class="dr-history-empty">El historial de tiradas aparecerá aquí</p>
74
+ <p class="dr-history-empty">{ui.emptyHistoryText}</p>
68
75
  </div>
69
76
  </div>
70
77
 
@@ -72,6 +79,10 @@
72
79
  </div>
73
80
 
74
81
  <script>
82
+ import type { DiceRollerUI } from './index';
83
+ const root = document.getElementById('dice-roller-root') as HTMLElement;
84
+ const ui = JSON.parse(root.dataset.ui || '{}') as DiceRollerUI;
85
+
75
86
  type Pool = { sides: number; count: number }[];
76
87
 
77
88
  let pool: Pool = [];
@@ -94,9 +105,9 @@
94
105
 
95
106
  function renderPool(): void {
96
107
  if (pool.length === 0) {
97
- poolDisplay.innerHTML = '<span class="dr-pool-empty">Haz clic en los dados para añadirlos</span>';
108
+ poolDisplay.innerHTML = `<span class="dr-pool-empty">${ui.emptyBagText}</span>`;
98
109
  rollBtn.disabled = true;
99
- rollText.textContent = 'Lanzar dados';
110
+ rollText.textContent = ui.rollBtn;
100
111
  return;
101
112
  }
102
113
 
@@ -106,14 +117,15 @@
106
117
  chip.className = 'dr-pool-chip';
107
118
  chip.innerHTML = `
108
119
  <span class="dr-chip-label">${count}d${sides}</span>
109
- <button class="dr-chip-remove" data-sides="${sides}" title="Quitar un d${sides}">−</button>
120
+ <button class="dr-chip-remove" data-sides="${sides}">−</button>
110
121
  `;
111
122
  poolDisplay.appendChild(chip);
112
123
  });
113
124
 
114
125
  const total = poolTotal();
115
126
  rollBtn.disabled = false;
116
- rollText.textContent = `Lanzar ${total} dado${total !== 1 ? 's' : ''}`;
127
+ const label = total === 1 ? ui.rollOneLabel : ui.rollManyLabel;
128
+ rollText.textContent = label.replace('$COUNT', total.toString());
117
129
  }
118
130
 
119
131
  function addDie(sides: number): void {
@@ -224,7 +236,7 @@
224
236
  rollBtn.addEventListener('click', rollAll);
225
237
 
226
238
  document.getElementById('dr-clear-history')?.addEventListener('click', () => {
227
- historyList.innerHTML = '<p class="dr-history-empty">El historial de tiradas aparecerá aquí</p>';
239
+ historyList.innerHTML = `<p class="dr-history-empty">${ui.emptyHistoryText}</p>`;
228
240
  });
229
241
  </script>
230
242
 
@@ -378,7 +390,7 @@
378
390
  font-style: italic;
379
391
  }
380
392
 
381
- .dr-pool-chip {
393
+ :global(.dr-pool-chip) {
382
394
  display: flex;
383
395
  align-items: center;
384
396
  gap: 0.25rem;
@@ -388,13 +400,13 @@
388
400
  padding: 0.2rem 0.5rem 0.2rem 0.75rem;
389
401
  }
390
402
 
391
- .dr-chip-label {
403
+ :global(.dr-chip-label) {
392
404
  font-size: 0.8rem;
393
405
  font-weight: 700;
394
406
  color: var(--dr-primary);
395
407
  }
396
408
 
397
- .dr-chip-remove {
409
+ :global(.dr-chip-remove) {
398
410
  width: 1.125rem;
399
411
  height: 1.125rem;
400
412
  border-radius: 50%;
@@ -411,7 +423,7 @@
411
423
  padding: 0;
412
424
  }
413
425
 
414
- .dr-chip-remove:hover {
426
+ :global(.dr-chip-remove:hover) {
415
427
  background: var(--dr-primary-dark);
416
428
  }
417
429
 
@@ -581,7 +593,7 @@
581
593
  justify-content: center;
582
594
  }
583
595
 
584
- .dr-result-pip {
596
+ :global(.dr-result-pip) {
585
597
  display: flex;
586
598
  flex-direction: column;
587
599
  align-items: center;
@@ -594,24 +606,24 @@
594
606
  transition: border-color 0.2s;
595
607
  }
596
608
 
597
- .dr-pip-max {
609
+ :global(.dr-pip-max) {
598
610
  border-color: var(--dr-success);
599
611
  background: rgba(16, 185, 129, 0.1);
600
612
  }
601
613
 
602
- .dr-pip-min {
614
+ :global(.dr-pip-min) {
603
615
  border-color: var(--dr-danger);
604
616
  background: rgba(239, 68, 68, 0.1);
605
617
  }
606
618
 
607
- .dr-pip-val {
619
+ :global(.dr-pip-val) {
608
620
  font-size: 1.25rem;
609
621
  font-weight: 800;
610
622
  color: var(--dr-text);
611
623
  line-height: 1;
612
624
  }
613
625
 
614
- .dr-pip-die {
626
+ :global(.dr-pip-die) {
615
627
  font-size: 0.65rem;
616
628
  color: var(--dr-text-muted);
617
629
  font-weight: 600;
@@ -662,7 +674,7 @@
662
674
  margin: 1rem 0;
663
675
  }
664
676
 
665
- .dr-history-item {
677
+ :global(.dr-history-item) {
666
678
  display: grid;
667
679
  grid-template-columns: 1fr auto auto;
668
680
  align-items: center;
@@ -686,7 +698,7 @@
686
698
  }
687
699
  }
688
700
 
689
- .dr-hist-expr {
701
+ :global(.dr-hist-expr) {
690
702
  color: var(--dr-text-muted);
691
703
  font-size: 0.75rem;
692
704
  overflow: hidden;
@@ -694,13 +706,13 @@
694
706
  white-space: nowrap;
695
707
  }
696
708
 
697
- .dr-hist-result {
709
+ :global(.dr-hist-result) {
698
710
  font-weight: 800;
699
711
  font-size: 1rem;
700
712
  color: var(--dr-primary);
701
713
  }
702
714
 
703
- .dr-hist-time {
715
+ :global(.dr-hist-time) {
704
716
  font-size: 0.7rem;
705
717
  color: var(--dr-text-muted);
706
718
  }
@@ -1,9 +1,77 @@
1
+ import type { WithContext, FAQPage, HowTo, SoftwareApplication } from 'schema-dts';
1
2
  import type { DiceRollerLocaleContent } from '../index';
2
3
 
4
+ const slug = 'dice-roller';
5
+ const title = 'Dice Roller';
6
+ const description = 'A complete dice simulator for your RPG and board games. Roll d4, d6, d8, d10, d12, d20 and d100 with modifiers and history.';
7
+
8
+ const faq: DiceRollerLocaleContent['faq'] = [
9
+ {
10
+ question: 'How can I simulate a roll with advantage (D&D)?',
11
+ answer: 'Add two d20 dice to the bag by clicking the d20 button twice. When rolling, observe the two individual results and keep the higher one. The displayed total will be the sum, but you can see each die separately in the result breakdown.',
12
+ },
13
+ {
14
+ question: 'What does the green or red color on results mean?',
15
+ answer: 'Green results indicate that die rolled its maximum possible value (a "critical"). Red results indicate the minimum value (a "1", the worst possible result). This makes it easy to spot crits and fumbles at a glance.',
16
+ },
17
+ {
18
+ question: 'Can I add multiple dice of the same type?',
19
+ answer: 'Yes. Each click on a die adds it to the bag. If you click the d6 three times, the bag will show "3d6". To reduce the count, click the "−" button that appears next to each die group in the bag.',
20
+ },
21
+ {
22
+ question: 'Are digital dice as random as physical ones?',
23
+ answer: 'Statistically, yes. Modern JavaScript engines use pseudorandom algorithms (xorshift128+) with very high quality uniform distribution. A real physical die can have small manufacturing imperfections that bias results; the digital die does not have that problem.',
24
+ },
25
+ {
26
+ question: 'What is the d100 and how is it used?',
27
+ answer: 'The d100 (or d%) generates a number from 1 to 100 and is used in percentage-based game systems, such as Call of Cthulhu or Warhammer Fantasy Roleplay. It represents "direct probability": if your Stealth skill is 65%, you need to roll 65 or less to succeed.',
28
+ },
29
+ ];
30
+
31
+ const howTo: DiceRollerLocaleContent['howTo'] = [
32
+ { name: 'Build the dice pool', text: 'Click the die buttons (d4, d6, d8...) to add them to your pool. Each click adds one die of the selected type. You can mix different types in the same roll.' },
33
+ { name: 'Adjust the modifier', text: 'Use the "+" and "−" buttons next to the modifier to apply bonuses or penalties (like the ability modifier in D&D). The modifier is automatically added to the total.' },
34
+ { name: 'Roll the dice', text: 'Press the "Roll Dice" button. The right panel shows the final total and the breakdown of each individual die, with crits (maximum) in green and fumbles (minimum) in red.' },
35
+ { name: 'Check the history', text: 'Each roll is recorded in the history with the dice expression used, the total result, and the exact time. You can clear the history with the corresponding button.' },
36
+ ];
37
+
38
+ const faqSchema: WithContext<FAQPage> = {
39
+ '@context': 'https://schema.org',
40
+ '@type': 'FAQPage',
41
+ mainEntity: faq.map((item) => ({
42
+ '@type': 'Question',
43
+ name: item.question,
44
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
45
+ })),
46
+ };
47
+
48
+ const howToSchema: WithContext<HowTo> = {
49
+ '@context': 'https://schema.org',
50
+ '@type': 'HowTo',
51
+ name: title,
52
+ description,
53
+ step: howTo.map((step) => ({
54
+ '@type': 'HowToStep',
55
+ name: step.name,
56
+ text: step.text,
57
+ })),
58
+ };
59
+
60
+ const appSchema: WithContext<SoftwareApplication> = {
61
+ '@context': 'https://schema.org',
62
+ '@type': 'SoftwareApplication',
63
+ name: title,
64
+ description,
65
+ applicationCategory: 'UtilitiesApplication',
66
+ operatingSystem: 'Web',
67
+ offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' },
68
+ inLanguage: 'en',
69
+ };
70
+
3
71
  export const content: DiceRollerLocaleContent = {
4
- slug: 'dice-roller',
5
- title: 'Dice Roller',
6
- description: 'A complete dice simulator for your RPG and board games. Roll d4, d6, d8, d10, d12, d20 and d100 with modifiers and history.',
72
+ slug,
73
+ title,
74
+ description,
7
75
  faqTitle: 'Frequently Asked Questions',
8
76
  bibliographyTitle: 'Chance Bibliography',
9
77
  ui: {
@@ -14,7 +82,16 @@ export const content: DiceRollerLocaleContent = {
14
82
  historyLabel: 'History',
15
83
  clearHistoryBtn: 'Clear History',
16
84
  faqTitle: 'FAQ',
17
- bibliographyTitle: 'References'
85
+ bibliographyTitle: 'References',
86
+ addDiceLabel: 'Add dice to the bag',
87
+ bagLabel: 'Dice bag',
88
+ emptyBagBtn: 'Empty',
89
+ emptyBagText: 'Click the dice to add them',
90
+ modifierLabel: 'Modifier',
91
+ rollManyLabel: 'Roll $COUNT dice',
92
+ rollOneLabel: 'Roll $COUNT die',
93
+ preRollText: 'Add dice and roll',
94
+ emptyHistoryText: 'Roll history will appear here'
18
95
  },
19
96
  seo: [
20
97
  { type: 'title', text: 'The Art of Randomness: History and Mathematics of Dice', level: 2 },
@@ -50,38 +127,12 @@ export const content: DiceRollerLocaleContent = {
50
127
  { term: 'Percentile Roll', definition: 'A roll using two d10 to produce a result from 1–100, used in skill-based systems where abilities are measured as percentages.' },
51
128
  ]},
52
129
  ],
53
- faq: [
54
- {
55
- question: 'How can I simulate a roll with advantage (D&D)?',
56
- answer: 'Add two d20 dice to the bag by clicking the d20 button twice. When rolling, observe the two individual results and keep the higher one. The displayed total will be the sum, but you can see each die separately in the result breakdown.',
57
- },
58
- {
59
- question: 'What does the green or red color on results mean?',
60
- answer: 'Green results indicate that die rolled its maximum possible value (a "critical"). Red results indicate the minimum value (a "1", the worst possible result). This makes it easy to spot crits and fumbles at a glance.',
61
- },
62
- {
63
- question: 'Can I add multiple dice of the same type?',
64
- answer: 'Yes. Each click on a die adds it to the bag. If you click the d6 three times, the bag will show "3d6". To reduce the count, click the "−" button that appears next to each die group in the bag.',
65
- },
66
- {
67
- question: 'Are digital dice as random as physical ones?',
68
- answer: 'Statistically, yes. Modern JavaScript engines use pseudorandom algorithms (xorshift128+) with very high quality uniform distribution. A real physical die can have small manufacturing imperfections that bias results; the digital die does not have that problem.',
69
- },
70
- {
71
- question: 'What is the d100 and how is it used?',
72
- answer: 'The d100 (or d%) generates a number from 1 to 100 and is used in percentage-based game systems, such as Call of Cthulhu or Warhammer Fantasy Roleplay. It represents "direct probability": if your Stealth skill is 65%, you need to roll 65 or less to succeed.',
73
- },
74
- ],
130
+ faq,
75
131
  bibliography: [
76
132
  { name: 'D&D Beyond – Dice mechanics rules', url: 'https://www.dndbeyond.com/sources/basic-rules/using-ability-scores' },
77
133
  { name: 'Roll20 – Virtual tabletop and dice systems', url: 'https://roll20.net/' },
78
134
  { name: 'Pathfinder – d20 System Reference', url: 'https://paizo.com/pathfinder' },
79
135
  ],
80
- howTo: [
81
- { name: 'Build the dice pool', text: 'Click the die buttons (d4, d6, d8...) to add them to your pool. Each click adds one die of the selected type. You can mix different types in the same roll.' },
82
- { name: 'Adjust the modifier', text: 'Use the "+" and "−" buttons next to the modifier to apply bonuses or penalties (like the ability modifier in D&D). The modifier is automatically added to the total.' },
83
- { name: 'Roll the dice', text: 'Press the "Roll Dice" button. The right panel shows the final total and the breakdown of each individual die, with crits (maximum) in green and fumbles (minimum) in red.' },
84
- { name: 'Check the history', text: 'Each roll is recorded in the history with the dice expression used, the total result, and the exact time. You can clear the history with the corresponding button.' },
85
- ],
86
- schemas: []
136
+ howTo,
137
+ schemas: [faqSchema as any, howToSchema as any, appSchema],
87
138
  };
@@ -1,9 +1,77 @@
1
+ import type { WithContext, FAQPage, HowTo, SoftwareApplication } from 'schema-dts';
1
2
  import type { DiceRollerLocaleContent } from '../index';
2
3
 
4
+ const slug = 'lanzador-dados';
5
+ const title = 'Tirador de Dados';
6
+ const description = 'Simulador de dados virtual con bolsa personalizable, modificadores y historial de tiradas para tus juegos de rol y tablero.';
7
+
8
+ const faq: DiceRollerLocaleContent['faq'] = [
9
+ {
10
+ question: '¿Cómo puedo simular una tirada con ventaja (D&D)?',
11
+ answer: 'Añade dos dados d20 a la bolsa haciendo clic dos veces en el botón d20. Al lanzar, observa los dos resultados individuales y quédate con el mayor. El total mostrado será la suma, pero puedes ver cada dado por separado en el desglose de resultados.',
12
+ },
13
+ {
14
+ question: '¿Qué significa el color verde o rojo en los resultados?',
15
+ answer: 'Los resultados en verde indican que ese dado ha sacado su valor máximo posible (un "crítico"). Los resultados en rojo indican el valor mínimo (un "1", el peor resultado posible). Esto facilita identificar críticos y pifias de un vistazo.',
16
+ },
17
+ {
18
+ question: '¿Puedo añadir varios dados del mismo tipo?',
19
+ answer: 'Sí. Cada clic en un dado lo añade a la bolsa. Si haces clic tres veces en d6, la bolsa mostrará "3d6". Para reducir la cantidad, haz clic en el botón "−" que aparece junto a cada grupo de dados en la bolsa.',
20
+ },
21
+ {
22
+ question: '¿Los dados digitales son tan aleatorios como los físicos?',
23
+ answer: 'Estadísticamente, sí. Los motores JavaScript modernos usan algoritmos pseudoaleatorios (xorshift128+) con distribución uniforme de muy alta calidad. Un dado físico real puede tener pequeñas imperfecciones de fabricación que sesguen los resultados; el dado digital no tiene ese problema.',
24
+ },
25
+ {
26
+ question: '¿Qué es el d100 y cómo se usa?',
27
+ answer: 'El d100 (o d%) genera un número del 1 al 100 y se usa en sistemas de juego basados en porcentajes, como Call of Cthulhu o Warhammer Fantasy Roleplay. Representa "probabilidad directa": si tu habilidad de Sigilo es 65%, necesitas sacar 65 o menos para tener éxito.',
28
+ },
29
+ ];
30
+
31
+ const howTo: DiceRollerLocaleContent['howTo'] = [
32
+ { name: 'Construir la bolsa de dados', text: 'Haz clic en los botones de dado (d4, d6, d8...) para añadirlos a tu bolsa. Cada clic añade un dado del tipo seleccionado. Puedes mezclar tipos distintos en la misma tirada.' },
33
+ { name: 'Ajustar el modificador', text: 'Usa los botones "+" y "−" junto al modificador para aplicar bonificaciones o penalizaciones (como el modificador de habilidad en D&D). El modificador se suma automáticamente al total.' },
34
+ { name: 'Lanzar los dados', text: 'Pulsa el botón "Lanzar dados". El panel derecho muestra el total final y el desglose de cada dado individual, con los críticos (máximo) en verde y las pifias (mínimo) en rojo.' },
35
+ { name: 'Consultar el historial', text: 'Cada tirada queda registrada en el historial con la expresión de dados usada, el resultado total y la hora exacta. Puedes limpiar el historial con el botón correspondiente.' },
36
+ ];
37
+
38
+ const faqSchema: WithContext<FAQPage> = {
39
+ '@context': 'https://schema.org',
40
+ '@type': 'FAQPage',
41
+ mainEntity: faq.map((item) => ({
42
+ '@type': 'Question',
43
+ name: item.question,
44
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
45
+ })),
46
+ };
47
+
48
+ const howToSchema: WithContext<HowTo> = {
49
+ '@context': 'https://schema.org',
50
+ '@type': 'HowTo',
51
+ name: title,
52
+ description,
53
+ step: howTo.map((step) => ({
54
+ '@type': 'HowToStep',
55
+ name: step.name,
56
+ text: step.text,
57
+ })),
58
+ };
59
+
60
+ const appSchema: WithContext<SoftwareApplication> = {
61
+ '@context': 'https://schema.org',
62
+ '@type': 'SoftwareApplication',
63
+ name: title,
64
+ description,
65
+ applicationCategory: 'UtilitiesApplication',
66
+ operatingSystem: 'Web',
67
+ offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' },
68
+ inLanguage: 'es',
69
+ };
70
+
3
71
  export const content: DiceRollerLocaleContent = {
4
- slug: 'tirador-dados',
5
- title: 'Tirador de Dados',
6
- description: 'Simulador de dados virtual con bolsa personalizable, modificadores y historial de tiradas para tus juegos de rol y tablero.',
72
+ slug,
73
+ title,
74
+ description,
7
75
  faqTitle: 'Preguntas Frecuentes',
8
76
  bibliographyTitle: 'Bibliografía del Azar',
9
77
  ui: {
@@ -14,7 +82,16 @@ export const content: DiceRollerLocaleContent = {
14
82
  historyLabel: 'Historial',
15
83
  clearHistoryBtn: 'Limpiar Historial',
16
84
  faqTitle: 'FAQ',
17
- bibliographyTitle: 'Referencias'
85
+ bibliographyTitle: 'Referencias',
86
+ addDiceLabel: 'Añadir dados a la bolsa',
87
+ bagLabel: 'Bolsa de dados',
88
+ emptyBagBtn: 'Vaciar',
89
+ emptyBagText: 'Haz clic en los dados para añadirlos',
90
+ modifierLabel: 'Modificador',
91
+ rollManyLabel: 'Lanzar $COUNT dados',
92
+ rollOneLabel: 'Lanzar $COUNT dado',
93
+ preRollText: 'Añade dados y lanza',
94
+ emptyHistoryText: 'El historial de tiradas aparecerá aquí'
18
95
  },
19
96
  seo: [
20
97
  { type: 'title', text: 'El arte de la aleatoriedad: historia y matemáticas de los dados', level: 2 },
@@ -52,38 +129,12 @@ export const content: DiceRollerLocaleContent = {
52
129
  { term: 'Tirada percentil', definition: 'Tirada usando dos d10 para producir un resultado del 1 al 100, usada en sistemas de habilidades basados en porcentajes.' },
53
130
  ]},
54
131
  ],
55
- faq: [
56
- {
57
- question: '¿Cómo puedo simular una tirada con ventaja (D&D)?',
58
- answer: 'Añade dos dados d20 a la bolsa haciendo clic dos veces en el botón d20. Al lanzar, observa los dos resultados individuales y quédate con el mayor. El total mostrado será la suma, pero puedes ver cada dado por separado en el desglose de resultados.',
59
- },
60
- {
61
- question: '¿Qué significa el color verde o rojo en los resultados?',
62
- answer: 'Los resultados en verde indican que ese dado ha sacado su valor máximo posible (un "crítico"). Los resultados en rojo indican el valor mínimo (un "1", el peor resultado posible). Esto facilita identificar críticos y pifias de un vistazo.',
63
- },
64
- {
65
- question: '¿Puedo añadir varios dados del mismo tipo?',
66
- answer: 'Sí. Cada clic en un dado lo añade a la bolsa. Si haces clic tres veces en d6, la bolsa mostrará "3d6". Para reducir la cantidad, haz clic en el botón "−" que aparece junto a cada grupo de dados en la bolsa.',
67
- },
68
- {
69
- question: '¿Los dados digitales son tan aleatorios como los físicos?',
70
- answer: 'Estadísticamente, sí. Los motores JavaScript modernos usan algoritmos pseudoaleatorios (xorshift128+) con distribución uniforme de muy alta calidad. Un dado físico real puede tener pequeñas imperfecciones de fabricación que sesguen los resultados; el dado digital no tiene ese problema.',
71
- },
72
- {
73
- question: '¿Qué es el d100 y cómo se usa?',
74
- answer: 'El d100 (o d%) genera un número del 1 al 100 y se usa en sistemas de juego basados en porcentajes, como Call of Cthulhu o Warhammer Fantasy Roleplay. Representa "probabilidad directa": si tu habilidad de Sigilo es 65%, necesitas sacar 65 o menos para tener éxito.',
75
- },
76
- ],
132
+ faq,
77
133
  bibliography: [
78
134
  { name: 'D&D Beyond – Reglas de mecánicas de dados', url: 'https://www.dndbeyond.com/sources/basic-rules/using-ability-scores' },
79
135
  { name: 'Roll20 – Virtual tabletop y sistemas de dados', url: 'https://roll20.net/' },
80
136
  { name: 'Pathfinder – Sistema d20 de referencia', url: 'https://paizo.com/pathfinder' },
81
137
  ],
82
- howTo: [
83
- { name: 'Construir la bolsa de dados', text: 'Haz clic en los botones de dado (d4, d6, d8...) para añadirlos a tu bolsa. Cada clic añade un dado del tipo seleccionado. Puedes mezclar tipos distintos en la misma tirada.' },
84
- { name: 'Ajustar el modificador', text: 'Usa los botones "+" y "−" junto al modificador para aplicar bonificaciones o penalizaciones (como el modificador de habilidad en D&D). El modificador se suma automáticamente al total.' },
85
- { name: 'Lanzar los dados', text: 'Pulsa el botón "Lanzar dados". El panel derecho muestra el total final y el desglose de cada dado individual, con los críticos (máximo) en verde y las pifias (mínimo) en rojo.' },
86
- { name: 'Consultar el historial', text: 'Cada tirada queda registrada en el historial con la expresión de dados usada, el resultado total y la hora exacta. Puedes limpiar el historial con el botón correspondiente.' },
87
- ],
88
- schemas: []
138
+ howTo,
139
+ schemas: [faqSchema as any, howToSchema as any, appSchema],
89
140
  };