@jjlmoya/utils-tools 1.1.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 (134) hide show
  1. package/package.json +63 -0
  2. package/src/category/i18n/en.ts +172 -0
  3. package/src/category/i18n/es.ts +172 -0
  4. package/src/category/i18n/fr.ts +172 -0
  5. package/src/category/index.ts +23 -0
  6. package/src/category/seo.astro +15 -0
  7. package/src/components/PreviewNavSidebar.astro +116 -0
  8. package/src/components/PreviewToolbar.astro +143 -0
  9. package/src/data.ts +11 -0
  10. package/src/env.d.ts +5 -0
  11. package/src/index.ts +90 -0
  12. package/src/layouts/PreviewLayout.astro +117 -0
  13. package/src/pages/[locale]/[slug].astro +146 -0
  14. package/src/pages/[locale].astro +251 -0
  15. package/src/pages/index.astro +4 -0
  16. package/src/tests/faq_count.test.ts +19 -0
  17. package/src/tests/locale_completeness.test.ts +42 -0
  18. package/src/tests/mocks/astro_mock.js +2 -0
  19. package/src/tests/no_h1_in_components.test.ts +48 -0
  20. package/src/tests/schemas_fulfillment.test.ts +23 -0
  21. package/src/tests/seo_length.test.ts +23 -0
  22. package/src/tests/title_quality.test.ts +56 -0
  23. package/src/tests/tool_validation.test.ts +17 -0
  24. package/src/tool/date-diff-calculator/bibliography.astro +14 -0
  25. package/src/tool/date-diff-calculator/component.astro +370 -0
  26. package/src/tool/date-diff-calculator/i18n/en.ts +132 -0
  27. package/src/tool/date-diff-calculator/i18n/es.ts +132 -0
  28. package/src/tool/date-diff-calculator/i18n/fr.ts +132 -0
  29. package/src/tool/date-diff-calculator/index.ts +22 -0
  30. package/src/tool/date-diff-calculator/seo.astro +14 -0
  31. package/src/tool/date-diff-calculator/ui.ts +17 -0
  32. package/src/tool/drive-direct-link/bibliography.astro +14 -0
  33. package/src/tool/drive-direct-link/component.astro +280 -0
  34. package/src/tool/drive-direct-link/i18n/en.ts +118 -0
  35. package/src/tool/drive-direct-link/i18n/es.ts +118 -0
  36. package/src/tool/drive-direct-link/i18n/fr.ts +118 -0
  37. package/src/tool/drive-direct-link/index.ts +22 -0
  38. package/src/tool/drive-direct-link/seo.astro +14 -0
  39. package/src/tool/drive-direct-link/ui.ts +10 -0
  40. package/src/tool/email-list-cleaner/bibliography.astro +14 -0
  41. package/src/tool/email-list-cleaner/component.astro +375 -0
  42. package/src/tool/email-list-cleaner/i18n/en.ts +140 -0
  43. package/src/tool/email-list-cleaner/i18n/es.ts +140 -0
  44. package/src/tool/email-list-cleaner/i18n/fr.ts +140 -0
  45. package/src/tool/email-list-cleaner/index.ts +22 -0
  46. package/src/tool/email-list-cleaner/seo.astro +14 -0
  47. package/src/tool/email-list-cleaner/ui.ts +15 -0
  48. package/src/tool/env-badge-spain/bibliography.astro +14 -0
  49. package/src/tool/env-badge-spain/component.astro +303 -0
  50. package/src/tool/env-badge-spain/components/BadgeForm.astro +243 -0
  51. package/src/tool/env-badge-spain/components/BadgeResult.astro +151 -0
  52. package/src/tool/env-badge-spain/i18n/en.ts +153 -0
  53. package/src/tool/env-badge-spain/i18n/es.ts +153 -0
  54. package/src/tool/env-badge-spain/i18n/fr.ts +153 -0
  55. package/src/tool/env-badge-spain/index.ts +22 -0
  56. package/src/tool/env-badge-spain/seo.astro +14 -0
  57. package/src/tool/env-badge-spain/ui.ts +53 -0
  58. package/src/tool/morse-beacon/bibliography.astro +14 -0
  59. package/src/tool/morse-beacon/component.astro +534 -0
  60. package/src/tool/morse-beacon/i18n/en.ts +157 -0
  61. package/src/tool/morse-beacon/i18n/es.ts +157 -0
  62. package/src/tool/morse-beacon/i18n/fr.ts +157 -0
  63. package/src/tool/morse-beacon/index.ts +22 -0
  64. package/src/tool/morse-beacon/logic/MorseEngine.ts +124 -0
  65. package/src/tool/morse-beacon/seo.astro +14 -0
  66. package/src/tool/morse-beacon/ui.ts +18 -0
  67. package/src/tool/password-generator/bibliography.astro +14 -0
  68. package/src/tool/password-generator/component.astro +259 -0
  69. package/src/tool/password-generator/components/Config.astro +227 -0
  70. package/src/tool/password-generator/components/Display.astro +147 -0
  71. package/src/tool/password-generator/components/Strength.astro +70 -0
  72. package/src/tool/password-generator/i18n/en.ts +166 -0
  73. package/src/tool/password-generator/i18n/es.ts +166 -0
  74. package/src/tool/password-generator/i18n/fr.ts +166 -0
  75. package/src/tool/password-generator/index.ts +22 -0
  76. package/src/tool/password-generator/seo.astro +14 -0
  77. package/src/tool/password-generator/ui.ts +16 -0
  78. package/src/tool/routes/bibliography.astro +14 -0
  79. package/src/tool/routes/component.astro +543 -0
  80. package/src/tool/routes/i18n/en.ts +157 -0
  81. package/src/tool/routes/i18n/es.ts +157 -0
  82. package/src/tool/routes/i18n/fr.ts +157 -0
  83. package/src/tool/routes/index.ts +22 -0
  84. package/src/tool/routes/logic/GeocodingService.ts +60 -0
  85. package/src/tool/routes/logic/RouteManager.ts +192 -0
  86. package/src/tool/routes/logic/RouteService.ts +66 -0
  87. package/src/tool/routes/seo.astro +14 -0
  88. package/src/tool/routes/ui.ts +16 -0
  89. package/src/tool/rule-of-three/bibliography.astro +14 -0
  90. package/src/tool/rule-of-three/component.astro +369 -0
  91. package/src/tool/rule-of-three/i18n/en.ts +171 -0
  92. package/src/tool/rule-of-three/i18n/es.ts +171 -0
  93. package/src/tool/rule-of-three/i18n/fr.ts +171 -0
  94. package/src/tool/rule-of-three/index.ts +22 -0
  95. package/src/tool/rule-of-three/seo.astro +14 -0
  96. package/src/tool/rule-of-three/ui.ts +13 -0
  97. package/src/tool/seo-content-optimizer/bibliography.astro +14 -0
  98. package/src/tool/seo-content-optimizer/component.astro +552 -0
  99. package/src/tool/seo-content-optimizer/i18n/en.ts +136 -0
  100. package/src/tool/seo-content-optimizer/i18n/es.ts +136 -0
  101. package/src/tool/seo-content-optimizer/i18n/fr.ts +136 -0
  102. package/src/tool/seo-content-optimizer/index.ts +22 -0
  103. package/src/tool/seo-content-optimizer/seo.astro +14 -0
  104. package/src/tool/seo-content-optimizer/ui.ts +29 -0
  105. package/src/tool/speed-reader/bibliography.astro +14 -0
  106. package/src/tool/speed-reader/component.astro +586 -0
  107. package/src/tool/speed-reader/i18n/en.ts +152 -0
  108. package/src/tool/speed-reader/i18n/es.ts +152 -0
  109. package/src/tool/speed-reader/i18n/fr.ts +152 -0
  110. package/src/tool/speed-reader/index.ts +22 -0
  111. package/src/tool/speed-reader/logic/RSVPEngine.ts +106 -0
  112. package/src/tool/speed-reader/seo.astro +14 -0
  113. package/src/tool/speed-reader/ui.ts +14 -0
  114. package/src/tool/text-pixel-calculator/bibliography.astro +14 -0
  115. package/src/tool/text-pixel-calculator/component.astro +315 -0
  116. package/src/tool/text-pixel-calculator/components/Editor.astro +240 -0
  117. package/src/tool/text-pixel-calculator/components/Preview.astro +155 -0
  118. package/src/tool/text-pixel-calculator/components/Stats.astro +87 -0
  119. package/src/tool/text-pixel-calculator/i18n/en.ts +133 -0
  120. package/src/tool/text-pixel-calculator/i18n/es.ts +133 -0
  121. package/src/tool/text-pixel-calculator/i18n/fr.ts +133 -0
  122. package/src/tool/text-pixel-calculator/index.ts +22 -0
  123. package/src/tool/text-pixel-calculator/seo.astro +14 -0
  124. package/src/tool/text-pixel-calculator/ui.ts +15 -0
  125. package/src/tool/whatsapp-link/bibliography.astro +14 -0
  126. package/src/tool/whatsapp-link/component.astro +455 -0
  127. package/src/tool/whatsapp-link/i18n/en.ts +128 -0
  128. package/src/tool/whatsapp-link/i18n/es.ts +128 -0
  129. package/src/tool/whatsapp-link/i18n/fr.ts +128 -0
  130. package/src/tool/whatsapp-link/index.ts +22 -0
  131. package/src/tool/whatsapp-link/seo.astro +14 -0
  132. package/src/tool/whatsapp-link/ui.ts +15 -0
  133. package/src/tools.ts +15 -0
  134. package/src/types.ts +72 -0
