@rydr/game-sdk 8.22.0 → 9.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/dist/client/PlatformClient.d.ts +54 -0
  2. package/dist/client/PlatformClient.d.ts.map +1 -1
  3. package/dist/client/PlatformClient.js +108 -13
  4. package/dist/client/PlatformClient.js.map +1 -1
  5. package/dist/host/PlatformHost.d.ts +21 -6
  6. package/dist/host/PlatformHost.d.ts.map +1 -1
  7. package/dist/host/PlatformHost.js +9 -2
  8. package/dist/host/PlatformHost.js.map +1 -1
  9. package/dist/protocol/boards.d.ts +1 -13
  10. package/dist/protocol/boards.d.ts.map +1 -1
  11. package/dist/protocol/boards.js.map +1 -1
  12. package/dist/protocol/buttons.d.ts +1 -1
  13. package/dist/protocol/buttons.js +1 -1
  14. package/dist/protocol/guards.d.ts.map +1 -1
  15. package/dist/protocol/guards.js +1 -0
  16. package/dist/protocol/guards.js.map +1 -1
  17. package/dist/protocol/identity.d.ts +1 -1
  18. package/dist/protocol/index.d.ts +1 -0
  19. package/dist/protocol/index.d.ts.map +1 -1
  20. package/dist/protocol/index.js +1 -0
  21. package/dist/protocol/index.js.map +1 -1
  22. package/dist/protocol/messages.d.ts +26 -18
  23. package/dist/protocol/messages.d.ts.map +1 -1
  24. package/dist/protocol/stages.d.ts +102 -0
  25. package/dist/protocol/stages.d.ts.map +1 -0
  26. package/dist/protocol/stages.js +19 -0
  27. package/dist/protocol/stages.js.map +1 -0
  28. package/dist/protocol/version.d.ts +2 -2
  29. package/dist/protocol/version.d.ts.map +1 -1
  30. package/dist/protocol/version.js +46 -2
  31. package/dist/protocol/version.js.map +1 -1
  32. package/dist/three/character/kit.d.ts +1 -1
  33. package/dist/three/character/kit.js +1 -1
  34. package/dist/three/character/riders.d.ts +1 -1
  35. package/dist/three/character/riders.js +1 -1
  36. package/dist/three/character/skeleton.d.ts +1 -1
  37. package/dist/three/character/skeleton.js +1 -1
  38. package/dist/training/compile.d.ts +1 -1
  39. package/dist/training/compile.js +1 -1
  40. package/dist/training/zones.d.ts +2 -2
  41. package/dist/training/zones.js +2 -2
  42. package/dist/ui/README.md +2 -3
  43. package/dist/ui/option-menu.d.ts +1 -1
  44. package/dist/ui/option-menu.js +1 -1
  45. package/dist/ui/rider-rig.d.ts +1 -1
  46. package/dist/ui/rider-rig.js +2 -2
  47. package/package.json +1 -5
  48. package/dist/difficulty/index.d.ts +0 -141
  49. package/dist/difficulty/index.d.ts.map +0 -1
  50. package/dist/difficulty/index.js +0 -300
  51. package/dist/difficulty/index.js.map +0 -1
@@ -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
- export const RYDR_PROTOCOL_VERSION = 34;
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 = "8.22.0";
304
+ export const RYDR_SDK_VERSION = "9.0.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 `@rydr/game-sdk/difficulty`, where a hand-ported copy of the
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 `@rydr/game-sdk/difficulty`, where a hand-ported copy of the
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 `@rydr/game-sdk/difficulty`, where a hand-ported copy of the
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 `@rydr/game-sdk/difficulty`, where a hand-ported copy of the
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 `@rydr/game-sdk/difficulty`, where a hand-ported copy of the
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 `@rydr/game-sdk/difficulty`, where a hand-ported copy of the
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 moves their difficulty dial
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
@@ -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 moves their difficulty dial
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
@@ -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
- * difficulty level — is a different thing entirely and comes from
8
- * `@rydr/game-sdk/difficulty`; never mix the two.)
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
@@ -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
- * difficulty level — is a different thing entirely and comes from
8
- * `@rydr/game-sdk/difficulty`; never mix the two.)
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 difficulty of the run they're
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**: they are deliberately not `@rydr/game-sdk/difficulty`'s ramp, which colours the rider's
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.
@@ -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 difficulty of the very run they are deciding
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.
@@ -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 difficulty of the very run they are deciding
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.
@@ -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 `@rydr/game-sdk/difficulty`'s ramp, which
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
  *
@@ -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 `@rydr/game-sdk/difficulty`'s ramp, which
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
- * `@rydr/game-sdk/difficulty`'s ramp.
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": "8.22.0",
3
+ "version": "9.0.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"}