@rydr/game-sdk 8.11.0 → 8.13.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 (135) hide show
  1. package/README.md +26 -2
  2. package/dist/client/PlatformClient.d.ts.map +1 -1
  3. package/dist/client/PlatformClient.js +14 -2
  4. package/dist/client/PlatformClient.js.map +1 -1
  5. package/dist/client/Room.d.ts +9 -4
  6. package/dist/client/Room.d.ts.map +1 -1
  7. package/dist/client/Room.js +8 -5
  8. package/dist/client/Room.js.map +1 -1
  9. package/dist/host/PlatformHost.d.ts +4 -2
  10. package/dist/host/PlatformHost.d.ts.map +1 -1
  11. package/dist/host/PlatformHost.js +5 -3
  12. package/dist/host/PlatformHost.js.map +1 -1
  13. package/dist/protocol/messages.d.ts +11 -4
  14. package/dist/protocol/messages.d.ts.map +1 -1
  15. package/dist/protocol/room.d.ts +26 -0
  16. package/dist/protocol/room.d.ts.map +1 -1
  17. package/dist/protocol/version.d.ts +2 -2
  18. package/dist/protocol/version.d.ts.map +1 -1
  19. package/dist/protocol/version.js +23 -2
  20. package/dist/protocol/version.js.map +1 -1
  21. package/dist/three/README.md +111 -0
  22. package/dist/three/character/index.d.ts +14 -0
  23. package/dist/three/character/index.d.ts.map +1 -0
  24. package/dist/three/character/index.js +14 -0
  25. package/dist/three/character/index.js.map +1 -0
  26. package/dist/three/character/kit.d.ts +74 -0
  27. package/dist/three/character/kit.d.ts.map +1 -0
  28. package/dist/three/character/kit.js +254 -0
  29. package/dist/three/character/kit.js.map +1 -0
  30. package/dist/three/character/riders.d.ts +20 -0
  31. package/dist/three/character/riders.d.ts.map +1 -0
  32. package/dist/three/character/riders.js +383 -0
  33. package/dist/three/character/riders.js.map +1 -0
  34. package/dist/three/character/skeleton.d.ts +105 -0
  35. package/dist/three/character/skeleton.d.ts.map +1 -0
  36. package/dist/three/character/skeleton.js +57 -0
  37. package/dist/three/character/skeleton.js.map +1 -0
  38. package/dist/three/controller/glyph-texture.d.ts +29 -0
  39. package/dist/three/controller/glyph-texture.d.ts.map +1 -0
  40. package/dist/three/controller/glyph-texture.js +68 -0
  41. package/dist/three/controller/glyph-texture.js.map +1 -0
  42. package/dist/three/controller/index.d.ts +12 -0
  43. package/dist/three/controller/index.d.ts.map +1 -0
  44. package/dist/three/controller/index.js +12 -0
  45. package/dist/three/controller/index.js.map +1 -0
  46. package/dist/three/controller/joycon-designs.d.ts +49 -0
  47. package/dist/three/controller/joycon-designs.d.ts.map +1 -0
  48. package/dist/three/controller/joycon-designs.js +742 -0
  49. package/dist/three/controller/joycon-designs.js.map +1 -0
  50. package/dist/three/controller/joycon-shoulder-mesh.d.ts +41 -0
  51. package/dist/three/controller/joycon-shoulder-mesh.d.ts.map +1 -0
  52. package/dist/three/controller/joycon-shoulder-mesh.js +527 -0
  53. package/dist/three/controller/joycon-shoulder-mesh.js.map +1 -0
  54. package/dist/three/controller/joycon-spec.d.ts +233 -0
  55. package/dist/three/controller/joycon-spec.d.ts.map +1 -0
  56. package/dist/three/controller/joycon-spec.js +285 -0
  57. package/dist/three/controller/joycon-spec.js.map +1 -0
  58. package/dist/three/controller/three-pad-renderer.d.ts +81 -0
  59. package/dist/three/controller/three-pad-renderer.d.ts.map +1 -0
  60. package/dist/three/controller/three-pad-renderer.js +433 -0
  61. package/dist/three/controller/three-pad-renderer.js.map +1 -0
  62. package/dist/three/index.d.ts +2 -0
  63. package/dist/three/index.d.ts.map +1 -1
  64. package/dist/three/index.js +2 -0
  65. package/dist/three/index.js.map +1 -1
  66. package/dist/three/rider/cyclist-pose.d.ts +62 -0
  67. package/dist/three/rider/cyclist-pose.d.ts.map +1 -0
  68. package/dist/three/rider/cyclist-pose.js +173 -0
  69. package/dist/three/rider/cyclist-pose.js.map +1 -0
  70. package/dist/three/rider/index.d.ts +8 -0
  71. package/dist/three/rider/index.d.ts.map +1 -0
  72. package/dist/three/rider/index.js +8 -0
  73. package/dist/three/rider/index.js.map +1 -0
  74. package/dist/three/rider/three-rider-rig.d.ts +80 -0
  75. package/dist/three/rider/three-rider-rig.d.ts.map +1 -0
  76. package/dist/three/rider/three-rider-rig.js +418 -0
  77. package/dist/three/rider/three-rider-rig.js.map +1 -0
  78. package/dist/ui/README.md +153 -1
  79. package/dist/ui/controller/combo-demo.d.ts +9 -0
  80. package/dist/ui/controller/combo-demo.d.ts.map +1 -1
  81. package/dist/ui/controller/combo-demo.js +1 -0
  82. package/dist/ui/controller/combo-demo.js.map +1 -1
  83. package/dist/ui/controller/control-spotlight.d.ts +10 -1
  84. package/dist/ui/controller/control-spotlight.d.ts.map +1 -1
  85. package/dist/ui/controller/control-spotlight.js +42 -42
  86. package/dist/ui/controller/control-spotlight.js.map +1 -1
  87. package/dist/ui/controller/control-trainer.d.ts +14 -0
  88. package/dist/ui/controller/control-trainer.d.ts.map +1 -1
  89. package/dist/ui/controller/control-trainer.js +6 -0
  90. package/dist/ui/controller/control-trainer.js.map +1 -1
  91. package/dist/ui/controller/controller-map.d.ts +9 -0
  92. package/dist/ui/controller/controller-map.d.ts.map +1 -1
  93. package/dist/ui/controller/controller-map.js +8 -6
  94. package/dist/ui/controller/controller-map.js.map +1 -1
  95. package/dist/ui/controller/controller-pad.d.ts +35 -2
  96. package/dist/ui/controller/controller-pad.d.ts.map +1 -1
  97. package/dist/ui/controller/controller-pad.js +47 -7
  98. package/dist/ui/controller/controller-pad.js.map +1 -1
  99. package/dist/ui/controller/index.d.ts +1 -0
  100. package/dist/ui/controller/index.d.ts.map +1 -1
  101. package/dist/ui/controller/index.js +1 -0
  102. package/dist/ui/controller/index.js.map +1 -1
  103. package/dist/ui/controller/renderer.d.ts +118 -0
  104. package/dist/ui/controller/renderer.d.ts.map +1 -0
  105. package/dist/ui/controller/renderer.js +93 -0
  106. package/dist/ui/controller/renderer.js.map +1 -0
  107. package/dist/ui/controller/styles.js +30 -0
  108. package/dist/ui/controller/styles.js.map +1 -1
  109. package/dist/ui/index.d.ts +7 -0
  110. package/dist/ui/index.d.ts.map +1 -1
  111. package/dist/ui/index.js +7 -0
  112. package/dist/ui/index.js.map +1 -1
  113. package/dist/ui/keycap.d.ts +11 -0
  114. package/dist/ui/keycap.d.ts.map +1 -1
  115. package/dist/ui/keycap.js +3 -0
  116. package/dist/ui/keycap.js.map +1 -1
  117. package/dist/ui/pad-hints.d.ts +78 -0
  118. package/dist/ui/pad-hints.d.ts.map +1 -0
  119. package/dist/ui/pad-hints.js +103 -0
  120. package/dist/ui/pad-hints.js.map +1 -0
  121. package/dist/ui/rider-rig.d.ts +315 -0
  122. package/dist/ui/rider-rig.d.ts.map +1 -0
  123. package/dist/ui/rider-rig.js +1000 -0
  124. package/dist/ui/rider-rig.js.map +1 -0
  125. package/dist/ui/showcase/index.d.ts +11 -0
  126. package/dist/ui/showcase/index.d.ts.map +1 -1
  127. package/dist/ui/showcase/index.js +109 -1
  128. package/dist/ui/showcase/index.js.map +1 -1
  129. package/dist/ui/solo-labeled-diamond.d.ts +7 -0
  130. package/dist/ui/solo-labeled-diamond.d.ts.map +1 -1
  131. package/dist/ui/solo-labeled-diamond.js +1 -1
  132. package/dist/ui/solo-labeled-diamond.js.map +1 -1
  133. package/dist/ui/styles.js +9 -0
  134. package/dist/ui/styles.js.map +1 -1
  135. package/package.json +8 -4
