-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapi.html
More file actions
150 lines (135 loc) · 7.47 KB
/
api.html
File metadata and controls
150 lines (135 loc) · 7.47 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Lake Powell Forecast API</title>
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='0.9em' font-size='90'>💧</text></svg>">
<style>
:root { --bg: #0f172a; --surface: #1e293b; --border: #334155; --text: #e2e8f0; --dim: #94a3b8; --accent: #38bdf8; }
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', monospace; background: var(--bg); color: var(--text); padding: 2rem; line-height: 1.6; }
.container { max-width: 800px; margin: 0 auto; }
h1 { color: var(--accent); font-size: 1.3rem; margin-bottom: 0.5rem; }
h2 { color: var(--accent); font-size: 1rem; margin: 1.5rem 0 0.5rem; }
p, li { font-size: 0.875rem; color: var(--dim); }
code { background: var(--surface); padding: 0.15rem 0.4rem; border-radius: 3px; font-size: 0.85rem; color: var(--accent); }
pre { background: var(--surface); border: 1px solid var(--border); border-radius: 0.5rem; padding: 1rem; overflow-x: auto; margin: 0.75rem 0; font-size: 0.8rem; }
.form { background: var(--surface); border: 1px solid var(--border); border-radius: 0.75rem; padding: 1.25rem; margin: 1rem 0; }
.form label { display: block; font-size: 0.8rem; color: var(--dim); margin-bottom: 0.25rem; }
.form input, .form select { background: var(--bg); border: 1px solid var(--border); color: var(--text); padding: 0.5rem; border-radius: 0.375rem; width: 100%; margin-bottom: 0.75rem; font-size: 0.875rem; }
.form button { background: var(--accent); color: var(--bg); border: none; padding: 0.6rem 1.5rem; border-radius: 0.375rem; cursor: pointer; font-weight: 600; font-size: 0.875rem; }
.form button:hover { opacity: 0.9; }
#result { white-space: pre-wrap; color: var(--text); }
a { color: var(--accent); }
ul { padding-left: 1.5rem; margin: 0.5rem 0; }
.nav { display: flex; gap: 1.5rem; margin-bottom: 1.5rem; padding-bottom: 0.75rem; border-bottom: 1px solid var(--border); font-size: 0.8rem; }
.nav a { color: var(--dim); text-decoration: none; }
.nav a:hover { color: var(--accent); }
.nav a.active { color: var(--accent); font-weight: 600; }
</style>
</head>
<body>
<div class="container">
<nav class="nav">
<a href="./">Home</a>
<a href="api.html" class="active">API</a>
<a href="methodology.html">Methodology</a>
</nav>
<h1>Lake Powell Forecast API</h1>
<p>Run forecast scenarios programmatically. The engine runs client-side — results are computed in your browser using the same model as the <a href="index.html">main analyzer</a>.</p>
<h2>Interactive Query</h2>
<div class="form">
<label>Current Elevation (ft)</label>
<input type="number" id="f-elev" value="3529.4" step="0.1">
<label>Current Date</label>
<input type="date" id="f-date" value="2026-03-13">
<label>April 1 SWE (tenths mm, basin avg)</label>
<input type="number" id="f-swe" value="3364" step="50">
<label>Release Multiplier</label>
<input type="number" id="f-release" value="1.0" step="0.05" min="0.5" max="2.0">
<label>Forecast End Date</label>
<input type="date" id="f-end" value="2027-06-01">
<button onclick="runForecast()">Run Forecast</button>
</div>
<h2>Result</h2>
<pre id="result">Click "Run Forecast" to see results...</pre>
<h2>URL API</h2>
<p>Pass parameters via URL hash to pre-fill and auto-run:</p>
<pre>api.html#elev=3529.4&date=2026-03-13&swe=3364&release=1.0&end=2027-06-01</pre>
<h2>JavaScript Module API</h2>
<p>Import the forecast engine directly in your own code:</p>
<pre><script type="module">
import { forecast, findLowPoint, THRESHOLDS } from './forecast.js';
const results = forecast({
currentElevation: 3529.4,
currentDate: '2026-03-13',
sweApr1: 3364,
releaseMultiplier: 1.0,
forecastEndDate: '2027-06-01',
});
const low = findLowPoint(results);
console.log('Projected low:', low);
</script></pre>
<h2>Parameters</h2>
<ul>
<li><code>currentElevation</code> — Lake elevation in ft (NGVD 1929). Get latest from <a href="https://waterservices.usgs.gov/nwis/dv/?format=json&sites=09379900¶meterCd=62614&period=P7D" target="_blank">USGS API</a>.</li>
<li><code>currentDate</code> — YYYY-MM-DD format.</li>
<li><code>sweApr1</code> — Basin-average April 1 Snow Water Equivalent in tenths of mm. Get from <a href="https://www.ncei.noaa.gov/access/services/data/v1?dataset=daily-summaries&stations=USS0006J03S,USS0006J09S,USS0006L02S,USS0006L11S,USS0007M12S,USS0009G03S,USS0009J01S,USS0007J03S,USS0006K24S,USS0006K29S&startDate=2026-03-01&endDate=2026-03-13&dataTypes=WESD&format=json" target="_blank">NCEI API</a>.</li>
<li><code>releaseMultiplier</code> — Scale factor on baseline decline rates. 1.0 = current Mid-Elevation Tier (~7.48 MAF/yr).</li>
<li><code>forecastEndDate</code> — YYYY-MM-DD. Forecast projects monthly to this date.</li>
</ul>
<h2>Response</h2>
<p>Returns JSON with monthly projections, the low point, and threshold crossings.</p>
<h2>For Claude / LLM Integration</h2>
<p>The forecast engine is a pure JavaScript module with zero dependencies. To use in an AI context:</p>
<ol style="padding-left:1.5rem;margin:0.5rem 0;">
<li>Fetch current elevation from USGS: <code>GET https://waterservices.usgs.gov/nwis/dv/?format=json&sites=09379900¶meterCd=62614&period=P1D</code></li>
<li>Fetch current SWE from NCEI (10-station average)</li>
<li>Run <code>forecast()</code> with those inputs</li>
<li>Interpret results against <code>THRESHOLDS</code></li>
</ol>
</div>
<script type="module">
import { forecast, findLowPoint, getCrossedThresholds, THRESHOLDS } from './forecast.js';
window.runForecast = function() {
const params = {
currentElevation: parseFloat(document.getElementById('f-elev').value),
currentDate: document.getElementById('f-date').value,
sweApr1: parseInt(document.getElementById('f-swe').value),
releaseMultiplier: parseFloat(document.getElementById('f-release').value),
forecastEndDate: document.getElementById('f-end').value,
};
const results = forecast(params);
const low = findLowPoint(results);
const crossed = getCrossedThresholds(low.elevation);
const output = {
params,
monthlyProjections: results,
lowPoint: low,
thresholdsCrossed: crossed.map(t => ({
elevation: t.elevation,
label: t.label,
severity: t.severity,
consequence: t.consequence,
})),
summary: `From ${params.currentElevation} ft on ${params.currentDate}, ` +
`with SWE=${params.sweApr1} and release=${params.releaseMultiplier}x, ` +
`projected low is ${low.elevation} ft on ${low.date}. ` +
`${crossed.length} thresholds crossed: ${crossed.map(t => t.label).join(', ') || 'none'}.`,
};
document.getElementById('result').textContent = JSON.stringify(output, null, 2);
};
// Auto-run from URL hash
if (window.location.hash) {
const params = new URLSearchParams(window.location.hash.slice(1));
if (params.get('elev')) document.getElementById('f-elev').value = params.get('elev');
if (params.get('date')) document.getElementById('f-date').value = params.get('date');
if (params.get('swe')) document.getElementById('f-swe').value = params.get('swe');
if (params.get('release')) document.getElementById('f-release').value = params.get('release');
if (params.get('end')) document.getElementById('f-end').value = params.get('end');
window.runForecast();
}
</script>
</body>
</html>