@jjlmoya/utils-audiovisual 1.2.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 (120) hide show
  1. package/package.json +60 -0
  2. package/src/category/i18n/en.ts +198 -0
  3. package/src/category/i18n/es.ts +198 -0
  4. package/src/category/i18n/fr.ts +198 -0
  5. package/src/category/index.ts +17 -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 +4 -0
  10. package/src/env.d.ts +5 -0
  11. package/src/index.ts +32 -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/seo_length.test.ts +22 -0
  21. package/src/tests/tool_validation.test.ts +17 -0
  22. package/src/tool/chromaticLens/bibliography.astro +17 -0
  23. package/src/tool/chromaticLens/component.astro +178 -0
  24. package/src/tool/chromaticLens/i18n/en.ts +246 -0
  25. package/src/tool/chromaticLens/i18n/es.ts +244 -0
  26. package/src/tool/chromaticLens/i18n/fr.ts +244 -0
  27. package/src/tool/chromaticLens/index.ts +43 -0
  28. package/src/tool/chromaticLens/logic.ts +87 -0
  29. package/src/tool/chromaticLens/seo.astro +15 -0
  30. package/src/tool/chromaticLens/style.css +308 -0
  31. package/src/tool/chromaticLens/ui.ts +109 -0
  32. package/src/tool/collageMaker/bibliography.astro +17 -0
  33. package/src/tool/collageMaker/component.astro +302 -0
  34. package/src/tool/collageMaker/i18n/en.ts +233 -0
  35. package/src/tool/collageMaker/i18n/es.ts +231 -0
  36. package/src/tool/collageMaker/i18n/fr.ts +231 -0
  37. package/src/tool/collageMaker/index.ts +51 -0
  38. package/src/tool/collageMaker/logic.ts +134 -0
  39. package/src/tool/collageMaker/seo.astro +15 -0
  40. package/src/tool/collageMaker/style.css +386 -0
  41. package/src/tool/exifCleaner/bibliography.astro +18 -0
  42. package/src/tool/exifCleaner/component.astro +162 -0
  43. package/src/tool/exifCleaner/i18n/en.ts +277 -0
  44. package/src/tool/exifCleaner/i18n/es.ts +277 -0
  45. package/src/tool/exifCleaner/i18n/fr.ts +277 -0
  46. package/src/tool/exifCleaner/index.ts +57 -0
  47. package/src/tool/exifCleaner/logic.ts +135 -0
  48. package/src/tool/exifCleaner/seo.astro +18 -0
  49. package/src/tool/exifCleaner/style.css +289 -0
  50. package/src/tool/exifCleaner/ui.ts +117 -0
  51. package/src/tool/imageCompressor/bibliography.astro +17 -0
  52. package/src/tool/imageCompressor/component.astro +262 -0
  53. package/src/tool/imageCompressor/i18n/en.ts +232 -0
  54. package/src/tool/imageCompressor/i18n/es.ts +230 -0
  55. package/src/tool/imageCompressor/i18n/fr.ts +230 -0
  56. package/src/tool/imageCompressor/index.ts +50 -0
  57. package/src/tool/imageCompressor/logic.ts +79 -0
  58. package/src/tool/imageCompressor/seo.astro +15 -0
  59. package/src/tool/imageCompressor/style.css +503 -0
  60. package/src/tool/printQualityCalculator/bibliography.astro +18 -0
  61. package/src/tool/printQualityCalculator/component.astro +318 -0
  62. package/src/tool/printQualityCalculator/i18n/en.ts +247 -0
  63. package/src/tool/printQualityCalculator/i18n/es.ts +245 -0
  64. package/src/tool/printQualityCalculator/i18n/fr.ts +245 -0
  65. package/src/tool/printQualityCalculator/index.ts +56 -0
  66. package/src/tool/printQualityCalculator/logic.ts +53 -0
  67. package/src/tool/printQualityCalculator/seo.astro +18 -0
  68. package/src/tool/printQualityCalculator/style.css +491 -0
  69. package/src/tool/printQualityCalculator/ui.ts +122 -0
  70. package/src/tool/privacyBlur/bibliography.astro +17 -0
  71. package/src/tool/privacyBlur/component.astro +230 -0
  72. package/src/tool/privacyBlur/i18n/en.ts +238 -0
  73. package/src/tool/privacyBlur/i18n/es.ts +236 -0
  74. package/src/tool/privacyBlur/i18n/fr.ts +236 -0
  75. package/src/tool/privacyBlur/index.ts +49 -0
  76. package/src/tool/privacyBlur/logic.ts +249 -0
  77. package/src/tool/privacyBlur/seo.astro +15 -0
  78. package/src/tool/privacyBlur/style.css +332 -0
  79. package/src/tool/privacyBlur/ui.ts +124 -0
  80. package/src/tool/subtitleSync/bibliography.astro +17 -0
  81. package/src/tool/subtitleSync/component.astro +187 -0
  82. package/src/tool/subtitleSync/i18n/en.ts +241 -0
  83. package/src/tool/subtitleSync/i18n/es.ts +241 -0
  84. package/src/tool/subtitleSync/i18n/fr.ts +241 -0
  85. package/src/tool/subtitleSync/index.ts +49 -0
  86. package/src/tool/subtitleSync/logic.ts +91 -0
  87. package/src/tool/subtitleSync/seo.astro +15 -0
  88. package/src/tool/subtitleSync/style.css +325 -0
  89. package/src/tool/subtitleSync/ui.ts +152 -0
  90. package/src/tool/timelapseCalculator/bibliography.astro +15 -0
  91. package/src/tool/timelapseCalculator/component.astro +148 -0
  92. package/src/tool/timelapseCalculator/i18n/en.ts +169 -0
  93. package/src/tool/timelapseCalculator/i18n/es.ts +169 -0
  94. package/src/tool/timelapseCalculator/i18n/fr.ts +169 -0
  95. package/src/tool/timelapseCalculator/index.ts +52 -0
  96. package/src/tool/timelapseCalculator/logic.ts +46 -0
  97. package/src/tool/timelapseCalculator/seo.astro +18 -0
  98. package/src/tool/timelapseCalculator/style.css +285 -0
  99. package/src/tool/tvDistance/bibliography.astro +17 -0
  100. package/src/tool/tvDistance/component.astro +178 -0
  101. package/src/tool/tvDistance/i18n/en.ts +223 -0
  102. package/src/tool/tvDistance/i18n/es.ts +223 -0
  103. package/src/tool/tvDistance/i18n/fr.ts +223 -0
  104. package/src/tool/tvDistance/index.ts +49 -0
  105. package/src/tool/tvDistance/logic.ts +47 -0
  106. package/src/tool/tvDistance/seo.astro +15 -0
  107. package/src/tool/tvDistance/style.css +435 -0
  108. package/src/tool/tvDistance/ui.ts +66 -0
  109. package/src/tool/videoFrameExtractor/bibliography.astro +17 -0
  110. package/src/tool/videoFrameExtractor/component.astro +285 -0
  111. package/src/tool/videoFrameExtractor/i18n/en.ts +235 -0
  112. package/src/tool/videoFrameExtractor/i18n/es.ts +235 -0
  113. package/src/tool/videoFrameExtractor/i18n/fr.ts +235 -0
  114. package/src/tool/videoFrameExtractor/index.ts +53 -0
  115. package/src/tool/videoFrameExtractor/logic.ts +49 -0
  116. package/src/tool/videoFrameExtractor/seo.astro +15 -0
  117. package/src/tool/videoFrameExtractor/style.css +426 -0
  118. package/src/tool/videoFrameExtractor/ui.ts +179 -0
  119. package/src/tools.ts +25 -0
  120. package/src/types.ts +72 -0
