@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.
Files changed (40) hide show
  1. package/package.json +2 -2
  2. package/scripts/validate-icons.mjs +57 -0
  3. package/src/category/index.ts +2 -0
  4. package/src/entries.ts +4 -0
  5. package/src/index.ts +1 -0
  6. package/src/tests/locale_completeness.test.ts +2 -2
  7. package/src/tests/tool_validation.test.ts +2 -2
  8. package/src/tool/fpv-drone-lap-timer/audio.ts +160 -0
  9. package/src/tool/fpv-drone-lap-timer/bibliography.astro +6 -0
  10. package/src/tool/fpv-drone-lap-timer/bibliography.ts +14 -0
  11. package/src/tool/fpv-drone-lap-timer/bootstrap.ts +20 -0
  12. package/src/tool/fpv-drone-lap-timer/component.astro +136 -0
  13. package/src/tool/fpv-drone-lap-timer/contract.test.ts +24 -0
  14. package/src/tool/fpv-drone-lap-timer/controller.ts +304 -0
  15. package/src/tool/fpv-drone-lap-timer/dom-views.ts +213 -0
  16. package/src/tool/fpv-drone-lap-timer/entry.ts +27 -0
  17. package/src/tool/fpv-drone-lap-timer/export.ts +41 -0
  18. package/src/tool/fpv-drone-lap-timer/fpv-drone-lap-timer.css +705 -0
  19. package/src/tool/fpv-drone-lap-timer/i18n/de.ts +216 -0
  20. package/src/tool/fpv-drone-lap-timer/i18n/en.ts +216 -0
  21. package/src/tool/fpv-drone-lap-timer/i18n/es.ts +216 -0
  22. package/src/tool/fpv-drone-lap-timer/i18n/fr.ts +216 -0
  23. package/src/tool/fpv-drone-lap-timer/i18n/id.ts +216 -0
  24. package/src/tool/fpv-drone-lap-timer/i18n/it.ts +216 -0
  25. package/src/tool/fpv-drone-lap-timer/i18n/ja.ts +216 -0
  26. package/src/tool/fpv-drone-lap-timer/i18n/ko.ts +216 -0
  27. package/src/tool/fpv-drone-lap-timer/i18n/nl.ts +216 -0
  28. package/src/tool/fpv-drone-lap-timer/i18n/pl.ts +216 -0
  29. package/src/tool/fpv-drone-lap-timer/i18n/pt.ts +216 -0
  30. package/src/tool/fpv-drone-lap-timer/i18n/ru.ts +216 -0
  31. package/src/tool/fpv-drone-lap-timer/i18n/sv.ts +216 -0
  32. package/src/tool/fpv-drone-lap-timer/i18n/tr.ts +216 -0
  33. package/src/tool/fpv-drone-lap-timer/i18n/zh.ts +216 -0
  34. package/src/tool/fpv-drone-lap-timer/index.ts +10 -0
  35. package/src/tool/fpv-drone-lap-timer/logic.test.ts +152 -0
  36. package/src/tool/fpv-drone-lap-timer/logic.ts +228 -0
  37. package/src/tool/fpv-drone-lap-timer/seo.astro +16 -0
  38. package/src/tool/fpv-drone-lap-timer/storage.ts +52 -0
  39. package/src/tool/fpv-drone-lap-timer/ui.ts +58 -0
  40. 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-drone-lap-timer';