@@ -34,8 +34,9 @@
34
34
  import type { AxisName, ButtonEdge, ButtonName } from "../../protocol/buttons.js";
35
35
  import { type GlyphSet } from "../../protocol/glyphs.js";
36
36
  import { type PadDriver, type PadSvg } from "./pad-svg.js";
37
+ import { type PadRenderer, type PadRendererFactory, type PartRect } from "./renderer.js";
37
38
  import type { ControlName } from "./tokens.js";
38
- import type { PadBrandKey, PadLayout } from "./types.js";
39
+ import type { PadBrandKey, PadLayout, PadPart } from "./types.js";
39
40
  /**
40
41
  * What the host reports about the controller in the rider's hands, and how to hear about a swap.
41
42
  *
@@ -130,11 +131,36 @@ export interface ControllerPadOptions {
130
131
  * `mountControlTrainer` sets it when a step names one.
131
132
  */
132
133
  allowShellOwned?: boolean;
134
+ /**
135
+ * What actually DRAWS the pad. Default: the flat SVG drawing this kit has always used.
136
+ *
137
+ * Pass `createThreePadRenderer` from `@rydr/game-sdk/three` for the Joy-Con in 3D. Every view built
138
+ * on this pad — the map, the combo demo, the spotlight, the guided lesson — then renders against it
139
+ * unchanged, because none of them draws the controller themselves: they talk to a `PadDriver` and
140
+ * ask where a part is. See `renderer.ts` for that contract.
141
+ */
142
+ renderer?: PadRendererFactory;
133
143
  }
