Skip to content

Commit 14e1271

Browse files
committed
update to ScyWeb
1 parent a6cc5e8 commit 14e1271

13 files changed

Lines changed: 96899 additions & 0 deletions

calctale/chemistry.html

Lines changed: 506 additions & 0 deletions
Large diffs are not rendered by default.

calctale/chemistry_test_data/reactions/CHEM_AUDIT_1777181966863.html

Lines changed: 43100 additions & 0 deletions
Large diffs are not rendered by default.

calctale/chemistry_test_data/reactions/chemistry_export_1777181975065.csv

Lines changed: 1001 additions & 0 deletions
Large diffs are not rendered by default.

calctale/chemistry_test_data/reactions/reaction_library_v1.csv

Lines changed: 1001 additions & 0 deletions
Large diffs are not rendered by default.
326 KB
Loading

calctale/chemistry_test_data/reactions/reaction_library_v2.csv

Lines changed: 1001 additions & 0 deletions
Large diffs are not rendered by default.
326 KB
Loading

calctale/index.html

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
flex-direction: column;
4141
box-shadow: 10px 0 30px rgba(0,0,0,0.5);
4242
z-index: 100;
43+
overflow: auto;
4344
}
4445

4546
.sidebar-header {
@@ -174,11 +175,21 @@ <h3>Engineering</h3>
174175
<div id="eng-nav"></div>
175176
</div>
176177

178+
<div class="nav-section">
179+
<h3>Chemistry</h3>
180+
<div id="chem-nav"></div>
181+
</div>
182+
177183
<div class="nav-section">
178184
<h3>Statistics</h3>
179185
<div id="stats-nav"></div>
180186
</div>
181187

188+
<div class="nav-section">
189+
<h3>Meteorologist</h3>
190+
<div id="meteo-nav"></div>
191+
</div>
192+
182193
<!--<div class="nav-section" style="margin-top:auto">
183194
<h3>System Tools</h3>
184195
<a href="#" class="nav-item" onclick="loadPage('')"></a>
@@ -209,8 +220,14 @@ <h3>System Tools</h3>
209220
engineer: [
210221
{ label: "Integrative Analysis", path: "engineer.html" }
211222
],
223+
chemistry: [
224+
{ label: "Integrative Analysis", path: "chemistry.html" }
225+
],
212226
statistics: [
213227
{ label: "Integrative Analysis", path: "statistics.html" }
228+
],
229+
meteorologist: [
230+
{ label: "Integrative Analysis", path: "meteorologist.html" }
214231
]
215232
};
216233

@@ -219,7 +236,9 @@ <h3>System Tools</h3>
219236
const basics = document.getElementById('basics-nav');
220237
const physNav = document.getElementById('physics-nav');
221238
const engNav = document.getElementById('eng-nav');
239+
const chemNav = document.getElementById('chem-nav');
222240
const statsNav = document.getElementById('stats-nav');
241+
const meteoNav = document.getElementById('meteo-nav');
223242
const mathNav = document.getElementById('math-nav');
224243

225244
// Render Basics Links
@@ -240,12 +259,24 @@ <h3>System Tools</h3>
240259
engNav.appendChild(btn);
241260
});
242261

262+
// Render Chemistry Links
263+
appRegistry.chemistry.forEach(app => {
264+
const btn = createNavItem(app);
265+
chemNav.appendChild(btn);
266+
});
267+
243268
// Render Statistics Links
244269
appRegistry.statistics.forEach(app => {
245270
const btn = createNavItem(app);
246271
statsNav.appendChild(btn);
247272
});
248273

