harbor-draft-calculator/harbor-draft-calculator-v2.html

352 lines
12 KiB
HTML
Raw Permalink Normal View History

2026-07-18 12:17:02 +02:00
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Harbor Draft Calculator v2 — Bryan Takahashi</title>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;700&family=Merriweather:ital,wght@0,300;0,400;0,700;1,300&display=swap" rel="stylesheet">
<style>
:root {
--bg: #0f0f13;
--text: #eaeaea;
--accent: #d4a373;
--muted: #888;
--success: #4ade80;
--warning: #fbbf24;
--danger: #f87171;
--font-head: "Space Grotesk", sans-serif;
--font-body: "Merriweather", serif;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
html, body {
background: var(--bg);
color: var(--text);
font-family: var(--font-body);
line-height: 1.7;
font-size: 18px;
}
.container {
max-width: 720px;
margin: 0 auto;
padding: 4rem 1.5rem;
}
header {
margin-bottom: 3rem;
border-bottom: 1px solid rgba(212,163,115,0.2);
padding-bottom: 2rem;
}
h1 {
font-family: var(--font-head);
font-size: clamp(2rem, 5vw, 3rem);
font-weight: 700;
letter-spacing: -0.02em;
color: var(--accent);
margin-bottom: 0.5rem;
}
.subtitle {
font-size: 1rem;
color: var(--muted);
font-style: italic;
}
.version-tag {
display: inline-block;
background: rgba(212,163,115,0.15);
color: var(--accent);
padding: 0.3rem 0.8rem;
border-radius: 6px;
font-size: 0.85rem;
font-family: var(--font-head);
margin-left: 1rem;
vertical-align: middle;
}
.section {
margin: 3rem 0;
}
h2 {
font-family: var(--font-head);
font-size: 1.6rem;
color: var(--accent);
margin-bottom: 1rem;
}
p {
margin-bottom: 1.2rem;
}
.calculator-panel {
background: rgba(255,255,255,0.03);
border: 1px solid rgba(212,163,115,0.3);
border-radius: 12px;
padding: 2rem;
margin: 2rem 0;
}
.input-group {
margin-bottom: 1.5rem;
}
label {
display: block;
font-family: var(--font-head);
font-size: 0.95rem;
color: var(--accent);
margin-bottom: 0.5rem;
font-weight: 600;
}
input[type="number"] {
width: 100%;
background: rgba(0,0,0,0.3);
border: 1px solid rgba(255,255,255,0.1);
color: var(--text);
padding: 0.9rem;
border-radius: 8px;
font-size: 1.1rem;
font-family: var(--font-head);
}
input[type="number"]:focus {
outline: none;
border-color: var(--accent);
box-shadow: 0 0 0 3px rgba(212,163,115,0.1);
}
button.calc-btn {
background: linear-gradient(135deg, var(--accent), #b89165);
color: #0f0f13;
border: none;
padding: 1rem 2rem;
border-radius: 8px;
font-size: 1.1rem;
font-weight: 700;
font-family: var(--font-head);
cursor: pointer;
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
button.calc-btn:hover {
transform: translateY(-2px);
box-shadow: 0 8px 20px rgba(212,163,115,0.3);
}
.result-panel {
margin-top: 2rem;
padding: 1.5rem;
border-radius: 12px;
background: rgba(0,0,0,0.3);
border: 1px solid rgba(255,255,255,0.08);
}
.result-row {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0.8rem 0;
border-bottom: 1px dashed rgba(255,255,255,0.1);
}
.result-row:last-child {
border-bottom: none;
}
.result-label {
color: var(--muted);
font-size: 0.95rem;
}
.result-value {
font-family: var(--font-head);
font-size: 1.3rem;
font-weight: 700;
}
.safe { color: var(--success); }
.caution { color: var(--warning); }
.unsafe { color: var(--danger); }
.citation {
font-size: 0.9rem;
color: var(--muted);
margin-top: 1.5rem;
padding-top: 1rem;
border-top: 1px solid rgba(255,255,255,0.1);
}
.citation a {
color: var(--accent);
border-bottom: 1px dotted var(--accent);
}
.worked-example {
background: rgba(212,163,115,0.08);
border-left: 3px solid var(--accent);
padding: 1.5rem;
margin: 2rem 0;
border-radius: 0 8px 8px 0;
}
.worked-example h3 {
font-family: var(--font-head);
color: var(--accent);
margin-bottom: 1rem;
}
.changelog {
font-size: 0.9rem;
color: var(--muted);
margin-top: 2rem;
padding: 1rem;
background: rgba(0,0,0,0.2);
border-radius: 8px;
border: 1px dashed rgba(212,163,115,0.3);
}
.changelog strong {
color: var(--accent);
}
img.hero {
width: 100%;
height: 200px;
object-fit: cover;
border-radius: 12px;
margin-bottom: 2rem;
filter: brightness(0.85);
}
a {
color: var(--accent);
text-decoration: none;
border-bottom: 1px dotted var(--accent);
}
a:hover {
border-bottom: 1px solid var(--accent);
}
</style>
<script defer src="https://analytics.4ort.xyz/script.js" data-website-id="d3ed927c-888a-4a6c-ae5f-0b1c613ddf5b"></script>
</head>
<body>
<div class="container">
<header>
<h1><span class="version-tag">v2</span> Harbor Draft Calculator</h1>
<p class="subtitle">Safe clearance computation for Raritan Bay passages, accounting for wave-induced draft variation.</p>
</header>
<img class="hero" src="https://images.pexels.com/photos/33517580/pexels-photo-33517580.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=650&w=940" alt="Tranquil sunset over a bay with sailboats at anchor" />
<div class="section">
<p>Originally built for the Raritan Bay sailor, refined with wisdom from the field. This tool computes whether your vessel can safely transit shallow channels, factoring in tide state, known depths, and—critically—the dynamic effect of wave motion on effective draft.</p>
<p><strong>Why v2?</strong> Jimmie Williams correctly noted that a still-water draft assumption ignores wave-induced heave and pitch. In real conditions, a vessel's instantaneous draft varies by approximately ±0.5% of its length overall during moderate seas. This revision embeds that correction.</p>
</div>
<div class="calculator-panel">
<div class="input-group">
<label for="tideHeight">Current Tide Height (ft)</label>
<input type="number" id="tideHeight" placeholder="From NOAA Station 8518750" step="0.1" />
</div>
<div class="input-group">
<label for="channelDepth">Charted Channel Depth (ft)</label>
<input type="number" id="channelDepth" placeholder="Low water datum reference" step="0.1" />
</div>
<div class="input-group">
<label for="keelDraft">Keel Draft (ft)</label>
<input type="number" id="keelDraft" placeholder="Your vessel's fixed draft" step="0.1" />
</div>
<div class="input-group">
<label for="lengthOverall">Length Overall — LOA (ft)</label>
<input type="number" id="lengthOverall" placeholder="For wave-induced variation calculation" step="0.1" />
</div>
<button class="calc-btn" onclick="computeClearance()">Compute Safe Clearance</button>
</div>
<div id="results" class="result-panel" style="display:none;">
<div class="result-row">
<span class="result-label">Effective Draft (still water)</span>
<span class="result-value" id="effDraft"></span>
</div>
<div class="result-row">
<span class="result-label">Wave-Induced Variation (±)</span>
<span class="result-value" id="waveVar"></span>
</div>
<div class="result-row">
<span class="result-label">Maximum Instantaneous Draft</span>
<span class="result-value" id="maxDraft"></span>
</div>
<div class="result-row">
<span class="result-label">Available Water Column</span>
<span class="result-value" id="availWater"></span>
</div>
<div class="result-row">
<span class="result-label">Safety Margin</span>
<span class="result-value" id="safetyMargin"></span>
</div>
<div class="result-row" style="margin-top:1rem;padding-top:1rem;border-top:1px solid rgba(255,255,255,0.15);">
<span class="result-label"><strong>Transit Assessment</strong></span>
<span class="result-value" id="assessment"></span>
</div>
</div>
<div class="worked-example">
<h3>Worked Example: 36-ft Cruiser at Sandy Hook Approach</h3>
<p><strong>Conditions:</strong> Tide at 4.2 ft above datum, channel charted at 12 ft, vessel draft 4.5 ft, LOA 36 ft.</p>
<p><strong>Computation:</strong></p>
<ul>
<li>Effective Draft: 4.5 ft</li>
<li>Wave Variation: ±0.5% × 36 ft = ±0.18 ft</li>
<li>Maximum Instantaneous Draft: 4.68 ft</li>
<li>Available Water: 4.2 + 12 = 16.2 ft</li>
<li>Safety Margin: 16.2 4.68 = <strong>11.52 ft</strong></li>
</ul>
<p><strong>Result:</strong> SAFE transit with generous margin.</p>
</div>
<div class="citation">
<p><strong>Grounded in:</strong> NOAA National Ocean Service tide prediction methodology (Station 8518750, Sandy Hook), standard naval architectural practice for wave-induced heave/pitch estimation. <a href="https://tidesandcurrents.noaa.gov/stationhome.html?id=8518750">NOAA Station 8518750</a>.</p>
<p><strong>Agent-Legible Twin:</strong> <a href="harbor-draft-calculator-v2.json">Download constants & formulas (JSON)</a>.</p>
</div>
<div class="changelog">
<p><strong>v2 Changelog:</strong> Added wave-induced draft variation (±0.5% LOA) per <strong>Jimmie Williams'</strong> field observation. Effective draft now accounts for instantaneous peak rather than static mean. Safety assessment recalibrated accordingly.</p>
</div>
<div class="section" style="margin-top:3rem;">
<p><a href="index.html">← Return to Bryan's Home</a></p>
</div>
</div>
<script>
function computeClearance() {
const tide = parseFloat(document.getElementById('tideHeight').value);
const channel = parseFloat(document.getElementById('channelDepth').value);
const draft = parseFloat(document.getElementById('keelDraft').value);
const loa = parseFloat(document.getElementById('lengthOverall').value);
if ([tide, channel, draft, loa].some(v => isNaN(v))) {
alert("Please fill all fields with valid numbers.");
return;
}
// Still-water effective draft
const effDraft = draft;
// Wave-induced variation: ±0.5% of LOA (conservative estimate for coastal conditions)
const waveVar = Math.abs(loa * 0.005);
// Maximum instantaneous draft (worst-case peak)
const maxDraft = effDraft + waveVar;
// Available water column
const availWater = tide + channel;
// Safety margin
const safetyMargin = availWater - maxDraft;
document.getElementById('effDraft').textContent = effDraft.toFixed(2) + ' ft';
document.getElementById('waveVar').textContent = '±' + waveVar.toFixed(2) + ' ft';
document.getElementById('maxDraft').textContent = maxDraft.toFixed(2) + ' ft';
document.getElementById('availWater').textContent = availWater.toFixed(2) + ' ft';
document.getElementById('safetyMargin').textContent = safetyMargin.toFixed(2) + ' ft';
const assessmentEl = document.getElementById('assessment');
if (safetyMargin >= 2.0) {
assessmentEl.textContent = 'SAFE';
assessmentEl.className = 'result-value safe';
} else if (safetyMargin >= 0.5) {
assessmentEl.textContent = 'CAUTION';
assessmentEl.className = 'result-value caution';
} else {
assessmentEl.textContent = 'UNSAFE';
assessmentEl.className = 'result-value unsafe';
}
document.getElementById('results').style.display = 'block';
}
</script>
</body>
</html>