The published artifact source now lives in docs/, and pack-dist emits it as CONTROLS.html beside the plain-text CONTROLS.txt so players get the diagrams without the repo. The artifact source is a fragment - the publisher supplies the document shell - so it is wrapped here with a doctype, charset and viewport. Without those a browser opens it in quirks mode and renders the typography as mojibake. Written without a BOM so the charset declaration is the only thing speaking. The map itself gains a section for the mouse: the button banks reach under the glass, and the six displays are the players to size and the radar to place. Verified the five radar-placement diagrams against the layout they describe - box 16:9, radar 16.7x39.3% of it, centred flush to the bottom edge, flush in either bottom corner, and 30/30 vertically when halfway up a side. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1525 lines
83 KiB
HTML
1525 lines
83 KiB
HTML
<title>Red Planet 4.12.3 — Controls</title>
|
||
|
||
<style>
|
||
:root {
|
||
--void: #05070a;
|
||
--void-2: #080d10;
|
||
--glass: #0a1410;
|
||
--glass-edge: #16261d;
|
||
--phosphor: #40ff40;
|
||
--phosphor-2: #8dffa0;
|
||
--dim: #189418;
|
||
--hazard: #b0302a;
|
||
--hazard-lit: #ff5a48;
|
||
--amber: #c8a32e;
|
||
--amber-lit: #ffd25e;
|
||
--rust: #8a3a1e;
|
||
--ink: #b9cfc0;
|
||
--ink-quiet: #6d8478;
|
||
|
||
--mono: "Cascadia Mono", Consolas, "SF Mono", ui-monospace, Menlo, monospace;
|
||
--sans: system-ui, -apple-system, "Segoe UI Variable Text", "Segoe UI", Roboto, sans-serif;
|
||
|
||
--u: 42px; /* keycap unit */
|
||
--gap: 5px;
|
||
}
|
||
|
||
* { box-sizing: border-box; }
|
||
|
||
body {
|
||
margin: 0;
|
||
background:
|
||
radial-gradient(120% 90% at 50% -10%, #0d1a14 0%, transparent 60%),
|
||
var(--void);
|
||
color: var(--ink);
|
||
font-family: var(--sans);
|
||
line-height: 1.65;
|
||
-webkit-font-smoothing: antialiased;
|
||
}
|
||
|
||
/* faint CRT vignette, no animation */
|
||
body::after {
|
||
content: "";
|
||
position: fixed;
|
||
inset: 0;
|
||
pointer-events: none;
|
||
background: radial-gradient(130% 100% at 50% 45%, transparent 55%, rgba(0,0,0,.55) 100%);
|
||
z-index: 5;
|
||
}
|
||
|
||
.wrap {
|
||
max-width: 1180px;
|
||
margin: 0 auto;
|
||
padding: clamp(28px, 5vw, 64px) clamp(16px, 4vw, 40px) 80px;
|
||
position: relative;
|
||
z-index: 1;
|
||
}
|
||
|
||
/* ---------- masthead ---------- */
|
||
|
||
.masthead { border-bottom: 1px solid var(--glass-edge); padding-bottom: 28px; }
|
||
|
||
.eyebrow {
|
||
font-family: var(--mono);
|
||
font-size: .72rem;
|
||
letter-spacing: .28em;
|
||
text-transform: uppercase;
|
||
color: var(--dim);
|
||
margin: 0 0 14px;
|
||
}
|
||
|
||
h1 {
|
||
font-family: var(--mono);
|
||
font-size: clamp(1.9rem, 5.2vw, 3.1rem);
|
||
line-height: 1.05;
|
||
letter-spacing: .04em;
|
||
text-transform: uppercase;
|
||
color: var(--phosphor);
|
||
text-shadow: 0 0 22px rgba(64,255,64,.28);
|
||
margin: 0 0 18px;
|
||
text-wrap: balance;
|
||
}
|
||
|
||
.lede { max-width: 62ch; margin: 0; color: var(--ink); }
|
||
.lede code { font-family: var(--mono); color: var(--phosphor-2); font-size: .92em; }
|
||
|
||
.provenance {
|
||
margin: 18px 0 0;
|
||
font-family: var(--mono);
|
||
font-size: .74rem;
|
||
letter-spacing: .08em;
|
||
color: var(--ink-quiet);
|
||
}
|
||
|
||
/* ---------- at-a-glance ---------- */
|
||
|
||
.glance {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
|
||
gap: 1px;
|
||
background: var(--glass-edge);
|
||
border: 1px solid var(--glass-edge);
|
||
margin: 34px 0 0;
|
||
}
|
||
|
||
.glance div { background: var(--void-2); padding: 16px 18px; }
|
||
|
||
.glance dt {
|
||
font-family: var(--mono);
|
||
font-size: .68rem;
|
||
letter-spacing: .2em;
|
||
text-transform: uppercase;
|
||
color: var(--ink-quiet);
|
||
margin: 0 0 6px;
|
||
}
|
||
|
||
.glance dd {
|
||
margin: 0;
|
||
font-family: var(--mono);
|
||
font-size: 1.02rem;
|
||
color: var(--phosphor);
|
||
}
|
||
|
||
.glance dd small { display: block; font-family: var(--sans); font-size: .78rem; color: var(--ink-quiet); letter-spacing: 0; margin-top: 3px; }
|
||
|
||
/* ---------- sections ---------- */
|
||
|
||
section { margin-top: 64px; }
|
||
|
||
h2 {
|
||
font-family: var(--mono);
|
||
font-size: .82rem;
|
||
letter-spacing: .3em;
|
||
text-transform: uppercase;
|
||
color: var(--phosphor);
|
||
margin: 0 0 6px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 14px;
|
||
}
|
||
|
||
h2::after {
|
||
content: "";
|
||
flex: 1;
|
||
height: 1px;
|
||
background: linear-gradient(90deg, var(--glass-edge), transparent);
|
||
}
|
||
|
||
.sub { margin: 0 0 26px; max-width: 60ch; color: var(--ink-quiet); font-size: .93rem; }
|
||
|
||
/* ---------- panel frame ---------- */
|
||
|
||
.panel {
|
||
background:
|
||
linear-gradient(180deg, rgba(64,255,64,.03), transparent 40%),
|
||
var(--glass);
|
||
border: 1px solid var(--glass-edge);
|
||
padding: clamp(16px, 3vw, 30px);
|
||
overflow-x: auto;
|
||
}
|
||
|
||
/* ---------- readout ---------- */
|
||
|
||
.readout {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
align-items: baseline;
|
||
gap: 8px 22px;
|
||
border: 1px solid var(--glass-edge);
|
||
border-top: none;
|
||
background: var(--void-2);
|
||
padding: 13px clamp(16px, 3vw, 30px);
|
||
font-family: var(--mono);
|
||
min-height: 54px;
|
||
}
|
||
|
||
.readout .rd-name { color: var(--phosphor); font-size: 1rem; letter-spacing: .04em; }
|
||
.readout .rd-addr {
|
||
color: var(--amber-lit);
|
||
font-size: .82rem;
|
||
border: 1px solid rgba(200,163,46,.35);
|
||
padding: 1px 8px;
|
||
}
|
||
.readout .rd-desc { color: var(--ink-quiet); font-size: .85rem; font-family: var(--sans); }
|
||
.readout[data-idle="true"] .rd-name { color: var(--ink-quiet); }
|
||
|
||
/* ---------- keyboard ---------- */
|
||
|
||
.kb { display: flex; flex-direction: column; gap: 14px; min-width: 940px; position: relative; padding-top: 22px; }
|
||
|
||
/* cluster outlines drawn over the keys after layout */
|
||
.kb-groups { position: absolute; inset: 0; pointer-events: none; }
|
||
.kb-groups svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
|
||
.kb-groups path { fill: none; stroke-width: 1; opacity: .85; }
|
||
.kb-groups path.g-mfd { stroke: #ff9a8c; }
|
||
.kb-groups path.g-col { stroke: var(--amber-lit); }
|
||
.kb-groups path.g-fly { stroke: var(--phosphor); }
|
||
|
||
.kb-groups .g-label {
|
||
position: absolute;
|
||
transform: translate(0, -100%);
|
||
font-family: var(--mono);
|
||
font-size: .56rem;
|
||
letter-spacing: .16em;
|
||
text-transform: uppercase;
|
||
white-space: nowrap;
|
||
padding-bottom: 3px;
|
||
}
|
||
|
||
.kb-groups .g-label.g-mfd { color: #ff9a8c; }
|
||
.kb-groups .g-label.g-col { color: var(--amber-lit); }
|
||
.kb-groups .g-label.g-fly { color: var(--phosphor); }
|
||
.kb-bank { display: flex; gap: 22px; }
|
||
.kb-main { display: flex; flex-direction: column; gap: var(--gap); }
|
||
.kb-row { display: flex; gap: var(--gap); }
|
||
/* room above the rows that start an MFD zone, for its label */
|
||
.kb-row.zone { margin-top: 18px; }
|
||
.kb-side { display: flex; flex-direction: column; gap: var(--gap); justify-content: flex-end; }
|
||
/* nav column: block sits with the number rows, arrows drop to the bottom */
|
||
.kb-nav {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: var(--gap);
|
||
align-items: center;
|
||
padding-top: calc(var(--u) + var(--gap));
|
||
height: 100%;
|
||
}
|
||
.kb-nav .grow { flex: 1 1 auto; min-height: var(--gap); }
|
||
.kb-pad { display: grid; grid-template-columns: repeat(4, var(--u)); gap: var(--gap); }
|
||
|
||
.key {
|
||
width: var(--u);
|
||
height: var(--u);
|
||
flex: none;
|
||
border: 1px solid #1d2b24;
|
||
border-bottom-color: #0c1512;
|
||
background: linear-gradient(180deg, #101a16, #0b120f);
|
||
color: #4e6a5c;
|
||
font-family: var(--mono);
|
||
font-size: .72rem;
|
||
line-height: 1.1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 2px;
|
||
padding: 2px;
|
||
cursor: default;
|
||
transition: transform .08s ease, box-shadow .12s ease, border-color .12s ease;
|
||
}
|
||
|
||
.key span.k-sub {
|
||
font-size: .53rem;
|
||
letter-spacing: .04em;
|
||
text-transform: uppercase;
|
||
opacity: .85;
|
||
}
|
||
|
||
.key[data-role] { cursor: pointer; }
|
||
.key:focus-visible { outline: 2px solid var(--phosphor); outline-offset: 2px; }
|
||
|
||
.key[data-role="flight"] {
|
||
color: var(--phosphor);
|
||
border-color: #2c6b38;
|
||
background: linear-gradient(180deg, #10281a, #0a1a11);
|
||
}
|
||
.key[data-role="mfd"] {
|
||
color: #ff9a8c;
|
||
border-color: #6b2723;
|
||
background: linear-gradient(180deg, #2a100e, #1a0a09);
|
||
}
|
||
.key[data-role="column"] {
|
||
color: var(--amber-lit);
|
||
border-color: #6d5a1c;
|
||
background: linear-gradient(180deg, #251d08, #171205);
|
||
}
|
||
.key[data-role="abort"] {
|
||
color: #fff;
|
||
border-color: #8a2f2a;
|
||
background: linear-gradient(180deg, #3a1210, #220a09);
|
||
}
|
||
|
||
.key[data-role]:hover,
|
||
.key.is-active {
|
||
transform: translateY(-1px);
|
||
border-color: currentColor;
|
||
box-shadow: 0 0 0 1px currentColor, 0 0 18px -4px currentColor;
|
||
}
|
||
|
||
.key.w125 { width: calc(var(--u) * 1.25 + var(--gap) * .25); }
|
||
.key.w15 { width: calc(var(--u) * 1.5 + var(--gap) * .5); }
|
||
.key.w175 { width: calc(var(--u) * 1.75 + var(--gap) * .75); }
|
||
.key.w2 { width: calc(var(--u) * 2 + var(--gap)); }
|
||
.key.w225 { width: calc(var(--u) * 2.25 + var(--gap) * 1.25); }
|
||
.key.w275 { width: calc(var(--u) * 2.75 + var(--gap) * 1.75); }
|
||
.key.w6 { width: calc(var(--u) * 6.25 + var(--gap) * 5.25); }
|
||
|
||
/* numpad: the tall +/Enter keys own two rows, 0 owns two columns */
|
||
.key.tall { grid-row: span 2; height: calc(var(--u) * 2 + var(--gap)); }
|
||
.key.pad0 { grid-column: span 2; width: calc(var(--u) * 2 + var(--gap)); }
|
||
|
||
.spacer { width: calc(var(--u) * .5); flex: none; }
|
||
|
||
/* ---------- legend ---------- */
|
||
|
||
.legend {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 10px 26px;
|
||
margin-top: 20px;
|
||
font-family: var(--mono);
|
||
font-size: .74rem;
|
||
letter-spacing: .06em;
|
||
}
|
||
|
||
.legend span { display: flex; align-items: center; gap: 8px; color: var(--ink-quiet); }
|
||
.legend i { width: 13px; height: 13px; border: 1px solid; display: block; }
|
||
.lg-flight { color: var(--phosphor); border-color: currentColor; background: #10281a; }
|
||
.lg-mfd { color: #ff9a8c; border-color: currentColor; background: #2a100e; }
|
||
.lg-col { color: var(--amber-lit); border-color: currentColor; background: #251d08; }
|
||
.lg-off { color: #4e6a5c; border-color: #1d2b24; background: #101a16; }
|
||
|
||
/* ---------- pad ---------- */
|
||
|
||
.pad-shell { display: flex; justify-content: center; }
|
||
svg.pad { width: 100%; max-width: 720px; height: auto; }
|
||
svg.pad .body { fill: #0c1512; stroke: #1f3329; stroke-width: 2; }
|
||
svg.pad .ctl { fill: #12211a; stroke: #2c6b38; stroke-width: 1.6; cursor: pointer; transition: fill .12s ease, stroke .12s ease; }
|
||
svg.pad .ctl:hover, svg.pad .ctl.is-active { fill: #1a3b26; stroke: var(--phosphor); }
|
||
svg.pad .lbl { font-family: var(--mono); font-size: 11px; fill: var(--phosphor); letter-spacing: .06em; pointer-events: none; }
|
||
svg.pad .lbl-q { font-family: var(--mono); font-size: 10px; fill: var(--ink-quiet); letter-spacing: .08em; pointer-events: none; text-transform: uppercase; }
|
||
svg.pad .lead { stroke: #244a33; stroke-width: 1; fill: none; }
|
||
svg.pad .cap { font-family: var(--mono); font-size: 11px; fill: #cfe8d8; pointer-events: none; }
|
||
|
||
/* ---------- pod stick ---------- */
|
||
|
||
.stick-wrap {
|
||
display: grid;
|
||
grid-template-columns: minmax(230px, 300px) 1fr;
|
||
gap: 22px;
|
||
align-items: start;
|
||
}
|
||
|
||
.mfd-tile {
|
||
margin: 0;
|
||
border: 1px solid var(--glass-edge);
|
||
background: #040806;
|
||
padding: 0 0 14px;
|
||
}
|
||
|
||
.mfd-tile figcaption {
|
||
font-family: var(--mono);
|
||
font-size: .78rem;
|
||
letter-spacing: .22em;
|
||
text-transform: uppercase;
|
||
color: var(--phosphor);
|
||
text-align: center;
|
||
padding: 14px 10px 6px;
|
||
text-shadow: 0 0 14px rgba(64,255,64,.35);
|
||
}
|
||
|
||
svg.stick { width: 100%; height: auto; display: block; }
|
||
.stick-hidden { display: none; }
|
||
|
||
/* the cockpit's own trigger-status plate, with hotspots on its circles */
|
||
.stick-art { position: relative; padding: 4px 10px 10px; }
|
||
.stick-art img {
|
||
width: 100%;
|
||
height: auto;
|
||
display: block;
|
||
filter: drop-shadow(0 0 10px rgba(64,255,64,.25));
|
||
}
|
||
|
||
.stick-art .hot {
|
||
position: absolute;
|
||
left: var(--cx);
|
||
top: var(--cy);
|
||
width: 21%;
|
||
aspect-ratio: 1;
|
||
transform: translate(-50%, -50%);
|
||
border-radius: 50%;
|
||
border: 1px solid transparent;
|
||
background: transparent;
|
||
padding: 0;
|
||
cursor: pointer;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
transition: background .12s ease, border-color .12s ease;
|
||
}
|
||
|
||
.stick-art .hot span {
|
||
font-family: var(--mono);
|
||
font-size: .58rem;
|
||
letter-spacing: .06em;
|
||
text-transform: uppercase;
|
||
color: transparent;
|
||
transition: color .12s ease;
|
||
}
|
||
|
||
.stick-art .hot:hover,
|
||
.stick-art .hot:focus-visible,
|
||
.stick-art .hot.is-active {
|
||
background: rgba(64,255,64,.22);
|
||
border-color: var(--phosphor);
|
||
outline: none;
|
||
}
|
||
|
||
.stick-art .hot:hover span,
|
||
.stick-art .hot:focus-visible span,
|
||
.stick-art .hot.is-active span { color: #eafff0; }
|
||
|
||
/* the pod's own instruction plates */
|
||
.axis-art {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
||
gap: 18px;
|
||
margin-top: 22px;
|
||
}
|
||
|
||
.art-tile {
|
||
margin: 0;
|
||
border: 1px solid var(--glass-edge);
|
||
background:
|
||
radial-gradient(120% 90% at 50% 0%, rgba(64,255,64,.05), transparent 60%),
|
||
#040806;
|
||
padding: 18px 18px 16px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 12px;
|
||
}
|
||
|
||
.art-tile img {
|
||
width: 100%;
|
||
height: auto;
|
||
display: block;
|
||
filter: drop-shadow(0 0 12px rgba(64,255,64,.25));
|
||
}
|
||
|
||
.art-tile figcaption { font-size: .87rem; color: var(--ink-quiet); }
|
||
.art-tile figcaption em {
|
||
display: block;
|
||
font-style: normal;
|
||
font-family: var(--mono);
|
||
font-size: .74rem;
|
||
letter-spacing: .2em;
|
||
text-transform: uppercase;
|
||
color: var(--phosphor);
|
||
margin-bottom: 5px;
|
||
}
|
||
.art-tile figcaption b { font-family: var(--mono); font-weight: 400; color: var(--phosphor-2); }
|
||
|
||
.art-credit { margin: 12px 0 0; font-size: .78rem; color: var(--ink-quiet); font-style: italic; }
|
||
|
||
.stick-key table { min-width: 0; }
|
||
.stick-key th { color: var(--phosphor); font-family: var(--mono); font-size: .8rem; letter-spacing: .06em; text-transform: none; }
|
||
.stick-key table { border: 1px solid var(--glass-edge); }
|
||
.stick-note { margin: 14px 0 0; font-size: .86rem; color: var(--ink-quiet); max-width: 46ch; }
|
||
|
||
/* ---------- cockpit map ---------- */
|
||
|
||
.cockpit {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, 1fr);
|
||
gap: 16px;
|
||
min-width: 720px;
|
||
}
|
||
|
||
.mfd {
|
||
border: 1px solid var(--glass-edge);
|
||
background: #060c09;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.mfd-strip {
|
||
display: flex;
|
||
gap: 2px;
|
||
padding: 3px;
|
||
background: #150a09;
|
||
}
|
||
|
||
.mfd-strip b {
|
||
flex: 1;
|
||
background: linear-gradient(180deg, #b0302a, #7d211d);
|
||
color: #ffd9d3;
|
||
font-family: var(--mono);
|
||
font-size: .62rem;
|
||
font-weight: 400;
|
||
text-align: center;
|
||
padding: 4px 0;
|
||
letter-spacing: .04em;
|
||
}
|
||
|
||
.mfd-strip.amber b { background: linear-gradient(180deg, #c8a32e, #8d711b); color: #2a2205; }
|
||
|
||
.mfd-face {
|
||
padding: 14px 12px;
|
||
text-align: center;
|
||
font-family: var(--mono);
|
||
}
|
||
|
||
.mfd-face em { display: block; font-style: normal; color: var(--phosphor); font-size: .8rem; letter-spacing: .12em; text-transform: uppercase; }
|
||
.mfd-face small { display: block; color: var(--ink-quiet); font-size: .68rem; margin-top: 5px; letter-spacing: .06em; }
|
||
|
||
.mfd.wide { grid-column: span 3; }
|
||
.cockpit-note { grid-column: span 3; margin: 2px 0 0; font-size: .82rem; color: var(--ink-quiet); }
|
||
|
||
/* the map is portrait, flanked by six amber buttons a side */
|
||
.cockpit { align-items: start; }
|
||
.mfd-map { min-height: 300px; }
|
||
.map-body { display: flex; align-items: stretch; flex: 1; }
|
||
|
||
.map-col {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 2px;
|
||
padding: 3px;
|
||
background: #150a09;
|
||
}
|
||
|
||
.map-col b {
|
||
flex: 1;
|
||
min-height: 26px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
background: linear-gradient(90deg, #c8a32e, #8d711b);
|
||
color: #2a2205;
|
||
font-family: var(--mono);
|
||
font-size: .62rem;
|
||
font-weight: 400;
|
||
letter-spacing: .04em;
|
||
padding: 0 7px;
|
||
}
|
||
|
||
.map-face {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 6px;
|
||
padding: 14px 8px;
|
||
font-family: var(--mono);
|
||
text-align: center;
|
||
background:
|
||
repeating-linear-gradient(0deg, rgba(64,255,64,.05) 0 1px, transparent 1px 22px),
|
||
#060c09;
|
||
}
|
||
|
||
.map-face em { font-style: normal; color: var(--phosphor); font-size: .8rem; letter-spacing: .12em; text-transform: uppercase; }
|
||
.map-face small { color: var(--ink-quiet); font-size: .66rem; letter-spacing: .06em; line-height: 1.5; }
|
||
|
||
/* ---------- tables ---------- */
|
||
|
||
.tbl-scroll { overflow-x: auto; border: 1px solid var(--glass-edge); }
|
||
table { width: 100%; border-collapse: collapse; font-size: .87rem; min-width: 480px; }
|
||
caption { text-align: left; font-family: var(--mono); font-size: .7rem; letter-spacing: .2em; text-transform: uppercase; color: var(--ink-quiet); padding: 12px 14px; background: var(--void-2); }
|
||
th, td { text-align: left; padding: 9px 14px; border-top: 1px solid var(--glass-edge); }
|
||
th { font-family: var(--mono); font-size: .68rem; letter-spacing: .16em; text-transform: uppercase; color: var(--ink-quiet); font-weight: 400; }
|
||
td.mono { font-family: var(--mono); color: var(--phosphor); white-space: nowrap; }
|
||
td.addr { font-family: var(--mono); color: var(--amber-lit); font-variant-numeric: tabular-nums; white-space: nowrap; }
|
||
tbody tr:hover td { background: rgba(64,255,64,.035); }
|
||
|
||
/* ---------- rebind ---------- */
|
||
|
||
pre {
|
||
margin: 0;
|
||
padding: 18px clamp(14px, 3vw, 24px);
|
||
background: var(--void-2);
|
||
border: 1px solid var(--glass-edge);
|
||
overflow-x: auto;
|
||
font-family: var(--mono);
|
||
font-size: .82rem;
|
||
line-height: 1.7;
|
||
color: var(--ink);
|
||
}
|
||
|
||
pre b { color: var(--phosphor); font-weight: 400; }
|
||
pre i { color: var(--ink-quiet); font-style: normal; }
|
||
|
||
.two-col { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 22px; }
|
||
|
||
.callout {
|
||
border-left: 2px solid var(--hazard);
|
||
background: linear-gradient(90deg, rgba(176,48,42,.12), transparent 70%);
|
||
padding: 14px 18px;
|
||
margin-top: 26px;
|
||
}
|
||
|
||
.callout p { margin: 0; font-size: .9rem; }
|
||
.callout strong { font-family: var(--mono); color: var(--hazard-lit); letter-spacing: .04em; }
|
||
|
||
footer {
|
||
margin-top: 72px;
|
||
padding-top: 22px;
|
||
border-top: 1px solid var(--glass-edge);
|
||
font-family: var(--mono);
|
||
font-size: .74rem;
|
||
letter-spacing: .06em;
|
||
color: var(--ink-quiet);
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 8px 24px;
|
||
}
|
||
|
||
/* ---------- the mouse: button reach + display layout ---------- */
|
||
|
||
h3 {
|
||
font-family: var(--mono);
|
||
font-size: .78rem;
|
||
font-weight: 400;
|
||
letter-spacing: .2em;
|
||
text-transform: uppercase;
|
||
color: var(--phosphor);
|
||
margin: 46px 0 8px;
|
||
}
|
||
|
||
.reach { display: flex; justify-content: center; }
|
||
|
||
.reach-fig { margin: 0; width: min(430px, 100%); }
|
||
|
||
.reach-glass {
|
||
position: relative;
|
||
aspect-ratio: 4 / 3;
|
||
background: var(--glass);
|
||
border: 1px solid var(--glass-edge);
|
||
overflow: hidden;
|
||
}
|
||
|
||
/* the press region: half the glass, top and bottom */
|
||
.reach-band {
|
||
position: absolute;
|
||
left: 0;
|
||
right: 0;
|
||
height: 50%;
|
||
background: repeating-linear-gradient(-45deg,
|
||
rgba(176,48,42,.16) 0 5px, transparent 5px 11px);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-family: var(--mono);
|
||
font-size: .66rem;
|
||
letter-spacing: .14em;
|
||
text-transform: uppercase;
|
||
color: #e08a7e;
|
||
}
|
||
.reach-band.is-top { top: 0; border-bottom: 1px dashed rgba(176,48,42,.6); }
|
||
.reach-band.is-bot { bottom: 0; }
|
||
|
||
/* the lamp strip, all that shows outside the glass */
|
||
.reach-strip {
|
||
position: absolute;
|
||
left: 0;
|
||
right: 0;
|
||
height: 8px;
|
||
display: flex;
|
||
gap: 2px;
|
||
z-index: 2;
|
||
}
|
||
.reach-strip.is-top { top: 0; }
|
||
.reach-strip.is-bot { bottom: 0; }
|
||
.reach-strip i { flex: 1; background: var(--hazard); display: block; }
|
||
.reach-strip.is-lit i:nth-child(2) { background: var(--hazard-lit); }
|
||
|
||
.reach-fig figcaption {
|
||
margin-top: 12px;
|
||
font-size: .84rem;
|
||
color: var(--ink-quiet);
|
||
}
|
||
.reach-fig figcaption b {
|
||
font-family: var(--mono);
|
||
font-weight: 400;
|
||
color: var(--phosphor-2);
|
||
}
|
||
|
||
/* ---------- radar placement thumbnails ---------- */
|
||
|
||
.pos-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(148px, 1fr));
|
||
gap: 18px;
|
||
}
|
||
|
||
.pos { margin: 0; }
|
||
|
||
.pos-box {
|
||
position: relative;
|
||
aspect-ratio: 16 / 9;
|
||
background: var(--void-2);
|
||
border: 1px solid var(--glass-edge);
|
||
}
|
||
|
||
/* sizes are the real canvas proportions: MFD 320x240, radar 324x432
|
||
of a 1920x1080 cockpit */
|
||
.pos-box i,
|
||
.pos-box u {
|
||
position: absolute;
|
||
display: block;
|
||
}
|
||
.pos-box i {
|
||
width: 16.7%;
|
||
height: 22.2%;
|
||
background: #2a100e;
|
||
border: 1px solid #7d3029;
|
||
}
|
||
.pos-box u {
|
||
width: 16.9%;
|
||
height: 40%;
|
||
background: #251d08;
|
||
border: 1px solid var(--amber);
|
||
}
|
||
|
||
.pos-box i.ul { left: 0; top: 0; }
|
||
.pos-box i.uc { left: 41.65%; top: 0; }
|
||
.pos-box i.ur { right: 0; top: 0; }
|
||
.pos-box i.ll { left: 0; bottom: 0; }
|
||
.pos-box i.lr { right: 0; bottom: 0; }
|
||
|
||
/* centred on the bottom edge, as the pod had it */
|
||
.pos-box u { left: 41.55%; bottom: 0; }
|
||
|
||
/* in a bottom corner the lower MFD beside it slides inboard */
|
||
.p-left u { left: 0; bottom: 0; }
|
||
.p-left i.ll { left: 16.9%; }
|
||
.p-right u { left: auto; right: 0; bottom: 0; }
|
||
.p-right i.lr { right: 16.9%; }
|
||
|
||
/* halfway up a side it leaves the bottom row alone */
|
||
.p-midleft u { left: 0; bottom: auto; top: 30%; }
|
||
.p-midright u { left: auto; right: 0; bottom: auto; top: 30%; }
|
||
|
||
.pos figcaption {
|
||
margin-top: 9px;
|
||
font-family: var(--mono);
|
||
font-size: .72rem;
|
||
letter-spacing: .12em;
|
||
color: var(--phosphor);
|
||
}
|
||
.pos figcaption small {
|
||
display: block;
|
||
font-family: var(--sans);
|
||
font-size: .76rem;
|
||
letter-spacing: 0;
|
||
color: var(--ink-quiet);
|
||
margin-top: 2px;
|
||
}
|
||
|
||
@media (prefers-reduced-motion: reduce) {
|
||
* { transition: none !important; }
|
||
}
|
||
</style>
|
||
|
||
<div class="wrap">
|
||
|
||
<header class="masthead">
|
||
<p class="eyebrow">Virtual World Entertainment · Tesla pod · RP 4.12.3</p>
|
||
<h1>Red Planet<br>Controls Map</h1>
|
||
<p class="lede">
|
||
Every input the pod answers to, on the gamepad and the keyboard. The
|
||
keyboard is the pod's button board: the letter and number rows are the
|
||
MFD banks laid out as they are printed on the panel, and flight moved to
|
||
the number pad so the board stays free.
|
||
</p>
|
||
<p class="provenance">Generated from the default <code>bindings.txt</code> · all of it rebindable</p>
|
||
</header>
|
||
|
||
<dl class="glance">
|
||
<div>
|
||
<dt>Fly</dt>
|
||
<dd>Num 8 2 4 6<small>stick · 7/9 pedals · 0 fires</small></dd>
|
||
</div>
|
||
<div>
|
||
<dt>Throttle</dt>
|
||
<dd>Shift / Ctrl<small>walks up or down, holds where you leave it</small></dd>
|
||
</div>
|
||
<div>
|
||
<dt>Reverse</dt>
|
||
<dd>Alt<small>the throttle button on the pod stick</small></dd>
|
||
</div>
|
||
<div>
|
||
<dt>Abort</dt>
|
||
<dd>Alt + Q<small>ends your mission, score banked</small></dd>
|
||
</div>
|
||
</dl>
|
||
|
||
|
||
|
||
<section>
|
||
<h2>Gamepad</h2>
|
||
<p class="sub">An Xbox-compatible pad drives all five axes and the grip buttons. Hover or tap a control for its RIO address.</p>
|
||
|
||
<div class="panel pad-shell">
|
||
<svg class="pad" viewBox="0 0 700 400" role="img" aria-label="Xbox controller diagram with Red Planet bindings">
|
||
<!-- shoulders -->
|
||
<rect class="ctl" data-name="LB — Panic" data-addr="0x3D" data-desc="Panic button" x="112" y="60" width="86" height="26" rx="13"></rect>
|
||
<rect class="ctl" data-name="RB — Reverse thrust" data-addr="0x3F" data-desc="Throttle button on the pod stick" x="502" y="60" width="86" height="26" rx="13"></rect>
|
||
<rect class="ctl" data-name="LT — Left pedal" data-addr="axis" data-desc="Left pedal, deadzone 0.12" x="132" y="26" width="66" height="24" rx="12"></rect>
|
||
<rect class="ctl" data-name="RT — Right pedal" data-addr="axis" data-desc="Right pedal, deadzone 0.12" x="502" y="26" width="66" height="24" rx="12"></rect>
|
||
<text class="lbl-q" x="132" y="20">LT · left pedal</text>
|
||
<text class="lbl-q" x="502" y="20">RT · right pedal</text>
|
||
<text class="lbl-q" x="112" y="102">LB · panic</text>
|
||
<text class="lbl-q" x="486" y="102">RB · reverse thrust</text>
|
||
|
||
<!-- body -->
|
||
<path class="body" d="M196 112 h308 c46 0 78 26 92 74 l32 108 c14 48 -10 82 -52 82 c-36 0 -58 -22 -74 -54 l-22 -44 h-180 l-22 44 c-16 32 -38 54 -74 54 c-42 0 -66 -34 -52 -82 l32 -108 c14 -48 46 -74 92 -74 z"></path>
|
||
|
||
<!-- left stick -->
|
||
<circle class="ctl" data-name="Left stick — Joystick X / Y" data-addr="axes" data-desc="Inverted, deadzone 0.24 (pod convention)" cx="248" cy="176" r="34"></circle>
|
||
<text class="cap" x="222" y="181">STICK</text>
|
||
<path class="lead" d="M214 176 H150"></path>
|
||
<text class="lbl-q" x="66" y="180">joystick X/Y</text>
|
||
|
||
<!-- dpad -->
|
||
<g class="ctl" data-name="D-pad — Hat" data-addr="0x41–0x44" data-desc="Look up, back, left, right">
|
||
<rect x="286" y="266" width="24" height="66" rx="4"></rect>
|
||
<rect x="265" y="287" width="66" height="24" rx="4"></rect>
|
||
</g>
|
||
<path class="lead" d="M265 299 H180"></path>
|
||
<text class="lbl-q" x="96" y="303">hat · look</text>
|
||
|
||
<!-- right stick -->
|
||
<circle class="ctl" data-name="Right stick Y — Throttle" data-addr="axis" data-desc="Winds the throttle up or down; position holds" cx="404" cy="266" r="32"></circle>
|
||
<text class="cap" x="381" y="271">THRTL</text>
|
||
<path class="lead" d="M436 266 H520"></path>
|
||
<text class="lbl-q" x="524" y="270">throttle (Y)</text>
|
||
|
||
<!-- face buttons -->
|
||
<circle class="ctl" data-name="Y — Upper" data-addr="0x47" data-desc="Upper stick button" cx="470" cy="146" r="20"></circle>
|
||
<circle class="ctl" data-name="X — Pinky" data-addr="0x45" data-desc="Pinky stick button" cx="428" cy="180" r="20"></circle>
|
||
<circle class="ctl" data-name="B — Middle" data-addr="0x46" data-desc="Middle stick button" cx="512" cy="180" r="20"></circle>
|
||
<circle class="ctl" data-name="A — Main trigger" data-addr="0x40" data-desc="Fires the selected tool" cx="470" cy="214" r="20"></circle>
|
||
<text class="lbl" x="465" y="151">Y</text>
|
||
<text class="lbl" x="423" y="185">X</text>
|
||
<text class="lbl" x="507" y="185">B</text>
|
||
<text class="lbl" x="465" y="219">A</text>
|
||
<path class="lead" d="M490 214 L556 236"></path>
|
||
<text class="lbl-q" x="560" y="240">A · main trigger</text>
|
||
<text class="lbl-q" x="560" y="196">Y upper · X pinky · B middle</text>
|
||
<path class="lead" d="M532 180 H556"></path>
|
||
|
||
<!-- start / back: unbound by default, free to map -->
|
||
<circle class="ctl" data-name="Back" data-addr="unbound" data-desc="Free — map it in bindings.txt" cx="316" cy="176" r="13"></circle>
|
||
<circle class="ctl" data-name="Start" data-addr="unbound" data-desc="Free — map it in bindings.txt" cx="384" cy="176" r="13"></circle>
|
||
<text class="lbl-q" x="292" y="146">unbound</text>
|
||
</svg>
|
||
</div>
|
||
<div class="readout" id="rd-pad" data-idle="true">
|
||
<span class="rd-name">Select a control</span>
|
||
<span class="rd-desc">Hover the diagram to read its binding.</span>
|
||
</div>
|
||
</section>
|
||
|
||
<section>
|
||
<h2>Keyboard</h2>
|
||
<p class="sub">
|
||
Colour is the bank each key drives: green flies the pod, red is an MFD
|
||
button bank, amber is a column beside the map. Dark keys are unbound and
|
||
free to take.
|
||
</p>
|
||
|
||
<div class="panel">
|
||
<div class="kb" id="kb"></div>
|
||
<div class="legend">
|
||
<span><i class="lg-flight"></i> flight & stick</span>
|
||
<span><i class="lg-mfd"></i> MFD button banks</span>
|
||
<span><i class="lg-col"></i> secondary / screen columns</span>
|
||
<span><i class="lg-off"></i> unbound</span>
|
||
</div>
|
||
</div>
|
||
<div class="readout" id="rd-kb" data-idle="true">
|
||
<span class="rd-name">Select a key</span>
|
||
<span class="rd-desc">Hover a key to read what it drives.</span>
|
||
</div>
|
||
|
||
<div class="callout">
|
||
<p><strong>ALT + Q</strong> aborts the mission on the spot — score banked, back to the menu or lobby. It is the only chord the engine listens for; the arrow keys are safe.</p>
|
||
</div>
|
||
</section>
|
||
|
||
<section>
|
||
<h2>Where the keys live on the panel</h2>
|
||
<p class="sub">
|
||
Each MFD carries eight buttons: a four-wide top row and a four-wide row
|
||
beneath it. The keyboard rows run left to right across the upper MFDs,
|
||
then the lower pair — the same order your hand finds them in the pod.
|
||
</p>
|
||
|
||
<div class="panel">
|
||
<div class="cockpit">
|
||
<div class="mfd">
|
||
<div class="mfd-strip"><b>1</b><b>2</b><b>3</b><b>4</b></div>
|
||
<div class="mfd-face"><em>Upper Left</em><small>0x2F – 0x2C<br>0x2B – 0x28</small></div>
|
||
<div class="mfd-strip"><b>Q</b><b>W</b><b>E</b><b>R</b></div>
|
||
</div>
|
||
<div class="mfd">
|
||
<div class="mfd-strip"><b>5</b><b>6</b><b>7</b><b>8</b></div>
|
||
<div class="mfd-face"><em>Upper Middle</em><small>0x27 – 0x24<br>0x23 – 0x20</small></div>
|
||
<div class="mfd-strip"><b>T</b><b>Y</b><b>U</b><b>I</b></div>
|
||
</div>
|
||
<div class="mfd">
|
||
<div class="mfd-strip"><b>9</b><b>0</b><b>-</b><b>=</b></div>
|
||
<div class="mfd-face"><em>Upper Right</em><small>0x37 – 0x34<br>0x33 – 0x30</small></div>
|
||
<div class="mfd-strip"><b>O</b><b>P</b><b>[</b><b>]</b></div>
|
||
</div>
|
||
|
||
<div class="mfd">
|
||
<div class="mfd-strip"><b>A</b><b>S</b><b>D</b><b>F</b></div>
|
||
<div class="mfd-face"><em>Lower Left</em><small>0x0F – 0x0C<br>0x0B – 0x08</small></div>
|
||
<div class="mfd-strip"><b>Z</b><b>X</b><b>C</b><b>V</b></div>
|
||
</div>
|
||
<div class="mfd mfd-map">
|
||
<div class="map-body">
|
||
<div class="map-col">
|
||
<b>F1</b><b>F2</b><b>F3</b><b>F4</b><b>F5</b><b>F6</b>
|
||
</div>
|
||
<div class="map-face">
|
||
<em>Map · radar</em>
|
||
<small>
|
||
Secondary 0x10 – 0x15<br>
|
||
Screen 0x18 – 0x1D
|
||
</small>
|
||
</div>
|
||
<div class="map-col">
|
||
<b>F7</b><b>F8</b><b>F9</b><b>F10</b><b>F11</b><b>F12</b>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="mfd">
|
||
<div class="mfd-strip"><b>H</b><b>J</b><b>K</b><b>L</b></div>
|
||
<div class="mfd-face"><em>Lower Right</em><small>0x07 – 0x04<br>0x03 – 0x00</small></div>
|
||
<div class="mfd-strip"><b>N</b><b>M</b><b>,</b><b>.</b></div>
|
||
</div>
|
||
|
||
<p class="cockpit-note">
|
||
G and B stay unbound on purpose: they are the physical gap between the
|
||
lower clusters. Every button here is also a mouse target on screen —
|
||
see <em style="font-style:normal;color:var(--phosphor)">The mouse</em>
|
||
below — and lights when the game commands its lamp.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
|
||
<section>
|
||
<h2>The pod stick</h2>
|
||
<p class="sub">
|
||
What the gamepad stands in for. This is the cockpit's own TRIGGER STATUS
|
||
readout — four buttons on the grip, drawn the way the upper-right MFD
|
||
draws them. Hover one for its address and its stand-ins.
|
||
</p>
|
||
|
||
<div class="stick-wrap">
|
||
<figure class="mfd-tile">
|
||
<figcaption>Trigger Status</figcaption>
|
||
<div class="stick-art">
|
||
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANwAAAEKCAYAAAB5SjsHAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAsrSURBVHhe7dULjhypEoXh2v+mLC/A8l5mA3dUHtE3+zgp3nAg/09C2J08gswg6vUCAAAAAAAAAAAAxP9e/1T1AAD401+v3B4AgD70F6a1V/q8tgcAPI3+EozqY3RcbLw+r+0BAKfRSp/qY1LjUs9jdF5svj4v7YFb7wRJNQAN9EKVtOD369fXWp/6UqXzdXzvefo81QNf3knRo/14/dSlAQR6Ya4th87R1kNYp3Y9nZ+7jo6PzdPnqR4PFS7FtbXQtVrXA44x8mL0WjvMbVnjStfLXVfHx+bp81SPhwgXYfSHn7UPYGv2JajZb9Yvge6T2k/Hxcbr81iPw9Ukfw+r9gWWWZ30OfvrL8CnsT3pfql9dVxsvD7XHofKSfYZXOIAhnJJ9Fgcscqv/x9N40jtr+Ni4/V5bBwOEEvyVdziAbpyS/BrPKmKH/t7SmrdFJ2fWkfHxcbH/o5DaGK7cI0LaOKa2L3iis3XX5rYuFy56+i41Hgcpldi9+YaF1DNPal7xJf6JdHnsXG5ctfRcanxOECPhB7JPT4g6VpR3RNaY8xtusa1V/pc+1q56+SOwwFiSeriGl9pA5YKSXjt3RNUYyxp1zXueqXPY+NKpdZLPcdB7hLUyTW+0gYsEZLvLgndE1QvUW7TNT71s8T21f/jYLEkdeEeH/AlVlGv3BO6Z3z6PmL9aLrfrH1homdS9+QaF/BNaeV0TeySuHLGKH1PsX6UWfvATEliz+QaF/BHS8V0S+6aeErGrtTynXCImgQfyS0e4EuviumS5K1x1M4bRb+P9nio1kTvpVccrfOBb0ZUyl7JXmvE/j3XKqHfR3vgjxFJn2P0vqPWxeG0Uo5IpNHJr2bup+9tdB/E/g788U6M0EaatQ9QZWalvF6G3vuNXHsm/R56ltjfgVt6MVoTR9dqXQ8YYmWl1AtSell0Tul8R7nfI3cc8Be9LC0NsBSS0yVJ9eKUtl2F2LWPyR0HFNELddcAe24V0i2e0fS82qeUjgeA53CpkC5xzKLnLT137TwAOJ9LhXSJYxY9b+25W+cDwLlWV8jV+8+i5+x13l7rAMA5elfaUqv3n0XP2fu8vdcDgP2Nqrgpq/adRc83+pyz9gGAfcyujLP3m03PN+ucs/cDAH+zKuOsfWbTc60+n0scAOBjVGUcte5qei6X87nFg0O8EyrVAFtaGVsTttc6V3qhSlqrsIb2rnaJE4b08rQ0wFJITu1TSsd/opel9OLonNL5b3qekrkOdo0bk+kFaU0YXat1PWAIrZDax8a1GHkxUmvrOe7G7OSUc2CQT5ehp1n7AN9oBUwloI7TvsXsS3DdT88xK4ZZTj0XKmniz7JqXzycVkDtY3Rcavyd1Um/ev8ZWr4PDuKS7C5x4GG0EmqfouNT81wS3SWO0XK/Cw7kluRu8eABtAKm+hgddzfeLcHd4hnpCWfEhWtyu8aFQ+kvUm6fouNdE9s1rt70e+BwrontGhcOpxWwtI+5JnRq7Cru8fWU+92wMfeEdo8PB9LKl9PXNEfu8fUUzviEsx5FL1Juc+QeHw4Ukq2kr2mO3OMbIZz1SWfeml6k3ObIPT4cKCRbSV/THLnHN0I465PO/BjuCe0eHw6kFa9XH/7tnNDu8Y10971wANekdo0Lh9NKN6J3TGzXuGbR74RDuCa2a1w4nFa63n34t1Nyu8Wz0t33wubcEtwtHjyIVrjefeCS5C5xuIh9L2zOJdFd4sBDaYXr3V+tTvbV+zv79N2wsVVJv2pf4ButbL36T2Yn/+z9dlTy/bChWZdg1j7AR1rRWvtS14sw4kKMXPtkrd8V5vRitH5oXat1PaALrWS5fW96ObTl0Dml8/E33t0D/Hj9/OvC1DbASkjKWD9L2O/369e3v9U29BHeJe/0YfRC3TUAmaik3vguANCKXzpPfBcA6IWK6oXvAQC9UVm98D0AoDcqqwe+AwCMQoX1wHcAgN6orB74DgAwChXWA98BAHqjsnrgOxzq/UFTDUADvVAlDXPxzjeml6elAYjQy1J6cXRO6XzUC++Yd70JvSCtH07Xal0POMbIizFybfxfeLe8Y3OzLsOsfQBbsy/B7P2eiF86U6uSf9W+wDKrk371/ifjF86MS7K7xAEM5ZLoLnGcivdqwC3J3eIBunJLcLd4ThLeKe92Edfkdo0LaOKa2K5x7Y5fuMVcE9s1LqCae1K7x7cz3ukC7gntHh9QxD2hr/HltpQwJrc/1enns1SSqCvoZcptgCX3JNWLlNt0jR79aU4/n6VYkrq4xlfSAEvuSaoXKaep8Lde/SlOPZe1T4nqwD0+oIh7QveITyt5a3+aU89lq0dSj+AaF9DENbE1rtw+RseV9kqfx3p3u8R5jPcLD82Ja1xAM7fkvotHfzlSfYyOS/UxOi7Wu9slzqO8X3poDtziAbpzSfJYHLv8cuwSZ7BbvMeIJfpsLnEAw61O9k/7ayW+G3NHx6fm6bjUeFU7b5Xd4j3Op6QfadW+wHKzkz9nP63En8be0Xm5fS6dVzp/ld3iPdb7A4Q20qx9AHvXy9D7QpSurZVY+1U0Du3d7Rbv8fRitH4YXat1PeA4ekFKL4vOKZ3/FsbqnNjfR9N9Y7273eJ9FL0sLQ1AJr08pa1GmBebr89j42rputrHxrnbLd7Hu16kWAOwSG1FzZ2n40b1MbnjXOwWLwD4aq2orfNq+1y181bZLV4A8FdbWUvHz1Z7rlV2ixcA9lFaYXPHrVJ6ntV2ixcA9lFaYUvHz+YaV4z7+wSA/eVW2txxq7jGFeP+PgFgf7mVNnfcbK5xpewaNwDsI7fS5o6bzTWulF3jfqz3h0o1AA30QpU0Ff529+yT0vGj1Z5jtV3jfgS9PC0NQIReltKLo3O0hTElaueN4hZPrl3jPpZejtYPo2u1rgccY+TFaF07zKmZO4JLHKXc3uNjtVyGErP2AWzNvgQ1+7lVZpc4Srm9x8epSf4eVu0LLLM66Wv2Lxk7wu6/ELvHv62aZB/BJQ5gKJdEL41jdYVevX+r3ePfUmmSj+YWD9CVW4KXxLO6Qq/at5fV7+9xSpJ7Jte4gCauiZ0b16oKvWrf3k45xzZyE3s217iAau5JXRLf7Eo9e79RTjnHFkoSegX3+IAi7gldEt/sSj1rn9Fmv7dHK0noFdzjA4q4J3RNfCVja5z2i3DaeazVJPRM7vEBRdwTuia+0RV79PqznXYeazUJPZN7fEAR94Ruia935e69notTz2WrJalHco0LaOKa2K1x9arcvdZxdfr57LQm9iiucQHN3JK7ZzxawXPXLB2/q6ec00rPBO/BLR6gO5ckHxWHVvLc/nRPO6+NUYleyiUOYLjVyX7df3QMWtm1f4qnntvGrIRXq/YFlpud/Nf9Zu2J//ALZ2LWBZi1D2Bv5C+Prk2lXYP3bkYvReuH0bVa1wOOoxek9LLoHG1hDObj/RvTi1Lbfrx+6tIAYvQClbTg9+vX11rXHnPx/jejF+quAehML1nsomlF3bU/xannOt77g2kDMIhettiF04r6tN6Ne3yIeH8wbQAG0csWu3BPqah6ztJ+llX7opFeNj4gMJBettiFo6J+p+8j1fei6/ZeHxOkLhuASbSScinz6PvSvlavdQDgfFoxc3vU0fdY+j5r5wHA82jFzO3RRt9n6r3mjgMABFo5c3v0kXqv+jw2DgCgtHLm9ugr9l557wBQSytobo++9L3yvgGglVbS3B59xN5r7O8AgF600lJx2+h71PcZ+zsAoDetuFTePPq+Yr1KPQcA9EblvafvJdanlI4HAPT2lEqs5yztS7XOn+xfQl/05xq/h9sAAAAASUVORK5CYII=" alt="The pod joystick as the cockpit draws it, with its four grip buttons circled">
|
||
<button class="hot" type="button" style="--cx:37.7%; --cy:13.9%"
|
||
data-name="Upper" data-addr="0x47" data-desc="Thumb button — pad Y"><span>Upper</span></button>
|
||
<button class="hot" type="button" style="--cx:37.7%; --cy:36.5%"
|
||
data-name="Main trigger" data-addr="0x40" data-desc="Index trigger — pad A, Space, NumPad 0"><span>Main</span></button>
|
||
<button class="hot" type="button" style="--cx:37.7%; --cy:59.0%"
|
||
data-name="Middle" data-addr="0x46" data-desc="Middle finger — pad B"><span>Middle</span></button>
|
||
<button class="hot" type="button" style="--cx:37.7%; --cy:81.6%"
|
||
data-name="Pinky" data-addr="0x45" data-desc="Pinky finger — pad X"><span>Pinky</span></button>
|
||
</div>
|
||
<svg class="stick-hidden" viewBox="0 0 250 360" aria-hidden="true" hidden>
|
||
<!-- grip: tapered column, leaning back like the pod stick -->
|
||
<path class="stk" d="M156 62 c30 -6 50 10 52 42 l6 156 c1 26 -4 40 -16 48 l-72 6 c-15 1 -23 -9 -21 -24 l24 -196 c3 -22 13 -30 27 -32 z"></path>
|
||
<!-- thumb cap, top right -->
|
||
<circle class="stk" cx="196" cy="86" r="22"></circle>
|
||
<!-- trigger hook and lower nub, left face -->
|
||
<path class="stk" d="M124 150 c-13 1 -21 9 -21 20 c0 10 8 17 19 17"></path>
|
||
<path class="stk" d="M116 222 c-11 1 -18 8 -18 17 c0 9 7 15 16 15"></path>
|
||
<!-- hat / thumb cylinder -->
|
||
<rect class="stk" x="150" y="238" width="28" height="46" rx="14"></rect>
|
||
<!-- base -->
|
||
<path class="stk" d="M104 300 l100 -10 c15 -2 24 8 24 21 l0 20 c0 13 -9 21 -22 22 l-88 8 c-15 1 -24 -8 -24 -21 l0 -20 c0 -11 4 -18 10 -20 z"></path>
|
||
|
||
<!-- callouts: top to bottom as the hand finds them -->
|
||
<g class="ctl stick-btn" data-name="Upper" data-addr="0x47" data-desc="Thumb button — pad Y">
|
||
<line class="lead2" x1="86" y1="96" x2="146" y2="96"></line>
|
||
<circle cx="60" cy="96" r="25"></circle>
|
||
</g>
|
||
<g class="ctl stick-btn" data-name="Middle" data-addr="0x46" data-desc="Middle finger — pad B">
|
||
<line class="lead2" x1="86" y1="164" x2="120" y2="164"></line>
|
||
<circle cx="60" cy="164" r="25"></circle>
|
||
</g>
|
||
<g class="ctl stick-btn" data-name="Pinky" data-addr="0x45" data-desc="Pinky finger — pad X">
|
||
<line class="lead2" x1="86" y1="232" x2="112" y2="232"></line>
|
||
<circle cx="60" cy="232" r="25"></circle>
|
||
</g>
|
||
<g class="ctl stick-btn" data-name="Main trigger" data-addr="0x40" data-desc="Index trigger — pad A, Space, NumPad 0">
|
||
<line class="lead2" x1="86" y1="300" x2="112" y2="300"></line>
|
||
<circle cx="60" cy="300" r="25"></circle>
|
||
</g>
|
||
</svg>
|
||
</figure>
|
||
|
||
<div class="stick-key">
|
||
<table>
|
||
<caption>Grip buttons</caption>
|
||
<tbody>
|
||
<tr><th>Upper</th><td class="addr">0x47</td><td class="mono">Y</td></tr>
|
||
<tr><th>Main</th><td class="addr">0x40</td><td class="mono">A · Space · Num 0</td></tr>
|
||
<tr><th>Middle</th><td class="addr">0x46</td><td class="mono">B</td></tr>
|
||
<tr><th>Pinky</th><td class="addr">0x45</td><td class="mono">X</td></tr>
|
||
<tr><th>Throttle</th><td class="addr">0x3F</td><td class="mono">RB · Alt</td></tr>
|
||
<tr><th>Panic</th><td class="addr">0x3D</td><td class="mono">LB</td></tr>
|
||
<tr><th>Hat</th><td class="addr">0x41–44</td><td class="mono">D-pad · arrows</td></tr>
|
||
<tr><th>Config 1 · 2</th><td class="addr">0x37 · 0x36</td><td class="mono">unbound — yours to map</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<p class="stick-note">
|
||
The throttle button is reverse thrust; the hat looks around. Both live
|
||
off the grip on the real stick.
|
||
</p>
|
||
<div class="readout" id="rd-stick" data-idle="true">
|
||
<span class="rd-name">Select a button</span>
|
||
<span class="rd-desc">Hover a circle on the grip.</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="axis-art">
|
||
<figure class="art-tile">
|
||
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAe4AAAFnCAYAAABgqKpGAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAACgYSURBVHhe7dpb0qS6km7Ralr1v1PnGJalXGKm7hIgiDm+px/cXYIggp3L9v/8jyRJkiRJkiRJkiRJkiRJkiRJmvC//+9//x+PSZKkTfniliTpJY6Xti9uSZJeIry4fXlLkrS5+KXti1uSpM354pYk6SX40vblLUnSxvjC9sUtSdKmUi9q/i1JkjaRekmnjkmSpIel/rVdOi5Jkh6Uezn74pYkaTO1l3PpnCRJulntxVw7L0mSblL71/ahpUaSJN2g5YXsi1uSpA30vJBb6yRJ0kV6XsY9L3lJkrRY74u4t16SJC008hIe6ZEkSZNG//U82idJkiaMvnx9cUuSdLPZl+9MryRJ6jT74p198UuSpEYrXrorZkiSpAarXrir5kiSpIyV/1JeNUeSJGWsfNmu/B8BkiQJVr9oV8+TJEmRK16yV8yUJOnnXfWv46vmSpL00+IX7MqX7BUzJUlS4uW96mW7cpYkSYLVL++VsyRJUgJf3jMv3RUzJElSg1Uv3RUzJElShS9uSZJeZPWLe3aOJEkqWPXCXTVHkiQVrHzhrpojSZIyfHFLkvQiV7y4V8ySJEkJq1+2K2dJkiTwxS1J0ovMvrjZNztPkiQVzL5o2Ts7T5IkFcy+aFP9/FuSJC2SevH2iPtTYb0kSZow+5Lli5phvSRJmjD7kuWLmmG9JEmaMPuSZS9f3KNzJUlSwuwLNtc7O1eSJCXMvmBLvaVzkiRp0MwLdqZXkiQNmHn5zvRKkqQBMy/fmV5JkjRg5uU70ytJkgbMvHxneiVJ0oCZl+9MryRJGjDz8p3plSRJA2ZevjO9kiRp0OjL1xe3JEkv4otbkqSbzbx4fXFLknSzmZfvTK8kSRow8/Kd6ZUkSQNmXr4zvZIkacDMy3emV5IkDZh5+c70SpKkATMv39A72i9JkjrNvHh9cUuSdLOZF68vbkmSXsYXtyRJkiRJq/kvbUmSbjbz8vU/k0uSdLOZl6//5zRJkm428+L1xS1J0s1mXry+uCVJutnMi9cXtyRJN5t58friliTpZjMvXl/ckiQ9YObF64tbkqSX8cUtSZIkSZIkSfpRX/xP5PH/4Y5pretNPFeSpMu84cXDl+Rorprbmnjd804kSWqUerHsgC+9FbljjVx61zzvVJL0KTM/9He+LPhyqq3J2tlcPT+Xleudr0CS9EozP+pXvRT4wimFvQHrZnP1/FSuXut8RZKkz5t9CfBFMhLOjLF2JlfNzeXOtZj4WiVJH7Lix54vjZFwZsC6mVw1N5U712pJvB9J0sut+HHni6I3nBdj7WiumJnKXeuMJt6fJOml+IPOv1vwBdEbzgtYN5orZqZyxxqrEt8TSdLL8Ed99Med/T3hrIB1I1k9L5Wr51+d+B5Jkl6CP+YjP+jsbw3nxFjbm5WzUrly9hOJ75ckaXP8ER/9IeeMlnBGwLrerJzFXDV3h8T3TZK0Mf6Aj/6Qs78W9sdY25pVc1K5YuauOd9FSdJ2+MM9+gPO/lrYH7CuNavmMFfMfEvia5ckdZj5IW3t44/26JrsL4W9AetakprBYymck5vJc7+U+D5IkhqN/oj29PEHu6c3xv5c2Bernd8Br+fr4fVLkhqM/oi29vDHema9WtjzJbzWL4XXKkmquOMHlD/Wo+vN9H4N7+fbw+uTpE/gj92qH7yVs3K47zvW/DW8t28Mr0mSXok/bgzrR62eR9z31ev9Ot7nN4XXMmr1PEnqwh+3t/7QXbFvlfF5eUN4Da04Z2aWJE3jDxLD+hErZ6VcOVt1fGZ2D/dPrE+FPZJ0K/4oMawftXqe9sNnZ+fM7Dvu/aJfuEZpC7M/LuyfmZWzep72xWfoa+H1fsXXr0/aAn9QZn5c2M+wftTqedoXn6GvhNf5BV+/Pulx/CHJhX0tOGN2Xsrqedobn6O3h9f3dl+/PulR/IK1hnNq2D8zK2f1PO2Pz9Jbw+t6M17b165Pegy/WCPhzBr2M6yXevB5elN4LW/F6/rStUlb4BdsJJzZgjNm50kBn6e3hNfxRrymL12btCV+2XrDeTXsn5klEZ+p3cP9vw2v50vXJm2PX7qecFbNbL9Uw2ds13Dfb8JrYVgvqWD2S8MvYGs4R3oKn81dw32/Ca+FYb2kjJVfHs5qCWeoDe8d/1Y7PpM7h3t/A15DKuyRlMAvTirs6cFZpbBXaaX7ljuuf/E+vi28nt1x/6mwRxLwS1ML+3twVi7s0x+8T6l7xuM8r/w9emN4bTvj3nNhn6T/wy/LSDizB2etmPlFvD+p9NTHtb+E9+Er4XXuivuO9547LinCL8psOL/HihlfxHtcykhf3PNlvO6vhde7I+6Z+y6dk5T4kqwO11M73svWzPSfd/B9vP63h9e3G+43tefaeemn8QtyZbi2/sV7NpJV8+I5sdK5L+B9eFt4PTvhXlN7Lp2T9H/4Rbkj3MOv4/2Zyeq58bxfxXuyc7j3XXCfuf3WzkvK4JfnqnDdX8J7sSpXzT/v/rfx3uwU7nUH3GNpry01khrxCzUbzv86Xv9VuXq981XpwHv0ZLi3p3F/tX221kk/Y/UXgl+y1nDOV/G6r86da8dr6Yz36s5wL0/i3lr22FMrfR6/EKmwZxTnrp6/M17znblzH/FaquP9uypc9yncV+v+euulz+KXoSecpTTetydy9V7OV6wZvLerwnWewD217o31LT3SJ/GLsCpc59fwfjydK/cWz6aWGtXxns+Es+/EvfTsaaRH+iR+Ga4O1/8SXuvT4f4C1o2EM2Ol2tQx9eM97gln3YX76N3PaJ/0Kfwi3B3u5614XU+Geythby3sj7E211c6pzm8t7mw7y7cR+9eZnqlT+CX4O5wP2/D63ky3BvVajmvVh9jfSotteep++F+U2HP07i/J/fJPYzsY7Zfej1+Ce4M9/ImvJYnw73FWMuw/lA6F+OsWnr6zitdj+uvCNfYxVP74/0Z3cdsv/Rq/ALcHe7njXhNd4R7INa3hDNy2Nea0Rlx3yjOvDvczy/iPRm9N+wfmSG9Fh/+u8P97K62d17fFeGaMdb2hvNirB3J7Ly4P4c9PeGsA2tmw/m/gvdh5n6smCG9Fr8Ad4Z72R33n7sG1qwI14ixtjecF2PtbFbNPe8yj325sC+FPbPh/C/jtc/eg1VzpNfhw393uJ+dce8M6w+sGQlnBqwbCWcGrFuZ1Wucd57Hvlp/7dzqcI0v4bWmwp4Ya1Nhj6Qfxx+JUth7YE1LOCNgXW84L2DdFblyvXh2Sa2ec3trZ8M13o7Xlwv7Atblwj5JP4w/EC3hjIB1DOtjrO0JZ8VYe2XuWDdeowfn5MK+A2tWhGu8Ea+pFPYGrMuFfdIn8cG/M9zLrrjv3nBe0Fp3YG1rOCfG2rty5/rnK85jX0s4I2DdinCNt+B1lMLeGGtTYY/0WXz47wr3sSvueyacfcgdP7C/J5wVY+2deWof8boBa2Zy5WyGa70Rr6l0Xawr1Uo/gV+Iu8J97Ih7XhWuk8KelnBGjLVP5c49xWvFWDcTzg5Ytypc5614XaVra62TfgK/EHeGe9kJ97oyXKuG/QzrY6zdIXfs7XwX/sO6mXD2gcfZM5N47hf0XF9PrfR5/ELcGe5lF9znynCtHj2zWPt0uL8Da1aEawSsmwlnB6nz7B1NPPMreq6xp1b6PH4h7gr3sQvuc2VSa5X+7sX1dgj3mMKekXBmwLqZcPaBNalanutJPOdLeJ2la2VdqVb6CfxC3BXuYwfc48qU1uLx+O8arrNLuM+gdJ4zWsIZAetmwtkH1jA9tbnEM76m51p7aqWfwC/FXeE+nsb9rUxtndz5+Dhxxg7hHmOsLfWwJhf2pbCnNZwTsK6UkZ4j5xW/qeeae2qln8AvxV3hPp7Eva1M61qlmvhcwJonw70FrMuFfQHrSj254wf2lsLegHUtGemPe76s57p7aqWfwC/FXeE+nsJ9rUzvOrXaeF6p7o5wLzHWtoZzglIdz6VqYqwbrW9Jz5y49ut47aXrb62Tfgq/GHeF+3ga9zebkdktPXFNwJorw7UD1s2EswOeY18qcX2s9fxsWuadV/6+nuvvqZV+Br8Yd4X72AX3OZKZeS198Xxi7YpwjRhrV4ZrxVhbC/tz2Deb0uz43C/puQ89tUrjPfQ+fgA/0LvCfTwhtxfutSezc2r98fkS9o2EM2OsvTIr1+asgHUrk1onPvZrSveHemp/Ae9H7r7Uzuvl+AHfGe7lbrW9cL+lzPQyqRnn6X+UzgWc3RLOCFh3R67aw+p5pZyvQD33p6f2K3jNtZT6eU4fwYfgznAvd+N+cntiDdNbXwtnxX+HY6mwLsbaVNgTsO6uXLmPK2aWcr6S39VzX3pq34rX2JvSvNQ5HtNL8UG4M9zL3bif0t54vreuN5wbsC4V9lBLLWfenav3cvV8Jl7vl/Xcl57at+A1jYQzg1JNy7FcrzZ1fizuC/dxN+6HYf2hdJ79ubCvFeeUwt5WnPNE7tjP1fOZ+Jp+Wc996andFa9hNJxLpfrcMf6dO5Y6pw3wA7oz3MuduJdc2PcE7qk1nJPDvidy557uWidOvOav6rknPbW74J5nw/k5uZ6WY7Xe3Hk9jB/OneFe7sS9MKx/Avc0Gs7NYd9duXsfd64VEq+pb+FnPRPOjqVqcv2pY/Fx/p2rY+IaPYgfzN3hfu7CfazeD+f2rsGeFeEaKey5Ok+sf/d6R7hm/LfeiZ/xTDg7qNXlzs8c43EmrtOD+MHcGe7lbqP74HX0hLOI9UxvfRz25rBvdbhewLorcvd6IVwz3sfX5e5FCmtr9U/g/kbDuQHrcvW5c6njtWPx8dS5VI0exA/m7nA/O8ntkdfQGs6JsTYV9gSsq4X9OeybDefnsG9l7lqHidf9NT33oqf2btzbaDj3wJpUSj2146ljPN5zThvgB3RnuJfdpPbJa2hNPCPGulTYk8KeWtifw77ecN5hpGZFrp6fSrwmtda92ej9qNXeifsaCWceWFNKqbd2PHWMx3kuyB3Xw/jh3R3uZ3fcf2s458AahvVB6Txn1ML+HPbVwv6AdbUe1szkqrlMvE4K63t636bn+npq78I99YSzAta1pDRj1XGe0+b44d0d7mdn3Htreuewnmp1nFcKe3PYlwp7cthX62fdSFbPSyVeg1hbCnt1P34mPeGsA2t6UprVe7x2jue1KX5oT4R72hX3XQv7D6xhWE+9da1hfw77cv218wfWjNS2ZuUsJp5NrO0N5+l6/AxawzkH1oykNnP0eO58KuzRBvghPRHuqdfKWTnccynspVp96tghV39IHec6tbA/p1TPmSO1I/W1rJgRct7Vv1g/Gs7VtXj/W8IZB9bMhLMPufMtx3kudb5Uq43ww3oi3FMN+0fntOI6qZR6eO6QOl6rnznXGva34Ixc2HdgzUx9LjO9IeddnLF2Jpx9yB3fUcv1BKyt1V+Fe2jJihm1cI1D7nypt3ROL8UP9alwX8T6VNhT09rDdWprsqZUG9TqWs7lzh/imlrYm8O+1nDOgTUz9cxIT8h51X+xfjSce2BNrm4nPfvtqb0S91EKew+sWRWucyjVtBzP1eS01ukB/ECfyuy+2N+itbd1LdYxrA9qNS3ncudjcW0t7A1YNxrOPbBmpj6kpzbkvMoZa2fC2QfWpMIejeF9LWWmdyRcL8jVlPp5LlcXlM5pI/ww3xpeV81oH3EftbA/yJ0r9bXMjXEvtbD/wJqZcPaBNSvqeTyV89Qz1s6Esw+sqYX96sP7mcto34rEa+bW/7uxyrnU+VrYrw3xQ3tjeE0tRvsC7qEnnJVTqq/NKx3vCfsPrJkJZx9YM1JfOseaFNaOhnMD1pXCXo3hfc1lpK+1riVcPyjVlc6lzufCPm2MH97bwuu5EtceDeemlGprs3LHA+6nFPYGrBsN5was66lPHeO5FNaOhnMD1tXCfo3hfc2ltY91xPrexHNyc+PjPJc6H7CuVKvN8YN8U3gtV+G6K8I1YqWa2ozcceJ+SmHvgTUz4ewDa1rra8eIs0fDuQHramH/oXROZby/qbTWx3Ul7OsJZwW1Op5P1ehj+IG/JbyO1bjeFeGaQe5cqTd3/JA6ft5JPew/sGYmnH1gTa2+FWeNhnMD1pXC3qC17ik9++upXYVrptJaX6uLzwesaQn7+XeuNnU+V1fSW6+H8cN+Q3gNK3GtK8O1S0p9ueMp3EMt7CfWz4SzD6yp1eewdzScG7CuFPZSqZ5/PyG3t5TStVyB66XSWt9ax9qW+lTYz79ztQFrSmGvXogf6u7h/lfgGneGe0kp1eeOE9ethb3x38TemXD2gTW1+oC1o+HcgHWlsDen1JM6pv/wnjOttXFdrTaktz4VzuDfTHw+YA2TqucxvQQ/3J3DvZe01HP+U+G+YqW63PEY16ol1ctj8d8B58yEsw8tNQfWjYZzA9aVwt6aXG/qmP7D+85cVRtntC8OZ/BvJj7fa7ZfG+ADsWu475pcH+fuEO4xKNXkjgdco5RaL8/FfwfsmQ3nl7B3NJwbsK4U9gY8z9rcjNQx/Se+b0xrHWtb6pmZ3hDOiP8OxxjWlIz2aSN8AHYP91+Sq+fM3cL9HnLnasdb09qfOn/u/IN9M+FsYv1oOPfAmlrYH+Tq2JOrYZ3+w3vLtNYdOU9u64kz0xuHc+K/w7FcWHtgTa5OG+MH+KbwWnpw1s7h3nNS9ZxVS9xb6y/VxecC1szkqtmcG7CuFPYGrGupbT2uP3h/47TWhcT1AWtqGe1juIf474A9LeEMbYwf3pvDa2vBGW8Jr6OG/bWM9NdqzxP/YM1oVs477/AP1tTC/gNrGNaXjPT8Et5bprUu5Dz9D9bUMtqXynkn+Rf4gb0M67UpfnBfCa+zhL1vDa8rhT21jPa39sR1AWt6csWcgDW1sP/AmlzYlzLS84t4n5jWujjnFf5gTSkjPaWcd/JH7rhejB/818LrzWHf28Pri7G2lJnekJbe8ypnrG3Jyv6ANbWw/8CaWtgfY22t/m49+7r6Ojif6amNE/fFWJdLb31LzjvRz+CD8Obw2krY+4XMXONMb5zSjPhcCftqGe2N+wLW1ML+A2tawzlBa53+4P1iWuuY8ypnrGV6akcSz9cP4gPxpvBaWnDGF9J7jb31tXDOefp/Uj0xzs1ltD7GmlrYf2BNazjnwJpcnc54z1LpqWXOq52xNtfHc6sTr6UfxYdi53DvPTjr7eH1HViTquP5kXBmCntKvaxheutirKmF/QfWtIZzYi01+hfvcSo9tamcV+zDWXcktwce18fxwdgl3GcvzvtCeI2H3Dn25upmcHYq7AlYx3oej88R60phb8C61nCO1uG9TqW3PpV4RivOeDLcm34QH4qnwn2VlOo59+3h9T2F+6qF/UGuJnc8dl6hHvYfWNMaztFavN+5jPSkEs+pYe8T4Z6kEz4wd4X7KKn1cPbbw+u7G/fTE846pM7x7xhn1sL+A2tawzm6Bu97KSM9qZx3kMaeu8J9UEuNxvV8FlviA3VVuG5Jaw/XeEN4DU/j/kbDuS04oxT2BqxrDefoWrz/pYz21XLFzFria2k12qd/8fNgWP9qvLgV4RolPT1cZ6dwr7vhfmfD+TnsK4W9Aetawzlfx+uv3YOe2h6cW8ts/53hXnukZvBvteNnUwv7P4UXOxrOzemtP3Ctu8P97I77XxmuFbCuFPYS62th/y/puRc9ta04szWcc2DNXeE+RnBmanbqmNJ4H3vDeZ/HG9AazsnprQ+43lXhum/D61kZrkWsZ1ifw75c2Kf78TPpDecR63vCWbM4v5ZUb3xM/fe0NVzn5/CG5MK+nN564roz4ey34/WtDNeJ/6ZSbwv2M6zXc/jZjIZzn8S9jSQ3k8d/Ce/RVeG6+j+8UT03q7c+h+uXwt4v4jWvTGodHov/rmF96m8mPq998HNaFa6zEtdaGa51qJ3/It6XO8O9KKP3ZvXW5/AD+9UPjte/MqV1UufiY5Tq5d+s4znthZ/Vr4b3JdZa91a8F0+H+5O2w4d2VVrWKZ3PHc+d/zsocyzIHddz+Nn+UngvDjxXq38TXv9u4X61iDd3DT6wK9OzVq4udSx1vsdo35f13Nee2h6c+yup3Yfcufj4rngtbwmvQ4vM3OCZ3i/iQ7siI2ukalPHUudbjfT8gp77ytpafQ/O/XJ47QfWsC53fBfc+xvDa9JCMzfZD+lffHhnMjqbPfybic+3GOnR/fg5fy283gNrmFTdecKzuN83h9emhWZush9SHh/i3szOi/ta5sQ1sdp57Y+f9dvD6zuwJpdUT3xsJ9z728Lr0UIzN9kP6Y/SPYjvUWtm+4/EM2Ksy9XWzutd+Jm/MbymA2tqSfXGx3bF69g93L8Wm7nRflB/1B5ani9ltC+VeFZQOqc1ap9BrOUzW4nrvSG8hgNrepKacZ6+L17LruG+tdjMjfaD+oMPbe5+sIbpqW1JPC/M5LGg1qt2Pfeyp3YVrrlruO+Adb1JzTmvsCdex67hvnWBmZvth/UHH9zafWEN63huJPG8VpwxOufX9dzDntrVuPYu4T4PrJlJam58bDfc/+7h/nWBmZvth9X+pSr15Y4zcd2VnljzS3o+N9bW6q/A9Z8K93VgzYrk5sfHd8B9vyW8Dl1g9mbP9r8dH9pc2CfthM/rneFeDqxZndQ65x08i/t9S3gduog3fA4fXIb10s74/F4Zrh2w7oqk1jrv4hnc59vC69FFZm74aN8XrXyAOSsX9mkfPZ9VT+0duJ+V4VoB665Obu34+J24vzeG16QLzdz0md4vGr0X/AK0hnO0j57Pqqd2tdKa3NdMODtg3V3J7SE+fgfu683htelCMzfdD20NfgFawznaR89n1VO7Wm1tnu8JZ8VY+0RSeznv8lrcz5vDa9PFZm68H9wa/BK0hnO0j57Pqqd2Na6dWp/na2F/jLVPJrWn826vwX3smN598hp1sZkb7we3Br8EreEc7aXn82qtW4n7K+2B5xnWx1i7S3J7jI+vxPV3DPccsI5hvS42c+P94Nbgl6A1nKO99HxePbWrcE2mVhufJ9bumNx+4+MrcN0dwz3nsK+nVwvN3Hw/vDX4RWgJZ2g/PZ9ZT+0KXC8X9tWwf/ek9n2+onFca9dw3z1m+zVo5sNb9eH/Mn6JamG/9tXz2fXUrsD1UmFPDvvelNQ1nK9uDNfZMdyzXmTmQ/QhmMcvUy7s0/74GZY+x9a6FbhWKuyJsfbNSV1XfGwU19kp3Ks2VfrASudqfBjWiO+j9/Rbej7TntoZXIdhfYy1b0/u2uLjLUp9XPOpcF/aXOnDyx1vUZqrPt7Lb4o/19pn21M7imswrE9hz9uTuq7zFedxVm0Ga+4I96AXyX2Y/LtHap6k/+S+dyk9taO4xsh67Ht7Utd1vuI0zimFvQfWXBGuqZfhB8qwvsVsv/R1/J6VviusK9WO4OzRddj79qSu63zFZ+zvDecdWDMbztdL8YNlWN9itl/6BT3ftZ7aHpw7swb7357ctcXHeW5VuMaBNT3hLH0AP+TZD3y2X/oFPd+1ntoncZ9vTu664uPEGSvCNQ6syYV9+hB+yLMf/Gy/9Avi70nt+9Ja9zTu883JXVd8vITzZsP5Aetq9fqI1IfNv3uk5kk6i78nte8L61K1qWN34x7fntR18Xrjv3M4dzacfyid0wflHgj+3So3T/pF8fehFvbGWJsKe+7G/bw9qevKXW98vOS8wnw4Xz9k5UPgQyWd8ce2FPYGrMuFfXfiXt6e3HXljvN8DftGwpn6ISsfhJWzpK84/9zmw76Adbmw707cy9uTu7bUsVziGSXsq4X9+kErH4iVs6QvOf/0psOeGGtTYc+duJe3J3dtqWMtieflsCcV9uiHrXoofMCkPP4Iz35XVs1ZgXt5e3LXljvek3hGzkiPfsyqB2TVHOmrzj/Hc9+VVXNW4F6+kNS1na/6D/a1hnOkLqseplVzpC87/3yPf184Y3TOCtzHF5K7tvOV/4d1PeEsqcmKB8gHUWrDH+7R78yKGStwH19I7trOV57GntZwjlS04sHxAZTa8Ud75Hsz278K9/GF5K4vPt6Cc3Nhn1S14gFaMUP6Feef7bHvzkzvStzHF5K7vvh4L64xO08/btWD5EMp9eF3pud7M9q3GvfxheSuLz4uPW7Vg1n6Akg64/el53sz0nMF7uMrSV0frzv+W7pd6sEcxS/AqrnSF/G70vqdYX1LzxW4h68kdX2l647PSbe44gH0wZba8LvS8p1hba3+KtzDV5K7vvPV189Ll7riwfOBltrwBdDyvempvQr38JXkru989WetddIyVzxwPshSu/j70vLdaa27EvfwleSuMT4uPW71w7l6nvQL4u9N7TvUUnM17uEryV1jfFx63OqHc/U86VfE353S96h2/g7cw9Ph/g6saUmuPz4ubWHVw+mDLs2Jv0O571Pp3F24h1rYfwfuoSW5/vi4tIVVD+iqOdIvi79Hue9U6dzVuHZLOOMO3ENrcv3n6dLDVjycK2ZI+uP8yvj3e1U6dzWuXQv7Z3F+bg3WtCbXf54ubWD24fQBl9biiyP+buWO34Fr11LqL51rDWcErGtNrv88XdrAzAM60ysp7/zqyId9V+LapbT2tdalwt7ROSG5/r+LSLuYeUBneiXlnV8d+bDvSlw7l56euLalPiTVw797k+v/u5C0k5EH1AdbuhZfIKmw50pcO5ee+vMK/T2p46xvTW2utJWRB9QHW7pe/D3LhT1X4bqpzNQHrMnV587xeGtys+Pj0jZ6H9Leeknj4u9bKqy/CtdNpaf2yHmFP1iTquW5+DyPtyY3Pz4ubaP3Ie2tlzQn/s4xrL0S12Za646cJ/+HdazlOdbweGtKa8TnpG20PqA+zNIz+DJ54nvItZneulDLv0u1ubTUlFJaJz4nbaP1IW2tk7Te+XVy//eQazMttXENlWp5jmmty6W0VnxO2kbLQ9pSI+la51fKvd9HrsvU6lPn+XeqlnNS6anNJTfj70ak3dQeUh9kaQ9PvVi4LsP6Etbn5nCNXHrrU8nN+LsZaTelB7V0TtL9nvpOxuvm9sC/Y6lzqRnx8ZaM9DC5GX83JO2m9KCWzkl6xhPfyfi3IPe7wL9LUv3x8daM9sXJzfi7KWlHqQfVB1ja193fS77U+NuQOpZSqjtPbstMb0huxt+NSTtKPag+wJICvtT428DjtZyn9/eHzPYfKe0jPidthQ8q/5b0286vs39/H3g8l/PU9r5cVswp7Sc+J22HD6wPrqSAvwv8feDxVM4T23pqWTGrtKf4nLQdPrA+tJIC/jbwN4LHmfO0en1rVswr7Ss+J22HD6wPraSAvw38jeBxnq/VjWbF3NL+4nPSdnxgJZXwN4K/E7njAXtXZMXs0h7jc9KWfGAlpfCF1vM7wZ6VWbFGaa/xOWlLPqySUvhCa3m5se6KrForN+fvxUi78mGVlMIXWu7lxnNXZ9W6uTl/L0zalQ+qpBS+0Jie2pVZtWZuzt+LkiTpTfhCS6W3fkVWrZeb8/eCJEl6C77Mchnpmc2q9XJz/l6QJElvwZdZKaN9o1m1VmnO3wuSJGnW1S8XvsRaMtvfk1XrlOb8vRhJkla460XDdXIZ6RnNqnVKc/5ejCRJq931wuHLjempncmqNUpz/l6IJElX4cvnqhcQ18itx3Orsmp+ac7fi5Ak6Q53vIi4BtfhuVVZNb805+9FSJJUs/oFcsVLiTNz83luRVbNLu0zPidJUhJfHgzrR6yYyRmp9Nb3ZNXc0h7jc5IknfCl0RLOGNE7k/WljPa1ZNXc0h7jc5Ik/YMvjp5w1ojSTJ5rzYoZqayaWdpffE6SpCK+RFrDOaM4dyar566cV5oVn5Mk/bDelwJfKK3hnF6cN5OVM1fusTQrPidJ+kF8MfS+INjXE86qYf9sVs6+a1Z8TpL0Q/hCqIX9KezpCWfFWLsyq9ZZNedIaVZ8TpL0A/gi6A3n5bCvJytntWTFWitmhJRmxeckSR/Hl8BsOD+HfaWw98Ca1Vmx1mx/nNJ+4nOSpB/CF8JsOD+Hfa39rF+d2bVmepnSXuJzkqSPaf3RZ91sOD+np/bAdVZnZq3RvlRK+4jPSZI+gj/2qbAnYN1sOH8U516R0fVG+3IpzSud60k8R5L0EP44t4ZzDqyZDef34ryrMrLmSE8ptXmlcyOJ15Mk3YA/xDPh7ANrRsO5PTjryvSu21tfS21e6dxs4rUlSRfgD+/KcK0Da1rCGSM48+r0rNtT25K/F52ZWTq3KvEeJEkL8If26nD9A2sY1o/i3DvSun5rXU9qM0vnVibehyRpEH9c7w73E7TUjOIe7krLHlpqelObWTq3MvE+JEmd+KO6Q7jHK3DNu1PbR+38SP5efGZu6dyqxHuQJHXij+qO4Z5X4Tp3p7SX0rmZ1OaWzq1IvL4kqQN/UHcM93wVrntnUvtIHVuV2uzSudnEa0vST5n5MeSP6Y7hnu/EvdwR7iHG2tnUZpfOzSReV5J+Cn8QW38cWbtruO+Vetdi/ZXh2gfWrEhtfuncaLhm/LckfR5/FHPprX8656tcj+ulwp4Ya9+a2jWVzvUmXivM5DFJ+jz+OL49vL4rcM1a2E+sf1Nq11E615N4nXgej0vSp/HH8c3htV2Ja/eEs4j1u6e299K5lsTzg9I5Sfo0/ki+Mbymq3H9mXA2sX7H1PZbOldLPJszeE6SPo8/km8Mr+kO3MPKcK2AdTultMfRa4j7gtp5Sfo8/li+KbyWu3AfV4Xrxlj7dEr76t13XB+01EjS5/HH8C3hddyN+7kj3EOMtU+ktJeevca1Qe28JP0M/mjuHu7/KdzX3eF+AtbdmdIeWvYY1wQtNZL0U/jDuGu47x1wj0+EewpYd0dKa5f2Fp8LWJOrk6Sfwh/GXcN974L7fDrcX8C6q1JaL7Wf+FjAvlKtJP0c/jjuGu57J9zrDuEeA9atTmkd7iP+O2BPqleSfhp/IN8SXsfTuL9dwn0GrFuV0vzzDs5Y29IjST+HP5JvDa/rKdzXTuFeA9bNpjT3vPIfrKnVS9JP4w/lm8Nrewr3tVu43wNrZlKa2bNmXCtJavjh3Dm8lh1xz7uF+z2wpje1WaVzqTpJUoQ/lruG+34TXsuOWbnn2pzSufi8JAn4g7lLuM8v4bXulFX7rM1pOSdJSuCP5t3hfn4N78cOWbG/0ozWc5KkBP5wXhmu/Star5/368nM7ql0Xalz8TFJUgZ/UFeH6/2ykXvDnjszu49SL2fHf0uSCviDOhrO1b94z2buH/uvyOx6pd54tiSpEX9MW8M5asP7WAp7R3FuKewNWNeaUv95BUlSE/6YpsIejeO97Q3n3YF76ElpxnkVSVITf0zvx3u+KlxnBmePpjTvvKIkSZviC+yrKV1zfE6SpK3xJfbVlK45PidJ0vb4IvtiStcbn5MkaXt8kX0xpWs93w1Jkl6CL7QvJXeN5zsgSdLL8MX2leSu73z1kiS9FF9wb0/uus5XLUnSi/El99bkrik+LknSZ/BF+LbkriU+LknSp/Bl+KakruF8dZIkfRRfim8I936+IkmSfgBfjrsmtef4mCRJP4Uvyt3CvcZ/S5L0s/jC3CXcpyRJivDF+WS4N0mSVMAX6d3hfiRJUiO+VK8M15YkSQvwhTsTzpYkSTfii5lhvSRJkiRJkiRJkiRJkiRJkiRJ2sn/B+6V+QEqVNbiAAAAAElFTkSuQmCC" alt="Pod diagram: the stick pitches, rolls and yaws the VTV">
|
||
<figcaption>
|
||
<em>Stick — attitude</em>
|
||
Pitch, roll and yaw. <b>Left stick</b> on the pad, <b>Num 8 2 4 6</b> on
|
||
the keyboard.
|
||
</figcaption>
|
||
</figure>
|
||
<figure class="art-tile">
|
||
<img src="data:image/png;base64,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" alt="Pod diagram: the throttle drives the VTV forward and back">
|
||
<figcaption>
|
||
<em>Throttle — travel</em>
|
||
Forward and reverse. <b>Right stick Y</b> on the pad,
|
||
<b>Shift</b> / <b>Ctrl</b> on the keyboard; it holds where you leave it.
|
||
</figcaption>
|
||
</figure>
|
||
</div>
|
||
<p class="art-credit">Both plates are the pod's own instruction art, lifted from the shipped gauge assets.</p>
|
||
</section>
|
||
|
||
<section>
|
||
<h2>The mouse</h2>
|
||
<p class="sub">
|
||
The third input. Every button on every display is clickable and lights
|
||
when the game commands its lamp — and each one reaches in under the
|
||
glass beside it, so the picture is the press target. The lit strip at
|
||
the edge is only the lamp.
|
||
</p>
|
||
|
||
<div class="panel">
|
||
<div class="reach">
|
||
<figure class="reach-fig">
|
||
<div class="reach-glass">
|
||
<span class="reach-strip is-top is-lit" aria-hidden="true"><i></i><i></i><i></i><i></i></span>
|
||
<span class="reach-band is-top">press — top row</span>
|
||
<span class="reach-band is-bot">press — bottom row</span>
|
||
<span class="reach-strip is-bot" aria-hidden="true"><i></i><i></i><i></i><i></i></span>
|
||
</div>
|
||
<figcaption>
|
||
One MFD. Four buttons above the glass and four below, each
|
||
<b>240px</b> deep against a <b>480px</b> pane — so the two banks
|
||
meet in the middle and the whole face answers the mouse. Only
|
||
<b>10px</b> of each clears the edge to show its lamp.
|
||
</figcaption>
|
||
</figure>
|
||
</div>
|
||
</div>
|
||
|
||
<h3>Arranging the glass</h3>
|
||
<p class="sub">
|
||
The pod bolted its displays down at one size. On a desktop panel there
|
||
is room to trade viewscreen for instrument, so all six are yours to
|
||
size — and the radar to place. Set these in <code>environ.ini</code>
|
||
beside the exe; they are read once at startup.
|
||
</p>
|
||
|
||
<div class="pos-grid">
|
||
<figure class="pos">
|
||
<div class="pos-box p-center">
|
||
<i class="ul"></i><i class="uc"></i><i class="ur"></i>
|
||
<i class="ll"></i><i class="lr"></i><u></u>
|
||
</div>
|
||
<figcaption>CENTER<small>as the pod had it</small></figcaption>
|
||
</figure>
|
||
<figure class="pos">
|
||
<div class="pos-box p-left">
|
||
<i class="ul"></i><i class="uc"></i><i class="ur"></i>
|
||
<i class="ll"></i><i class="lr"></i><u></u>
|
||
</div>
|
||
<figcaption>LEFT<small>bottom corner; the MFD slides inboard</small></figcaption>
|
||
</figure>
|
||
<figure class="pos">
|
||
<div class="pos-box p-right">
|
||
<i class="ul"></i><i class="uc"></i><i class="ur"></i>
|
||
<i class="ll"></i><i class="lr"></i><u></u>
|
||
</div>
|
||
<figcaption>RIGHT<small>the same, other side</small></figcaption>
|
||
</figure>
|
||
<figure class="pos">
|
||
<div class="pos-box p-midleft">
|
||
<i class="ul"></i><i class="uc"></i><i class="ur"></i>
|
||
<i class="ll"></i><i class="lr"></i><u></u>
|
||
</div>
|
||
<figcaption>MIDLEFT<small>halfway up; leaves the bottom row alone</small></figcaption>
|
||
</figure>
|
||
<figure class="pos">
|
||
<div class="pos-box p-midright">
|
||
<i class="ul"></i><i class="uc"></i><i class="ur"></i>
|
||
<i class="ll"></i><i class="lr"></i><u></u>
|
||
</div>
|
||
<figcaption>MIDRIGHT<small>halfway up, right</small></figcaption>
|
||
</figure>
|
||
</div>
|
||
|
||
<div class="tbl-scroll" style="margin-top:26px">
|
||
<table>
|
||
<caption>environ.ini — display layout</caption>
|
||
<tbody>
|
||
<tr><th>L4MFDSCALE</th><td>All five MFDs, as a percentage of pod size. <span style="color:var(--ink-quiet)">25–200, default 100</span></td></tr>
|
||
<tr><th>L4MFDSCALE_<span style="color:var(--phosphor)">xx</span></th><td>Any one on its own — <span class="addr" style="font-family:var(--mono)">UL UC UR LL LR</span>. Unset inherits the line above.</td></tr>
|
||
<tr><th>L4RADARSCALE</th><td>The radar alone. It already sits at 1.35× the MFDs.</td></tr>
|
||
<tr><th>L4RADARPOS</th><td class="mono">CENTER · LEFT · RIGHT · MIDLEFT · MIDRIGHT</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
<div class="callout">
|
||
<p>
|
||
<strong>Ask for too much and the layout wins.</strong> Panes are
|
||
clamped against their actual neighbours and shrink evenly, so nothing
|
||
overlaps and nothing comes out stretched. Scale the MFDs beside the
|
||
radar and it is the radar that gives way — halfway up a side it has
|
||
one above and one below, and it grows from the middle both ways.
|
||
</p>
|
||
</div>
|
||
|
||
<h3>Filling the screen</h3>
|
||
<p class="sub" style="margin-bottom:0">
|
||
The cockpit fits itself to whatever window it gets and keeps 16:9, so a
|
||
wide panel letterboxes rather than stretching. Launch with
|
||
<code>-fit</code> — <code>start-fullscreen.bat</code> — and it goes
|
||
borderless over the whole monitor and picks the render size to land on
|
||
the viewscreen 1:1, instead of you guessing at <code>-res</code>.
|
||
</p>
|
||
</section>
|
||
|
||
<section>
|
||
<h2>Rebinding</h2>
|
||
<p class="sub">
|
||
<code>bindings.txt</code> sits beside the exe, written with the full
|
||
default layout on first run. Change a line, restart. Delete the file to
|
||
restore these defaults — worth doing after an update, since an existing
|
||
file is never overwritten.
|
||
</p>
|
||
|
||
<div class="two-col">
|
||
<pre><i># grammar</i>
|
||
<b>key</b> <name> <b>button</b> <addr> [toggle]
|
||
<b>key</b> <name> <b>axis</b> <axis> deflect <n>
|
||
<b>key</b> <name> <b>axis</b> <axis> rate <n>
|
||
<b>pad</b> <button> <b>button</b> <addr> [toggle]
|
||
<b>padaxis</b> <src> <b>axis</b> <axis> [invert]
|
||
[deadzone <d>] [rate <n>]
|
||
|
||
<i># deflect springs back, rate sticks where
|
||
# you leave it (that is the throttle)</i></pre>
|
||
|
||
<pre><i># examples</i>
|
||
<b>key</b> J <b>button</b> 0x40 <i># trigger on J too</i>
|
||
<b>pad</b> X <b>button</b> 0x40 <i># trigger on X</i>
|
||
|
||
<b>key</b> NumPadAdd <b>axis</b> Throttle rate 0.75
|
||
<b>key</b> NumPadSubtract <b>axis</b> Throttle rate -0.75
|
||
|
||
<i># drop 'invert' to flip the stick</i>
|
||
<b>padaxis</b> LeftStickX <b>axis</b> JoystickX deadzone 0.2</pre>
|
||
</div>
|
||
|
||
<div class="tbl-scroll" style="margin-top:22px">
|
||
<table>
|
||
<caption>Reference — axes, address space, key names</caption>
|
||
<tbody>
|
||
<tr><th>Axes</th><td class="mono">Throttle · LeftPedal · RightPedal · JoystickX · JoystickY</td></tr>
|
||
<tr><th>Buttons</th><td class="addr">0x00 – 0x47</td></tr>
|
||
<tr><th>Keypads</th><td class="addr">0x50 – 0x6F <span style="color:var(--ink-quiet);font-family:var(--sans)">— unbound by default; the game never reads them</span></td></tr>
|
||
<tr><th>Key names</th><td class="mono">A–Z · D0–D9 · F1–F12 · NumPad0–9 · Up Down Left Right · Space · Return · Shift · Ctrl · Alt · OemMinus · Oemplus · Oemcomma · OemPeriod</td></tr>
|
||
<tr><th>Pad</th><td class="mono">A B X Y · DPadUp/Down/Left/Right · Start · Back · LeftShoulder · RightShoulder · LeftThumb · RightThumb</td></tr>
|
||
<tr><th>Pad axes</th><td class="mono">LeftStickX/Y · RightStickX/Y · LeftTrigger · RightTrigger</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</section>
|
||
|
||
<footer>
|
||
<span>Red Planet 4.12.3</span>
|
||
<span>gitea.mysticmachines.com/VWE/RP412</span>
|
||
<span>docs/CONTROLS.md · CONTROLS.txt ships with the game</span>
|
||
<span>RGB keyboards mirror the pod lamps · RP412KEYLIGHT=0 to disable</span>
|
||
</footer>
|
||
</div>
|
||
|
||
<script>
|
||
(function () {
|
||
"use strict";
|
||
|
||
// Key rows, straight from the default bindings profile.
|
||
// [cap, sub-label, role, address, description, widthClass]
|
||
var F = "flight", M = "mfd", C = "column", X = null;
|
||
|
||
var SP = "spacer";
|
||
|
||
var rows = [
|
||
[
|
||
["Esc", "", X], [SP],
|
||
["F1", "SEC", C, "0x10", "Secondary column 1"],
|
||
["F2", "SEC", C, "0x11", "Secondary column 2"], ["F3", "SEC", C, "0x12", "Secondary column 3"],
|
||
["F4", "SEC", C, "0x13", "Secondary column 4"], [SP],
|
||
["F5", "SEC", C, "0x14", "Secondary column 5"],
|
||
["F6", "SEC", C, "0x15", "Secondary column 6"], ["F7", "SCR", C, "0x18", "Screen column 1"],
|
||
["F8", "SCR", C, "0x19", "Screen column 2"], [SP],
|
||
["F9", "SCR", C, "0x1A", "Screen column 3"],
|
||
["F10", "SCR", C, "0x1B", "Screen column 4"], ["F11", "SCR", C, "0x1C", "Screen column 5"],
|
||
["F12", "SCR", C, "0x1D", "Screen column 6"]
|
||
],
|
||
[
|
||
["`", "", X],
|
||
["1", "", M, "0x2F", "Upper Left MFD · top 1"], ["2", "", M, "0x2E", "Upper Left MFD · top 2"],
|
||
["3", "", M, "0x2D", "Upper Left MFD · top 3"], ["4", "", M, "0x2C", "Upper Left MFD · top 4"],
|
||
["5", "", M, "0x27", "Upper Middle MFD · top 1"], ["6", "", M, "0x26", "Upper Middle MFD · top 2"],
|
||
["7", "", M, "0x25", "Upper Middle MFD · top 3"], ["8", "", M, "0x24", "Upper Middle MFD · top 4"],
|
||
["9", "", M, "0x37", "Upper Right MFD · top 1"],
|
||
["0", "", M, "0x36", "Upper Right MFD · top 2"],
|
||
["-", "", M, "0x35", "Upper Right MFD · top 3"], ["=", "", M, "0x34", "Upper Right MFD · top 4"],
|
||
["Bksp", "", X, "", "", "w2"]
|
||
],
|
||
[
|
||
["Tab", "", X, "", "", "w15"],
|
||
["Q", "ABORT", M, "0x2B", "Upper Left MFD · lower 1 — with Alt, aborts the mission"],
|
||
["W", "", M, "0x2A", "Upper Left MFD · lower 2"], ["E", "", M, "0x29", "Upper Left MFD · lower 3"],
|
||
["R", "", M, "0x28", "Upper Left MFD · lower 4"], ["T", "", M, "0x23", "Upper Middle MFD · lower 1"],
|
||
["Y", "", M, "0x22", "Upper Middle MFD · lower 2"], ["U", "", M, "0x21", "Upper Middle MFD · lower 3"],
|
||
["I", "", M, "0x20", "Upper Middle MFD · lower 4"], ["O", "", M, "0x33", "Upper Right MFD · lower 1"],
|
||
["P", "", M, "0x32", "Upper Right MFD · lower 2"], ["[", "", M, "0x31", "Upper Right MFD · lower 3"],
|
||
["]", "", M, "0x30", "Upper Right MFD · lower 4"], ["\\", "", X, "", "", "w15"]
|
||
],
|
||
[
|
||
["Caps", "", X, "", "", "w175"],
|
||
["A", "", M, "0x0F", "Lower Left MFD · top 1"], ["S", "", M, "0x0E", "Lower Left MFD · top 2"],
|
||
["D", "", M, "0x0D", "Lower Left MFD · top 3"], ["F", "", M, "0x0C", "Lower Left MFD · top 4"],
|
||
["G", "GAP", X, "", "Panel gap between the lower clusters — free"],
|
||
["H", "", M, "0x07", "Lower Right MFD · top 1"], ["J", "", M, "0x06", "Lower Right MFD · top 2"],
|
||
["K", "", M, "0x05", "Lower Right MFD · top 3"], ["L", "", M, "0x04", "Lower Right MFD · top 4"],
|
||
[";", "", X], ["'", "", X], ["Enter", "", X, "", "", "w225"]
|
||
],
|
||
[
|
||
["Shift", "THR +", F, "axis", "Throttle up — walks the axis, position holds", "w225"],
|
||
["Z", "", M, "0x0B", "Lower Left MFD · lower 1"], ["X", "", M, "0x0A", "Lower Left MFD · lower 2"],
|
||
["C", "", M, "0x09", "Lower Left MFD · lower 3"], ["V", "", M, "0x08", "Lower Left MFD · lower 4"],
|
||
["B", "GAP", X, "", "Panel gap between the lower clusters — free"],
|
||
["N", "", M, "0x03", "Lower Right MFD · lower 1"], ["M", "", M, "0x02", "Lower Right MFD · lower 2"],
|
||
[",", "", M, "0x01", "Lower Right MFD · lower 3"], [".", "", M, "0x00", "Lower Right MFD · lower 4"],
|
||
["/", "", X], ["Shift", "THR +", F, "axis", "Throttle up", "w275"]
|
||
],
|
||
[
|
||
["Ctrl", "THR −", F, "axis", "Throttle down — walks the axis, position holds", "w125", "ctrl-l"],
|
||
["Win", "", X, "", "", "w125"],
|
||
["Alt", "REV", F, "0x3F", "Reverse thrust — the pod stick's throttle button", "w125"],
|
||
["Space", "TRIGGER", F, "0x40", "Main trigger", "w6"],
|
||
["Alt", "REV", F, "0x3F", "Reverse thrust", "w125"],
|
||
["Fn", "", X, "", "", "w125"],
|
||
["Menu", "", X, "", "", "w125"],
|
||
["Ctrl", "THR −", F, "axis", "Throttle down", "w125"]
|
||
]
|
||
];
|
||
|
||
var navRows = [
|
||
[["Ins", "", X], ["Home", "", X], ["PgUp", "", X]],
|
||
[["Del", "", X], ["End", "", X], ["PgDn", "", X]],
|
||
"grow",
|
||
[["↑", "HAT", F, "0x42", "Hat up — look"]],
|
||
[["←", "HAT", F, "0x44", "Hat left"], ["↓", "HAT", F, "0x41", "Hat back"], ["→", "HAT", F, "0x43", "Hat right"]]
|
||
];
|
||
|
||
// Physical numpad order. The tall + and Enter each own two rows and
|
||
// 0 owns two columns, so the rest lands where it does on the board.
|
||
var padKeys = [
|
||
["Num", "", X], ["/", "", X], ["*", "", X], ["−", "", X],
|
||
|
||
["7", "L PED", F, "axis", "Left pedal"],
|
||
["8", "FWD", F, "axis", "Stick forward"],
|
||
["9", "R PED", F, "axis", "Right pedal"],
|
||
["+", "", X, "", "", "tall"],
|
||
|
||
["4", "LEFT", F, "axis", "Stick left"],
|
||
["5", "", X],
|
||
["6", "RIGHT", F, "axis", "Stick right"],
|
||
|
||
["1", "", X],
|
||
["2", "BACK", F, "axis", "Stick back"],
|
||
["3", "", X],
|
||
["Ent", "", X, "", "", "tall"],
|
||
|
||
["0", "TRIGGER", F, "0x40", "Main trigger", "pad0"],
|
||
[".", "", X]
|
||
];
|
||
|
||
var kbEl = document.getElementById("kb");
|
||
var rdKb = document.getElementById("rd-kb");
|
||
var rdPad = document.getElementById("rd-pad");
|
||
|
||
function makeKey(def) {
|
||
if (def[0] === SP) {
|
||
var gap = document.createElement("div");
|
||
gap.className = "spacer";
|
||
gap.setAttribute("aria-hidden", "true");
|
||
return gap;
|
||
}
|
||
var cap = def[0], sub = def[1], role = def[2], addr = def[3] || "", desc = def[4] || "", w = def[5], id = def[6];
|
||
var el = document.createElement(role ? "button" : "div");
|
||
el.className = "key" + (w ? " " + w : "");
|
||
if (id) el.setAttribute("data-id", id);
|
||
if (role) {
|
||
el.type = "button";
|
||
el.setAttribute("data-role", cap === "Q" && sub === "ABORT" ? "mfd" : role);
|
||
el.setAttribute("data-name", cap);
|
||
el.setAttribute("data-addr", addr);
|
||
el.setAttribute("data-desc", desc);
|
||
} else if (desc) {
|
||
el.setAttribute("data-name", cap);
|
||
el.setAttribute("data-desc", desc);
|
||
el.setAttribute("data-role", "");
|
||
el.removeAttribute("data-role");
|
||
el.title = desc;
|
||
}
|
||
var main = document.createElement("span");
|
||
main.textContent = cap;
|
||
el.appendChild(main);
|
||
if (sub) {
|
||
var s = document.createElement("span");
|
||
s.className = "k-sub";
|
||
s.textContent = sub;
|
||
el.appendChild(s);
|
||
}
|
||
return el;
|
||
}
|
||
|
||
// main block
|
||
var bank = document.createElement("div");
|
||
bank.className = "kb-bank";
|
||
|
||
var main = document.createElement("div");
|
||
main.className = "kb-main";
|
||
rows.forEach(function (row, index) {
|
||
var r = document.createElement("div");
|
||
// the number row and the home row each open a bank of MFDs
|
||
r.className = "kb-row" + (index === 1 || index === 3 ? " zone" : "");
|
||
row.forEach(function (def) { r.appendChild(makeKey(def)); });
|
||
main.appendChild(r);
|
||
});
|
||
bank.appendChild(main);
|
||
|
||
// nav cluster
|
||
var nav = document.createElement("div");
|
||
nav.className = "kb-side";
|
||
var navWrap = document.createElement("div");
|
||
navWrap.className = "kb-nav";
|
||
navRows.forEach(function (row) {
|
||
if (row === "grow") {
|
||
var g = document.createElement("div");
|
||
g.className = "grow";
|
||
navWrap.appendChild(g);
|
||
return;
|
||
}
|
||
var r = document.createElement("div");
|
||
r.className = "kb-row";
|
||
row.forEach(function (def) { r.appendChild(makeKey(def)); });
|
||
navWrap.appendChild(r);
|
||
});
|
||
nav.appendChild(navWrap);
|
||
bank.appendChild(nav);
|
||
|
||
// numpad
|
||
var side = document.createElement("div");
|
||
side.className = "kb-side";
|
||
var pad = document.createElement("div");
|
||
pad.className = "kb-pad";
|
||
padKeys.forEach(function (def) { pad.appendChild(makeKey(def)); });
|
||
side.appendChild(pad);
|
||
bank.appendChild(side);
|
||
|
||
kbEl.appendChild(bank);
|
||
|
||
// ---- readouts ----
|
||
function show(readout, name, addr, desc) {
|
||
readout.setAttribute("data-idle", "false");
|
||
readout.innerHTML = "";
|
||
var n = document.createElement("span");
|
||
n.className = "rd-name";
|
||
n.textContent = name;
|
||
readout.appendChild(n);
|
||
if (addr) {
|
||
var a = document.createElement("span");
|
||
a.className = "rd-addr";
|
||
a.textContent = addr;
|
||
readout.appendChild(a);
|
||
}
|
||
if (desc) {
|
||
var d = document.createElement("span");
|
||
d.className = "rd-desc";
|
||
d.textContent = desc;
|
||
readout.appendChild(d);
|
||
}
|
||
}
|
||
|
||
function bind(root, readout, selector) {
|
||
var active = null;
|
||
root.addEventListener("pointerover", function (e) {
|
||
var t = e.target.closest(selector);
|
||
if (!t || !t.getAttribute("data-name")) return;
|
||
if (active) active.classList.remove("is-active");
|
||
active = t;
|
||
t.classList.add("is-active");
|
||
show(readout, t.getAttribute("data-name"), t.getAttribute("data-addr"), t.getAttribute("data-desc"));
|
||
});
|
||
root.addEventListener("focusin", function (e) {
|
||
var t = e.target.closest(selector);
|
||
if (!t || !t.getAttribute("data-name")) return;
|
||
show(readout, t.getAttribute("data-name"), t.getAttribute("data-addr"), t.getAttribute("data-desc"));
|
||
});
|
||
root.addEventListener("click", function (e) {
|
||
var t = e.target.closest(selector);
|
||
if (!t || !t.getAttribute("data-name")) return;
|
||
show(readout, t.getAttribute("data-name"), t.getAttribute("data-addr"), t.getAttribute("data-desc"));
|
||
});
|
||
}
|
||
|
||
// ---- cluster outlines -------------------------------------------
|
||
// Each MFD owns two runs of four keys on staggered rows, so the
|
||
// outline is a stepped polygon that hugs both runs exactly.
|
||
var byCap = {};
|
||
Array.prototype.forEach.call(main.querySelectorAll(".key"), function (el) {
|
||
var cap = el.firstChild ? el.firstChild.textContent : "";
|
||
var id = el.getAttribute("data-id");
|
||
if (id) byCap["#" + id] = el;
|
||
if (cap && !byCap[cap]) byCap[cap] = el;
|
||
});
|
||
|
||
var groups = [
|
||
{ label: "Radar left · secondary", kind: "g-col", top: ["F1", "F6"] },
|
||
{ label: "Radar right · screen", kind: "g-col", top: ["F7", "F12"] },
|
||
{ label: "Upper left MFD", kind: "g-mfd", top: ["1", "4"], bottom: ["Q", "R"] },
|
||
{ label: "Upper middle MFD", kind: "g-mfd", top: ["5", "8"], bottom: ["T", "I"] },
|
||
{ label: "Upper right MFD", kind: "g-mfd", top: ["9", "="], bottom: ["O", "]"] },
|
||
{ label: "Lower left MFD", kind: "g-mfd", top: ["A", "F"], bottom: ["Z", "V"] },
|
||
{ label: "Lower right MFD", kind: "g-mfd", top: ["H", "L"], bottom: ["N", "."] }
|
||
];
|
||
|
||
function drawGroups() {
|
||
var old = kbEl.querySelector(".kb-groups");
|
||
if (old) old.remove();
|
||
|
||
var host = document.createElement("div");
|
||
host.className = "kb-groups";
|
||
var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
||
host.appendChild(svg);
|
||
|
||
var base = kbEl.getBoundingClientRect();
|
||
var pad = 3;
|
||
|
||
function box(a, b) {
|
||
if (!a || !b) return null;
|
||
var ra = a.getBoundingClientRect(), rb = b.getBoundingClientRect();
|
||
return {
|
||
l: ra.left - base.left - pad,
|
||
r: rb.right - base.left + pad,
|
||
t: ra.top - base.top - pad,
|
||
b: ra.bottom - base.top + pad
|
||
};
|
||
}
|
||
|
||
groups.forEach(function (g) {
|
||
var top = box(byCap[g.top[0]], byCap[g.top[1]]);
|
||
if (!top) return;
|
||
var bot = g.bottom ? box(byCap[g.bottom[0]], byCap[g.bottom[1]]) : null;
|
||
var d;
|
||
if (bot) {
|
||
d = "M" + top.l + " " + top.t +
|
||
"H" + top.r + "V" + bot.t +
|
||
"H" + bot.r + "V" + bot.b +
|
||
"H" + bot.l + "V" + top.b +
|
||
"H" + top.l + "Z";
|
||
} else {
|
||
d = "M" + top.l + " " + top.t + "H" + top.r + "V" + top.b + "H" + top.l + "Z";
|
||
}
|
||
var path = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
||
path.setAttribute("d", d);
|
||
path.setAttribute("class", g.kind);
|
||
svg.appendChild(path);
|
||
|
||
var label = document.createElement("span");
|
||
label.className = "g-label " + g.kind;
|
||
label.textContent = g.label;
|
||
label.style.left = top.l + "px";
|
||
label.style.top = top.t + "px";
|
||
host.appendChild(label);
|
||
});
|
||
|
||
kbEl.appendChild(host);
|
||
}
|
||
|
||
drawGroups();
|
||
window.addEventListener("resize", drawGroups);
|
||
if (document.fonts && document.fonts.ready) document.fonts.ready.then(drawGroups);
|
||
|
||
bind(kbEl, rdKb, ".key");
|
||
bind(document.querySelector("svg.pad"), rdPad, ".ctl");
|
||
bind(document.querySelector(".stick-art"), document.getElementById("rd-stick"), ".hot");
|
||
})();
|
||
</script>
|