@rydr/game-sdk 7.0.1 → 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/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
package/README.md
CHANGED
|
@@ -519,6 +519,25 @@ dia.cards.Z.keycap.setCooldown(0.4, 3); // depleting ring + countdown
|
|
|
519
519
|
- **`mountDialogueCard`** — an NPC dialogue box (name + typewriter line + continue keycap). **`mountChoiceCard`** — a player menu (prompt + selectable list, ▲▼ + confirm). **`mountLabeledDiamond`** — a pip cluster with a card-seated label radiating from each active button.
|
|
520
520
|
- **`createLabelKeycap(button, opts)`** — a keycap for a button printed with a WORD, not a letter (`OPTIONS` → "Menu"/"Options"/"+", `LT`/`RT`, the stick clicks): a pill instead of a pip, same state machine.
|
|
521
521
|
- **`mountPauseMenu(host, opts)`** — **the shared in-game menu**, opened by the game's own `OPTIONS` button: the game's name big at the top *in the game's own font*, a free `Resume` row plus the game's own rows, each able to advertise the `shortcut` that does the same thing during play. It takes the controller over while up (`session.grabInput`) and declares `setActivity("menu")` so the trainer eases — but it **cannot** pause your loop; freeze that yourself in `onOpen`/`onClose`. Don't hand-roll a pause screen: [`src/ui/README.md`](src/ui/README.md) has the full contract.
|
|
522
|
+
- **The controller family** — for showing a rider their whole control scheme. **`mountControllerPad`** draws the controller in their hands and lights it as they press (stick caps follow the real axes). **`mountControllerMap`** surrounds that pad with action callouts, each joined by a line to its button — the "Commandes" screen. **`mountComboDemo`** loops an animation of the combination one action requires. Describe your controls **once**, declaratively, and the SDK owns the rest:
|
|
523
|
+
|
|
524
|
+
```ts
|
|
525
|
+
import { mountControllerMap, type ControlAction } from "@rydr/game-sdk/ui";
|
|
526
|
+
|
|
527
|
+
const CONTROLS: ControlAction[] = [
|
|
528
|
+
{ label: "Se déplacer", combo: ["LSTICK"] }, // a whole stick = free movement
|
|
529
|
+
{ label: "Freiner", combo: ["LT"] },
|
|
530
|
+
{ label: "Tir chargé", combo: ["RT", "DIAMOND_DOWN"], hint: "Maintenir" },
|
|
531
|
+
{ label: "Dash", combo: ["LSTICK_PRESS", "LT"] }, // the line lands on the trigger
|
|
532
|
+
];
|
|
533
|
+
mountControllerMap(pauseOverlay, { press: session, actions: CONTROLS, title: "Commandes" });
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
You never name a letter: you say `DIAMOND_DOWN` and the rider sees `A`, `✕` or `B` on the correct
|
|
537
|
+
physical button — on a Switch Pro the highlight stays on the *bottom* button while only the lettering
|
|
538
|
+
shifts — and it re-letters itself if they swap pads mid-screen. Six silhouettes ship, including a
|
|
539
|
+
**Zwift Play / Ride** shape whose absent controls (no joysticks, no triggers) simply aren't drawn.
|
|
540
|
+
Read [`src/ui/README.md`](src/ui/README.md) → "Showing your controls" before building a legend by hand.
|
|
522
541
|
|
|
523
542
|
Wire any keycap to real input by passing the `session` — it structurally satisfies `ButtonSource`, and the keycap then shows its pressed sink while its button is held. The kit speaks the canonical `ButtonName`/`ButtonEdge` vocabulary.
|
|
524
543
|
|
|
@@ -44,4 +44,11 @@ export declare function buttonLabel(set: GlyphSet, name: ButtonName): string;
|
|
|
44
44
|
* positionally (keycaps, prompts) and treats everything else as a plain label.
|
|
45
45
|
*/
|
|
46
46
|
export declare function isDiamondButton(name: ButtonName): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* The label printed on an upper shoulder button for `set` — `("playstation", "left")` → `"L1"`.
|
|
49
|
+
*
|
|
50
|
+
* Use it when naming the rider's resistance controls. Like {@link buttonLabel}, this is the only place
|
|
51
|
+
* allowed to know these strings; never hard-code `"L1"` in a prompt.
|
|
52
|
+
*/
|
|
53
|
+
export declare function bumperLabel(set: GlyphSet, side: "left" | "right"): string;
|
|
47
54
|
//# sourceMappingURL=glyphs.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glyphs.d.ts","sourceRoot":"","sources":["../../src/protocol/glyphs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE/C;;;;;;;GAOG;AACH,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,aAAa,GAAG,UAAU,GAAG,OAAO,CAAC;AAErE,0DAA0D;AAC1D,eAAO,MAAM,iBAAiB,EAAE,QAAiB,CAAC;AA4DlD;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,CAGnE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAEzD"}
|
|
1
|
+
{"version":3,"file":"glyphs.d.ts","sourceRoot":"","sources":["../../src/protocol/glyphs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE/C;;;;;;;GAOG;AACH,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,aAAa,GAAG,UAAU,GAAG,OAAO,CAAC;AAErE,0DAA0D;AAC1D,eAAO,MAAM,iBAAiB,EAAE,QAAiB,CAAC;AA4DlD;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,CAGnE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAEzD;AAoBD;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,CAEzE"}
|
package/dist/protocol/glyphs.js
CHANGED
|
@@ -93,4 +93,30 @@ export function buttonLabel(set, name) {
|
|
|
93
93
|
export function isDiamondButton(name) {
|
|
94
94
|
return name in FACE[DEFAULT_GLYPH_SET];
|
|
95
95
|
}
|
|
96
|
+
/**
|
|
97
|
+
* The UPPER shoulder buttons — the ones that are NOT game input.
|
|
98
|
+
*
|
|
99
|
+
* They deliberately have no {@link ButtonName}: on this platform the upper shoulders are the rider's
|
|
100
|
+
* trainer resistance − / + and are handled by the shell, never delivered to a game (see the shell-owned
|
|
101
|
+
* keys in `protocol/buttons.ts`). They still need lettering, though, because the shell has to *name*
|
|
102
|
+
* them when teaching a rider where they are — and because the controller drawing prints them.
|
|
103
|
+
*
|
|
104
|
+
* Separate from {@link SHOULDERS}, which covers the lower triggers a game DOES receive (`LT`/`RT`).
|
|
105
|
+
*/
|
|
106
|
+
const BUMPERS = {
|
|
107
|
+
xbox: { left: "LB", right: "RB" },
|
|
108
|
+
playstation: { left: "L1", right: "R1" },
|
|
109
|
+
nintendo: { left: "L", right: "R" },
|
|
110
|
+
// Zwift Play has no lettering on its paddles at all, so say what they DO.
|
|
111
|
+
zwift: { left: "−", right: "+" },
|
|
112
|
+
};
|
|
113
|
+
/**
|
|
114
|
+
* The label printed on an upper shoulder button for `set` — `("playstation", "left")` → `"L1"`.
|
|
115
|
+
*
|
|
116
|
+
* Use it when naming the rider's resistance controls. Like {@link buttonLabel}, this is the only place
|
|
117
|
+
* allowed to know these strings; never hard-code `"L1"` in a prompt.
|
|
118
|
+
*/
|
|
119
|
+
export function bumperLabel(set, side) {
|
|
120
|
+
return (BUMPERS[set] ?? BUMPERS[DEFAULT_GLYPH_SET])[side];
|
|
121
|
+
}
|
|
96
122
|
//# sourceMappingURL=glyphs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glyphs.js","sourceRoot":"","sources":["../../src/protocol/glyphs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAcH,0DAA0D;AAC1D,MAAM,CAAC,MAAM,iBAAiB,GAAa,MAAM,CAAC;AAElD;;;;;;;GAOG;AACH,MAAM,IAAI,GAAiE;IACzE,2DAA2D;IAC3D,IAAI,EAAE,YAAY,CAAC,EAAE,YAAY,EAAE,GAAG,EAAE,aAAa,EAAE,GAAG,EAAE,YAAY,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE;IAChG,WAAW,EAAE,KAAK,CAAC,EAAE,YAAY,EAAE,GAAG,EAAE,aAAa,EAAE,GAAG,EAAE,YAAY,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE;IAChG,QAAQ,EAAE,QAAQ,CAAC,EAAE,YAAY,EAAE,GAAG,EAAE,aAAa,EAAE,GAAG,EAAE,YAAY,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE;IAChG,KAAK,EAAE,WAAW,CAAC,EAAE,YAAY,EAAE,GAAG,EAAE,aAAa,EAAE,GAAG,EAAE,YAAY,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE;CACjG,CAAC;AAEF,gGAAgG;AAChG,MAAM,SAAS,GAAiE;IAC9E,IAAI,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE;IACpE,WAAW,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE;IAC3E,QAAQ,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,EAAE,YAAY,EAAE,GAAG,EAAE;IACtE,KAAK,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE;CACtE,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,GAAiE;IAC3E,IAAI,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE;IACzB,WAAW,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE;IACnC,QAAQ,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE;IAC1B,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE;CAC3B,CAAC;AAEF,+EAA+E;AAC/E,MAAM,UAAU,GAAqC;IACnD,EAAE,EAAE,GAAG;IACP,IAAI,EAAE,GAAG;IACT,IAAI,EAAE,GAAG;IACT,KAAK,EAAE,GAAG;IACV,GAAG,EAAE,GAAG;IACR,KAAK,EAAE,GAAG;IACV,KAAK,EAAE,GAAG;IACV,MAAM,EAAE,GAAG;CACZ,CAAC;AAEF;;;;;;;;;;GAUG;AACH,MAAM,UAAU,WAAW,CAAC,GAAa,EAAE,IAAgB;IACzD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,iBAAiB,CAAC;IACnD,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC;AAC3G,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,IAAgB;IAC9C,OAAO,IAAI,IAAI,IAAI,CAAC,iBAAiB,CAAC,CAAC;AACzC,CAAC"}
|
|
1
|
+
{"version":3,"file":"glyphs.js","sourceRoot":"","sources":["../../src/protocol/glyphs.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,5 +9,5 @@
|
|
|
9
9
|
export declare const RYDR_PROTOCOL_VERSION: 30;
|
|
10
10
|
/** Semver of this SDK build. Sent in the handshake for telemetry/debugging.
|
|
11
11
|
* (Bumped to 2.0.0 by `npm version major` on release — see CHANGELOG [Unreleased].) */
|
|
12
|
-
export declare const RYDR_SDK_VERSION = "7.0
|
|
12
|
+
export declare const RYDR_SDK_VERSION = "7.1.0";
|
|
13
13
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/protocol/version.js
CHANGED
|
@@ -176,5 +176,5 @@
|
|
|
176
176
|
export const RYDR_PROTOCOL_VERSION = 30;
|
|
177
177
|
/** Semver of this SDK build. Sent in the handshake for telemetry/debugging.
|
|
178
178
|
* (Bumped to 2.0.0 by `npm version major` on release — see CHANGELOG [Unreleased].) */
|
|
179
|
-
export const RYDR_SDK_VERSION = "7.0
|
|
179
|
+
export const RYDR_SDK_VERSION = "7.1.0";
|
|
180
180
|
//# sourceMappingURL=version.js.map
|
package/dist/ui/README.md
CHANGED
|
@@ -53,6 +53,13 @@ feed its `{x, y, onScreen}` into `setScreenPos`/`setVisible` — don't compute p
|
|
|
53
53
|
| `mountOverheatHudBar(host, opts)` | fn | **The whole overheat package**: centred inferno bar + label + COOLING DOWN countdown, composing the vignette and glitch above. One `update(heat01, locked, lockoutRemaining)` per frame. |
|
|
54
54
|
| `createLabelKeycap(button, opts)` | fn | A keycap for a button printed with a WORD, not a letter — `OPTIONS` ("Menu"/"Options"/"+"), `LT`/`RT`, the stick clicks. A pill, not a pip. |
|
|
55
55
|
| `mountPauseMenu(host, opts)` | fn | **The in-game menu**, opened by the game's own `OPTIONS` button: game name big in YOUR font, a free `Resume` row + your own rows, each able to advertise its in-game `shortcut`. Takes the controller over while up and eases the trainer. See below. |
|
|
56
|
+
| `mountControllerPad(host, opts)` | fn | **The rider's controller, drawn live** — buttons light while held, stick caps follow the real axes. Pass `press: session`. |
|
|
57
|
+
| `mountControllerMap(host, opts)` | fn | **The controls screen** — that pad flanked by action callouts, each joined by a line to its button. Takes a declarative `ControlAction[]`. |
|
|
58
|
+
| `mountComboDemo(host, opts)` | fn | **"Do this" animation** — loops the combination one action requires: buttons sink in, the stick swings, release, repeat. |
|
|
59
|
+
| `mountControlTrainer(host, opts)` | fn | **Guided lesson** — a title, one panel per step side by side, one shared controller below. Watches the rider: white "do this" → blue "doing it" → green ✓. Fires `onComplete` when every step is done. |
|
|
60
|
+
| `createComboStrip(action, opts)` | fn | Just the chip row for one action (`[L2] + [✕]`), for embedding in your own layout. |
|
|
61
|
+
| `createInputChip(token, opts)` | fn | One control's pictogram, for embedding in your own layout. Delegates to `createKeycap` / `createDpadKeycap` / `createLabelKeycap` for the buttons, and draws its own stick pictograms. The atom the two views are built from. |
|
|
62
|
+
| `DEFAULT_STICK_STYLE` | const | The joystick drawing convention the kit uses (`"profile"`). Override per-call with `stickStyle`. |
|
|
56
63
|
| `injectCss()` | fn | Force the `.rydr-ui-*` CSS into `<head>` early (components call it for you). |
|
|
57
64
|
|
|
58
65
|
Types: `DiamondButton` (`"DIAMOND_UP"\|"DIAMOND_DOWN"\|"DIAMOND_LEFT"\|"DIAMOND_RIGHT"`), `DirButton`, `KeycapVariant` (`"full"\|"solo"`),
|
|
@@ -100,6 +107,118 @@ freeze them in `onOpen`/`onClose`. What it *guarantees* is that a game which kee
|
|
|
100
107
|
handlers go quiet, `isDown`/`stick` read resting, and anything held is released first. It also declares
|
|
101
108
|
`setActivity("menu")` while up and `"playing"` on close, so trainer resistance eases like on any other
|
|
102
109
|
non-racing screen.
|
|
110
|
+
`LabeledDiamond`, `ActionDiamond`, `Rarity`, `RarityCard`,
|
|
111
|
+
`ControlAction`, `ComboToken`, `StickDir`, `StickPictogramStyle`, `PadInputSource`, `PadBrandKey`, `PadPart`, `PadLayout`,
|
|
112
|
+
`ControllerPad`, `ControllerMap`, `ComboDemo`, `InputChip`, `ComboStrip`.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Showing your controls
|
|
117
|
+
|
|
118
|
+
**Don't hand-build a control legend.** Describe your scheme once and pass it in; the SDK owns which
|
|
119
|
+
physical button that is on the rider's pad, the letter printed on it, the layout, the callout lines and
|
|
120
|
+
the animation.
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
import { mountControllerMap, mountComboDemo, type ControlAction } from "@rydr/game-sdk/ui";
|
|
124
|
+
|
|
125
|
+
const CONTROLS: ControlAction[] = [
|
|
126
|
+
{ label: "Se déplacer", combo: ["LSTICK"], hint: "Stick gauche" },
|
|
127
|
+
{ label: "Freiner", combo: ["LT"] },
|
|
128
|
+
{ label: "Sauter", combo: ["DIAMOND_DOWN"] },
|
|
129
|
+
{ label: "Tir chargé", combo: ["RT", "DIAMOND_DOWN"], hint: "Maintenir" },
|
|
130
|
+
{ label: "Dash", combo: ["LSTICK_PRESS", "LT"] },
|
|
131
|
+
{ label: "Ultime", combo: ["DIAMOND_UP", "DIAMOND_LEFT"], disabled: true },
|
|
132
|
+
];
|
|
133
|
+
|
|
134
|
+
// STATIC — the whole scheme at once. An inline widget: you own the host.
|
|
135
|
+
mountControllerMap(pauseOverlay, { press: session, actions: CONTROLS, title: "Commandes" });
|
|
136
|
+
|
|
137
|
+
// DYNAMIC — "here's how you do this one", looping.
|
|
138
|
+
const demo = mountComboDemo(tutorialHost, { press: session, action: CONTROLS[4] });
|
|
139
|
+
demo.setAction(CONTROLS[3]); // swaps cleanly mid-loop
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
A **combo token** is a `ButtonName` (`"LT"`, `"DIAMOND_DOWN"`, `"UP"`), a whole stick (`"LSTICK"` —
|
|
143
|
+
free movement), or a stick pushed one way (`"LSTICK:left"`). One token is a simple control; several
|
|
144
|
+
render as `[L2] + [✕]`, or `[L2] → [✕]` with `sequence: true`.
|
|
145
|
+
|
|
146
|
+
**The callout line points at the first *non-generic* token** — sticks and the d-pad are "generic"
|
|
147
|
+
because many actions share them, so `["LSTICK_PRESS", "LT"]` points at the trigger, not at the stick
|
|
148
|
+
every other action also mentions. Set `anchor` on the action to override. Sides and column order are
|
|
149
|
+
derived from where each button physically sits on the layout, so they stay right across Xbox,
|
|
150
|
+
PlayStation, Switch Pro, Joy-Con and Zwift shapes; set `side` to override.
|
|
151
|
+
|
|
152
|
+
**It's an inline widget, not a screen** — no backdrop, no close button, no fixed positioning. You decide
|
|
153
|
+
whether the host is a pause overlay, a pre-race panel or a settings tab:
|
|
154
|
+
|
|
155
|
+
```ts
|
|
156
|
+
const overlay = document.createElement("div");
|
|
157
|
+
overlay.style.cssText = "position:fixed;inset:0;display:grid;place-items:center;background:rgba(4,8,14,.72)";
|
|
158
|
+
document.body.appendChild(overlay);
|
|
159
|
+
mountControllerMap(overlay, { press: session, actions: CONTROLS });
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Notes worth knowing:
|
|
163
|
+
|
|
164
|
+
- **Never name a letter.** You say `DIAMOND_DOWN`; the rider sees `A`, `✕` or `B` on the right physical
|
|
165
|
+
button. On a Switch Pro the highlight stays on the *bottom* button while the letters shift — that's
|
|
166
|
+
the whole point of the positional vocabulary. The views also **re-letter themselves** if the rider
|
|
167
|
+
swaps pads mid-screen (pass `press: session`), so you never rebuild them.
|
|
168
|
+
- **`LT`/`RT` are your shoulder buttons**, and they letter as `LT` / `L2` / `ZL`. The upper `L1`/`R1`
|
|
169
|
+
bumpers are the shell's resistance − / +, and `View`/`Guide` are the shell's too — all of them are
|
|
170
|
+
drawn faint and can never light, so a rider can tell "this game doesn't use that" from "that isn't
|
|
171
|
+
the game's to use".
|
|
172
|
+
- **Devices differ.** A Zwift Play has no joysticks and no triggers, so they aren't drawn at all. A
|
|
173
|
+
phone exposes only the confirm/back pair — the protocol can't tell us which buttons a device has, so
|
|
174
|
+
pass `available: [...]` if your game knows, and don't gate a required flow behind a rare control.
|
|
175
|
+
- **The joysticks are pictures, not letters.** `LSTICK` draws a well ringed by four arrows (move any
|
|
176
|
+
way), `LSTICK:left` slides the cap that way with one arrow, and `LSTICK_PRESS` draws a **side view** of
|
|
177
|
+
the stick being pushed down — because a click is motion straight at the viewer, which a top-down
|
|
178
|
+
drawing cannot show, and because "L3" tells a rider nothing about what to do with their thumb (the
|
|
179
|
+
brand letter is still in the chip's tooltip). Three conventions exist via `stickStyle`: `"profile"`
|
|
180
|
+
(the default — use it), `"topdown"`, `"glyph"`. Every *button* shape comes from the keycap factories, so
|
|
181
|
+
a trigger or OPTIONS reads identically in a legend and in an in-game prompt.
|
|
182
|
+
- Tuned for up to **5 callouts per side**; past that it warns rather than dropping one.
|
|
183
|
+
- Live catalog: `npm run showcase` in the SDK repo, or the platform's `/game-ui` route.
|
|
184
|
+
|
|
185
|
+
### Teaching a control — `mountControlTrainer`
|
|
186
|
+
|
|
187
|
+
For a lesson the rider has to *perform*, not just watch. Built for paired controls: one concept, two
|
|
188
|
+
linked halves, **one shared controller drawing** below both panels.
|
|
189
|
+
|
|
190
|
+
```ts
|
|
191
|
+
mountControlTrainer(modalBody, {
|
|
192
|
+
title: "Changer la résistance",
|
|
193
|
+
press: shellInput,
|
|
194
|
+
steps: [
|
|
195
|
+
{ label: "Réduire la résistance", combo: ["LSTICK_PRESS", "LB"] },
|
|
196
|
+
{ label: "Augmenter la résistance", combo: ["LSTICK_PRESS", "RB"] },
|
|
197
|
+
],
|
|
198
|
+
onComplete: () => closeModal(), // the component never closes itself
|
|
199
|
+
});
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Each step walks three states, on both its chips and the shared pad: **whitish + pulsing** ("do this"),
|
|
203
|
+
**accent, pulse stops** ("you're doing it"), **green + ✓** ("done"). The prompt shows **one step at a
|
|
204
|
+
time, alternating**, and builds each combination **cumulatively** — the stick click lights, stays lit, and
|
|
205
|
+
the shoulder joins it a beat later; then the other half takes its turn, and it loops. **The two surfaces speak different languages.** The
|
|
206
|
+
**pad** is physical — white = *press this*, blue = *you're pressing it*, and **never green**; white and blue
|
|
207
|
+
have already taught the rider that colour there means *now*, so progress as a third colour reads as "and this
|
|
208
|
+
one too". The **panels** are logical — grey = to do, green + ✓ = done, and that stays for the rest of the
|
|
209
|
+
lesson. The confirmation still lands on the controls the rider just pressed, because a panel's chips picture
|
|
210
|
+
the same combination one line up. Nothing special happens to the pad at completion: blue persists while the
|
|
211
|
+
controls are held and clears when they let go, which is simply the truth of the hardware. A step goes green **the moment its whole
|
|
212
|
+
combination is held** — holding all of it *is* doing it, so there is nothing to wait for, and it stays green
|
|
213
|
+
whether or not the rider keeps the controls down. Blue is the state in between: on a two-control step, after
|
|
214
|
+
the first control and before the second. Focus also lingers on a step that has just gone green before the
|
|
215
|
+
rotation moves on, so "you did it" lands before "now this one".
|
|
216
|
+
|
|
217
|
+
> **⚠️ `LB` / `RB` (the upper shoulders) are shell-owned and a game cannot observe them.** The SDK client turns those
|
|
218
|
+
> keys into `trainer.adjustResistance` intents; `session.onButton` never fires for them. A game can train
|
|
219
|
+
> its *own* buttons, but a resistance lesson has to be driven by the shell — which is also the only place
|
|
220
|
+
> that lesson belongs. `mountControllerMap` may still *point at* them; only the interactive trainer needs
|
|
221
|
+
> a source that sees them.
|
|
103
222
|
|
|
104
223
|
---
|
|
105
224
|
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* COMBO DEMO — the dynamic view: a looping animation of the combination a rider must perform.
|
|
3
|
+
*
|
|
4
|
+
* ```ts
|
|
5
|
+
* const demo = mountComboDemo(host, {
|
|
6
|
+
* press: session, // for the rider's lettering, NOT for input
|
|
7
|
+
* action: { label: "Dash", combo: ["LT", "LSTICK:left"] },
|
|
8
|
+
* });
|
|
9
|
+
* demo.setAction(next); // swaps cleanly mid-loop
|
|
10
|
+
* ```
|
|
11
|
+
*
|
|
12
|
+
* The timeline is **derived from the combo**, never authored per action, which is what keeps it generic:
|
|
13
|
+
*
|
|
14
|
+
* - *hold* (default) — idle, then each control engages in turn 200 ms apart (a stick eases to full
|
|
15
|
+
* deflection rather than snapping), everything holds together for a beat, releases, and repeats. The
|
|
16
|
+
* stagger is the point: it shows that the controls are held *simultaneously*, which a single
|
|
17
|
+
* all-at-once flash does not.
|
|
18
|
+
* - *sequence* (`action.sequence`) — each control presses, holds and releases in turn, with the strip's
|
|
19
|
+
* `→` separators filling in behind the current step.
|
|
20
|
+
* - a stick token with no direction sweeps once around its travel circle: "any direction".
|
|
21
|
+
*
|
|
22
|
+
* It drives exactly the same `PadDriver.setPart` / `setStick` and `ComboStrip.setPressed` that real input
|
|
23
|
+
* drives in the static view, so the demo and the live pad cannot drift apart — there is one renderer.
|
|
24
|
+
*
|
|
25
|
+
* **Self-driving, unlike `createPowerRace`.** This is an attract animation with no gameplay coupling, so
|
|
26
|
+
* it owns its own `requestAnimationFrame` rather than asking the game for a `tick(dt)`. It pauses while
|
|
27
|
+
* the tab is hidden, and `play()`/`pause()` are there for the caller.
|
|
28
|
+
*
|
|
29
|
+
* **`prefers-reduced-motion` is honoured by not animating at all**: the demo renders the fully-engaged end
|
|
30
|
+
* state statically. A looping motion graphic is precisely what that media query exists to suppress, and a
|
|
31
|
+
* still frame of "all of this, held together" still answers the rider's question.
|
|
32
|
+
*/
|
|
33
|
+
import type { GlyphSet } from "../../protocol/glyphs.js";
|
|
34
|
+
import { type ControllerPad, type PadInputSource } from "./controller-pad.js";
|
|
35
|
+
import type { StickPictogramStyle } from "./input-chip.js";
|
|
36
|
+
import { type ControlAction } from "./tokens.js";
|
|
37
|
+
import type { PadBrandKey } from "./types.js";
|
|
38
|
+
export interface ComboDemoOptions {
|
|
39
|
+
/** The single action to demonstrate. */
|
|
40
|
+
action: ControlAction;
|
|
41
|
+
/**
|
|
42
|
+
* A session, used ONLY to learn the rider's lettering and to follow pad swaps — the demo deliberately
|
|
43
|
+
* does not wire it to input. The animation is the sole writer of the drawing's state; letting real
|
|
44
|
+
* presses write it too would make the two fight for the same classes every frame.
|
|
45
|
+
*/
|
|
46
|
+
press?: PadInputSource;
|
|
47
|
+
brand?: PadBrandKey;
|
|
48
|
+
glyphSet?: GlyphSet;
|
|
49
|
+
/** Draw the controller. Default true; `false` gives a compact chips-only cue. */
|
|
50
|
+
showPad?: boolean;
|
|
51
|
+
/** Show the action's label above the animation. Default true. */
|
|
52
|
+
showLabel?: boolean;
|
|
53
|
+
size?: "sm" | "md" | "lg";
|
|
54
|
+
labels?: boolean;
|
|
55
|
+
colored?: boolean;
|
|
56
|
+
accent?: string;
|
|
57
|
+
/** Drawing convention for the joystick pictograms in the chips. See {@link StickPictogramStyle}. */
|
|
58
|
+
stickStyle?: StickPictogramStyle;
|
|
59
|
+
/** Playback rate. `1` = normal, `0.5` = half speed for a slow walkthrough. */
|
|
60
|
+
speed?: number;
|
|
61
|
+
/** Called each time the loop completes a full cycle. */
|
|
62
|
+
onCycle?: () => void;
|
|
63
|
+
}
|
|
64
|
+
export interface ComboDemo {
|
|
65
|
+
readonly root: HTMLDivElement;
|
|
66
|
+
readonly pad: ControllerPad | undefined;
|
|
67
|
+
setAction(action: ControlAction): void;
|
|
68
|
+
play(): void;
|
|
69
|
+
pause(): void;
|
|
70
|
+
setSpeed(mult: number): void;
|
|
71
|
+
dispose(): void;
|
|
72
|
+
}
|
|
73
|
+
export declare function mountComboDemo(host: HTMLElement, opts: ComboDemoOptions): ComboDemo;
|
|
74
|
+
//# sourceMappingURL=combo-demo.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"combo-demo.d.ts","sourceRoot":"","sources":["../../../src/ui/controller/combo-demo.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAEzD,OAAO,EAAsB,KAAK,aAAa,EAAE,KAAK,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAClG,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAG3D,OAAO,EAAgC,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAC/E,OAAO,KAAK,EAAE,WAAW,EAAW,MAAM,YAAY,CAAC;AAEvD,MAAM,WAAW,gBAAgB;IAC/B,wCAAwC;IACxC,MAAM,EAAE,aAAa,CAAC;IACtB;;;;OAIG;IACH,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,iFAAiF;IACjF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,iEAAiE;IACjE,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAC1B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oGAAoG;IACpG,UAAU,CAAC,EAAE,mBAAmB,CAAC;IACjC,8EAA8E;IAC9E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wDAAwD;IACxD,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAC9B,QAAQ,CAAC,GAAG,EAAE,aAAa,GAAG,SAAS,CAAC;IACxC,SAAS,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAAC;IACvC,IAAI,IAAI,IAAI,CAAC;IACb,KAAK,IAAI,IAAI,CAAC;IACd,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,OAAO,IAAI,IAAI,CAAC;CACjB;AA4CD,wBAAgB,cAAc,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,gBAAgB,GAAG,SAAS,CA4OnF"}
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* COMBO DEMO — the dynamic view: a looping animation of the combination a rider must perform.
|
|
3
|
+
*
|
|
4
|
+
* ```ts
|
|
5
|
+
* const demo = mountComboDemo(host, {
|
|
6
|
+
* press: session, // for the rider's lettering, NOT for input
|
|
7
|
+
* action: { label: "Dash", combo: ["LT", "LSTICK:left"] },
|
|
8
|
+
* });
|
|
9
|
+
* demo.setAction(next); // swaps cleanly mid-loop
|
|
10
|
+
* ```
|
|
11
|
+
*
|
|
12
|
+
* The timeline is **derived from the combo**, never authored per action, which is what keeps it generic:
|
|
13
|
+
*
|
|
14
|
+
* - *hold* (default) — idle, then each control engages in turn 200 ms apart (a stick eases to full
|
|
15
|
+
* deflection rather than snapping), everything holds together for a beat, releases, and repeats. The
|
|
16
|
+
* stagger is the point: it shows that the controls are held *simultaneously*, which a single
|
|
17
|
+
* all-at-once flash does not.
|
|
18
|
+
* - *sequence* (`action.sequence`) — each control presses, holds and releases in turn, with the strip's
|
|
19
|
+
* `→` separators filling in behind the current step.
|
|
20
|
+
* - a stick token with no direction sweeps once around its travel circle: "any direction".
|
|
21
|
+
*
|
|
22
|
+
* It drives exactly the same `PadDriver.setPart` / `setStick` and `ComboStrip.setPressed` that real input
|
|
23
|
+
* drives in the static view, so the demo and the live pad cannot drift apart — there is one renderer.
|
|
24
|
+
*
|
|
25
|
+
* **Self-driving, unlike `createPowerRace`.** This is an attract animation with no gameplay coupling, so
|
|
26
|
+
* it owns its own `requestAnimationFrame` rather than asking the game for a `tick(dt)`. It pauses while
|
|
27
|
+
* the tab is hidden, and `play()`/`pause()` are there for the caller.
|
|
28
|
+
*
|
|
29
|
+
* **`prefers-reduced-motion` is honoured by not animating at all**: the demo renders the fully-engaged end
|
|
30
|
+
* state statically. A looping motion graphic is precisely what that media query exists to suppress, and a
|
|
31
|
+
* still frame of "all of this, held together" still answers the rider's question.
|
|
32
|
+
*/
|
|
33
|
+
import { createComboStrip } from "./combo-strip.js";
|
|
34
|
+
import { mountControllerPad } from "./controller-pad.js";
|
|
35
|
+
import { litPartOfControl } from "./parts-map.js";
|
|
36
|
+
import { injectPadCss } from "./styles.js";
|
|
37
|
+
import { parseToken, STICK_DIR_VECTOR } from "./tokens.js";
|
|
38
|
+
// Timings in seconds. Tuned to read at a glance from a few feet away, not to be brisk.
|
|
39
|
+
const HOLD_IDLE = 0.4;
|
|
40
|
+
const HOLD_STAGGER = 0.2;
|
|
41
|
+
const HOLD_RAMP = 0.2;
|
|
42
|
+
const HOLD_SUSTAIN = 0.7;
|
|
43
|
+
const HOLD_RELEASE = 0.25;
|
|
44
|
+
const HOLD_TAIL = 0.5;
|
|
45
|
+
const SEQ_IDLE = 0.4;
|
|
46
|
+
const SEQ_PRESS = 0.35;
|
|
47
|
+
const SEQ_GAP = 0.15;
|
|
48
|
+
const SEQ_TAIL = 0.4;
|
|
49
|
+
/** One full revolution of an undirected stick sweep. */
|
|
50
|
+
const SWEEP_PERIOD = 1.2;
|
|
51
|
+
const smoothstep = (t) => {
|
|
52
|
+
const c = Math.max(0, Math.min(1, t));
|
|
53
|
+
return c * c * (3 - 2 * c);
|
|
54
|
+
};
|
|
55
|
+
function channelsOf(action) {
|
|
56
|
+
return action.combo.map((token, index) => {
|
|
57
|
+
const t = parseToken(token);
|
|
58
|
+
if (t.kind === "stick") {
|
|
59
|
+
return {
|
|
60
|
+
index,
|
|
61
|
+
stick: {
|
|
62
|
+
side: t.stick === "LSTICK" ? "l" : "r",
|
|
63
|
+
vec: t.dir ? STICK_DIR_VECTOR[t.dir] : null, // null = undirected → sweep
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
return { index, part: litPartOfControl(t.name) };
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
export function mountComboDemo(host, opts) {
|
|
71
|
+
injectPadCss();
|
|
72
|
+
const root = document.createElement("div");
|
|
73
|
+
root.className = "rydr-paddemo";
|
|
74
|
+
host.appendChild(root);
|
|
75
|
+
const showPad = opts.showPad ?? true;
|
|
76
|
+
const showLabel = opts.showLabel ?? true;
|
|
77
|
+
let speed = opts.speed ?? 1;
|
|
78
|
+
let labelEl;
|
|
79
|
+
let hintEl;
|
|
80
|
+
if (showLabel) {
|
|
81
|
+
labelEl = document.createElement("div");
|
|
82
|
+
labelEl.className = "rydr-paddemo-label";
|
|
83
|
+
root.appendChild(labelEl);
|
|
84
|
+
hintEl = document.createElement("div");
|
|
85
|
+
hintEl.className = "rydr-paddemo-hint";
|
|
86
|
+
root.appendChild(hintEl);
|
|
87
|
+
}
|
|
88
|
+
const padCell = document.createElement("div");
|
|
89
|
+
const stripCell = document.createElement("div");
|
|
90
|
+
if (showPad)
|
|
91
|
+
root.appendChild(padCell);
|
|
92
|
+
root.appendChild(stripCell);
|
|
93
|
+
// Glyph-only shim: gives the pad the rider's lettering and pad-swap notifications, while its inert
|
|
94
|
+
// `onButton` guarantees real presses never write the drawing the animation owns.
|
|
95
|
+
const glyphOnly = opts.press && {
|
|
96
|
+
onButton: () => () => { },
|
|
97
|
+
hardware: opts.press.hardware,
|
|
98
|
+
};
|
|
99
|
+
const pad = showPad
|
|
100
|
+
? mountControllerPad(padCell, {
|
|
101
|
+
press: glyphOnly,
|
|
102
|
+
brand: opts.brand,
|
|
103
|
+
glyphSet: opts.glyphSet,
|
|
104
|
+
size: opts.size ?? "md",
|
|
105
|
+
labels: opts.labels,
|
|
106
|
+
accent: opts.accent,
|
|
107
|
+
})
|
|
108
|
+
: undefined;
|
|
109
|
+
let action = opts.action;
|
|
110
|
+
let channels = channelsOf(action);
|
|
111
|
+
let strip;
|
|
112
|
+
function buildStrip() {
|
|
113
|
+
strip = createComboStrip(action, {
|
|
114
|
+
glyphSet: opts.glyphSet ?? pad?.glyphSet() ?? undefined,
|
|
115
|
+
colored: opts.colored,
|
|
116
|
+
stickStyle: opts.stickStyle,
|
|
117
|
+
});
|
|
118
|
+
stripCell.textContent = "";
|
|
119
|
+
stripCell.appendChild(strip.el);
|
|
120
|
+
}
|
|
121
|
+
function syncLabel() {
|
|
122
|
+
if (labelEl)
|
|
123
|
+
labelEl.textContent = action.label;
|
|
124
|
+
if (hintEl) {
|
|
125
|
+
hintEl.textContent = action.hint ?? "";
|
|
126
|
+
hintEl.style.display = action.hint ? "" : "none";
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
buildStrip();
|
|
130
|
+
syncLabel();
|
|
131
|
+
/** Total cycle length, in seconds at speed 1. */
|
|
132
|
+
function cycleLength() {
|
|
133
|
+
const n = Math.max(1, action.combo.length);
|
|
134
|
+
if (action.sequence)
|
|
135
|
+
return SEQ_IDLE + n * (SEQ_PRESS + SEQ_GAP) + SEQ_TAIL;
|
|
136
|
+
return HOLD_IDLE + (n - 1) * HOLD_STAGGER + HOLD_RAMP + HOLD_SUSTAIN + HOLD_RELEASE + HOLD_TAIL;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Write the state of the whole combination at cycle time `t` (seconds).
|
|
140
|
+
*
|
|
141
|
+
* One function for both modes and for the reduced-motion still, so there is exactly one place that
|
|
142
|
+
* decides what "engaged" looks like.
|
|
143
|
+
*/
|
|
144
|
+
function renderAt(t) {
|
|
145
|
+
const driver = pad?.driver();
|
|
146
|
+
if (action.sequence) {
|
|
147
|
+
let completed = 0;
|
|
148
|
+
channels.forEach((ch) => {
|
|
149
|
+
const start = SEQ_IDLE + ch.index * (SEQ_PRESS + SEQ_GAP);
|
|
150
|
+
const end = start + SEQ_PRESS;
|
|
151
|
+
if (t >= end)
|
|
152
|
+
completed++;
|
|
153
|
+
const on = t >= start && t < end;
|
|
154
|
+
const ramp = on ? smoothstep((t - start) / Math.min(0.12, SEQ_PRESS / 3)) : 0;
|
|
155
|
+
applyChannel(ch, on, ramp, t - start, driver);
|
|
156
|
+
});
|
|
157
|
+
strip.setStep(completed);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
const n = Math.max(1, action.combo.length);
|
|
161
|
+
const allDown = HOLD_IDLE + (n - 1) * HOLD_STAGGER + HOLD_RAMP;
|
|
162
|
+
const sustainEnd = allDown + HOLD_SUSTAIN;
|
|
163
|
+
const releaseEnd = sustainEnd + HOLD_RELEASE;
|
|
164
|
+
for (const ch of channels) {
|
|
165
|
+
const onset = HOLD_IDLE + ch.index * HOLD_STAGGER;
|
|
166
|
+
const on = t >= onset && t < sustainEnd;
|
|
167
|
+
let ramp = 0;
|
|
168
|
+
if (t >= onset && t < sustainEnd)
|
|
169
|
+
ramp = smoothstep((t - onset) / HOLD_RAMP);
|
|
170
|
+
else if (t >= sustainEnd && t < releaseEnd)
|
|
171
|
+
ramp = 1 - smoothstep((t - sustainEnd) / HOLD_RELEASE);
|
|
172
|
+
applyChannel(ch, on, ramp, t - onset, driver);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
function applyChannel(ch, on, ramp, since, driver) {
|
|
176
|
+
if (ch.stick) {
|
|
177
|
+
let x;
|
|
178
|
+
let y;
|
|
179
|
+
if (ch.stick.vec) {
|
|
180
|
+
x = ch.stick.vec[0] * ramp;
|
|
181
|
+
y = ch.stick.vec[1] * ramp;
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
// Undirected: sweep the cap around its circle so it reads as "any direction".
|
|
185
|
+
const angle = (Math.max(0, since) / SWEEP_PERIOD) * Math.PI * 2;
|
|
186
|
+
x = Math.cos(angle) * ramp;
|
|
187
|
+
y = Math.sin(angle) * ramp;
|
|
188
|
+
}
|
|
189
|
+
driver?.setStick(ch.stick.side, x, y);
|
|
190
|
+
strip.setDeflectionAt(ch.index, x, y);
|
|
191
|
+
// A stick is "pressed" in the strip once it's meaningfully deflected — matches the pad's own glow.
|
|
192
|
+
strip.setPressedAt(ch.index, ramp > 0.35);
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
strip.setPressedAt(ch.index, on);
|
|
196
|
+
if (ch.part && driver) {
|
|
197
|
+
driver.setPart(ch.part, on);
|
|
198
|
+
if (ch.part === "lt")
|
|
199
|
+
driver.setMeter("l", on ? 1 : 0);
|
|
200
|
+
if (ch.part === "rt")
|
|
201
|
+
driver.setMeter("r", on ? 1 : 0);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
/** The still frame for reduced motion: everything engaged, sticks at full deflection. */
|
|
205
|
+
function renderStill() {
|
|
206
|
+
const driver = pad?.driver();
|
|
207
|
+
for (const ch of channels)
|
|
208
|
+
applyChannel(ch, true, 1, 0, driver);
|
|
209
|
+
strip.setStep(action.combo.length);
|
|
210
|
+
}
|
|
211
|
+
// ── the loop ────────────────────────────────────────────────────────────────────────────────────
|
|
212
|
+
const reduceMotion = typeof matchMedia === "function" && matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
213
|
+
let raf = 0;
|
|
214
|
+
let elapsed = 0;
|
|
215
|
+
let lastTs = 0;
|
|
216
|
+
let wantPlaying = true;
|
|
217
|
+
function frame(ts) {
|
|
218
|
+
raf = requestAnimationFrame(frame);
|
|
219
|
+
const dt = lastTs ? Math.min(0.05, (ts - lastTs) / 1000) : 0;
|
|
220
|
+
lastTs = ts;
|
|
221
|
+
elapsed += dt * speed;
|
|
222
|
+
const len = cycleLength();
|
|
223
|
+
if (elapsed >= len) {
|
|
224
|
+
elapsed -= len * Math.floor(elapsed / len);
|
|
225
|
+
opts.onCycle?.();
|
|
226
|
+
}
|
|
227
|
+
renderAt(elapsed);
|
|
228
|
+
}
|
|
229
|
+
function start() {
|
|
230
|
+
if (raf || reduceMotion)
|
|
231
|
+
return;
|
|
232
|
+
lastTs = 0;
|
|
233
|
+
raf = requestAnimationFrame(frame);
|
|
234
|
+
}
|
|
235
|
+
function stop() {
|
|
236
|
+
if (raf)
|
|
237
|
+
cancelAnimationFrame(raf);
|
|
238
|
+
raf = 0;
|
|
239
|
+
}
|
|
240
|
+
const onVisibility = () => {
|
|
241
|
+
if (document.visibilityState === "hidden")
|
|
242
|
+
stop();
|
|
243
|
+
else if (wantPlaying)
|
|
244
|
+
start();
|
|
245
|
+
};
|
|
246
|
+
document.addEventListener("visibilitychange", onVisibility);
|
|
247
|
+
if (reduceMotion)
|
|
248
|
+
renderStill();
|
|
249
|
+
else
|
|
250
|
+
start();
|
|
251
|
+
// A pad swap rebuilds the drawing (new nodes, new driver) and re-letters, so the chips must follow.
|
|
252
|
+
const offRebuild = pad?.onRebuild(() => {
|
|
253
|
+
buildStrip();
|
|
254
|
+
if (reduceMotion)
|
|
255
|
+
renderStill();
|
|
256
|
+
});
|
|
257
|
+
function reset(next) {
|
|
258
|
+
action = next;
|
|
259
|
+
channels = channelsOf(action);
|
|
260
|
+
// Release the previous combination before the new one draws, or a part the old action lit and the
|
|
261
|
+
// new one doesn't would stay lit forever.
|
|
262
|
+
pad?.driver().clearAll();
|
|
263
|
+
buildStrip();
|
|
264
|
+
syncLabel();
|
|
265
|
+
elapsed = 0;
|
|
266
|
+
lastTs = 0;
|
|
267
|
+
if (reduceMotion)
|
|
268
|
+
renderStill();
|
|
269
|
+
}
|
|
270
|
+
return {
|
|
271
|
+
root,
|
|
272
|
+
pad,
|
|
273
|
+
setAction: reset,
|
|
274
|
+
play() {
|
|
275
|
+
wantPlaying = true;
|
|
276
|
+
start();
|
|
277
|
+
},
|
|
278
|
+
pause() {
|
|
279
|
+
wantPlaying = false;
|
|
280
|
+
stop();
|
|
281
|
+
},
|
|
282
|
+
setSpeed(mult) {
|
|
283
|
+
speed = Math.max(0.05, mult);
|
|
284
|
+
},
|
|
285
|
+
dispose() {
|
|
286
|
+
stop();
|
|
287
|
+
document.removeEventListener("visibilitychange", onVisibility);
|
|
288
|
+
offRebuild?.();
|
|
289
|
+
strip.dispose();
|
|
290
|
+
pad?.dispose();
|
|
291
|
+
root.remove();
|
|
292
|
+
},
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
//# sourceMappingURL=combo-demo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"combo-demo.js","sourceRoot":"","sources":["../../../src/ui/controller/combo-demo.ts"],"names":[],"mappings":"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"}
|