@rydr/game-sdk 7.1.0 → 8.0.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.
Files changed (39) hide show
  1. package/README.md +28 -4
  2. package/dist/client/PlatformClient.d.ts +14 -7
  3. package/dist/client/PlatformClient.d.ts.map +1 -1
  4. package/dist/client/PlatformClient.js.map +1 -1
  5. package/dist/difficulty/index.d.ts +141 -0
  6. package/dist/difficulty/index.d.ts.map +1 -0
  7. package/dist/difficulty/index.js +300 -0
  8. package/dist/difficulty/index.js.map +1 -0
  9. package/dist/nav/README.md +1 -1
  10. package/dist/protocol/version.d.ts +1 -1
  11. package/dist/protocol/version.js +1 -1
  12. package/dist/ui/README.md +28 -15
  13. package/dist/ui/action-diamond.js +1 -1
  14. package/dist/ui/action-diamond.js.map +1 -1
  15. package/dist/ui/controller/input-chip.d.ts +2 -1
  16. package/dist/ui/controller/input-chip.d.ts.map +1 -1
  17. package/dist/ui/controller/input-chip.js +9 -8
  18. package/dist/ui/controller/input-chip.js.map +1 -1
  19. package/dist/ui/index.d.ts +1 -1
  20. package/dist/ui/index.d.ts.map +1 -1
  21. package/dist/ui/index.js +1 -1
  22. package/dist/ui/index.js.map +1 -1
  23. package/dist/ui/keycap.d.ts +51 -20
  24. package/dist/ui/keycap.d.ts.map +1 -1
  25. package/dist/ui/keycap.js +94 -28
  26. package/dist/ui/keycap.js.map +1 -1
  27. package/dist/ui/{pause-menu.d.ts → option-menu.d.ts} +34 -24
  28. package/dist/ui/option-menu.d.ts.map +1 -0
  29. package/dist/ui/{pause-menu.js → option-menu.js} +134 -90
  30. package/dist/ui/option-menu.js.map +1 -0
  31. package/dist/ui/showcase/index.js +9 -9
  32. package/dist/ui/showcase/index.js.map +1 -1
  33. package/dist/ui/solo-labeled-diamond.js +1 -1
  34. package/dist/ui/solo-labeled-diamond.js.map +1 -1
  35. package/dist/ui/styles.js +14 -9
  36. package/dist/ui/styles.js.map +1 -1
  37. package/package.json +5 -1
  38. package/dist/ui/pause-menu.d.ts.map +0 -1
  39. package/dist/ui/pause-menu.js.map +0 -1
@@ -2,20 +2,26 @@
2
2
  * KEYCAP — a DOM/CSS keycap of the controller face buttons (zero dependencies), so a game can show
3
3
  * "which button to press" in a consistent visual language. Two shapes:
4
4
  *
5
- * • "full" — the classic diamond: the active button enlarged + coloured, the other three small + grey.
5
+ * • "full" — the classic diamond: the active button enlarged, the other three small + grey.
6
6
  * • "solo" — light variation: JUST the active button (the idle siblings removed).
7
7
  *
8
8
  * The keycap is a small STATE MACHINE: it can pulse (the bouncing attract animation), show a pressed
9
- * sink, run a depleting COOLDOWN ring + countdown, render colored or neutral ("mono"), and hide.
9
+ * sink, run a depleting COOLDOWN ring + countdown, and hide.
10
+ *
11
+ * **Mono by default** — a white face with a dark letter, which is the RYDR look everywhere (the shell
12
+ * draws all of its own chrome that way). The per-button role hues still exist behind
13
+ * `colored: true`, for a deliberately loud isolated affordance or to show the palette itself.
10
14
  *
11
15
  * Two button families share that machine: `createKeycap` for the A/B/Y/Z face buttons (a letter on
12
16
  * the active pip) and `createDpadKeycap` for the UP/DOWN/LEFT/RIGHT directional buttons (a white
13
17
  * chevron on a steel-grey pip, rotated per direction). They differ ONLY in the face drawn and the
14
18
  * button name the press-wiring listens for; everything else is identical.
15
19
  *
16
- * A third factory, `createLabelKeycap`, covers the buttons whose printed name is a WORD rather than a
17
- * letterthe system/options button, the shoulder triggers, the stick clicks as a PILL instead of a
18
- * circle, since "Options" cannot fit in a pip sized for one glyph.
20
+ * A third factory, `createButtonKeycap`, covers what's left the system/options button, the shoulder
21
+ * triggers, the stick clicks and draws each the way the pad does: `OPTIONS` as a round pip with the
22
+ * pad's ICON (`☰` on Xbox/DualSense, `+` on a Switch Pro), since it's a small round key like the
23
+ * others; the triggers and stick clicks as a text PILL, since those are printed with a word ("LT",
24
+ * "L2", "LS") that no pip sized for one glyph could hold.
19
25
  */
20
26
  import type { ButtonName, ButtonEdge } from "../protocol/index.js";
21
27
  import { type GlyphSet } from "../protocol/glyphs.js";
