@rydr/game-sdk 8.22.0 → 9.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 +100 -0
- package/dist/client/PlatformClient.d.ts +60 -0
- package/dist/client/PlatformClient.d.ts.map +1 -1
- package/dist/client/PlatformClient.js +108 -13
- package/dist/client/PlatformClient.js.map +1 -1
- package/dist/host/PlatformHost.d.ts +21 -6
- package/dist/host/PlatformHost.d.ts.map +1 -1
- package/dist/host/PlatformHost.js +9 -2
- package/dist/host/PlatformHost.js.map +1 -1
- package/dist/protocol/boards.d.ts +1 -13
- package/dist/protocol/boards.d.ts.map +1 -1
- package/dist/protocol/boards.js.map +1 -1
- package/dist/protocol/buttons.d.ts +1 -1
- package/dist/protocol/buttons.js +1 -1
- package/dist/protocol/guards.d.ts.map +1 -1
- package/dist/protocol/guards.js +1 -0
- package/dist/protocol/guards.js.map +1 -1
- package/dist/protocol/identity.d.ts +1 -1
- package/dist/protocol/index.d.ts +1 -0
- package/dist/protocol/index.d.ts.map +1 -1
- package/dist/protocol/index.js +1 -0
- package/dist/protocol/index.js.map +1 -1
- package/dist/protocol/messages.d.ts +26 -18
- package/dist/protocol/messages.d.ts.map +1 -1
- package/dist/protocol/stages.d.ts +154 -0
- package/dist/protocol/stages.d.ts.map +1 -0
- package/dist/protocol/stages.js +19 -0
- package/dist/protocol/stages.js.map +1 -0
- package/dist/protocol/version.d.ts +2 -2
- package/dist/protocol/version.d.ts.map +1 -1
- package/dist/protocol/version.js +46 -2
- package/dist/protocol/version.js.map +1 -1
- package/dist/three/character/kit.d.ts +1 -1
- package/dist/three/character/kit.js +1 -1
- package/dist/three/character/riders.d.ts +1 -1
- package/dist/three/character/riders.js +1 -1
- package/dist/three/character/skeleton.d.ts +1 -1
- package/dist/three/character/skeleton.js +1 -1
- package/dist/training/compile.d.ts +1 -1
- package/dist/training/compile.js +1 -1
- package/dist/training/zones.d.ts +2 -2
- package/dist/training/zones.js +2 -2
- package/dist/ui/README.md +2 -3
- package/dist/ui/option-menu.d.ts +1 -1
- package/dist/ui/option-menu.js +1 -1
- package/dist/ui/rider-rig.d.ts +1 -1
- package/dist/ui/rider-rig.js +2 -2
- package/package.json +1 -5
- package/dist/difficulty/index.d.ts +0 -141
- package/dist/difficulty/index.d.ts.map +0 -1
- package/dist/difficulty/index.js +0 -300
- package/dist/difficulty/index.js.map +0 -1
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SEQUENCE STAGES — the shapes for an authored run of several games back to back.
|
|
3
|
+
*
|
|
4
|
+
* The platform owns the sequence; a game owns only the thing it was asked to play. A game never
|
|
5
|
+
* learns what comes before or after it, how many stages there are, or that a sequence exists beyond
|
|
6
|
+
* the one stage it holds — so a mash up can be re-authored, reordered or cut short with no game
|
|
7
|
+
* change anywhere.
|
|
8
|
+
*
|
|
9
|
+
* The whole contract is two messages: the shell says PLAY THIS (`rydr/stage.play`) and the guest
|
|
10
|
+
* reports back (`rydr/stage.report`). Everything else the platform needs it already has — the deep
|
|
11
|
+
* link that gets the game to the right screen (`startPath`/`initialPath`), the attempt identity and
|
|
12
|
+
* effort window (`rydr/run.start`), and the score (`rydr/run.save`).
|
|
13
|
+
*
|
|
14
|
+
* Deliberately NOT here: progress. A stage's share of a sequence is counted in whole stages, so a
|
|
15
|
+
* game reporting "lap 2 of 3" would buy a progress bar nobody asked for at the cost of a channel
|
|
16
|
+
* every game has to implement. Add it when a screen actually needs it.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* What the shell asks a game to play for one stage of a sequence.
|
|
20
|
+
*
|
|
21
|
+
* The game is ALSO loaded at the offering's own deep link, exactly as an ordinary launch is, so
|
|
22
|
+
* `offeringId`/`settings` are how the shell says it precisely rather than the only way the game
|
|
23
|
+
* finds out. That redundancy is the point: a URL gets the rider to the right screen even on a guest
|
|
24
|
+
* that predates this contract, and the message carries the settings a URL cannot express (Guitar
|
|
25
|
+
* Hero's pacing targets have no path segment, and never will).
|
|
26
|
+
*/
|
|
27
|
+
export interface StageSpec {
|
|
28
|
+
/**
|
|
29
|
+
* Unique per ATTEMPT, minted by the shell — not per stage and not per sequence. A Retry mints a
|
|
30
|
+
* fresh one.
|
|
31
|
+
*
|
|
32
|
+
* It exists so a late report cannot advance the sequence twice. The rider skipping a stage, the
|
|
33
|
+
* game finishing it, and the shell tearing the guest down all race each other by nature, and a
|
|
34
|
+
* `stage.report` that arrives after a Skip refers to a stage the rider has already left. The shell
|
|
35
|
+
* drops any report whose `attemptId` is not the live one, which is cheaper and more honest than
|
|
36
|
+
* trying to stop the guest from sending it.
|
|
37
|
+
*/
|
|
38
|
+
attemptId: string;
|
|
39
|
+
/**
|
|
40
|
+
* WHICH launchable mode/preset of this game to play, e.g. `"short-race"` or `"one-song"`.
|
|
41
|
+
*
|
|
42
|
+
* One of the ids the game DECLARED in {@link OfferingDeclaration} (`rydr.offerings` in its
|
|
43
|
+
* package.json, carried onto its registry row). The platform never parses it — it only checks the
|
|
44
|
+
* id against that declaration before launching, exactly as an undeclared `boardId` is refused.
|
|
45
|
+
*
|
|
46
|
+
* A game that does not recognise it must still report `"unavailable"` rather than falling back to
|
|
47
|
+
* some default: the declaration says what the game offered at REGISTRATION, and the build actually
|
|
48
|
+
* deployed may be older or newer than that, so the id is a promise the guest still has to keep.
|
|
49
|
+
*/
|
|
50
|
+
offeringId: string;
|
|
51
|
+
/** Offering-specific settings, validated by the GAME (it owns its content and its rules). Opaque
|
|
52
|
+
* to the platform, which only round-trips whatever the sequence author wrote. */
|
|
53
|
+
settings?: Record<string, unknown>;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* How a stage attempt ended.
|
|
57
|
+
*
|
|
58
|
+
* `"completed"` and `"failed"` are both ENDINGS — the rider played the thing and it resolved, so
|
|
59
|
+
* either advances the sequence (the shell may offer a Retry first, its own policy). `"unavailable"`
|
|
60
|
+
* is a LAUNCH failure: nothing was played, and a sequence that treated it as an ending would march
|
|
61
|
+
* the rider past a stage they never saw.
|
|
62
|
+
*/
|
|
63
|
+
export type StageOutcome =
|
|
64
|
+
/** Played to its natural end: crossed the line, finished the song, survived the wave. */
|
|
65
|
+
"completed"
|
|
66
|
+
/** Played and lost: out of lives, timed out, eliminated. A real attempt, just not a win. */
|
|
67
|
+
| "failed"
|
|
68
|
+
/** Could NOT be played: unknown `offeringId`, settings this build rejects, missing or unpurchased
|
|
69
|
+
* content, an access check the game failed. Nothing was played. */
|
|
70
|
+
| "unavailable";
|
|
71
|
+
/**
|
|
72
|
+
* What a guest reports about the stage it was handed.
|
|
73
|
+
*
|
|
74
|
+
* Two jobs, one message. `"accepted"` is the ACK — sent as soon as the guest has understood the
|
|
75
|
+
* spec and is starting it, which is the only thing that tells the shell its guest speaks this
|
|
76
|
+
* contract at all. Exactly one TERMINAL report (a {@link StageOutcome}) follows, whenever the thing
|
|
77
|
+
* actually ends, which may be minutes later.
|
|
78
|
+
*
|
|
79
|
+
* The ack is separate from the ending because they answer different questions and a single message
|
|
80
|
+
* could not do both: "is this guest going to play this?" must be answered in seconds, while "did
|
|
81
|
+
* the rider finish?" cannot be rushed. Without the ack the shell's only read on a guest that stays
|
|
82
|
+
* silent is a timeout long enough to also cover a real race, i.e. useless.
|
|
83
|
+
*/
|
|
84
|
+
export interface StageReport {
|
|
85
|
+
/** Echoed from {@link StageSpec.attemptId}. A report carrying anything else is dropped. */
|
|
86
|
+
attemptId: string;
|
|
87
|
+
/** `"accepted"` once, up front; then exactly one {@link StageOutcome}. */
|
|
88
|
+
phase: "accepted" | StageOutcome;
|
|
89
|
+
/**
|
|
90
|
+
* Why, in words the RIDER can read — the shell shows it verbatim on the stage card. Worth sending
|
|
91
|
+
* on `"unavailable"` (it is all the rider gets to explain a stage that refused to start) and on
|
|
92
|
+
* `"failed"` where the reason is interesting ("Out of lives on wave 7"). Never parsed.
|
|
93
|
+
*/
|
|
94
|
+
reason?: string;
|
|
95
|
+
/**
|
|
96
|
+
* The `runId`s this attempt produced, if any — from {@link StageSpec} play that called
|
|
97
|
+
* `startRun`/`saveRun`.
|
|
98
|
+
*
|
|
99
|
+
* The shell uses them to show what the rider just scored without inventing a cross-game score of
|
|
100
|
+
* its own: unlike scores stay unlike, owned by their games, and the sequence keeps references.
|
|
101
|
+
* Empty/omitted is normal and means only that this stage scored nothing (a skipped song, an
|
|
102
|
+
* unscored tutorial), never that it failed.
|
|
103
|
+
*/
|
|
104
|
+
runIds?: string[];
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* A game's declaration of ONE launchable mode, so a sequence can be authored against it.
|
|
108
|
+
*
|
|
109
|
+
* This is the other half of {@link StageSpec}. `onStage` says how a game RESPONDS to a stage;
|
|
110
|
+
* without a declaration nothing said what stages a game could be asked for, so the `offeringId` was
|
|
111
|
+
* a bare string two repos had to agree on out of band — and the only feedback on a mismatch was
|
|
112
|
+
* `"unavailable"` at runtime, after the rider had already mounted the game.
|
|
113
|
+
*
|
|
114
|
+
* Declared in the game's `package.json` under `rydr.offerings` and carried onto its `GameManifest`
|
|
115
|
+
* at registration — the same path `rydr.boards` takes, for the same reason: the platform has to know
|
|
116
|
+
* before it launches anything, and a game's own code is behind an iframe it has not opened yet.
|
|
117
|
+
*
|
|
118
|
+
* ```jsonc
|
|
119
|
+
* "rydr": {
|
|
120
|
+
* "offerings": [
|
|
121
|
+
* { "id": "one-song", "label": "One song", "ends": "natural" },
|
|
122
|
+
* { "id": "endless", "label": "Endless survival", "ends": "open" }
|
|
123
|
+
* ]
|
|
124
|
+
* }
|
|
125
|
+
* ```
|
|
126
|
+
*
|
|
127
|
+
* Declaring is a PROMISE, not an implementation: the registry records what the game said when it was
|
|
128
|
+
* registered, and the deployed build is what actually answers. So the platform uses declarations to
|
|
129
|
+
* author and pre-check a sequence, never to skip the guest's own verdict.
|
|
130
|
+
*/
|
|
131
|
+
export interface OfferingDeclaration {
|
|
132
|
+
/** Stable id — the {@link StageSpec.offeringId} a stage will name. Renaming it breaks every
|
|
133
|
+
* authored sequence that referenced it, exactly as renaming a `boardId` orphans a leaderboard. */
|
|
134
|
+
id: string;
|
|
135
|
+
/** Rider-facing name, shown on the sequence's progress card (defaults to {@link id}). */
|
|
136
|
+
label?: string;
|
|
137
|
+
/**
|
|
138
|
+
* Whether the thing STOPS BY ITSELF. The one fact a sequence cannot work without.
|
|
139
|
+
*
|
|
140
|
+
* `"natural"` means gameplay reaches its own end and the guest reports `"completed"`/`"failed"`
|
|
141
|
+
* without being asked: a finish line, the end of a song, the last wave. `"open"` means it runs
|
|
142
|
+
* until something outside it intervenes (endless survival, a sandbox), so no terminal report is
|
|
143
|
+
* ever coming on its own and the rider's Skip is the only way on.
|
|
144
|
+
*
|
|
145
|
+
* A sequence made only of `"open"` stages would strand a rider forever on stage one, so the
|
|
146
|
+
* platform needs this to refuse or annotate such a mash up while it is being authored, rather than
|
|
147
|
+
* discovering it mid-ride.
|
|
148
|
+
*/
|
|
149
|
+
ends: "natural" | "open";
|
|
150
|
+
/** One line for whoever authors a sequence — what this mode actually is, and roughly how long it
|
|
151
|
+
* lasts ("3 laps, about 4 minutes"). Never shown to the rider. */
|
|
152
|
+
description?: string;
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=stages.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stages.d.ts","sourceRoot":"","sources":["../../src/protocol/stages.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH;;;;;;;;GAQG;AACH,MAAM,WAAW,SAAS;IACxB;;;;;;;;;OASG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB;;;;;;;;;;OAUG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;sFACkF;IAClF,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,YAAY;AACtB,yFAAyF;AACvF,WAAW;AACb,4FAA4F;GAC1F,QAAQ;AACV;oEACoE;GAClE,aAAa,CAAC;AAElB;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,WAAW;IAC1B,2FAA2F;IAC3F,SAAS,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,KAAK,EAAE,UAAU,GAAG,YAAY,CAAC;IACjC;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;;;OAQG;IACH,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,WAAW,mBAAmB;IAClC;uGACmG;IACnG,EAAE,EAAE,MAAM,CAAC;IACX,yFAAyF;IACzF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;;;;;;;OAWG;IACH,IAAI,EAAE,SAAS,GAAG,MAAM,CAAC;IACzB;uEACmE;IACnE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SEQUENCE STAGES — the shapes for an authored run of several games back to back.
|
|
3
|
+
*
|
|
4
|
+
* The platform owns the sequence; a game owns only the thing it was asked to play. A game never
|
|
5
|
+
* learns what comes before or after it, how many stages there are, or that a sequence exists beyond
|
|
6
|
+
* the one stage it holds — so a mash up can be re-authored, reordered or cut short with no game
|
|
7
|
+
* change anywhere.
|
|
8
|
+
*
|
|
9
|
+
* The whole contract is two messages: the shell says PLAY THIS (`rydr/stage.play`) and the guest
|
|
10
|
+
* reports back (`rydr/stage.report`). Everything else the platform needs it already has — the deep
|
|
11
|
+
* link that gets the game to the right screen (`startPath`/`initialPath`), the attempt identity and
|
|
12
|
+
* effort window (`rydr/run.start`), and the score (`rydr/run.save`).
|
|
13
|
+
*
|
|
14
|
+
* Deliberately NOT here: progress. A stage's share of a sequence is counted in whole stages, so a
|
|
15
|
+
* game reporting "lap 2 of 3" would buy a progress bar nobody asked for at the cost of a channel
|
|
16
|
+
* every game has to implement. Add it when a screen actually needs it.
|
|
17
|
+
*/
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=stages.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stages.js","sourceRoot":"","sources":["../../src/protocol/stages.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG"}
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
* built against an older protocol keeps working. Evolve the protocol
|
|
7
7
|
* ADDITIVELY — never change or remove an existing message shape.
|
|
8
8
|
*/
|
|
9
|
-
export declare const RYDR_PROTOCOL_VERSION:
|
|
9
|
+
export declare const RYDR_PROTOCOL_VERSION: 36;
|
|
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 = "
|
|
12
|
+
export declare const RYDR_SDK_VERSION = "9.1.0";
|
|
13
13
|
//# sourceMappingURL=version.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../src/protocol/version.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../src/protocol/version.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAqSH,eAAO,MAAM,qBAAqB,EAAG,EAAW,CAAC;AAEjD;wFACwF;AACxF,eAAO,MAAM,gBAAgB,UAAU,CAAC"}
|
package/dist/protocol/version.js
CHANGED
|
@@ -254,8 +254,52 @@
|
|
|
254
254
|
// Additive both ways: an older GAME sees a string it does not recognise and does whatever it does
|
|
255
255
|
// for unknown reasons, and an older SHELL never sends it. Unknown close reasons still report as
|
|
256
256
|
// `"dropped"`, which is the honest default for a close nobody labelled.
|
|
257
|
-
|
|
257
|
+
// Bumped 34 → 35: the FTP DIFFICULTY is gone, everywhere (BREAKING).
|
|
258
|
+
//
|
|
259
|
+
// The shell used to carry a rider-chosen difficulty — a level 1→50 stored as watts, nudgeable
|
|
260
|
+
// mid-ride with − / + — and this protocol carried three pieces of it. All three are removed:
|
|
261
|
+
//
|
|
262
|
+
// 1. `rydr/rider.adjustFtp` (game→platform) and the host's `onAdjustFtp`. It relayed the − / +
|
|
263
|
+
// keys a focused game iframe swallowed before the shell could see them. There is no dial left
|
|
264
|
+
// to step, so there is nothing to relay. The SDK's own keyboard handler no longer posts it.
|
|
265
|
+
// 2. `BoardEntry.ftpDifficulty` and `BoardEntry.difficultyChanged` — what a run was played at, and
|
|
266
|
+
// whether the dial moved during it. The platform no longer records either, so on every new
|
|
267
|
+
// entry they were about to be permanently `undefined`.
|
|
268
|
+
// 3. `AdminSeedEntry.ftpDifficulty` — the same value on an admin-authored seed row.
|
|
269
|
+
//
|
|
270
|
+
// The `@rydr/game-sdk/difficulty` subpath (the 1→50 ladder: `wattsForLevel`, `levelForWatts`,
|
|
271
|
+
// `stepWatts`, `snapWatts`, `visualForLevel`, `FTP_MIN`/`FTP_MAX`/`LEVEL_MIN`/`LEVEL_MAX`) is
|
|
272
|
+
// deleted with them. There is no replacement: watts are no longer a level.
|
|
273
|
+
//
|
|
274
|
+
// `ScopedIdentity.ftp` is UNCHANGED and still sent. What changed is only what it means — it is now
|
|
275
|
+
// the rider's actual FTP, typed into their profile, rather than a difficulty they dialled. A game
|
|
276
|
+
// scaling `%FTP` off it needs no code change.
|
|
277
|
+
// Bumped 35 → 36: adds SEQUENCE STAGES — `rydr/stage.play` (platform→game) and `rydr/stage.report`
|
|
278
|
+
// (game→platform), with the shapes in `./stages.ts` (`StageSpec`, `StageOutcome`, `StageReport`),
|
|
279
|
+
// client `session.onStage`/`session.finishStage`/`session.stage`, and host `sendStage`/`onStageReport`.
|
|
280
|
+
//
|
|
281
|
+
// It makes an authored MASH UP possible: the platform runs several games back to back, handing each
|
|
282
|
+
// one a mode and its settings and being told when that thing ended. Two messages is the whole
|
|
283
|
+
// contract, because everything else already existed — the deep link gets the game to the right
|
|
284
|
+
// screen, `run.start` opens the attempt and its effort window, `run.save` carries the score. What
|
|
285
|
+
// was missing was only "this attempt is over, and how it went", which cannot be inferred: a game
|
|
286
|
+
// saves a lap, visits a menu or finishes an unscored tutorial without any of it meaning "advance".
|
|
287
|
+
//
|
|
288
|
+
// A game opts in by registering an `onStage` handler, which is also how it DECLARES it speaks
|
|
289
|
+
// sequences — the SDK acks the shell on the game's behalf and auto-reports `"unavailable"` for a
|
|
290
|
+
// game with no handler, so an ordinary game needs no sequence code and can never strand a mash up
|
|
291
|
+
// on a stage it was never going to play. The guest→host message carries both the up-front ack and
|
|
292
|
+
// the terminal outcome (`phase`) because the two answer questions on totally different clocks:
|
|
293
|
+
// "will you play this?" in seconds, "did the rider finish?" possibly in minutes.
|
|
294
|
+
//
|
|
295
|
+
// Additive both ways. An older SHELL never sends `stage.play`, so `session.stage` stays `null` and
|
|
296
|
+
// an `onStage` handler simply never fires — the game plays as it always did. An older GAME never
|
|
297
|
+
// answers `stage.play`, which is exactly why a host MUST arm its own accept timeout: there is no
|
|
298
|
+
// "I am an old build" reply, and absence of an ack is the only signal. Nothing existing changed
|
|
299
|
+
// shape, and the `attemptId` round-trip exists so a report arriving after the rider skipped a stage
|
|
300
|
+
// is dropped rather than advancing the sequence twice.
|
|
301
|
+
export const RYDR_PROTOCOL_VERSION = 36;
|
|
258
302
|
/** Semver of this SDK build. Sent in the handshake for telemetry/debugging.
|
|
259
303
|
* (Bumped to 2.0.0 by `npm version major` on release — see CHANGELOG [Unreleased].) */
|
|
260
|
-
export const RYDR_SDK_VERSION = "
|
|
304
|
+
export const RYDR_SDK_VERSION = "9.1.0";
|
|
261
305
|
//# sourceMappingURL=version.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/protocol/version.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/protocol/version.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* The platform built a procedural humanoid rider — skeleton, proportions, and five art directions —
|
|
5
5
|
* with no assets and no build step. The rider rig needs exactly that, so it is published here rather
|
|
6
|
-
* than re-invented: the same argument as
|
|
6
|
+
* than re-invented: the same argument as every other shared contract here, where a hand-ported copy of the
|
|
7
7
|
* shell's ladder drifted until one rider's badge disagreed with the chrome.
|
|
8
8
|
*
|
|
9
9
|
* What came across: the SKELETON and the LOOK. What stayed behind: the walk cycle, the weapon mounts,
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* The platform built a procedural humanoid rider — skeleton, proportions, and five art directions —
|
|
5
5
|
* with no assets and no build step. The rider rig needs exactly that, so it is published here rather
|
|
6
|
-
* than re-invented: the same argument as
|
|
6
|
+
* than re-invented: the same argument as every other shared contract here, where a hand-ported copy of the
|
|
7
7
|
* shell's ladder drifted until one rider's badge disagreed with the chrome.
|
|
8
8
|
*
|
|
9
9
|
* What came across: the SKELETON and the LOOK. What stayed behind: the walk cycle, the weapon mounts,
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* The platform built a procedural humanoid rider — skeleton, proportions, and five art directions —
|
|
5
5
|
* with no assets and no build step. The rider rig needs exactly that, so it is published here rather
|
|
6
|
-
* than re-invented: the same argument as
|
|
6
|
+
* than re-invented: the same argument as every other shared contract here, where a hand-ported copy of the
|
|
7
7
|
* shell's ladder drifted until one rider's badge disagreed with the chrome.
|
|
8
8
|
*
|
|
9
9
|
* What came across: the SKELETON and the LOOK. What stayed behind: the walk cycle, the weapon mounts,
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* The platform built a procedural humanoid rider — skeleton, proportions, and five art directions —
|
|
5
5
|
* with no assets and no build step. The rider rig needs exactly that, so it is published here rather
|
|
6
|
-
* than re-invented: the same argument as
|
|
6
|
+
* than re-invented: the same argument as every other shared contract here, where a hand-ported copy of the
|
|
7
7
|
* shell's ladder drifted until one rider's badge disagreed with the chrome.
|
|
8
8
|
*
|
|
9
9
|
* What came across: the SKELETON and the LOOK. What stayed behind: the walk cycle, the weapon mounts,
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* The platform built a procedural humanoid rider — skeleton, proportions, and five art directions —
|
|
5
5
|
* with no assets and no build step. The rider rig needs exactly that, so it is published here rather
|
|
6
|
-
* than re-invented: the same argument as
|
|
6
|
+
* than re-invented: the same argument as every other shared contract here, where a hand-ported copy of the
|
|
7
7
|
* shell's ladder drifted until one rider's badge disagreed with the chrome.
|
|
8
8
|
*
|
|
9
9
|
* What came across: the SKELETON and the LOOK. What stayed behind: the walk cycle, the weapon mounts,
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* The platform built a procedural humanoid rider — skeleton, proportions, and five art directions —
|
|
5
5
|
* with no assets and no build step. The rider rig needs exactly that, so it is published here rather
|
|
6
|
-
* than re-invented: the same argument as
|
|
6
|
+
* than re-invented: the same argument as every other shared contract here, where a hand-ported copy of the
|
|
7
7
|
* shell's ladder drifted until one rider's badge disagreed with the chrome.
|
|
8
8
|
*
|
|
9
9
|
* What came across: the SKELETON and the LOOK. What stayed behind: the walk cycle, the weapon mounts,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Compiling a workout: authored segments → a flat, time-addressable timeline.
|
|
3
3
|
*
|
|
4
4
|
* This is where percentages of FTP finally become watts, and it happens **once**,
|
|
5
|
-
* at the start of a ride (and again if the rider
|
|
5
|
+
* at the start of a ride (and again if the rider edits their FTP
|
|
6
6
|
* mid-session). Everything downstream — the engine's clock, the chart, the ERG
|
|
7
7
|
* target — then addresses the timeline by *time* rather than re-walking the
|
|
8
8
|
* segment tree, which is what keeps a 3x13x30/15 workout (78 efforts, 157
|
package/dist/training/compile.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Compiling a workout: authored segments → a flat, time-addressable timeline.
|
|
3
3
|
*
|
|
4
4
|
* This is where percentages of FTP finally become watts, and it happens **once**,
|
|
5
|
-
* at the start of a ride (and again if the rider
|
|
5
|
+
* at the start of a ride (and again if the rider edits their FTP
|
|
6
6
|
* mid-session). Everything downstream — the engine's clock, the chart, the ERG
|
|
7
7
|
* target — then addresses the timeline by *time* rather than re-walking the
|
|
8
8
|
* segment tree, which is what keeps a 3x13x30/15 workout (78 efforts, 157
|
package/dist/training/zones.d.ts
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
*
|
|
5
5
|
* These are a *coaching* convention, not a platform scale, which is why they live
|
|
6
6
|
* here and not in `@rydr/game-sdk`. (The platform's own ladder — the 1→50 rider
|
|
7
|
-
*
|
|
8
|
-
*
|
|
7
|
+
* rider's own FTP — is a different thing entirely and arrives on the scoped
|
|
8
|
+
* identity as `ftp`; never mix the two.)
|
|
9
9
|
*
|
|
10
10
|
* Nothing outside this file should hardcode a zone colour: a chart, a badge and a
|
|
11
11
|
* live readout showing the same effort in three different colours is exactly the
|
package/dist/training/zones.js
CHANGED
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
*
|
|
5
5
|
* These are a *coaching* convention, not a platform scale, which is why they live
|
|
6
6
|
* here and not in `@rydr/game-sdk`. (The platform's own ladder — the 1→50 rider
|
|
7
|
-
*
|
|
8
|
-
*
|
|
7
|
+
* rider's own FTP — is a different thing entirely and arrives on the scoped
|
|
8
|
+
* identity as `ftp`; never mix the two.)
|
|
9
9
|
*
|
|
10
10
|
* Nothing outside this file should hardcode a zone colour: a chart, a badge and a
|
|
11
11
|
* live readout showing the same effort in three different colours is exactly the
|
package/dist/ui/README.md
CHANGED
|
@@ -133,7 +133,7 @@ handlers go quiet, `isDown`/`stick` read resting, and anything held is released
|
|
|
133
133
|
**It also does NOT touch the trainer.** The activity state is left exactly as your game set it, so a
|
|
134
134
|
rider who opens this mid-run keeps the resistance they were riding. This menu is an overlay over LIVE
|
|
135
135
|
gameplay, not a screen they navigated to — they're still on the bike with their legs turning, and
|
|
136
|
-
easing under them (then snapping back on Resume) would change the
|
|
136
|
+
easing under them (then snapping back on Resume) would change the intensity of the run they're
|
|
137
137
|
deciding whether to restart. If your game does want easing while it's up, call
|
|
138
138
|
`session.setActivity("menu")` in `onOpen` and `"playing"` in `onClose` — each game decides.
|
|
139
139
|
|
|
@@ -495,8 +495,7 @@ The scale runs `0 → 1.5 × ftp`, with the rider's threshold marked at two thir
|
|
|
495
495
|
above it for a sprint. Pass `ftp` (from `session.identity.ftp`) and never hard-code a raw-watt scale —
|
|
496
496
|
the same rule as `createPowerRace`. The effort colour is a **continuous ramp** over %FTP — grey-blue →
|
|
497
497
|
blue → violet → pink → red, interpolated rather than banded, so it never jumps mid-surge — and is **local to this
|
|
498
|
-
component
|
|
499
|
-
chosen *calibration level* and is a different quantity that happens to be measured in watts too.
|
|
498
|
+
component**, not a shared ramp.
|
|
500
499
|
|
|
501
500
|
Feed it **raw `power`**. It keeps both numbers: the readout shows the true instantaneous value while
|
|
502
501
|
the bar follows an internal EMA so it climbs smoothly between the trainer's sparse (~1–4 Hz) updates.
|
package/dist/ui/option-menu.d.ts
CHANGED
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
* game left it — a rider who opens it mid-run keeps the resistance they were riding. That is
|
|
46
46
|
* deliberate: this menu is a transient overlay over LIVE gameplay, not a screen the rider navigated
|
|
47
47
|
* to, and they are still on the bike with their legs turning. Dropping to the eased menu resistance
|
|
48
|
-
* and snapping back on `Resume` would change the
|
|
48
|
+
* and snapping back on `Resume` would change the intensity of the very run they are deciding
|
|
49
49
|
* whether to restart. (Contrast the PLATFORM overlay, which is the shell's own and does ease.)
|
|
50
50
|
* A game that genuinely wants easing here can still do it itself in `onOpen`/`onClose` —
|
|
51
51
|
* `session.setActivity("menu")` / `("playing")` — which is more flexible than an option anyway.
|
package/dist/ui/option-menu.js
CHANGED
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
* game left it — a rider who opens it mid-run keeps the resistance they were riding. That is
|
|
46
46
|
* deliberate: this menu is a transient overlay over LIVE gameplay, not a screen the rider navigated
|
|
47
47
|
* to, and they are still on the bike with their legs turning. Dropping to the eased menu resistance
|
|
48
|
-
* and snapping back on `Resume` would change the
|
|
48
|
+
* and snapping back on `Resume` would change the intensity of the very run they are deciding
|
|
49
49
|
* whether to restart. (Contrast the PLATFORM overlay, which is the shell's own and does ease.)
|
|
50
50
|
* A game that genuinely wants easing here can still do it itself in `onOpen`/`onClose` —
|
|
51
51
|
* `session.setActivity("menu")` / `("playing")` — which is more flexible than an option anyway.
|
package/dist/ui/rider-rig.d.ts
CHANGED
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
* 350 W rider therefore see the same gauge do the same thing for the same effort — never hard-code a
|
|
63
63
|
* raw-watt scale (the same rule as {@link createPowerRace}). The effort colour is a continuous ramp
|
|
64
64
|
* over %FTP — grey-blue, blue, violet, pink, red, with no band boundaries to jump at — and is
|
|
65
|
-
* are **local to this component**: they are deliberately NOT
|
|
65
|
+
* are **local to this component**: they are deliberately NOT a shared ramp, which
|
|
66
66
|
* colours the rider's *chosen calibration level* and would be a different quantity wearing the same
|
|
67
67
|
* paint.
|
|
68
68
|
*
|
package/dist/ui/rider-rig.js
CHANGED
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
* 350 W rider therefore see the same gauge do the same thing for the same effort — never hard-code a
|
|
63
63
|
* raw-watt scale (the same rule as {@link createPowerRace}). The effort colour is a continuous ramp
|
|
64
64
|
* over %FTP — grey-blue, blue, violet, pink, red, with no band boundaries to jump at — and is
|
|
65
|
-
* are **local to this component**: they are deliberately NOT
|
|
65
|
+
* are **local to this component**: they are deliberately NOT a shared ramp, which
|
|
66
66
|
* colours the rider's *chosen calibration level* and would be a different quantity wearing the same
|
|
67
67
|
* paint.
|
|
68
68
|
*
|
|
@@ -293,7 +293,7 @@ const FLY_GEAR = 2.1;
|
|
|
293
293
|
const STREAK_FULL_RPM = 95;
|
|
294
294
|
/**
|
|
295
295
|
* %FTP effort colours — LOCAL to this component. See the module header on why this is not
|
|
296
|
-
*
|
|
296
|
+
* this component's own ramp.
|
|
297
297
|
*
|
|
298
298
|
* A CONTINUOUS ramp, not a table of zones. It was six discrete bands (recovery, endurance, tempo,
|
|
299
299
|
* threshold, VO2, anaerobic) and every boundary was a jump: the bar changed colour in one frame while
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rydr/game-sdk",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "9.1.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/bdefrenne/rydr-game-sdk.git"
|
|
@@ -44,10 +44,6 @@
|
|
|
44
44
|
"types": "./dist/overlay/index.d.ts",
|
|
45
45
|
"import": "./dist/overlay/index.js"
|
|
46
46
|
},
|
|
47
|
-
"./difficulty": {
|
|
48
|
-
"types": "./dist/difficulty/index.d.ts",
|
|
49
|
-
"import": "./dist/difficulty/index.js"
|
|
50
|
-
},
|
|
51
47
|
"./sounds": {
|
|
52
48
|
"types": "./dist/sounds/index.d.ts",
|
|
53
49
|
"import": "./dist/sounds/index.js"
|
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The **FTP-difficulty ladder** — levels 1 → 50, and the watts each one means.
|
|
3
|
-
*
|
|
4
|
-
* This is the rider's chosen calibration: the number every game's `%FTP` demands are a percentage
|
|
5
|
-
* of. It is **not** a measurement of anyone's fitness, and it is not the rank of a score.
|
|
6
|
-
*
|
|
7
|
-
* ## Why this lives in the SDK
|
|
8
|
-
*
|
|
9
|
-
* A leaderboard row carries watts — `BoardEntry.ftpDifficulty` in `src/protocol/boards.ts` — and
|
|
10
|
-
* nothing else. Any game that draws a rider's badge next to their score therefore has to turn those
|
|
11
|
-
* watts into a level and a colour, and a game cannot import the shell's copy across the iframe
|
|
12
|
-
* boundary. Before this module existed the only way through that was to hand-port the ladder into
|
|
13
|
-
* each game, which is exactly what happened: guitar hero shipped a private copy that kept rendering
|
|
14
|
-
* a retired 36-rung metal ladder long after the shell had moved on, so one rider's `ftpDifficulty`
|
|
15
|
-
* produced a bronze "3" in-game and a ramp-coloured "26" in the chrome. **The interpretation of a
|
|
16
|
-
* protocol field belongs to the protocol.** The shell imports this module too — there is one ladder,
|
|
17
|
-
* published once, and both sides read it.
|
|
18
|
-
*
|
|
19
|
-
* Pure by design: no `lit`, no `three`, no DOM. {@link visualForLevel} returns CSS strings, which any
|
|
20
|
-
* renderer can use — a Lit component's `style`, an `innerHTML` template, a canvas fill.
|
|
21
|
-
*
|
|
22
|
-
* ## The scale
|
|
23
|
-
*
|
|
24
|
-
* **Watts are what get stored; the level is derived here.** Every persisted copy of the dial (the
|
|
25
|
-
* shell's `profile.ftpDifficulty`, a leaderboard entry's `ftp_difficulty`) holds watts, and every
|
|
26
|
-
* client computes the level from it through {@link levelForWatts}. That's what lets this scale be
|
|
27
|
-
* redrawn — floor, band widths, tier count — without migrating or reinterpreting a single stored row.
|
|
28
|
-
* The cost, accepted: redrawing it re-labels history, so a shift in the levels reported by analytics
|
|
29
|
-
* can mean the ladder moved rather than the riders.
|
|
30
|
-
*
|
|
31
|
-
* ```
|
|
32
|
-
* watts = level ≤ 9 ? 50 + 5 × (level − 1) // 50, 55, 60 … 90
|
|
33
|
-
* : level × 10 // 100, 110 … 500
|
|
34
|
-
* ```
|
|
35
|
-
*
|
|
36
|
-
* `level × 10 = watts` holds exactly from 100 W up, where essentially every rider sits — that
|
|
37
|
-
* relationship is the point of the number, since it makes "22" readable as "~220 W" with no lookup.
|
|
38
|
-
* Below 100 W the steps are finer because a flat 10 W step there is a **20%** jump where at 400 W
|
|
39
|
-
* it's 2.5%. The floor of 50 W is the researched floor for a deconditioned adult; the ceiling of
|
|
40
|
-
* 500 W is beyond any realistic rider on purpose, so nobody is ever pinned at either end.
|
|
41
|
-
*
|
|
42
|
-
* **There is deliberately no watts-per-press constant** (see {@link stepWatts}): the watts a − / +
|
|
43
|
-
* press moves are whatever the neighbouring rung is — 5 W inside levels 1 → 9, 10 W from level 10
|
|
44
|
-
* up, and 10 W across the 9 → 10 boundary. Any single constant is wrong in one of those bands by
|
|
45
|
-
* construction, which is the bug that convention replaced.
|
|
46
|
-
*
|
|
47
|
-
* The rationale for the whole design, including the colour ramp below, is written up in the platform
|
|
48
|
-
* repo: `rydr-platform/docs/run-level-and-leaderboards.md`.
|
|
49
|
-
*/
|
|
50
|
-
/** Weakest level. The ladder is **1-based** — there is no level 0. */
|
|
51
|
-
export declare const LEVEL_MIN = 1;
|
|
52
|
-
/** Strongest level. */
|
|
53
|
-
export declare const LEVEL_MAX = 50;
|
|
54
|
-
/** Watts of the fine band's first rung, i.e. of {@link LEVEL_MIN}. */
|
|
55
|
-
export declare const FTP_MIN = 50;
|
|
56
|
-
/** Watts at {@link LEVEL_MAX}. A real ceiling, not a bucket: nobody is meant to reach it. */
|
|
57
|
-
export declare const FTP_MAX = 500;
|
|
58
|
-
/** Levels per tier badge. Ten tiers × five levels covers 1 → 50 exactly. */
|
|
59
|
-
export declare const LEVELS_PER_TIER = 5;
|
|
60
|
-
/** Number of tier badges. */
|
|
61
|
-
export declare const TIER_COUNT: number;
|
|
62
|
-
/** One rung of the ladder. */
|
|
63
|
-
export interface FtpLevel {
|
|
64
|
-
/** The level itself, 1 (weakest) → 50 (strongest). This is the number riders see. */
|
|
65
|
-
level: number;
|
|
66
|
-
/** What the level means in watts — the value that actually gets stored. */
|
|
67
|
-
watts: number;
|
|
68
|
-
/**
|
|
69
|
-
* Band index, 0 → 9 — five levels each. Purely structural: it exists so a ladder picker can
|
|
70
|
-
* group 50 rungs into scannable rows, and it carries **no meaning of its own**. The metal and gem
|
|
71
|
-
* names it used to have (Iron → Diamond) were dropped with the tier colours, because a named tier
|
|
72
|
-
* reads as a club to belong to and the level is a dial the rider sets, not a rank they earned.
|
|
73
|
-
* Label a band with {@link rangeLabelForTier}, never with a name.
|
|
74
|
-
*/
|
|
75
|
-
tier: number;
|
|
76
|
-
}
|
|
77
|
-
/** The pill's visual styling for a level. */
|
|
78
|
-
export interface LevelVisual {
|
|
79
|
-
/** CSS `background` for the pill — a translucent two-stop gradient of the level's colour. */
|
|
80
|
-
fill: string;
|
|
81
|
-
/** Keyline colour. Held at a higher alpha than the fill so the hue stays crisp. */
|
|
82
|
-
accent: string;
|
|
83
|
-
/** Shadow/glow colour under the pill. */
|
|
84
|
-
glow: string;
|
|
85
|
-
/** Colour for the numeral — the level's own hue, brightened until it's legible on the fill. */
|
|
86
|
-
ink: string;
|
|
87
|
-
}
|
|
88
|
-
/** Clamp any number to a whole level inside the ladder. */
|
|
89
|
-
export declare function clampLevel(level: number): number;
|
|
90
|
-
/** The watts a level means. Clamps, so it's safe to call with arithmetic results. */
|
|
91
|
-
export declare function wattsForLevel(level: number): number;
|
|
92
|
-
/**
|
|
93
|
-
* The level a watts value sits at — the **nearest** rung, so any number (a legacy profile, the
|
|
94
|
-
* weight-relative result of an onboarding questionnaire, one day a measured estimate) has a level.
|
|
95
|
-
* Ties round up, which matters only for values landing exactly between two rungs.
|
|
96
|
-
*
|
|
97
|
-
* Each band's formula is inverted, then whichever candidate rung is genuinely closer wins. Trusting
|
|
98
|
-
* one formula by a `watts < 100` branch is wrong **at the seam**, because the gap from level 9 (90 W)
|
|
99
|
-
* to level 10 (100 W) is 10 W while the low-band formula divides by 5: it read 98 W as level 11 and
|
|
100
|
-
* snapped it up to 110 W — a 12% jump — and 93 W as level 10. Only 93, 94, 98 and 99 W were affected,
|
|
101
|
-
* which is exactly why it took a brute-force sweep against {@link FTP_LEVELS} to notice.
|
|
102
|
-
*/
|
|
103
|
-
export declare function levelForWatts(watts: number): number;
|
|
104
|
-
/** Snap arbitrary watts onto the ladder — `wattsForLevel(levelForWatts(w))`. Idempotent. */
|
|
105
|
-
export declare function snapWatts(watts: number): number;
|
|
106
|
-
/**
|
|
107
|
-
* Move one level from wherever `watts` is, and return the new **watts**.
|
|
108
|
-
*
|
|
109
|
-
* This is the only correct way to step the dial: it derives the level, moves it by one, and reads
|
|
110
|
-
* that level's watts back. Off-ladder input snaps to its nearest rung on the first press, then
|
|
111
|
-
* steps from there. At either end of the ladder it returns the end.
|
|
112
|
-
*/
|
|
113
|
-
export declare function stepWatts(watts: number, direction: 1 | -1): number;
|
|
114
|
-
/** The tier badge index (0 → 9) a level belongs to. */
|
|
115
|
-
export declare function tierForLevel(level: number): number;
|
|
116
|
-
/**
|
|
117
|
-
* A level's ramp colour as one flat hex.
|
|
118
|
-
*
|
|
119
|
-
* {@link visualForLevel} returns a translucent CSS gradient, which is right for a pill and useless
|
|
120
|
-
* to anything that needs a single value — a gradient stop, a chart series, a canvas fill. Callers
|
|
121
|
-
* wanting to draw the ramp itself (e.g. a results-screen level track) sample this per level.
|
|
122
|
-
*/
|
|
123
|
-
export declare function colourForLevel(level: number): string;
|
|
124
|
-
/** The pill styling for a level — its position on the ramp. */
|
|
125
|
-
export declare function visualForLevel(level: number): LevelVisual;
|
|
126
|
-
/** Every rung, weakest → strongest (level 1 → 50). */
|
|
127
|
-
export declare const FTP_LEVELS: readonly FtpLevel[];
|
|
128
|
-
/** The rung a watts value sits on — the whole {@link FtpLevel}, for UI that needs its parts. */
|
|
129
|
-
export declare function levelAt(watts: number): FtpLevel;
|
|
130
|
-
/** Watts label for a level — "255 W". */
|
|
131
|
-
export declare function wattsLabel(level: number): string;
|
|
132
|
-
/**
|
|
133
|
-
* Level-range label for a band — "26-30". This is what a band gets called now that the metal names
|
|
134
|
-
* are gone: a band is a group of five rungs on a dial, so its honest label is which rungs it spans.
|
|
135
|
-
*/
|
|
136
|
-
export declare function levelRangeLabelForTier(tier: number): string;
|
|
137
|
-
/** Watts-range label for a whole tier badge — "270-310 W". */
|
|
138
|
-
export declare function rangeLabelForTier(tier: number): string;
|
|
139
|
-
/** The levels belonging to a tier badge, weakest → strongest. */
|
|
140
|
-
export declare function levelsInTier(tier: number): readonly FtpLevel[];
|
|
141
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/difficulty/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AAEH,sEAAsE;AACtE,eAAO,MAAM,SAAS,IAAI,CAAC;AAC3B,uBAAuB;AACvB,eAAO,MAAM,SAAS,KAAK,CAAC;AAG5B,sEAAsE;AACtE,eAAO,MAAM,OAAO,KAAK,CAAC;AAG1B,6FAA6F;AAC7F,eAAO,MAAM,OAAO,MAAM,CAAC;AAE3B,4EAA4E;AAC5E,eAAO,MAAM,eAAe,IAAI,CAAC;AACjC,6BAA6B;AAC7B,eAAO,MAAM,UAAU,QAA8B,CAAC;AAEtD,8BAA8B;AAC9B,MAAM,WAAW,QAAQ;IACvB,qFAAqF;IACrF,KAAK,EAAE,MAAM,CAAC;IACd,2EAA2E;IAC3E,KAAK,EAAE,MAAM,CAAC;IACd;;;;;;OAMG;IACH,IAAI,EAAE,MAAM,CAAC;CACd;AAED,6CAA6C;AAC7C,MAAM,WAAW,WAAW;IAC1B,6FAA6F;IAC7F,IAAI,EAAE,MAAM,CAAC;IACb,mFAAmF;IACnF,MAAM,EAAE,MAAM,CAAC;IACf,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,+FAA+F;IAC/F,GAAG,EAAE,MAAM,CAAC;CACb;AAID,2DAA2D;AAC3D,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED,qFAAqF;AACrF,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGnD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAQnD;AAED,4FAA4F;AAC5F,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,CAElE;AAsLD,uDAAuD;AACvD,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAElD;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGpD;AAED,+DAA+D;AAC/D,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,CASzD;AAID,sDAAsD;AACtD,eAAO,MAAM,UAAU,EAAE,SAAS,QAAQ,EAGxC,CAAC;AAEH,gGAAgG;AAChG,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,CAE/C;AAED,yCAAyC;AACzC,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEhD;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG3D;AAED,8DAA8D;AAC9D,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGtD;AAED,iEAAiE;AACjE,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,QAAQ,EAAE,CAE9D"}
|