@jjlmoya/utils-nautical 1.22.0 → 1.23.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 (41) hide show
  1. package/package.json +1 -1
  2. package/src/category/index.ts +2 -1
  3. package/src/data.ts +1 -0
  4. package/src/entries.ts +4 -1
  5. package/src/index.ts +1 -0
  6. package/src/tests/i18n_coverage.test.ts +6 -1
  7. package/src/tests/locale_completeness.test.ts +2 -2
  8. package/src/tests/tool_validation.test.ts +7 -4
  9. package/src/tool/hullSpeed/bibliography.astro +14 -0
  10. package/src/tool/hullSpeed/bibliography.ts +12 -0
  11. package/src/tool/hullSpeed/component.astro +116 -0
  12. package/src/tool/hullSpeed/controller.ts +204 -0
  13. package/src/tool/hullSpeed/dom-views.ts +141 -0
  14. package/src/tool/hullSpeed/entry.ts +32 -0
  15. package/src/tool/hullSpeed/evaluator.ts +20 -0
  16. package/src/tool/hullSpeed/hull-draw.ts +185 -0
  17. package/src/tool/hullSpeed/i18n/de.ts +199 -0
  18. package/src/tool/hullSpeed/i18n/en.ts +199 -0
  19. package/src/tool/hullSpeed/i18n/es.ts +199 -0
  20. package/src/tool/hullSpeed/i18n/fr.ts +199 -0
  21. package/src/tool/hullSpeed/i18n/id.ts +199 -0
  22. package/src/tool/hullSpeed/i18n/it.ts +199 -0
  23. package/src/tool/hullSpeed/i18n/ja.ts +199 -0
  24. package/src/tool/hullSpeed/i18n/ko.ts +199 -0
  25. package/src/tool/hullSpeed/i18n/nl.ts +199 -0
  26. package/src/tool/hullSpeed/i18n/pl.ts +199 -0
  27. package/src/tool/hullSpeed/i18n/pt.ts +199 -0
  28. package/src/tool/hullSpeed/i18n/ru.ts +199 -0
  29. package/src/tool/hullSpeed/i18n/sv.ts +199 -0
  30. package/src/tool/hullSpeed/i18n/tr.ts +199 -0
  31. package/src/tool/hullSpeed/i18n/zh.ts +199 -0
  32. package/src/tool/hullSpeed/index.ts +11 -0
  33. package/src/tool/hullSpeed/logic.test.ts +105 -0
  34. package/src/tool/hullSpeed/logic.ts +116 -0
  35. package/src/tool/hullSpeed/presets.ts +17 -0
  36. package/src/tool/hullSpeed/sailboat-hull-speed-calculator.css +504 -0
  37. package/src/tool/hullSpeed/seo.astro +15 -0
  38. package/src/tool/hullSpeed/storage.test.ts +23 -0
  39. package/src/tool/hullSpeed/storage.ts +65 -0
  40. package/src/tool/hullSpeed/ui.ts +43 -0
  41. package/src/tools.ts +3 -0
