@jjlmoya/utils-drones 1.35.0 → 1.36.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 (33) hide show
  1. package/package.json +1 -1
  2. package/src/entries.ts +4 -0
  3. package/src/index.ts +1 -0
  4. package/src/tests/locale_completeness.test.ts +2 -2
  5. package/src/tests/tool_validation.test.ts +2 -2
  6. package/src/tool/fpv-drone-speed-calculator/bibliography.astro +6 -0
  7. package/src/tool/fpv-drone-speed-calculator/bibliography.ts +14 -0
  8. package/src/tool/fpv-drone-speed-calculator/component.astro +115 -0
  9. package/src/tool/fpv-drone-speed-calculator/controller.ts +105 -0
  10. package/src/tool/fpv-drone-speed-calculator/dom-views.ts +80 -0
  11. package/src/tool/fpv-drone-speed-calculator/entry.ts +27 -0
  12. package/src/tool/fpv-drone-speed-calculator/fpv-drone-speed-calculator.css +558 -0
  13. package/src/tool/fpv-drone-speed-calculator/i18n/de.ts +20 -0
  14. package/src/tool/fpv-drone-speed-calculator/i18n/en.ts +47 -0
  15. package/src/tool/fpv-drone-speed-calculator/i18n/es.ts +40 -0
  16. package/src/tool/fpv-drone-speed-calculator/i18n/fr.ts +13 -0
  17. package/src/tool/fpv-drone-speed-calculator/i18n/id.ts +13 -0
  18. package/src/tool/fpv-drone-speed-calculator/i18n/it.ts +13 -0
  19. package/src/tool/fpv-drone-speed-calculator/i18n/ja.ts +13 -0
  20. package/src/tool/fpv-drone-speed-calculator/i18n/ko.ts +13 -0
  21. package/src/tool/fpv-drone-speed-calculator/i18n/nl.ts +13 -0
  22. package/src/tool/fpv-drone-speed-calculator/i18n/pl.ts +13 -0
  23. package/src/tool/fpv-drone-speed-calculator/i18n/pt.ts +13 -0
  24. package/src/tool/fpv-drone-speed-calculator/i18n/ru.ts +13 -0
  25. package/src/tool/fpv-drone-speed-calculator/i18n/sv.ts +13 -0
  26. package/src/tool/fpv-drone-speed-calculator/i18n/tr.ts +13 -0
  27. package/src/tool/fpv-drone-speed-calculator/i18n/zh.ts +13 -0
  28. package/src/tool/fpv-drone-speed-calculator/index.ts +11 -0
  29. package/src/tool/fpv-drone-speed-calculator/logic.test.ts +53 -0
  30. package/src/tool/fpv-drone-speed-calculator/logic.ts +126 -0
  31. package/src/tool/fpv-drone-speed-calculator/seo.astro +16 -0
  32. package/src/tool/fpv-drone-speed-calculator/ui.ts +47 -0
  33. package/src/tools.ts +3 -0