@@ -40,7 +46,12 @@ export interface ButtonSource {
40
46
  export interface KeycapOptions {
41
47
  /** "solo" (default) shows only the active button; "full" shows the 4-button diamond. */
42
48
  variant?: KeycapVariant;
43
- /** Per-button hue (default true). `false` → a neutral palette (full colour can be too loud). */
49
+ /**
50
+ * Per-button hue. **Default `false` — mono** (a white face with a dark letter), which is the RYDR
51
+ * look: the shell draws every keycap in its chrome that way, so a coloured cap is the one loud key
52
+ * on the screen. Pass `true` only for a deliberately loud, isolated affordance (or to show the
53
+ * palette itself, as the showcase does).
54
+ */
44
55
  colored?: boolean;
45
56
  /** Run the bouncing pulse on the active button (default true). */
46
57
  animate?: boolean;
@@ -55,6 +66,20 @@ export interface KeycapOptions {
55
66
  * a settings screen, a showcase, a screenshot.
56
67
  */
57
68
  glyphSet?: GlyphSet;
69
+ /**
70
+ * Size multiplier for the whole keycap — pip diameter, letter, glyph and (on the pill shape) its
71
+ * height, padding and type. Default `1`.
72
+ *
73
+ * **This is the ONLY sanctioned way to make a keycap smaller.** The kit's rule against restyling
74
+ * stands: don't override the `.rydr-ui-*` sizes and never wrap a cap in `transform: scale()`, which
75
+ * leaves a full-size layout box, blurs the text and breaks any positioning done against it. This
76
+ * option resizes the real geometry instead, so layout stays honest.
77
+ *
78
+ * For **secondary** emphasis only — a hint the rider *may* use (the option menu's `Shortcut` caps ride
79
+ * at `0.65`), never a primary prompt. A prompt telling the rider what to press now stays at `1`: full
80
+ * size is what keeps it legible from a few feet away on a trainer.
81
+ */
82
+ scale?: number;
58
83
  }
59
84
  /** A bare keycap with its state setters. */
60
85
  export interface Keycap {
@@ -101,24 +126,30 @@ export interface Keycap {
101
126
  */
102
127
  export declare function createKeycap(button: DiamondButton, opts?: KeycapOptions): Keycap;
103
128
  /**
104
- * Build a keycap for a button whose printed name is a **word, not a letter** — the system/options
105
- * button (`OPTIONS` → "Menu" / "Options" / "+"), the shoulder triggers (`LT`/`RT` "LT" / "L2" / "ZL")
106
- * and the stick clicks (`LSTICK_PRESS`/`RSTICK_PRESS` "LS" / "L3" / "L").
129
+ * Build a keycap for the buttons that carry neither a face letter nor a direction — the system/options
130
+ * button (`OPTIONS`), the shoulder triggers (`LT`/`RT`) and the stick clicks
131
+ * (`LSTICK_PRESS`/`RSTICK_PRESS`) drawn the way the rider's pad actually draws them:
132
+ *
133
+ * • **`OPTIONS` → a round pip with the pad's ICON** (`☰` on Xbox/DualSense, `+` on a Switch Pro).
134
+ * It is a small round key on every pad, so it gets the same circular pip as the d-pad's chevron and
135
+ * sits in the same visual family as the face buttons.
136
+ * • **everything else → a text PILL** carrying {@link buttonLabel} ("LT" / "L2" / "ZL", "LS" / "L3"),
137
+ * because those buttons really are printed with a *word*, and no word fits a pip sized for one
138
+ * glyph. The trigger hardware isn't round either.
107
139
  *
108
- * A **pill** rather than a circular pip, because "Options" does not fit in a pip sized for one glyph.
109
- * Everything else is the pip's own language reused verbatim (raised lip, pulse, pressed sink, inert
110
- * grey), so the two shapes read as one family, and the text still comes from {@link buttonLabel} — the
111
- * rule that no letter is ever hardcoded holds here too.
140
+ * Either way the state machine is the pip's, reused verbatim (raised lip, pulse, pressed sink, inert
141
+ * grey), and nothing is hardcoded per brand: the icon comes from {@link SYSTEM_ICON} and the text from
142
+ * {@link buttonLabel}.
112
143
  *
113
- * Steel-grey by default (a system button is never the confirm/back hue), and — unlike the pip
114
- * factories — the attract pulse is **off** unless asked for: these caps label a shortcut the rider can
115
- * take, not an action being demanded of them. `setCooldown` is accepted for interface parity but draws
116
- * nothing: these buttons open menus, they don't gate timed abilities.
144
+ * Steel-grey (these are never the confirm/back hues), and — unlike the pip factories — the attract
145
+ * pulse is **off** unless asked for: these caps label a shortcut the rider *can* take, not an action
146
+ * being demanded of them. `setCooldown` is accepted for interface parity but draws nothing on the pill:
147
+ * these buttons open menus, they don't gate timed abilities.
117
148
  *
118
- * Pass a face-diamond or d-pad button here and you get its letter/arrow in a pill — legal, but prefer
119
- * {@link createKeycap} / {@link createDpadKeycap}, which draw the real button shape.
149
+ * Pass a face-diamond or d-pad button here and you get its letter in a pill — legal, but prefer
150
+ * {@link createKeycap} / {@link createDpadKeycap}, which draw those buttons' real shapes.
120
151
  */
121
- export declare function createLabelKeycap(button: ButtonName, opts?: KeycapOptions): Keycap;
152
+ export declare function createButtonKeycap(button: ButtonName, opts?: KeycapOptions): Keycap;
122
153
  /**
123
154
  * Build a bare directional (UP/DOWN/LEFT/RIGHT) keycap. Identical state machine to {@link createKeycap}
124
155
  * — solo/full, pulse, pressed, cooldown ring — only the active button shows a WHITE chevron (rotated
@@ -1 +1 @@
1
- {"version":3,"file":"keycap.d.ts","sourceRoot":"","sources":["../../src/ui/keycap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAkC,KAAK,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAGtF,+FAA+F;AAC/F,MAAM,MAAM,aAAa,GAAG,YAAY,GAAG,cAAc,GAAG,cAAc,GAAG,eAAe,CAAC;AAC7F,8EAA8E;AAC9E,MAAM,MAAM,SAAS,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AACzD,sEAAsE;AACtE,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,MAAM,CAAC;AAC5C,8CAA8C;AAC9C,MAAM,MAAM,cAAc,GAAG,aAAa,CAAC;AAE3C;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE;QAAE,IAAI,EAAE,UAAU,CAAC;QAAC,IAAI,EAAE,UAAU,CAAA;KAAE,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;CAC/E;AAoBD,MAAM,WAAW,aAAa;IAC5B,wFAAwF;IACxF,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,gGAAgG;IAChG,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,kEAAkE;IAClE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;OAGG;IACH,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAED,4CAA4C;AAC5C,MAAM,WAAW,MAAM;IACrB,mDAAmD;IACnD,EAAE,EAAE,WAAW,CAAC;IAChB,uCAAuC;IACvC,UAAU,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAAC;IAC9B,2CAA2C;IAC3C,WAAW,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAAC;IAC/B;;;OAGG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAChE,6BAA6B;IAC7B,UAAU,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAAC;IAC9B;;;;;;;;;;;;OAYG;IACH,SAAS,CAAC,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;IACvC,8FAA8F;IAC9F,WAAW,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAAC;IAC/B,4BAA4B;IAC5B,UAAU,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAAC;IAC9B,OAAO,IAAI,IAAI,CAAC;CACjB;AA4KD;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,GAAE,aAAkB,GAAG,MAAM,CAEpF;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,GAAE,aAAkB,GAAG,MAAM,CAwBtF;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,SAAS,EAAE,IAAI,GAAE,aAAkB,GAAG,MAAM,CAEjF"}
1
+ {"version":3,"file":"keycap.d.ts","sourceRoot":"","sources":["../../src/ui/keycap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAkC,KAAK,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAGtF,+FAA+F;AAC/F,MAAM,MAAM,aAAa,GAAG,YAAY,GAAG,cAAc,GAAG,cAAc,GAAG,eAAe,CAAC;AAC7F,8EAA8E;AAC9E,MAAM,MAAM,SAAS,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AACzD,sEAAsE;AACtE,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,MAAM,CAAC;AAC5C,8CAA8C;AAC9C,MAAM,MAAM,cAAc,GAAG,aAAa,CAAC;AAE3C;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE;QAAE,IAAI,EAAE,UAAU,CAAC;QAAC,IAAI,EAAE,UAAU,CAAA;KAAE,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;CAC/E;AAoBD,MAAM,WAAW,aAAa;IAC5B,wFAAwF;IACxF,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,kEAAkE;IAClE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;OAGG;IACH,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB;;;;;;;;;;;;OAYG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,4CAA4C;AAC5C,MAAM,WAAW,MAAM;IACrB,mDAAmD;IACnD,EAAE,EAAE,WAAW,CAAC;IAChB,uCAAuC;IACvC,UAAU,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAAC;IAC9B,2CAA2C;IAC3C,WAAW,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAAC;IAC/B;;;OAGG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAChE,6BAA6B;IAC7B,UAAU,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAAC;IAC9B;;;;;;;;;;;;OAYG;IACH,SAAS,CAAC,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAAC;IACvC,8FAA8F;IAC9F,WAAW,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAAC;IAC/B,4BAA4B;IAC5B,UAAU,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAAC;IAC9B,OAAO,IAAI,IAAI,CAAC;CACjB;AA2ND;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,GAAE,aAAkB,GAAG,MAAM,CAEpF;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,GAAE,aAAkB,GAAG,MAAM,CAgCvF;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,SAAS,EAAE,IAAI,GAAE,aAAkB,GAAG,MAAM,CAEjF"}
package/dist/ui/keycap.js CHANGED
@@ -2,20 +2,26 @@
2
2
  * KEYCAP — a DOM/CSS keycap of the controller face buttons (zero dependencies), so a game can show
3
3
  * "which button to press" in a consistent visual language. Two shapes:
4
4
  *
5
- * • "full" — the classic diamond: the active button enlarged + coloured, the other three small + grey.
5
+ * • "full" — the classic diamond: the active button enlarged, the other three small + grey.
6
6
  * • "solo" — light variation: JUST the active button (the idle siblings removed).
7
7
  *
8
8
  * The keycap is a small STATE MACHINE: it can pulse (the bouncing attract animation), show a pressed
9
- * sink, run a depleting COOLDOWN ring + countdown, render colored or neutral ("mono"), and hide.
9
+ * sink, run a depleting COOLDOWN ring + countdown, and hide.
10
+ *
11
+ * **Mono by default** — a white face with a dark letter, which is the RYDR look everywhere (the shell
12
+ * draws all of its own chrome that way). The per-button role hues still exist behind
13
+ * `colored: true`, for a deliberately loud isolated affordance or to show the palette itself.
10
14
  *
11
15
  * Two button families share that machine: `createKeycap` for the A/B/Y/Z face buttons (a letter on
12
16
  * the active pip) and `createDpadKeycap` for the UP/DOWN/LEFT/RIGHT directional buttons (a white
13
17
  * chevron on a steel-grey pip, rotated per direction). They differ ONLY in the face drawn and the
14
18
  * button name the press-wiring listens for; everything else is identical.
15
19
  *
16
- * A third factory, `createLabelKeycap`, covers the buttons whose printed name is a WORD rather than a
17
- * letterthe system/options button, the shoulder triggers, the stick clicks as a PILL instead of a
18
- * circle, since "Options" cannot fit in a pip sized for one glyph.
20
+ * A third factory, `createButtonKeycap`, covers what's left the system/options button, the shoulder
21
+ * triggers, the stick clicks and draws each the way the pad does: `OPTIONS` as a round pip with the
22
+ * pad's ICON (`☰` on Xbox/DualSense, `+` on a Switch Pro), since it's a small round key like the
23
+ * others; the triggers and stick clicks as a text PILL, since those are printed with a word ("LT",
24
+ * "L2", "LS") that no pip sized for one glyph could hold.
19
25
  */
20
26
  import { buttonLabel, DEFAULT_GLYPH_SET } from "../protocol/glyphs.js";
21
27
  import { injectCss } from "./styles.js";
@@ -70,6 +76,29 @@ const ROT = { top: 0, rgt: 90, bot: 180, lft: 270 };
70
76
  const CHEVRON = `<polyline points="5,15 12,8 19,15" fill="none" stroke="currentColor" stroke-width="3.2" stroke-linecap="round" stroke-linejoin="round"/>`;
71
77
  /** Background tone of a directional keycap's active pip ("acier" / steel-grey); the glyph stays white. */
72
78
  const DPAD_TONE = "#566273";
79
+ /**
80
+ * The ICON a pad prints on its system button, per family — because the button itself is a small round
81
+ * key, drawn with a symbol rather than lettered: `☰` on an Xbox pad's Menu button and on a DualSense's
82
+ * Options button, `+` on a Switch Pro. Only the RYDR-historic Zwift pad has no such button at all, and
83
+ * it borrows the hamburger.
84
+ *
85
+ * This is the ICON, not the NAME: prose still says "press Menu" / "press Options" / "press +" via
86
+ * {@link buttonLabel}, which stays the single home for a button's printed *text*. A button with an
87
+ * entry here is drawn as a round pip like the d-pad's chevron; one without (the shoulder triggers, the
88
+ * stick clicks) falls back to a text pill, because those really are printed with a word.
89
+ */
90
+ const SYSTEM_ICON = (() => {
91
+ const HAMBURGER = `<g fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round">` +
92
+ `<line x1="6" y1="8" x2="18" y2="8"/><line x1="6" y1="12" x2="18" y2="12"/><line x1="6" y1="16" x2="18" y2="16"/></g>`;
93
+ const PLUS = `<g fill="none" stroke="currentColor" stroke-width="3" stroke-linecap="round">` +
94
+ `<line x1="12" y1="6" x2="12" y2="18"/><line x1="6" y1="12" x2="18" y2="12"/></g>`;
95
+ return {
96
+ xbox: { OPTIONS: HAMBURGER },
97
+ playstation: { OPTIONS: HAMBURGER },
98
+ nintendo: { OPTIONS: PLUS },
99
+ zwift: { OPTIONS: HAMBURGER },
100
+ };
101
+ })();
73
102
  const PIP = 20, PIP_ACTIVE = 38, LETTER_FONT = 23;
74
103
  const NEUTRAL_ACTIVE = "#ffffff"; // mono active button: white face (the letter stays dark)
75
104
  const INACTIVE = "#3a424e"; // the idle siblings in a full diamond
@@ -80,14 +109,29 @@ const INACTIVE = "#3a424e"; // the idle siblings in a full diamond
80
109
  * A factory rather than a constant because the letter depends on which controller is paired; the set
81
110
  * is resolved once when the keycap is built. See {@link buttonLabel}.
82
111
  */
83
- const letterFaceFor = (set) => (pos, active) => {
112
+ const letterFaceFor = (set) => (pos, active, size) => {
84
113
  const lt = document.createElement("span");
85
114
  lt.className = "rydr-ui-pip-letter";
115
+ // Sized from the pip it sits on, not from the constant, so a `scale`d cap keeps the same
116
+ // letter-to-key proportion. At the default pip this is exactly LETTER_FONT.
86
117
  if (active)
87
- lt.style.fontSize = `${LETTER_FONT}px`;
118
+ lt.style.fontSize = `${(size * LETTER_FONT) / PIP_ACTIVE}px`;
88
119
  lt.textContent = buttonLabel(set, BUTTON_AT[pos]);
89
120
  return lt;
90
121
  };
122
+ /** System face — the white icon the pad prints on that button (see {@link SYSTEM_ICON}). */
123
+ const iconFaceFor = (svgBody) => (_pos, active, size) => {
124
+ if (!active)
125
+ return null;
126
+ const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
127
+ svg.setAttribute("viewBox", "0 0 24 24");
128
+ svg.setAttribute("width", String(Math.round(size * 0.62)));
129
+ svg.setAttribute("height", String(Math.round(size * 0.62)));
130
+ svg.setAttribute("class", "rydr-ui-pip-glyph");
131
+ svg.style.color = "#ffffff"; // white icon on the steel pip, exactly like the chevron
132
+ svg.innerHTML = svgBody;
133
+ return svg;
134
+ };
91
135
  /** Directional face — a white chevron (only on the active button; siblings stay blank). */
92
136
  const chevronFace = (pos, active, size) => {
93
137
  if (!active)
@@ -122,19 +166,22 @@ function makePip(active, color, pos, size, animate, face) {
122
166
  return pip;
123
167
  }
124
168
  /** Build the keycap for `activePos`; returns the element + a reference to the active pip (for state). */
125
- function buildPips(activePos, variant, colored, animate, face, accent) {
169
+ function buildPips(activePos, variant, colored, animate, face, scale, accent) {
126
170
  const diamond = document.createElement("div");
127
171
  diamond.className = "rydr-ui-diamond";
128
172
  // `accent` (used by the directional keycap) overrides the per-button hue with a fixed tone.
129
173
  const activeColor = accent ?? (colored ? COLOR[activePos] : NEUTRAL_ACTIVE);
174
+ // Every dimension below derives from these two, so `scale` resizes the real geometry (and the faces,
175
+ // which size themselves off the pip they're drawn on) rather than transforming a full-size box.
176
+ const pipIdle = PIP * scale, pipActive = PIP_ACTIVE * scale;
130
177
  if (variant === "solo") {
131
- diamond.style.width = diamond.style.height = `${PIP_ACTIVE}px`;
132
- const pip = makePip(true, activeColor, activePos, PIP_ACTIVE, animate, face);
178
+ diamond.style.width = diamond.style.height = `${pipActive}px`;
179
+ const pip = makePip(true, activeColor, activePos, pipActive, animate, face);
133
180
  pip.style.left = pip.style.top = "0px";
134
181
  diamond.appendChild(pip);
135
182
  return { el: diamond, activePip: pip };
136
183
  }
137
- const ri = PIP / 2, Ra = PIP_ACTIVE / 2, r0 = Ra, D = r0 + ri;
184
+ const ri = pipIdle / 2, Ra = pipActive / 2, r0 = Ra, D = r0 + ri;
138
185
  let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
139
186
  const pts = {};
140
187
  for (const k of ["top", "lft", "rgt", "bot"]) {
@@ -169,9 +216,13 @@ function build(activePos, pressName, face, opts, accent) {
169
216
  injectCss();
170
217
  const variant = opts.variant ?? "solo";
171
218
  const animate = opts.animate ?? true;
172
- const colored = opts.colored ?? true;
173
- const { el, activePip } = buildPips(activePos, variant, colored, animate, face, accent);
219
+ const colored = opts.colored ?? false; // mono is the RYDR look — see KeycapOptions.colored
220
+ const scale = opts.scale ?? 1;
221
+ const { el, activePip } = buildPips(activePos, variant, colored, animate, face, scale, accent);
174
222
  const num = activePip.querySelector(".rydr-ui-cd-num");
223
+ // The countdown's type lives in CSS; scale it with the pip so a small cap's number still fits inside.
224
+ if (num && scale !== 1)
225
+ num.style.fontSize = `${18 * scale}px`;
175
226
  const setPressed = (on) => activePip.classList.toggle("pressed", on);
176
227
  // wire to real controller input: pressed while THIS button is held (down → pressed, up → released)
177
228
  const off = opts.press?.onButton((e) => { if (e.name === pressName)
@@ -209,29 +260,44 @@ export function createKeycap(button, opts = {}) {
209
260
  return build(POS_OF[button], button, letterFaceFor(resolveGlyphSet(opts)), opts);
210
261
  }
211
262
  /**
212
- * Build a keycap for a button whose printed name is a **word, not a letter** — the system/options
213
- * button (`OPTIONS` → "Menu" / "Options" / "+"), the shoulder triggers (`LT`/`RT` "LT" / "L2" / "ZL")
214
- * and the stick clicks (`LSTICK_PRESS`/`RSTICK_PRESS` "LS" / "L3" / "L").
263
+ * Build a keycap for the buttons that carry neither a face letter nor a direction — the system/options
264
+ * button (`OPTIONS`), the shoulder triggers (`LT`/`RT`) and the stick clicks
265
+ * (`LSTICK_PRESS`/`RSTICK_PRESS`) drawn the way the rider's pad actually draws them:
266
+ *
267
+ * • **`OPTIONS` → a round pip with the pad's ICON** (`☰` on Xbox/DualSense, `+` on a Switch Pro).
268
+ * It is a small round key on every pad, so it gets the same circular pip as the d-pad's chevron and
269
+ * sits in the same visual family as the face buttons.
270
+ * • **everything else → a text PILL** carrying {@link buttonLabel} ("LT" / "L2" / "ZL", "LS" / "L3"),
271
+ * because those buttons really are printed with a *word*, and no word fits a pip sized for one
272
+ * glyph. The trigger hardware isn't round either.
215
273
  *
216
- * A **pill** rather than a circular pip, because "Options" does not fit in a pip sized for one glyph.
217
- * Everything else is the pip's own language reused verbatim (raised lip, pulse, pressed sink, inert
218
- * grey), so the two shapes read as one family, and the text still comes from {@link buttonLabel} — the
219
- * rule that no letter is ever hardcoded holds here too.
274
+ * Either way the state machine is the pip's, reused verbatim (raised lip, pulse, pressed sink, inert
275
+ * grey), and nothing is hardcoded per brand: the icon comes from {@link SYSTEM_ICON} and the text from
276
+ * {@link buttonLabel}.
220
277
  *
221
- * Steel-grey by default (a system button is never the confirm/back hue), and — unlike the pip
222
- * factories — the attract pulse is **off** unless asked for: these caps label a shortcut the rider can
223
- * take, not an action being demanded of them. `setCooldown` is accepted for interface parity but draws
224
- * nothing: these buttons open menus, they don't gate timed abilities.
278
+ * Steel-grey (these are never the confirm/back hues), and — unlike the pip factories — the attract
279
+ * pulse is **off** unless asked for: these caps label a shortcut the rider *can* take, not an action
280
+ * being demanded of them. `setCooldown` is accepted for interface parity but draws nothing on the pill:
281
+ * these buttons open menus, they don't gate timed abilities.
225
282
  *
226
- * Pass a face-diamond or d-pad button here and you get its letter/arrow in a pill — legal, but prefer
227
- * {@link createKeycap} / {@link createDpadKeycap}, which draw the real button shape.
283
+ * Pass a face-diamond or d-pad button here and you get its letter in a pill — legal, but prefer
284
+ * {@link createKeycap} / {@link createDpadKeycap}, which draw those buttons' real shapes.
228
285
  */
229
- export function createLabelKeycap(button, opts = {}) {
286
+ export function createButtonKeycap(button, opts = {}) {
287
+ const set = resolveGlyphSet(opts);
288
+ const icon = SYSTEM_ICON[SYSTEM_ICON[set] ? set : DEFAULT_GLYPH_SET][button];
289
+ // A button the pad draws with a symbol is a ROUND KEY: reuse the pip machinery (solo variant, steel
290
+ // tone, icon face). `activePos` only picks the hue and the sibling layout, neither of which a solo
291
+ // accented pip uses — "bot" is an inert placeholder, not a claim about where the button sits.
292
+ if (icon)
293
+ return build("bot", button, iconFaceFor(icon), { ...opts, variant: "solo", animate: opts.animate ?? false }, DPAD_TONE);
230
294
  injectCss();
231
295
  const el = document.createElement("span");
232
296
  el.className = "rydr-ui-cap" + (opts.animate ?? false ? " anim" : "");
233
297
  el.style.setProperty("--c", DPAD_TONE);
234
- el.textContent = buttonLabel(resolveGlyphSet(opts), button);
298
+ if (opts.scale != null && opts.scale !== 1)
299
+ el.style.setProperty("--s", String(opts.scale));
300
+ el.textContent = buttonLabel(set, button);
235
301
  const setPressed = (on) => { el.classList.toggle("pressed", on); };
236
302
  const off = opts.press?.onButton((e) => { if (e.name === button)
237
303
  setPressed(e.edge === "down"); });
@@ -1 +1 @@
1
- {"version":3,"file":"keycap.js","sourceRoot":"","sources":["../../src/ui/keycap.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"keycap.js","sourceRoot":"","sources":["../../src/ui/keycap.ts"],"names":[],"mappings":"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"}
@@ -1,14 +1,14 @@
1
1
  /**
2
- * PAUSE MENU — the in-game menu every RYDR game shares, opened by the game's own `OPTIONS` button.
2
+ * OPTION MENU — the in-game menu every RYDR game shares, opened by the game's own `OPTIONS` button.
3
3
  *
4
4
  * This is the GAME's menu, deliberately distinct from the PLATFORM's overlay (which the shell opens on
5
5
  * `MENU` / `M` / phone MENU and which never reaches a game — see `ButtonName`). The platform overlay
6
6
  * carries the rider's concerns: activity, hardware, volume, exit. This one carries the *game's*:
7
7
  * resume, restart, back to your own menu. It deliberately quotes the platform overlay's visual language
8
- * — dim + blurred backdrop, frosted rows, the staggered "warp" entrance — so pause reads as a RYDR
8
+ * — dim + blurred backdrop, frosted rows, the staggered "warp" entrance — so it reads as a RYDR
9
9
  * surface one level shallower than the platform's, rather than as a second, unrelated menu.
10
10
  *
11
- * const pause = mountPauseMenu(document.body, {
11
+ * const menu = mountOptionMenu(document.body, {
12
12
  * session,
13
13
  * title: "Split Racing",
14
14
  * canOpen: () => phase === "playing", // the game decides WHEN it may open
@@ -23,16 +23,28 @@
23
23
  * `Resume` is prepended for free, so the shortest useful menu is no items at all.
24
24
  *
25
25
  * **Everything the rider reads is in the GAME's font.** The title and every row inherit the host's
26
- * font-family (override with the `font` option or the `--rydr-pause-font` custom property), because
26
+ * font-family (override with the `font` option or the `--rydr-option-font` custom property), because
27
27
  * this menu belongs to the game, not to the shell — the one exception being the keycaps, which keep
28
28
  * their standard RYDR type because they are pictures of the rider's physical controller.
29
29
  *
30
+ * Inheritance being the mechanism, the host page has to actually DECLARE a font: with nothing setting
31
+ * `font-family` up the tree, this renders in the browser default (Times). Every real game sets a body
32
+ * font, so it costs nothing — but a menu that looks like a legal document is that, not a bug here.
33
+ *
30
34
  * **What it does NOT do: stop your game.** No library can — your loop, timers and physics are yours.
31
35
  * The menu tells you when it opens and closes; freeze there. What it *does* guarantee is that a game
32
36
  * which keeps running cannot be *driven* while the rider is in the menu: it takes the controller over
33
37
  * for the duration (`session.grabInput`), so your `onButton` handlers go quiet, `isDown`/`stick` read
34
- * resting, and anything held is released first. It also declares `"menu"` to the shell while it's up,
35
- * so trainer resistance eases like on any other non-racing screen, and restores `"playing"` on resume.
38
+ * resting, and anything held is released first.
39
+ *
40
+ * **It also does NOT touch the trainer.** Opening this menu leaves the activity state exactly as the
41
+ * game left it — a rider who opens it mid-run keeps the resistance they were riding. That is
42
+ * deliberate: this menu is a transient overlay over LIVE gameplay, not a screen the rider navigated
43
+ * to, and they are still on the bike with their legs turning. Dropping to the eased menu resistance
44
+ * and snapping back on `Resume` would change the difficulty of the very run they are deciding
45
+ * whether to restart. (Contrast the PLATFORM overlay, which is the shell's own and does ease.)
46
+ * A game that genuinely wants easing here can still do it itself in `onOpen`/`onClose` —
47
+ * `session.setActivity("menu")` / `("playing")` — which is more flexible than an option anyway.
36
48
  *
37
49
  * A row may advertise a `shortcut` — the button the rider can press *in-game* to do the same thing
38
50
  * (`Restart · Shortcut [Y]`). Binding that shortcut during play stays the game's own job; the menu
@@ -41,12 +53,14 @@
41
53
  import type { ButtonEdge, ButtonName, GlyphSet } from "../protocol/index.js";
42
54
  import { type NavCue } from "../nav/spatial-nav.js";
43
55
  /**
44
- * The slice of a `PlatformSession` the menu uses. A real session satisfies it structurally, and every
45
- * capability past `onButton` is optional so a stand-in (a showcase double, a test) works too — without
46
- * `grabInput` the menu simply can't quiet the game's own input, and without `setActivity` the trainer
47
- * isn't eased.
56
+ * The slice of a `PlatformSession` the menu uses — input, and nothing else. A real session satisfies
57
+ * it structurally, and `grabInput` is optional so a stand-in (a showcase double, a test) works too:
58
+ * without it the menu simply can't quiet the game's own input.
59
+ *
60
+ * Deliberately no `setActivity`. The menu does not touch the trainer (see the header), so asking for
61
+ * that capability would advertise a power it no longer uses.
48
62
  */
49
- export interface PauseMenuSession {
63
+ export interface OptionMenuSession {
50
64
  onButton(cb: (e: {
51
65
  name: ButtonName;
52
66
  edge: ButtonEdge;
@@ -55,10 +69,9 @@ export interface PauseMenuSession {
55
69
  name: ButtonName;
56
70
  edge: ButtonEdge;
57
71
  }) => void): () => void;
58
- setActivity?(state: "playing" | "menu"): void;
59
72
  }
60
73
  /** One row of the menu. */
61
- export interface PauseMenuItem {
74
+ export interface OptionMenuItem {
62
75
  /** The row's text — keep it short (it's read from a few feet away): "Restart", "Back to menu". */
63
76
  label: string;
64
77
  /** Run when the rider picks the row (with `A`, a click, or the row's `shortcut`). */
@@ -79,13 +92,13 @@ export interface PauseMenuItem {
79
92
  * is to close first, so the action runs on a resumed game with input already handed back. */
80
93
  keepOpen?: boolean;
81
94
  }
82
- export interface PauseMenuOptions {
95
+ export interface OptionMenuOptions {
83
96
  /** The platform session — for input, the trainer-easing hint, and the rider's controller lettering. */
84
- session?: PauseMenuSession;
97
+ session?: OptionMenuSession;
85
98
  /** The game's name, printed big at the top in the game's own font. */
86
99
  title: string;
87
100
  /** The rows after `Resume`. Replaceable at any time with `setItems`. */
88
- items?: PauseMenuItem[];
101
+ items?: OptionMenuItem[];
89
102
  /** Which button opens (and closes) the menu. Default `"OPTIONS"` — the game's own menu button. */
90
103
  openButton?: ButtonName;
91
104
  /**
@@ -96,9 +109,6 @@ export interface PauseMenuOptions {
96
109
  canOpen?: () => boolean;
97
110
  /** Label of the free first row. Default `"Resume"`. */
98
111
  resumeLabel?: string;
99
- /** Declare `"menu"` to the shell while open and `"playing"` on close (eases trainer resistance).
100
- * Default `true`. Turn it off only if the game manages activity state itself around the menu. */
101
- activity?: boolean;
102
112
  /** Take the controller over while open via `session.grabInput` (default `true`). Off = the game keeps
103
113
  * receiving input behind the menu, which it must then ignore itself. */
104
114
  captureInput?: boolean;
@@ -114,7 +124,7 @@ export interface PauseMenuOptions {
114
124
  /** The menu closed (resume, back, the backdrop, or a row that ran) — unfreeze here. */
115
125
  onClose?: () => void;
116
126
  }
117
- export interface PauseMenu {
127
+ export interface OptionMenu {
118
128
  /** The overlay root (mounted in the host; hidden while closed). */
119
129
  root: HTMLElement;
120
130
  /** Open it (no-op if already open or `canOpen` refuses). Returns whether it opened. */
@@ -125,7 +135,7 @@ export interface PauseMenu {
125
135
  toggle(): boolean;
126
136
  isOpen(): boolean;
127
137
  /** Replace the rows after `Resume` (rebuilt live if the menu is open). */
128
- setItems(items: PauseMenuItem[]): void;
138
+ setItems(items: OptionMenuItem[]): void;
129
139
  /** Change the big title. */
130
140
  setTitle(title: string): void;
131
141
  /**
@@ -137,8 +147,8 @@ export interface PauseMenu {
137
147
  dispose(): void;
138
148
  }
139
149
  /**
140
- * Mount the pause menu (hidden until opened). Appended to `host` — normally `document.body`, so the
150
+ * Mount the option menu (hidden until opened). Appended to `host` — normally `document.body`, so the
141
151
  * overlay covers the game whatever the DOM under it looks like.
142
152
  */
143
- export declare function mountPauseMenu(host: HTMLElement, opts: PauseMenuOptions): PauseMenu;
144
- //# sourceMappingURL=pause-menu.d.ts.map
153
+ export declare function mountOptionMenu(host: HTMLElement, opts: OptionMenuOptions): OptionMenu;
154
+ //# sourceMappingURL=option-menu.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"option-menu.d.ts","sourceRoot":"","sources":["../../src/ui/option-menu.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAE7E,OAAO,EAAoB,KAAK,MAAM,EAAmB,MAAM,uBAAuB,CAAC;AAYvF;;;;;;;GAOG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE;QAAE,IAAI,EAAE,UAAU,CAAC;QAAC,IAAI,EAAE,UAAU,CAAA;KAAE,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAC9E,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE;QAAE,IAAI,EAAE,UAAU,CAAC;QAAC,IAAI,EAAE,UAAU,CAAA;KAAE,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;CACtF;AAcD,2BAA2B;AAC3B,MAAM,WAAW,cAAc;IAC7B,kGAAkG;IAClG,KAAK,EAAE,MAAM,CAAC;IACd,qFAAqF;IACrF,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,UAAU,CAAC;IACtB,wGAAwG;IACxG,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,qEAAqE;IACrE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,+FAA+F;IAC/F,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB;kGAC8F;IAC9F,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,uGAAuG;IACvG,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B,sEAAsE;IACtE,KAAK,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,KAAK,CAAC,EAAE,cAAc,EAAE,CAAC;IACzB,kGAAkG;IAClG,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,OAAO,CAAC;IACxB,uDAAuD;IACvD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;6EACyE;IACzE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,8DAA8D;IAC9D,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3B;mDAC+C;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,+CAA+C;IAC/C,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,uFAAuF;IACvF,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,mEAAmE;IACnE,IAAI,EAAE,WAAW,CAAC;IAClB,uFAAuF;IACvF,IAAI,IAAI,OAAO,CAAC;IAChB,4CAA4C;IAC5C,KAAK,IAAI,IAAI,CAAC;IACd,uEAAuE;IACvE,MAAM,IAAI,OAAO,CAAC;IAClB,MAAM,IAAI,OAAO,CAAC;IAClB,0EAA0E;IAC1E,QAAQ,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,IAAI,CAAC;IACxC,4BAA4B;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B;;;;OAIG;IACH,YAAY,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC;IACxC,OAAO,IAAI,IAAI,CAAC;CACjB;AA6CD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,iBAAiB,GAAG,UAAU,CAuUtF"}