@jjlmoya/utils-drones 1.39.0 → 1.41.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.
- package/package.json +2 -2
- package/scripts/validate-icons.mjs +57 -0
- package/src/category/index.ts +2 -0
- package/src/entries.ts +4 -0
- package/src/index.ts +1 -0
- package/src/tests/locale_completeness.test.ts +2 -2
- package/src/tests/tool_validation.test.ts +2 -2
- package/src/tool/fpv-drone-lap-timer/audio.ts +160 -0
- package/src/tool/fpv-drone-lap-timer/bibliography.astro +6 -0
- package/src/tool/fpv-drone-lap-timer/bibliography.ts +14 -0
- package/src/tool/fpv-drone-lap-timer/bootstrap.ts +20 -0
- package/src/tool/fpv-drone-lap-timer/component.astro +136 -0
- package/src/tool/fpv-drone-lap-timer/contract.test.ts +24 -0
- package/src/tool/fpv-drone-lap-timer/controller.ts +304 -0
- package/src/tool/fpv-drone-lap-timer/dom-views.ts +213 -0
- package/src/tool/fpv-drone-lap-timer/entry.ts +27 -0
- package/src/tool/fpv-drone-lap-timer/export.ts +41 -0
- package/src/tool/fpv-drone-lap-timer/fpv-drone-lap-timer.css +705 -0
- package/src/tool/fpv-drone-lap-timer/i18n/de.ts +216 -0
- package/src/tool/fpv-drone-lap-timer/i18n/en.ts +216 -0
- package/src/tool/fpv-drone-lap-timer/i18n/es.ts +216 -0
- package/src/tool/fpv-drone-lap-timer/i18n/fr.ts +216 -0
- package/src/tool/fpv-drone-lap-timer/i18n/id.ts +216 -0
- package/src/tool/fpv-drone-lap-timer/i18n/it.ts +216 -0
- package/src/tool/fpv-drone-lap-timer/i18n/ja.ts +216 -0
- package/src/tool/fpv-drone-lap-timer/i18n/ko.ts +216 -0
- package/src/tool/fpv-drone-lap-timer/i18n/nl.ts +216 -0
- package/src/tool/fpv-drone-lap-timer/i18n/pl.ts +216 -0
- package/src/tool/fpv-drone-lap-timer/i18n/pt.ts +216 -0
- package/src/tool/fpv-drone-lap-timer/i18n/ru.ts +216 -0
- package/src/tool/fpv-drone-lap-timer/i18n/sv.ts +216 -0
- package/src/tool/fpv-drone-lap-timer/i18n/tr.ts +216 -0
- package/src/tool/fpv-drone-lap-timer/i18n/zh.ts +216 -0
- package/src/tool/fpv-drone-lap-timer/index.ts +10 -0
- package/src/tool/fpv-drone-lap-timer/logic.test.ts +152 -0
- package/src/tool/fpv-drone-lap-timer/logic.ts +228 -0
- package/src/tool/fpv-drone-lap-timer/seo.astro +16 -0
- package/src/tool/fpv-drone-lap-timer/storage.ts +52 -0
- package/src/tool/fpv-drone-lap-timer/ui.ts +58 -0
- package/src/tools.ts +3 -0
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import type { FpvDroneLapTimerLocaleContent } from '../entry';
|
|
2
|
+
import type { WithContext, SoftwareApplication, FAQPage, HowTo } from 'schema-dts';
|
|
3
|
+
import type { SEOSection } from '../../../types';
|
|
4
|
+
import { BIBLIOGRAPHY_ITEMS } from '../bibliography';
|
|
5
|
+
|
|
6
|
+
const slug = 'fpv-drohnen-renn-rundenzaehler';
|
|
7
|
+
const title = 'FPV Drohnen Rennen Runden und Split Timer';
|
|
8
|
+
const description = 'Interaktiver Rundentimer für FPV-Drohnenrennen mit FAI-Akustikstartsequenz, Split-Delta-Pacing, Rundenbestzeit-Warnungen, Rundenkonsistenzindex und Geschwindigkeitstelemetrie.';
|
|
9
|
+
|
|
10
|
+
const ui = {
|
|
11
|
+
setupHeading: 'Strecken- und Sitzungskonfiguration',
|
|
12
|
+
trackLengthLabel: 'Streckenlänge',
|
|
13
|
+
trackLengthUnit: 'Meter',
|
|
14
|
+
targetLapsLabel: 'Zielrundenzahl',
|
|
15
|
+
targetLapsUnit: 'Runden (0 für freies Training)',
|
|
16
|
+
batteryCapacityLabel: 'Akkukapazität',
|
|
17
|
+
batteryCapacityUnit: 'mAh',
|
|
18
|
+
soundEnabledLabel: 'Akustische Signale aktivieren',
|
|
19
|
+
debounceThresholdLabel: 'Rundenauslöser-Entprellung',
|
|
20
|
+
debounceThresholdUnit: 'Sekunden',
|
|
21
|
+
presetMultiGpLabel: 'MultiGP-Spezifikation (250m / 3 Runden)',
|
|
22
|
+
presetWhoopLabel: 'Tiny Whoop (65m / 5 Runden)',
|
|
23
|
+
presetSprintLabel: 'Hochgeschwindigkeitssprint (400m / 2 Runden)',
|
|
24
|
+
startCountdownButton: 'FAI-Startcountdown starten',
|
|
25
|
+
pauseTimerButton: 'Sitzung pausieren',
|
|
26
|
+
resumeTimerButton: 'Timer fortsetzen',
|
|
27
|
+
resetTimerButton: 'Sitzung zurücksetzen',
|
|
28
|
+
recordLapButton: 'RUNDE ERFASSEN',
|
|
29
|
+
spacebarHint: 'LEERTASTE drücken oder Riesentaste antippen, um den Zieldurchgang zu markieren',
|
|
30
|
+
statusIdle: 'Startbereit',
|
|
31
|
+
statusCountdown: 'FAI-Countdown läuft',
|
|
32
|
+
statusRunning: 'Renntimer aktiv',
|
|
33
|
+
statusPaused: 'Sitzung pausiert',
|
|
34
|
+
statusFinished: 'Rennen beendet',
|
|
35
|
+
currentLapHeading: 'Aktuelle Rundenzeit',
|
|
36
|
+
lapNumberPrefix: 'Runde',
|
|
37
|
+
lastLapHeading: 'Letzte Runde',
|
|
38
|
+
fastestLapHeading: 'Schnellste Runde',
|
|
39
|
+
averageLapHeading: 'Durchschnittliche Runde',
|
|
40
|
+
deltaBestHeading: 'Delta zur Bestzeit',
|
|
41
|
+
consistencyIndexHeading: 'Rundenkonsistenzindex',
|
|
42
|
+
estimatedSpeedHeading: 'Geschätzte Durchschnittsgeschwindigkeit',
|
|
43
|
+
estimatedBatteryHeading: 'Geschätzter Akkuverbrauch',
|
|
44
|
+
speedUnitKmh: 'km/h',
|
|
45
|
+
speedUnitMph: 'mph',
|
|
46
|
+
batteryUsedUnit: 'mAh',
|
|
47
|
+
batteryRemainingUnit: 'mAh verbleibend',
|
|
48
|
+
lapHistoryHeading: 'Rundenzeiten und Tempovergleich',
|
|
49
|
+
lapColumnHeader: 'Runde #',
|
|
50
|
+
timeColumnHeader: 'Rundenzeit',
|
|
51
|
+
splitColumnHeader: 'Delta zur Bestzeit',
|
|
52
|
+
speedColumnHeader: 'Durchschnittstempo',
|
|
53
|
+
batteryColumnHeader: 'Akkubedarf',
|
|
54
|
+
noLapsRecordedNotice: 'Noch keine Runden erfasst. Countdown starten und Leertaste oder Taste antippen, um die erste Runde zu protokollieren.',
|
|
55
|
+
consistencyRatingElite: 'Elite-Konsistenz',
|
|
56
|
+
consistencyRatingPro: 'Profi-Konsistenz',
|
|
57
|
+
consistencyRatingClub: 'Vereinsfahrer-Konsistenz',
|
|
58
|
+
consistencyRatingNovice: 'Trainings-Konsistenz',
|
|
59
|
+
fastestLapBadge: 'SCHNELLSTE RUNDE',
|
|
60
|
+
sessionSummaryHeading: 'Sitzungszusammenfassung & Export',
|
|
61
|
+
totalTimeLabel: 'Gesamtrenndauer',
|
|
62
|
+
completedLapsLabel: 'Absolvierte Runden',
|
|
63
|
+
exportCsvButton: 'Runden als CSV exportieren',
|
|
64
|
+
copySummaryButton: 'Textzusammenfassung kopieren',
|
|
65
|
+
copiedNotice: 'Sitzungszusammenfassung in die Zwischenablage kopiert!',
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const faqItems = [
|
|
69
|
+
{
|
|
70
|
+
question: 'Wie funktioniert die akustische FAI-Startsequenz in diesem Timer?',
|
|
71
|
+
answer: 'Die Startsequenz bildet die offiziellen F9U-Drohnenrennregeln der Fédération Aéronautique Internationale (FAI) CIAM nach. Vier vorbereitende Signaltöne im Sekundenabstand bereiten den Piloten vor, gefolgt von einem hohen Startsignal, das den Renntimer bei t = 0 startet.',
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
question: 'Wie wird der Rundenkonsistenzindex berechnet?',
|
|
75
|
+
answer: 'Der Konsistenzwert bewertet die Standardabweichung der gefahrenen Rundenzeiten im Verhältnis zur Durchschnittsrunde der Sitzung. Ein Wert über 95 Prozent steht für hervorragende Linientreue und feinfühlige Gasdosierung.',
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
question: 'Kann ein Fußschalter oder Schalter der Fernsteuerung genutzt werden?',
|
|
79
|
+
answer: 'Ja. Jede kabellose Tastatur, jedes Bluetooth-Fußpedal oder gamepad-basierte Makro, das das Drücken der Leertaste sendet, löst die Rundenzeitnahme sofort aus, ohne dass der Bildschirm berührt werden muss.',
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
question: 'Warum gibt es eine Entprellungszeit beim Auslösen?',
|
|
83
|
+
answer: 'Renntore werden mit hoher Geschwindigkeit passiert. Eine versehentliche Doppelauslösung könnte Fehlmessungen im Millisekundenbereich auslösen. Der Entprellungsfilter ignoriert Impulse unterhalb der definierten Schwelle (standardmäßig 3 Sekunden).',
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
question: 'Wie präzise ist die geschätzte Durchschnittsgeschwindigkeit?',
|
|
87
|
+
answer: 'Die Berechnung teilt die deklarierte Mittellinienstrecke durch die gemessene Rundenzeit. Die tatsächliche Drohnengeschwindigkeit variiert in Kurven je nach geflogener Linie und Schräglage.',
|
|
88
|
+
},
|
|
89
|
+
];
|
|
90
|
+
|
|
91
|
+
const howToSteps = [
|
|
92
|
+
{
|
|
93
|
+
name: 'Streckenlänge und Rundenanzahl festlegen',
|
|
94
|
+
text: 'Geben Sie die Rundenlänge in Metern und die Zielrundenzahl ein oder wählen Sie eine Vorlage wie MultiGP Spec.',
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
name: 'Akustischen FAI-Startcountdown initiieren',
|
|
98
|
+
text: 'Klicken Sie auf Countdown starten und lauschen Sie den 3 vorbereitenden Tönen und dem Startton.',
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
name: 'Runden beim Zieldurchgang erfassen',
|
|
102
|
+
text: 'Drücken Sie jedes Mal die Leertaste oder die Haupttaste, wenn die Drohne das Start-/Zieltor durchfliegt.',
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
name: 'Telemetrie, Deltazeiten und Konsistenz auswerten',
|
|
106
|
+
text: 'Überprüfen Sie das Balkendiagramm, die Rundenvergleiche und den Konsistenzwert und exportieren Sie nach CSV.',
|
|
107
|
+
},
|
|
108
|
+
];
|
|
109
|
+
|
|
110
|
+
const seoSections: SEOSection[] = [
|
|
111
|
+
{
|
|
112
|
+
type: 'title',
|
|
113
|
+
text: 'Grundlagen der hochpräzisen Rundenzeitnahme im FPV-Multirotor-Rennsport',
|
|
114
|
+
level: 2,
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
type: 'paragraph',
|
|
118
|
+
html: 'Wettbewerbsfähiges FPV-Drohnenracing verlangt Millisekunden-Präzision und außergewöhnliche Kurvenkonsistenz. 5-Zoll-Rennquads erreichen über 140 km/h zwischen 3D-Toren, Slalomstangen und Dive-Loops. Effektives Training erfordert sofortige akustische Rückmeldung am Start, exakte Rundenzeiten und Einblicke in den Leistungsabfall über mehrere Runden.',
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
type: 'title',
|
|
122
|
+
text: 'Vergleich gängiger Multirotor-Rennklassen und Timing-Parameter',
|
|
123
|
+
level: 2,
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
type: 'table',
|
|
127
|
+
headers: ['Klasse / Spezifikation', 'Typische Streckenlänge', 'Zielrunden', 'Durchschnittliche Rundenzeit', 'Spitzentempo', 'Empfohlene Entprellung'],
|
|
128
|
+
rows: [
|
|
129
|
+
['Tiny Whoop (65mm 1S)', '50m bis 80m', '5 Runden', '8.5s bis 13.0s', '35 bis 55 km/h', '2.0 Sekunden'],
|
|
130
|
+
['Micro 3.5-Zoll (4S)', '120m bis 180m', '4 Runden', '12.0s bis 18.0s', '70 bis 110 km/h', '2.5 Sekunden'],
|
|
131
|
+
['MultiGP Spec 5-Zoll (6S)', '200m bis 300m', '3 Runden', '14.0s bis 22.0s', '100 bis 150 km/h', '3.0 Sekunden'],
|
|
132
|
+
['Offenes Feldsprint (6S/8S)', '350m bis 500m', '2 Runden', '20.0s bis 32.0s', '130 bis 180 km/h', '4.0 Sekunden'],
|
|
133
|
+
],
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
type: 'title',
|
|
137
|
+
text: 'Akustische Startsequenzen und FAI F9U-Sportbestimmungen',
|
|
138
|
+
level: 2,
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
type: 'paragraph',
|
|
142
|
+
html: 'Gemäß FAI CIAM Sektion 4 für Drohnenrennen starten Wertungsläufe mit standardisierten Tönen statt Sichtflaggen, um faire Reaktionszeiten über die Videobrillen sicherzustellen. Die Sequenz umfasst Signaltöne im Sekundenrhythmus, gefolgt vom hohen Startton zum Scharfschalten.',
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
type: 'list',
|
|
146
|
+
items: [
|
|
147
|
+
'Vorbereitungstöne: Akustische Signale zum Stabilisieren der Gasstellung und vollen Konzentration.',
|
|
148
|
+
'Startton (Go): Sofortiger Startimpuls für die Zeitnahme bei t = 0.',
|
|
149
|
+
'Akustische Bestätigung: Klare Töne bestätigen den Rundenabschluss ohne Blickkontaktverlust.',
|
|
150
|
+
'Rundenbestzeit-Signal: Harmonischer Ton, sobald der bestehende Streckenrekord unterboten wird.',
|
|
151
|
+
],
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
type: 'title',
|
|
155
|
+
text: 'Rundenkonsistenzindex und strategisches Rennmanagement',
|
|
156
|
+
level: 2,
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
type: 'paragraph',
|
|
160
|
+
html: 'Eine einzelne Bestzeit begeistert, Meisterschaften gewinnt jedoch die Rundenkonstanz. Piloten mit weniger als 0.3 Sekunden Rundenabweichung halten das Propwash-Risiko gering und schonen die Akkuspannung für den Schlusssprint.',
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
type: 'tip',
|
|
164
|
+
title: 'Praxistipp für das Flugfeld',
|
|
165
|
+
html: 'Platzieren Sie das Timing-Tablet gut hörbar an der Pilotenstation. Ein Bluetooth-Fußtaster oder eine kleine Tastatur auf dem Koffer erlaubt das Auslösen per Fuß oder Daumen bei jedem Zieldurchflug.',
|
|
166
|
+
},
|
|
167
|
+
];
|
|
168
|
+
|
|
169
|
+
const schemas: FpvDroneLapTimerLocaleContent['schemas'] = [
|
|
170
|
+
{
|
|
171
|
+
'@context': 'https://schema.org',
|
|
172
|
+
'@type': 'FAQPage',
|
|
173
|
+
mainEntity: faqItems.map((item) => ({
|
|
174
|
+
'@type': 'Question',
|
|
175
|
+
name: item.question,
|
|
176
|
+
acceptedAnswer: { '@type': 'Answer', text: item.answer },
|
|
177
|
+
})),
|
|
178
|
+
} as WithContext<FAQPage>,
|
|
179
|
+
{
|
|
180
|
+
'@context': 'https://schema.org',
|
|
181
|
+
'@type': 'HowTo',
|
|
182
|
+
name: title,
|
|
183
|
+
description,
|
|
184
|
+
step: howToSteps.map((s, index) => ({
|
|
185
|
+
'@type': 'HowToStep',
|
|
186
|
+
position: index + 1,
|
|
187
|
+
name: s.name,
|
|
188
|
+
text: s.text,
|
|
189
|
+
})),
|
|
190
|
+
} as WithContext<HowTo>,
|
|
191
|
+
{
|
|
192
|
+
'@context': 'https://schema.org',
|
|
193
|
+
'@type': 'SoftwareApplication',
|
|
194
|
+
name: title,
|
|
195
|
+
description,
|
|
196
|
+
applicationCategory: 'UtilityApplication',
|
|
197
|
+
operatingSystem: 'All',
|
|
198
|
+
offers: {
|
|
199
|
+
'@type': 'Offer',
|
|
200
|
+
price: '0',
|
|
201
|
+
priceCurrency: 'EUR',
|
|
202
|
+
},
|
|
203
|
+
} as WithContext<SoftwareApplication>,
|
|
204
|
+
];
|
|
205
|
+
|
|
206
|
+
export const content: FpvDroneLapTimerLocaleContent = {
|
|
207
|
+
slug,
|
|
208
|
+
title,
|
|
209
|
+
description,
|
|
210
|
+
ui,
|
|
211
|
+
seo: seoSections,
|
|
212
|
+
faq: faqItems,
|
|
213
|
+
howTo: howToSteps,
|
|
214
|
+
bibliography: BIBLIOGRAPHY_ITEMS,
|
|
215
|
+
schemas,
|
|
216
|
+
};
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import type { FpvDroneLapTimerLocaleContent } from '../entry';
|
|
2
|
+
import type { WithContext, SoftwareApplication, FAQPage, HowTo } from 'schema-dts';
|
|
3
|
+
import type { SEOSection } from '../../../types';
|
|
4
|
+
import { BIBLIOGRAPHY_ITEMS } from '../bibliography';
|
|
5
|
+
|
|
6
|
+
const slug = 'fpv-drone-lap-timer';
|
|
7
|
+
const title = 'FPV Drone Race Lap and Split Timer';
|
|
8
|
+
const description = 'Interactive lap timer for FPV drone racing with FAI acoustic start sequence, split delta pacing, fastest lap alerts, lap consistency index, and speed telemetry.';
|
|
9
|
+
|
|
10
|
+
const ui = {
|
|
11
|
+
setupHeading: 'Track and Session Configuration',
|
|
12
|
+
trackLengthLabel: 'Track Circuit Length',
|
|
13
|
+
trackLengthUnit: 'meters',
|
|
14
|
+
targetLapsLabel: 'Target Laps Count',
|
|
15
|
+
targetLapsUnit: 'laps (0 for open practice)',
|
|
16
|
+
batteryCapacityLabel: 'Battery Pack Capacity',
|
|
17
|
+
batteryCapacityUnit: 'mAh',
|
|
18
|
+
soundEnabledLabel: 'Enable Acoustic Tones',
|
|
19
|
+
debounceThresholdLabel: 'Lap Trigger Debounce Guard',
|
|
20
|
+
debounceThresholdUnit: 'seconds',
|
|
21
|
+
presetMultiGpLabel: 'MultiGP Spec (250m / 3 Laps)',
|
|
22
|
+
presetWhoopLabel: 'Tiny Whoop (65m / 5 Laps)',
|
|
23
|
+
presetSprintLabel: 'High Speed Sprint (400m / 2 Laps)',
|
|
24
|
+
startCountdownButton: 'Start FAI Race Countdown',
|
|
25
|
+
pauseTimerButton: 'Pause Session',
|
|
26
|
+
resumeTimerButton: 'Resume Timer',
|
|
27
|
+
resetTimerButton: 'Reset Session',
|
|
28
|
+
recordLapButton: 'RECORD LAP',
|
|
29
|
+
spacebarHint: 'Press SPACEBAR or tap the giant button to mark lap finish',
|
|
30
|
+
statusIdle: 'Ready for Start',
|
|
31
|
+
statusCountdown: 'FAI Countdown in Progress',
|
|
32
|
+
statusRunning: 'Race Timer Active',
|
|
33
|
+
statusPaused: 'Session Paused',
|
|
34
|
+
statusFinished: 'Race Completed',
|
|
35
|
+
currentLapHeading: 'Current Lap Time',
|
|
36
|
+
lapNumberPrefix: 'Lap',
|
|
37
|
+
lastLapHeading: 'Last Lap',
|
|
38
|
+
fastestLapHeading: 'Fastest Lap',
|
|
39
|
+
averageLapHeading: 'Average Lap',
|
|
40
|
+
deltaBestHeading: 'Delta to Session Best',
|
|
41
|
+
consistencyIndexHeading: 'Lap Consistency Index',
|
|
42
|
+
estimatedSpeedHeading: 'Estimated Average Speed',
|
|
43
|
+
estimatedBatteryHeading: 'Estimated Battery Used',
|
|
44
|
+
speedUnitKmh: 'km/h',
|
|
45
|
+
speedUnitMph: 'mph',
|
|
46
|
+
batteryUsedUnit: 'mAh',
|
|
47
|
+
batteryRemainingUnit: 'mAh remaining',
|
|
48
|
+
lapHistoryHeading: 'Lap Times and Pace Comparison',
|
|
49
|
+
lapColumnHeader: 'Lap #',
|
|
50
|
+
timeColumnHeader: 'Lap Time',
|
|
51
|
+
splitColumnHeader: 'Delta to Best',
|
|
52
|
+
speedColumnHeader: 'Average Speed',
|
|
53
|
+
batteryColumnHeader: 'Est. Battery Drain',
|
|
54
|
+
noLapsRecordedNotice: 'No laps recorded yet. Start the countdown and press Spacebar or tap to register your first lap.',
|
|
55
|
+
consistencyRatingElite: 'Elite Consistency',
|
|
56
|
+
consistencyRatingPro: 'Pro Racer Consistency',
|
|
57
|
+
consistencyRatingClub: 'Club Racer Consistency',
|
|
58
|
+
consistencyRatingNovice: 'Training Consistency',
|
|
59
|
+
fastestLapBadge: 'FASTEST LAP',
|
|
60
|
+
sessionSummaryHeading: 'Session Summary & Export',
|
|
61
|
+
totalTimeLabel: 'Total Race Duration',
|
|
62
|
+
completedLapsLabel: 'Completed Laps',
|
|
63
|
+
exportCsvButton: 'Export Laps to CSV',
|
|
64
|
+
copySummaryButton: 'Copy Text Summary',
|
|
65
|
+
copiedNotice: 'Session summary copied to clipboard!',
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const faqItems = [
|
|
69
|
+
{
|
|
70
|
+
question: 'How does the FAI acoustic start sequence work in this timer?',
|
|
71
|
+
answer: 'The start sequence mirrors official Fédération Aéronautique Internationale (FAI) CIAM F9U drone racing rules. Four distinct countdown beeps spaced one second apart prepare the pilot, followed by an immediate high-frequency buzzer tone signaling the race start and triggering timer zero.',
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
question: 'How is the Lap Consistency Index calculated?',
|
|
75
|
+
answer: 'The consistency score evaluates the standard deviation of your completed lap times relative to your session average lap time. A score above 95 percent represents exceptional line consistency, while wider fluctuations indicate throttle or line inconsistency.',
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
question: 'Can I use a physical controller or flight radio button to trigger laps?',
|
|
79
|
+
answer: 'Yes. Any wireless keyboard, Bluetooth foot pedal, or mapped gamepad switch that sends a Spacebar keypress will trigger lap recording instantly without requiring you to look at or touch the screen.',
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
question: 'Why is there a debounce guard on the lap record button?',
|
|
83
|
+
answer: 'FPV race gates are traversed in seconds, but accidental double-touches or switch bounce can register false split-second laps. The debounce guard rejects triggers occurring under a user-defined threshold (default 3 seconds).',
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
question: 'How accurate is the estimated average speed calculation?',
|
|
87
|
+
answer: 'The speed estimate calculates the linear velocity based on the declared track center-line length divided by the recorded lap duration. Actual drone speed through corners will vary based on racing line radius and banking angle.',
|
|
88
|
+
},
|
|
89
|
+
];
|
|
90
|
+
|
|
91
|
+
const howToSteps = [
|
|
92
|
+
{
|
|
93
|
+
name: 'Set Track Length and Practice Mode',
|
|
94
|
+
text: 'Enter your track circuit length in meters and target lap count, or choose a preset like MultiGP Spec or Tiny Whoop.',
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
name: 'Initiate FAI Acoustic Start Countdown',
|
|
98
|
+
text: 'Click Start Countdown. Listen to the 4 preparatory beeps followed by the high-pitch tone at race start.',
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
name: 'Record Laps as You Cross the Finish Gate',
|
|
102
|
+
text: 'Tap the giant on-screen trigger button or tap Spacebar on your keyboard each time your drone clears the start/finish gate.',
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
name: 'Analyze Telemetry, Splits, and Consistency',
|
|
106
|
+
text: 'Inspect the pace comparison chart, split deltas, and consistency index score, then export your telemetry data to CSV.',
|
|
107
|
+
},
|
|
108
|
+
];
|
|
109
|
+
|
|
110
|
+
const seoSections: SEOSection[] = [
|
|
111
|
+
{
|
|
112
|
+
type: 'title',
|
|
113
|
+
text: 'Principles of High-Precision Lap Timing in FPV Multirotor Drone Racing',
|
|
114
|
+
level: 2,
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
type: 'paragraph',
|
|
118
|
+
html: 'Competitive FPV drone racing demands sub-second precision and unflinching line consistency. Pilots piloting 5-inch multirotors reach speeds in excess of 140 km/h through complex three-dimensional gates, flags, and dive loops. Training effectively requires immediate auditory feedback at the start line, split-second lap marking, and analytical insight into pace degradation across multi-lap heats.',
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
type: 'title',
|
|
122
|
+
text: 'Comparison of Multirotor Racing Track Classes and Timing Parameters',
|
|
123
|
+
level: 2,
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
type: 'table',
|
|
127
|
+
headers: ['Class / Spec', 'Typical Circuit Length', 'Target Heat Laps', 'Average Lap Time', 'Top Speed Range', 'Recommended Debounce'],
|
|
128
|
+
rows: [
|
|
129
|
+
['Tiny Whoop (65mm 1S)', '50m to 80m', '5 laps', '8.5s to 13.0s', '35 to 55 km/h', '2.0 seconds'],
|
|
130
|
+
['Micro 3.5-Inch (4S)', '120m to 180m', '4 laps', '12.0s to 18.0s', '70 to 110 km/h', '2.5 seconds'],
|
|
131
|
+
['MultiGP Spec 5-Inch (6S)', '200m to 300m', '3 laps', '14.0s to 22.0s', '100 to 150 km/h', '3.0 seconds'],
|
|
132
|
+
['Open Field Sprint (6S/8S)', '350m to 500m', '2 laps', '20.0s to 32.0s', '130 to 180 km/h', '4.0 seconds'],
|
|
133
|
+
],
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
type: 'title',
|
|
137
|
+
text: 'Acoustic Countdown Sequences and FAI F9U Sporting Regulations',
|
|
138
|
+
level: 2,
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
type: 'paragraph',
|
|
142
|
+
html: 'Under the Fédération Aéronautique Internationale (FAI) CIAM Section 4 regulations for drone racing, races commence with standardized acoustic signals rather than visual flags to ensure equitable pilot reaction times across video goggles. The standard countdown consists of four 440 Hz tones at one-second intervals, culminating in a 880 Hz high tone upon which pilots arm and launch.',
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
type: 'list',
|
|
146
|
+
items: [
|
|
147
|
+
'Tone 1 to 4: Pre-arm acoustic alerts for pilots to settle throttle positions and establish situational focus.',
|
|
148
|
+
'Tone 5 (Go): Instant launch signal where timing registers immediately at t = 0.',
|
|
149
|
+
'Acoustic Confirmation: High-contrast audio chirps verify lap registration without forcing pilots to break goggle line-of-sight.',
|
|
150
|
+
'Personal Best Chime: Harmonic alert triggers when the current lap beats the existing session benchmark.',
|
|
151
|
+
],
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
type: 'title',
|
|
155
|
+
text: 'Understanding the Lap Consistency Index and Race Strategy',
|
|
156
|
+
level: 2,
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
type: 'paragraph',
|
|
160
|
+
html: 'While setting a blistering single lap is thrilling, multirotor championship heats are won by consistency. The Lap Consistency Index quantifies variance across heats. A pilot whose laps vary by less than 0.3 seconds maintains smooth throttle management, avoids turbulent propwash lines, and preserves battery voltage for the final sprint.',
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
type: 'tip',
|
|
164
|
+
title: 'Field Practice Tip for Gate Timing',
|
|
165
|
+
html: 'Position your timing tablet or mobile phone within clear audio reach near your pilot station. Use a Bluetooth media button or wireless keyboard resting on your flight case to trigger laps effortlessly with your foot or thumb.',
|
|
166
|
+
},
|
|
167
|
+
];
|
|
168
|
+
|
|
169
|
+
const schemas: FpvDroneLapTimerLocaleContent['schemas'] = [
|
|
170
|
+
{
|
|
171
|
+
'@context': 'https://schema.org',
|
|
172
|
+
'@type': 'FAQPage',
|
|
173
|
+
mainEntity: faqItems.map((item) => ({
|
|
174
|
+
'@type': 'Question',
|
|
175
|
+
name: item.question,
|
|
176
|
+
acceptedAnswer: { '@type': 'Answer', text: item.answer },
|
|
177
|
+
})),
|
|
178
|
+
} as WithContext<FAQPage>,
|
|
179
|
+
{
|
|
180
|
+
'@context': 'https://schema.org',
|
|
181
|
+
'@type': 'HowTo',
|
|
182
|
+
name: title,
|
|
183
|
+
description,
|
|
184
|
+
step: howToSteps.map((s, index) => ({
|
|
185
|
+
'@type': 'HowToStep',
|
|
186
|
+
position: index + 1,
|
|
187
|
+
name: s.name,
|
|
188
|
+
text: s.text,
|
|
189
|
+
})),
|
|
190
|
+
} as WithContext<HowTo>,
|
|
191
|
+
{
|
|
192
|
+
'@context': 'https://schema.org',
|
|
193
|
+
'@type': 'SoftwareApplication',
|
|
194
|
+
name: title,
|
|
195
|
+
description,
|
|
196
|
+
applicationCategory: 'UtilityApplication',
|
|
197
|
+
operatingSystem: 'All',
|
|
198
|
+
offers: {
|
|
199
|
+
'@type': 'Offer',
|
|
200
|
+
price: '0',
|
|
201
|
+
priceCurrency: 'USD',
|
|
202
|
+
},
|
|
203
|
+
} as WithContext<SoftwareApplication>,
|
|
204
|
+
];
|
|
205
|
+
|
|
206
|
+
export const content: FpvDroneLapTimerLocaleContent = {
|
|
207
|
+
slug,
|
|
208
|
+
title,
|
|
209
|
+
description,
|
|
210
|
+
ui,
|
|
211
|
+
seo: seoSections,
|
|
212
|
+
faq: faqItems,
|
|
213
|
+
howTo: howToSteps,
|
|
214
|
+
bibliography: BIBLIOGRAPHY_ITEMS,
|
|
215
|
+
schemas,
|
|
216
|
+
};
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import type { FpvDroneLapTimerLocaleContent } from '../entry';
|
|
2
|
+
import type { WithContext, SoftwareApplication, FAQPage, HowTo } from 'schema-dts';
|
|
3
|
+
import type { SEOSection } from '../../../types';
|
|
4
|
+
import { BIBLIOGRAPHY_ITEMS } from '../bibliography';
|
|
5
|
+
|
|
6
|
+
const slug = 'cronometro-vueltas-dron-fpv';
|
|
7
|
+
const title = 'Cronómetro de Vueltas y Splits para Carreras de Drones FPV';
|
|
8
|
+
const description = 'Cronómetro interactivo para carreras de drones FPV con secuencia acústica de salida FAI, ritmo de splits, avisos de vuelta rápida, índice de consistencia y telemetría de velocidad.';
|
|
9
|
+
|
|
10
|
+
const ui = {
|
|
11
|
+
setupHeading: 'Configuración de Pista y Sesión',
|
|
12
|
+
trackLengthLabel: 'Longitud del Circuito',
|
|
13
|
+
trackLengthUnit: 'metros',
|
|
14
|
+
targetLapsLabel: 'Número Objetivo de Vueltas',
|
|
15
|
+
targetLapsUnit: 'vueltas (0 para práctica abierta)',
|
|
16
|
+
batteryCapacityLabel: 'Capacidad de la Batería',
|
|
17
|
+
batteryCapacityUnit: 'mAh',
|
|
18
|
+
soundEnabledLabel: 'Activar Tonos Acústicos',
|
|
19
|
+
debounceThresholdLabel: 'Protección Antirrebote de Vuelta',
|
|
20
|
+
debounceThresholdUnit: 'segundos',
|
|
21
|
+
presetMultiGpLabel: 'MultiGP Spec (250m / 3 Vueltas)',
|
|
22
|
+
presetWhoopLabel: 'Tiny Whoop (65m / 5 Vueltas)',
|
|
23
|
+
presetSprintLabel: 'Sprint de Alta Velocidad (400m / 2 Vueltas)',
|
|
24
|
+
startCountdownButton: 'Iniciar Cuenta Atrás FAI',
|
|
25
|
+
pauseTimerButton: 'Pausar Sesión',
|
|
26
|
+
resumeTimerButton: 'Reanudar Cronómetro',
|
|
27
|
+
resetTimerButton: 'Reiniciar Sesión',
|
|
28
|
+
recordLapButton: 'MARCAR VUELTA',
|
|
29
|
+
spacebarHint: 'Pulsa la BARRA ESPACIADORA o toca el botón gigante para registrar el paso por meta',
|
|
30
|
+
statusIdle: 'Listo para Salida',
|
|
31
|
+
statusCountdown: 'Cuenta Atrás FAI en Progreso',
|
|
32
|
+
statusRunning: 'Cronómetro de Carrera Activo',
|
|
33
|
+
statusPaused: 'Sesión Pausada',
|
|
34
|
+
statusFinished: 'Carrera Completada',
|
|
35
|
+
currentLapHeading: 'Tiempo de Vuelta Actual',
|
|
36
|
+
lapNumberPrefix: 'Vuelta',
|
|
37
|
+
lastLapHeading: 'Última Vuelta',
|
|
38
|
+
fastestLapHeading: 'Mejor Vuelta',
|
|
39
|
+
averageLapHeading: 'Vuelta Media',
|
|
40
|
+
deltaBestHeading: 'Diferencia con Mejor Vuelta',
|
|
41
|
+
consistencyIndexHeading: 'Índice de Consistencia',
|
|
42
|
+
estimatedSpeedHeading: 'Velocidad Media Estimada',
|
|
43
|
+
estimatedBatteryHeading: 'Batería Estimada Usada',
|
|
44
|
+
speedUnitKmh: 'km/h',
|
|
45
|
+
speedUnitMph: 'mph',
|
|
46
|
+
batteryUsedUnit: 'mAh',
|
|
47
|
+
batteryRemainingUnit: 'mAh restantes',
|
|
48
|
+
lapHistoryHeading: 'Tiempos de Vuelta y Comparación de Ritmo',
|
|
49
|
+
lapColumnHeader: 'Vuelta #',
|
|
50
|
+
timeColumnHeader: 'Tiempo',
|
|
51
|
+
splitColumnHeader: 'Diferencia Mejor',
|
|
52
|
+
speedColumnHeader: 'Velocidad Media',
|
|
53
|
+
batteryColumnHeader: 'Consumo Batería',
|
|
54
|
+
noLapsRecordedNotice: 'Aún no hay vueltas registradas. Inicia la cuenta atrás y pulsa la barra espaciadora o el botón para registrar tu primera vuelta.',
|
|
55
|
+
consistencyRatingElite: 'Consistencia Élite',
|
|
56
|
+
consistencyRatingPro: 'Consistencia Profesional',
|
|
57
|
+
consistencyRatingClub: 'Consistencia Club',
|
|
58
|
+
consistencyRatingNovice: 'Consistencia en Entrenamiento',
|
|
59
|
+
fastestLapBadge: 'MEJOR VUELTA',
|
|
60
|
+
sessionSummaryHeading: 'Resumen de Sesión y Exportación',
|
|
61
|
+
totalTimeLabel: 'Duración Total de Carrera',
|
|
62
|
+
completedLapsLabel: 'Vueltas Completadas',
|
|
63
|
+
exportCsvButton: 'Exportar Vueltas a CSV',
|
|
64
|
+
copySummaryButton: 'Copiar Resumen de Texto',
|
|
65
|
+
copiedNotice: '¡Resumen de sesión copiado al portapapeles!',
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const faqItems = [
|
|
69
|
+
{
|
|
70
|
+
question: '¿Cómo funciona la secuencia acústica de salida FAI en este cronómetro?',
|
|
71
|
+
answer: 'La secuencia de salida reproduce el reglamento oficial de carreras de drones F9U de la Federación Aeronáutica Internacional (FAI). Se emiten cuatro pitidos preparatorios separados por un segundo, seguidos de un tono agudo inmediato tipo chicharra que marca la salida y activa el cronómetro en cero.',
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
question: '¿Cómo se calcula el Índice de Consistencia de Vuelta?',
|
|
75
|
+
answer: 'La puntuación de consistencia evalúa la desviación estándar de tus vueltas completadas respecto a la media de la sesión. Una puntuación superior al 95 por ciento representa una trazada y gestión de gas sumamente precisa, mientras que valores inferiores evidencian dispersión en el ritmo.',
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
question: '¿Puedo usar un pedal físico o un mando de radio para marcar las vueltas?',
|
|
79
|
+
answer: 'Sí. Cualquier teclado inalámbrico, pedal Bluetooth o pulsador de emisora configurado para enviar la pulsación de la barra espaciadora registrará la vuelta al instante sin necesidad de mirar ni tocar la pantalla.',
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
question: '¿Por qué hay un filtro antirrebote en el botón de vuelta?',
|
|
83
|
+
answer: 'En FPV las puertas se cruzan a gran velocidad, pero una doble pulsación accidental o el rebote de un interruptor podrían registrar falsas vueltas de fracciones de segundo. El antirrebote descarta activaciones que ocurran antes del umbral definido (3 segundos por defecto).',
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
question: '¿Qué precisión tiene la velocidad media estimada?',
|
|
87
|
+
answer: 'El cálculo divide la distancia longitudinal declarada del centro de pista entre el tiempo de vuelta. La velocidad real del dron en curvas variará según el radio de trazada y el ángulo de alabeo en cada sector.',
|
|
88
|
+
},
|
|
89
|
+
];
|
|
90
|
+
|
|
91
|
+
const howToSteps = [
|
|
92
|
+
{
|
|
93
|
+
name: 'Configura la distancia de pista y el objetivo',
|
|
94
|
+
text: 'Introduce la longitud del circuito en metros y el número de vueltas objetivo, o elige un preajuste como MultiGP Spec o Tiny Whoop.',
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
name: 'Inicia la cuenta atrás acústica FAI',
|
|
98
|
+
text: 'Haz clic en Iniciar Cuenta Atrás. Escucha los cuatro tonos preparatorios y el tono agudo de salida que arranca el cronómetro.',
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
name: 'Registra cada vuelta al cruzar la puerta de meta',
|
|
102
|
+
text: 'Pulsa el botón gigante en pantalla o presiona la barra espaciadora cada vez que el dron cruce la puerta de salida y meta.',
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
name: 'Analiza la telemetría, deltas y consistencia',
|
|
106
|
+
text: 'Examina la gráfica de ritmo, las diferencias respecto a la mejor vuelta y la puntuación de consistencia, y luego exporta a CSV.',
|
|
107
|
+
},
|
|
108
|
+
];
|
|
109
|
+
|
|
110
|
+
const seoSections: SEOSection[] = [
|
|
111
|
+
{
|
|
112
|
+
type: 'title',
|
|
113
|
+
text: 'Fundamentos de la Cronometración de Alta Precisión en Carreras de Drones FPV',
|
|
114
|
+
level: 2,
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
type: 'paragraph',
|
|
118
|
+
html: 'La competición en carreras de drones multirotor FPV exige precisión de milisegundos y una consistencia de trazada rigurosa. Los pilotos que manejan drones de 5 pulgadas alcanzan velocidades superiores a los 140 km/h sorteando puertas tridimensionales, banderas y loops en picado. Entrenar de forma óptima requiere retroalimentación acústica en la salida, registro de pasos por meta y análisis de la degradación de ritmo a lo largo de las mangas.',
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
type: 'title',
|
|
122
|
+
text: 'Comparativa de Clases de Circuitos Multirrotor y Parámetros de Cronometraje',
|
|
123
|
+
level: 2,
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
type: 'table',
|
|
127
|
+
headers: ['Clase / Categoría', 'Longitud Típica de Pista', 'Vueltas Objetivo', 'Tiempo Medio por Vuelta', 'Rango de Velocidad Máxima', 'Antirrebote Sugerido'],
|
|
128
|
+
rows: [
|
|
129
|
+
['Tiny Whoop (65mm 1S)', '50m a 80m', '5 vueltas', '8.5s a 13.0s', '35 a 55 km/h', '2.0 segundos'],
|
|
130
|
+
['Micro 3.5 Pulgadas (4S)', '120m a 180m', '4 vueltas', '12.0s a 18.0s', '70 a 110 km/h', '2.5 segundos'],
|
|
131
|
+
['MultiGP Spec 5 Pulgadas (6S)', '200m a 300m', '3 vueltas', '14.0s a 22.0s', '100 a 150 km/h', '3.0 segundos'],
|
|
132
|
+
['Sprint Abierto en Campo (6S/8S)', '350m a 500m', '2 vueltas', '20.0s a 32.0s', '130 a 180 km/h', '4.0 segundos'],
|
|
133
|
+
],
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
type: 'title',
|
|
137
|
+
text: 'Secuencias Acústicas de Salida y Reglamentación Deportiva FAI F9U',
|
|
138
|
+
level: 2,
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
type: 'paragraph',
|
|
142
|
+
html: 'Bajo el reglamento FAI CIAM Sección 4 para carreras de drones, las mangas inician con señales sonoras estandarizadas en lugar de banderas visuales para garantizar tiempos de reacción idénticos a través de las gafas FPV. La secuencia consiste en tonos a 440 Hz a intervalos de un segundo, culminando en un tono de 880 Hz donde los pilotos arman motores y despegan.',
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
type: 'list',
|
|
146
|
+
items: [
|
|
147
|
+
'Tonos preparatorios: Alertas sonoras para fijar posición de acelerador y concentración en el trazado.',
|
|
148
|
+
'Tono de Salida (Go): Señal instantánea que inicia el cronometraje exactamente en t = 0.',
|
|
149
|
+
'Confirmación Sonora: Pitidos acústicos que verifican el paso por meta sin apartar la mirada de las gafas.',
|
|
150
|
+
'Aviso de Vuelta Rápida: Tono armónico especial cuando la vuelta actual supera el récord de la sesión.',
|
|
151
|
+
],
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
type: 'title',
|
|
155
|
+
text: 'Comprendiendo el Índice de Consistencia y la Estrategia de Carrera',
|
|
156
|
+
level: 2,
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
type: 'paragraph',
|
|
160
|
+
html: 'Aunque marcar una vuelta rápida aislada es gratificante, los campeonatos de drones se ganan por consistencia. El índice evalúa la desviación entre vueltas: un piloto que varía menos de 0.3 segundos gestiona mejor el acelerador, evita turbulencias de hélices ajenas y preserva el voltaje de la batería para el sprint final.',
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
type: 'tip',
|
|
164
|
+
title: 'Consejo para Entrenar en el Campo de Vuelo',
|
|
165
|
+
html: 'Coloca tu teléfono o tablet con buen volumen cerca de tu estación de pilotaje. Utiliza un pulsador Bluetooth o un teclado inalámbrico sobre tu maleta de vuelo para pulsar con el pie o el pulgar cada vez que pases por meta.',
|
|
166
|
+
},
|
|
167
|
+
];
|
|
168
|
+
|
|
169
|
+
const schemas: FpvDroneLapTimerLocaleContent['schemas'] = [
|
|
170
|
+
{
|
|
171
|
+
'@context': 'https://schema.org',
|
|
172
|
+
'@type': 'FAQPage',
|
|
173
|
+
mainEntity: faqItems.map((item) => ({
|
|
174
|
+
'@type': 'Question',
|
|
175
|
+
name: item.question,
|
|
176
|
+
acceptedAnswer: { '@type': 'Answer', text: item.answer },
|
|
177
|
+
})),
|
|
178
|
+
} as WithContext<FAQPage>,
|
|
179
|
+
{
|
|
180
|
+
'@context': 'https://schema.org',
|
|
181
|
+
'@type': 'HowTo',
|
|
182
|
+
name: title,
|
|
183
|
+
description,
|
|
184
|
+
step: howToSteps.map((s, index) => ({
|
|
185
|
+
'@type': 'HowToStep',
|
|
186
|
+
position: index + 1,
|
|
187
|
+
name: s.name,
|
|
188
|
+
text: s.text,
|
|
189
|
+
})),
|
|
190
|
+
} as WithContext<HowTo>,
|
|
191
|
+
{
|
|
192
|
+
'@context': 'https://schema.org',
|
|
193
|
+
'@type': 'SoftwareApplication',
|
|
194
|
+
name: title,
|
|
195
|
+
description,
|
|
196
|
+
applicationCategory: 'UtilityApplication',
|
|
197
|
+
operatingSystem: 'All',
|
|
198
|
+
offers: {
|
|
199
|
+
'@type': 'Offer',
|
|
200
|
+
price: '0',
|
|
201
|
+
priceCurrency: 'EUR',
|
|
202
|
+
},
|
|
203
|
+
} as WithContext<SoftwareApplication>,
|
|
204
|
+
];
|
|
205
|
+
|
|
206
|
+
export const content: FpvDroneLapTimerLocaleContent = {
|
|
207
|
+
slug,
|
|
208
|
+
title,
|
|
209
|
+
description,
|
|
210
|
+
ui,
|
|
211
|
+
seo: seoSections,
|
|
212
|
+
faq: faqItems,
|
|
213
|
+
howTo: howToSteps,
|
|
214
|
+
bibliography: BIBLIOGRAPHY_ITEMS,
|
|
215
|
+
schemas,
|
|
216
|
+
};
|