334 lines
13 KiB
Markdown
334 lines
13 KiB
Markdown
# Pilot's Toolkit — Documentation
|
||
|
||
*RC1 — February 28, 2026*
|
||
|
||
---
|
||
|
||
## Overview
|
||
|
||
Pilot's Toolkit is a collection of aviation utilities for flight crews. It runs as a web app (React/Vite) and an Android app (Kotlin/Jetpack Compose). Both platforms share the same data files and feature set.
|
||
|
||
All calculations carry the disclaimer: **Not for operational use — verify all calculations independently.**
|
||
|
||
---
|
||
|
||
## Modules
|
||
|
||
### Fuel Order Calculator
|
||
|
||
Enter total fuel required, fuel on board, and fuel density to get the order quantity in US gallons, imperial gallons, and liters, all rounded up to the nearest 10 units.
|
||
|
||
Fuel density is entered at the 15°C reference temperature. The three-way toggle switches between specific gravity, kg/L, and lb/US gallon — values auto-convert when you switch units. If you don't have a fuel ticket, the default (0.810 SG / 6.76 lb/gal) is typical Jet-A.
|
||
|
||
The ambient temperature field corrects density using the ASTM D1250 Table 6B thermal expansion model. Temperature defaults to °C; tap the toggle to switch to °F (the value converts live). The primary volume unit (US gal, imperial gal, or liters) is set in the hamburger menu and defaults based on locale.
|
||
|
||
### Pavement Strength
|
||
|
||
Calculates ACN/ACR values for the selected aircraft at a given weight, using linear regression fits from official aircraft manual charts. Supports PCN (legacy) and PCR (ICAO 2024+ transition), rigid and flexible pavement types, and four subgrade categories (A through D).
|
||
|
||
Enter the airport's published PCN or PCR value in the comparison field to see a pass/exceed result with percentage. Airport pavement values can be found in the Jeppesen airport pages, the national AIP, or airport operator publications.
|
||
|
||
Some aircraft (G450, G650) show a computed ESWL using a weight-based formula. Others (G700) show fixed ESWL thresholds (single wheel and dual wheel) because the manufacturer publishes specific values rather than a formula.
|
||
|
||
### Crosswind Calculator
|
||
|
||
Enter wind as a five-digit string — for example, typing `31015` auto-formats to `310/15` when the field loses focus. Gust goes in the separate field. Runway accepts either a runway number (01–36) or a heading (010–360).
|
||
|
||
The output shows headwind/tailwind and crosswind components for both sustained and gust winds. Tailwind values display in red.
|
||
|
||
### Fuel Buckets
|
||
|
||
Drag the slider to a stage length and see the interpolated fuel burn rate. Data comes from either the aircraft's built-in bucket schedule (G450 only at RC1) or an operator-specific profile loaded via CSV or JSON import in the hamburger menu.
|
||
|
||
**CSV format** for import: two columns — stage length (hours, decimal) and fuel burn (lbs/hr). A header row is optional and auto-detected.
|
||
|
||
```
|
||
stage_length,fuel_burn
|
||
0.1,650
|
||
1.0,548.5
|
||
3.0,449
|
||
```
|
||
|
||
Profiles are named and stored per aircraft. See the "Fuel Profile JSON Format" section below for the JSON import/export schema.
|
||
|
||
### HF Frequencies
|
||
|
||
Fetches current ARINC HF frequency schedules for Atlantic and Pacific. Shows a staleness indicator — frequencies change on propagation-based windows (typically every few hours), so the 4-hour threshold flags when you should reload. The link opens the ARINC page directly in your browser.
|
||
|
||
### Passdown
|
||
|
||
A crew changeover form for sharing operational information: crew emails, registration, date, airport, FBO, FBO phone, maintenance status, and narrative. Records are stored locally (IndexedDB on web, SharedPreferences on Android).
|
||
|
||
The history view shows all passdowns with age-based color coding: today's entries are highlighted, yesterday's are muted, older entries are dimmed. Filter by registration and/or date range. Batch export produces a `.ptz` file of all matching results. See ".ptz File Format" below for the schema.
|
||
|
||
### Flight Level ↔ Meters
|
||
|
||
Two modes. **Meters ↔ Feet Lookup** searches the OEM conversion table (ICAO Table 15, 107 entries). Type in either direction and results filter live. **China FLAS** shows the China RVSM Flight Level Allocation Scheme with dual toggle buttons for eastbound (0°–179°) and westbound (186°–359°) filtering. RVSM levels are color-coded blue (east) and amber (west). When both buttons are active, all levels display.
|
||
|
||
ATC clears flight levels in meters; the pilot sets the altimeter to the corresponding feet value from the table. Due to rounding, the onboard metric readout may differ from the cleared value by up to 30 meters.
|
||
|
||
**Do not use for approach minima.** Chart values are rounded to the nearest 100 feet.
|
||
|
||
---
|
||
|
||
## Data File Structure
|
||
|
||
All aircraft-specific and reference data lives in JSON files shared by both platforms. This is the section to read if you need to edit existing data or add a new airframe.
|
||
|
||
### Directory Layout
|
||
|
||
**Web** (Vite `src/` directory):
|
||
```
|
||
src/
|
||
data/
|
||
reference.json
|
||
aircraft/
|
||
G450.json
|
||
G500.json
|
||
G650.json
|
||
G700.json
|
||
```
|
||
|
||
**Android** (`app/src/main/`):
|
||
```
|
||
assets/
|
||
reference.json
|
||
aircraft/
|
||
G450.json
|
||
G500.json
|
||
G650.json
|
||
G700.json
|
||
```
|
||
|
||
Both platforms read the same JSON — just placed in the appropriate directory. The web app imports via Vite at build time; Android reads from `assets/` at runtime via `DataLoader.init(context)`.
|
||
|
||
### Error Handling
|
||
|
||
Each aircraft file loads independently. If `G700.json` has a syntax error, the other three airframes still load normally. The app logs a warning rather than crashing. On Android, `DataLoader.loadErrors` contains a map of failed aircraft IDs and error messages.
|
||
|
||
### reference.json
|
||
|
||
Airframe-agnostic data. Not included in per-aircraft export/import.
|
||
|
||
```json
|
||
{
|
||
"_meta": {
|
||
"format": "pilot-toolkit-data",
|
||
"version": 3
|
||
},
|
||
"pavementSubgrades": {
|
||
"A": "A – High",
|
||
"B": "B – Medium",
|
||
"C": "C – Low",
|
||
"D": "D – Ultra Low"
|
||
},
|
||
"metersToFeet": {
|
||
"source": "...",
|
||
"caution": "Do not use for approach minima.",
|
||
"entries": [
|
||
[15100, 49500],
|
||
[300, 1000]
|
||
]
|
||
},
|
||
"chinaFLAS": {
|
||
"source": "...",
|
||
"entries": [
|
||
[15500, 50900],
|
||
[100, 300]
|
||
],
|
||
"rvsmEastbound": [29100, 31100, 33100, 35100, 37100, 39100, 41100],
|
||
"rvsmWestbound": [30100, 32100, 34100, 36100, 38100, 40100]
|
||
}
|
||
}
|
||
```
|
||
|
||
The `entries` arrays are `[meters, feet]` pairs, sorted descending by meters. RVSM arrays list feet values assigned to each direction.
|
||
|
||
### Aircraft JSON Files
|
||
|
||
Each file represents one airframe. The filename (minus `.json`) is the aircraft ID used throughout the app.
|
||
|
||
#### Required Fields
|
||
|
||
| Field | Type | Description |
|
||
|-------|------|-------------|
|
||
| `_meta.format` | string | Must be `"pilot-toolkit-aircraft"` |
|
||
| `_meta.version` | number | Schema version (currently `3`) |
|
||
| `_meta.aircraftId` | string | Must match the filename |
|
||
| `label` | string | Display name (e.g., `"G700"`) |
|
||
| `available` | boolean | `true` if the aircraft has enough data for calculations; `false` shows it as a placeholder |
|
||
|
||
#### Optional Fields (null if not available)
|
||
|
||
| Field | Type | Description |
|
||
|-------|------|-------------|
|
||
| `weightLimits` | object | `minBew`, `mtow`, `maxRamp` (all integers, lbs) |
|
||
| `eswl` | object | ESWL configuration — see below |
|
||
| `pcn` | object | PCN regression coefficients — see below |
|
||
| `pcr` | object | PCR regression coefficients — same structure as `pcn` |
|
||
| `pcnError` | string | Error margin (e.g., `"±2%"`) |
|
||
| `pcrError` | string | Error margin |
|
||
| `windLimitations` | object | Reserved for future use, currently `null` |
|
||
| `fuelBuckets` | array | Array of `[stageLength, fuelBurn]` pairs |
|
||
|
||
#### ESWL — Two Types
|
||
|
||
The `eswl` field uses a `type` discriminator.
|
||
|
||
**Formula type** (G450, G650): ESWL is calculated as `weight × weightFactor ÷ wheelFactor`.
|
||
|
||
```json
|
||
"eswl": {
|
||
"type": "formula",
|
||
"weightFactor": 0.45,
|
||
"wheelFactor": 1.23
|
||
}
|
||
```
|
||
|
||
**Thresholds type** (G700): Manufacturer publishes fixed values.
|
||
|
||
```json
|
||
"eswl": {
|
||
"type": "thresholds",
|
||
"singleWheel": { "label": "S-85", "value": 85000, "unit": "lbs" },
|
||
"dualWheel": { "label": "D-108", "value": 108000, "unit": "lbs" },
|
||
"note": "Unrestricted operations at or above these values."
|
||
}
|
||
```
|
||
|
||
#### Pavement Coefficients (PCN/PCR)
|
||
|
||
Linear regression: `result = slope × weight + intercept`. The structure is the same for both `pcn` and `pcr`:
|
||
|
||
```json
|
||
"pcn": {
|
||
"rigid": {
|
||
"A": { "slope": 0.0003323, "intercept": -2.4247 },
|
||
"B": { "slope": 0.0003268, "intercept": -1.2011 },
|
||
"C": { "slope": 0.0003521, "intercept": -2.1385 },
|
||
"D": { "slope": 0.0003547, "intercept": -1.5244 }
|
||
},
|
||
"flexible": {
|
||
"A": { "slope": 0.000286, "intercept": -2.4517 },
|
||
"...": "..."
|
||
}
|
||
}
|
||
```
|
||
|
||
Each combination of pavement type (rigid/flexible) and subgrade (A/B/C/D) has its own slope and intercept. These are derived from linear regression fits to official aircraft manual charts.
|
||
|
||
#### Fuel Buckets
|
||
|
||
Array of `[stageLength, fuelBurn]` pairs sorted by stage length. Stage length is in decimal hours; fuel burn is in lbs/hr.
|
||
|
||
```json
|
||
"fuelBuckets": [
|
||
[0.1, 650.0],
|
||
[1.0, 548.5],
|
||
[3.0, 449.0],
|
||
[9.9, 456.6]
|
||
]
|
||
```
|
||
|
||
Set to `null` if no built-in data is available for the airframe. Users can still load operator-specific data via CSV or JSON import.
|
||
|
||
### Adding a New Airframe
|
||
|
||
1. Create a new JSON file in `aircraft/` (e.g., `G280.json`).
|
||
2. Set `_meta.aircraftId` and `label` to match.
|
||
3. Set `available` to `false` if the data is incomplete — the app shows the aircraft in the selector but disables calculations.
|
||
4. Populate whichever fields you have. Everything except `_meta`, `label`, and `available` is nullable.
|
||
5. On Android, the file is auto-discovered from the `aircraft/` directory. On web, add an import line and a `loadAircraft()` call in `toolkit.jsx`.
|
||
|
||
---
|
||
|
||
## Exchange Formats
|
||
|
||
### .ptz File Format
|
||
|
||
The `.ptz` format is a **gzipped JSON array** of passdown objects. The format is open — third-party tools and operators are free to generate or consume `.ptz` files.
|
||
|
||
To inspect a `.ptz` file manually: `gunzip < PASSDOWN_N12345_2026-02-28.ptz | python3 -m json.tool`
|
||
|
||
Each object in the array has the following fields:
|
||
|
||
| Field | Type | Description |
|
||
|-------|------|-------------|
|
||
| `id` | string | Unique identifier (UUID-style) |
|
||
| `date` | string | Passdown date (`YYYY-MM-DD`) |
|
||
| `registration` | string | Aircraft registration (e.g., `N12345`) |
|
||
| `airport` | string | ICAO code (e.g., `KPTK`) |
|
||
| `fbo` | string | FBO name |
|
||
| `fboPhone` | string | FBO phone number |
|
||
| `pic` | string | PIC email |
|
||
| `sic` | string | SIC email |
|
||
| `ca1` | string | Lead cabin attendant email |
|
||
| `oncomingPic` | string | Oncoming PIC email |
|
||
| `oncomingSic` | string | Oncoming SIC email |
|
||
| `maintenance` | string | Maintenance status / squawks |
|
||
| `narrative` | string | Free-text operational notes |
|
||
| `createdAt` | string | ISO 8601 timestamp |
|
||
| `updatedAt` | string | ISO 8601 timestamp |
|
||
| `lastSentAt` | string | ISO 8601 timestamp (empty string if never sent) |
|
||
|
||
Filename conventions:
|
||
- Single passdown: `PASSDOWN_REG_DATE.ptz`
|
||
- Batch (single tail): `PASSDOWN_BATCH_REG_FROMDATE_TODATE.ptz`
|
||
- Batch (mixed tails): `PASSDOWN_BATCH_Nrecords_FROMDATE_TODATE.ptz`
|
||
|
||
On import, duplicates are detected by `id` and flagged in the preview screen.
|
||
|
||
### Fuel Profile JSON Format
|
||
|
||
Exported as `FUEL_PROFILE_name_aircraft.json`. The app validates the `format` field on import.
|
||
|
||
```json
|
||
{
|
||
"format": "pilot-toolkit-fuel-profile",
|
||
"version": 1,
|
||
"aircraft": "G450",
|
||
"aircraftLabel": "G450",
|
||
"name": "FLEXJET G450",
|
||
"entries": 99,
|
||
"buckets": [
|
||
[0.1, 650.0],
|
||
[1.0, 548.5],
|
||
[9.9, 456.6]
|
||
]
|
||
}
|
||
```
|
||
|
||
| Field | Required on Import | Description |
|
||
|-------|-------------------|-------------|
|
||
| `format` | Yes | Must be `"pilot-toolkit-fuel-profile"` |
|
||
| `aircraft` | Yes | Target aircraft ID (e.g., `"G450"`) |
|
||
| `name` | No | Profile name (defaults to `"Imported"`) |
|
||
| `buckets` | Yes | Array of `[stageLength, fuelBurn]` pairs |
|
||
| `version`, `aircraftLabel`, `entries` | No | Informational; ignored on import |
|
||
|
||
### Fuel Bucket CSV Format
|
||
|
||
Two columns: stage length (decimal hours) and fuel burn (lbs/hr). Header row is optional and auto-detected.
|
||
|
||
```
|
||
stage_length,fuel_burn
|
||
0.1,650
|
||
1.0,548.5
|
||
3.0,449
|
||
9.9,456.6
|
||
```
|
||
|
||
On import, the app prompts for a profile name. The data replaces any existing profile for the selected aircraft.
|
||
|
||
---
|
||
|
||
## Settings
|
||
|
||
Available in the hamburger menu (☰):
|
||
|
||
- **Aircraft selector** — Sets the active airframe for pavement, fuel order, and fuel bucket modules. "Set Default" persists the choice across sessions.
|
||
- **Dark mode** — Toggles light/dark theme.
|
||
- **Primary volume unit** — US gallons, imperial gallons, or liters. Affects fuel order output. Auto-detected from locale on first use.
|
||
- **Passdown retention** — How long to keep passdown history: 3, 6, 12, 24, or 36 months, or never delete. Auto-purge runs on app open.
|
||
- **Fuel profiles** — View, export, and clear loaded profiles per aircraft. CSV and JSON import.
|