From 629778078b1663cd4841f7c3876c5e3eb179b244 Mon Sep 17 00:00:00 2001 From: handfly Date: Sun, 3 May 2026 13:12:40 -0400 Subject: [PATCH] Update documentation --- .directory | 2 +- README-web.md | 84 ++++++++++++++++++++++++++++ SOL_Cluster_Developer_Overview.docx | Bin 0 -> 18663 bytes 3 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 README-web.md create mode 100644 SOL_Cluster_Developer_Overview.docx diff --git a/.directory b/.directory index 9dd830b..5a02205 100644 --- a/.directory +++ b/.directory @@ -1,2 +1,2 @@ [Desktop Entry] -Icon=orange-folder-git +Icon=orange-folder-github diff --git a/README-web.md b/README-web.md new file mode 100644 index 0000000..c5f8388 --- /dev/null +++ b/README-web.md @@ -0,0 +1,84 @@ +# Pilot's Toolkit — Web + +A collection of aviation utilities for flight crews, built with React and Vite. Single-page application designed for browser-based cockpit use and future Docker deployment. + +**Not for operational use — verify all calculations independently.** + +--- + +## Modules + +- **Fuel Order Calculator** — Fuel quantity in US/imperial gallons and liters with ASTM D1250 Table 6B density correction and ambient temperature adjustment. +- **Pavement Strength / ESWL** — ACN/ACR calculation with PCN/PCR comparison, rigid/flexible pavement types, four subgrade categories. Reverse-solves maximum allowable weight when pavement is exceeded. +- **Crosswind Calculator** — Headwind, tailwind, and crosswind components from wind direction/speed and runway heading. Auto-formats five-digit wind input on blur. +- **Fuel Buckets** — Stage length vs. fuel burn schedule with slider interpolation. Supports operator-specific CSV and JSON profile import. +- **HF Frequencies** — Active ARINC HF assignments for Atlantic and Pacific with staleness indicator. +- **Passdown** — Crew changeover form with local storage, autocomplete, history, batch .ptz export, email compose via `mailto:`, and stale-record detection on send. +- **Flight Level ↔ Meters** — ICAO meters-to-feet conversion table and China RVSM FLAS with directional filtering. +- **Crew Rest** — Augmented operations rest calculator for 3–4 pilots. Equal-division sequential rest rotation with lock toggle to prevent accidental edits mid-flight. + +## Project Structure + +``` +pilot-toolkit-web/ + package.json ← Dependencies and scripts + vite.config.js ← Vite + React plugin + index.html ← Entry HTML + src/ + main.jsx ← React root mount + toolkit.jsx ← All eight modules (~3,600 lines) + data/ + reference.json ← Flight levels, subgrade labels + aircraft/ + G450.json ← Per-airframe data + G500.json + G650.json + G700.json +``` + +## Data Architecture + +All aircraft and reference data lives in JSON files under `src/data/`. Vite imports these statically at build time — they are tree-shaken into the production bundle. + +- **`reference.json`** — Airframe-agnostic: meters-to-feet table (107 entries), China FLAS (50 entries), RVSM direction sets, pavement subgrade labels. +- **`aircraft/*.json`** — One file per airframe: weight limits, ESWL config (formula or thresholds), PCN/PCR linear regression coefficients, fuel bucket schedules. Each file is imported individually in `toolkit.jsx` and wrapped in a `loadAircraft()` call with error handling. + +Each aircraft file loads independently. A parse failure is caught and logged to `dataLoadErrors` — it does not crash the app or affect other airframes. + +**Adding a new airframe** requires adding an import line and a `loadAircraft()` call in `toolkit.jsx` (Vite does not support dynamic JSON imports at build time). + +## Storage + +- **`localStorage`** — Dark mode, default aircraft, volume unit, passdown retention period, fuel profiles (per aircraft). +- **IndexedDB** — Passdown records and autocomplete lookups. Accessed via async helper functions. + +All data is local to the browser. No backend, no accounts, no external APIs (except ARINC HF frequency pages). + +## Exchange Formats + +- **`.ptz`** — Gzipped JSON array of passdown objects. Exported via browser `CompressionStream`, imported via `DecompressionStream`. Open format. +- **Fuel profile JSON** — Validated on import by `format: "pilot-toolkit-fuel-profile"` field. +- **Fuel profile CSV** — Two columns (stage length, fuel burn), optional header row. + +## Dependencies + +Production: `react`, `react-dom` (2 packages). No other runtime dependencies. + +Dev: `vite`, `@vitejs/plugin-react`. + +Compression uses the browser-native `CompressionStream` / `DecompressionStream` APIs — no external gzip library. + +## Build + +``` +npm install +npm run dev # Development server +npm run build # Production build → dist/ +npm run preview # Preview production build +``` + +Production build produces a single HTML file and a single JS bundle (~250 KB, ~72 KB gzipped). + +## Deployment + +Currently runs as a local dev server. Docker deployment (Phase II) is planned — the production build output (`dist/`) can be served by any static file server (nginx, Caddy, etc.) with no backend required. diff --git a/SOL_Cluster_Developer_Overview.docx b/SOL_Cluster_Developer_Overview.docx new file mode 100644 index 0000000000000000000000000000000000000000..c55d4259f405b528e599aaf1a32dd8d4bb53b14b GIT binary patch literal 18663 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 WR>1ynM3?|fK*;Nvh`^68|Nj6C{|kKp literal 0 HcmV?d00001