@@ -0,0 +1,169 @@
1
+ import type { WithContext, FAQPage, HowTo, SoftwareApplication } from 'schema-dts';
2
+ import type { TimelapseUI, TimelapseLocaleContent } from '../index';
3
+
4
+ const slug = 'timelapse-hyperlapse-calculator-perfect-intervals';
5
+ const title = 'Timelapse and Hyperlapse Calculator: Perfect Intervals';
6
+ const description = 'Calculate the exact interval between photos, total duration, and storage for your timelapses. Essential tool for photographers.';
7
+
8
+ const ui: TimelapseUI = {
9
+ title: "Timelapse Calculator",
10
+ paramsTitle: "Parameters",
11
+ eventDuration: "How long is the real event?",
12
+ hours: "Hours",
13
+ minutes: "Minutes",
14
+ videoDuration: "What final video do you want?",
15
+ seconds: "Duration (sec)",
16
+ fps: "FPS",
17
+ resultsTitle: "Results",
18
+ intervalLabel: "Set your intervalometer to:",
19
+ secondsUnit: "seconds",
20
+ totalPhotos: "Total Photos",
21
+ speed: "Speed",
22
+ shutterSpeed: "Shutter Speed",
23
+ storage: "Size (RAW)",
24
+ rule180Info: "The 180° rule suggests a shutter speed of half the interval for smooth motion blur.",
25
+ };
26
+
27
+ const faq: TimelapseLocaleContent['faq'] = [
28
+ {
29
+ question: "How do I choose the correct interval for my timelapse?",
30
+ answer: "It depends on the speed of the movement you are capturing. For fast clouds, use 2-3 seconds. For the movement of the sun or stars, 15-30 seconds. For plants growing or building construction, 5-15 minutes.",
31
+ },
32
+ {
33
+ question: "How many photos do I need for a one-minute video?",
34
+ answer: "A standard video has 24 or 30 frames per second (fps). For one minute of video at 24fps, you need exactly 1440 photographs (60 seconds * 24 photos/second).",
35
+ },
36
+ {
37
+ question: "What is 'Flicker' and how do I avoid it?",
38
+ answer: "It is an annoying flickering caused by small variations in exposure between photos. To avoid it, always use manual mode (M), fixed white balance, and prioritize using lenses with a manual aperture ring or 'lens twist' techniques.",
39
+ },
40
+ {
41
+ question: "Why is shutter speed important?",
42
+ answer: "For movement to look fluid (180° rule), the shutter speed should be approximately half the interval. For example, if the interval is 2 seconds, try shooting at 1 second to create natural motion blur.",
43
+ },
44
+ ];
45
+
46
+ const howTo: TimelapseLocaleContent['howTo'] = [
47
+ {
48
+ name: "Define the final video duration",
49
+ text: "Indicate how many seconds or minutes you want the resulting video to last (e.g., 10 seconds for Instagram).",
50
+ },
51
+ {
52
+ name: "Select the output FPS",
53
+ text: "Choose the fluidity of the video: 24 (cinema), 30 (web), or 60 (smooth slow motion).",
54
+ },
55
+ {
56
+ name: "Adjust the capture interval",
57
+ text: "Configure every how many seconds your camera will fire according to the speed of the scene.",
58
+ },
59
+ {
60
+ name: "Verify storage space",
61
+ text: "The calculator will tell you how many Gigabytes the session will take. Ensure your SD card has enough space before starting.",
62
+ },
63
+ ];
64
+
65
+ const bibliography: TimelapseLocaleContent['bibliography'] = [
66
+ {
67
+ name: "Timescapes Forum - Digital Timelapse Acquisition & Processing",
68
+ url: "https://timescapes.org/phpBB3/viewforum.php?f=4",
69
+ },
70
+ {
71
+ name: "Magic Lantern - Auto ETTR & Bulb Ramping Algorithms",
72
+ url: "https://wiki.magiclantern.fm/ettr",
73
+ },
74
+ {
75
+ name: "LRTimelapse - Visual Deflicker & Holy Grail Workflow",
76
+ url: "https://lrtimelapse.com/tutorial/advanced/",
77
+ },
78
+ {
79
+ name: "PhotoPills - Advanced Timelapse Calculator & NPF Rule",
80
+ url: "https://www.photopills.com/calculators/timelapse",
81
+ },
82
+ ];
83
+
84
+ const seo: TimelapseLocaleContent['seo'] = [
85
+ { type: 'title', text: 'Definitive Guide to Timelapse and Hyperlapse Intervals', level: 2 },
86
+ { type: 'paragraph', html: 'The difference between an amateur high-speed video and a <strong>cinematic timelapse</strong> mathematically lies in one single factor: <strong>the interval</strong>. This calculator removes the guesswork, allowing you to precisely plan your intervalometer shot to capture sunrises, urban traffic, or the Milky Way with perfect fluidity.' },
87
+
88
+ { type: 'title', text: 'Recommended Intervals Table (Cheat Sheet)', level: 3 },
89
+ { type: 'paragraph', html: 'Use this quick reference table to set your intervalometer according to the subject. The goal is to capture enough movement to be perceptible but smooth.' },
90
+ { type: 'table', headers: ['Subject / Scene', 'Suggested Interval', 'Event Duration (Minimum)'], rows: [
91
+ ['Fast Clouds / Storms', '1 - 2 seconds', '20 - 30 min'],
92
+ ['Urban Traffic / People (Blur)', '0.5 - 2 seconds', '15 - 20 min'],
93
+ ['Sunset / Sunrise (Holy Grail)', '5 - 10 seconds', '1.5 - 2.5 hours'],
94
+ ['Slow Clouds / Shadows', '10 - 15 seconds', '2 - 3 hours'],
95
+ ['Stars / Milky Way (Astro)', '15 - 30 seconds*', '3 - 5 hours'],
96
+ ['Construction / Fast Plants', '5 - 15 minutes', 'Days / Weeks']
97
+ ]},
98
+ { type: 'tip', title: 'Note for Astro', html: 'The interval is usually dictated by the exposure time needed to capture light (500 rule) + 1 or 2 seconds of buffer for card writing.' },
99
+
100
+ { type: 'title', text: 'The 180° Rule (Motion Blur)', level: 3 },
101
+ { type: 'paragraph', html: 'A common mistake in timelapse is getting a "jittery" or staccato (strobing) video. To get that smooth cinematic look, you need <strong>motion blur</strong>.' },
102
+ { type: 'card', title: 'The Rule', icon: 'mdi:information', html: 'Your Shutter Speed should be half of your interval. <br /><br /> <em>Example:</em> If you shoot every <strong>4 seconds</strong>, your exposure should be <strong>2 seconds</strong>. This fills the "temporal gap" between photos, creating trails in cars and soft water.' },
103
+
104
+ { type: 'title', text: 'Flicker and Manual Aperture', level: 3 },
105
+ { type: 'paragraph', html: '"Flicker" is the annoying flickering caused by micro-variations in the diaphragm aperture between shots.' },
106
+ { type: 'list', items: [
107
+ '<strong>Lens Twist:</strong> Slightly unlock the lens on DSLRs to break the electronic connection and fix the aperture mechanically.',
108
+ '<strong>All Manual:</strong> ISO, White Balance, and Focus must be fixed. Never use automatic modes.',
109
+ '<strong>Shoot in RAW:</strong> Essential for correcting exposure and color in post-production without destroying the image.'
110
+ ]},
111
+
112
+ { type: 'diagnostic', variant: 'success', title: 'Advanced Technique: The "Holy Grail"', icon: 'mdi:crown', badge: 'Pro Technique', html: 'The "Holy Grail" refers to the smooth transition from day to night (or vice versa). It is the most difficult technical challenge because light changes drastically (up to 15 stops of aperture).' },
113
+
114
+ { type: 'stats', columns: 3, items: [
115
+ { label: 'Bulb Ramping', value: 'Gradual Exposure', icon: 'mdi:brightness-6' },
116
+ { label: 'Post-Pro', value: 'LRTimelapse', icon: 'mdi:television-guide' },
117
+ { label: 'Strategy', value: 'Night Interval', icon: 'mdi:weather-night' }
118
+ ]},
119
+
120
+ { type: 'title', text: 'Conclusion: The Zen of Simple Mechanics', level: 3 },
121
+ { type: 'paragraph', html: 'Mastering your timelapse starts with understanding your intervalometer\'s math. Don\'t let a poorly chosen interval ruin your session.' }
122
+ ];
123
+
124
+ const faqSchema: WithContext<FAQPage> = {
125
+ '@context': 'https://schema.org',
126
+ '@type': 'FAQPage',
127
+ mainEntity: faq.map((item) => ({
128
+ '@type': 'Question',
129
+ name: item.question,
130
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
131
+ })),
132
+ };
133
+
134
+ const howToSchema: WithContext<HowTo> = {
135
+ '@context': 'https://schema.org',
136
+ '@type': 'HowTo',
137
+ name: title,
138
+ description,
139
+ step: howTo.map((step) => ({
140
+ '@type': 'HowToStep',
141
+ name: step.name,
142
+ text: step.text,
143
+ })),
144
+ };
145
+
146
+ const appSchema: WithContext<SoftwareApplication> = {
147
+ '@context': 'https://schema.org',
148
+ '@type': 'SoftwareApplication',
149
+ name: title,
150
+ description,
151
+ applicationCategory: 'UtilitiesApplication',
152
+ operatingSystem: 'Web',
153
+ offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' },
154
+ inLanguage: 'en',
155
+ };
156
+
157
+ export const content: TimelapseLocaleContent = {
158
+ slug,
159
+ title,
160
+ description,
161
+ ui,
162
+ seo,
163
+ faq,
164
+ faqTitle: 'Frequently Asked Questions about Timelapse Production',
165
+ bibliography,
166
+ bibliographyTitle: 'Timelapse Theory and Resources',
167
+ howTo,
168
+ schemas: [faqSchema as any, howToSchema as any, appSchema],
169
+ };
@@ -0,0 +1,169 @@
1
+ import type { WithContext, FAQPage, HowTo, SoftwareApplication } from 'schema-dts';
2
+ import type { TimelapseUI, TimelapseLocaleContent } from '../index';
3
+
4
+ const slug = 'calculadora-timelapse';
5
+ const title = 'Calculadora de Timelapse y Hyperlapse: Intervalos Perfectos';
6
+ const description = 'Calcula el intervalo exacto entre fotos, duración total y almacenamiento para tus timelapses. Herramienta esencial para fotógrafos.';
7
+
8
+ const ui: TimelapseUI = {
9
+ title: "Calculadora Timelapse",
10
+ paramsTitle: "Parámetros",
11
+ eventDuration: "¿Cuánto dura el evento real?",
12
+ hours: "Horas",
13
+ minutes: "Minutos",
14
+ videoDuration: "¿Cómo quieres el video final?",
15
+ seconds: "Duración (seg)",
16
+ fps: "FPS",
17
+ resultsTitle: "Resultados",
18
+ intervalLabel: "Configura tu intervalómetro a:",
19
+ secondsUnit: "segundos",
20
+ totalPhotos: "Total Fotos",
21
+ speed: "Velocidad",
22
+ shutterSpeed: "Duración Disparo",
23
+ storage: "Peso (RAW)",
24
+ rule180Info: "La regla de los 180° sugiere una velocidad de obturación de la mitad del intervalo para un movimiento fluido.",
25
+ };
26
+
27
+ const faq: TimelapseLocaleContent['faq'] = [
28
+ {
29
+ question: "¿Cómo elijo el intervalo correcto para mi timelapse?",
30
+ answer: "Depende de la velocidad del movimiento que capturas. Para nubes rápidas, usa 2-3 segundos. Para el movimiento del sol o estrellas, 15-30 segundos. Para plantas creciendo o construcción de edificios, 5-15 minutos.",
31
+ },
32
+ {
33
+ question: "¿Cuántas fotos necesito para un video de un minuto?",
34
+ answer: "Un video estándar tiene 24 o 30 fotogramas por segundo (fps). Para un minuto de video a 24fps, necesitas exactamente 1440 fotografías (60 segundos * 24 fotos/segundo).",
35
+ },
36
+ {
37
+ question: "¿Qué es el 'Flicker' y cómo lo evito?",
38
+ answer: "Es un parpadeo molesto causado por pequeñas variaciones de exposición entre fotos. Para evitarlo, usa siempre modo manual (M), balance de blancos fijo y prioriza el uso de objetivos con anillo de diafragma manual o técnicas de 'lens twist'.",
39
+ },
40
+ {
41
+ question: "¿Por qué es importante el tiempo de obturación?",
42
+ answer: "Para que el movimiento se vea fluido (regla de los 180°), el tiempo de obturación debería ser aproximadamente la mitad del intervalo. Por ejemplo, si el intervalo es de 2 segundos, intenta disparar a 1 segundo para crear un desenfoque de movimiento natural.",
43
+ },
44
+ ];
45
+
46
+ const howTo: TimelapseLocaleContent['howTo'] = [
47
+ {
48
+ name: "Definir la duración del video final",
49
+ text: "Indica cuántos segundos o minutos quieres que dure el video resultante (ej. 10 segundos para Instagram).",
50
+ },
51
+ {
52
+ name: "Seleccionar los FPS de salida",
53
+ text: "Elige la fluidez del video: 24 (cine), 30 (web) o 60 (cámara lenta fluida).",
54
+ },
55
+ {
56
+ name: "Ajustar el intervalo de captura",
57
+ text: "Configura cada cuántos segundos disparará tu cámara según la velocidad de la escena.",
58
+ },
59
+ {
60
+ name: "Verificar espacio de almacenamiento",
61
+ text: "La calculadora te dirá cuántos Gigabytes ocupará la sesión. Asegúrate de que tu tarjeta SD tenga espacio suficiente antes de empezar.",
62
+ },
63
+ ];
64
+
65
+ const bibliography: TimelapseLocaleContent['bibliography'] = [
66
+ {
67
+ name: "Timescapes Forum - Digital Timelapse Acquisition & Processing",
68
+ url: "https://timescapes.org/phpBB3/viewforum.php?f=4",
69
+ },
70
+ {
71
+ name: "Magic Lantern - Auto ETTR & Bulb Ramping Algorithms",
72
+ url: "https://wiki.magiclantern.fm/ettr",
73
+ },
74
+ {
75
+ name: "LRTimelapse - Visual Deflicker & Holy Grail Workflow",
76
+ url: "https://lrtimelapse.com/tutorial/advanced/",
77
+ },
78
+ {
79
+ name: "PhotoPills - Advanced Timelapse Calculator & NPF Rule",
80
+ url: "https://www.photopills.com/calculators/timelapse",
81
+ },
82
+ ];
83
+
84
+ const seo: TimelapseLocaleContent['seo'] = [
85
+ { type: 'title', text: 'Guía Definitiva de Intervalos Timelapse y Hyperlapse', level: 2 },
86
+ { type: 'paragraph', html: 'La diferencia entre un vídeo acelerado amateur y un <strong>timelapse cinematográfico</strong> reside matemáticamente en un solo factor: <strong>el intervalo</strong>. Esta calculadora elimina las conjeturas, permitiéndote planificar con precisión el disparo de tu intervalómetro para capturar amaneceres, tráfico urbano o la Vía Láctea con fluidez perfecta.' },
87
+
88
+ { type: 'title', text: 'Tabla de Intervalos Recomendados (Cheat Sheet)', level: 3 },
89
+ { type: 'paragraph', html: 'Usa esta tabla de referencia rápida para configurar tu intervalómetro según el sujeto. El objetivo es capturar suficiente movimiento para que sea perceptible pero fluido.' },
90
+ { type: 'table', headers: ['Sujeto / Escena', 'Intervalo Sugerido', 'Duración Evento (Mínima)'], rows: [
91
+ ['Nubes rápidas / Tormentas', '1 - 2 segundos', '20 - 30 min'],
92
+ ['Tráfico Urbano / Personas (Blur)', '0.5 - 2 segundos', '15 - 20 min'],
93
+ ['Atardecer / Amanecer (Holy Grail)', '5 - 10 segundos', '1.5 - 2.5 horas'],
94
+ ['Nubes Lentas / Sombras', '10 - 15 segundos', '2 - 3 horas'],
95
+ ['Estrellas / Vía Láctea (Astro)', '15 - 30 segundos*', '3 - 5 horas'],
96
+ ['Construcción / Plantas Rápidas', '5 - 15 minutos', 'Días / Semanas']
97
+ ]},
98
+ { type: 'tip', title: 'Nota para Astro', html: 'El intervalo suele estar dictado por el tiempo de exposición necesario para captar luz (regla 500) + 1 o 2 segundos de buffer para escritura en tarjeta.' },
99
+
100
+ { type: 'title', text: 'La Regla de los 180° (Motion Blur)', level: 3 },
101
+ { type: 'paragraph', html: 'Un error común en timelapse es obtener un vídeo "nervioso" o staccato (strobing). Para obtener ese look cinematográfico suave, necesitas <strong>motion blur</strong>.' },
102
+ { type: 'card', title: 'La Regla', icon: 'mdi:information', html: 'Tu velocidad de obturación (Shutter Speed) debe ser la mitad de tu intervalo. <br /><br /> <em>Ejemplo:</em> Si disparas cada <strong>4 segundos</strong>, tu exposición debería ser de <strong>2 segundos</strong>. Esto rellena el "vacío temporal" entre fotos, creando estelas en coches y agua suave.' },
103
+
104
+ { type: 'title', text: 'Flicker y Apertura Manual', level: 3 },
105
+ { type: 'paragraph', html: 'El "Flicker" es el parpadeo molesto causado por micro-variaciones en la apertura del diafragma entre disparo y disparo.' },
106
+ { type: 'list', items: [
107
+ '<strong>Lens Twist:</strong> Desbloquea ligeramente el objetivo en DSLRs para romper la conexión electrónica y fijar la apertura mecánicamente.',
108
+ '<strong>Todo Manual:</strong> ISO, Balance de Blancos y Enfoque deben estar fijos. Nunca uses modos automáticos.',
109
+ '<strong>Dispara en RAW:</strong> Esencial para corregir exposición y color en post-producción sin destruir la imagen.'
110
+ ]},
111
+
112
+ { type: 'diagnostic', variant: 'success', title: 'Técnica Avanzada: El "Holy Grail"', icon: 'mdi:crown', badge: 'Pro Teknik', html: 'Se llama "Santo Grial" a la transición fluida del día a la noche (o viceversa). Es el reto técnico más difícil porque la luz cambia drásticamente (hasta 15 pasos de diafragma).' },
113
+
114
+ { type: 'stats', columns: 3, items: [
115
+ { label: 'Bulb Ramping', value: 'Exposición Gradual', icon: 'mdi:brightness-6' },
116
+ { label: 'Post-Pro', value: 'LRTimelapse', icon: 'mdi:television-guide' },
117
+ { label: 'Estrategia', value: 'Intervalo Nocturno', icon: 'mdi:weather-night' }
118
+ ]},
119
+
120
+ { type: 'title', text: 'Conclusión: El Zen de la Mecánica Simple', level: 3 },
121
+ { type: 'paragraph', html: 'Dominar tu timelapse empieza por entender las matemáticas de tu intervalómetro. No permitas que un intervalo mal elegido arruine tu sesión.' }
122
+ ];
123
+
124
+ const faqSchema: WithContext<FAQPage> = {
125
+ '@context': 'https://schema.org',
126
+ '@type': 'FAQPage',
127
+ mainEntity: faq.map((item) => ({
128
+ '@type': 'Question',
129
+ name: item.question,
130
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
131
+ })),
132
+ };
133
+
134
+ const howToSchema: WithContext<HowTo> = {
135
+ '@context': 'https://schema.org',
136
+ '@type': 'HowTo',
137
+ name: title,
138
+ description,
139
+ step: howTo.map((step) => ({
140
+ '@type': 'HowToStep',
141
+ name: step.name,
142
+ text: step.text,
143
+ })),
144
+ };
145
+
146
+ const appSchema: WithContext<SoftwareApplication> = {
147
+ '@context': 'https://schema.org',
148
+ '@type': 'SoftwareApplication',
149
+ name: title,
150
+ description,
151
+ applicationCategory: 'UtilitiesApplication',
152
+ operatingSystem: 'Web',
153
+ offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' },
154
+ inLanguage: 'es',
155
+ };
156
+
157
+ export const content: TimelapseLocaleContent = {
158
+ slug,
159
+ title,
160
+ description,
161
+ ui,
162
+ seo,
163
+ faq,
164
+ faqTitle: 'Preguntas frecuentes sobre producción timelapse',
165
+ bibliography,
166
+ bibliographyTitle: 'Teoría y recursos de producción timelapse',
167
+ howTo,
168
+ schemas: [faqSchema as any, howToSchema as any, appSchema],
169
+ };
@@ -0,0 +1,169 @@
1
+ import type { WithContext, FAQPage, HowTo, SoftwareApplication } from 'schema-dts';
2
+ import type { TimelapseUI, TimelapseLocaleContent } from '../index';
3
+
4
+ const slug = 'calculatrice-timelapse-hyperlapse-intervalles-parfaits';
5
+ const title = 'Calculatrice de Timelapse et Hyperlapse : Intervalles Parfaits';
6
+ const description = 'Calculez l\'intervalle exact entre les photos, la durée totale et le stockage pour vos timelapses. Outil essentiel pour les photographes.';
7
+
8
+ const ui: TimelapseUI = {
9
+ title: "Calculatrice Timelapse",
10
+ paramsTitle: "Paramètres",
11
+ eventDuration: "Quelle est la durée de l'événement réel ?",
12
+ hours: "Heures",
13
+ minutes: "Minutes",
14
+ videoDuration: "Quelle vidéo finale voulez-vous ?",
15
+ seconds: "Durée (sec)",
16
+ fps: "FPS",
17
+ resultsTitle: "Résultats",
18
+ intervalLabel: "Réglez votre intervallomètre sur :",
19
+ secondsUnit: "secondes",
20
+ totalPhotos: "Total Photos",
21
+ speed: "Vitesse",
22
+ shutterSpeed: "Durée d'exposition",
23
+ storage: "Taille (RAW)",
24
+ rule180Info: "La règle des 180° suggère une vitesse d'obturation de la moitié de l'intervalle pour un flou de mouvement fluide.",
25
+ };
26
+
27
+ const faq: TimelapseLocaleContent['faq'] = [
28
+ {
29
+ question: "Comment choisir l'intervalle correct pour mon timelapse ?",
30
+ answer: "Cela dépend de la vitesse du mouvement que vous capturez. Pour des nuages rapides, utilisez 2-3 secondes. Pour le mouvement du soleil ou des étoiles, 15-30 secondes. Pour la croissance des plantes ou la construction de bâtiments, 5-15 minutes.",
31
+ },
32
+ {
33
+ question: "Combien de photos ai-je besoin pour une vidéo d'une minute ?",
34
+ answer: "Une vidéo standard a 24 ou 30 images par seconde (fps). Pour une minute de vidéo à 24fps, vous avez besoin exactement de 1440 photographies (60 secondes * 24 photos/seconde).",
35
+ },
36
+ {
37
+ question: "Qu'est-ce que le 'Flicker' et comment l'éviter ?",
38
+ answer: "C'est un clignotement gênant causé par de petites variations d'exposition entre les photos. Pour l'éviter, utilisez toujours le mode manuel (M), une balance des blancs fixe et privilégiez l'utilisation d'objectifs avec une bague de diaphragme manuelle.",
39
+ },
40
+ {
41
+ question: "Pourquoi le temps d'obturation est-il important ?",
42
+ answer: "Pour que le mouvement paraisse fluide (règle des 180°), le temps d'obturation devrait être environ la moitié de l'intervalle. Par exemple, si l'intervalle est de 2 secondes, essayez de photographier à 1 seconde.",
43
+ },
44
+ ];
45
+
46
+ const howTo: TimelapseLocaleContent['howTo'] = [
47
+ {
48
+ name: "Définir la durée de la vidéo finale",
49
+ text: "Indiquez combien de secondes ou de minutes vous souhaitez que la vidéo résultante dure (ex : 10 secondes pour Instagram).",
50
+ },
51
+ {
52
+ name: "Sélectionner les FPS de sortie",
53
+ text: "Choisissez la fluidité de la vidéo : 24 (cinéma), 30 (web) ou 60 (ralenti fluide).",
54
+ },
55
+ {
56
+ name: "Ajuster l'intervalle de capture",
57
+ text: "Configurez chaque combien de secondes votre appareil déclenchera selon la vitesse de la scène.",
58
+ },
59
+ {
60
+ name: "Vérifier l'espace de stockage",
61
+ text: "La calculatrice vous dira combien de Gigaoctets la session occupera. Assurez-vous que votre carte SD a assez d'espace.",
62
+ },
63
+ ];
64
+
65
+ const bibliography: TimelapseLocaleContent['bibliography'] = [
66
+ {
67
+ name: "Timescapes Forum - Digital Timelapse Acquisition & Processing",
68
+ url: "https://timescapes.org/phpBB3/viewforum.php?f=4",
69
+ },
70
+ {
71
+ name: "Magic Lantern - Auto ETTR & Bulb Ramping Algorithms",
72
+ url: "https://wiki.magiclantern.fm/ettr",
73
+ },
74
+ {
75
+ name: "LRTimelapse - Visual Deflicker & Holy Grail Workflow",
76
+ url: "https://lrtimelapse.com/tutorial/advanced/",
77
+ },
78
+ {
79
+ name: "PhotoPills - Advanced Timelapse Calculator & NPF Rule",
80
+ url: "https://www.photopills.com/calculators/timelapse",
81
+ },
82
+ ];
83
+
84
+ const seo: TimelapseLocaleContent['seo'] = [
85
+ { type: 'title', text: 'Guide Ultime des Intervalles Timelapse et Hyperlapse', level: 2 },
86
+ { type: 'paragraph', html: 'La différence entre une vidéo accélérée amateur et un <strong>timelapse cinématographique</strong> réside mathématiquement dans un seul facteur : <strong>l\'intervalle</strong>. Cette calculatrice élimine les devinettes, vous permettant de planifier avec précision la capture de levers de soleil, du trafic urbain ou de la Voie lactée.' },
87
+
88
+ { type: 'title', text: 'Tableau des Intervalles Recommandés (Aide-mémoire)', level: 3 },
89
+ { type: 'paragraph', html: 'Utilisez ce tableau de référence rapide pour régler votre intervallomètre en fonction du sujet.' },
90
+ { type: 'table', headers: ['Sujet / Scène', 'Intervalle Suggeré', 'Durée de l\'Événement (Minimum)'], rows: [
91
+ ['Nuages rapides / Orages', '1 - 2 secondes', '20 - 30 min'],
92
+ ['Trafic urbain / Personnes (Flou)', '0,5 - 2 secondes', '15 - 20 min'],
93
+ ['Coucher / Lever de soleil (Holy Grail)', '5 - 10 secondes', '1,5 - 2,5 heures'],
94
+ ['Nuages lents / Ombres', '10 - 15 secondes', '2 - 3 heures'],
95
+ ['Étoiles / Voie lactée (Astro)', '15 - 30 secondes*', '3 - 5 heures'],
96
+ ['Construction / Croissance rapide', '5 - 15 minutes', 'Jours / Semaines']
97
+ ]},
98
+ { type: 'tip', title: 'Note pour l\'Astro', html: 'L\'intervalle est généralement dicté par le temps d\'exposition nécessaire pour capter la lumière + 1 ou 2 secondes de tampon.' },
99
+
100
+ { type: 'title', text: 'La Règle des 180° (Motion Blur)', level: 3 },
101
+ { type: 'paragraph', html: 'Une erreur courante est d\'obtenir une vidéo "saccadée". Pour obtenir ce look cinématographique fluide, vous avez besoin de <strong>flou de mouvement</strong>.' },
102
+ { type: 'card', title: 'La Règle', icon: 'mdi:information', html: 'Votre vitesse d\'obturation doit être la moitié de votre intervalle. <br /><br /> <em>Exemple :</em> Si vous photographiez toutes les <strong>4 secondes</strong>, votre exposition devrait être de <strong>2 secondes</strong>.' },
103
+
104
+ { type: 'title', text: 'Flicker et Ouverture Manuelle', level: 3 },
105
+ { type: 'paragraph', html: 'Le "Flicker" est le clignotement gênant causé par des micro-variations de l\'ouverture du diaphragme entre les prises.' },
106
+ { type: 'list', items: [
107
+ '<strong>Lens Twist :</strong> Déverrouillez légèrement l\'objectif sur les reflex pour rompre la connexion électronique et fixer l\'ouverture mécaniquement.',
108
+ '<strong>Tout Manuel :</strong> ISO, Balance des Blancs et Mise au point doivent être fixes. N\'utilisez jamais de modes automatiques.',
109
+ '<strong>Photographiez en RAW :</strong> Essentiel pour corriger l\'exposition en post-production sans détruire l\'image.'
110
+ ]},
111
+
112
+ { type: 'diagnostic', variant: 'success', title: 'Technique Avancée : Le "Saint Graal"', icon: 'mdi:crown', badge: 'Technique Pro', html: 'On appelle "Saint Graal" la transition fluide du jour à la nuit (ou vice-versa). C\'est le défi technique le plus difficile car la lumière change radicalement.' },
113
+
114
+ { type: 'stats', columns: 3, items: [
115
+ { label: 'Bulb Ramping', value: 'Exposition Graduelle', icon: 'mdi:brightness-6' },
116
+ { label: 'Post-Pro', value: 'LRTimelapse', icon: 'mdi:television-guide' },
117
+ { label: 'Stratégie', value: 'Intervalle Nocturne', icon: 'mdi:weather-night' }
118
+ ]},
119
+
120
+ { type: 'title', text: 'Conclusion : Le Zen de la Mécanique Simple', level: 3 },
121
+ { type: 'paragraph', html: 'Maîtriser votre timelapse commence par comprendre les mathématiques de votre intervallomètre. Ne laissez pas un intervalle mal choisi gâcher votre session.' }
122
+ ];
123
+
124
+ const faqSchema: WithContext<FAQPage> = {
125
+ '@context': 'https://schema.org',
126
+ '@type': 'FAQPage',
127
+ mainEntity: faq.map((item) => ({
128
+ '@type': 'Question',
129
+ name: item.question,
130
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
131
+ })),
132
+ };
133
+
134
+ const howToSchema: WithContext<HowTo> = {
135
+ '@context': 'https://schema.org',
136
+ '@type': 'HowTo',
137
+ name: title,
138
+ description,
139
+ step: howTo.map((step) => ({
140
+ '@type': 'HowToStep',
141
+ name: step.name,
142
+ text: step.text,
143
+ })),
144
+ };
145
+
146
+ const appSchema: WithContext<SoftwareApplication> = {
147
+ '@context': 'https://schema.org',
148
+ '@type': 'SoftwareApplication',
149
+ name: title,
150
+ description,
151
+ applicationCategory: 'UtilitiesApplication',
152
+ operatingSystem: 'Web',
153
+ offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' },
154
+ inLanguage: 'fr',
155
+ };
156
+
157
+ export const content: TimelapseLocaleContent = {
158
+ slug,
159
+ title,
160
+ description,
161
+ ui,
162
+ seo,
163
+ faq,
164
+ faqTitle: 'Foire Aux Questions sur la Production de Timelapses',
165
+ bibliography,
166
+ bibliographyTitle: 'Théorie et Ressources sur le Timelapse',
167
+ howTo,
168
+ schemas: [faqSchema as any, howToSchema as any, appSchema],
169
+ };
@@ -0,0 +1,52 @@
1
+ import type { AudiovisualToolEntry, ToolLocaleContent, ToolDefinition } from '../../types';
2
+ import TimelapseCalculator from './component.astro';
3
+ import TimelapseSEO from './seo.astro';
4
+ import TimelapseBibliography from './bibliography.astro';
5
+
6
+ export interface TimelapseUI {
7
+ title: string;
8
+ paramsTitle: string;
9
+ eventDuration: string;
10
+ hours: string;
11
+ minutes: string;
12
+ videoDuration: string;
13
+ seconds: string;
14
+ fps: string;
15
+ resultsTitle: string;
16
+ intervalLabel: string;
17
+ secondsUnit: string;
18
+ totalPhotos: string;
19
+ speed: string;
20
+ shutterSpeed: string;
21
+ storage: string;
22
+ rule180Info: string;
23
+ [key: string]: string;
24
+ }
25
+
26
+ export type TimelapseLocaleContent = ToolLocaleContent<TimelapseUI>;
27
+
28
+ import { content as es } from './i18n/es';
29
+ import { content as en } from './i18n/en';
30
+ import { content as fr } from './i18n/fr';
31
+
32
+ export const timelapseCalculator: AudiovisualToolEntry<TimelapseUI> = {
33
+ id: 'timelapse-calculator',
34
+ icons: {
35
+ bg: 'mdi:camera-timer',
36
+ fg: 'mdi:clock-fast',
37
+ },
38
+ i18n: {
39
+ es: async () => es as unknown as TimelapseLocaleContent,
40
+ en: async () => en as unknown as TimelapseLocaleContent,
41
+ fr: async () => fr as unknown as TimelapseLocaleContent,
42
+ },
43
+ };
44
+
45
+ export { TimelapseCalculator, TimelapseSEO, TimelapseBibliography };
46
+
47
+ export const TIMELAPSE_CALCULATOR_TOOL: ToolDefinition = {
48
+ entry: timelapseCalculator as unknown as AudiovisualToolEntry,
49
+ Component: TimelapseCalculator,
50
+ SEOComponent: TimelapseSEO,
51
+ BibliographyComponent: TimelapseBibliography,
52
+ };
@@ -0,0 +1,46 @@
1
+ export const RAW_SIZE_MB = 25;
2
+ export const GB_CONVERSION = 1024;
3
+
4
+ export interface TimelapseResult {
5
+ interval: number;
6
+ totalFrames: number;
7
+ storageGB: number;
8
+ speedFactor: number;
9
+ shutterSpeed: number;
10
+ }
11
+
12
+ export const calculateTimelapse = (
13
+ eventDurationSecs: number,
14
+ videoTargetSecs: number,
15
+ fps: number
16
+ ): TimelapseResult => {
17
+ const totalFrames = videoTargetSecs * fps;
18
+ const interval =
19
+ totalFrames > 0 && eventDurationSecs > 0 ? eventDurationSecs / totalFrames : 0;
20
+
21
+ const rawSizeGB = (totalFrames * RAW_SIZE_MB) / GB_CONVERSION;
22
+ const speedFactor = videoTargetSecs > 0 ? eventDurationSecs / videoTargetSecs : 0;
23
+
24
+ const shutterSpeed = interval / 2;
25
+
26
+ return {
27
+ interval,
28
+ totalFrames: Math.floor(totalFrames),
29
+ storageGB: rawSizeGB,
30
+ speedFactor,
31
+ shutterSpeed,
32
+ };
33
+ };
34
+
35
+ export const formatTime = (seconds: number): string => {
36
+ const h = Math.floor(seconds / 3600)
37
+ .toString()
38
+ .padStart(2, "0");
39
+ const m = Math.floor((seconds % 3600) / 60)
40
+ .toString()
41
+ .padStart(2, "0");
42
+ const s = Math.floor(seconds % 60)
43
+ .toString()
44
+ .padStart(2, "0");
45
+ return h === "00" ? `${m}:${s}` : `${h}:${m}:${s}`;
46
+ };
@@ -0,0 +1,18 @@
1
+ ---
2
+ import { SEORenderer } from '@jjlmoya/utils-shared';
3
+ import { timelapseCalculator } 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 localeContentLoader = (timelapseCalculator.i18n as any)[locale];
12
+ const content = localeContentLoader ? await localeContentLoader() : null;
13
+ if (!content) return null;
14
+
15
+ const seoSections = content.seo;
16
+ ---
17
+
18
+ <SEORenderer content={{ locale, sections: seoSections || [] }} />