274+
// Render Meteorologist Links
275+
appRegistry.meteorologist.forEach(app => {
276+
const btn = createNavItem(app);
277+
meteoNav.appendChild(btn);
278+
});
279+
249280
// Load Default Page
250281
if (appRegistry.basics.length > 0) {
251282
loadPage(appRegistry.basics[0].path);

calctale/meteorologist.html

Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>CalcTale | Meteorologist</title>
6+
<style>
7+
:root { --neon: #00f5ff; --dark: #050a10; --slate: #0d1b2a; --gold: #f2af29; --border: #1b263b; --alert: #ff007a; }
8+
body { font-family: 'Courier New', monospace; background: var(--dark); color: #c5c6c7; margin: 0; padding: 20px; display: flex; flex-direction: column; height: 95vh; overflow: hidden; }
9+
10+
#fs-auth-overlay { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background: rgba(5, 10, 16, 0.98); z-index: 9999; display: flex; flex-direction: column; align-items: center; justify-content: center; cursor: pointer; border: 4px solid var(--gold); }
11+
#fs-auth-overlay h1 { color: var(--gold); text-transform: uppercase; letter-spacing: 2px; }
12+
13+
.main-layout { display: grid; grid-template-columns: 380px 1fr; gap: 20px; flex-grow: 1; overflow: hidden; }
14+
.panel { background: var(--slate); border: 1px solid var(--border); padding: 20px; display: flex; flex-direction: column; gap: 10px; overflow-y: auto; }
15+
h2 { color: var(--neon); font-size: 14px; text-transform: uppercase; border-bottom: 1px solid var(--border); padding-bottom: 5px; margin: 0; }
16+
label { font-size: 10px; color: #45a29e; text-transform: uppercase; }
17+
input { width: 100%; background: #000; color: #fff; border: 1px solid #333; padding: 10px; box-sizing: border-box; font-family: monospace; }
18+
.btn { background: var(--neon); color: var(--dark); border: none; padding: 12px; font-weight: bold; cursor: pointer; text-transform: uppercase; }
19+
20+
#canvas-container { background: #000; border: 1px solid var(--neon); overflow: auto; position: relative; flex-grow: 1; }
21+
canvas { image-rendering: pixelated; display: block; position: absolute; top: 0; left: 0; }
22+
#weather-canvas { pointer-events: none; opacity: 0.6; }
23+
#pressure-canvas { pointer-events: none; visibility: hidden; }
24+
#debug-layer { pointer-events: none; z-index: 2000; }
25+
26+
#data-card {
27+
position: absolute; background: rgba(13, 27, 42, 0.95); border: 1px solid var(--neon);
28+
padding: 15px; color: var(--neon); font-size: 12px; pointer-events: none;
29+
display: none; z-index: 1000; box-shadow: 0 0 15px rgba(0, 245, 255, 0.3);
30+
min-width: 240px;
31+
}
32+
#data-card b { color: var(--gold); text-transform: uppercase; font-size: 14px; }
33+
#log { height: 150px; background: #000; color: #00f5ff; font-size: 11px; padding: 10px; border: 1px solid #111; overflow-y: auto; white-space: pre-wrap; margin-top: 10px; }
34+
</style>
35+
</head>
36+
<body>
37+
38+
<div id="fs-auth-overlay" onclick="mountSovereignSystem()">
39+
<h1>System Initialization</h1>
40+
<p>Click to Mount Directory & Load MZMO Stack</p>
41+
</div>
42+
43+
<div class="main-layout">
44+
<div class="panel">
45+
<h2>1. Map Architecture</h2>
46+
<label>Create Map Database (City CSV)</label>
47+
<input type="file" id="city-csv" onchange="createMapDatabase(event)">
48+
<label>Mount Map (.PNG)</label>
49+
<input type="file" onchange="mountLayer(event, 'map')">
50+
<button class="btn" style="background: var(--gold)" onclick="exportLayer('map')">Export Map DB</button>
51+
52+
<h2>2. Data Architecture</h2>
53+
<label>Ingest Weather Vectors (CSV)</label>
54+
<input type="file" onchange="ingestWeather(event)">
55+
<!--<label>Mount Weather (.PNG)</label>
56+
<input type="file" onchange="mountLayer(event, 'weather')">
57+
<button class="btn" style="background: var(--gold)" onclick="exportLayer('weather')">Export Weather DB</button>-->
58+
59+
<hr style="border-color: #1b263b">
60+
<h2>3. Cross Reference</h2>
61+
<input type="text" id="coords" placeholder="" value="29.680694,-82.349175">
62+
<button class="btn" onclick="executePeek()">Geolocate</button>
63+
<div id="log">SYSTEM READY...</div>
64+
</div>
65+
66+
<div id="canvas-container">
67+
<div id="data-card"></div>
68+
<canvas id="map-canvas" width="4000" height="4000"></canvas>
69+
<canvas id="weather-canvas" width="4000" height="4000"></canvas>
70+
<canvas id="pressure-canvas" width="4000" height="4000"></canvas>
71+
<canvas id="debug-layer" width="4000" height="4000"></canvas>
72+
</div>
73+
</div>
74+
75+
<script>
76+
const DIM = 4000;
77+
const mapCtx = document.getElementById('map-canvas').getContext('2d', { willReadFrequently: true });
78+
const wetCtx = document.getElementById('weather-canvas').getContext('2d', { willReadFrequently: true });
79+
const prsCtx = document.getElementById('pressure-canvas').getContext('2d', { willReadFrequently: true });
80+
const dbgCtx = document.getElementById('debug-layer').getContext('2d');
81+
const logArea = document.getElementById('log');
82+
const card = document.getElementById('data-card');
83+
84+
let folderHandle = null;
85+
let cityRegistry = ["Gainesville City"];
86+
87+
function log(msg) {
88+
logArea.innerHTML += `> ${msg}\n`;
89+
logArea.scrollTop = logArea.scrollHeight;
90+
}
91+
92+
async function mountSovereignSystem() {
93+
try {
94+
folderHandle = await window.showDirectoryPicker({ mode: 'readwrite' });
95+
document.getElementById('fs-auth-overlay').style.display = 'none';
96+
log("Directory Mounted.");
97+
await autoLoadMZMOs();
98+
} catch (err) { log("FS Access Denied: " + err); }
99+
}
100+
101+
async function autoLoadMZMOs() {
102+
for await (const entry of folderHandle.values()) {
103+
if (entry.name === 'MZMO_MAP.png') await loadToCanvas(entry, mapCtx, "IDENTITY");
104+
if (entry.name === 'MZMO_WEATHER.png') await loadToCanvas(entry, wetCtx, "THERMAL");
105+
if (entry.name === 'MZMO_PRESSURE.png') await loadToCanvas(entry, prsCtx, "AERO");
106+
}
107+
}
108+
109+
async function loadToCanvas(entry, ctx, label) {
110+
const file = await entry.getFile();
111+
const img = await createImageBitmap(file);
112+
ctx.drawImage(img, 0, 0);
113+
log(`${label} layer auto-loaded.`);
114+
}
115+
116+
function geoToPixel(lat, lon) {
117+
const x = Math.floor(((parseFloat(lon) + 180) / 360) * (DIM - 1));
118+
const y = Math.floor(((90 - parseFloat(lat)) / 180) * (DIM - 1));
119+
return { x, y };
120+
}
121+
122+
function getCityChecksum(name) {
123+
let sum = 0;
124+
const clean = name.toLowerCase().replace(/[^a-z]/g, '');
125+
for (let i = 0; i < clean.length; i++) sum += (clean.charCodeAt(i) - 96);
126+
return sum % 256;
127+
}
128+
129+
async function createMapDatabase(e) {
130+
const text = await e.target.files[0].text();
131+
const lines = text.split('\n').slice(1);
132+
const imgData = mapCtx.createImageData(DIM, DIM);
133+
cityRegistry = [];
134+
135+
lines.forEach(line => {
136+
const p = line.split(',');
137+
if (p.length < 4) return;
138+
const cityName = p[1].trim();
139+
const { x, y } = geoToPixel(p[2], p[3]);
140+
const i = (y * DIM + x) * 4;
141+
142+
imgData.data[i] = cityName.length;
143+
imgData.data[i+1] = getCityChecksum(cityName);
144+
imgData.data[i+2] = cityName.charCodeAt(0);
145+
imgData.data[i+3] = 255;
146+
cityRegistry.push(cityName);
147+
});
148+
mapCtx.putImageData(imgData, 0, 0);
149+
log("Map Database Baked into RAM and Layer.");
150+
if(folderHandle) await autoExport('map', 'MZMO_MAP.png');
151+
}
152+
153+
async function ingestWeather(e) {
154+
const text = await e.target.files[0].text();
155+
const lines = text.split('\n').slice(1);
156+
const thermalData = wetCtx.createImageData(DIM, DIM);
157+
const aeroData = prsCtx.createImageData(DIM, DIM);
158+
159+
lines.forEach(line => {
160+
const p = line.split(',');
161+
if (p.length < 6) return;
162+
const { x, y } = geoToPixel(p[1], p[2]);
163+
const i = (y * DIM + x) * 4;
164+
165+
// THERMAL (16-bit Temp R+G, 8-bit Dewpoint B)
166+
const temp = Math.floor((parseFloat(p[3]) + 100) * 100);
167+
thermalData.data[i] = (temp >> 8) & 0xFF;
168+
thermalData.data[i+1] = temp & 0xFF;
169+
thermalData.data[i+2] = p[4] ? Math.floor(parseFloat(p[4]) + 50) : 0;
170+
thermalData.data[i+3] = 255;
171+
172+
// AERO (16-bit Pressure R+G, 8-bit Humidity B)
173+
const press = Math.floor((parseFloat(p[5]) || 1013.25) * 10);
174+
aeroData.data[i] = (press >> 8) & 0xFF;
175+
aeroData.data[i+1] = press & 0xFF;
176+
aeroData.data[i+2] = p[6] ? Math.floor(parseFloat(p[6])) : 0;
177+
aeroData.data[i+3] = 255;
178+
});
179+
180+
wetCtx.putImageData(thermalData, 0, 0);
181+
prsCtx.putImageData(aeroData, 0, 0);
182+
log("Meteo Layers Baked.");
183+
if(folderHandle) {
184+
await autoExport('weather', 'MZMO_WEATHER.png');
185+
await autoExport('pressure', 'MZMO_PRESSURE.png');
186+
}
187+
}
188+
189+
async function autoExport(cid, filename) {
190+
const canvas = document.getElementById(cid + '-canvas');
191+
const blob = await new Promise(res => canvas.toBlob(res));
192+
const fh = await folderHandle.getFileHandle(filename, { create: true });
193+
const ws = await fh.createWritable();
194+
await ws.write(blob);
195+
await ws.close();
196+
log(`Auto-Saved: ${filename}`);
197+
}
198+
199+
function executePeek() {
200+
const input = document.getElementById('coords').value.split(',');
201+
if(input.length < 2) return log("Error: Need Lat, Lon.");
202+
const lat = input[0].trim(), lon = input[1].trim();
203+
const { x, y } = geoToPixel(lat, lon);
204+
205+
dbgCtx.clearRect(0,0,DIM,DIM);
206+
dbgCtx.strokeStyle = "#ff007a";
207+
dbgCtx.strokeRect(x - 5, y - 5, 10, 10);
208+
209+
const m = mapCtx.getImageData(x, y, 1, 1).data;
210+
const w = wetCtx.getImageData(x, y, 1, 1).data;
211+
const a = prsCtx.getImageData(x, y, 1, 1).data;
212+
213+
let locName = "NO IDENTITY DATA";
214+
if(m[3] > 0) {
215+
if (cityRegistry.length === 0) {
216+
locName = `ENCODED ID: [Len:${m[0]}, Sum:${m[1]}, Hint:${String.fromCharCode(m[2])}]`;
217+
} else {
218+
const match = cityRegistry.find(n => n.length === m[0] && getCityChecksum(n) === m[1] && n.charCodeAt(0) === m[2]);
219+
locName = match || "ID MISMATCH";
220+
}
221+
}
222+
223+
const temp = (w[3] > 0) ? (((w[0] << 8) | w[1]) / 100 - 100).toFixed(2) : "N/A";
224+
const press = (a[3] > 0) ? (((a[0] << 8) | a[1]) / 10).toFixed(1) : "N/A";
225+
const hum = (a[3] > 0) ? a[2] : "N/A";
226+
227+
card.style.display = 'block';
228+
card.style.left = (x + 20) + 'px'; card.style.top = (y - 20) + 'px';
229+
card.innerHTML = `
230+
<b>${locName}</b><br>
231+
COORDS: ${lat}, ${lon}<br>
232+
<hr style="border-color:var(--border)">
233+
TEMP: ${temp}°C<br>
234+
PRES: ${press} hPa<br>
235+
HUMI: ${hum}%
236+
`;
237+
log(`FORENSIC PEEK AT [${x},${y}]`);
238+
239+
document.getElementById('canvas-container').scrollTo({left: x - 400, top: y - 400, behavior: 'smooth'});
240+
}
241+
242+
function mountLayer(e, type) {
243+
const img = new Image();
244+
const ctx = type === 'map' ? mapCtx : wetCtx;
245+
img.onload = () => { ctx.drawImage(img, 0, 0); log(`${type.toUpperCase()} mounted.`); };
246+
img.src = URL.createObjectURL(e.target.files[0]);
247+
}
248+
249+
function exportLayer(type) {
250+
const canvas = document.getElementById(type + '-canvas');
251+
const link = document.createElement('a');
252+
link.download = `MZMO_${type.toUpperCase()}.png`;
253+
link.href = canvas.toDataURL("image/png");
254+
link.click();
255+
}
256+
</script>
257+
</body>
258+
</html>
982 KB
Loading

0 commit comments

Comments
 (0)