134
144
  export interface ControllerPad {
135
145
  readonly root: HTMLDivElement;
136
- /** The current drawing's node cache. Replaced on a re-letter — don't hold onto it across one. */
146
+ /**
147
+ * The current drawing's node cache. Replaced on a re-letter — don't hold onto it across one.
148
+ *
149
+ * ⚠️ **Flat renderer only.** Throws when the pad is drawn by anything else (the three.js Joy-Con has
150
+ * no `<svg>`), because handing back a fake node would fail later and further from the cause. Reach
151
+ * for {@link ControllerPad.partRect} / {@link ControllerPad.setReferenced} instead — they answer the
152
+ * two questions this was actually being used for, on every renderer.
153
+ */
137
154
  svg(): PadSvg;
155
+ /** Whatever is drawing the pad right now. Replaced on a re-letter, like {@link svg}. */
156
+ renderer(): PadRenderer;
157
+ /**
158
+ * Where a part sits on screen, in viewport pixels — or `null` for one this layout doesn't draw.
159
+ * Subtract your own host's rect for host-relative pixels.
160
+ */
161
+ partRect(part: PadPart): PartRect | null;
162
+ /** Mark the parts a callout points at, so a faint one stops reading as disabled. */
163
+ setReferenced(parts: ReadonlySet<PadPart>): void;
138
164
  driver(): PadDriver;
139
165
  layout(): PadLayout;
140
166
  /**
@@ -146,6 +172,13 @@ export interface ControllerPad {
146
172
  brand(): PadBrandKey;
147
173
  /** Fires after the drawing is rebuilt (a pad swap). The map view uses it to re-route its lines. */
148
174
  onRebuild(cb: () => void): () => void;
175
+ /**
176
+ * Fires when the pad MOVES without being rebuilt — a 3D renderer tilting to show a trigger.
177
+ *
178
+ * Anything positioned from {@link partRect} should re-place itself here, or it stays where the pad
179
+ * used to be. Returns an unsubscribe; a no-op on renderers that never move.
180
+ */
181
+ onProjectionChange(cb: () => void): () => void;
149
182
  setVisible(on: boolean): void;
150
183
  dispose(): void;
151
184
  }
