@rydr/game-sdk 7.0.0 → 7.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -0
- package/dist/protocol/glyphs.d.ts +7 -0
- package/dist/protocol/glyphs.d.ts.map +1 -1
- package/dist/protocol/glyphs.js +26 -0
- package/dist/protocol/glyphs.js.map +1 -1
- package/dist/protocol/version.d.ts +1 -1
- package/dist/protocol/version.js +1 -1
- package/dist/three/perf-overlay.d.ts +52 -2
- package/dist/three/perf-overlay.d.ts.map +1 -1
- package/dist/three/perf-overlay.js +188 -3
- package/dist/three/perf-overlay.js.map +1 -1
- package/dist/ui/README.md +119 -0
- package/dist/ui/controller/combo-demo.d.ts +74 -0
- package/dist/ui/controller/combo-demo.d.ts.map +1 -0
- package/dist/ui/controller/combo-demo.js +295 -0
- package/dist/ui/controller/combo-demo.js.map +1 -0
- package/dist/ui/controller/combo-strip.d.ts +36 -0
- package/dist/ui/controller/combo-strip.d.ts.map +1 -0
- package/dist/ui/controller/combo-strip.js +66 -0
- package/dist/ui/controller/combo-strip.js.map +1 -0
- package/dist/ui/controller/control-trainer.d.ts +132 -0
- package/dist/ui/controller/control-trainer.d.ts.map +1 -0
- package/dist/ui/controller/control-trainer.js +570 -0
- package/dist/ui/controller/control-trainer.js.map +1 -0
- package/dist/ui/controller/controller-map.d.ts +82 -0
- package/dist/ui/controller/controller-map.d.ts.map +1 -0
- package/dist/ui/controller/controller-map.js +291 -0
- package/dist/ui/controller/controller-map.js.map +1 -0
- package/dist/ui/controller/controller-pad.d.ts +122 -0
- package/dist/ui/controller/controller-pad.d.ts.map +1 -0
- package/dist/ui/controller/controller-pad.js +200 -0
- package/dist/ui/controller/controller-pad.js.map +1 -0
- package/dist/ui/controller/index.d.ts +26 -0
- package/dist/ui/controller/index.d.ts.map +1 -0
- package/dist/ui/controller/index.js +26 -0
- package/dist/ui/controller/index.js.map +1 -0
- package/dist/ui/controller/input-chip.d.ts +100 -0
- package/dist/ui/controller/input-chip.d.ts.map +1 -0
- package/dist/ui/controller/input-chip.js +322 -0
- package/dist/ui/controller/input-chip.js.map +1 -0
- package/dist/ui/controller/layouts/dualsense.d.ts +12 -0
- package/dist/ui/controller/layouts/dualsense.d.ts.map +1 -0
- package/dist/ui/controller/layouts/dualsense.js +64 -0
- package/dist/ui/controller/layouts/dualsense.js.map +1 -0
- package/dist/ui/controller/layouts/index.d.ts +20 -0
- package/dist/ui/controller/layouts/index.d.ts.map +1 -0
- package/dist/ui/controller/layouts/index.js +34 -0
- package/dist/ui/controller/layouts/index.js.map +1 -0
- package/dist/ui/controller/layouts/joycon.d.ts +21 -0
- package/dist/ui/controller/layouts/joycon.d.ts.map +1 -0
- package/dist/ui/controller/layouts/joycon.js +76 -0
- package/dist/ui/controller/layouts/joycon.js.map +1 -0
- package/dist/ui/controller/layouts/switch-pro.d.ts +12 -0
- package/dist/ui/controller/layouts/switch-pro.d.ts.map +1 -0
- package/dist/ui/controller/layouts/switch-pro.js +60 -0
- package/dist/ui/controller/layouts/switch-pro.js.map +1 -0
- package/dist/ui/controller/layouts/xbox.d.ts +11 -0
- package/dist/ui/controller/layouts/xbox.d.ts.map +1 -0
- package/dist/ui/controller/layouts/xbox.js +59 -0
- package/dist/ui/controller/layouts/xbox.js.map +1 -0
- package/dist/ui/controller/layouts/zwift.d.ts +27 -0
- package/dist/ui/controller/layouts/zwift.d.ts.map +1 -0
- package/dist/ui/controller/layouts/zwift.js +62 -0
- package/dist/ui/controller/layouts/zwift.js.map +1 -0
- package/dist/ui/controller/pad-svg.d.ts +105 -0
- package/dist/ui/controller/pad-svg.d.ts.map +1 -0
- package/dist/ui/controller/pad-svg.js +289 -0
- package/dist/ui/controller/pad-svg.js.map +1 -0
- package/dist/ui/controller/parts-map.d.ts +96 -0
- package/dist/ui/controller/parts-map.d.ts.map +1 -0
- package/dist/ui/controller/parts-map.js +187 -0
- package/dist/ui/controller/parts-map.js.map +1 -0
- package/dist/ui/controller/styles.d.ts +19 -0
- package/dist/ui/controller/styles.d.ts.map +1 -0
- package/dist/ui/controller/styles.js +364 -0
- package/dist/ui/controller/styles.js.map +1 -0
- package/dist/ui/controller/tokens.d.ts +106 -0
- package/dist/ui/controller/tokens.d.ts.map +1 -0
- package/dist/ui/controller/tokens.js +50 -0
- package/dist/ui/controller/tokens.js.map +1 -0
- package/dist/ui/controller/types.d.ts +157 -0
- package/dist/ui/controller/types.d.ts.map +1 -0
- package/dist/ui/controller/types.js +61 -0
- package/dist/ui/controller/types.js.map +1 -0
- package/dist/ui/index.d.ts +8 -0
- package/dist/ui/index.d.ts.map +1 -1
- package/dist/ui/index.js +8 -0
- package/dist/ui/index.js.map +1 -1
- package/dist/ui/keycap.d.ts +14 -0
- package/dist/ui/keycap.d.ts.map +1 -1
- package/dist/ui/keycap.js +5 -0
- package/dist/ui/keycap.js.map +1 -1
- package/dist/ui/showcase/gallery.d.ts +13 -1
- package/dist/ui/showcase/gallery.d.ts.map +1 -1
- package/dist/ui/showcase/gallery.js.map +1 -1
- package/dist/ui/showcase/index.d.ts.map +1 -1
- package/dist/ui/showcase/index.js +257 -1
- package/dist/ui/showcase/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one SVG renderer for every controller silhouette, plus the animation layer that drives it.
|
|
3
|
+
*
|
|
4
|
+
* `buildPadSvg` emits nodes and hands back the node caches directly — `parts`, `sticks`, `meters`. That
|
|
5
|
+
* is the ONLY coupling between the drawing and whatever animates it: nothing ever re-renders the SVG
|
|
6
|
+
* per frame; a driver mutates classes and attributes on cached nodes. (The platform's Lit version had
|
|
7
|
+
* to re-scan the shadow root with `querySelectorAll` after each render to rebuild these maps; building
|
|
8
|
+
* them as we go is strictly less machinery.)
|
|
9
|
+
*
|
|
10
|
+
* `createPadDriver` is that animation layer. It keeps a `lastVal` dirty-guard so an **idle pad costs
|
|
11
|
+
* zero DOM writes** even when polled at 60 Hz — that guard is not an optimisation to trim, it's the
|
|
12
|
+
* reason this is cheap enough to run beside a game loop.
|
|
13
|
+
*
|
|
14
|
+
* Both are input-agnostic: they know about positions (`PadPart`), never about `ButtonName`s, key codes
|
|
15
|
+
* or gamepad indices. `controller-pad.ts` owns the translation from canonical input to positions.
|
|
16
|
+
*/
|
|
17
|
+
import { partCentre } from "./types.js";
|
|
18
|
+
const NS = "http://www.w3.org/2000/svg";
|
|
19
|
+
/**
|
|
20
|
+
* Parts a game can never bind, so the drawing must never light them.
|
|
21
|
+
*
|
|
22
|
+
* The bumpers are the rider's resistance − / + and `select`/`home` are the shell's own menu and guide —
|
|
23
|
+
* all four are handled by the shell and are never delivered to a game (see `protocol/buttons.ts` on
|
|
24
|
+
* the shell-owned keys). They are still DRAWN, faintly, because a rider needs to tell "this game
|
|
25
|
+
* doesn't use that button" apart from "that button isn't the game's to use".
|
|
26
|
+
*
|
|
27
|
+
* `setPart` refuses them outright rather than trusting callers: today no `ButtonName` maps here, and
|
|
28
|
+
* enforcing it in the driver keeps that true if someone later adds one by mistake.
|
|
29
|
+
*/
|
|
30
|
+
export const SHELL_OWNED_PARTS = new Set(["lb", "rb", "select", "home"]);
|
|
31
|
+
/** Below this, a stick move is sub-pixel at every render size — skip the DOM write entirely. */
|
|
32
|
+
const STICK_EPSILON = 0.02;
|
|
33
|
+
/** Past this deflection the stick glows like a pressed button. Matches the shell's feel. */
|
|
34
|
+
export const STICK_LIT_DEADZONE = 0.18;
|
|
35
|
+
function el(tag, attrs, className) {
|
|
36
|
+
const node = document.createElementNS(NS, tag);
|
|
37
|
+
if (className)
|
|
38
|
+
node.setAttribute("class", className);
|
|
39
|
+
if (attrs)
|
|
40
|
+
for (const [k, v] of Object.entries(attrs))
|
|
41
|
+
node.setAttribute(k, String(v));
|
|
42
|
+
return node;
|
|
43
|
+
}
|
|
44
|
+
function geomEl(g, className) {
|
|
45
|
+
switch (g.kind) {
|
|
46
|
+
case "circle":
|
|
47
|
+
return el("circle", { cx: g.cx, cy: g.cy, r: g.r }, className);
|
|
48
|
+
case "rect":
|
|
49
|
+
return el("rect", { x: g.x, y: g.y, width: g.w, height: g.h, rx: g.rx ?? 2 }, className);
|
|
50
|
+
case "path":
|
|
51
|
+
return el("path", { d: g.d }, className);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function titled(parent, text) {
|
|
55
|
+
const t = el("title");
|
|
56
|
+
t.textContent = text;
|
|
57
|
+
parent.appendChild(t);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* How far a pressed control travels, in viewBox units, and equally how far its shadow sits below it at
|
|
61
|
+
* rest. One number for both, because the effect only reads if the face lands exactly ON its own shadow.
|
|
62
|
+
*/
|
|
63
|
+
export const PRESS_DEPTH = 1.4;
|
|
64
|
+
/**
|
|
65
|
+
* One highlightable part: a `<g data-part>` holding a fixed drop shadow and a `.rydr-pad-face` group
|
|
66
|
+
* (shape + glyph) that sinks onto it when pressed.
|
|
67
|
+
*
|
|
68
|
+
* The shadow is what makes a press read as *down* rather than merely *coloured*. A recolour alone says
|
|
69
|
+
* "this one is involved"; a face that drops onto its own shadow says "this one is held". Same trick as
|
|
70
|
+
* the kit's keycaps, which raise on a `box-shadow` and sink by the same distance — this is the SVG
|
|
71
|
+
* equivalent, since an SVG shape can't take one.
|
|
72
|
+
*
|
|
73
|
+
* The face is a GROUP so the glyph travels with the button; a shape that moved while its letter stayed
|
|
74
|
+
* put would look broken rather than pressed.
|
|
75
|
+
*/
|
|
76
|
+
function buildPart(name, spec, showGlyph, smallGlyph = false) {
|
|
77
|
+
const g = el("g", { "data-part": name }, "rydr-pad-part" + (SHELL_OWNED_PARTS.has(name) ? " shell-owned" : ""));
|
|
78
|
+
titled(g, spec.label);
|
|
79
|
+
const shadow = geomEl(spec.geom, "rydr-pad-shadow");
|
|
80
|
+
shadow.setAttribute("transform", `translate(0 ${PRESS_DEPTH})`);
|
|
81
|
+
g.appendChild(shadow);
|
|
82
|
+
const face = el("g", {}, "rydr-pad-face");
|
|
83
|
+
face.appendChild(geomEl(spec.geom, "rydr-pad-shape"));
|
|
84
|
+
if (showGlyph) {
|
|
85
|
+
const c = partCentre(spec.geom);
|
|
86
|
+
if (spec.glyphPath) {
|
|
87
|
+
// Vector glyph (PlayStation's ✕ ◯ ▢ △), drawn centred on (0,0) then translated onto the part.
|
|
88
|
+
face.appendChild(el("path", { d: spec.glyphPath, transform: `translate(${c.x} ${c.y})` }, "rydr-pad-glyph-vec"));
|
|
89
|
+
}
|
|
90
|
+
else if (spec.glyph) {
|
|
91
|
+
const t = el("text", { x: c.x, y: c.y }, "rydr-pad-glyph" + (smallGlyph ? " sm" : ""));
|
|
92
|
+
t.textContent = spec.glyph;
|
|
93
|
+
face.appendChild(t);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
g.appendChild(face);
|
|
97
|
+
return { g, face };
|
|
98
|
+
}
|
|
99
|
+
/** A trigger: the same part shape, plus a meter rect that fills bottom-up as travel goes 0 → 1. */
|
|
100
|
+
function buildTrigger(name, spec, side, showGlyph) {
|
|
101
|
+
const { g, face } = buildPart(name, spec, false);
|
|
102
|
+
const m = spec.meter;
|
|
103
|
+
// Starts empty: y at the BOTTOM of the band with zero height, so growth reads upward. It lives in the
|
|
104
|
+
// face group so the fill travels down with the trigger instead of hovering where the trigger used to be.
|
|
105
|
+
const meter = el("rect", { "data-meter": side, x: m.x, y: m.y + m.h, width: m.w, height: 0, rx: m.rx ?? 2 }, "rydr-pad-meter");
|
|
106
|
+
face.appendChild(meter);
|
|
107
|
+
if (showGlyph) {
|
|
108
|
+
const c = partCentre(spec.geom);
|
|
109
|
+
const t = el("text", { x: c.x, y: c.y }, "rydr-pad-glyph sm");
|
|
110
|
+
t.textContent = spec.glyph;
|
|
111
|
+
face.appendChild(t);
|
|
112
|
+
}
|
|
113
|
+
return { g, meter };
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Build the drawing for `layout`.
|
|
117
|
+
*
|
|
118
|
+
* Draw order matters and matches the shell's: body → decor → triggers → bumpers → d-pad → face →
|
|
119
|
+
* system → sticks. Sticks come last so a deflected cap draws over the shell rather than under it.
|
|
120
|
+
*/
|
|
121
|
+
export function buildPadSvg(layout, opts = {}) {
|
|
122
|
+
const labels = opts.labels ?? true;
|
|
123
|
+
const [minX, minY, w, h] = layout.viewBox;
|
|
124
|
+
const svg = el("svg", {
|
|
125
|
+
viewBox: `${minX} ${minY} ${w} ${h}`,
|
|
126
|
+
preserveAspectRatio: "xMidYMid meet",
|
|
127
|
+
role: "img",
|
|
128
|
+
"aria-label": `${layout.displayName} — button map`,
|
|
129
|
+
});
|
|
130
|
+
const parts = new Map();
|
|
131
|
+
const sticks = {};
|
|
132
|
+
const meters = {};
|
|
133
|
+
const add = (name, spec, showGlyph, smallGlyph = false) => {
|
|
134
|
+
const { g } = buildPart(name, spec, showGlyph, smallGlyph);
|
|
135
|
+
parts.set(name, g);
|
|
136
|
+
svg.appendChild(g);
|
|
137
|
+
};
|
|
138
|
+
svg.appendChild(el("path", { d: layout.body.d }, "rydr-pad-body"));
|
|
139
|
+
for (const d of layout.decor ?? []) {
|
|
140
|
+
const g = el("g", d.opacity != null ? { opacity: d.opacity } : {}, "rydr-pad-decor");
|
|
141
|
+
g.appendChild(geomEl(d.geom, "rydr-pad-shape"));
|
|
142
|
+
svg.appendChild(g);
|
|
143
|
+
}
|
|
144
|
+
if (layout.triggers) {
|
|
145
|
+
for (const [side, name] of [["l", "lt"], ["r", "rt"]]) {
|
|
146
|
+
const spec = side === "l" ? layout.triggers.l : layout.triggers.r;
|
|
147
|
+
const { g, meter } = buildTrigger(name, spec, side, labels);
|
|
148
|
+
parts.set(name, g);
|
|
149
|
+
meters[side] = meter;
|
|
150
|
+
svg.appendChild(g);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if (layout.bumpers) {
|
|
154
|
+
add("lb", layout.bumpers.l, labels);
|
|
155
|
+
add("rb", layout.bumpers.r, labels);
|
|
156
|
+
}
|
|
157
|
+
if (layout.dpad) {
|
|
158
|
+
// The d-pad never carries a glyph: the arrows are the same on every pad and the arms are too
|
|
159
|
+
// small to letter legibly at this scale.
|
|
160
|
+
add("dpadUp", layout.dpad.up, false);
|
|
161
|
+
add("dpadDown", layout.dpad.down, false);
|
|
162
|
+
add("dpadLeft", layout.dpad.left, false);
|
|
163
|
+
add("dpadRight", layout.dpad.right, false);
|
|
164
|
+
}
|
|
165
|
+
add("faceTop", layout.face.top, labels);
|
|
166
|
+
add("faceRight", layout.face.right, labels);
|
|
167
|
+
add("faceBottom", layout.face.bottom, labels);
|
|
168
|
+
add("faceLeft", layout.face.left, labels);
|
|
169
|
+
if (layout.system?.select)
|
|
170
|
+
add("select", layout.system.select, labels, true);
|
|
171
|
+
if (layout.system?.start)
|
|
172
|
+
add("start", layout.system.start, labels, true);
|
|
173
|
+
if (layout.system?.home)
|
|
174
|
+
add("home", layout.system.home, false);
|
|
175
|
+
if (layout.sticks) {
|
|
176
|
+
for (const [side, pressPart] of [["l", "lstickPress"], ["r", "rstickPress"]]) {
|
|
177
|
+
const spec = side === "l" ? layout.sticks.l : layout.sticks.r;
|
|
178
|
+
const group = el("g", {}, "rydr-pad-stickgrp");
|
|
179
|
+
titled(group, spec.label);
|
|
180
|
+
group.appendChild(el("circle", { cx: spec.cx, cy: spec.cy, r: spec.well }, "rydr-pad-well"));
|
|
181
|
+
// ONE group carries both the translate and `.deflected`. The `[data-part]` node inside it is the
|
|
182
|
+
// stick CLICK, whose `.on` class `setPart` owns — two writers on one class would fight.
|
|
183
|
+
const moving = el("g", { "data-stick": side, transform: "translate(0 0)" }, "rydr-pad-stick");
|
|
184
|
+
// Same shadow-and-face pairing as a button, so CLICKING the stick reads as pressing it down —
|
|
185
|
+
// distinct from deflecting it, which is the outer group's translate.
|
|
186
|
+
const press = el("g", { "data-part": pressPart }, "rydr-pad-part");
|
|
187
|
+
press.appendChild(el("circle", { cx: spec.cx, cy: spec.cy + PRESS_DEPTH, r: spec.cap }, "rydr-pad-shadow"));
|
|
188
|
+
const capFace = el("g", {}, "rydr-pad-face");
|
|
189
|
+
capFace.appendChild(el("circle", { cx: spec.cx, cy: spec.cy, r: spec.cap }, "rydr-pad-shape"));
|
|
190
|
+
press.appendChild(capFace);
|
|
191
|
+
moving.appendChild(press);
|
|
192
|
+
group.appendChild(moving);
|
|
193
|
+
svg.appendChild(group);
|
|
194
|
+
parts.set(pressPart, press);
|
|
195
|
+
sticks[side] = moving;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return { svg, parts, sticks, meters };
|
|
199
|
+
}
|
|
200
|
+
export function createPadDriver(pad, layout, opts = {}) {
|
|
201
|
+
/** Dirty-guard: last value written per key, so an unchanged frame does no DOM work at all. */
|
|
202
|
+
const lastVal = new Map();
|
|
203
|
+
/** Numeric codes, because `lastVal` is a number map (it also holds stick offsets). */
|
|
204
|
+
const STATE_CODE = { off: 0, on: 1, hint: 2, done: 3 };
|
|
205
|
+
const setPartState = (part, state) => {
|
|
206
|
+
if (SHELL_OWNED_PARTS.has(part) && !opts.allowShellOwned)
|
|
207
|
+
return;
|
|
208
|
+
const code = STATE_CODE[state];
|
|
209
|
+
if (lastVal.get(part) === code)
|
|
210
|
+
return;
|
|
211
|
+
lastVal.set(part, code);
|
|
212
|
+
const node = pad.parts.get(part);
|
|
213
|
+
if (!node)
|
|
214
|
+
return;
|
|
215
|
+
node.classList.toggle("on", state === "on");
|
|
216
|
+
node.classList.toggle("hint", state === "hint");
|
|
217
|
+
node.classList.toggle("done", state === "done");
|
|
218
|
+
};
|
|
219
|
+
const setPart = (part, on) => setPartState(part, on ? "on" : "off");
|
|
220
|
+
const setStick = (side, x, y, lit = "auto") => {
|
|
221
|
+
const node = pad.sticks[side];
|
|
222
|
+
if (!node)
|
|
223
|
+
return; // this layout has no stick on that side (Zwift Play has neither)
|
|
224
|
+
// Lit state FIRST, and outside the epsilon guard below: a stick released in a single frame must
|
|
225
|
+
// still stop glowing even though the move itself is too small to redraw.
|
|
226
|
+
const litKey = `${side}lit`;
|
|
227
|
+
const resolved = lit === "auto" ? (Math.hypot(x, y) > STICK_LIT_DEADZONE ? "on" : "off") : lit;
|
|
228
|
+
const code = resolved === "on" ? 1 : resolved === "hint" ? 2 : 0;
|
|
229
|
+
if (lastVal.get(litKey) !== code) {
|
|
230
|
+
lastVal.set(litKey, code);
|
|
231
|
+
node.classList.toggle("deflected", resolved === "on");
|
|
232
|
+
node.classList.toggle("hint", resolved === "hint");
|
|
233
|
+
}
|
|
234
|
+
const travel = (side === "l" ? layout.sticks?.l : layout.sticks?.r)?.travel ?? 0;
|
|
235
|
+
const dx = x * travel;
|
|
236
|
+
// NEGATED, and this is the one line that differs from the shell. The shell feeds raw W3C axes,
|
|
237
|
+
// where stick-DOWN is +1 — the same direction SVG's y grows — so it deliberately does not invert.
|
|
238
|
+
// The SDK's AxisName convention is up = +1 (see protocol/buttons.ts), so here we must.
|
|
239
|
+
const dy = -y * travel;
|
|
240
|
+
const lastX = lastVal.get(`${side}x`) ?? 0;
|
|
241
|
+
const lastY = lastVal.get(`${side}y`) ?? 0;
|
|
242
|
+
if (Math.abs(dx - lastX) < STICK_EPSILON && Math.abs(dy - lastY) < STICK_EPSILON)
|
|
243
|
+
return;
|
|
244
|
+
lastVal.set(`${side}x`, dx);
|
|
245
|
+
lastVal.set(`${side}y`, dy);
|
|
246
|
+
node.setAttribute("transform", `translate(${dx.toFixed(2)} ${dy.toFixed(2)})`);
|
|
247
|
+
};
|
|
248
|
+
const setMeter = (side, v01) => {
|
|
249
|
+
const node = pad.meters[side];
|
|
250
|
+
if (!node)
|
|
251
|
+
return;
|
|
252
|
+
const v = Math.max(0, Math.min(1, v01));
|
|
253
|
+
const key = `${side}m`;
|
|
254
|
+
if (Math.abs((lastVal.get(key) ?? 0) - v) < 0.01)
|
|
255
|
+
return;
|
|
256
|
+
lastVal.set(key, v);
|
|
257
|
+
const m = (side === "l" ? layout.triggers?.l : layout.triggers?.r)?.meter;
|
|
258
|
+
if (!m)
|
|
259
|
+
return;
|
|
260
|
+
const filled = m.h * v;
|
|
261
|
+
node.setAttribute("y", String(m.y + m.h - filled));
|
|
262
|
+
node.setAttribute("height", String(filled));
|
|
263
|
+
};
|
|
264
|
+
return {
|
|
265
|
+
setPart,
|
|
266
|
+
setPartState,
|
|
267
|
+
setStick,
|
|
268
|
+
setMeter,
|
|
269
|
+
setAvailable(available) {
|
|
270
|
+
for (const [name, node] of pad.parts) {
|
|
271
|
+
const dim = available != null && !available.includes(name) && !SHELL_OWNED_PARTS.has(name);
|
|
272
|
+
node.classList.toggle("unavailable", dim);
|
|
273
|
+
}
|
|
274
|
+
},
|
|
275
|
+
clearAll() {
|
|
276
|
+
for (const [name, node] of pad.parts) {
|
|
277
|
+
node.classList.remove("on", "hint", "done");
|
|
278
|
+
lastVal.set(name, 0);
|
|
279
|
+
}
|
|
280
|
+
for (const side of ["l", "r"]) {
|
|
281
|
+
pad.sticks[side]?.classList.remove("deflected", "hint");
|
|
282
|
+
lastVal.delete(`${side}lit`);
|
|
283
|
+
setStick(side, 0, 0, "off");
|
|
284
|
+
setMeter(side, 0);
|
|
285
|
+
}
|
|
286
|
+
},
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
//# sourceMappingURL=pad-svg.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pad-svg.js","sourceRoot":"","sources":["../../../src/ui/controller/pad-svg.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical input → drawn position. This module is where "the game said `DIAMOND_DOWN`" becomes "light
|
|
3
|
+
* the bottom face button", and it is the reason one action list draws correctly on every controller.
|
|
4
|
+
*
|
|
5
|
+
* **It maps to POSITIONS, never to letters.** `DIAMOND_DOWN` → `faceBottom` on every pad; each layout
|
|
6
|
+
* places `faceBottom` where that brand actually puts it, and `buttonLabel()` supplies the letter printed
|
|
7
|
+
* on it. So a Switch Pro (which prints `A` on the RIGHT button and `B` on the bottom) still highlights
|
|
8
|
+
* the bottom button for confirm — only the lettering shifts. Getting that backwards is the single most
|
|
9
|
+
* likely way a controller diagram lies to a rider.
|
|
10
|
+
*
|
|
11
|
+
* There are deliberately TWO lookups, because "which part lights up" and "which part a callout line
|
|
12
|
+
* points at" are not the same question — see {@link litPartOfButton} and {@link anchorPartOfToken}.
|
|
13
|
+
*/
|
|
14
|
+
import type { ButtonName } from "../../protocol/buttons.js";
|
|
15
|
+
import { type ComboToken, type ControlAction, type ControlName, type ShellControl } from "./tokens.js";
|
|
16
|
+
import { type PadLayout, type PadPart, type PartGeom } from "./types.js";
|
|
17
|
+
/**
|
|
18
|
+
* Which part to LIGHT when a button is held.
|
|
19
|
+
*
|
|
20
|
+
* Partial on purpose: the right stick's digital directions (`RUP`/`RDOWN`/`RLEFT`/`RRIGHT`) map to
|
|
21
|
+
* nothing here. Lighting the stick's *click* for a *direction* would be a lie, and the truthful visual
|
|
22
|
+
* already exists — the cap physically moves, driven by the `RX`/`RY` axes, which the platform emits for
|
|
23
|
+
* every controller (quantized to the endpoints on non-hall hardware, and synthesized from the numpad on
|
|
24
|
+
* a keyboard). So a right-stick direction shows up as deflection, not as a highlight.
|
|
25
|
+
*
|
|
26
|
+
* `OPTIONS` lands on `start`, the button labelled "Options" on a DualSense and "Menu" on an Xbox pad —
|
|
27
|
+
* the game's own menu button. The shell's overlay menu is a different key and never reaches a game.
|
|
28
|
+
*/
|
|
29
|
+
export declare const LIT_PART_OF_BUTTON: Readonly<Partial<Record<ButtonName, PadPart>>>;
|
|
30
|
+
/**
|
|
31
|
+
* The shell-owned controls, which have no {@link ButtonName} but do have a place on the drawing: the
|
|
32
|
+
* upper shoulders ARE the rider's resistance − / +.
|
|
33
|
+
*
|
|
34
|
+
* Kept separate from {@link LIT_PART_OF_BUTTON} so that nothing which walks the game vocabulary can
|
|
35
|
+
* accidentally light them — a game never receives these, and the drawing renders them faint by default
|
|
36
|
+
* (see `SHELL_OWNED_PARTS`). Only an explicit opt-in lets them light, which is exactly what a lesson
|
|
37
|
+
* teaching the rider where they are needs.
|
|
38
|
+
*/
|
|
39
|
+
export declare const PART_OF_SHELL_CONTROL: Readonly<Record<ShellControl, PadPart>>;
|
|
40
|
+
export declare function litPartOfButton(name: ButtonName): PadPart | undefined;
|
|
41
|
+
/** The part to light for any control — game button or shell-owned. */
|
|
42
|
+
export declare function litPartOfControl(name: ControlName): PadPart | undefined;
|
|
43
|
+
/** The four canonical directions the LEFT stick shares with the d-pad, and their axis signs. */
|
|
44
|
+
export declare const DPAD_DIRECTIONS: Readonly<Record<"UP" | "DOWN" | "LEFT" | "RIGHT", readonly [number, number]>>;
|
|
45
|
+
/**
|
|
46
|
+
* Which part a callout LINE should point at.
|
|
47
|
+
*
|
|
48
|
+
* Differs from {@link litPartOfButton} in exactly one way: a right-stick direction (or a bare stick
|
|
49
|
+
* token) resolves to that stick, because "this action uses the right stick" is precisely what the line
|
|
50
|
+
* should be saying — even though a *direction* shouldn't light the stick's click.
|
|
51
|
+
*/
|
|
52
|
+
export declare function anchorPartOfToken(token: ComboToken): PadPart | undefined;
|
|
53
|
+
/**
|
|
54
|
+
* The movement controls that many actions share, so a callout line to one of them says nothing useful.
|
|
55
|
+
*
|
|
56
|
+
* Both sticks (whole or directional), both stick clicks, the d-pad, and the right-stick directions. In a
|
|
57
|
+
* game where the left stick steers, half the actions mention it; anchoring all their lines there makes a
|
|
58
|
+
* hairball around one part, while the distinctive button in each combination is what actually identifies
|
|
59
|
+
* the action.
|
|
60
|
+
*/
|
|
61
|
+
export declare function isGenericToken(token: ComboToken): boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Which token the callout line points at: **the first non-generic token**, falling back to the first
|
|
64
|
+
* token when every one of them is generic.
|
|
65
|
+
*
|
|
66
|
+
* ["LSTICK_PRESS", "LT"] → LT (the distinctive button, not the shared stick)
|
|
67
|
+
* ["LSTICK:left", "RT"] → RT
|
|
68
|
+
* ["LT", "DIAMOND_DOWN"] → LT (first, since neither is generic)
|
|
69
|
+
* ["LSTICK"] → LSTICK (all generic → the first, so "Move" points at the stick)
|
|
70
|
+
* ["DIAMOND_DOWN"] → DIAMOND_DOWN
|
|
71
|
+
*
|
|
72
|
+
* `action.anchor` overrides this outright, so the rule is a sensible default rather than a ceiling.
|
|
73
|
+
*/
|
|
74
|
+
export declare function anchorTokenOf(action: ControlAction): ComboToken | undefined;
|
|
75
|
+
/**
|
|
76
|
+
* The geometry of a drawn part in a given layout, or `undefined` when that layout has no such part (a
|
|
77
|
+
* Zwift pod has no sticks, no triggers and no system buttons).
|
|
78
|
+
*
|
|
79
|
+
* Stick clicks are synthesised from the {@link StickSpec} — the cap circle — since they have no
|
|
80
|
+
* `PartSpec` of their own.
|
|
81
|
+
*/
|
|
82
|
+
export declare function partGeomOf(layout: PadLayout, part: PadPart): PartGeom | undefined;
|
|
83
|
+
/** Where a part sits in the layout's own viewBox units, for ordering and side placement. */
|
|
84
|
+
export declare function partCentreOf(layout: PadLayout, part: PadPart): {
|
|
85
|
+
x: number;
|
|
86
|
+
y: number;
|
|
87
|
+
} | undefined;
|
|
88
|
+
/**
|
|
89
|
+
* Which column a callout belongs in: the side of the pad its anchor is physically on.
|
|
90
|
+
*
|
|
91
|
+
* Derived from the layout rather than hardcoded per brand, so it stays right across four very different
|
|
92
|
+
* control arrangements — Xbox's diagonal offset, DualSense's symmetric sticks, and the two-pod shapes —
|
|
93
|
+
* and for any layout added later.
|
|
94
|
+
*/
|
|
95
|
+
export declare function sideOfPart(layout: PadLayout, part: PadPart): "left" | "right";
|
|
96
|
+
//# sourceMappingURL=parts-map.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parts-map.d.ts","sourceRoot":"","sources":["../../../src/ui/controller/parts-map.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAA8B,KAAK,UAAU,EAAE,KAAK,aAAa,EAAE,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AACnI,OAAO,EAAc,KAAK,SAAS,EAAE,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,CAAC;AAErF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,kBAAkB,EAAE,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,CAc7E,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,qBAAqB,EAAE,QAAQ,CAAC,MAAM,CAAC,YAAY,EAAE,OAAO,CAAC,CAGzE,CAAC;AAEF,wBAAgB,eAAe,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,GAAG,SAAS,CAErE;AAED,sEAAsE;AACtE,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,GAAG,SAAS,CAEvE;AAED,gGAAgG;AAChG,eAAO,MAAM,eAAe,EAAE,QAAQ,CAAC,MAAM,CAAC,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAKzG,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,GAAG,SAAS,CAYxE;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAkBzD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,UAAU,GAAG,SAAS,CAG3E;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,SAAS,CA0BjF;AAED,4FAA4F;AAC5F,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAGnG;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,CAI7E"}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical input → drawn position. This module is where "the game said `DIAMOND_DOWN`" becomes "light
|
|
3
|
+
* the bottom face button", and it is the reason one action list draws correctly on every controller.
|
|
4
|
+
*
|
|
5
|
+
* **It maps to POSITIONS, never to letters.** `DIAMOND_DOWN` → `faceBottom` on every pad; each layout
|
|
6
|
+
* places `faceBottom` where that brand actually puts it, and `buttonLabel()` supplies the letter printed
|
|
7
|
+
* on it. So a Switch Pro (which prints `A` on the RIGHT button and `B` on the bottom) still highlights
|
|
8
|
+
* the bottom button for confirm — only the lettering shifts. Getting that backwards is the single most
|
|
9
|
+
* likely way a controller diagram lies to a rider.
|
|
10
|
+
*
|
|
11
|
+
* There are deliberately TWO lookups, because "which part lights up" and "which part a callout line
|
|
12
|
+
* points at" are not the same question — see {@link litPartOfButton} and {@link anchorPartOfToken}.
|
|
13
|
+
*/
|
|
14
|
+
import { isShellControl, parseToken } from "./tokens.js";
|
|
15
|
+
import { partCentre } from "./types.js";
|
|
16
|
+
/**
|
|
17
|
+
* Which part to LIGHT when a button is held.
|
|
18
|
+
*
|
|
19
|
+
* Partial on purpose: the right stick's digital directions (`RUP`/`RDOWN`/`RLEFT`/`RRIGHT`) map to
|
|
20
|
+
* nothing here. Lighting the stick's *click* for a *direction* would be a lie, and the truthful visual
|
|
21
|
+
* already exists — the cap physically moves, driven by the `RX`/`RY` axes, which the platform emits for
|
|
22
|
+
* every controller (quantized to the endpoints on non-hall hardware, and synthesized from the numpad on
|
|
23
|
+
* a keyboard). So a right-stick direction shows up as deflection, not as a highlight.
|
|
24
|
+
*
|
|
25
|
+
* `OPTIONS` lands on `start`, the button labelled "Options" on a DualSense and "Menu" on an Xbox pad —
|
|
26
|
+
* the game's own menu button. The shell's overlay menu is a different key and never reaches a game.
|
|
27
|
+
*/
|
|
28
|
+
export const LIT_PART_OF_BUTTON = {
|
|
29
|
+
UP: "dpadUp",
|
|
30
|
+
DOWN: "dpadDown",
|
|
31
|
+
LEFT: "dpadLeft",
|
|
32
|
+
RIGHT: "dpadRight",
|
|
33
|
+
DIAMOND_UP: "faceTop",
|
|
34
|
+
DIAMOND_RIGHT: "faceRight",
|
|
35
|
+
DIAMOND_DOWN: "faceBottom",
|
|
36
|
+
DIAMOND_LEFT: "faceLeft",
|
|
37
|
+
LT: "lt",
|
|
38
|
+
RT: "rt",
|
|
39
|
+
LSTICK_PRESS: "lstickPress",
|
|
40
|
+
RSTICK_PRESS: "rstickPress",
|
|
41
|
+
OPTIONS: "start",
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* The shell-owned controls, which have no {@link ButtonName} but do have a place on the drawing: the
|
|
45
|
+
* upper shoulders ARE the rider's resistance − / +.
|
|
46
|
+
*
|
|
47
|
+
* Kept separate from {@link LIT_PART_OF_BUTTON} so that nothing which walks the game vocabulary can
|
|
48
|
+
* accidentally light them — a game never receives these, and the drawing renders them faint by default
|
|
49
|
+
* (see `SHELL_OWNED_PARTS`). Only an explicit opt-in lets them light, which is exactly what a lesson
|
|
50
|
+
* teaching the rider where they are needs.
|
|
51
|
+
*/
|
|
52
|
+
export const PART_OF_SHELL_CONTROL = {
|
|
53
|
+
LB: "lb",
|
|
54
|
+
RB: "rb",
|
|
55
|
+
};
|
|
56
|
+
export function litPartOfButton(name) {
|
|
57
|
+
return LIT_PART_OF_BUTTON[name];
|
|
58
|
+
}
|
|
59
|
+
/** The part to light for any control — game button or shell-owned. */
|
|
60
|
+
export function litPartOfControl(name) {
|
|
61
|
+
return isShellControl(name) ? PART_OF_SHELL_CONTROL[name] : LIT_PART_OF_BUTTON[name];
|
|
62
|
+
}
|
|
63
|
+
/** The four canonical directions the LEFT stick shares with the d-pad, and their axis signs. */
|
|
64
|
+
export const DPAD_DIRECTIONS = {
|
|
65
|
+
UP: [0, 1],
|
|
66
|
+
DOWN: [0, -1],
|
|
67
|
+
LEFT: [-1, 0],
|
|
68
|
+
RIGHT: [1, 0],
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* Which part a callout LINE should point at.
|
|
72
|
+
*
|
|
73
|
+
* Differs from {@link litPartOfButton} in exactly one way: a right-stick direction (or a bare stick
|
|
74
|
+
* token) resolves to that stick, because "this action uses the right stick" is precisely what the line
|
|
75
|
+
* should be saying — even though a *direction* shouldn't light the stick's click.
|
|
76
|
+
*/
|
|
77
|
+
export function anchorPartOfToken(token) {
|
|
78
|
+
const t = parseToken(token);
|
|
79
|
+
if (t.kind === "stick")
|
|
80
|
+
return t.stick === "LSTICK" ? "lstickPress" : "rstickPress";
|
|
81
|
+
switch (t.name) {
|
|
82
|
+
case "RUP":
|
|
83
|
+
case "RDOWN":
|
|
84
|
+
case "RLEFT":
|
|
85
|
+
case "RRIGHT":
|
|
86
|
+
return "rstickPress";
|
|
87
|
+
default:
|
|
88
|
+
return litPartOfControl(t.name);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* The movement controls that many actions share, so a callout line to one of them says nothing useful.
|
|
93
|
+
*
|
|
94
|
+
* Both sticks (whole or directional), both stick clicks, the d-pad, and the right-stick directions. In a
|
|
95
|
+
* game where the left stick steers, half the actions mention it; anchoring all their lines there makes a
|
|
96
|
+
* hairball around one part, while the distinctive button in each combination is what actually identifies
|
|
97
|
+
* the action.
|
|
98
|
+
*/
|
|
99
|
+
export function isGenericToken(token) {
|
|
100
|
+
const t = parseToken(token);
|
|
101
|
+
if (t.kind === "stick")
|
|
102
|
+
return true;
|
|
103
|
+
switch (t.name) {
|
|
104
|
+
case "UP":
|
|
105
|
+
case "DOWN":
|
|
106
|
+
case "LEFT":
|
|
107
|
+
case "RIGHT":
|
|
108
|
+
case "RUP":
|
|
109
|
+
case "RDOWN":
|
|
110
|
+
case "RLEFT":
|
|
111
|
+
case "RRIGHT":
|
|
112
|
+
case "LSTICK_PRESS":
|
|
113
|
+
case "RSTICK_PRESS":
|
|
114
|
+
return true;
|
|
115
|
+
default:
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Which token the callout line points at: **the first non-generic token**, falling back to the first
|
|
121
|
+
* token when every one of them is generic.
|
|
122
|
+
*
|
|
123
|
+
* ["LSTICK_PRESS", "LT"] → LT (the distinctive button, not the shared stick)
|
|
124
|
+
* ["LSTICK:left", "RT"] → RT
|
|
125
|
+
* ["LT", "DIAMOND_DOWN"] → LT (first, since neither is generic)
|
|
126
|
+
* ["LSTICK"] → LSTICK (all generic → the first, so "Move" points at the stick)
|
|
127
|
+
* ["DIAMOND_DOWN"] → DIAMOND_DOWN
|
|
128
|
+
*
|
|
129
|
+
* `action.anchor` overrides this outright, so the rule is a sensible default rather than a ceiling.
|
|
130
|
+
*/
|
|
131
|
+
export function anchorTokenOf(action) {
|
|
132
|
+
if (action.anchor)
|
|
133
|
+
return action.anchor;
|
|
134
|
+
return action.combo.find((t) => !isGenericToken(t)) ?? action.combo[0];
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* The geometry of a drawn part in a given layout, or `undefined` when that layout has no such part (a
|
|
138
|
+
* Zwift pod has no sticks, no triggers and no system buttons).
|
|
139
|
+
*
|
|
140
|
+
* Stick clicks are synthesised from the {@link StickSpec} — the cap circle — since they have no
|
|
141
|
+
* `PartSpec` of their own.
|
|
142
|
+
*/
|
|
143
|
+
export function partGeomOf(layout, part) {
|
|
144
|
+
switch (part) {
|
|
145
|
+
case "dpadUp": return layout.dpad?.up.geom;
|
|
146
|
+
case "dpadDown": return layout.dpad?.down.geom;
|
|
147
|
+
case "dpadLeft": return layout.dpad?.left.geom;
|
|
148
|
+
case "dpadRight": return layout.dpad?.right.geom;
|
|
149
|
+
case "faceTop": return layout.face.top.geom;
|
|
150
|
+
case "faceRight": return layout.face.right.geom;
|
|
151
|
+
case "faceBottom": return layout.face.bottom.geom;
|
|
152
|
+
case "faceLeft": return layout.face.left.geom;
|
|
153
|
+
case "lb": return layout.bumpers?.l.geom;
|
|
154
|
+
case "rb": return layout.bumpers?.r.geom;
|
|
155
|
+
case "lt": return layout.triggers?.l.geom;
|
|
156
|
+
case "rt": return layout.triggers?.r.geom;
|
|
157
|
+
case "start": return layout.system?.start?.geom;
|
|
158
|
+
case "select": return layout.system?.select?.geom;
|
|
159
|
+
case "home": return layout.system?.home?.geom;
|
|
160
|
+
case "lstickPress": {
|
|
161
|
+
const s = layout.sticks?.l;
|
|
162
|
+
return s && { kind: "circle", cx: s.cx, cy: s.cy, r: s.cap };
|
|
163
|
+
}
|
|
164
|
+
case "rstickPress": {
|
|
165
|
+
const s = layout.sticks?.r;
|
|
166
|
+
return s && { kind: "circle", cx: s.cx, cy: s.cy, r: s.cap };
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/** Where a part sits in the layout's own viewBox units, for ordering and side placement. */
|
|
171
|
+
export function partCentreOf(layout, part) {
|
|
172
|
+
const geom = partGeomOf(layout, part);
|
|
173
|
+
return geom && partCentre(geom);
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Which column a callout belongs in: the side of the pad its anchor is physically on.
|
|
177
|
+
*
|
|
178
|
+
* Derived from the layout rather than hardcoded per brand, so it stays right across four very different
|
|
179
|
+
* control arrangements — Xbox's diagonal offset, DualSense's symmetric sticks, and the two-pod shapes —
|
|
180
|
+
* and for any layout added later.
|
|
181
|
+
*/
|
|
182
|
+
export function sideOfPart(layout, part) {
|
|
183
|
+
const centre = partCentreOf(layout, part);
|
|
184
|
+
const midX = layout.viewBox[0] + layout.viewBox[2] / 2;
|
|
185
|
+
return (centre?.x ?? midX) < midX ? "left" : "right";
|
|
186
|
+
}
|
|
187
|
+
//# sourceMappingURL=parts-map.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parts-map.js","sourceRoot":"","sources":["../../../src/ui/controller/parts-map.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAE,cAAc,EAAE,UAAU,EAA4E,MAAM,aAAa,CAAC;AACnI,OAAO,EAAE,UAAU,EAA+C,MAAM,YAAY,CAAC;AAErF;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAmD;IAChF,EAAE,EAAE,QAAQ;IACZ,IAAI,EAAE,UAAU;IAChB,IAAI,EAAE,UAAU;IAChB,KAAK,EAAE,WAAW;IAClB,UAAU,EAAE,SAAS;IACrB,aAAa,EAAE,WAAW;IAC1B,YAAY,EAAE,YAAY;IAC1B,YAAY,EAAE,UAAU;IACxB,EAAE,EAAE,IAAI;IACR,EAAE,EAAE,IAAI;IACR,YAAY,EAAE,aAAa;IAC3B,YAAY,EAAE,aAAa;IAC3B,OAAO,EAAE,OAAO;CACjB,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAA4C;IAC5E,EAAE,EAAE,IAAI;IACR,EAAE,EAAE,IAAI;CACT,CAAC;AAEF,MAAM,UAAU,eAAe,CAAC,IAAgB;IAC9C,OAAO,kBAAkB,CAAC,IAAI,CAAC,CAAC;AAClC,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,gBAAgB,CAAC,IAAiB;IAChD,OAAO,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC;AACvF,CAAC;AAED,gGAAgG;AAChG,MAAM,CAAC,MAAM,eAAe,GAAkF;IAC5G,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;IACV,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACb,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACb,KAAK,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;CACd,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAiB;IACjD,MAAM,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IAC5B,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO;QAAE,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,aAAa,CAAC;IACpF,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;QACf,KAAK,KAAK,CAAC;QACX,KAAK,OAAO,CAAC;QACb,KAAK,OAAO,CAAC;QACb,KAAK,QAAQ;YACX,OAAO,aAAa,CAAC;QACvB;YACE,OAAO,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAC,KAAiB;IAC9C,MAAM,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IAC5B,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO;QAAE,OAAO,IAAI,CAAC;IACpC,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;QACf,KAAK,IAAI,CAAC;QACV,KAAK,MAAM,CAAC;QACZ,KAAK,MAAM,CAAC;QACZ,KAAK,OAAO,CAAC;QACb,KAAK,KAAK,CAAC;QACX,KAAK,OAAO,CAAC;QACb,KAAK,OAAO,CAAC;QACb,KAAK,QAAQ,CAAC;QACd,KAAK,cAAc,CAAC;QACpB,KAAK,cAAc;YACjB,OAAO,IAAI,CAAC;QACd;YACE,OAAO,KAAK,CAAC;IACjB,CAAC;AACH,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,aAAa,CAAC,MAAqB;IACjD,IAAI,MAAM,CAAC,MAAM;QAAE,OAAO,MAAM,CAAC,MAAM,CAAC;IACxC,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACzE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CAAC,MAAiB,EAAE,IAAa;IACzD,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,QAAQ,CAAC,CAAC,OAAO,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC;QAC3C,KAAK,UAAU,CAAC,CAAC,OAAO,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC;QAC/C,KAAK,UAAU,CAAC,CAAC,OAAO,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC;QAC/C,KAAK,WAAW,CAAC,CAAC,OAAO,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC;QACjD,KAAK,SAAS,CAAC,CAAC,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;QAC5C,KAAK,WAAW,CAAC,CAAC,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;QAChD,KAAK,YAAY,CAAC,CAAC,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;QAClD,KAAK,UAAU,CAAC,CAAC,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;QAC9C,KAAK,IAAI,CAAC,CAAC,OAAO,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC;QACzC,KAAK,IAAI,CAAC,CAAC,OAAO,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC;QACzC,KAAK,IAAI,CAAC,CAAC,OAAO,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC;QAC1C,KAAK,IAAI,CAAC,CAAC,OAAO,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC;QAC1C,KAAK,OAAO,CAAC,CAAC,OAAO,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC;QAChD,KAAK,QAAQ,CAAC,CAAC,OAAO,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC;QAClD,KAAK,MAAM,CAAC,CAAC,OAAO,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC;QAC9C,KAAK,aAAa,CAAC,CAAC,CAAC;YACnB,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;YAC3B,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC;QAC/D,CAAC;QACD,KAAK,aAAa,CAAC,CAAC,CAAC;YACnB,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;YAC3B,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC;QAC/D,CAAC;IACH,CAAC;AACH,CAAC;AAED,4FAA4F;AAC5F,MAAM,UAAU,YAAY,CAAC,MAAiB,EAAE,IAAa;IAC3D,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACtC,OAAO,IAAI,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC;AAClC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CAAC,MAAiB,EAAE,IAAa;IACzD,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC1C,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACvD,OAAO,CAAC,MAAM,EAAE,CAAC,IAAI,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;AACvD,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scoped `.rydr-pad-*` CSS for the controller family — the pad drawing, the input chips, the static
|
|
3
|
+
* controller map and the combo demo — injected once into `<head>`.
|
|
4
|
+
*
|
|
5
|
+
* Self-contained like the rest of `@rydr/game-sdk/ui`: no global styles, no dependence on host CSS
|
|
6
|
+
* variables, no font loading. The pad's own tokens (`--pad-body`, `--pad-accent`, …) are declared on
|
|
7
|
+
* `.rydr-pad` itself, so a caller theming the accent sets ONE property via the `accent` option rather
|
|
8
|
+
* than reaching into this stylesheet.
|
|
9
|
+
*
|
|
10
|
+
* Ported from the platform shell's `rydr-controller-diagram.ts`, with `:host` rewritten to `.rydr-pad`
|
|
11
|
+
* and every internal class prefixed — the shell had shadow DOM to scope bare `.part` / `.shape` names;
|
|
12
|
+
* we don't, so the prefix IS the scoping.
|
|
13
|
+
*
|
|
14
|
+
* The type sizes and dimensions here are tuned for a **trainer screen read from a few feet away while
|
|
15
|
+
* pedaling**, exactly as the rest of the kit. They are part of the contract, not defaults to override.
|
|
16
|
+
*/
|
|
17
|
+
/** Force the controller CSS into `<head>`. Components call this for you; idempotent. */
|
|
18
|
+
export declare function injectPadCss(): void;
|
|
19
|
+
//# sourceMappingURL=styles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../../src/ui/controller/styles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,wFAAwF;AACxF,wBAAgB,YAAY,IAAI,IAAI,CAUnC"}
|