7
+ const title = 'FPVドローンレース ラップ&スプリットタイマー';
8
+ const description = 'FAI音響スタートシーケンス、区間スプリット差分、最速ラップ通知、ラップ一貫性指数、速度テレメトリを備えたFPVドローンレース用インタラクティブタイマー。';
9
+
10
+ const ui = {
11
+ setupHeading: 'コースとセッション設定',
12
+ trackLengthLabel: 'コース全長',
13
+ trackLengthUnit: 'メートル',
14
+ targetLapsLabel: '目標ラップ数',
15
+ targetLapsUnit: 'ラップ (0でフリー練習)',
16
+ batteryCapacityLabel: 'バッテリー容量',
17
+ batteryCapacityUnit: 'mAh',
18
+ soundEnabledLabel: '音響シグナルを有効化',
19
+ debounceThresholdLabel: '二重押し防止ガード時間',
20
+ debounceThresholdUnit: '秒',
21
+ presetMultiGpLabel: 'MultiGP仕様 (250m / 3周)',
22
+ presetWhoopLabel: 'Tiny Whoop (65m / 5周)',
23
+ presetSprintLabel: '高速スプリント (400m / 2周)',
24
+ startCountdownButton: 'FAIカウントダウン開始',
25
+ pauseTimerButton: 'セッション一時停止',
26
+ resumeTimerButton: 'タイマー再開',
27
+ resetTimerButton: 'セッションリセット',
28
+ recordLapButton: 'ラップ記録',
29
+ spacebarHint: 'ゲート通過時にスペースキーを押すか、巨大ボタンをタップしてください',
30
+ statusIdle: 'スタート待機中',
31
+ statusCountdown: 'FAIカウントダウン中',
32
+ statusRunning: 'レース計測中',
33
+ statusPaused: '一時停止中',
34
+ statusFinished: 'レース完了',
35
+ currentLapHeading: '現在ラップタイム',
36
+ lapNumberPrefix: '周回',
37
+ lastLapHeading: '前回ラップ',
38
+ fastestLapHeading: '最速ラップ',
39
+ averageLapHeading: '平均ラップ',
40
+ deltaBestHeading: 'ベスト差',
41
+ consistencyIndexHeading: 'ラップ一貫性指数',
42
+ estimatedSpeedHeading: '推定平均時速',
43
+ estimatedBatteryHeading: '推定バッテリー消費',
44
+ speedUnitKmh: 'km/h',
45
+ speedUnitMph: 'mph',
46
+ batteryUsedUnit: 'mAh',
47
+ batteryRemainingUnit: 'mAh 残量',
48
+ lapHistoryHeading: 'ラップタイムとペース比較',
49
+ lapColumnHeader: '周回 #',
50
+ timeColumnHeader: 'タイム',
51
+ splitColumnHeader: 'ベスト差',
52
+ speedColumnHeader: '平均時速',
53
+ batteryColumnHeader: 'バッテリー消費',
54
+ noLapsRecordedNotice: '記録されたラップはまだありません。カウントダウンを開始してスペースキーを押してください。',
55
+ consistencyRatingElite: 'エリート級の一貫性',
56
+ consistencyRatingPro: 'プロレーサー級の一貫性',
57
+ consistencyRatingClub: 'クラブ級の一貫性',
58
+ consistencyRatingNovice: 'トレーニング段階の一貫性',
59
+ fastestLapBadge: '最速ラップ',
60
+ sessionSummaryHeading: 'セッション要約と出力',
61
+ totalTimeLabel: 'レース総所要時間',
62
+ completedLapsLabel: '完了ラップ数',
63
+ exportCsvButton: 'ラップをCSVで保存',
64
+ copySummaryButton: '要約テキストをコピー',
65
+ copiedNotice: 'セッション要約をクリップボードにコピーしました!',
66
+ };
67
+
68
+ const faqItems = [
69
+ {
70
+ question: 'FAI音響スタートシークエンスはどのように動作しますか?',
71
+ answer: '国際航空連盟(FAI)CIAM F9Uドローンレースの公式ルールに準拠しています。1秒間隔の予備ビープ音が4回鳴った後、甲高い発走音が鳴り、タイマーが完全にゼロから開始されます。',
72
+ },
73
+ {
74
+ question: 'ラップ一貫性指数はどのように計算されますか?',
75
+ answer: '完了したラップタイムの標準偏差とセッション平均ラップタイムを比較してスコア化します。95%以上は極めて精密なライン取りとスロットルワークが行われていることを示します。',
76
+ },
77
+ {
78
+ question: 'フットペダルやプロポのスイッチでラップを記録できますか?',
79
+ answer: 'はい。スペースキーのキー入力を送信できるワイヤレスキーボード、Bluetoothフットスイッチ、ゲームパッドのボタンなどを使用すれば、画面を見ずに足や手元で即座にラップを記録できます。',
80
+ },
81
+ {
82
+ question: '誤動作防止(デバウンスガード)が設定されている理由は何ですか?',
83
+ answer: 'FPVゲートは高速で通過しますが、意図しない二度押しやスイッチのチャタリングにより誤ったミリ秒単位のラップが記録されるのを防ぐため、指定時間(標準3秒)未満の入力を除外します。',
84
+ },
85
+ {
86
+ question: '推定平均速度の精度はどの程度ですか?',
87
+ answer: '入力されたコース中心線の全長を計測されたラップ時間で割ることで算出されます。コーナー通過時の実速度はライン取りの半径や機体のバンク角によって異なります。',
88
+ },
89
+ ];
90
+
91
+ const howToSteps = [
92
+ {
93
+ name: 'コース長と周回数を設定する',
94
+ text: 'メートル単位のコース全長と目標周回数を入力するか、MultiGPなどのプリセットを選択します。',
95
+ },
96
+ {
97
+ name: 'FAI音響カウントダウンを開始する',
98
+ text: 'カウントダウン開始をクリックし、予備ブザー音に続いて発走ブザー音が鳴るのを待ちます。',
99
+ },
100
+ {
101
+ name: 'ゲート通過ごとにラップを記録する',
102
+ text: 'ドローンがスタート・フィニッシュゲートを通過するたびに、画面のボタンを押すかスペースキーを叩きます。',
103
+ },
104
+ {
105
+ name: 'テレメトリ、差分、一貫性を分析する',
106
+ text: 'ペース比較チャート、ベストタイムとの差分、一貫性指数を確認し、計測データをCSV形式で出力します。',
107
+ },
108
+ ];
109
+
110
+ const seoSections: SEOSection[] = [
111
+ {
112
+ type: 'title',
113
+ text: 'FPVマルチロータードローンレースにおける高精度タイム計測の要件',
114
+ level: 2,
115
+ },
116
+ {
117
+ type: 'paragraph',
118
+ html: '競技用FPVドローンレースでは、ミリ秒単位の計時精度とブレのない飛行ラインが求められます。5インチレーシング機は時速140kmを超え、立体的なゲートやダイブループをすり抜けます。効果的な練習には、統一された音響スタート合図、ゲート通過時の即時記録、複数周回にわたるペース配分の分析が欠かせません。',
119
+ },
120
+ {
121
+ type: 'title',
122
+ text: '各種ドローン競技カテゴリーと計測パラメーターの比較',
123
+ level: 2,
124
+ },
125
+ {
126
+ type: 'table',
127
+ headers: ['規格 / クラス', '典型的なコース長', '周回数', '平均ラップタイム', '想定最高速度', '推奨ガード時間'],
128
+ rows: [
129
+ ['Tiny Whoop (65mm 1S)', '50m - 80m', '5周', '8.5秒 - 13.0秒', '35 - 55 km/h', '2.0秒'],
130
+ ['Micro 3.5インチ (4S)', '120m - 180m', '4周', '12.0秒 - 18.0秒', '70 - 110 km/h', '2.5秒'],
131
+ ['MultiGP Spec 5インチ (6S)', '200m - 300m', '3周', '14.0秒 - 22.0秒', '100 - 150 km/h', '3.0秒'],
132
+ ['オープンフィールド (6S/8S)', '350m - 500m', '2周', '20.0秒 - 32.0秒', '130 - 180 km/h', '4.0秒'],
133
+ ],
134
+ },
135
+ {
136
+ type: 'title',
137
+ text: '発走音シークエンスとFAI F9Uスポーツ規定',
138
+ level: 2,
139
+ },
140
+ {
141
+ type: 'paragraph',
142
+ html: 'FAI CIAM Section 4のドローンレース規定に基づき、ビデオゴーグルを装着したパイロット間の反応差を均一にするため、視覚的な旗ではなく規定の音響シグナルで発走します。1秒間隔の440Hz音に続き、880Hzの発走音でタイマーがスタートします。',
143
+ },
144
+ {
145
+ type: 'list',
146
+ items: [
147
+ '予備シグナル:スロットル位置を定め、最初のゲートへの視線を集中させる準備音。',
148
+ '発走音 (Go):即座にアームして離陸するシグナルで、t = 0から計測が開始されます。',
149
+ '通過確認音:ゴーグルから目を離さずにラップ記録を確認できる明瞭な確認音。',
150
+ 'ベストタイム通知音:セッションの最高記録を更新した際に鳴る特別な和音チャイム。',
151
+ ],
152
+ },
153
+ {
154
+ type: 'title',
155
+ text: 'ラップ一貫性指数とレース戦略の重要性',
156
+ level: 2,
157
+ },
158
+ {
159
+ type: 'paragraph',
160
+ html: '一度きりの突出したファステストラップも魅力的ですが、大会で勝利を収めるのは一貫性です。周回ごとのタイム差が0.3秒未満に収まるパイロットは、プロップウォッシュの乱気流を避け、バッテリー電圧を最終スプリントまで保つことができます。',
161
+ },
162
+ {
163
+ type: 'tip',
164
+ title: '練習現場での活用テクニック',
165
+ html: '計測タブレットやスマートフォンをパイロット席の近くに置き、音量を十分に上げてください。Bluetoothのフットスイッチや小型キーボードを足元に配置すれば、プロポのスティックから指を離さずに足でラップを記録できます。',
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: 'JPY',
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 드론 레이싱 랩 및 스플릿 타이머';
8
+ const description = 'FAI 음향 스타트 시퀀스, 구간 스플릿 편차, 최고 랩 알림, 랩 일관성 지수 및 속도 텔레메트리를 지원하는 FPV 드론 레이싱 대화형 랩타이머.';
9
+
10
+ const ui = {
11
+ setupHeading: '트랙 및 세션 설정',
12
+ trackLengthLabel: '트랙 서킷 길이',
13
+ trackLengthUnit: '미터',
14
+ targetLapsLabel: '목표 랩 수',
15
+ targetLapsUnit: '랩 (0 설정 시 무제한 연습)',
16
+ batteryCapacityLabel: '배터리 용량',
17
+ batteryCapacityUnit: 'mAh',
18
+ soundEnabledLabel: '음향 시그널 활성화',
19
+ debounceThresholdLabel: '중복 입력 방지 시간',
20
+ debounceThresholdUnit: '초',
21
+ presetMultiGpLabel: 'MultiGP 규격 (250m / 3랩)',
22
+ presetWhoopLabel: '타이니 웁 (65m / 5랩)',
23
+ presetSprintLabel: '초고속 스프린트 (400m / 2랩)',
24
+ startCountdownButton: 'FAI 카운트다운 시작',
25
+ pauseTimerButton: '세션 일시정지',
26
+ resumeTimerButton: '타이머 재개',
27
+ resetTimerButton: '세션 초기화',
28
+ recordLapButton: '랩 기록',
29
+ spacebarHint: '게이트 통과 시 스페이스바를 누르거나 대형 버튼을 터치하세요',
30
+ statusIdle: '출발 대기',
31
+ statusCountdown: 'FAI 카운트다운 진행 중',
32
+ statusRunning: '레이스 타이머 작동 중',
33
+ statusPaused: '세션 일시정지됨',
34
+ statusFinished: '레이스 완료',
35
+ currentLapHeading: '현재 랩타임',
36
+ lapNumberPrefix: '랩',
37
+ lastLapHeading: '직전 랩',
38
+ fastestLapHeading: '최고 랩타임',
39
+ averageLapHeading: '평균 랩타임',
40
+ deltaBestHeading: '최고 기록 대비 편차',
41
+ consistencyIndexHeading: '랩 일관성 지수',
42
+ estimatedSpeedHeading: '예상 평균 시속',
43
+ estimatedBatteryHeading: '예상 배터리 소모량',
44
+ speedUnitKmh: 'km/h',
45
+ speedUnitMph: 'mph',
46
+ batteryUsedUnit: 'mAh',
47
+ batteryRemainingUnit: 'mAh 잔여',
48
+ lapHistoryHeading: '랩 타임 및 페이스 비교',
49
+ lapColumnHeader: '랩 #',
50
+ timeColumnHeader: '시간',
51
+ splitColumnHeader: '최고 대비 편차',
52
+ speedColumnHeader: '평균 속도',
53
+ batteryColumnHeader: '배터리 소모',
54
+ noLapsRecordedNotice: '기록된 랩이 없습니다. 카운트다운을 시작하고 스페이스바를 눌러 첫 랩을 기록하세요.',
55
+ consistencyRatingElite: '엘리트급 일관성',
56
+ consistencyRatingPro: '프로 선수급 일관성',
57
+ consistencyRatingClub: '클럽 레이서급 일관성',
58
+ consistencyRatingNovice: '훈련 단계 일관성',
59
+ fastestLapBadge: '최고 랩',
60
+ sessionSummaryHeading: '세션 요약 및 내보내기',
61
+ totalTimeLabel: '총 레이스 시간',
62
+ completedLapsLabel: '완주한 랩',
63
+ exportCsvButton: '랩 기록 CSV 내보내기',
64
+ copySummaryButton: '텍스트 요약 복사',
65
+ copiedNotice: '세션 요약이 클립보드에 복사되었습니다!',
66
+ };
67
+
68
+ const faqItems = [
69
+ {
70
+ question: 'FAI 음향 스타트 시퀀스는 어떻게 진행되나요?',
71
+ answer: '국제항공연맹(FAI) CIAM F9U 드론 레이싱 공식 규정을 정확히 반영합니다. 1초 간격의 예비 신호음 4회가 울린 뒤 고주파 스타트 버저가 울리며 정밀하게 0초부터 타이머가 작동합니다.',
72
+ },
73
+ {
74
+ question: '랩 일관성 지수는 어떻게 계산되나요?',
75
+ answer: '완주한 각 랩타임의 표준 편차를 세션 평균 랩타임과 비교하여 산출합니다. 95% 이상은 정밀한 스로틀 제어와 균일한 비행 라인을 유지하고 있음을 나타냅니다.',
76
+ },
77
+ {
78
+ question: '풋 페달이나 조종기 스위치로 랩을 기록할 수 있나요?',
79
+ answer: '네. 스페이스바 키 입력을 전송할 수 있는 무선 키보드, 블루투스 발판 스위치 또는 조종기 스위치를 연결하면 화면을 보지 않고도 손쉽게 랩을 기록할 수 있습니다.',
80
+ },
81
+ {
82
+ question: '중복 입력 방지(디바운스) 가드가 필요한 이유는 무엇인가요?',
83
+ answer: '게이트는 매우 빠른 속도로 통과되지만 스위치 튐이나 손가락의 순간적인 두 번 터치로 찰나의 랩이 잘못 기록되는 것을 방지하기 위해 설정 시간(기본 3초) 이내의 입력을 무시합니다.',
84
+ },
85
+ {
86
+ question: '예상 평균 시속은 얼마나 정확한가요?',
87
+ answer: '입력된 트랙의 중심선 총 길이를 기록된 랩 소요 시간으로 나누어 계산합니다. 실제 코너 통과 속도는 선회 반경과 기체의 뱅크 각도에 따라 달라질 수 있습니다.',
88
+ },
89
+ ];
90
+
91
+ const howToSteps = [
92
+ {
93
+ name: '트랙 길이 및 목표 랩 수 설정',
94
+ text: '미터 단위의 서킷 길이와 완주할 랩 수를 입력하거나 MultiGP와 같은 프리셋을 선택합니다.',
95
+ },
96
+ {
97
+ name: 'FAI 음향 카운트다운 시작',
98
+ text: '카운트다운 시작 버튼을 누르고 예비 신호음에 이어 울리는 출발 버저에 맞춰 출발합니다.',
99
+ },
100
+ {
101
+ name: '피니시 게이트 통과 시 랩 기록',
102
+ text: '드론이 출발/도착 게이트를 통과할 때마다 화면 버튼이나 스페이스바를 누릅니다.',
103
+ },
104
+ {
105
+ name: '텔레메트리, 편차 및 일관성 분석',
106
+ text: '페이스 차트, 최고 랩 대비 시간차, 일관성 지수를 확인하고 측정 기록을 CSV로 저장합니다.',
107
+ },
108
+ ];
109
+
110
+ const seoSections: SEOSection[] = [
111
+ {
112
+ type: 'title',
113
+ text: 'FPV 멀티로터 드론 레이싱에서 고정밀 랩타임 계측의 중요성',
114
+ level: 2,
115
+ },
116
+ {
117
+ type: 'paragraph',
118
+ html: '고성능 FPV 드론 레이싱 경기는 밀리초 단위의 정밀성과 흔들림 없는 비행 라인을 필요로 합니다. 5인치 레이싱 드론은 140 km/h가 넘는 속도로 3차원 게이트와 깃발을 가로지릅니다. 효과적인 실전 연습을 위해서는 표준화된 사운드 스타트, 즉각적인 게이트 통과 체크, 여러 랩에 걸친 페이스 저하 분석이 필수적입니다.',
119
+ },
120
+ {
121
+ type: 'title',
122
+ text: '드론 레이싱 규격별 트랙 제원 및 타이밍 파라미터 비교',
123
+ level: 2,
124
+ },
125
+ {
126
+ type: 'table',
127
+ headers: ['규격 / 클래스', '일반적인 트랙 길이', '히트당 랩 수', '평균 랩타임', '최고 시속 범위', '권장 방지 시간'],
128
+ rows: [
129
+ ['타이니 웁 (65mm 1S)', '50m - 80m', '5랩', '8.5초 - 13.0초', '35 - 55 km/h', '2.0초'],
130
+ ['마이크로 3.5인치 (4S)', '120m - 180m', '4랩', '12.0초 - 18.0초', '70 - 110 km/h', '2.5초'],
131
+ ['MultiGP 5인치 (6S)', '200m - 300m', '3랩', '14.0초 - 22.0초', '100 - 150 km/h', '3.0초'],
132
+ ['오픈 필드 스프린트 (6S/8S)', '350m - 500m', '2랩', '20.0초 - 32.0초', '130 - 180 km/h', '4.0초'],
133
+ ],
134
+ },
135
+ {
136
+ type: 'title',
137
+ text: '출발 음향 시퀀스와 FAI F9U 스포츠 규정',
138
+ level: 2,
139
+ },
140
+ {
141
+ type: 'paragraph',
142
+ html: 'FAI CIAM 섹션 4 드론 레이싱 규정에 따라 FPV 고글을 착용한 조종사 간의 공평한 반응 시간을 보장하기 위해 깃발 대신 공인된 음향 신호로 경기를 시작합니다. 1초 간격의 440Hz 톤 4회에 이어 모터를 가동하는 880Hz 스타트 톤으로 전환됩니다.',
143
+ },
144
+ {
145
+ type: 'list',
146
+ items: [
147
+ '예비 신호음: 스로틀 위치를 안정화하고 첫 코너 진입 시야를 확보하기 위한 알림음.',
148
+ '출발 신호음 (Go): 즉시 가속하여 날아오르는 신호로 정확히 t = 0부터 계측이 시작됩니다.',
149
+ '통과 확인음: 고글에서 시선을 떼지 않고도 랩이 정상 기록되었음을 확인시켜 주는 알림음.',
150
+ '최고 기록 멜로디: 세션 내 최고 랩타임을 경신했을 때 울리는 경쾌한 화음 차임.',
151
+ ],
152
+ },
153
+ {
154
+ type: 'title',
155
+ text: '랩 일관성 지수와 레이스 전략 운영',
156
+ level: 2,
157
+ },
158
+ {
159
+ type: 'paragraph',
160
+ html: '단 한 번의 폭발적인 랩타임도 훌륭하지만 대회 승패는 꾸준함이 좌우합니다. 일관성 지수는 기록의 편차를 평가합니다. 랩 편차가 0.3초 미만인 조종사는 후류 와류를 피하고 배터리 전압을 마지막 랩까지 안정적으로 유지할 수 있습니다.',
161
+ },
162
+ {
163
+ type: 'tip',
164
+ title: '비행 연습 현장 활용 팁',
165
+ html: '조종석 가까이 태블릿이나 스마트폰을 소리가 잘 들리도록 배치하세요. 블루투스 풋 스위치나 작은 무선 패드를 바닥에 놓으면 조종기 스틱을 놓지 않고도 발로 랩을 기록할 수 있습니다.',
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: 'KRW',
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-race-rondetimer';
7
+ const title = 'FPV Drone Race Ronden en Splittimer';
8
+ const description = 'Interactieve rondetimer voor FPV drone racing met FAI akoestische startsequentie, split-delta analyse, snelste ronde waarschuwingen, rondeconsistentie-index en snelheidstelemetrie.';
9
+
10
+ const ui = {
11
+ setupHeading: 'Circuit- en Sessieconfiguratie',
12
+ trackLengthLabel: 'Circuitlengte',
13
+ trackLengthUnit: 'meter',
14
+ targetLapsLabel: 'Doelaantal Ronden',
15
+ targetLapsUnit: 'ronden (0 voor vrije training)',
16
+ batteryCapacityLabel: 'Accucapaciteit',
17
+ batteryCapacityUnit: 'mAh',
18
+ soundEnabledLabel: 'Akoestische Tonen Inschakelen',
19
+ debounceThresholdLabel: 'Ronde-ontdemping Drempel',
20
+ debounceThresholdUnit: 'seconden',
21
+ presetMultiGpLabel: 'MultiGP Spec (250m / 3 Ronden)',
22
+ presetWhoopLabel: 'Tiny Whoop (65m / 5 Ronden)',
23
+ presetSprintLabel: 'Hogesnelheidssprint (400m / 2 Ronden)',
24
+ startCountdownButton: 'Start FAI Countdown',
25
+ pauseTimerButton: 'Pauzeer Sessie',
26
+ resumeTimerButton: 'Hervat Timer',
27
+ resetTimerButton: 'Reset Sessie',
28
+ recordLapButton: 'RONDE REGISTREREN',
29
+ spacebarHint: 'Druk op SPATIEBALK of tik op de grote knop om finishpassage te markeren',
30
+ statusIdle: 'Klaar voor Start',
31
+ statusCountdown: 'FAI Countdown Bezig',
32
+ statusRunning: 'Racetimer Actief',
33
+ statusPaused: 'Sessie Gepauzeerd',
34
+ statusFinished: 'Race Voltooid',
35
+ currentLapHeading: 'Huidige Rondetijd',
36
+ lapNumberPrefix: 'Ronde',
37
+ lastLapHeading: 'Laatste Ronde',
38
+ fastestLapHeading: 'Snelste Ronde',
39
+ averageLapHeading: 'Gemiddelde Ronde',
40
+ deltaBestHeading: 'Delta t.o.v. Snelste',
41
+ consistencyIndexHeading: 'Rondeconsistentie-index',
42
+ estimatedSpeedHeading: 'Geschatte Gemiddelde Snelheid',
43
+ estimatedBatteryHeading: 'Geschat Accuverbruik',
44
+ speedUnitKmh: 'km/u',
45
+ speedUnitMph: 'mph',
46
+ batteryUsedUnit: 'mAh',
47
+ batteryRemainingUnit: 'mAh resterend',
48
+ lapHistoryHeading: 'Rondetijden en Tempovergelijking',
49
+ lapColumnHeader: 'Ronde #',
50
+ timeColumnHeader: 'Rondetijd',
51
+ splitColumnHeader: 'Delta t.o.v. Best',
52
+ speedColumnHeader: 'Gemiddelde Snelheid',
53
+ batteryColumnHeader: 'Accuverbruik',
54
+ noLapsRecordedNotice: 'Nog geen ronden geregistreerd. Start de countdown en druk op Spatiebalk om je eerste ronde vast te leggen.',
55
+ consistencyRatingElite: 'Elite Consistentie',
56
+ consistencyRatingPro: 'Pro Racer Consistentie',
57
+ consistencyRatingClub: 'Clubcoureur Consistentie',
58
+ consistencyRatingNovice: 'Training Consistentie',
59
+ fastestLapBadge: 'SNELSTE RONDE',
60
+ sessionSummaryHeading: 'Sessieoverzicht en Export',
61
+ totalTimeLabel: 'Totale Raceduur',
62
+ completedLapsLabel: 'Voltooide Ronden',
63
+ exportCsvButton: 'Exporteer Ronden naar CSV',
64
+ copySummaryButton: 'Kopieer Tekstoverzicht',
65
+ copiedNotice: 'Sessieoverzicht naar klembord gekopieerd!',
66
+ };
67
+
68
+ const faqItems = [
69
+ {
70
+ question: 'Hoe werkt de FAI akoestische startsequentie in deze timer?',
71
+ answer: 'De startsequentie simuleert de officiële F9U droneracing-voorschriften van de Fédération Aéronautique Internationale (FAI). Vier voorbereidende pieptonen met tussenpozen van één seconde bereiden de piloot voor, gevolgd door een hoge startzoemer die de timer op exact nul activeert.',
72
+ },
73
+ {
74
+ question: 'Hoe wordt de Rondeconsistentie-index berekend?',
75
+ answer: 'De score toetst de standaardafwijking van je voltooide rondetijden aan het gemiddelde van de sessie. Een score boven 95 procent wijst op een uiterst strakke racelijn en nauwkeurige gasbeheersing.',
76
+ },
77
+ {
78
+ question: 'Kan ik een voetpedaal of zenderschakelaar gebruiken?',
79
+ answer: 'Ja. Elk draadloos toetsenbord, bluetooth-pedaal of zender-switch die het indrukken van de spatiebalk simuleert registreert de ronde direct, zonder dat je het scherm hoeft aan te raken.',
80
+ },
81
+ {
82
+ question: 'Waarom is er een ontdempingsbeveiliging op de rondeknop?',
83
+ answer: 'FPV-poorten worden op hoge snelheid gepasseerd. Een onbedoelde dubbele klik zou valse rondetijden kunnen registreren. De ontdempingsfilter negeert signalen binnen de ingestelde tijd (standaard 3 seconden).',
84
+ },
85
+ {
86
+ question: 'Hoe nauwkeurig is de geschatte gemiddelde snelheid?',
87
+ answer: 'De snelheid is berekend op basis van de ingevoerde hartlijnafstand van het circuit gedeeld door de rondeduur. De werkelijke snelheid in bochten wijkt af afhankelijk van de gevlogen radius en hellingshoek.',
88
+ },
89
+ ];
90
+
91
+ const howToSteps = [
92
+ {
93
+ name: 'Stel circuitlengte en rondedoel in',
94
+ text: 'Voer de circuitafstand in meters en het gewenste aantal ronden in of kies een preset zoals MultiGP Spec.',
95
+ },
96
+ {
97
+ name: 'Start de FAI akoestische countdown',
98
+ text: 'Klik op Start Countdown. Luister naar de voorbereidende tonen en het startsignaal bij vertrek.',
99
+ },
100
+ {
101
+ name: 'Registreer elke ronde bij de finishpoort',
102
+ text: 'Druk op de spatiebalk of klik op de grote knop wanneer de drone door de start/finish-poort vliegt.',
103
+ },
104
+ {
105
+ name: 'Analyseer telemetrie, splits en consistentie',
106
+ text: 'Bekijk de tempografiek, deltaverschillen en consistentiescore en exporteer de data naar een CSV-bestand.',
107
+ },
108
+ ];
109
+
110
+ const seoSections: SEOSection[] = [
111
+ {
112
+ type: 'title',
113
+ text: 'Principes van uiterst nauwkeurige tijdwaarneming bij FPV multirotor drone racing',
114
+ level: 2,
115
+ },
116
+ {
117
+ type: 'paragraph',
118
+ html: 'Competitieve FPV-droneraces vereisen millisecondenprecisie en onberispelijke lijnconsistentie. 5-inch quads bereiken snelheden boven 140 km/u door 3D-poorten en vlaggen. Doeltreffend trainen vraagt om akoestische startsignalen, directe ronderegistratie en inzicht in het tempo over meerdere ronden.',
119
+ },
120
+ {
121
+ type: 'title',
122
+ text: 'Vergelijking van raceklassen en timingparameters',
123
+ level: 2,
124
+ },
125
+ {
126
+ type: 'table',
127
+ headers: ['Klasse / Specificatie', 'Typische Circuitlengte', 'Aantal Ronden', 'Gemiddelde Rondetijd', 'Topsnelheidsbereik', 'Aanbevolen Ontdemping'],
128
+ rows: [
129
+ ['Tiny Whoop (65mm 1S)', '50m tot 80m', '5 ronden', '8.5s tot 13.0s', '35 tot 55 km/u', '2.0 seconden'],
130
+ ['Micro 3.5-inch (4S)', '120m tot 180m', '4 ronden', '12.0s tot 18.0s', '70 tot 110 km/u', '2.5 seconden'],
131
+ ['MultiGP Spec 5-inch (6S)', '200m tot 300m', '3 ronden', '14.0s tot 22.0s', '100 tot 150 km/u', '3.0 seconden'],
132
+ ['Open Veld Sprint (6S/8S)', '350m tot 500m', '2 ronden', '20.0s tot 32.0s', '130 tot 180 km/u', '4.0 seconden'],
133
+ ],
134
+ },
135
+ {
136
+ type: 'title',
137
+ text: 'Akoestische starttonen en FAI F9U sportreglementen',
138
+ level: 2,
139
+ },
140
+ {
141
+ type: 'paragraph',
142
+ html: 'Onder FAI CIAM Sectie 4 regels voor droneracing starten heats met gestandaardiseerde geluidssignalen in plaats van visuele vlaggen om gelijke reactietijden in FPV-videobrillen te waarborgen. De sequentie gebruikt 440 Hz tonen met één seconde tussenpauze en een 880 Hz starttoon.',
143
+ },
144
+ {
145
+ type: 'list',
146
+ items: [
147
+ 'Voorbereidingstonen: Signalen om gasstand af te stemmen en focus op het circuit te richten.',
148
+ 'Starttoon (Go): Direct signaal waarmee de tijdwaarneming precies op t = 0 aanvangt.',
149
+ 'Akoestische bevestiging: Duidelijke feedbackpiep bij het passeren van de poort.',
150
+ 'Snelste ronde melodie: Onderscheidend akkoord wanneer het sessie-record verbroken wordt.',
151
+ ],
152
+ },
153
+ {
154
+ type: 'title',
155
+ text: 'De Consistentie-index en tactisch racemanagement',
156
+ level: 2,
157
+ },
158
+ {
159
+ type: 'paragraph',
160
+ html: 'Een losse snelle ronde is mooi, maar kampioenschappen worden beslist op consistentie. De index toont schommelingen aan: een piloot die binnen 0.3 seconden blijft behoudt controle en spaart accuspanning voor de eindsprint.',
161
+ },
162
+ {
163
+ type: 'tip',
164
+ title: 'Praktijktip voor het vliegveld',
165
+ html: 'Plaats je timingapparaat op goed hoorbaar volume nabij je stoel. Gebruik een bluetooth-knop of klein toetsenbordje op de grond om met je voet ronden te registreren zonder de zendersticks los te laten.',
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
+ };