@@ -0,0 +1,558 @@
1
+ :root {
2
+ --speed-ink: #14211f;
3
+ --speed-muted: #60706d;
4
+ --speed-paper: #f3f1e8;
5
+ --speed-card: #fffdf5;
6
+ --speed-line: #d8d8c8;
7
+ --speed-teal: #006b68;
8
+ --speed-lime: #c7f36d;
9
+ --speed-coral: #ee745a;
10
+ --speed-slate: #1f3333;
11
+ --speed-shadow: rgba(20, 33, 31, .14);
12
+ }
13
+
14
+ .theme-dark .fpv-speed-tool {
15
+ --speed-ink: #edf5ee;
16
+ --speed-muted: #a7b6b0;
17
+ --speed-paper: #17221f;
18
+ --speed-card: #1e2d29;
19
+ --speed-line: #3a4c46;
20
+ --speed-teal: #61d1c1;
21
+ --speed-lime: #d5f67f;
22
+ --speed-coral: #ff9e80;
23
+ --speed-slate: #10201d;
24
+ --speed-shadow: rgba(0, 0, 0, .28);
25
+ }
26
+
27
+ .fpv-speed-tool {
28
+ overflow: hidden;
29
+ border: 1px solid var(--speed-line);
30
+ border-radius: 1.5rem;
31
+ background: var(--speed-card);
32
+ box-shadow: 0 1.4rem 3.5rem var(--speed-shadow);
33
+ color: var(--speed-ink);
34
+ }
35
+
36
+ .speed-brief,
37
+ .flight-deck,
38
+ .assumptions-row {
39
+ padding: clamp(1rem, 3vw, 2rem);
40
+ }
41
+
42
+ .speed-brief {
43
+ display: flex;
44
+ align-items: center;
45
+ justify-content: space-between;
46
+ gap: 1rem;
47
+ border-bottom: 1px solid var(--speed-line);
48
+ background: var(--speed-paper);
49
+ }
50
+
51
+ .speed-brief p,
52
+ .assumptions-row p {
53
+ max-width: 54rem;
54
+ margin: .45rem 0 0;
55
+ color: var(--speed-muted);
56
+ font-size: .82rem;
57
+ line-height: 1.55;
58
+ }
59
+
60
+ .brief-kicker {
61
+ color: var(--speed-teal);
62
+ font-size: .67rem;
63
+ font-weight: 900;
64
+ letter-spacing: .15em;
65
+ text-transform: uppercase;
66
+ }
67
+
68
+ .unit-switch,
69
+ .preset-track {
70
+ display: flex;
71
+ flex-wrap: wrap;
72
+ gap: .45rem;
73
+ }
74
+
75
+ button {
76
+ cursor: pointer;
77
+ font: inherit;
78
+ }
79
+
80
+ .unit-button,
81
+ .preset-button {
82
+ border: 1px solid var(--speed-line);
83
+ border-radius: .45rem;
84
+ background: transparent;
85
+ color: var(--speed-muted);
86
+ font-size: .74rem;
87
+ font-weight: 800;
88
+ padding: .62rem .75rem;
89
+ transition: transform .18s ease, background .18s ease, color .18s ease;
90
+ }
91
+
92
+ .unit-button:hover,
93
+ .preset-button:hover {
94
+ transform: translateY(-1px);
95
+ border-color: var(--speed-teal);
96
+ color: var(--speed-teal);
97
+ }
98
+
99
+ .unit-button.is-selected,
100
+ .preset-button.is-selected {
101
+ border-color: var(--speed-teal);
102
+ background: var(--speed-teal);
103
+ color: #fff;
104
+ }
105
+
106
+ .flight-deck {
107
+ display: grid;
108
+ grid-template-columns: minmax(15rem, .75fr) minmax(0, 1.75fr);
109
+ gap: clamp(1.25rem, 4vw, 3rem);
110
+ }
111
+
112
+ .control-rail {
113
+ padding-right: clamp(0rem, 2vw, 1.5rem);
114
+ border-right: 1px solid var(--speed-line);
115
+ }
116
+
117
+ h2,
118
+ h3 {
119
+ margin: .32rem 0 0;
120
+ line-height: 1.1;
121
+ }
122
+
123
+ h2 {
124
+ font-size: clamp(1.22rem, 2.6vw, 1.8rem);
125
+ }
126
+
127
+ h3 {
128
+ font-size: 1rem;
129
+ }
130
+
131
+ .preset-track {
132
+ margin: 1.25rem 0 1.6rem;
133
+ }
134
+
135
+ .input-list {
136
+ display: grid;
137
+ gap: .65rem;
138
+ }
139
+
140
+ .input-row {
141
+ position: relative;
142
+ display: grid;
143
+ gap: .3rem;
144
+ }
145
+
146
+ .input-row span {
147
+ color: var(--speed-muted);
148
+ font-size: .74rem;
149
+ font-weight: 800;
150
+ }
151
+
152
+ .input-row input {
153
+ width: 100%;
154
+ border: 1px solid var(--speed-line);
155
+ border-radius: .55rem;
156
+ background: var(--speed-paper);
157
+ color: var(--speed-ink);
158
+ font-size: 1.02rem;
159
+ font-weight: 800;
160
+ padding: .72rem 2.5rem .72rem .75rem;
161
+ }
162
+
163
+ .input-row small {
164
+ position: absolute;
165
+ right: .75rem;
166
+ bottom: .77rem;
167
+ color: var(--speed-muted);
168
+ font-size: .7rem;
169
+ font-weight: 900;
170
+ }
171
+
172
+ button:focus-visible,
173
+ input:focus-visible {
174
+ outline: 3px solid var(--speed-coral);
175
+ outline-offset: 2px;
176
+ }
177
+
178
+ .speed-orchestra {
179
+ min-width: 0;
180
+ }
181
+
182
+ .speed-orchestra-header,
183
+ .subheading {
184
+ display: flex;
185
+ align-items: flex-start;
186
+ justify-content: space-between;
187
+ gap: 1rem;
188
+ }
189
+
190
+ .diagnosis {
191
+ border: 1px solid var(--speed-teal);
192
+ border-radius: 999px;
193
+ color: var(--speed-teal);
194
+ font-size: .72rem;
195
+ font-weight: 900;
196
+ padding: .55rem .7rem;
197
+ text-align: center;
198
+ }
199
+
200
+ [data-diagnosis="overspeed"] .diagnosis,
201
+ [data-diagnosis="high-slip"] .diagnosis {
202
+ border-color: var(--speed-coral);
203
+ color: var(--speed-coral);
204
+ }
205
+
206
+ .speed-lane {
207
+ position: relative;
208
+ min-height: 19rem;
209
+ margin: 1.25rem 0;
210
+ overflow: hidden;
211
+ border-radius: 1rem;
212
+ background:
213
+ radial-gradient(circle at 78% 20%, rgba(199, 243, 109, .14), transparent 24%),
214
+ linear-gradient(155deg, #102a31 0%, var(--speed-slate) 58%, #14221e 100%);
215
+ }
216
+
217
+ .lane-grid {
218
+ position: absolute;
219
+ inset: 0;
220
+ opacity: .52;
221
+ background-image: linear-gradient(105deg, transparent 0 48%, rgba(199, 243, 109, .16) 49% 50%, transparent 51%), repeating-linear-gradient(90deg, transparent 0 2.9rem, rgba(255, 255, 255, .1) 3rem);
222
+ background-size: 100% 100%, 3rem 100%;
223
+ }
224
+
225
+ .lane-horizon {
226
+ position: absolute;
227
+ right: -10%;
228
+ bottom: 0;
229
+ left: -10%;
230
+ height: 5.5rem;
231
+ border-top: 1px solid rgba(199, 243, 109, .28);
232
+ background: linear-gradient(180deg, rgba(199, 243, 109, .1), transparent);
233
+ clip-path: polygon(0 45%, 100% 0, 100% 100%, 0 100%);
234
+ }
235
+
236
+ .lane-header {
237
+ position: absolute;
238
+ top: 1rem;
239
+ right: 1.15rem;
240
+ left: 1.15rem;
241
+ z-index: 1;
242
+ display: flex;
243
+ justify-content: space-between;
244
+ color: rgba(255, 255, 255, .7);
245
+ font-size: .65rem;
246
+ font-weight: 800;
247
+ letter-spacing: .04em;
248
+ text-transform: uppercase;
249
+ }
250
+
251
+ .lane-header > span:first-child {
252
+ color: var(--speed-lime);
253
+ letter-spacing: .14em;
254
+ }
255
+
256
+ .lane-header > span:last-child {
257
+ display: inline-flex;
258
+ align-items: center;
259
+ gap: .35rem;
260
+ color: rgba(255, 255, 255, .68);
261
+ letter-spacing: 0;
262
+ text-transform: none;
263
+ }
264
+
265
+ .lane-header b {
266
+ font-size: .58rem;
267
+ font-weight: 800;
268
+ }
269
+
270
+ .lane-header i {
271
+ display: inline-block;
272
+ width: 3rem;
273
+ height: 1px;
274
+ background: rgba(255, 255, 255, .36);
275
+ }
276
+
277
+ .speed-comparison {
278
+ position: absolute;
279
+ top: 5rem;
280
+ right: 1.15rem;
281
+ bottom: 1.25rem;
282
+ left: 1.15rem;
283
+ z-index: 1;
284
+ display: grid;
285
+ align-content: center;
286
+ gap: 1.2rem;
287
+ }
288
+
289
+ .comparison-scale {
290
+ display: grid;
291
+ grid-template-columns: repeat(3, 1fr);
292
+ color: rgba(255, 255, 255, .5);
293
+ font-size: .58rem;
294
+ font-weight: 800;
295
+ }
296
+
297
+ .comparison-scale span:nth-child(2) { text-align: center; }
298
+ .comparison-scale span:last-child { text-align: right; }
299
+
300
+ .comparison-row {
301
+ display: grid;
302
+ grid-template-columns: minmax(9.5rem, 1fr) minmax(10rem, 2.2fr);
303
+ align-items: center;
304
+ gap: 1rem;
305
+ }
306
+
307
+ .comparison-label {
308
+ display: grid;
309
+ gap: .35rem;
310
+ color: rgba(255, 255, 255, .7);
311
+ font-size: .65rem;
312
+ font-weight: 800;
313
+ line-height: 1.2;
314
+ }
315
+
316
+ .comparison-label strong {
317
+ color: var(--speed-lime);
318
+ font-size: clamp(1.1rem, 2.3vw, 1.55rem);
319
+ line-height: 1;
320
+ white-space: nowrap;
321
+ }
322
+
323
+ .comparison-row:nth-child(3) .comparison-label strong {
324
+ color: var(--speed-coral);
325
+ }
326
+
327
+ .comparison-track {
328
+ position: relative;
329
+ height: 1.15rem;
330
+ overflow: hidden;
331
+ border: 1px solid rgba(255, 255, 255, .22);
332
+ border-radius: 99rem;
333
+ background:
334
+ linear-gradient(90deg, transparent 0 49.7%, rgba(255, 255, 255, .16) 50%, transparent 50.3%),
335
+ rgba(255, 255, 255, .08);
336
+ }
337
+
338
+ .comparison-fill {
339
+ display: block;
340
+ height: 100%;
341
+ border-radius: inherit;
342
+ transition: width .3s ease;
343
+ }
344
+
345
+ .comparison-fill-estimated {
346
+ width: var(--speed-position, 58%);
347
+ background: linear-gradient(90deg, var(--speed-teal), var(--speed-lime));
348
+ box-shadow: 0 0 .9rem rgba(199, 243, 109, .42);
349
+ }
350
+
351
+ .comparison-fill-pitch {
352
+ width: var(--pitch-position, 70%);
353
+ background: repeating-linear-gradient(135deg, var(--speed-coral) 0 .45rem, #ffb095 .45rem .8rem);
354
+ opacity: .9;
355
+ }
356
+
357
+ .comparison-gap {
358
+ display: flex;
359
+ align-items: baseline;
360
+ justify-content: center;
361
+ gap: .55rem;
362
+ margin-top: .2rem;
363
+ padding-top: .85rem;
364
+ border-top: 1px solid rgba(255, 255, 255, .14);
365
+ color: rgba(255, 255, 255, .68);
366
+ font-size: .65rem;
367
+ font-weight: 800;
368
+ }
369
+
370
+ .comparison-gap strong {
371
+ color: var(--speed-coral);
372
+ font-size: 1.05rem;
373
+ }
374
+
375
+ .comparison-gap small {
376
+ color: rgba(255, 255, 255, .55);
377
+ font-size: .65rem;
378
+ }
379
+
380
+ .speed-readouts {
381
+ display: grid;
382
+ grid-template-columns: 1.4fr 1fr 1fr;
383
+ gap: 1px;
384
+ border: 1px solid var(--speed-line);
385
+ background: var(--speed-line);
386
+ }
387
+
388
+ .hero-readout,
389
+ .readout {
390
+ display: grid;
391
+ gap: .35rem;
392
+ min-width: 0;
393
+ padding: .9rem;
394
+ background: var(--speed-card);
395
+ }
396
+
397
+ .hero-readout strong {
398
+ color: var(--speed-teal);
399
+ font-size: clamp(1.25rem, 3vw, 1.9rem);
400
+ }
401
+
402
+ .readout strong {
403
+ font-size: clamp(1rem, 2vw, 1.35rem);
404
+ }
405
+
406
+ .hero-readout span,
407
+ .readout span,
408
+ .metric-strip span,
409
+ .sensitivity-point span,
410
+ .sensitivity-point small {
411
+ color: var(--speed-muted);
412
+ font-size: .68rem;
413
+ font-weight: 800;
414
+ }
415
+
416
+ .diagnosis-advice {
417
+ min-height: 2.7rem;
418
+ margin: 1rem 0;
419
+ color: var(--speed-muted);
420
+ font-size: .78rem;
421
+ line-height: 1.5;
422
+ }
423
+
424
+ .sensitivity {
425
+ border-top: 1px solid var(--speed-line);
426
+ padding-top: 1rem;
427
+ }
428
+
429
+ .sensitivity-row {
430
+ display: grid;
431
+ grid-template-columns: repeat(3, 1fr);
432
+ gap: .75rem;
433
+ margin-top: 1rem;
434
+ }
435
+
436
+ .sensitivity-point {
437
+ display: grid;
438
+ gap: .35rem;
439
+ min-width: 0;
440
+ padding: .75rem;
441
+ border-left: 3px solid var(--speed-line);
442
+ }
443
+
444
+ .sensitivity-point.is-current { border-left-color: var(--speed-coral); }
445
+ .sensitivity-point strong { font-size: 1rem; }
446
+ .sensitivity-point small { font-size: .68rem; }
447
+
448
+ .sensitivity-bar {
449
+ height: .32rem;
450
+ margin-top: .3rem;
451
+ overflow: hidden;
452
+ border-radius: 999px;
453
+ background: var(--speed-paper);
454
+ }
455
+
456
+ .sensitivity-bar i {
457
+ display: block;
458
+ width: var(--bar-width, 50%);
459
+ height: 100%;
460
+ border-radius: inherit;
461
+ background: var(--speed-teal);
462
+ transition: width .3s ease;
463
+ }
464
+
465
+ .metric-strip {
466
+ display: grid;
467
+ grid-template-columns: repeat(3, 1fr);
468
+ gap: 1rem;
469
+ margin-top: 1.25rem;
470
+ padding-top: 1rem;
471
+ border-top: 1px solid var(--speed-line);
472
+ }
473
+
474
+ .metric-strip div {
475
+ display: grid;
476
+ gap: .35rem;
477
+ }
478
+
479
+ .metric-strip strong {
480
+ font-size: .94rem;
481
+ }
482
+
483
+ .assumptions-row {
484
+ display: grid;
485
+ grid-template-columns: 1fr 1fr;
486
+ gap: 1.5rem;
487
+ border-top: 1px solid var(--speed-line);
488
+ background: var(--speed-paper);
489
+ }
490
+
491
+ .assumptions-row p {
492
+ margin: 0;
493
+ }
494
+
495
+ .assumptions-row strong {
496
+ color: var(--speed-ink);
497
+ }
498
+
499
+ @media (max-width: 780px) {
500
+ .speed-brief {
501
+ align-items: flex-start;
502
+ flex-direction: column;
503
+ }
504
+
505
+ .flight-deck {
506
+ grid-template-columns: 1fr;
507
+ }
508
+
509
+ .control-rail {
510
+ padding-right: 0;
511
+ border-right: 0;
512
+ border-bottom: 1px solid var(--speed-line);
513
+ padding-bottom: 1.5rem;
514
+ }
515
+ }
516
+
517
+ @media (max-width: 540px) {
518
+ .speed-readouts,
519
+ .assumptions-row { grid-template-columns: 1fr; }
520
+ .sensitivity-row { gap: .35rem; }
521
+ .sensitivity-point { padding: .45rem; }
522
+ .metric-strip { gap: .5rem; }
523
+ .metric-strip strong { font-size: .8rem; }
524
+ .speed-lane { min-height: 20rem; }
525
+ .lane-header {
526
+ right: .8rem;
527
+ left: .8rem;
528
+ font-size: .58rem;
529
+ }
530
+
531
+ .lane-header i {
532
+ width: 1.5rem;
533
+ }
534
+
535
+ .speed-comparison {
536
+ top: 4.4rem;
537
+ right: .8rem;
538
+ left: .8rem;
539
+ gap: 1rem;
540
+ }
541
+
542
+ .comparison-row {
543
+ grid-template-columns: minmax(7.5rem, 1fr) minmax(8rem, 1.35fr);
544
+ gap: .7rem;
545
+ }
546
+
547
+ .comparison-label {
548
+ font-size: .58rem;
549
+ }
550
+
551
+ .comparison-label strong {
552
+ font-size: 1rem;
553
+ }
554
+
555
+ .comparison-gap {
556
+ font-size: .58rem;
557
+ }
558
+ }
@@ -0,0 +1,20 @@
1
+ import type { FAQPage, HowTo, SoftwareApplication, WithContext } from 'schema-dts';
2
+ import type { SEOSection } from '../../../types';
3
+ import type { FpvDroneSpeedLocaleContent } from '../entry';
4
+ import { BIBLIOGRAPHY_ITEMS } from '../bibliography';
5
+
6
+ const title = 'Geschwindigkeitsrechner für FPV Drohnen';
7
+ const description = 'Schätze die Vorwärtsgeschwindigkeit aus Motor KV, Akkuspannung, Propellersteigung, Wirkungsgrad und Flugmasse und sieh Schlupf und Empfindlichkeit getrennt.';
8
+ const ui = { presetsLabel: 'Mit einem Flugsetup starten', presetRacing: 'Racing 4S', presetFreestyle: 'Freestyle 6S', presetCruiser: 'Cruiser 7 Zoll', unitsLabel: 'Anzeigeeinheiten', metricUnit: 'Metrisch', imperialUnit: 'Imperial', inputsLabel: 'Flugrezept', motorKvLabel: 'Motor KV', batteryVoltageLabel: 'Akkuspannung', propellerPitchLabel: 'Propellersteigung', efficiencyLabel: 'Wirkungsgradschätzung', aircraftMassLabel: 'Flugmasse', calculateFromLabel: 'Schätzung aus fünf Eingaben', resultsLabel: 'Flugspur', estimatedSpeedLabel: 'Geschätzte Vorwärtsgeschwindigkeit', pitchSpeedLabel: 'Steiggeschwindigkeit ohne Schlupf', loadedRpmLabel: 'Motordrehzahl unter Last', noLoadRpmLabel: 'Drehzahl ohne Last', slipLabel: 'Durch Schlupf verlorene Geschwindigkeit', loadEffectLabel: 'Lastkorrektur', speedLaneLabel: 'Geschwindigkeitsspur des Propellers', sensitivityLabel: 'Nur eine Änderung auf einmal', lowerPitchLabel: 'Kleinere Steigung', selectedPitchLabel: 'Gewählte Steigung', higherPitchLabel: 'Größere Steigung', diagnosisLabel: 'Einordnung', diagnosisPlanning: 'Planungsschätzung', diagnosisHighSlip: 'Hoher Schlupf', diagnosisHeavyLoad: 'Hohe Last', diagnosisOverspeed: 'Drehzahl prüfen', diagnosisPlanningAdvice: 'Nutze dies als erste Größenordnung und vergleiche sie danach mit Herstellerdaten oder einem Prüfstand.', diagnosisHighSlipAdvice: 'Der gewählte Wirkungsgrad lässt eine große Lücke zwischen geometrischer Steiggeschwindigkeit und Vorwärtsflug. Prüfe Last, Spannungseinbruch und Motortemperatur.', diagnosisHeavyLoadAdvice: 'Die Flugmasse macht die Lastkorrektur wichtiger. Behandle die Geschwindigkeit als groben Planungsbereich und prüfe den kompletten Antrieb.', diagnosisOverspeedAdvice: 'Die Leerlaufdrehzahl ist für dieses Setup ungewöhnlich hoch. Prüfe Motor, Akku und Propellergrenzen vor dem Einschalten.', assumptionsLabel: 'Modellgrenze.', assumptionsText: 'Die Steiggeschwindigkeit ist geometrisch: Steigung mal belastete Drehzahl. Der Wirkungsgrad ist ein eingegebener Näherungswert für Schlupf; die Masse erzeugt eine kleine, sichtbare Lastkorrektur. Propellerdurchmesser, Schubkurve und Wind fehlen.', safetyText: 'Keine Fluggarantie. Halte Abstand zum Propeller und prüfe Strom, Temperatur, Vibrationen und Geschwindigkeit kontrolliert.', speedAxisStart: '0 km/h', speedAxisEnd: '300 km/h', noLoadCaption: 'ohne Last', loadedCaption: 'belastet', slipCaption: 'Schlupf', massUnit: 'g', speedUnit: 'km/h' } satisfies Record<string, string>;
9
+ const faq = [
10
+ { question: 'Wie wird die Steiggeschwindigkeit einer FPV Drohne berechnet?', answer: 'Die Propellersteigung wird mit der belasteten Drehzahl multipliziert und von Zoll pro Umdrehung in Kilometer pro Stunde umgerechnet. Das ist eine geometrische Geschwindigkeit ohne Schlupf und keine Zusage für die Fluggeschwindigkeit.' },
11
+ { question: 'Was bedeutet Wirkungsgrad in dieser Schätzung?', answer: 'Der Wirkungsgrad ist ein Planungswert für die Lücke zwischen geometrischer Steiggeschwindigkeit und geschätztem Vortrieb. Er ersetzt keine Propellerkennlinie und keinen Flugtest.' },
12
+ { question: 'Warum beeinflusst die Flugmasse das Ergebnis?', answer: 'Ein schweres Fluggerät belastet den Antrieb meist stärker. Das Modell verwendet deshalb eine kleine begrenzte Drehzahlkorrektur. Ohne Durchmesser, Schubdaten und Motordrehmoment bleibt sie eine transparente Näherung.' },
13
+ { question: 'Bestätigt der Rechner, dass die Drohne sicher fliegt?', answer: 'Nein. Motor, ESC, Akku, Propeller, Rahmen und Flugsteuerung müssen anhand ihrer Herstellergrenzen und eines gesicherten Prüfstands geprüft werden.' },
14
+ { question: 'Warum ist die echte Geschwindigkeit kleiner als die Steigungsgeschwindigkeit?', answer: 'Die geometrische Geschwindigkeit nimmt an, dass der Propeller seine Nennsteigung pro Umdrehung vorrückt. Schlupf, Blattform, Spannungseinbruch, Last und Einbauverluste verringern den nutzbaren Vortrieb.' },
15
+ ];
16
+ const howTo = [{ name: 'Antrieb eingeben', text: 'Gib Motor KV und die erwartete Akkuspannung unter Last ein, nicht nur den Nennwert des Akkus.' }, { name: 'Propeller und Fluggerät beschreiben', text: 'Gib Steigung, einen vorsichtigen Wirkungsgrad und die flugfertige Masse ein. Ein Preset hilft beim Start.' }, { name: 'Spur lesen und prüfen', text: 'Vergleiche Schätzung, Steiggeschwindigkeit, Schlupf und Steigungsempfindlichkeit. Verwende das Ergebnis als Prüfplan.' }];
17
+ const seo: SEOSection[] = [{ type: 'title', text: 'FPV Drohnengeschwindigkeit aus der Propellersteigung schätzen', level: 2 }, { type: 'paragraph', html: 'Eine Geschwindigkeitsschätzung für FPV Drohnen beginnt mit der Strecke, die ein Propeller mit fester Steigung pro Umdrehung zurücklegen würde. Motor KV und Akkuspannung liefern eine erste Drehzahl; Wirkungsgrad und Flugmasse setzen die Zahl in einen vorsichtigen Planungsrahmen. Der Rechner zeigt geometrische Steiggeschwindigkeit und geschätzten Vortrieb gemeinsam, damit Annahmen nicht mit Messwerten verwechselt werden.' }, { type: 'title', text: 'Die Geschwindigkeitsspur lesen', level: 2 }, { type: 'table', headers: ['Signal', 'Bedeutung'], rows: [['Steigung ohne Schlupf', 'Steigung mal belastete Drehzahl; jede Umdrehung bewegt den Propeller um seine Nennsteigung.'], ['Geschätzter Vortrieb', 'Der Wert ohne Schlupf, multipliziert mit dem eingegebenen Wirkungsgrad.'], ['Verlorene Geschwindigkeit', 'Prozentuale Lücke zwischen geometrischer Steigung und geschätztem Vortrieb.'], ['Steigungsempfindlichkeit', 'Ergebnis bei 0,5 Zoll weniger oder mehr Steigung im gleichen Setup.']] }, { type: 'title', text: 'Die Schätzung sinnvoll verwenden', level: 2 }, { type: 'list', items: ['Verwende die erwartete Spannung unter Last.', 'Beginne mit bekannten Motor Propeller Daten oder Herstellerwerten.', 'Nutze hohen Schlupf als Hinweis, Last, Spannungseinbruch und Propellerwahl zu prüfen.', 'Kontrolliere Strom, Temperatur, Vibrationen und echte Geschwindigkeit vor dem Flug.'] }, { type: 'paragraph', html: 'Propellerleistung verändert sich mit Fortschrittsgrad, Blattgeometrie, Luftdichte, Zufluss und Betriebswinkel. Forschungsmethoden für UAV Propeller verwenden gemessene oder identifizierte Aerodynamikdaten. Dieser Rechner bleibt bewusst einfacher und ersetzt weder Kennlinie noch Schubprüfstand.' }, { type: 'tip', title: 'Die Lücke als Entscheidungshilfe nutzen', html: 'Wenn ein Setup nur wegen einer hohen Zahl ohne Schlupf schnell wirkt, prüfe die Differenz zur wirkungsgradbereinigten Schätzung. Eine kleinere Steigung kann die Last verringern, braucht aber weiterhin eine echte Antriebsprüfung.' }];
18
+ const schemas: FpvDroneSpeedLocaleContent['schemas'] = [{ '@context': 'https://schema.org', '@type': 'FAQPage', mainEntity: faq.map((item) => ({ '@type': 'Question', name: item.question, acceptedAnswer: { '@type': 'Answer', text: item.answer } })) } as WithContext<FAQPage>, { '@context': 'https://schema.org', '@type': 'HowTo', name: title, description, step: howTo.map((step, index) => ({ '@type': 'HowToStep', position: index + 1, name: step.name, text: step.text })) } as WithContext<HowTo>, { '@context': 'https://schema.org', '@type': 'SoftwareApplication', name: title, description, applicationCategory: 'UtilityApplication', operatingSystem: 'All', offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' } } as WithContext<SoftwareApplication>];
19
+ export const content: FpvDroneSpeedLocaleContent = { slug: 'fpv-drohnen-geschwindigkeitsrechner', title, description, ui, seo, faq, bibliography: BIBLIOGRAPHY_ITEMS, howTo, schemas };
20
+ seo.push({ type: 'title', text: 'Messung bleibt der letzte Schritt', level: 2 });
@@ -0,0 +1,47 @@
1
+ import type { FAQPage, HowTo, SoftwareApplication, WithContext } from 'schema-dts';
2
+ import type { SEOSection } from '../../../types';
3
+ import type { FpvDroneSpeedLocaleContent } from '../entry';
4
+ import { BIBLIOGRAPHY_ITEMS } from '../bibliography';
5
+
6
+ const slug = 'fpv-drone-speed-calculator';
7
+ const title = 'FPV Drone Speed Calculator';
8
+ const description = 'Estimate an FPV drone propeller speed from motor KV, battery voltage, propeller pitch, efficiency and aircraft mass, with slip and sensitivity shown separately.';
9
+
10
+ const ui = {
11
+ presetsLabel: 'Start with a flight setup', presetRacing: 'Racing 4S', presetFreestyle: 'Freestyle 6S', presetCruiser: 'Cruiser 7 inch',
12
+ unitsLabel: 'Display units', metricUnit: 'Metric', imperialUnit: 'Imperial', inputsLabel: 'Flight recipe', motorKvLabel: 'Motor KV', batteryVoltageLabel: 'Battery voltage', propellerPitchLabel: 'Propeller pitch', efficiencyLabel: 'Efficiency estimate', aircraftMassLabel: 'Aircraft mass', calculateFromLabel: 'Build the estimate from five inputs', resultsLabel: 'Flight trace', estimatedSpeedLabel: 'Estimated forward speed', pitchSpeedLabel: 'No-slip pitch speed', loadedRpmLabel: 'Loaded motor speed', noLoadRpmLabel: 'No-load RPM', slipLabel: 'Speed left as slip', loadEffectLabel: 'Load correction', speedLaneLabel: 'Propeller speed lane', sensitivityLabel: 'One change at a time', lowerPitchLabel: 'Lower pitch', selectedPitchLabel: 'Selected pitch', higherPitchLabel: 'Higher pitch', diagnosisLabel: 'Reading', diagnosisPlanning: 'Planning estimate', diagnosisHighSlip: 'High slip', diagnosisHeavyLoad: 'Heavy load', diagnosisOverspeed: 'Check RPM', diagnosisPlanningAdvice: 'Use this as a first sizing estimate, then compare it with a manufacturer chart or a thrust-stand test.', diagnosisHighSlipAdvice: 'The selected efficiency leaves a wide gap between geometric pitch speed and forward speed. Check propeller loading, battery sag and motor temperature.', diagnosisHeavyLoadAdvice: 'The aircraft mass makes the load correction more influential. Treat the speed as a broad planning range and validate the complete powertrain.', diagnosisOverspeedAdvice: 'The no-load RPM is unusually high for this setup. Check the motor, battery and propeller limits before applying power.', assumptionsLabel: 'Model boundary.', assumptionsText: 'Pitch speed is geometric: pitch x loaded RPM. Efficiency is a user-entered proxy for slip; aircraft mass applies a small transparent load correction. The model has no propeller diameter, thrust curve or wind data.', safetyText: 'This is not a flight guarantee. Keep clear of the propeller and validate current, temperature, vibration and speed in a controlled test.', speedAxisStart: '0 km/h', speedAxisEnd: '300 km/h', noLoadCaption: 'no-load', loadedCaption: 'loaded', slipCaption: 'slip', massUnit: 'g', speedUnit: 'km/h',
13
+ } satisfies Record<string, string>;
14
+
15
+ const faq = [
16
+ { question: 'How is FPV drone pitch speed calculated?', answer: 'The calculator multiplies propeller pitch by loaded revolutions per minute and converts inches per revolution into kilometres per hour. That is a geometric no-slip speed, not a promise of airspeed.' },
17
+ { question: 'What does efficiency mean in this speed estimate?', answer: 'Efficiency is an explicit planning proxy for the gap between geometric pitch speed and estimated forward speed. It does not replace a propeller performance map or a flight test.' },
18
+ { question: 'Why does aircraft mass affect the result?', answer: 'A heavier aircraft generally loads the powertrain more, so the tool applies a small bounded RPM correction. Without propeller diameter, thrust data and motor torque data, this correction is only a transparent heuristic.' },
19
+ { question: 'Can this calculator confirm my drone is safe to fly?', answer: 'No. It cannot validate a motor, ESC, battery, propeller, frame or flight controller. Check manufacturer limits and verify the setup on a restrained test stand before flight.' },
20
+ { question: 'Why is the real speed lower than pitch speed?', answer: 'Geometric pitch assumes the propeller advances its stated distance every revolution. Slip, blade shape, airflow, voltage sag, loading and installation losses reduce the useful forward speed.' },
21
+ ];
22
+
23
+ const howTo = [
24
+ { name: 'Enter the powertrain', text: 'Enter motor KV and the battery voltage you expect under load, not only the nominal pack label.' },
25
+ { name: 'Describe the propeller and aircraft', text: 'Enter geometric pitch, a conservative efficiency estimate and ready-to-fly aircraft mass. Use the presets when you need a starting point.' },
26
+ { name: 'Read the trace and validate it', text: 'Compare estimated speed with no-slip pitch speed, slip and the pitch sensitivity view. Treat the result as a test plan and verify the complete powertrain safely.' },
27
+ ];
28
+
29
+ const seo: SEOSection[] = [
30
+ { type: 'title', text: 'Estimate FPV Drone Speed from Propeller Pitch', level: 2 },
31
+ { type: 'paragraph', html: 'An FPV drone speed estimate starts with the distance a fixed-pitch propeller would advance in one revolution. Motor KV and battery voltage provide a first RPM estimate, while efficiency and aircraft mass help frame a conservative planning number. This calculator keeps the geometric pitch speed and the estimated forward speed visible together so you can see the assumptions instead of confusing them with a measured result.' },
32
+ { type: 'title', text: 'What the speed trace means', level: 2 },
33
+ { type: 'table', headers: ['Signal', 'Interpretation'], rows: [['No-slip pitch speed', 'Pitch multiplied by loaded RPM. It assumes the propeller advances its nominal pitch every revolution.'], ['Estimated forward speed', 'The no-slip value multiplied by the efficiency proxy you entered.'], ['Speed left as slip', 'The percentage gap between geometric pitch speed and estimated forward speed.'], ['Pitch sensitivity', 'The result if the same setup used a propeller with 0.5 inch less or more pitch.']] },
34
+ { type: 'title', text: 'A practical way to use the estimate', level: 2 },
35
+ { type: 'list', items: ['Use the battery voltage expected under load rather than an optimistic full-charge value.', 'Start with a known motor and propeller combination or a manufacturer data point.', 'Treat a high slip reading as a prompt to inspect loading, voltage sag and propeller choice.', 'Validate current, temperature, vibration and actual speed in a controlled test before flight.'] },
36
+ { type: 'title', text: 'Why the model has limits', level: 2 },
37
+ { type: 'paragraph', html: 'Propeller performance changes across advance ratio, blade geometry, air density, inflow and operating angle. Research models for UAV propellers use measured or identified aerodynamic data across operating conditions. This lightweight calculator is deliberately narrower: it is useful for comparing a few setup assumptions, but it cannot replace a propeller chart, thrust stand or flight instrumentation.' },
38
+ { type: 'tip', title: 'Use the gap as a decision signal', html: 'If a setup looks fast only because its no-slip number is high, inspect the gap to the efficiency-adjusted estimate. A lower-pitch propeller may trade headline speed for a more manageable load and better response, but that choice still needs a real powertrain check.' },
39
+ ];
40
+
41
+ const schemas: FpvDroneSpeedLocaleContent['schemas'] = [
42
+ { '@context': 'https://schema.org', '@type': 'FAQPage', mainEntity: faq.map((item) => ({ '@type': 'Question', name: item.question, acceptedAnswer: { '@type': 'Answer', text: item.answer } })) } as WithContext<FAQPage>,
43
+ { '@context': 'https://schema.org', '@type': 'HowTo', name: title, description, step: howTo.map((step, index) => ({ '@type': 'HowToStep', position: index + 1, name: step.name, text: step.text })) } as WithContext<HowTo>,
44
+ { '@context': 'https://schema.org', '@type': 'SoftwareApplication', name: title, description, applicationCategory: 'UtilityApplication', operatingSystem: 'All', offers: { '@type': 'Offer', price: '0', priceCurrency: 'USD' } } as WithContext<SoftwareApplication>,
45
+ ];
46
+
47
+ export const content: FpvDroneSpeedLocaleContent = { slug, title, description, ui, seo, faq, bibliography: BIBLIOGRAPHY_ITEMS, howTo, schemas };
@@ -0,0 +1,40 @@
1
+ import type { FAQPage, HowTo, SoftwareApplication, WithContext } from 'schema-dts';
2
+ import type { SEOSection } from '../../../types';
3
+ import type { FpvDroneSpeedLocaleContent } from '../entry';
4
+ import { BIBLIOGRAPHY_ITEMS } from '../bibliography';
5
+
6
+ const slug = 'calculadora-velocidad-drone-fpv';
7
+ const title = 'Calculadora de Velocidad para Drones FPV';
8
+ const description = 'Estima la velocidad de un dron FPV a partir del KV del motor, el voltaje, el paso de hélice, la eficiencia y la masa de la aeronave, mostrando el deslizamiento y la sensibilidad.';
9
+ const ui = {
10
+ presetsLabel: 'Empieza con un montaje', presetRacing: 'Carreras 4S', presetFreestyle: 'Freestyle 6S', presetCruiser: 'Crucero 7 pulgadas', unitsLabel: 'Unidades de pantalla', metricUnit: 'Métrico', imperialUnit: 'Imperial', inputsLabel: 'Receta de vuelo', motorKvLabel: 'KV del motor', batteryVoltageLabel: 'Voltaje de batería', propellerPitchLabel: 'Paso de hélice', efficiencyLabel: 'Estimación de eficiencia', aircraftMassLabel: 'Masa de la aeronave', calculateFromLabel: 'Construye la estimación con cinco datos', resultsLabel: 'Trazado de vuelo', estimatedSpeedLabel: 'Velocidad de avance estimada', pitchSpeedLabel: 'Velocidad de paso sin deslizamiento', loadedRpmLabel: 'Velocidad cargada del motor', noLoadRpmLabel: 'RPM sin carga', slipLabel: 'Velocidad perdida por deslizamiento', loadEffectLabel: 'Corrección por carga', speedLaneLabel: 'Carril de velocidad de la hélice', sensitivityLabel: 'Cambia una cosa cada vez', lowerPitchLabel: 'Paso menor', selectedPitchLabel: 'Paso elegido', higherPitchLabel: 'Paso mayor', diagnosisLabel: 'Lectura', diagnosisPlanning: 'Estimación de planificación', diagnosisHighSlip: 'Deslizamiento alto', diagnosisHeavyLoad: 'Carga alta', diagnosisOverspeed: 'Revisa las RPM', diagnosisPlanningAdvice: 'Úsalo como primera comparación y contrástalo con una tabla del fabricante o un ensayo en banco.', diagnosisHighSlipAdvice: 'La eficiencia elegida deja una brecha amplia entre la velocidad geométrica y el avance. Revisa carga, caída de voltaje y temperatura.', diagnosisHeavyLoadAdvice: 'La masa da más peso a la corrección de carga. Trata la velocidad como un rango amplio y valida todo el conjunto.', diagnosisOverspeedAdvice: 'Las RPM sin carga son inusualmente altas. Comprueba los límites del motor, la batería y la hélice antes de aplicar potencia.', assumptionsLabel: 'Límite del modelo.', assumptionsText: 'La velocidad de paso es geométrica: paso x RPM cargadas. La eficiencia es un indicador introducido por el usuario para aproximar el deslizamiento; la masa aplica una corrección de carga pequeña y transparente. No se usan diámetro, curva de empuje ni viento.', safetyText: 'No es una garantía de vuelo. Mantén distancia de la hélice y valida corriente, temperatura, vibraciones y velocidad en una prueba controlada.', speedAxisStart: '0 km/h', speedAxisEnd: '300 km/h', noLoadCaption: 'sin carga', loadedCaption: 'cargado', slipCaption: 'deslizamiento', massUnit: 'g', speedUnit: 'km/h',
11
+ } satisfies Record<string, string>;
12
+ const faq = [
13
+ { question: '¿Cómo se calcula la velocidad de paso de un dron FPV?', answer: 'Se multiplica el paso de la hélice por las revoluciones por minuto cargadas y se convierten las pulgadas por revolución a kilómetros por hora. Es una velocidad geométrica sin deslizamiento, no una promesa de velocidad aérea.' },
14
+ { question: '¿Qué significa la eficiencia en esta estimación?', answer: 'La eficiencia es un indicador de planificación que representa la distancia entre la velocidad geométrica y el avance estimado. No sustituye una curva de rendimiento ni una prueba de vuelo.' },
15
+ { question: '¿Por qué influye la masa de la aeronave?', answer: 'Una aeronave pesada suele cargar más el sistema, por lo que la herramienta aplica una corrección de RPM pequeña y limitada. Sin diámetro, empuje y par del motor, solo es una heurística transparente.' },
16
+ { question: '¿Confirma esta calculadora que el dron es seguro?', answer: 'No. No valida motor, ESC, batería, hélice, estructura ni controlador. Comprueba los límites del fabricante y verifica el conjunto en un banco sujeto antes de volar.' },
17
+ { question: '¿Por qué la velocidad real es menor que la de paso?', answer: 'La velocidad geométrica supone que la hélice avanza su paso nominal en cada vuelta. El deslizamiento, la forma de las palas, la caída de voltaje, la carga y las pérdidas de montaje reducen el avance útil.' },
18
+ ];
19
+ const howTo = [
20
+ { name: 'Introduce la propulsión', text: 'Escribe el KV del motor y el voltaje que esperas bajo carga, no solo el valor nominal de la batería.' },
21
+ { name: 'Describe la hélice y el dron', text: 'Introduce el paso geométrico, una eficiencia prudente y la masa lista para volar. Usa un preset si necesitas un punto de partida.' },
22
+ { name: 'Lee el trazado y valida', text: 'Compara la velocidad estimada con la de paso, el deslizamiento y la sensibilidad. Convierte el resultado en un plan de prueba y valida la propulsión con seguridad.' },
23
+ ];
24
+ const seo: SEOSection[] = [
25
+ { type: 'title', text: 'Estimar la velocidad de un dron FPV con el paso de hélice', level: 2 },
26
+ { type: 'paragraph', html: 'Una estimación de velocidad para un dron FPV parte de la distancia que una hélice de paso fijo avanzaría en una vuelta. El KV y el voltaje proporcionan una primera aproximación de las RPM; la eficiencia y la masa ayudan a encuadrar una cifra de planificación. La calculadora mantiene visibles la velocidad geométrica y el avance estimado para que las hipótesis no se confundan con una medición.' },
27
+ { type: 'title', text: 'Qué significa el trazado de velocidad', level: 2 },
28
+ { type: 'table', headers: ['Señal', 'Interpretación'], rows: [['Velocidad de paso sin deslizamiento', 'Paso multiplicado por las RPM cargadas. Supone que la hélice avanza su paso nominal en cada vuelta.'], ['Velocidad de avance estimada', 'El valor sin deslizamiento multiplicado por la eficiencia introducida.'], ['Velocidad perdida por deslizamiento', 'Porcentaje de diferencia entre velocidad geométrica y avance estimado.'], ['Sensibilidad al paso', 'Resultado si el mismo montaje usara 0,5 pulgadas menos o más de paso.']] },
29
+ { type: 'title', text: 'Cómo usar la estimación', level: 2 },
30
+ { type: 'list', items: ['Usa el voltaje esperado bajo carga y no un valor optimista de batería recién cargada.', 'Parte de una combinación de motor y hélice conocida o de datos del fabricante.', 'Interpreta un deslizamiento alto como señal para revisar carga, caída de voltaje y elección de hélice.', 'Verifica corriente, temperatura, vibraciones y velocidad real en una prueba controlada antes de volar.'] },
31
+ { type: 'title', text: 'Por qué el modelo tiene límites', level: 2 },
32
+ { type: 'paragraph', html: 'El rendimiento de una hélice cambia con el avance, la geometría de las palas, la densidad del aire, la entrada de flujo y el ángulo de operación. Los modelos de hélices UAV de investigación usan datos medidos o identificados para cubrir esas condiciones. Esta calculadora es más estrecha: sirve para comparar hipótesis de montaje, pero no reemplaza una tabla de hélice, un banco de empuje ni instrumentación de vuelo.' },
33
+ { type: 'tip', title: 'Usa la brecha para decidir', html: 'Si un montaje parece rápido solo porque su cifra sin deslizamiento es alta, revisa la distancia hasta la estimación ajustada por eficiencia. Una hélice de menor paso puede cambiar velocidad máxima por una carga más manejable, pero también necesita una comprobación real.' },
34
+ ];
35
+ const schemas: FpvDroneSpeedLocaleContent['schemas'] = [
36
+ { '@context': 'https://schema.org', '@type': 'FAQPage', mainEntity: faq.map((item) => ({ '@type': 'Question', name: item.question, acceptedAnswer: { '@type': 'Answer', text: item.answer } })) } as WithContext<FAQPage>,
37
+ { '@context': 'https://schema.org', '@type': 'HowTo', name: title, description, step: howTo.map((step, index) => ({ '@type': 'HowToStep', position: index + 1, name: step.name, text: step.text })) } as WithContext<HowTo>,
38
+ { '@context': 'https://schema.org', '@type': 'SoftwareApplication', name: title, description, applicationCategory: 'UtilityApplication', operatingSystem: 'All', offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' } } as WithContext<SoftwareApplication>,
39
+ ];
40
+ export const content: FpvDroneSpeedLocaleContent = { slug, title, description, ui, seo, faq, bibliography: BIBLIOGRAPHY_ITEMS, howTo, schemas };