@@ -0,0 +1,185 @@
1
+ import type { HullKind } from './logic';
2
+
3
+ interface Frame {
4
+ s: number;
5
+ b: number;
6
+ w: number;
7
+ L: number;
8
+ kind: HullKind;
9
+ }
10
+
11
+ export interface BoatDraw {
12
+ stern: number;
13
+ bow: number;
14
+ wl: number;
15
+ lift: number;
16
+ kind: HullKind;
17
+ }
18
+
19
+ function frameOf(draw: BoatDraw): Frame {
20
+ return {
21
+ s: draw.stern,
22
+ b: draw.bow,
23
+ w: draw.wl + draw.lift,
24
+ L: draw.bow - draw.stern,
25
+ kind: draw.kind,
26
+ };
27
+ }
28
+
29
+ function fb(kind: HullKind, length: number): number {
30
+ if (kind === 'planing') return 54 + length * 0.03;
31
+ if (kind === 'semi') return 62 + length * 0.035;
32
+ return 74 + length * 0.045;
33
+ }
34
+
35
+ function sheer(frame: Frame): { ds: number; db: number; ox: number; oy: number } {
36
+ if (frame.kind === 'planing') {
37
+ return {
38
+ ds: frame.w - 50,
39
+ db: frame.w - 58,
40
+ ox: Math.min(18, frame.L * 0.04),
41
+ oy: 12,
42
+ };
43
+ }
44
+ const rise = fb(frame.kind, frame.L);
45
+ return {
46
+ ds: frame.w - rise * 0.78,
47
+ db: frame.w - rise * 1.22,
48
+ ox: Math.min(24, frame.L * 0.05),
49
+ oy: 16,
50
+ };
51
+ }
52
+
53
+ function deckPlane(frame: Frame): string {
54
+ const { ds, db, ox, oy } = sheer(frame);
55
+ return `M ${frame.s} ${ds} L ${frame.b} ${db} L ${frame.b + ox} ${db - oy} L ${frame.s + ox} ${ds - oy} Z`;
56
+ }
57
+
58
+ function topsides(frame: Frame): string {
59
+ const { ds, db } = sheer(frame);
60
+ if (frame.kind === 'planing') {
61
+ const aft = frame.s - 18;
62
+ return `M ${frame.s} ${frame.w} L ${aft} ${ds} L ${frame.b - 8} ${db} L ${frame.b + 6} ${frame.w - 6} L ${frame.b} ${frame.w} Z`;
63
+ }
64
+ const stem = frame.kind === 'displacement' ? 18 : 9;
65
+ return `M ${frame.s} ${frame.w} L ${frame.s - 10} ${ds} L ${frame.b} ${db} L ${frame.b + stem} ${frame.w - 10} L ${frame.b} ${frame.w} Z`;
66
+ }
67
+
68
+ function gunwale(frame: Frame): string {
69
+ const { ds, db } = sheer(frame);
70
+ return `M ${frame.s} ${ds} L ${frame.b} ${db} L ${frame.b} ${db + 7} L ${frame.s} ${ds + 7} Z`;
71
+ }
72
+
73
+ function transom(frame: Frame): string {
74
+ const { ds, ox, oy } = sheer(frame);
75
+ if (frame.kind === 'planing') {
76
+ const aft = frame.s - 18;
77
+ return `M ${frame.s} ${frame.w} L ${aft} ${ds} L ${aft + ox} ${ds - oy} L ${frame.s + ox} ${frame.w - 4} Z`;
78
+ }
79
+ return `M ${frame.s} ${frame.w} L ${frame.s} ${ds} L ${frame.s + ox} ${ds - oy} L ${frame.s + ox} ${frame.w - 8} Z`;
80
+ }
81
+
82
+ function underbody(frame: Frame): string {
83
+ const s = frame.s;
84
+ const L = frame.L;
85
+ const w = frame.w;
86
+ if (frame.kind === 'planing') {
87
+ return `M ${s} ${w} L ${s + L * 0.18} ${w + 10} L ${s + L * 0.72} ${w + 11} L ${s + L * 0.92} ${w + 6} L ${frame.b} ${w} Z`;
88
+ }
89
+ return `M ${s} ${w} C ${s + L * 0.14} ${w + 32} ${s + L * 0.38} ${w + 48} ${s + L * 0.52} ${w + 46} C ${s + L * 0.72} ${w + 40} ${s + L * 0.9} ${w + 24} ${frame.b} ${w} Z`;
90
+ }
91
+
92
+ function keelPath(frame: Frame): string {
93
+ const s = frame.s;
94
+ const L = frame.L;
95
+ const w = frame.w;
96
+ if (frame.kind === 'planing') {
97
+ return `M ${s + L * 0.16} ${w} L ${s + L * 0.6} ${w} L ${s + L * 0.4} ${w + 22} Z`;
98
+ }
99
+ if (frame.kind === 'semi') {
100
+ return `M ${s + L * 0.22} ${w} L ${s + L * 0.7} ${w} L ${s + L * 0.5} ${w + 52} L ${s + L * 0.32} ${w + 46} Z`;
101
+ }
102
+ return `M ${s + L * 0.18} ${w} L ${s + L * 0.66} ${w} L ${s + L * 0.54} ${w + 78} L ${s + L * 0.28} ${w + 70} Z`;
103
+ }
104
+
105
+ function cabinPath(frame: Frame): string {
106
+ const { ds } = sheer(frame);
107
+ if (frame.kind === 'planing') return planingCockpit(frame, ds);
108
+ const x0 = frame.s + frame.L * 0.27;
109
+ const x1 = frame.s + frame.L * 0.6;
110
+ return `<path class="n-hull-cabin" d="M ${x0} ${ds} L ${x0 + 10} ${ds - 46} L ${x1 - 4} ${ds - 44} L ${x1 + 12} ${ds} Z" />`;
111
+ }
112
+
113
+ function planingCockpit(frame: Frame, ds: number): string {
114
+ const x0 = frame.s + frame.L * 0.22;
115
+ const x1 = frame.s + frame.L * 0.48;
116
+ const x2 = frame.s + frame.L * 0.7;
117
+ const screen = `M ${x1} ${ds} L ${x1 + 10} ${ds - 32} L ${x2} ${ds - 30} L ${x2 + 8} ${ds} Z`;
118
+ const console = `M ${x0} ${ds} L ${x0} ${ds - 16} L ${x1 - 4} ${ds - 16} L ${x1 - 4} ${ds} Z`;
119
+ return `<path class="n-hull-cabin" d="${console}" /><path class="n-hull-glass" d="${screen}" />`;
120
+ }
121
+
122
+ function ports(frame: Frame): string {
123
+ if (frame.kind === 'planing') return '';
124
+ const { ds } = sheer(frame);
125
+ const y = ds - 22;
126
+ const x1 = frame.s + frame.L * 0.36;
127
+ const x2 = frame.s + frame.L * 0.48;
128
+ return `<circle class="n-hull-glass" cx="${x1.toFixed(1)}" cy="${y.toFixed(1)}" r="5" /><circle class="n-hull-glass" cx="${x2.toFixed(1)}" cy="${y.toFixed(1)}" r="5" />`;
129
+ }
130
+
131
+ function rig(frame: Frame): string {
132
+ if (frame.kind === 'planing') return '';
133
+ const { ds } = sheer(frame);
134
+ const x = frame.s + frame.L * 0.42;
135
+ const boom = frame.L * 0.28;
136
+ return `<path class="n-hull-spar" d="M ${x} ${ds - 44} L ${x} ${ds - 168}" /><path class="n-hull-spar" d="M ${x} ${ds - 70} L ${x + boom} ${ds - 58}" />`;
137
+ }
138
+
139
+ function rudder(frame: Frame): string {
140
+ const s = frame.s;
141
+ const w = frame.w;
142
+ return `M ${s + 7} ${w} L ${s - 6} ${w + 40} L ${s + 12} ${w + 40} L ${s + 16} ${w} Z`;
143
+ }
144
+
145
+ function drive(frame: Frame): string {
146
+ if (frame.kind === 'planing') return outboard(frame);
147
+ return `<path class="n-hull-keel" d="${rudder(frame)}" />`;
148
+ }
149
+
150
+ function outboard(frame: Frame): string {
151
+ const { ds } = sheer(frame);
152
+ const x = frame.s - 14;
153
+ const cowling = `M ${x - 7} ${ds - 4} L ${x + 9} ${ds - 4} L ${x + 8} ${ds + 18} L ${x - 6} ${ds + 18} Z`;
154
+ const shaft = `M ${x} ${ds + 18} L ${x} ${frame.w + 28}`;
155
+ const foot = `M ${x - 5} ${frame.w + 24} L ${x + 14} ${frame.w + 26} L ${x + 12} ${frame.w + 34} L ${x - 4} ${frame.w + 32} Z`;
156
+ return `<path class="n-hull-keel" d="${cowling}" /><path class="n-hull-spar" d="${shaft}" /><path class="n-hull-keel" d="${foot}" />`;
157
+ }
158
+
159
+ function chine(frame: Frame): string {
160
+ if (frame.kind !== 'planing') return '';
161
+ const y = frame.w - 16;
162
+ return `<path class="n-hull-chine" d="M ${frame.s + 6} ${y} L ${frame.b - 10} ${y - 8}" />`;
163
+ }
164
+
165
+ function boot(frame: Frame): string {
166
+ return `M ${frame.s} ${frame.w - 4} L ${frame.b} ${frame.w - 4} L ${frame.b} ${frame.w + 5} L ${frame.s} ${frame.w + 5} Z`;
167
+ }
168
+
169
+ export function boatMarkup(draw: BoatDraw): string {
170
+ const frame = frameOf(draw);
171
+ return [
172
+ `<path class="n-hull-keel" d="${keelPath(frame)}" />`,
173
+ drive(frame),
174
+ `<path class="n-hull-body" d="${underbody(frame)}" />`,
175
+ `<path class="n-hull-topside" d="${topsides(frame)}" />`,
176
+ `<path class="n-hull-transom" d="${transom(frame)}" />`,
177
+ `<path class="n-hull-deck" d="${deckPlane(frame)}" />`,
178
+ `<path class="n-hull-gunwale" d="${gunwale(frame)}" />`,
179
+ `<path class="n-hull-bootfill" d="${boot(frame)}" />`,
180
+ chine(frame),
181
+ cabinPath(frame),
182
+ ports(frame),
183
+ rig(frame),
184
+ ].join('');
185
+ }
@@ -0,0 +1,199 @@
1
+ import { bibliography } from '../bibliography';
2
+ import type { HullSpeedLocaleContent, HullSpeedUI } from '../index';
3
+ import type { FAQPage, HowTo, SoftwareApplication, WithContext } from 'schema-dts';
4
+
5
+ const slug = 'rumpfgeschwindigkeit-rechner';
6
+ const title = 'Rechner für Rumpfgeschwindigkeit';
7
+ const description =
8
+ 'Ermittle die theoretische Rumpfgeschwindigkeit aus der Wasserlinienlänge, vergleiche ein Log und sieh, wann ein Verdränger in seine eigene Bugwelle klettert.';
9
+
10
+ const ui: HullSpeedUI = {
11
+ metric: 'Metrisch',
12
+ imperial: 'Imperial',
13
+ unitGroup: 'Einheiten',
14
+ sceneLabel: 'Wasserlinie und Bugwelle',
15
+ hullSpeedLabel: 'Rumpfgeschwindigkeit',
16
+ knotsUnit: 'kn',
17
+ kmhUnit: 'km/h',
18
+ mphUnit: 'mph',
19
+ ratioLabel: 'S/L',
20
+ froudeLabel: 'Fr',
21
+ lwlLabelMetric: 'Wasserlinienlänge',
22
+ lwlLabelImperial: 'Wasserlinienlänge',
23
+ lwlUnitM: 'm',
24
+ lwlUnitFt: 'ft',
25
+ observedLabel: 'Loggeschwindigkeit',
26
+ observedHint: 'Lass 0 stehen, um die theoretische Welle zu zeichnen. Tippe ein Log, um zu sehen, ob du noch in der Mulde sitzt.',
27
+ stretchHint: 'Zieh den Rumpf, um die Wasserlinie zu strecken',
28
+ hullKindLabel: 'Rumpfform',
29
+ displacement: 'Verdränger',
30
+ semi: 'Halbverdränger',
31
+ planing: 'Gleiter',
32
+ boatsLabel: 'Beispielwasserlinien',
33
+ dinghy: 'Jolle',
34
+ daysailer: 'Daysailer',
35
+ cruiser: 'Kreuzer',
36
+ bluewater: 'Hochsee',
37
+ workboat: 'Arbeitsschiff',
38
+ bandBelow: 'Noch eine kurze Welle',
39
+ bandNear: 'Näher an der Wellenbarriere',
40
+ bandAt: 'Auf der Bugwelle',
41
+ bandAbove: 'Versucht, die Welle zu erklimmen',
42
+ bandPlane: 'Im Gleitmodus, über der Rumpfgeschwindigkeit',
43
+ planingNote:
44
+ 'Ein Gleiter kann diese Welle hinter sich lassen. Die Rumpfgeschwindigkeit ist eine Referenz, keine Wand.',
45
+ displacementNote:
46
+ 'Ein Verdränger zahlt steil, sobald er seinen eigenen Sog einholt. Nimm sie als praktische Decke, nicht als GPS Ziel.',
47
+ semiNote:
48
+ 'Halbverdränger können den klassischen Faktor mit genug Leistung etwas überschreiten, bei scharfem Widerstandsanstieg.',
49
+ waveLegend: 'Bugwelle',
50
+ waterLegend: 'Wasserlinie',
51
+ markLegend: 'Rumpfgeschwindigkeit',
52
+ faqTitle: 'Fragen zur Rumpfgeschwindigkeit',
53
+ bibliographyTitle: 'Quellen',
54
+ };
55
+
56
+ const faq: HullSpeedLocaleContent['faq'] = [
57
+ {
58
+ question: 'Was ist die Rumpfgeschwindigkeit eines Segelboots?',
59
+ answer:
60
+ 'Es ist die Geschwindigkeit, bei der ein Verdränger mit einer Bugwelle fährt, die ungefähr so lang ist wie seine Wasserlinie. In nautischen Einheiten schätzt man sie als 1.34 mal die Wurzel der Wasserlinienlänge in Fuß. Das ist eine kritische Geschwindigkeit, kein harter physikalischer Stopp.',
61
+ },
62
+ {
63
+ question: 'Wie berechnet man die Rumpfgeschwindigkeit?',
64
+ answer:
65
+ 'Wandle die Wasserlinie in Fuß um, ziehe die Wurzel und multipliziere mit 1.34, um Knoten zu erhalten. Eine 10 m Wasserlinie sind etwa 32.8 ft, also rund 7.7 kn. Derselbe Punkt entspricht einer Froude Zahl nahe 0.40.',
66
+ },
67
+ {
68
+ question: 'Gilt die Rumpfgeschwindigkeit auch für Gleiter?',
69
+ answer:
70
+ 'Die Formel beschreibt weiter die Welle, die der Rumpf im Verdrängermodus machen würde. Gleiter und viele Halbverdränger sind gebaut, um über diese Welle zu klettern. Nimm die Zahl als Referenz und lies den Hinweis zur Rumpfform.',
71
+ },
72
+ {
73
+ question: 'Soll ich Wasserlinienlänge oder Gesamtlänge nehmen?',
74
+ answer:
75
+ 'Nimm die Länge in der Wasserlinie (LWL), die getauchte Länge, die die Welle wirklich macht. Gesamtlänge, Bugspriete und Überhänge setzen die Wellenlänge nicht. Miss LWL im Wasser, nicht die LOA aus dem Prospekt.',
76
+ },
77
+ ];
78
+
79
+ const howTo: HullSpeedLocaleContent['howTo'] = [
80
+ {
81
+ name: 'Wasserlinie strecken',
82
+ text: 'Zieh den Rumpf, bewege die Schiene oder wähle von der Jolle bis zum Arbeitsschiff. Die Rumpfgeschwindigkeit ist 1.34 mal die Wurzel dieser Länge in Fuß.',
83
+ },
84
+ {
85
+ name: 'Rumpfform wählen',
86
+ text: 'Verdränger, Halbverdränger oder Gleiter ändert den Kiel und ob das Boot aus seiner eigenen Welle herausklettern kann.',
87
+ },
88
+ {
89
+ name: 'Die Mulde lesen',
90
+ text: 'Bei Rumpfgeschwindigkeit sitzen Bug und Heckwelle eine Wasserlinie auseinander und das Boot liegt im Trog. Das ist die Barriere.',
91
+ },
92
+ {
93
+ name: 'Ein Log vergleichen',
94
+ text: 'Gib die Fahrt durchs Wasser ein. Eine kürzere Welle heißt, du fährst noch günstig. Eine längere Welle heißt, du kletterst in die Mulde.',
95
+ },
96
+ ];
97
+
98
+ const seo: HullSpeedLocaleContent['seo'] = [
99
+ {
100
+ type: 'title',
101
+ text: 'Was die Rumpfgeschwindigkeit wirklich sagt',
102
+ level: 2,
103
+ },
104
+ {
105
+ type: 'paragraph',
106
+ html: 'Ein Verdränger schiebt eine Welle vom Bug und eine vom Heck. Liegen diese Kämme etwa eine Wasserlinie auseinander, fährt das Boot mit seinem eigenen Sog. Extra Leistung türmt dann vor allem Wasser auf, statt Fahrt zu kaufen. Diesen Zustand nennen Segler Rumpfgeschwindigkeit.',
107
+ },
108
+ {
109
+ type: 'paragraph',
110
+ html: 'Der Rechner nutzt das übliche Amateurverhältnis 1.34 Knoten je Wurzel der Wasserlinie in Fuß. Schlanke, lange Rümpfe liegen etwas höher, Lastkähne tiefer. Nimm das Ergebnis als Lehrstrich und vergleiche es mit einem echten Log.',
111
+ },
112
+ {
113
+ type: 'title',
114
+ text: 'Durchgerechnete Wasserlinien',
115
+ level: 2,
116
+ },
117
+ {
118
+ type: 'table',
119
+ headers: ['Wasserlinie', 'Rumpfgeschwindigkeit', 'Typisches Boot'],
120
+ rows: [
121
+ ['4.2 m / 13.8 ft', '5.0 kn', 'Jolle'],
122
+ ['6.5 m / 21.3 ft', '6.2 kn', 'Daysailer'],
123
+ ['10 m / 32.8 ft', '7.7 kn', 'Familienkreuzer'],
124
+ ['13.5 m / 44.3 ft', '8.9 kn', 'Hochseeyacht'],
125
+ ['18 m / 59.1 ft', '10.3 kn', 'Kleines Arbeitsschiff'],
126
+ ],
127
+ },
128
+ {
129
+ type: 'title',
130
+ text: 'Die Bugwelle lesen',
131
+ level: 2,
132
+ },
133
+ {
134
+ type: 'list',
135
+ items: [
136
+ 'Unter der Marke ist die Welle kurz und das Boot noch günstig zu treiben.',
137
+ 'Nahe der Marke wird die Bugwelle steiler und Kraftstoff oder Segel kaufen weniger Fahrt.',
138
+ 'Auf der Marke passt die Wellenlänge zur LWL. Ein Verdränger steht an der klassischen Barriere.',
139
+ 'Darüber klettert ein Verdränger in seinen Sog. Ein Gleiter kann schon oben sein.',
140
+ ],
141
+ },
142
+ {
143
+ type: 'tip',
144
+ title: 'LWL messen, nicht LOA',
145
+ html: 'Die Prospektlänge enthält Überhänge. Die Welle interessiert die getauchte Wasserlinie. Hast du nur LOA, wird die berechnete Rumpfgeschwindigkeit zu optimistisch.',
146
+ },
147
+ {
148
+ type: 'title',
149
+ text: 'Die Froude Zahl in einem Satz',
150
+ level: 2,
151
+ },
152
+ {
153
+ type: 'paragraph',
154
+ html: 'Rumpfgeschwindigkeit ist eine bequeme Verpackung einer Froude Zahl nahe 0.40: Fahrt geteilt durch die Wurzel aus Schwerkraft mal Länge. Deshalb sind längere Wasserlinien schneller, auch wenn die Rumpfform gleich bleibt. LWL strecken hebt die Verdrängergrenze sauber; Pferdestärken tun das nicht.',
155
+ },
156
+ ];
157
+
158
+ const schemas: HullSpeedLocaleContent['schemas'] = [
159
+ {
160
+ '@context': 'https://schema.org',
161
+ '@type': 'SoftwareApplication',
162
+ name: title,
163
+ description,
164
+ applicationCategory: 'UtilityApplication',
165
+ operatingSystem: 'Web',
166
+ offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' },
167
+ } as WithContext<SoftwareApplication>,
168
+ {
169
+ '@context': 'https://schema.org',
170
+ '@type': 'FAQPage',
171
+ mainEntity: faq.map((item) => ({
172
+ '@type': 'Question',
173
+ name: item.question,
174
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
175
+ })),
176
+ } as WithContext<FAQPage>,
177
+ {
178
+ '@context': 'https://schema.org',
179
+ '@type': 'HowTo',
180
+ name: `${title} verwenden`,
181
+ step: howTo.map((step) => ({
182
+ '@type': 'HowToStep',
183
+ name: step.name,
184
+ text: step.text,
185
+ })),
186
+ } as WithContext<HowTo>,
187
+ ];
188
+
189
+ export const content: HullSpeedLocaleContent = {
190
+ slug,
191
+ title,
192
+ description,
193
+ ui,
194
+ seo,
195
+ faq,
196
+ bibliography,
197
+ howTo,
198
+ schemas,
199
+ };
@@ -0,0 +1,199 @@
1
+ import { bibliography } from '../bibliography';
2
+ import type { HullSpeedLocaleContent, HullSpeedUI } from '../index';
3
+ import type { FAQPage, HowTo, SoftwareApplication, WithContext } from 'schema-dts';
4
+
5
+ const slug = 'sailboat-hull-speed-calculator';
6
+ const title = 'Sailboat Hull Speed Calculator';
7
+ const description =
8
+ 'Find theoretical hull speed from waterline length, compare an observed speed, and see when a displacement hull is climbing its own bow wave.';
9
+
10
+ const ui: HullSpeedUI = {
11
+ metric: 'Metric',
12
+ imperial: 'Imperial',
13
+ unitGroup: 'Units',
14
+ sceneLabel: 'Waterline and bow wave',
15
+ hullSpeedLabel: 'Hull speed',
16
+ knotsUnit: 'kn',
17
+ kmhUnit: 'km/h',
18
+ mphUnit: 'mph',
19
+ ratioLabel: 'S/L',
20
+ froudeLabel: 'Fr',
21
+ lwlLabelMetric: 'Waterline length',
22
+ lwlLabelImperial: 'Waterline length',
23
+ lwlUnitM: 'm',
24
+ lwlUnitFt: 'ft',
25
+ observedLabel: 'Log speed',
26
+ observedHint: 'Leave at 0 to draw the theoretical wave. Type a log reading to see if you are still sitting in the hole.',
27
+ stretchHint: 'Drag the hull to stretch the waterline',
28
+ hullKindLabel: 'Hull form',
29
+ displacement: 'Displacement',
30
+ semi: 'Semi displacement',
31
+ planing: 'Planing',
32
+ boatsLabel: 'Example waterlines',
33
+ dinghy: 'Dinghy',
34
+ daysailer: 'Daysailer',
35
+ cruiser: 'Cruiser',
36
+ bluewater: 'Bluewater',
37
+ workboat: 'Workboat',
38
+ bandBelow: 'Still making a short wave',
39
+ bandNear: 'Approaching the wave barrier',
40
+ bandAt: 'Riding the bow wave',
41
+ bandAbove: 'Trying to climb the wave',
42
+ bandPlane: 'On the plane, past hull speed',
43
+ planingNote:
44
+ 'A planing hull can leave this wave behind. Hull speed is a reference, not a wall.',
45
+ displacementNote:
46
+ 'A displacement hull pays steeply as it catches its own wake. Treat hull speed as a practical ceiling, not a GPS target.',
47
+ semiNote:
48
+ 'Semi displacement hulls can press a little past the classic ratio with enough power, at a sharp rise in resistance.',
49
+ waveLegend: 'Bow wave',
50
+ waterLegend: 'Waterline',
51
+ markLegend: 'Hull speed',
52
+ faqTitle: 'Hull speed questions',
53
+ bibliographyTitle: 'References',
54
+ };
55
+
56
+ const faq: HullSpeedLocaleContent['faq'] = [
57
+ {
58
+ question: 'What is hull speed on a sailboat?',
59
+ answer:
60
+ 'Hull speed is the speed at which a displacement hull is travelling with a bow wave about as long as its own waterline. In nautical units it is commonly estimated as 1.34 times the square root of waterline length in feet. It is a critical speed, not a hard physical stop.',
61
+ },
62
+ {
63
+ question: 'How do you calculate hull speed?',
64
+ answer:
65
+ 'Convert waterline length to feet, take the square root, and multiply by 1.34 to get knots. A 10 m waterline is about 32.8 ft, so hull speed is about 7.7 kn. The same point corresponds to a Froude number near 0.40.',
66
+ },
67
+ {
68
+ question: 'Does hull speed apply to planing boats?',
69
+ answer:
70
+ 'The formula still describes the wave the hull would make if it stayed in displacement mode. Planing and many semi displacement craft are designed to climb over that wave. Use the number as a reference, then look at the hull form note.',
71
+ },
72
+ {
73
+ question: 'Should I use waterline length or overall length?',
74
+ answer:
75
+ 'Use length on the waterline (LWL), the immersed length that actually makes the wave. Overall length, bowsprits and overhangs do not set the wavelength. Measure LWL in the water, not from a brochure LOA.',
76
+ },
77
+ ];
78
+
79
+ const howTo: HullSpeedLocaleContent['howTo'] = [
80
+ {
81
+ name: 'Stretch the waterline',
82
+ text: 'Drag the hull, move the waterline rail, or pick a dinghy through workboat. Hull speed is 1.34 times the square root of that length in feet.',
83
+ },
84
+ {
85
+ name: 'Choose hull form',
86
+ text: 'Displacement, semi displacement or planing changes the keel and whether the boat can climb out of its own wave.',
87
+ },
88
+ {
89
+ name: 'Read the hole',
90
+ text: 'At hull speed the bow wave and stern wave sit one waterline apart and the boat sits in the trough. That is the barrier.',
91
+ },
92
+ {
93
+ name: 'Compare a log speed',
94
+ text: 'Enter speed through the water. A shorter wave means you are still cheap to drive. A longer wave means you are climbing the hole.',
95
+ },
96
+ ];
97
+
98
+ const seo: HullSpeedLocaleContent['seo'] = [
99
+ {
100
+ type: 'title',
101
+ text: 'What hull speed is actually telling you',
102
+ level: 2,
103
+ },
104
+ {
105
+ type: 'paragraph',
106
+ html: 'A displacement hull pushes a wave from the bow and another from the stern. When those crests sit about one waterline apart, the boat is travelling with its own wake. Extra power then mostly heaps water up instead of buying speed. That condition is what sailors call hull speed.',
107
+ },
108
+ {
109
+ type: 'paragraph',
110
+ html: 'The calculator uses the common amateur ratio 1.34 knots per square root of waterline feet. Fine, long hulls can sit a little higher; barges sit lower. Treat the result as a teaching mark, then compare a real log speed against it.',
111
+ },
112
+ {
113
+ type: 'title',
114
+ text: 'Worked waterline examples',
115
+ level: 2,
116
+ },
117
+ {
118
+ type: 'table',
119
+ headers: ['Waterline', 'Hull speed', 'Typical boat'],
120
+ rows: [
121
+ ['4.2 m / 13.8 ft', '5.0 kn', 'Dinghy'],
122
+ ['6.5 m / 21.3 ft', '6.2 kn', 'Daysailer'],
123
+ ['10 m / 32.8 ft', '7.7 kn', 'Family cruiser'],
124
+ ['13.5 m / 44.3 ft', '8.9 kn', 'Bluewater yacht'],
125
+ ['18 m / 59.1 ft', '10.3 kn', 'Small workboat'],
126
+ ],
127
+ },
128
+ {
129
+ type: 'title',
130
+ text: 'How to read the bow wave',
131
+ level: 2,
132
+ },
133
+ {
134
+ type: 'list',
135
+ items: [
136
+ 'Below the mark the wave is short and the boat is still cheap to drive.',
137
+ 'Near the mark the bow wave steepens and fuel or sail power buys less speed.',
138
+ 'On the mark the wavelength matches LWL. A displacement hull is at the classic barrier.',
139
+ 'Above the mark a displacement hull is climbing its wake. A planing hull may already be up.',
140
+ ],
141
+ },
142
+ {
143
+ type: 'tip',
144
+ title: 'Measure LWL, not LOA',
145
+ html: 'Brochure length includes overhangs. The wave cares about the immersed waterline. If you only have LOA, the hull speed you compute will be optimistic.',
146
+ },
147
+ {
148
+ type: 'title',
149
+ text: 'Froude number in one sentence',
150
+ level: 2,
151
+ },
152
+ {
153
+ type: 'paragraph',
154
+ html: 'Hull speed is a convenient packaging of a Froude number near 0.40: speed divided by the square root of gravity times length. That is why longer waterlines are faster even when the hull shape stays the same. Stretching LWL is the clean way to raise a displacement limit; adding horsepower is not.',
155
+ },
156
+ ];
157
+
158
+ const schemas: HullSpeedLocaleContent['schemas'] = [
159
+ {
160
+ '@context': 'https://schema.org',
161
+ '@type': 'SoftwareApplication',
162
+ name: title,
163
+ description,
164
+ applicationCategory: 'UtilityApplication',
165
+ operatingSystem: 'Web',
166
+ offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' },
167
+ } as WithContext<SoftwareApplication>,
168
+ {
169
+ '@context': 'https://schema.org',
170
+ '@type': 'FAQPage',
171
+ mainEntity: faq.map((item) => ({
172
+ '@type': 'Question',
173
+ name: item.question,
174
+ acceptedAnswer: { '@type': 'Answer', text: item.answer },
175
+ })),
176
+ } as WithContext<FAQPage>,
177
+ {
178
+ '@context': 'https://schema.org',
179
+ '@type': 'HowTo',
180
+ name: `How to use ${title}`,
181
+ step: howTo.map((step) => ({
182
+ '@type': 'HowToStep',
183
+ name: step.name,
184
+ text: step.text,
185
+ })),
186
+ } as WithContext<HowTo>,
187
+ ];
188
+
189
+ export const content: HullSpeedLocaleContent = {
190
+ slug,
191
+ title,
192
+ description,
193
+ ui,
194
+ seo,
195
+ faq,
196
+ bibliography,
197
+ howTo,
198
+ schemas,
199
+ };