Citation: match PFD/MFD size (portrait DU-870), Nav Source switch, manual audit

- MFD reworked to the same portrait DU-870 format as the PFD (800x940) so both
  tubes are identical size side-by-side in the PFD+MFD view, like the real panel.
- Nav Source Selector now on the PFD bezel (sits under the PFD per manual p24):
  NAV (VOR1/VOR2) / FMS buttons drive HSI_source_select; the HSI course pointer,
  CDI and source label colour by source — FMS magenta, VOR green (Honeywell
  convention). MFD source label (FMS1/VOR) follows the same coupling.
- Added the airspeed trend vector (PFD #3, was missing): smoothed acceleration
  projected 10 s, magenta, on the speed tape.
- Removed dead MFD soft-keys per manual: PFD SETUP → IN/HPA baro unit; EICAS SYS
  → FUEL-HYD/ELEC/APU/ENG sub-set readout (#11/#14) with RTN.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-04 14:16:15 +02:00
parent 6756acab4a
commit e8dfa84266
3 changed files with 94 additions and 28 deletions
+2 -2
View File
@@ -33,8 +33,8 @@
font-family: 'Roboto Mono','Consolas',monospace; font-family: 'Roboto Mono','Consolas',monospace;
} }
.cit-pfd { aspect-ratio: 800 / 940; } .cit-pfd { aspect-ratio: 800 / 940; }
.cit-mfd { aspect-ratio: 1 / 1; } .cit-mfd { aspect-ratio: 800 / 940; }
.cit-eicas { aspect-ratio: 760 / 900; } .cit-eicas { aspect-ratio: 800 / 940; }
.cit-pfd text, .cit-mfd text, .cit-eicas text { font-family: 'Roboto Mono','Consolas',monospace; } .cit-pfd text, .cit-mfd text, .cit-eicas text { font-family: 'Roboto Mono','Consolas',monospace; }
/* ---- bezel (soft-key / knob strip beneath a display) ---- */ /* ---- bezel (soft-key / knob strip beneath a display) ---- */
+53 -12
View File
@@ -32,6 +32,8 @@ export default function CitMFD({ xp }) {
const [ov, setOv] = useState({ traffic: true, terrain: false, apts: true, vor: true }); const [ov, setOv] = useState({ traffic: true, terrain: false, apts: true, vor: true });
const [setup, setSetup] = useState(null); // null | 'mfd' | 'eicas' | 'pfd' const [setup, setSetup] = useState(null); // null | 'mfd' | 'eicas' | 'pfd'
const [vspd, setVspd] = useState(false); const [vspd, setVspd] = useState(false);
const [baroUnit, setBaroUnit] = useState('in'); // PFD SETUP: IN / HPA
const [eicasSub, setEicasSub] = useState('fuel'); // EICAS SYS subset page
const [et, setEt] = useState(0); const [et, setEt] = useState(0);
const etRun = useRef(false); const etRun = useRef(false);
useEffect(() => { const id = setInterval(() => etRun.current && setEt((t) => t + 1), 1000); return () => clearInterval(id); }, []); useEffect(() => { const id = setInterval(() => etRun.current && setEt((t) => t + 1), 1000); return () => clearInterval(id); }, []);
@@ -41,8 +43,9 @@ export default function CitMFD({ xp }) {
const lon = useEased(num(V.lon), 0.14); const lon = useEased(num(V.lon), 0.14);
const hdg = useEasedAngle(num(V.heading), 0.10); const hdg = useEasedAngle(num(V.heading), 0.10);
const trk = num(V.track); const trk = num(V.track);
// arc map geometry: ownship near bottom, ~120° forward arc // arc map geometry: portrait DU-870 tube (identical to the PFD); ownship low,
const W = 760, H = 760, cx = W / 2, cy = 600, R = 470; // compass radius // ~120° forward arc filling the upper two-thirds, data blocks along the bottom.
const W = 800, H = 940, cx = 400, cy = 740, R = 540; // compass radius
const pxPerNm = R / rng; const pxPerNm = R / rng;
const project = (d, brg) => { // heading-up const project = (d, brg) => { // heading-up
const rel = toRad(brg - hdg); const rel = toRad(brg - hdg);
@@ -71,6 +74,10 @@ export default function CitMFD({ xp }) {
} }
} }
// coupled nav source (Nav Source Selector): FMS flight plan vs VOR1/VOR2.
const cdiSrc = num(V.cdiSrc);
const src = cdiSrc === 2 ? 'fms' : 'nav';
const srcLabel = cdiSrc === 2 ? 'FMS1' : cdiSrc === 1 ? 'VOR2' : 'VOR1';
const gs = Math.round(num(V.groundspeed) * 1.94384); const gs = Math.round(num(V.groundspeed) * 1.94384);
const tas = Math.round(num(V.tas)); const tas = Math.round(num(V.tas));
const sat = Math.round(num(V.oat)); const sat = Math.round(num(V.oat));
@@ -84,16 +91,16 @@ export default function CitMFD({ xp }) {
return ( return (
<div className="cit-screen"> <div className="cit-screen">
<svg className="cit-mfd" viewBox="0 0 760 760" preserveAspectRatio="xMidYMid meet"> <svg className="cit-mfd" viewBox="0 0 800 940" preserveAspectRatio="xMidYMid meet">
<rect x={0} y={0} width={760} height={760} fill="#04070a" /> <rect x={0} y={0} width={800} height={940} fill="#04070a" />
<clipPath id="mfdclip"><rect x={0} y={70} width={760} height={690} /></clipPath> <clipPath id="mfdclip"><rect x={0} y={70} width={800} height={770} /></clipPath>
{/* heading box (#2,#20) + FMS source (#4) */} {/* heading box (#2,#20) + FMS/NAV source (#4) */}
<text x={24} y={30} fontSize="14" fill="#19c3e0">HDG</text> <text x={24} y={30} fontSize="14" fill="#19c3e0">HDG</text>
<text x={24} y={52} fontSize="22" fill="#d24bd2">{String(Math.round(mod360(num(V.apHdgBug)))).padStart(3, '0')}</text> <text x={24} y={52} fontSize="22" fill="#d24bd2">{String(Math.round(mod360(num(V.apHdgBug)))).padStart(3, '0')}</text>
<rect x={300} y={12} width={160} height={30} fill="none" stroke="#2a3138" /> <rect x={320} y={12} width={160} height={30} fill="none" stroke="#2a3138" />
<text x={380} y={33} fontSize="18" fill="#13e000" textAnchor="middle">{String(Math.round(mod360(hdg))).padStart(3, '0')}°</text> <text x={400} y={33} fontSize="18" fill="#13e000" textAnchor="middle">{String(Math.round(mod360(hdg))).padStart(3, '0')}°</text>
<text x={720} y={30} fontSize="16" fill="#d24bd2" textAnchor="end">FMS1</text> <text x={776} y={30} fontSize="16" fill={src === 'fms' ? '#d24bd2' : '#13e000'} textAnchor="end">{srcLabel}</text>
<g clipPath="url(#mfdclip)"> <g clipPath="url(#mfdclip)">
{/* compass arc (#3) */} {/* compass arc (#3) */}
@@ -137,7 +144,7 @@ export default function CitMFD({ xp }) {
</g> </g>
{/* data group (#8) bottom-right */} {/* data group (#8) bottom-right */}
<g transform="translate(560 470)"> <g transform="translate(600 800)">
<rect x={0} y={0} width={184} height={120} fill="#070b0f" stroke="#2a3138" /> <rect x={0} y={0} width={184} height={120} fill="#070b0f" stroke="#2a3138" />
<text x={92} y={20} fontSize="12" fill="#9aa6ad" textAnchor="middle">NM {rng}</text> <text x={92} y={20} fontSize="12" fill="#9aa6ad" textAnchor="middle">NM {rng}</text>
<text x={10} y={44} fontSize="13" fill="#9aa6ad">ETE</text><text x={174} y={44} fontSize="14" fill="#13e000" textAnchor="end">{eteMin > 0 ? fmt(eteMin * 60) : ' '}</text> <text x={10} y={44} fontSize="13" fill="#9aa6ad">ETE</text><text x={174} y={44} fontSize="14" fill="#13e000" textAnchor="end">{eteMin > 0 ? fmt(eteMin * 60) : ' '}</text>
@@ -145,9 +152,29 @@ export default function CitMFD({ xp }) {
<text x={10} y={88} fontSize="13" fill="#9aa6ad">TAS</text><text x={174} y={88} fontSize="14" fill="#13e000" textAnchor="end">{tas}</text> <text x={10} y={88} fontSize="13" fill="#9aa6ad">TAS</text><text x={174} y={88} fontSize="14" fill="#13e000" textAnchor="end">{tas}</text>
<text x={10} y={110} fontSize="13" fill="#9aa6ad">GSPD</text><text x={174} y={110} fontSize="14" fill="#13e000" textAnchor="end">{gs}</text> <text x={10} y={110} fontSize="13" fill="#9aa6ad">GSPD</text><text x={174} y={110} fontSize="14" fill="#13e000" textAnchor="end">{gs}</text>
</g> </g>
{/* EICAS SYS subset (#11) — a sub-set of the dedicated EICAS display */}
{setup === 'eicas' && (() => {
const a = (x, i) => (Array.isArray(x) ? num(x[i]) : num(x));
const rows = eicasSub === 'elec' ? [['DC VOLTS', `${a(V.volts, 0).toFixed(0)} / ${a(V.volts, 1).toFixed(0)}`], ['DC AMPS', `${Math.round(a(V.genAmps, 0))} / ${Math.round(a(V.genAmps, 1) || a(V.genAmps, 0))}`], ['BATT', `${a(V.battVolt, 0).toFixed(1)}V`]]
: eicasSub === 'apu' ? [['APU RPM', '0%'], ['APU EGT', '— °C'], ['BLEED', 'OFF']]
: eicasSub === 'eng' ? [['N1 L/R', `${a(V.n1, 0).toFixed(1)} / ${a(V.n1, 1).toFixed(1)}`], ['N2 L/R', `${a(V.n2, 0).toFixed(0)} / ${a(V.n2, 1).toFixed(0)}`], ['ITT L/R', `${Math.round(a(V.itt, 0))} / ${Math.round(a(V.itt, 1))}`]]
: [['FUEL QTY', `${Math.round((a(V.fuelQty, 0) + a(V.fuelQty, 1)) * 2.20462)} LB`], ['FLOW L/R', `${Math.round(a(V.fuelFlow, 0) * 7936.6)} / ${Math.round(a(V.fuelFlow, 1) * 7936.6)}`], ['HYD A/B', `${Math.round(a(V.hydPress, 0))} / ${Math.round(a(V.hydPress, 1))}`]];
return (
<g transform="translate(250 240)">
<rect x={0} y={0} width={300} height={170} fill="#070b0f" stroke="#19c3e0" />
<text x={150} y={26} fontSize="15" fill="#19c3e0" textAnchor="middle">EICAS · {eicasSub.toUpperCase()}</text>
{rows.map(([k, v], i) => (
<g key={k} transform={`translate(0 ${56 + i * 32})`}>
<text x={18} y={0} fontSize="14" fill="#cfd6dc">{k}</text>
<text x={282} y={0} fontSize="14" fill="#13e000" textAnchor="end">{v}</text>
</g>
))}
</g>
);
})()}
{/* V-SPEEDS reference card (#10) — Citation X operating speeds, manual p80 */} {/* V-SPEEDS reference card (#10) — Citation X operating speeds, manual p80 */}
{vspd && ( {vspd && (
<g transform="translate(250 120)"> <g transform="translate(270 230)">
<rect x={0} y={0} width={260} height={300} fill="#070b0f" stroke="#19c3e0" /> <rect x={0} y={0} width={260} height={300} fill="#070b0f" stroke="#19c3e0" />
<text x={130} y={26} fontSize="16" fill="#19c3e0" textAnchor="middle">V-SPEEDS · CITATION X</text> <text x={130} y={26} fontSize="16" fill="#19c3e0" textAnchor="middle">V-SPEEDS · CITATION X</text>
{[['Vr (rotate)', '145'], ['Vfe (flaps)', '180'], ['Vmo SL-8000', '270'], ['Vmo >8000', '350'], {[['Vr (rotate)', '145'], ['Vfe (flaps)', '180'], ['Vmo SL-8000', '270'], ['Vmo >8000', '350'],
@@ -161,7 +188,7 @@ export default function CitMFD({ xp }) {
</g> </g>
)} )}
{/* clock / ET + WX status (#12,#16) bottom-left */} {/* clock / ET + WX status (#12,#16) bottom-left */}
<g transform="translate(20 470)"> <g transform="translate(16 800)">
<rect x={0} y={0} width={150} height={120} fill="#070b0f" stroke="#2a3138" /> <rect x={0} y={0} width={150} height={120} fill="#070b0f" stroke="#2a3138" />
<text x={75} y={20} fontSize="13" fill="#13e000" textAnchor="middle">{now.toTimeString().slice(0, 8)}</text> <text x={75} y={20} fontSize="13" fill="#13e000" textAnchor="middle">{now.toTimeString().slice(0, 8)}</text>
<text x={75} y={38} fontSize="11" fill="#9aa6ad" textAnchor="middle">CLOCK</text> <text x={75} y={38} fontSize="11" fill="#9aa6ad" textAnchor="middle">CLOCK</text>
@@ -180,6 +207,20 @@ export default function CitMFD({ xp }) {
<SK label="VOR" on={ov.vor} onClick={() => setOv((o) => ({ ...o, vor: !o.vor }))} /> <SK label="VOR" on={ov.vor} onClick={() => setOv((o) => ({ ...o, vor: !o.vor }))} />
<SK label="RTN" onClick={() => setSetup(null)} /> <SK label="RTN" onClick={() => setSetup(null)} />
</> </>
) : setup === 'pfd' ? (
<>
<SK label="IN" on={baroUnit === 'in'} onClick={() => setBaroUnit('in')} />
<SK label="HPA" on={baroUnit === 'hpa'} onClick={() => setBaroUnit('hpa')} />
<SK label="RTN" onClick={() => setSetup(null)} />
</>
) : setup === 'eicas' ? (
<>
<SK label="FUEL/HYD" on={eicasSub === 'fuel'} onClick={() => setEicasSub('fuel')} />
<SK label="ELEC" on={eicasSub === 'elec'} onClick={() => setEicasSub('elec')} />
<SK label="APU" on={eicasSub === 'apu'} onClick={() => setEicasSub('apu')} />
<SK label="ENG" on={eicasSub === 'eng'} onClick={() => setEicasSub('eng')} />
<SK label="RTN" onClick={() => setSetup(null)} />
</>
) : ( ) : (
<> <>
<button className="cit-sk" onClick={() => setSetup('pfd')}>PFD SETUP</button> <button className="cit-sk" onClick={() => setSetup('pfd')}>PFD SETUP</button>
+39 -14
View File
@@ -22,7 +22,7 @@ const hz2mhz = (hz) => (num(hz) / 100).toFixed(2);
// Citation X operating speeds (manual p80): Vso 115 · Vs1 136 · Vfe 180 · // Citation X operating speeds (manual p80): Vso 115 · Vs1 136 · Vfe 180 ·
// Vmo 270 (SL-8000') / 350 (above) · Mmo 0.935. // Vmo 270 (SL-8000') / 350 (above) · Mmo 0.935.
const VSO = 115, VS1 = 136, VFE = 180; const VSO = 115, VS1 = 136, VFE = 180;
function SpeedTape({ ias, mach, bug, alt }) { function SpeedTape({ ias, mach, bug, alt, trendKt }) {
const H = 560, mid = H / 2, pxkt = 3.4; // 3.4 px per knot const H = 560, mid = H / 2, pxkt = 3.4; // 3.4 px per knot
const y = (s) => mid + (ias - s) * pxkt; const y = (s) => mid + (ias - s) * pxkt;
const vmo = alt > 8000 ? 350 : 270; const vmo = alt > 8000 ? 350 : 270;
@@ -49,6 +49,13 @@ function SpeedTape({ ias, mach, bug, alt }) {
{/* Vfe flap-limit marker */} {/* Vfe flap-limit marker */}
<line x1={0} y1={y(VFE)} x2={12} y2={y(VFE)} stroke="#fff" strokeWidth="3" /> <line x1={0} y1={y(VFE)} x2={12} y2={y(VFE)} stroke="#fff" strokeWidth="3" />
{marks} {marks}
{/* airspeed trend vector (#3): magenta line from the index up/down */}
{Math.abs(trendKt) > 1 && (
<g>
<line x1={71} y1={mid} x2={71} y2={mid - trendKt * pxkt} stroke="#d24bd2" strokeWidth="3" />
<polygon points={`71,${mid - trendKt * pxkt} 67,${mid - trendKt * pxkt + (trendKt > 0 ? 8 : -8)} 75,${mid - trendKt * pxkt + (trendKt > 0 ? 8 : -8)}`} fill="#d24bd2" />
</g>
)}
</g> </g>
<defs> <defs>
<pattern id="barber" width="8" height="8" patternUnits="userSpaceOnUse" patternTransform="rotate(45)"> <pattern id="barber" width="8" height="8" patternUnits="userSpaceOnUse" patternTransform="rotate(45)">
@@ -208,7 +215,7 @@ function Attitude({ pitch, roll, slip, fdP, fdR, fdOn }) {
} }
// ── HSI (rotating compass with CDI + bearing pointers) ───────────────────────── // ── HSI (rotating compass with CDI + bearing pointers) ─────────────────────────
function HSI({ hdg, trk, crs, hdgBug, cdi, toFrom, brg1, brg2, srcLabel }) { function HSI({ hdg, trk, crs, hdgBug, cdi, toFrom, brg1, brg2, srcLabel, srcColor }) {
const R = 150; const R = 150;
const card = []; const card = [];
for (let d = 0; d < 360; d += 5) { for (let d = 0; d < 360; d += 5) {
@@ -237,15 +244,15 @@ function HSI({ hdg, trk, crs, hdgBug, cdi, toFrom, brg1, brg2, srcLabel }) {
<g>{card}</g> <g>{card}</g>
{/* heading bug (magenta) */} {/* heading bug (magenta) */}
<g transform={`rotate(${mod360(hdgBug - hdg)})`}><polygon points={`0,${-R} -9,${-R + 14} 9,${-R + 14}`} fill="#d24bd2" /></g> <g transform={`rotate(${mod360(hdgBug - hdg)})`}><polygon points={`0,${-R} -9,${-R + 14} 9,${-R + 14}`} fill="#d24bd2" /></g>
{/* course pointer + CDI deviation (cyan), #5 + #15 */} {/* course pointer + CDI deviation (#5 + #15) — FMS magenta / VOR green */}
<g transform={`rotate(${mod360(crs - hdg)})`}> <g transform={`rotate(${mod360(crs - hdg)})`}>
<line x1={0} y1={-R + 18} x2={0} y2={-50} stroke="#19c3e0" strokeWidth="3" /> <line x1={0} y1={-R + 18} x2={0} y2={-50} stroke={srcColor} strokeWidth="3" />
<polygon points={`0,${-R + 6} -8,${-R + 22} 8,${-R + 22}`} fill="#19c3e0" /> <polygon points={`0,${-R + 6} -8,${-R + 22} 8,${-R + 22}`} fill={srcColor} />
<line x1={0} y1={50} x2={0} y2={R - 18} stroke="#19c3e0" strokeWidth="3" /> <line x1={0} y1={50} x2={0} y2={R - 18} stroke={srcColor} strokeWidth="3" />
{/* CDI bar */} {/* CDI bar */}
<line x1={clamp(cdi, -2, 2) * 30} y1={-46} x2={clamp(cdi, -2, 2) * 30} y2={46} stroke="#19c3e0" strokeWidth="3.5" /> <line x1={clamp(cdi, -2, 2) * 30} y1={-46} x2={clamp(cdi, -2, 2) * 30} y2={46} stroke={srcColor} strokeWidth="3.5" />
{[-2, -1, 1, 2].map((d) => <circle key={d} cx={d * 30} cy={0} r="3" fill="none" stroke="#9aa6ad" strokeWidth="1.2" />)} {[-2, -1, 1, 2].map((d) => <circle key={d} cx={d * 30} cy={0} r="3" fill="none" stroke="#9aa6ad" strokeWidth="1.2" />)}
{toFrom !== 0 && <polygon points={toFrom > 0 ? '0,-14 -8,2 8,2' : '0,14 -8,-2 8,-2'} fill="#19c3e0" />} {toFrom !== 0 && <polygon points={toFrom > 0 ? '0,-14 -8,2 8,2' : '0,14 -8,-2 8,-2'} fill={srcColor} />}
</g> </g>
{/* bearing pointers — #6 secondary NAV (cyan circle = BRG1, white diamond = BRG2) */} {/* bearing pointers — #6 secondary NAV (cyan circle = BRG1, white diamond = BRG2) */}
{brg1 != null && ptr(brg1, '#19c3e0', false)} {brg1 != null && ptr(brg1, '#19c3e0', false)}
@@ -253,7 +260,7 @@ function HSI({ hdg, trk, crs, hdgBug, cdi, toFrom, brg1, brg2, srcLabel }) {
{/* fixed lubber line + aircraft */} {/* fixed lubber line + aircraft */}
<polygon points={`0,${-R - 2} -8,${-R - 16} 8,${-R - 16}`} fill="#fff" /> <polygon points={`0,${-R - 2} -8,${-R - 16} 8,${-R - 16}`} fill="#fff" />
<text x={0} y={-R - 22} fontSize="13" fill="#fff" textAnchor="middle" fontWeight="700">{String(Math.round(mod360(hdg))).padStart(3, '0')}</text> <text x={0} y={-R - 22} fontSize="13" fill="#fff" textAnchor="middle" fontWeight="700">{String(Math.round(mod360(hdg))).padStart(3, '0')}</text>
<text x={0} y={6} fontSize="12" fill="#13e000" textAnchor="middle">{srcLabel}</text> <text x={0} y={6} fontSize="12" fill={srcColor} textAnchor="middle">{srcLabel}</text>
</g> </g>
); );
} }
@@ -289,8 +296,20 @@ export default function CitPFD({ xp }) {
// bearing pointers only when a station is received (finite, nonzero) // bearing pointers only when a station is received (finite, nonzero)
const brg1 = (num(V.nav1Dme) > 0 || num(V.nav1Brg) > 0) ? brg1e : null; const brg1 = (num(V.nav1Dme) > 0 || num(V.nav1Brg) > 0) ? brg1e : null;
const brg2 = (num(V.nav2Dme) > 0 || num(V.nav2Brg) > 0) ? brg2e : null; const brg2 = (num(V.nav2Dme) > 0 || num(V.nav2Brg) > 0) ? brg2e : null;
const srcLabel = num(V.cdiSrc) === 2 ? 'FMS1' : num(V.cdiSrc) === 1 ? 'VOR2' : 'VOR1'; // Nav source (Nav Source Selector, manual p24): 0 VOR1 · 1 VOR2 · 2 FMS.
const dme = num(V.cdiSrc) === 1 ? num(V.nav2Dme) : num(V.nav1Dme); // FMS course is magenta, VOR course is green (Honeywell convention).
const cdiSrc = num(V.cdiSrc);
const srcLabel = cdiSrc === 2 ? 'FMS1' : cdiSrc === 1 ? 'VOR2' : 'VOR1';
const srcColor = cdiSrc === 2 ? '#d24bd2' : '#13e000';
const cycleNav = () => xp.setDataref('cdiSrc', cdiSrc === 1 ? 0 : 1); // toggle VOR1↔VOR2
const setFms = () => xp.setDataref('cdiSrc', 2);
const dme = cdiSrc === 1 ? num(V.nav2Dme) : num(V.nav1Dme);
// airspeed trend vector (#3): smoothed acceleration projected 10 s ahead
const t = trend.current, nowS = (typeof performance !== 'undefined' ? performance.now() : Date.now()) / 1000;
const dt = Math.min(0.5, Math.max(0.001, nowS - (t.t || nowS)));
const rate = (ias - (t.ias != null ? t.ias : ias)) / dt; // kt/s
t.s = (t.s || 0) * 0.92 + rate * 0.08; t.ias = ias; t.t = nowS;
const trendKt = clamp(t.s * 10, -45, 45);
return ( return (
<div className="cit-screen"> <div className="cit-screen">
@@ -299,7 +318,7 @@ export default function CitPFD({ xp }) {
{/* attitude */} {/* attitude */}
<g transform="translate(400 270)"><Attitude pitch={pitch} roll={roll} slip={slip} fdP={num(V.fdPitch)} fdR={num(V.fdRoll)} fdOn={fdOn} /></g> <g transform="translate(400 270)"><Attitude pitch={pitch} roll={roll} slip={slip} fdP={num(V.fdPitch)} fdR={num(V.fdRoll)} fdOn={fdOn} /></g>
{/* speed tape (#2,#3) */} {/* speed tape (#2,#3) */}
<g transform="translate(96 90)"><SpeedTape ias={ias} mach={mach} bug={num(V.apSpdBug)} alt={alt} /></g> <g transform="translate(96 90)"><SpeedTape ias={ias} mach={mach} bug={num(V.apSpdBug)} alt={alt} trendKt={trendKt} /></g>
<text x={120} y={78} fontSize="14" fill="#9aa6ad" textAnchor="middle">KIAS</text> <text x={120} y={78} fontSize="14" fill="#9aa6ad" textAnchor="middle">KIAS</text>
{/* AOA index (#manual p22) */} {/* AOA index (#manual p22) */}
<g transform="translate(48 600)"><AoaIndex alpha={aoa} /></g> <g transform="translate(48 600)"><AoaIndex alpha={aoa} /></g>
@@ -308,7 +327,7 @@ export default function CitPFD({ xp }) {
{/* VSI (#13,#14) */} {/* VSI (#13,#14) */}
<g transform="translate(716 130)"><VSI vs={vs} /></g> <g transform="translate(716 130)"><VSI vs={vs} /></g>
{/* HSI (#10) */} {/* HSI (#10) */}
<g transform="translate(400 690)"><HSI hdg={hdg} trk={trk} crs={crs} hdgBug={hdgBug} cdi={cdi} toFrom={toFrom} brg1={brg1} brg2={brg2} srcLabel={srcLabel} /></g> <g transform="translate(400 690)"><HSI hdg={hdg} trk={trk} crs={crs} hdgBug={hdgBug} cdi={cdi} toFrom={toFrom} brg1={brg1} brg2={brg2} srcLabel={srcLabel} srcColor={srcColor} /></g>
{/* CRS / HDG digital (#5,#7) */} {/* CRS / HDG digital (#5,#7) */}
<g fontSize="15" fontWeight="700"> <g fontSize="15" fontWeight="700">
@@ -334,8 +353,14 @@ export default function CitPFD({ xp }) {
<text x={760} y={84} fontSize="13" fill="#9aa6ad" textAnchor="end">FT</text> <text x={760} y={84} fontSize="13" fill="#9aa6ad" textAnchor="end">FT</text>
</svg> </svg>
{/* bezel buttons — MINIMUMS rotary (#8), RA/BARO (#9), STD (#11), BARO SET (#12) */} {/* bezel buttons — Nav Source Selector (p24, sits under the PFD), MINIMUMS
rotary (#8), RA/BARO (#9), STD (#11), BARO SET (#12), CRS, HDG */}
<div className="cit-bezel"> <div className="cit-bezel">
<div className="cit-bz-group">
<span className="cit-bz-lbl">NAV SRC</span>
<button className={`cit-bz-btn ${cdiSrc !== 2 ? 'on' : ''}`} onClick={cycleNav}>{cdiSrc === 1 ? 'VOR2' : 'VOR1'}</button>
<button className={`cit-bz-btn ${cdiSrc === 2 ? 'on' : ''}`} onClick={setFms}>FMS</button>
</div>
<div className="cit-bz-group"> <div className="cit-bz-group">
<span className="cit-bz-lbl">MINIMUMS</span> <span className="cit-bz-lbl">MINIMUMS</span>
<button className="cit-bz-knob" onClick={() => setMin((m) => ({ ...m, on: true, ft: m.ft - 50 }))}></button> <button className="cit-bz-knob" onClick={() => setMin((m) => ({ ...m, on: true, ft: m.ft - 50 }))}></button>