G1000: two-way sim sync, more PFD/MFD fidelity, authentic dialogs

Sync (FlyWithLua companions in plugins/ + server/fmssync.js):
- FMS flight-plan two-way sync (App <-> in-sim FMS) via fms-sync.lua
- G1000 UI-state publish (page/range/inset) via ui-sync.lua + CDI source,
  baro, map-range follow
- Terrain awareness: elevation grid probe (terrain-probe.lua) -> red/yellow
  MFD overlay vs aircraft altitude

PFD:
- AFCS mode annunciation bar from autopilot _status datarefs
- CDI source GPS/VLOC colouring, BRG1/BRG2 pointers + DME windows, marker beacons
- magenta speed/altitude trend vectors, selected-altitude alerting
- time-based (frame-rate-independent) smoothing for attitude/heading/tapes

MFD:
- nav data bar (DTK/ETE/active leg), airways overlay from earth_awy.dat,
  compass rose anchored to the ownship

Dialogs (NEAREST/FLIGHTPLAN/DIRECT-TO/PROCEDURES):
- flat, square, embedded G1000 look (no shadow/rounded/transparency)
- compact lower-right placement, no close X (softkey toggles), single window
- NEAREST 2-line entries (ILS/VFR, COM freq, runway length), PROC action menu

Service worker: network-first HTML so reloads pick up new builds (cache v2).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-02 02:17:06 +02:00
parent 354ea5d44b
commit 38b048ad41
23 changed files with 1707 additions and 213 deletions
+30 -9
View File
@@ -21,6 +21,7 @@ export default function Proc({ xp, onClose }) {
const [procs, setProcs] = useState(null);
const [err, setErr] = useState('');
const [cat, setCat] = useState('approach');
const [view, setView] = useState('menu'); // 'menu' (PDF action list) | 'pick'
const [selProc, setSelProc] = useState(null); // { name, transitions }
const [selTrans, setSelTrans] = useState('');
const [legs, setLegs] = useState([]);
@@ -59,12 +60,39 @@ export default function Proc({ xp, onClose }) {
onClose();
};
const catLabel = CATS.find((c) => c.id === cat).label;
// The PDF's action menu. SELECT … opens our picker for that category;
// ACTIVATE … are shown for authenticity (armed-procedure actions).
if (view === 'menu') {
const item = (label, onClick, sel) => (
<button className={`proc-menu-i ${sel ? 'sel' : ''}`} onClick={onClick}>{label}</button>
);
const sel = (c) => { setCat(c); setSelProc(null); setSelTrans(''); setView('pick'); };
return (
<div className="gwin-backdrop" onClick={onClose}>
<div className="dlg proc menu" onClick={(e) => e.stopPropagation()}>
<div className="dlg-head">PROCEDURES</div>
<div className="proc-menu">
{item('ACTIVATE VECTOR-TO-FINAL', () => {})}
{item('ACTIVATE APPROACH', () => {})}
{item('ACTIVATE MISSED APPROACH', () => {})}
{item('SELECT APPROACH', () => sel('approach'), true)}
{item('SELECT ARRIVAL', () => sel('arrival'))}
{item('SELECT DEPARTURE', () => sel('departure'))}
</div>
</div>
</div>
);
}
return (
<div className="dlg-backdrop" onClick={onClose}>
<div className="gwin-backdrop" onClick={onClose}>
<div className="dlg proc" onClick={(e) => e.stopPropagation()}>
<div className="dlg-head">PROCEDURES</div>
<div className="dlg-head">{catLabel}</div>
<div className="proc-body">
<div className="proc-apt">
<button className="proc-back" onClick={() => setView('menu')}></button>
<label>APT</label>
<input value={query} onChange={(e) => setQuery(e.target.value.toUpperCase())}
onKeyDown={(e) => e.key === 'Enter' && setIcao(query)}
@@ -73,13 +101,6 @@ export default function Proc({ xp, onClose }) {
</div>
{err && <div className="proc-err">{err}</div>}
<div className="proc-tabs">
{CATS.map((c) => (
<button key={c.id} className={cat === c.id ? 'on' : ''}
onClick={() => { setCat(c.id); setSelProc(null); setSelTrans(''); }}>{c.label}</button>
))}
</div>
<div className="proc-cols">
<div className="proc-list">
<div className="proc-coltitle">{procs ? `${catList.length}` : '—'} PROC</div>