@@ -0,0 +1,152 @@
1
+ import type { ToolLocaleContent } from '../../../types';
2
+ import type { WithContext, FAQPage, HowTo, SoftwareApplication } from 'schema-dts';
3
+ import type { SpeedReaderUI } from '../ui';
4
+
5
+ const faqData = [
6
+ {
7
+ question: 'What is RSVP technology?',
8
+ answer: 'RSVP stands for Rapid Serial Visual Presentation. Words appear one at a time at the same focal point, eliminating the need to move your eyes left to right. This allows reading at much higher speeds without sacrificing comprehension when practiced.',
9
+ },
10
+ {
11
+ question: 'Does reading faster reduce comprehension?',
12
+ answer: 'It depends on training. At moderate speeds (350-500 WPM), many users report higher concentration by eliminating subvocalization. At extreme speeds (800+ WPM), retention may decrease without prior practice.',
13
+ },
14
+ {
15
+ question: 'What is the average reading speed?',
16
+ answer: 'The average adult reads between 200 and 250 words per minute. With the RSVP reader and some practice, doubling that speed (400-500 WPM) while maintaining excellent comprehension is common.',
17
+ },
18
+ {
19
+ question: 'Does RSVP cause eye strain?',
20
+ answer: 'By eliminating the muscular effort of moving your eyes, many users find they can read with less fatigue than traditional methods. It may feel intense at first, but the brain adapts quickly.',
21
+ },
22
+ ];
23
+
24
+ const howToData = [
25
+ { name: 'Enter your text', text: 'Paste the article, book, or document you want to read into the text area.' },
26
+ { name: 'Configure WPM', text: 'Adjust the Words Per Minute. If you are a beginner, start at 300 WPM and increase gradually.' },
27
+ { name: 'Fix your gaze', text: 'Keep your eyes on the red letter (ORP focal point). Do not try to follow the words with eye movement.' },
28
+ { name: 'Start training', text: 'Press the play button and let the information flow. You can pause at any time.' },
29
+ ];
30
+
31
+ const faqSchema: WithContext<FAQPage> = {
32
+ '@context': 'https://schema.org',
33
+ '@type': 'FAQPage',
34
+ mainEntity: faqData.map((item) => ({
35
+ '@type': 'Question',
36
+ name: item.question,
37
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
38
+ })),
39
+ };
40
+
41
+ const howToSchema: WithContext<HowTo> = {
42
+ '@context': 'https://schema.org',
43
+ '@type': 'HowTo',
44
+ name: 'How to use the RSVP speed reader',
45
+ step: howToData.map((s) => ({ '@type': 'HowToStep', name: s.name, text: s.text })),
46
+ };
47
+
48
+ const appSchema: WithContext<SoftwareApplication> = {
49
+ '@context': 'https://schema.org',
50
+ '@type': 'SoftwareApplication',
51
+ name: 'RSVP Speed Reader',
52
+ applicationCategory: 'UtilitiesApplication',
53
+ operatingSystem: 'Web',
54
+ offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' },
55
+ description: 'Train your reading speed up to 1000 words per minute with RSVP technology and optimal recognition point alignment.',
56
+ };
57
+
58
+ const ui: SpeedReaderUI = {
59
+ progressLabel: 'Reading progress',
60
+ speedLabel: 'Speed',
61
+ slowLabel: 'SLOW',
62
+ fastLabel: 'GOD',
63
+ speedHint: 'Start at 300 WPM and increase gradually to push your limits.',
64
+ textLabel: 'Text to process',
65
+ textPlaceholder: 'Paste your article, book or text here...',
66
+ clearLabel: 'CLEAR',
67
+ words: 'words',
68
+ defaultText: 'Welcome to the RSVP Speed Reader. Paste your text below to begin. This technology will help you read up to three times faster by eliminating unnecessary eye movements.',
69
+ play: 'Play',
70
+ pause: 'Pause',
71
+ };
72
+
73
+ export const content: ToolLocaleContent<SpeedReaderUI> = {
74
+ slug: 'speed-reader',
75
+ title: 'RSVP Speed Reader',
76
+ description: 'Train your reading speed up to 1000 words per minute. RSVP technology with optimal focal point alignment. Double your intellectual productivity.',
77
+ ui,
78
+ faqTitle: 'Frequently Asked Questions',
79
+ faq: faqData,
80
+ howTo: howToData,
81
+ bibliographyTitle: 'References',
82
+ bibliography: [
83
+ { name: 'Rayner, K., et al. (2016). So much to read, so little time. Psychological Science in the Public Interest.', url: 'https://journals.sagepub.com/doi/full/10.1177/1529100615623267' },
84
+ { name: 'Forster, K. I. (1970). Visual perception of rapidly presented word sequences. Perception & Psychophysics.', url: 'https://link.springer.com/article/10.3758/BF03212522' },
85
+ { name: 'Öquist, G., & Goldstein, M. (2003). Towards an improved readability on mobile devices. Mobile HCI.', url: 'https://www.researchgate.net/publication/221063852_Towards_an_improved_readability_on_mobile_devices' },
86
+ { name: 'Juola, J. F., et al. (1982). Visual search and reading of rapid serial visual presentations. Perception & Psychophysics.', url: 'https://link.springer.com/article/10.3758/BF03202598' },
87
+ { name: 'Masson, M. E. J. (1983). Conceptual processing of text during rapid serial visual presentation. Journal of Educational Psychology.', url: 'https://psycnet.apa.org/record/1984-08638-001' },
88
+ { name: 'Saldana, D., & Greene, R. (2022). Reading effectiveness with RSVP apps. Reading Psychology.', url: 'https://www.tandfonline.com/doi/abs/10.1080/02702711.2022.2030000' },
89
+ ],
90
+ schemas: [faqSchema, howToSchema, appSchema],
91
+ seo: [
92
+ { type: 'title', level: 2, text: 'The Formula 1 of Reading: Unlock Your Mental Bandwidth' },
93
+ {
94
+ type: 'paragraph',
95
+ html: 'What if reading were, biomechanically, a waste of time? Your brain is a supercomputer throttled by an analogue connection: your eyes. The <strong>RSVP Reader</strong> breaks that bottleneck by presenting words at the exact focal point where your mind processes them fastest.',
96
+ },
97
+ {
98
+ type: 'paragraph',
99
+ html: 'Traditional reading is an inefficient process. Your eyes do not work like a scanner; they work like a burst-mode camera: stop, focus, jump. This jump, called a <strong>saccade</strong>, means you spend a large portion of reading time simply moving your eyes rather than absorbing information.',
100
+ },
101
+ {
102
+ type: 'tip',
103
+ html: '"RSVP reading is not just reading faster. It is eliminating the mechanical friction between text and your brain."',
104
+ },
105
+ { type: 'title', level: 3, text: 'The Science Behind Data Injection' },
106
+ {
107
+ type: 'comparative',
108
+ columns: 3,
109
+ items: [
110
+ {
111
+ icon: 'mdi:bullseye-arrow',
112
+ title: 'Optimal Recognition Point (ORP)',
113
+ description: 'Every word has a point where your brain recognises it fastest. The algorithm calculates that exact letter (the red one) and centres it perfectly. Your eyes do not move a single millimetre.',
114
+ },
115
+ {
116
+ icon: 'mdi:speedometer-slow',
117
+ title: 'Cognitive Silence',
118
+ highlight: true,
119
+ description: 'Above 400-500 WPM, your inner voice goes quiet — it cannot keep up. You stop "hearing" what you read and start "seeing" pure meanings and concepts. This is the ultimate flow state.',
120
+ },
121
+ {
122
+ icon: 'mdi:brain',
123
+ title: 'Visual Neuroplasticity',
124
+ description: 'Like going to the gym: 300 WPM will feel fast at first. After a week, 500 WPM will feel like a walk. You are re-training the neural pathways connecting your visual cortex to language processing.',
125
+ },
126
+ ],
127
+ },
128
+ { type: 'title', level: 3, text: 'Training Protocol: From Beginner to Neo' },
129
+ {
130
+ type: 'comparative',
131
+ columns: 3,
132
+ items: [
133
+ {
134
+ title: 'Level 1: The Awakening (200 to 300 WPM)',
135
+ description: 'Your normal reading speed. Get used to the interface. Relax your face and let the words come to you. Do not try to "grab" them.',
136
+ points: ['Ideal for beginners', 'ORP familiarisation', 'No eye strain'],
137
+ },
138
+ {
139
+ title: 'Level 2: Sound Barrier (400 to 500 WPM)',
140
+ highlight: true,
141
+ description: 'This is where the magic happens. You will feel discomfort. Do not slow down when you miss a word — your brain will learn to fill in gaps from context.',
142
+ points: ['Subvocalisation disappears', 'Mental flow state', 'Double your base speed'],
143
+ },
144
+ {
145
+ title: 'Level 3: Escape Velocity (600+ WPM)',
146
+ description: 'Advanced territory. Ideal for reviewing study material, reading news, or consuming technical documentation where you seek key concepts.',
147
+ points: ['Average novel in 2 hours', 'Maximum reading efficiency', 'Requires prior practice'],
148
+ },
149
+ ],
150
+ },
151
+ ],
152
+ };
@@ -0,0 +1,152 @@
1
+ import type { ToolLocaleContent } from '../../../types';
2
+ import type { WithContext, FAQPage, HowTo, SoftwareApplication } from 'schema-dts';
3
+ import type { SpeedReaderUI } from '../ui';
4
+
5
+ const faqData = [
6
+ {
7
+ question: '¿Qué es la tecnología RSVP?',
8
+ answer: 'RSVP significa Rapid Serial Visual Presentation. Es un método donde las palabras aparecen una tras otra en el mismo punto focal, eliminando la necesidad de mover los ojos de izquierda a derecha, lo que permite leer a velocidades mucho mayores.',
9
+ },
10
+ {
11
+ question: '¿Se pierde comprensión al leer tan rápido?',
12
+ answer: 'Depende del entrenamiento. A velocidades moderadas (350-500 PPM), muchos usuarios reportan mayor concentración al eliminar la subvocalización. A velocidades extremas (800+ PPM), la retención puede disminuir sin práctica previa.',
13
+ },
14
+ {
15
+ question: '¿Cuál es la velocidad de lectura normal?',
16
+ answer: 'Un adulto promedio lee entre 200 y 250 palabras por minuto. Con el lector RSVP y práctica, es común doblar esa velocidad (400-500 PPM) manteniendo una excelente comprensión.',
17
+ },
18
+ {
19
+ question: '¿Produce fatiga visual el método RSVP?',
20
+ answer: 'Al eliminar el esfuerzo muscular de mover los ojos, muchos usuarios encuentran que pueden leer con menos fatiga que el método tradicional. Al principio puede ser intenso, pero el cerebro se adapta rápidamente.',
21
+ },
22
+ ];
23
+
24
+ const howToData = [
25
+ { name: 'Introducir el texto', text: 'Pega el artículo, libro o documento que quieras leer en el área de texto.' },
26
+ { name: 'Configurar las PPM', text: 'Ajusta las Palabras Por Minuto. Si eres principiante, empieza en 300 PPM y sube gradualmente.' },
27
+ { name: 'Fijar la mirada', text: 'Mantén los ojos centrados en la letra roja (punto focal ORP). No intentes seguir las palabras con movimiento ocular.' },
28
+ { name: 'Iniciar el entrenamiento', text: 'Pulsa el botón de reproducir y deja que la información fluya. Puedes pausar en cualquier momento.' },
29
+ ];
30
+
31
+ const faqSchema: WithContext<FAQPage> = {
32
+ '@context': 'https://schema.org',
33
+ '@type': 'FAQPage',
34
+ mainEntity: faqData.map((item) => ({
35
+ '@type': 'Question',
36
+ name: item.question,
37
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
38
+ })),
39
+ };
40
+
41
+ const howToSchema: WithContext<HowTo> = {
42
+ '@context': 'https://schema.org',
43
+ '@type': 'HowTo',
44
+ name: 'Cómo usar el lector rápido RSVP',
45
+ step: howToData.map((s) => ({ '@type': 'HowToStep', name: s.name, text: s.text })),
46
+ };
47
+
48
+ const appSchema: WithContext<SoftwareApplication> = {
49
+ '@context': 'https://schema.org',
50
+ '@type': 'SoftwareApplication',
51
+ name: 'Lector Rápido RSVP',
52
+ applicationCategory: 'UtilitiesApplication',
53
+ operatingSystem: 'Web',
54
+ offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' },
55
+ description: 'Entrena tu velocidad de lectura hasta 1000 palabras por minuto con tecnología RSVP y alineación de punto focal óptimo.',
56
+ };
57
+
58
+ const ui: SpeedReaderUI = {
59
+ progressLabel: 'Progreso lectura',
60
+ speedLabel: 'Velocidad',
61
+ slowLabel: 'LENTO',
62
+ fastLabel: 'DIOS',
63
+ speedHint: 'Empieza en 300 PPM y sube gradualmente hasta romper tus límites.',
64
+ textLabel: 'Texto a procesar',
65
+ textPlaceholder: 'Pega aquí tu artículo, libro o texto...',
66
+ clearLabel: 'BORRAR',
67
+ words: 'palabras',
68
+ defaultText: 'Bienvenido al Lector Rápido RSVP. Pega tu texto abajo para comenzar. Esta tecnología te ayudará a leer hasta tres veces más rápido eliminando los movimientos oculares innecesarios.',
69
+ play: 'Reproducir',
70
+ pause: 'Pausar',
71
+ };
72
+
73
+ export const content: ToolLocaleContent<SpeedReaderUI> = {
74
+ slug: 'lectura-rapida',
75
+ title: 'RSVP Lector Rápido',
76
+ description: 'Entrena tu velocidad de lectura hasta 1000 palabras por minuto. Tecnología RSVP con alineación de punto focal óptimo. Dobla tu productividad intelectual.',
77
+ ui,
78
+ faqTitle: 'Preguntas Frecuentes',
79
+ faq: faqData,
80
+ howTo: howToData,
81
+ bibliographyTitle: 'Referencias',
82
+ bibliography: [
83
+ { name: 'Rayner, K., et al. (2016). So much to read, so little time. Psychological Science in the Public Interest.', url: 'https://journals.sagepub.com/doi/full/10.1177/1529100615623267' },
84
+ { name: 'Forster, K. I. (1970). Visual perception of rapidly presented word sequences. Perception & Psychophysics.', url: 'https://link.springer.com/article/10.3758/BF03212522' },
85
+ { name: 'Öquist, G., & Goldstein, M. (2003). Towards an improved readability on mobile devices. Mobile HCI.', url: 'https://www.researchgate.net/publication/221063852_Towards_an_improved_readability_on_mobile_devices' },
86
+ { name: 'Juola, J. F., et al. (1982). Visual search and reading of rapid serial visual presentations. Perception & Psychophysics.', url: 'https://link.springer.com/article/10.3758/BF03202598' },
87
+ { name: 'Masson, M. E. J. (1983). Conceptual processing of text during rapid serial visual presentation. Journal of Educational Psychology.', url: 'https://psycnet.apa.org/record/1984-08638-001' },
88
+ { name: 'Saldana, D., & Greene, R. (2022). Reading effectiveness with RSVP apps. Reading Psychology.', url: 'https://www.tandfonline.com/doi/abs/10.1080/02702711.2022.2030000' },
89
+ ],
90
+ schemas: [faqSchema, howToSchema, appSchema],
91
+ seo: [
92
+ { type: 'title', level: 2, text: 'La Fórmula 1 de la Lectura: Desbloquea tu Ancho de Banda Mental' },
93
+ {
94
+ type: 'paragraph',
95
+ html: '¿Y si leer fuera, biomecánicamente, una pérdida de tiempo? Tu cerebro es un superordenador frenado por una conexión analógica: tus ojos. El <strong>Lector RSVP</strong> rompe ese cuello de botella presentando las palabras en el punto focal exacto donde tu mente las procesa más rápido.',
96
+ },
97
+ {
98
+ type: 'paragraph',
99
+ html: 'La lectura tradicional es un proceso ineficiente. Tus ojos no funcionan como un escáner; funcionan como una cámara en ráfaga: se detienen, enfocan y saltan. Este salto, llamado <strong>sacada</strong>, te hace pasar gran parte del tiempo moviendo los ojos en lugar de absorber información.',
100
+ },
101
+ {
102
+ type: 'tip',
103
+ html: '"La lectura RSVP no es solo leer más rápido. Es eliminar la fricción mecánica entre el texto y tu cerebro."',
104
+ },
105
+ { type: 'title', level: 3, text: 'La Ciencia detrás de la Inyección de Datos' },
106
+ {
107
+ type: 'comparative',
108
+ columns: 3,
109
+ items: [
110
+ {
111
+ icon: 'mdi:bullseye-arrow',
112
+ title: 'Punto de Reconocimiento Óptimo (ORP)',
113
+ description: 'Cada palabra tiene un punto donde tu cerebro la reconoce más rápido. El algoritmo calcula esa letra exacta (la roja) y la alinea en el centro. Tus ojos no se mueven ni un milímetro.',
114
+ },
115
+ {
116
+ icon: 'mdi:speedometer-slow',
117
+ title: 'Silencio Cognitivo',
118
+ highlight: true,
119
+ description: 'Al superar las 400-500 PPM, tu voz interior se calla. No puede seguir el ritmo. Dejas de "oír" lo que lees y empiezas a "ver" significados e ideas puras. Es el estado de flujo definitivo.',
120
+ },
121
+ {
122
+ icon: 'mdi:brain',
123
+ title: 'Neuroplasticidad Visual',
124
+ description: 'Como ir al gimnasio: al principio, 300 PPM parecerá rápido. En una semana, 500 parecerá un paseo. Estás re-entrenando las vías neuronales que conectan el córtex visual con el lenguaje.',
125
+ },
126
+ ],
127
+ },
128
+ { type: 'title', level: 3, text: 'Protocolo de Entrenamiento: De Novato a Neo' },
129
+ {
130
+ type: 'comparative',
131
+ columns: 3,
132
+ items: [
133
+ {
134
+ title: 'Nivel 1: El Despertar (200 a 300 PPM)',
135
+ description: 'Tu velocidad normal. Acostúmbrate a la interfaz. Relaja la cara y deja que las palabras vengan a ti. No intentes "agarrarlas".',
136
+ points: ['Ideal para principiantes', 'Familiarización con ORP', 'Sin fatiga visual'],
137
+ },
138
+ {
139
+ title: 'Nivel 2: La Barrera del Sonido (400 a 500 PPM)',
140
+ highlight: true,
141
+ description: 'Aquí ocurre la magia. Sentirás incomodidad. No bajes la velocidad si pierdes una palabra. Tu cerebro aprenderá a rellenar huecos por contexto.',
142
+ points: ['La subvocalización desaparece', 'Estado de flujo mental', 'Dobla tu velocidad base'],
143
+ },
144
+ {
145
+ title: 'Nivel 3: Velocidad de Escape (600+ PPM)',
146
+ description: 'Territorio avanzado. Ideal para repasar temarios, leer noticias o consumir documentación técnica donde buscas conceptos clave.',
147
+ points: ['Novela promedio en 2 horas', 'Máxima eficiencia lectora', 'Requiere práctica previa'],
148
+ },
149
+ ],
150
+ },
151
+ ],
152
+ };
@@ -0,0 +1,152 @@
1
+ import type { ToolLocaleContent } from '../../../types';
2
+ import type { WithContext, FAQPage, HowTo, SoftwareApplication } from 'schema-dts';
3
+ import type { SpeedReaderUI } from '../ui';
4
+
5
+ const faqData = [
6
+ {
7
+ question: 'Qu\'est-ce que la technologie RSVP ?',
8
+ answer: 'RSVP signifie Rapid Serial Visual Presentation. Les mots apparaissent l\'un après l\'autre au même point focal, éliminant le besoin de déplacer les yeux de gauche à droite. Cela permet de lire à des vitesses bien supérieures avec de l\'entraînement.',
9
+ },
10
+ {
11
+ question: 'Perd-on en compréhension en lisant plus vite ?',
12
+ answer: 'Cela dépend de l\'entraînement. À des vitesses modérées (350-500 MPM), beaucoup d\'utilisateurs rapportent une meilleure concentration en éliminant la subvocalisation. À des vitesses extrêmes (800+ MPM), la rétention peut diminuer sans pratique préalable.',
13
+ },
14
+ {
15
+ question: 'Quelle est la vitesse de lecture normale ?',
16
+ answer: 'Un adulte moyen lit entre 200 et 250 mots par minute. Avec le lecteur RSVP et un peu de pratique, il est courant de doubler cette vitesse (400-500 MPM) en maintenant une excellente compréhension.',
17
+ },
18
+ {
19
+ question: 'La méthode RSVP fatigue-t-elle les yeux ?',
20
+ answer: 'En éliminant l\'effort musculaire de déplacer les yeux, de nombreux utilisateurs trouvent qu\'ils peuvent lire avec moins de fatigue qu\'avec les méthodes traditionnelles. Cela peut sembler intense au début, mais le cerveau s\'adapte rapidement.',
21
+ },
22
+ ];
23
+
24
+ const howToData = [
25
+ { name: 'Saisir le texte', text: 'Collez l\'article, le livre ou le document que vous souhaitez lire dans la zone de texte.' },
26
+ { name: 'Configurer les MPM', text: 'Ajustez les Mots Par Minute. Si vous débutez, commencez à 300 MPM et augmentez progressivement.' },
27
+ { name: 'Fixer le regard', text: 'Gardez les yeux sur la lettre rouge (point focal ORP). N\'essayez pas de suivre les mots avec des mouvements oculaires.' },
28
+ { name: 'Commencer l\'entraînement', text: 'Appuyez sur le bouton lecture et laissez l\'information s\'écouler. Vous pouvez faire une pause à tout moment.' },
29
+ ];
30
+
31
+ const faqSchema: WithContext<FAQPage> = {
32
+ '@context': 'https://schema.org',
33
+ '@type': 'FAQPage',
34
+ mainEntity: faqData.map((item) => ({
35
+ '@type': 'Question',
36
+ name: item.question,
37
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
38
+ })),
39
+ };
40
+
41
+ const howToSchema: WithContext<HowTo> = {
42
+ '@context': 'https://schema.org',
43
+ '@type': 'HowTo',
44
+ name: 'Comment utiliser le lecteur rapide RSVP',
45
+ step: howToData.map((s) => ({ '@type': 'HowToStep', name: s.name, text: s.text })),
46
+ };
47
+
48
+ const appSchema: WithContext<SoftwareApplication> = {
49
+ '@context': 'https://schema.org',
50
+ '@type': 'SoftwareApplication',
51
+ name: 'Lecteur Rapide RSVP',
52
+ applicationCategory: 'UtilitiesApplication',
53
+ operatingSystem: 'Web',
54
+ offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' },
55
+ description: 'Entraînez votre vitesse de lecture jusqu\'à 1000 mots par minute grâce à la technologie RSVP et l\'alignement du point de reconnaissance optimal.',
56
+ };
57
+
58
+ const ui: SpeedReaderUI = {
59
+ progressLabel: 'Progression lecture',
60
+ speedLabel: 'Vitesse',
61
+ slowLabel: 'LENT',
62
+ fastLabel: 'DIEU',
63
+ speedHint: 'Commencez à 300 MPM et augmentez progressivement pour repousser vos limites.',
64
+ textLabel: 'Texte à traiter',
65
+ textPlaceholder: 'Collez ici votre article, livre ou texte...',
66
+ clearLabel: 'EFFACER',
67
+ words: 'mots',
68
+ defaultText: 'Bienvenue dans le Lecteur Rapide RSVP. Collez votre texte ci-dessous pour commencer. Cette technologie vous aidera à lire jusqu\'à trois fois plus vite en éliminant les mouvements oculaires inutiles.',
69
+ play: 'Lecture',
70
+ pause: 'Pause',
71
+ };
72
+
73
+ export const content: ToolLocaleContent<SpeedReaderUI> = {
74
+ slug: 'lecteur-rapide',
75
+ title: 'RSVP Lecteur Rapide',
76
+ description: "Entraînez votre vitesse de lecture jusqu'à 1000 mots par minute. Technologie RSVP avec alignement du point focal optimal. Doublez votre productivité intellectuelle.",
77
+ ui,
78
+ faqTitle: 'Questions Fréquentes',
79
+ faq: faqData,
80
+ howTo: howToData,
81
+ bibliographyTitle: 'Références',
82
+ bibliography: [
83
+ { name: 'Rayner, K., et al. (2016). So much to read, so little time. Psychological Science in the Public Interest.', url: 'https://journals.sagepub.com/doi/full/10.1177/1529100615623267' },
84
+ { name: 'Forster, K. I. (1970). Visual perception of rapidly presented word sequences. Perception & Psychophysics.', url: 'https://link.springer.com/article/10.3758/BF03212522' },
85
+ { name: 'Öquist, G., & Goldstein, M. (2003). Towards an improved readability on mobile devices. Mobile HCI.', url: 'https://www.researchgate.net/publication/221063852_Towards_an_improved_readability_on_mobile_devices' },
86
+ { name: 'Juola, J. F., et al. (1982). Visual search and reading of rapid serial visual presentations. Perception & Psychophysics.', url: 'https://link.springer.com/article/10.3758/BF03202598' },
87
+ { name: 'Masson, M. E. J. (1983). Conceptual processing of text during rapid serial visual presentation. Journal of Educational Psychology.', url: 'https://psycnet.apa.org/record/1984-08638-001' },
88
+ { name: 'Saldana, D., & Greene, R. (2022). Reading effectiveness with RSVP apps. Reading Psychology.', url: 'https://www.tandfonline.com/doi/abs/10.1080/02702711.2022.2030000' },
89
+ ],
90
+ schemas: [faqSchema, howToSchema, appSchema],
91
+ seo: [
92
+ { type: 'title', level: 2, text: 'La Formule 1 de la Lecture : Débloquez Votre Bande Passante Mentale' },
93
+ {
94
+ type: 'paragraph',
95
+ html: 'Et si lire était, biomécaniquement, une perte de temps ? Votre cerveau est un superordinateur bridé par une connexion analogique : vos yeux. Le <strong>Lecteur RSVP</strong> brise ce goulot d\'étranglement en présentant les mots au point focal exact où votre esprit les traite le plus rapidement.',
96
+ },
97
+ {
98
+ type: 'paragraph',
99
+ html: 'La lecture traditionnelle est un processus inefficace. Vos yeux ne fonctionnent pas comme un scanner ; ils fonctionnent comme une caméra en rafale : arrêt, mise au point, saut. Ce saut, appelé <strong>saccade</strong>, vous fait passer une grande partie du temps à déplacer les yeux plutôt qu\'à absorber l\'information.',
100
+ },
101
+ {
102
+ type: 'tip',
103
+ html: '"La lecture RSVP n\'est pas seulement lire plus vite. C\'est éliminer la friction mécanique entre le texte et votre cerveau."',
104
+ },
105
+ { type: 'title', level: 3, text: 'La Science derrière l\'Injection de Données' },
106
+ {
107
+ type: 'comparative',
108
+ columns: 3,
109
+ items: [
110
+ {
111
+ icon: 'mdi:bullseye-arrow',
112
+ title: 'Point de Reconnaissance Optimal (ORP)',
113
+ description: 'Chaque mot a un point où votre cerveau le reconnaît le plus vite. L\'algorithme calcule cette lettre exacte (la rouge) et la centre parfaitement. Vos yeux ne bougent pas d\'un millimètre.',
114
+ },
115
+ {
116
+ icon: 'mdi:speedometer-slow',
117
+ title: 'Silence Cognitif',
118
+ highlight: true,
119
+ description: 'Au-delà de 400-500 MPM, votre voix intérieure se tait — elle ne peut pas suivre le rythme. Vous cessez d\'"entendre" ce que vous lisez et commencez à "voir" des significations et des idées pures.',
120
+ },
121
+ {
122
+ icon: 'mdi:brain',
123
+ title: 'Neuroplasticité Visuelle',
124
+ description: 'Comme aller à la salle de sport : 300 MPM semblera rapide au début. Après une semaine, 500 MPM semblera une promenade. Vous re-entraînez les voies neuronales reliant le cortex visuel au langage.',
125
+ },
126
+ ],
127
+ },
128
+ { type: 'title', level: 3, text: 'Protocole d\'Entraînement : Du Débutant à l\'Expert' },
129
+ {
130
+ type: 'comparative',
131
+ columns: 3,
132
+ items: [
133
+ {
134
+ title: "Niveau 1 : L'Éveil (200 à 300 MPM)",
135
+ description: "Votre vitesse de lecture normale. Habituez-vous à l'interface. Détendez le visage et laissez les mots venir à vous. N'essayez pas de les attraper.",
136
+ points: ['Idéal pour débutants', 'Familiarisation ORP', 'Sans fatigue oculaire'],
137
+ },
138
+ {
139
+ title: "Niveau 2 : Le Mur du Son (400 à 500 MPM)",
140
+ highlight: true,
141
+ description: "C'est ici que la magie se produit. Vous ressentirez de l'inconfort. Ne ralentissez pas si vous manquez un mot. Votre cerveau apprendra à combler les lacunes par le contexte.",
142
+ points: ['La subvocalisation disparaît', 'État de flux mental', 'Doublez votre vitesse de base'],
143
+ },
144
+ {
145
+ title: "Niveau 3 : Vitesse d'Évasion (600+ MPM)",
146
+ description: "Territoire avancé. Idéal pour réviser des cours, lire des actualités ou consommer de la documentation technique.",
147
+ points: ['Roman moyen en 2 heures', 'Efficacité de lecture maximale', 'Nécessite une pratique préalable'],
148
+ },
149
+ ],
150
+ },
151
+ ],
152
+ };
@@ -0,0 +1,22 @@
1
+ import type { ToolDefinition, ToolsToolEntry } from '../../types';
2
+ import type { SpeedReaderUI } from './ui';
3
+ import SpeedReaderComponent from './component.astro';
4
+ import SpeedReaderSEO from './seo.astro';
5
+ import SpeedReaderBibliography from './bibliography.astro';
6
+
7
+ export const speedReader: ToolsToolEntry<SpeedReaderUI> = {
8
+ id: 'speed-reader',
9
+ icons: { bg: 'mdi:book-open-page-variant', fg: 'mdi:lightning-bolt' },
10
+ i18n: {
11
+ es: () => import('./i18n/es').then((m) => m.content),
12
+ en: () => import('./i18n/en').then((m) => m.content),
13
+ fr: () => import('./i18n/fr').then((m) => m.content),
14
+ },
15
+ };
16
+
17
+ export const SPEED_READER_TOOL: ToolDefinition = {
18
+ entry: speedReader,
19
+ Component: SpeedReaderComponent,
20
+ SEOComponent: SpeedReaderSEO,
21
+ BibliographyComponent: SpeedReaderBibliography,
22
+ };
@@ -0,0 +1,106 @@
1
+ export interface RSVPWord {
2
+ original: string;
3
+ left: string;
4
+ pivot: string;
5
+ right: string;
6
+ delayMod: number;
7
+ }
8
+
9
+ export class RSVPEngine {
10
+ private words: RSVPWord[] = [];
11
+ private wpm = 300;
12
+ private isPlaying = false;
13
+ private currentIndex = 0;
14
+ private lastFrameTime = 0;
15
+ private accumulatedTime = 0;
16
+ private onWordUpdate: (word: RSVPWord) => void;
17
+ private onComplete: () => void;
18
+ private rafId: number | null = null;
19
+
20
+ constructor(onWordUpdate: (word: RSVPWord) => void, onComplete: () => void) {
21
+ this.onWordUpdate = onWordUpdate;
22
+ this.onComplete = onComplete;
23
+ }
24
+
25
+ setText(text: string): void {
26
+ this.words = text.trim().split(/\s+/).filter(Boolean).map((w) => this.processWord(w));
27
+ this.currentIndex = 0;
28
+ }
29
+
30
+ setWPM(wpm: number): void {
31
+ this.wpm = wpm;
32
+ }
33
+
34
+ play(): void {
35
+ if (this.isPlaying) return;
36
+ if (this.currentIndex >= this.words.length) this.currentIndex = 0;
37
+ this.isPlaying = true;
38
+ this.lastFrameTime = performance.now();
39
+ this.accumulatedTime = 0;
40
+ this.tick();
41
+ }
42
+
43
+ pause(rewind = true): void {
44
+ this.isPlaying = false;
45
+ if (this.rafId !== null) cancelAnimationFrame(this.rafId);
46
+ if (rewind) this.currentIndex = Math.max(0, this.currentIndex - 5);
47
+ this.showCurrentWord();
48
+ }
49
+
50
+ seek(pct: number): void {
51
+ if (!this.words.length) return;
52
+ this.currentIndex = Math.floor(this.words.length * (pct / 100));
53
+ this.showCurrentWord();
54
+ }
55
+
56
+ getProgress(): number {
57
+ if (!this.words.length) return 0;
58
+ return (this.currentIndex / this.words.length) * 100;
59
+ }
60
+
61
+ private showCurrentWord(): void {
62
+ const word = this.words[this.currentIndex];
63
+ if (word) this.onWordUpdate(word);
64
+ }
65
+
66
+ private calcDelayMod(word: string): number {
67
+ const lastChar = word[word.length - 1] ?? '';
68
+ if ('.?!'.includes(lastChar)) return 2.5;
69
+ if (',;:'.includes(lastChar)) return 2.0;
70
+ if (word.length > 12) return 1.5;
71
+ return 1;
72
+ }
73
+
74
+ private processWord(word: string): RSVPWord {
75
+ const len = word.length;
76
+ const pivotIndex = len <= 1 ? 0 : Math.min(Math.ceil((len - 1) * 0.35), len - 1);
77
+ return {
78
+ original: word,
79
+ left: word.slice(0, pivotIndex),
80
+ pivot: word[pivotIndex] ?? '',
81
+ right: word.slice(pivotIndex + 1),
82
+ delayMod: this.calcDelayMod(word),
83
+ };
84
+ }
85
+
86
+ private tick = (): void => {
87
+ if (!this.isPlaying) return;
88
+ const now = performance.now();
89
+ this.accumulatedTime += now - this.lastFrameTime;
90
+ this.lastFrameTime = now;
91
+ const baseInterval = 60000 / this.wpm;
92
+ const currentWord = this.words[this.currentIndex];
93
+ const targetDuration = baseInterval * (currentWord?.delayMod ?? 1);
94
+ if (this.accumulatedTime >= targetDuration) {
95
+ this.accumulatedTime -= targetDuration;
96
+ this.currentIndex++;
97
+ if (this.currentIndex >= this.words.length) {
98
+ this.isPlaying = false;
99
+ this.onComplete();
100
+ return;
101
+ }
102
+ this.showCurrentWord();
103
+ }
104
+ this.rafId = requestAnimationFrame(this.tick);
105
+ };
106
+ }
@@ -0,0 +1,14 @@
1
+ ---
2
+ import { SEORenderer } from '@jjlmoya/utils-shared';
3
+ import { speedReader } from './index';
4
+ import type { KnownLocale } from '../../types';
5
+
6
+ interface Props {
7
+ locale?: KnownLocale;
8
+ }
9
+
10
+ const { locale = 'es' } = Astro.props;
11
+ const content = await speedReader.i18n[locale]?.();
12
+ ---
13
+
14
+ {content && <SEORenderer content={{ locale, sections: content.seo }} />}
@@ -0,0 +1,14 @@
1
+ export interface SpeedReaderUI extends Record<string, string> {
2
+ progressLabel: string;
3
+ speedLabel: string;
4
+ slowLabel: string;
5
+ fastLabel: string;
6
+ speedHint: string;
7
+ textLabel: string;
8
+ textPlaceholder: string;
9
+ clearLabel: string;
10
+ words: string;
11
+ defaultText: string;
12
+ play: string;
13
+ pause: string;
14
+ }
@@ -0,0 +1,14 @@
1
+ ---
2
+ import { Bibliography as SharedBibliography } from '@jjlmoya/utils-shared';
3
+ import { textPixelCalculator } from './index';
4
+ import type { KnownLocale } from '../../types';
5
+
6
+ interface Props {
7
+ locale?: KnownLocale;
8
+ }
9
+
10
+ const { locale = 'es' } = Astro.props;
11
+ const content = await textPixelCalculator.i18n[locale]?.();
12
+ ---
13
+
14
+ {content && <SharedBibliography links={content.bibliography} />}