@@ -1 +1 @@
1
- {"version":3,"file":"controller-pad.d.ts","sourceRoot":"","sources":["../../../src/ui/controller/controller-pad.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AAClF,OAAO,EAAqB,KAAK,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAG5E,OAAO,EAAoD,KAAK,SAAS,EAAE,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAE7G,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAW,MAAM,YAAY,CAAC;AAElE;;;;;;GAMG;AACH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,mBAAmB,CAAC;IAC7B,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,EAAE,mBAAmB,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;CACrE;AAED,MAAM,WAAW,mBAAmB;IAClC,2GAA2G;IAC3G,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB;;;;;;;;;OASG;IACH,QAAQ,CAAC,EAAE,WAAW,CAAC;CACxB;AAED;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE;QAAE,IAAI,EAAE,WAAW,CAAC;QAAC,IAAI,EAAE,UAAU,CAAA;KAAE,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAC/E,yGAAyG;IACzG,IAAI,CAAC,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAAC;IAC9B;;;OAGG;IACH,WAAW,CAAC,IAAI,WAAW,EAAE,CAAC;IAC9B,uGAAuG;IACvG,QAAQ,CAAC,EAAE,gBAAgB,CAAC;CAC7B;AAED,MAAM,WAAW,oBAAoB;IACnC,+CAA+C;IAC/C,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB;;;;OAIG;IACH,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB;;;OAGG;IACH,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,gDAAgD;IAChD,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B,qEAAqE;IACrE,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,2FAA2F;IAC3F,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,gGAAgG;IAChG,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,SAAS,UAAU,EAAE,CAAC;IAClC;;;;;;;;;OASG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAC9B,iGAAiG;IACjG,GAAG,IAAI,MAAM,CAAC;IACd,MAAM,IAAI,SAAS,CAAC;IACpB,MAAM,IAAI,SAAS,CAAC;IACpB;;;OAGG;IACH,QAAQ,IAAI,QAAQ,CAAC;IACrB,yFAAyF;IACzF,KAAK,IAAI,WAAW,CAAC;IACrB,mGAAmG;IACnG,SAAS,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC;IACtC,UAAU,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAAC;IAC9B,OAAO,IAAI,IAAI,CAAC;CACjB;AAmBD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,GAAE,oBAAyB,GAAG,aAAa,CA+JpG"}
1
+ {"version":3,"file":"controller-pad.d.ts","sourceRoot":"","sources":["../../../src/ui/controller/controller-pad.ts"],"names":[],"mappings":"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"}
@@ -34,7 +34,8 @@
34
34
  import { DEFAULT_GLYPH_SET } from "../../protocol/glyphs.js";
35
35
  import { layoutForBrand } from "./layouts/index.js";
36
36
  import { DPAD_DIRECTIONS, litPartOfButton, litPartOfControl, triggerSideOfPart } from "./parts-map.js";
37
- import { buildPadSvg, createPadDriver, STICK_LIT_DEADZONE } from "./pad-svg.js";
37
+ import { STICK_LIT_DEADZONE } from "./pad-svg.js";
38
+ import { createSvgPadRenderer, } from "./renderer.js";
38
39
  import { injectPadCss } from "./styles.js";
39
40
  const DPAD_NAMES = ["UP", "DOWN", "LEFT", "RIGHT"];
40
41
  /** Explicit option → what the rider's hardware reports → the SDK-wide fallback. */
@@ -64,11 +65,16 @@ export function mountControllerPad(host, opts = {}) {
64
65
  /** Everything currently held, so a rebuild can restore the lit state rather than dropping it. */
65
66
  const held = new Set();
66
67
  const rebuildCbs = new Set();
68
+ /** Subscribers to renderer movement, re-attached whenever the renderer is replaced. */
69
+ const projectionCbs = new Set();
67
70
  let glyphSet = resolveGlyphSet(opts);
68
71
  let brand = resolveBrand(opts, glyphSet);
69
- let pad;
72
+ // `undefined` only before the first `build()`, which runs immediately below — the non-null assertions
73
+ // on the accessors are safe for exactly that reason.
74
+ let renderer;
70
75
  let driver;
71
76
  let layout;
77
+ const makeRenderer = opts.renderer ?? createSvgPadRenderer;
72
78
  const availableParts = () => {
73
79
  if (!opts.available)
74
80
  return null;
@@ -81,12 +87,23 @@ export function mountControllerPad(host, opts = {}) {
81
87
  return parts;
82
88
  };
83
89
  function build() {
90
+ // Dispose the outgoing renderer BEFORE dropping its node: a three.js one holds a WebGL context and
91
+ // GPU buffers that clearing the DOM would leak. The flat renderer has nothing to release, so this
92
+ // was invisible until a second renderer existed.
93
+ renderer?.dispose();
84
94
  layout = layoutForBrand(brand);
85
- pad = buildPadSvg(layout, { labels: opts.labels ?? true });
86
- driver = createPadDriver(pad, layout, { allowShellOwned: opts.allowShellOwned });
95
+ renderer = makeRenderer(layout, {
96
+ labels: opts.labels ?? true,
97
+ accent: opts.accent,
98
+ allowShellOwned: opts.allowShellOwned,
99
+ });
100
+ driver = renderer.driver;
87
101
  root.textContent = "";
88
- root.appendChild(pad.svg);
102
+ root.appendChild(renderer.node);
89
103
  driver.setAvailable(availableParts());
104
+ renderer.resize();
105
+ for (const cb of projectionCbs)
106
+ renderer.onProjectionChange?.(cb);
90
107
  }
91
108
  build();
92
109
  /**
@@ -187,7 +204,17 @@ export function mountControllerPad(host, opts = {}) {
187
204
  : undefined;
188
205
  return {
189
206
  root,
190
- svg: () => pad,
207
+ svg: () => {
208
+ const svg = renderer?.padSvg;
209
+ if (!svg) {
210
+ throw new Error("ControllerPad.svg() is only available on the flat SVG renderer — this pad is drawn by a " +
211
+ "custom renderer (e.g. the three.js Joy-Con). Use partRect()/setReferenced() instead.");
212
+ }
213
+ return svg;
214
+ },
215
+ renderer: () => renderer,
216
+ partRect: (part) => renderer.partRect(part),
217
+ setReferenced: (parts) => renderer.setReferenced(parts),
191
218
  driver: () => driver,
192
219
  layout: () => layout,
193
220
  glyphSet: () => glyphSet,
@@ -196,6 +223,16 @@ export function mountControllerPad(host, opts = {}) {
196
223
  rebuildCbs.add(cb);
197
224
  return () => rebuildCbs.delete(cb);
198
225
  },
226
+ onProjectionChange(cb) {
227
+ // Held per-renderer: a rebuild swaps the renderer, so re-subscribe through onRebuild as well.
228
+ projectionCbs.add(cb);
229
+ const offs = [...projectionCbs].map(() => renderer?.onProjectionChange?.(cb));
230
+ return () => {
231
+ projectionCbs.delete(cb);
232
+ for (const off of offs)
233
+ off?.();
234
+ };
235
+ },
199
236
  setVisible(on) {
200
237
  root.style.display = on ? "" : "none";
201
238
  },
@@ -205,8 +242,11 @@ export function mountControllerPad(host, opts = {}) {
205
242
  stopFrames();
206
243
  document.removeEventListener("visibilitychange", onVisibility);
207
244
  // Release everything before detaching: a button held at teardown must never leave a lit pad
208
- // behind if the caller re-parents or re-mounts the node.
245
+ // behind if the caller re-parents or re-mounts the node. The renderer's own dispose also frees
246
+ // whatever it holds beyond the DOM (a three.js one: geometries, materials, the WebGL context).
209
247
  driver.clearAll();
248
+ renderer?.dispose();
249
+ renderer = undefined;
210
250
  rebuildCbs.clear();
211
251
  root.remove();
212
252
  },
@@ -1 +1 @@
1
- {"version":3,"file":"controller-pad.js","sourceRoot":"","sources":["../../../src/ui/controller/controller-pad.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"controller-pad.js","sourceRoot":"","sources":["../../../src/ui/controller/controller-pad.ts"],"names":[],"mappings":"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"}
@@ -17,6 +17,7 @@ export * from "./tokens.js";
17
17
  export * from "./parts-map.js";
18
18
  export * from "./layouts/index.js";
19
19
  export * from "./pad-svg.js";
20
+ export * from "./renderer.js";
20
21
  export * from "./input-chip.js";
21
22
  export * from "./combo-strip.js";
22
23
  export * from "./controller-pad.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/controller/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ui/controller/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC"}
@@ -17,6 +17,7 @@ export * from "./tokens.js";
17
17
  export * from "./parts-map.js";
18
18
  export * from "./layouts/index.js";
19
19
  export * from "./pad-svg.js";
20
+ export * from "./renderer.js";
20
21
  export * from "./input-chip.js";
21
22
  export * from "./combo-strip.js";
22
23
  export * from "./controller-pad.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/ui/controller/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/ui/controller/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,118 @@
1
+ /**
2
+ * PAD RENDERER — the seam between the controller VIEWS and whatever actually draws the pad.
3
+ *
4
+ * The five views (`mountControllerPad`, `mountControllerMap`, `mountComboDemo`,
5
+ * `mountControlSpotlight`, `mountControlTrainer`) never draw a controller. They only ever:
6
+ *
7
+ * 1. tell it what to say → {@link PadDriver} (`setPart`, `setStick`, `setMeter`, …)
8
+ * 2. ask where a part is → {@link PadRenderer.partRect}
9
+ * 3. mark the parts a callout points at → {@link PadRenderer.setReferenced}
10
+ *
11
+ * That is the WHOLE contract, and it is small on purpose: everything else those views own — the
12
+ * timings, the `hint`/`on`/`done` grammar, waiting for the rider to actually perform a step, the
13
+ * re-lettering on a pad swap — is drawing-agnostic already. Naming the contract lets a second
14
+ * renderer exist (the three.js Joy-Con in `@rydr/game-sdk/three`) without any of it being duplicated.
15
+ *
16
+ * The default renderer is {@link createSvgPadRenderer}, which is exactly what the views did inline
17
+ * before this file existed. Nothing about the flat pad changed.
18
+ */
19
+ import type { PadDriver, PadSvg } from "./pad-svg.js";
20
+ import { type PadDriverOptions } from "./pad-svg.js";
21
+ import { type PadLayout, type PadPart } from "./types.js";
22
+ /**
23
+ * Where a part sits ON SCREEN, in viewport pixels — the same frame `getBoundingClientRect()` reports,
24
+ * so a caller subtracts its own host's rect and gets host-relative pixels.
25
+ *
26
+ * Deliberately the axis-aligned box and nothing more. A part in perspective is not a rectangle, but
27
+ * every consumer wants the same two things — a point to aim a caption at, and an edge to stop a leader
28
+ * line against — and those are both answerable from a box. Anything richer would be a 3D concept the
29
+ * SVG renderer could not honestly provide.
30
+ */
31
+ export interface PartRect {
32
+ left: number;
33
+ right: number;
34
+ top: number;
35
+ bottom: number;
36
+ width: number;
37
+ height: number;
38
+ }
39
+ /** Build a {@link PartRect} from an origin and a size. */
40
+ export declare function partRectOf(left: number, top: number, width: number, height: number): PartRect;
41
+ export interface PadRenderer {
42
+ /** The node to put in the pad's root. An `<svg>` for the flat renderer, a `<canvas>` for three.js. */
43
+ readonly node: SVGElement | HTMLElement;
44
+ readonly driver: PadDriver;
45
+ readonly layout: PadLayout;
46
+ /**
47
+ * Is the pad drawn as a LIT OBJECT IN VOLUME rather than a flat diagram? `true` for the three.js
48
+ * Joy-Con, absent for the SVG pad.
49
+ *
50
+ * Not a "which renderer is this" escape hatch — the views must never branch on that. It answers one
51
+ * question a caption has to ask: what am I sitting on? An opaque white chip is right over a flat
52
+ * diagram of known, uniform tone, and reads as a sticker stuck onto a shaded object whose local
53
+ * brightness the caption cannot predict. A renderer that draws in volume says so, and the views that
54
+ * put DOM ON the drawing pick the treatment that survives it (see the `.on-3d` rules in `styles.ts`).
55
+ */
56
+ readonly perspective?: boolean;
57
+ /**
58
+ * The flat renderer's node cache — **only** present on {@link createSvgPadRenderer}.
59
+ *
60
+ * A three.js pad has no `<svg>`, so this is `undefined` there rather than faked. It exists purely to
61
+ * back `ControllerPad.svg()` for callers styling the flat drawing by hand; nothing in the views
62
+ * reaches for it, and new code should use {@link partRect} / {@link setReferenced} instead.
63
+ */
64
+ readonly padSvg?: PadSvg;
65
+ /**
66
+ * Where a part currently sits on screen, or `null` for one this layout doesn't draw (a Zwift pod has
67
+ * no sticks) or one that isn't visible.
68
+ *
69
+ * **Projected from the layout's GEOMETRY, never measured off a drawn node.** That distinction is
70
+ * load-bearing for the sticks: the node registered as `lstickPress` lives inside the group that
71
+ * deflects, so measuring it pins a caption to the moving thumb-cap and the bubble drifts around as
72
+ * the stick sweeps. The geometry is the stick's RESTING centre — the one point on a stick that
73
+ * doesn't move, and the point a caption should aim at.
74
+ */
75
+ partRect(part: PadPart): PartRect | null;
76
+ /**
77
+ * Mark the parts a callout currently points at.
78
+ *
79
+ * Only meaningful for the parts drawn faint (the shell's View/Guide): a callout pointing at one makes
80
+ * it the subject of the screen, and leaving it at 40% then reads as "disabled". See the `.referenced`
81
+ * rule in `styles.ts`.
82
+ */
83
+ setReferenced(parts: ReadonlySet<PadPart>): void;
84
+ /** Re-read the host's size. The flat renderer scales by itself; a canvas has to be told. */
85
+ resize(): void;
86
+ /**
87
+ * Fires whenever {@link partRect} would answer differently WITHOUT anything being remounted — a 3D
88
+ * pad turning, say.
89
+ *
90
+ * The flat pad never moves on its own, so it doesn't implement this. A renderer that animates must,
91
+ * or every caption and leader line placed against it is left behind the moment it moves: those are
92
+ * DOM, positioned once from a projection, with nothing to tell them the projection changed.
93
+ */
94
+ onProjectionChange?(cb: () => void): () => void;
95
+ dispose(): void;
96
+ }
97
+ export interface PadRendererOptions extends PadDriverOptions {
98
+ /** Draw the face/trigger/bumper letters. Default true. */
99
+ labels?: boolean;
100
+ /** Accent colour for pressed parts. The flat renderer takes it from CSS; three.js needs it directly. */
101
+ accent?: string;
102
+ }
103
+ /**
104
+ * Builds a renderer for one layout. `mountControllerPad` calls this on every (re-)draw, so a factory
105
+ * must be safe to call repeatedly — a pad swap builds a fresh renderer and disposes the old one.
106
+ */
107
+ export type PadRendererFactory = (layout: PadLayout, opts: PadRendererOptions) => PadRenderer;
108
+ /**
109
+ * The flat SVG renderer — the default, and what every controller view drew before the seam existed.
110
+ *
111
+ * `partRect` is the one piece of genuinely new code here, and it isn't new logic: it's the projection
112
+ * `mountControlSpotlight` already did privately, moved somewhere both it and the map view can reach.
113
+ * The map view previously measured `getBoundingClientRect()` on the part node instead, which is why
114
+ * its leader lines used to chase a deflected stick cap around; going through the geometry fixes that
115
+ * as a side effect.
116
+ */
117
+ export declare function createSvgPadRenderer(layout: PadLayout, opts?: PadRendererOptions): PadRenderer;
118
+ //# sourceMappingURL=renderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../../src/ui/controller/renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,EAAgC,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEnF,OAAO,EAAc,KAAK,SAAS,EAAE,KAAK,OAAO,EAAE,MAAM,YAAY,CAAC;AAEtE;;;;;;;;GAQG;AACH,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,0DAA0D;AAC1D,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,QAAQ,CAE7F;AAED,MAAM,WAAW,WAAW;IAC1B,sGAAsG;IACtG,QAAQ,CAAC,IAAI,EAAE,UAAU,GAAG,WAAW,CAAC;IACxC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B;;;;;;;;;OASG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAC/B;;;;;;OAMG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;;;;;OASG;IACH,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,IAAI,CAAC;IACzC;;;;;;OAMG;IACH,aAAa,CAAC,KAAK,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;IACjD,4FAA4F;IAC5F,MAAM,IAAI,IAAI,CAAC;IACf;;;;;;;OAOG;IACH,kBAAkB,CAAC,CAAC,EAAE,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC;IAChD,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,kBAAmB,SAAQ,gBAAgB;IAC1D,0DAA0D;IAC1D,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,wGAAwG;IACxG,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,kBAAkB,KAAK,WAAW,CAAC;AAE9F;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,EAAE,IAAI,GAAE,kBAAuB,GAAG,WAAW,CA6DlG"}
@@ -0,0 +1,93 @@
1
+ /**
2
+ * PAD RENDERER — the seam between the controller VIEWS and whatever actually draws the pad.
3
+ *
4
+ * The five views (`mountControllerPad`, `mountControllerMap`, `mountComboDemo`,
5
+ * `mountControlSpotlight`, `mountControlTrainer`) never draw a controller. They only ever:
6
+ *
7
+ * 1. tell it what to say → {@link PadDriver} (`setPart`, `setStick`, `setMeter`, …)
8
+ * 2. ask where a part is → {@link PadRenderer.partRect}
9
+ * 3. mark the parts a callout points at → {@link PadRenderer.setReferenced}
10
+ *
11
+ * That is the WHOLE contract, and it is small on purpose: everything else those views own — the
12
+ * timings, the `hint`/`on`/`done` grammar, waiting for the rider to actually perform a step, the
13
+ * re-lettering on a pad swap — is drawing-agnostic already. Naming the contract lets a second
14
+ * renderer exist (the three.js Joy-Con in `@rydr/game-sdk/three`) without any of it being duplicated.
15
+ *
16
+ * The default renderer is {@link createSvgPadRenderer}, which is exactly what the views did inline
17
+ * before this file existed. Nothing about the flat pad changed.
18
+ */
19
+ import { buildPadSvg, createPadDriver } from "./pad-svg.js";
20
+ import { partGeomOf } from "./parts-map.js";
21
+ import { partCentre } from "./types.js";
22
+ /** Build a {@link PartRect} from an origin and a size. */
23
+ export function partRectOf(left, top, width, height) {
24
+ return { left, top, width, height, right: left + width, bottom: top + height };
25
+ }
26
+ /**
27
+ * The flat SVG renderer — the default, and what every controller view drew before the seam existed.
28
+ *
29
+ * `partRect` is the one piece of genuinely new code here, and it isn't new logic: it's the projection
30
+ * `mountControlSpotlight` already did privately, moved somewhere both it and the map view can reach.
31
+ * The map view previously measured `getBoundingClientRect()` on the part node instead, which is why
32
+ * its leader lines used to chase a deflected stick cap around; going through the geometry fixes that
33
+ * as a side effect.
34
+ */
35
+ export function createSvgPadRenderer(layout, opts = {}) {
36
+ const pad = buildPadSvg(layout, { labels: opts.labels ?? true });
37
+ const driver = createPadDriver(pad, layout, { allowShellOwned: opts.allowShellOwned });
38
+ return {
39
+ node: pad.svg,
40
+ driver,
41
+ layout,
42
+ padSvg: pad,
43
+ partRect(part) {
44
+ const geom = partGeomOf(layout, part);
45
+ const ctm = pad.svg.getScreenCTM();
46
+ if (!geom || !ctm)
47
+ return null;
48
+ let x;
49
+ let w;
50
+ let yTop;
51
+ let yBottom;
52
+ if (geom.kind === "circle") {
53
+ x = geom.cx - geom.r;
54
+ w = geom.r * 2;
55
+ yTop = geom.cy - geom.r;
56
+ yBottom = geom.cy + geom.r;
57
+ }
58
+ else if (geom.kind === "rect") {
59
+ x = geom.x;
60
+ w = geom.w;
61
+ yTop = geom.y;
62
+ yBottom = geom.y + geom.h;
63
+ }
64
+ else {
65
+ // A path part carries no cheap box, and no layout uses one for a part today.
66
+ const c = partCentre(geom);
67
+ x = c.x;
68
+ w = 0;
69
+ yTop = c.y;
70
+ yBottom = c.y;
71
+ }
72
+ const pt = pad.svg.createSVGPoint();
73
+ pt.x = x;
74
+ pt.y = yTop;
75
+ const topLeft = pt.matrixTransform(ctm);
76
+ pt.x = x + w;
77
+ pt.y = yBottom;
78
+ const bottomRight = pt.matrixTransform(ctm);
79
+ return partRectOf(topLeft.x, topLeft.y, bottomRight.x - topLeft.x, bottomRight.y - topLeft.y);
80
+ },
81
+ setReferenced(parts) {
82
+ for (const [name, node] of pad.parts)
83
+ node.classList.toggle("referenced", parts.has(name));
84
+ },
85
+ // The SVG scales itself through its viewBox — there is nothing to recompute on a resize.
86
+ resize() { },
87
+ dispose() {
88
+ driver.clearAll();
89
+ pad.svg.remove();
90
+ },
91
+ };
92
+ }
93
+ //# sourceMappingURL=renderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"renderer.js","sourceRoot":"","sources":["../../../src/ui/controller/renderer.ts"],"names":[],"mappings":"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"}
@@ -489,6 +489,36 @@ const CSS = `
489
489
  .rydr-padspot-tag.above.mine .rydr-padspot-caret { border-top-color: var(--pad-ok, #22c55e); }
490
490
  .rydr-padspot-tag.below.mine .rydr-padspot-caret { border-bottom-color: var(--pad-ok, #22c55e); }
491
491
 
492
+ /* ── the same caption over a pad drawn IN VOLUME (renderer.perspective) ──────────────────────────
493
+ The white chip above is right over the flat diagram: one known tone underneath, and a chip that
494
+ sits beside the drawing more than on it. On the three.js pad it lands on a shaded, lit shell whose
495
+ local brightness the caption cannot predict — so an opaque slab reads as a sticker, and worse, it
496
+ covers the very control it is naming. Here the caption is bare type instead: white, its own shadow,
497
+ nothing behind it. */
498
+ .rydr-padspot.on-3d .rydr-padspot-tag {
499
+ background: transparent;
500
+ color: #ffffff;
501
+ padding: 0;
502
+ border-radius: 0;
503
+ /* TWO layers, each doing a different job: the tight one keeps the letterforms legible where they
504
+ cross a pale shell (the Joy-Con's grey stick, a white rail), the wide diffuse one lifts the word
505
+ off whatever is behind it. One layer can do either, not both. */
506
+ text-shadow: 0 1px 2px rgba(0,0,0,0.9), 0 4px 14px rgba(0,0,0,0.65);
507
+ transition: opacity 300ms ease, color 200ms ease;
508
+ }
509
+ /* "That one was yours" — the tone moves to the TYPE, since there is no chip left to fill. */
510
+ .rydr-padspot.on-3d .rydr-padspot-tag.mine {
511
+ background: transparent;
512
+ color: var(--pad-ok, #22c55e);
513
+ }
514
+
515
+ /* NO POINTER AT ALL here — not the caret, not a chevron.
516
+ A pointer exists to disambiguate, and there is nothing to disambiguate: the control is lit, and the
517
+ caption is parked directly over it. Both looks were tried, and both read as debris left over from a
518
+ speech bubble that isn't there any more. The element stays in the DOM (the chip look needs it, and
519
+ the two looks swap on a pad rebuild) and is simply not drawn. */
520
+ .rydr-padspot.on-3d .rydr-padspot-caret { display: none; }
521
+
492
522
  /* A spotlight's highlights glide rather than snap: the base rule is a 60ms snap so a real press feels
493
523
  instant, which is right on a live pad and wrong here, where a control taking over from another should
494
524
  hand off visibly. Scoped to this view. */
@@ -1 +1 @@
1
- {"version":3,"file":"styles.js","sourceRoot":"","sources":["../../../src/ui/controller/styles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAE9D,MAAM,QAAQ,GAAG,cAAc,CAAC;AAChC,IAAI,WAAW,GAAG,KAAK,CAAC;AAExB,wFAAwF;AACxF,MAAM,UAAU,YAAY;IAC1B,IAAI,WAAW,IAAI,QAAQ,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,CAAC;QACrD,WAAW,GAAG,IAAI,CAAC;QACnB,OAAO;IACT,CAAC;IACD,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IAC9C,KAAK,CAAC,EAAE,GAAG,QAAQ,CAAC;IACpB,KAAK,CAAC,WAAW,GAAG,GAAG,CAAC;IACxB,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IACjC,WAAW,GAAG,IAAI,CAAC;AACrB,CAAC;AAED,qGAAqG;AACrG,mGAAmG;AACnG,MAAM,GAAG,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;2DA0B+C,WAAW;;;;;;;;;;;;;;;;;uBAiB/C,WAAW;uBACX,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uBAsKjB,iBAAiB,GAAG,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2T9C,CAAC"}
1
+ {"version":3,"file":"styles.js","sourceRoot":"","sources":["../../../src/ui/controller/styles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAE9D,MAAM,QAAQ,GAAG,cAAc,CAAC;AAChC,IAAI,WAAW,GAAG,KAAK,CAAC;AAExB,wFAAwF;AACxF,MAAM,UAAU,YAAY;IAC1B,IAAI,WAAW,IAAI,QAAQ,CAAC,cAAc,CAAC,QAAQ,CAAC,EAAE,CAAC;QACrD,WAAW,GAAG,IAAI,CAAC;QACnB,OAAO;IACT,CAAC;IACD,MAAM,KAAK,GAAG,QAAQ,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IAC9C,KAAK,CAAC,EAAE,GAAG,QAAQ,CAAC;IACpB,KAAK,CAAC,WAAW,GAAG,GAAG,CAAC;IACxB,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;IACjC,WAAW,GAAG,IAAI,CAAC;AACrB,CAAC;AAED,qGAAqG;AACrG,mGAAmG;AACnG,MAAM,GAAG,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;2DA0B+C,WAAW;;;;;;;;;;;;;;;;;uBAiB/C,WAAW;uBACX,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uBAsKjB,iBAAiB,GAAG,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyV9C,CAAC"}
@@ -16,6 +16,11 @@
16
16
  * declarative `ControlAction[]` and the SDK owns the rest — which physical button that is on the
17
17
  * rider's pad, the letter printed on it, the layout, and the animation.
18
18
  *
19
+ * And the **rider rig** (`mountRiderRig`) — the one drawing here whose subject is the BIKE rather than
20
+ * the pad: a cyclist pedalling on their trainer with their watts rising out of the roller, in three
21
+ * art directions. It is what a game puts on screen to say that the trainer is half of the
22
+ * controller. (Not `mountControlTrainer`, which is a guided lesson — see that file's header.)
23
+ *
19
24
  * Self-contained, like `@rydr/game-sdk/three`'s perf-overlay: it injects its own scoped `.rydr-ui-*`
20
25
  * CSS once into `<head>`, depends on no global styles or CSS variables, and pulls in no three.js — so
21
26
  * a game gets the look just by constructing a component. Wire any keycap to real input by passing the
@@ -43,9 +48,11 @@ export * from "./subtitle.js";
43
48
  export * from "./choice-card.js";
44
49
  export * from "./labeled-diamond.js";
45
50
  export * from "./solo-labeled-diamond.js";
51
+ export * from "./pad-hints.js";
46
52
  export * from "./rarity-card.js";
47
53
  export * from "./option-menu.js";
48
54
  export * from "./power-race.js";
55
+ export * from "./rider-rig.js";
49
56
  export * from "./admin-nav.js";
50
57
  export * from "./heat-vignette.js";
51
58
  export * from "./overheat-glitch.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ui/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,cAAc,aAAa,CAAC;AAC5B,cAAc,uBAAuB,CAAC;AACtC,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ui/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH,cAAc,aAAa,CAAC;AAC5B,cAAc,uBAAuB,CAAC;AACtC,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC"}
package/dist/ui/index.js CHANGED
@@ -16,6 +16,11 @@
16
16
  * declarative `ControlAction[]` and the SDK owns the rest — which physical button that is on the
17
17
  * rider's pad, the letter printed on it, the layout, and the animation.
18
18
  *
19
+ * And the **rider rig** (`mountRiderRig`) — the one drawing here whose subject is the BIKE rather than
20
+ * the pad: a cyclist pedalling on their trainer with their watts rising out of the roller, in three
21
+ * art directions. It is what a game puts on screen to say that the trainer is half of the
22
+ * controller. (Not `mountControlTrainer`, which is a guided lesson — see that file's header.)
23
+ *
19
24
  * Self-contained, like `@rydr/game-sdk/three`'s perf-overlay: it injects its own scoped `.rydr-ui-*`
20
25
  * CSS once into `<head>`, depends on no global styles or CSS variables, and pulls in no three.js — so
21
26
  * a game gets the look just by constructing a component. Wire any keycap to real input by passing the
@@ -43,9 +48,11 @@ export * from "./subtitle.js";
43
48
  export * from "./choice-card.js";
44
49
  export * from "./labeled-diamond.js";
45
50
  export * from "./solo-labeled-diamond.js";
51
+ export * from "./pad-hints.js";
46
52
  export * from "./rarity-card.js";
47
53
  export * from "./option-menu.js";
48
54
  export * from "./power-race.js";
55
+ export * from "./rider-rig.js";
49
56
  export * from "./admin-nav.js";
50
57
  export * from "./heat-vignette.js";
51
58
  export * from "./overheat-glitch.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ui/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,cAAc,aAAa,CAAC;AAC5B,cAAc,uBAAuB,CAAC;AACtC,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ui/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH,cAAc,aAAa,CAAC;AAC5B,cAAc,uBAAuB,CAAC;AACtC,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC;AAC9B,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,kBAAkB,CAAC;AACjC,cAAc,iBAAiB,CAAC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC"}
@@ -105,6 +105,17 @@ export interface KeycapOptions {
105
105
  * size is what keeps it legible from a few feet away on a trainer.
106
106
  */
107
107
  scale?: number;
108
+ /**
109
+ * Mark this cap as a HINT — a prompt naming a button the rider is invited to press — so it is not
110
+ * drawn when there is nothing to press it with. See `./pad-hints.ts` for the condition and
111
+ * {@link watchPadHints}, which a game must call once for this to do anything.
112
+ *
113
+ * **Default `false`, and that default is load-bearing.** This same factory also draws keycaps that
114
+ * are CONTROLS rather than prompts — guitar-hero's second gameplay renders its four face pads from
115
+ * it, rydr-game-party's mini-game HUDs likewise — and hiding those on a phone would delete the
116
+ * game. Opting in is how a cap says "I am only advice".
117
+ */
118
+ hint?: boolean;
108
119
  }
109
120
  /** A bare keycap with its state setters. */
110
121
  export interface Keycap {
@@ -1 +1 @@
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;AAEtF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAE1D,+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;;;;;;;;GAQG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE;QAAE,IAAI,EAAE,WAAW,CAAC;QAAC,IAAI,EAAE,UAAU,CAAA;KAAE,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;CAChF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE;IAAE,QAAQ,CAAC,EAAE,QAAQ,CAAC;IAAC,KAAK,CAAC,EAAE,YAAY,CAAA;CAAE,GAAG,QAAQ,CAI7F;AAED,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"}
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;AAEtF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAE1D,+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;;;;;;;;GAQG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE;QAAE,IAAI,EAAE,WAAW,CAAC;QAAC,IAAI,EAAE,UAAU,CAAA;KAAE,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;CAChF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE;IAAE,QAAQ,CAAC,EAAE,QAAQ,CAAC;IAAC,KAAK,CAAC,EAAE,YAAY,CAAA;CAAE,GAAG,QAAQ,CAI7F;AAED,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;IACf;;;;;;;;;OASG;IACH,IAAI,CAAC,EAAE,OAAO,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;AA6ND;;;;;;;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
@@ -222,6 +222,9 @@ function build(activePos, pressName, face, opts, accent) {
222
222
  const colored = opts.colored ?? false; // mono is the RYDR look — see KeycapOptions.colored
223
223
  const scale = opts.scale ?? 1;
224
224
  const { el, activePip } = buildPips(activePos, variant, colored, animate, face, scale, accent);
225
+ // Opt-in (see KeycapOptions.hint): the stylesheet hides these when nothing can press them.
226
+ if (opts.hint)
227
+ el.classList.add("rydr-ui-pad-hint");
225
228
  const num = activePip.querySelector(".rydr-ui-cd-num");
226
229
  // The countdown's type lives in CSS; scale it with the pip so a small cap's number still fits inside.
227
230
  if (num && scale !== 1)