@rydr/game-sdk 3.1.2 → 3.2.1

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 (82) hide show
  1. package/README.md +15 -2
  2. package/dist/characters/README.md +83 -0
  3. package/dist/characters/assets.d.ts +74 -0
  4. package/dist/characters/assets.d.ts.map +1 -0
  5. package/dist/characters/assets.js +234 -0
  6. package/dist/characters/assets.js.map +1 -0
  7. package/dist/characters/character-actor.d.ts +47 -0
  8. package/dist/characters/character-actor.d.ts.map +1 -0
  9. package/dist/characters/character-actor.js +119 -0
  10. package/dist/characters/character-actor.js.map +1 -0
  11. package/dist/characters/clips.d.ts +15 -0
  12. package/dist/characters/clips.d.ts.map +1 -0
  13. package/dist/characters/clips.js +24 -0
  14. package/dist/characters/clips.js.map +1 -0
  15. package/dist/characters/index.d.ts +30 -0
  16. package/dist/characters/index.d.ts.map +1 -0
  17. package/dist/characters/index.js +28 -0
  18. package/dist/characters/index.js.map +1 -0
  19. package/dist/characters/loader.d.ts +35 -0
  20. package/dist/characters/loader.d.ts.map +1 -0
  21. package/dist/characters/loader.js +84 -0
  22. package/dist/characters/loader.js.map +1 -0
  23. package/dist/characters/session-catalog.d.ts +10 -0
  24. package/dist/characters/session-catalog.d.ts.map +1 -0
  25. package/dist/characters/session-catalog.js +15 -0
  26. package/dist/characters/session-catalog.js.map +1 -0
  27. package/dist/client/PlatformClient.d.ts +9 -0
  28. package/dist/client/PlatformClient.d.ts.map +1 -1
  29. package/dist/client/PlatformClient.js +24 -0
  30. package/dist/client/PlatformClient.js.map +1 -1
  31. package/dist/host/PlatformHost.d.ts +18 -0
  32. package/dist/host/PlatformHost.d.ts.map +1 -1
  33. package/dist/host/PlatformHost.js +33 -0
  34. package/dist/host/PlatformHost.js.map +1 -1
  35. package/dist/protocol/characters.d.ts +82 -0
  36. package/dist/protocol/characters.d.ts.map +1 -0
  37. package/dist/protocol/characters.js +18 -0
  38. package/dist/protocol/characters.js.map +1 -0
  39. package/dist/protocol/guards.d.ts.map +1 -1
  40. package/dist/protocol/guards.js +3 -0
  41. package/dist/protocol/guards.js.map +1 -1
  42. package/dist/protocol/index.d.ts +1 -0
  43. package/dist/protocol/index.d.ts.map +1 -1
  44. package/dist/protocol/index.js +1 -0
  45. package/dist/protocol/index.js.map +1 -1
  46. package/dist/protocol/messages.d.ts +44 -2
  47. package/dist/protocol/messages.d.ts.map +1 -1
  48. package/dist/protocol/version.d.ts +2 -2
  49. package/dist/protocol/version.d.ts.map +1 -1
  50. package/dist/protocol/version.js +5 -2
  51. package/dist/protocol/version.js.map +1 -1
  52. package/dist/three/README.md +141 -0
  53. package/dist/three/index.d.ts +2 -0
  54. package/dist/three/index.d.ts.map +1 -1
  55. package/dist/three/index.js +2 -0
  56. package/dist/three/index.js.map +1 -1
  57. package/dist/three/screen-anchor.d.ts +62 -0
  58. package/dist/three/screen-anchor.d.ts.map +1 -0
  59. package/dist/three/screen-anchor.js +71 -0
  60. package/dist/three/screen-anchor.js.map +1 -0
  61. package/dist/three/waypoint-beacon.d.ts +56 -0
  62. package/dist/three/waypoint-beacon.d.ts.map +1 -0
  63. package/dist/three/waypoint-beacon.js +118 -0
  64. package/dist/three/waypoint-beacon.js.map +1 -0
  65. package/dist/ui/README.md +104 -0
  66. package/dist/ui/action-card.d.ts.map +1 -1
  67. package/dist/ui/action-card.js +16 -0
  68. package/dist/ui/action-card.js.map +1 -1
  69. package/dist/ui/index.d.ts +3 -2
  70. package/dist/ui/index.d.ts.map +1 -1
  71. package/dist/ui/index.js +3 -2
  72. package/dist/ui/index.js.map +1 -1
  73. package/dist/ui/rarity-card.d.ts +74 -0
  74. package/dist/ui/rarity-card.d.ts.map +1 -0
  75. package/dist/ui/rarity-card.js +105 -0
  76. package/dist/ui/rarity-card.js.map +1 -0
  77. package/dist/ui/showcase/index.d.ts.map +1 -1
  78. package/dist/ui/showcase/index.js +52 -1
  79. package/dist/ui/showcase/index.js.map +1 -1
  80. package/dist/ui/styles.js +31 -2
  81. package/dist/ui/styles.js.map +1 -1
  82. package/package.json +8 -3
@@ -0,0 +1,62 @@
1
+ /**
2
+ * SCREEN ANCHOR — place a floating UI element (a name tag, a button prompt, a health bar) a CONSTANT
3
+ * height above the TOP of a 3D object, then project that point to screen pixels. The standard
4
+ * "something hovering over a thing" placement, so games stop hand-rolling bbox + project math (and
5
+ * stop guessing pixel offsets that break when the model's size changes).
6
+ *
7
+ * On construction it measures the object's bounding box ONCE and remembers how far the top sits above
8
+ * the object's own origin (`topOffset`). Each `project()` re-reads the object's CURRENT world position
9
+ * — so the tag follows it as it moves or turns — and lifts by `topOffset + worldGap`. Keeping the gap
10
+ * in world units makes it perspective-correct (it shrinks with distance, like the object). `pixelGap`
11
+ * is an extra constant screen-space nudge UP on top of that — handy to clear a keycap that dangles
12
+ * below a card, or any fixed-size chrome the world gap can't account for.
13
+ *
14
+ * Defaults put a tag a little above the head by default; override `worldGap`/`pixelGap` per use and
15
+ * adapt from there. Call `remeasure()` if the object is rescaled or its model swapped.
16
+ */
17
+ import * as THREE from "three";
18
+ export interface ScreenPoint {
19
+ /** Horizontal position in CSS pixels within the host element. */
20
+ x: number;
21
+ /** Vertical position in CSS pixels within the host element. */
22
+ y: number;
23
+ /** False when the anchor is behind the camera (or off the near/far range) — hide the UI element. */
24
+ onScreen: boolean;
25
+ }
26
+ export interface ScreenAnchorOptions {
27
+ /** World-space lift above the object's bbox top (perspective-correct). Default 0.15 — just clear of
28
+ * the head. Raise it for a roomier tag; this default keeps the tag close, not floating. */
29
+ worldGap?: number;
30
+ /** Extra constant screen-space lift UP, in CSS pixels (e.g. to clear a dangling keycap). Default 0. */
31
+ pixelGap?: number;
32
+ /**
33
+ * Skip auto-measuring and use this fixed top height (world units above the object's origin). Pass it
34
+ * when you already KNOW the height — e.g. a model whose mesh loads asynchronously, so measuring at
35
+ * construction would read an empty bounding box. Without it the anchor measures the object instead.
36
+ */
37
+ topOffset?: number;
38
+ }
39
+ export declare class ScreenAnchor {
40
+ /** Height of the object's bbox top above its own origin, in world units (set by `remeasure`). */
41
+ topOffset: number;
42
+ worldGap: number;
43
+ pixelGap: number;
44
+ private target;
45
+ private _w;
46
+ private _p;
47
+ private pendingMeasure;
48
+ constructor(target: THREE.Object3D, opts?: ScreenAnchorOptions);
49
+ /** Re-measure the object's top. Call after the object is rescaled or its model is swapped. */
50
+ remeasure(): void;
51
+ /** The world-space point the UI should hover at: `worldGap` above the object's measured top. */
52
+ worldPoint(out?: THREE.Vector3): THREE.Vector3;
53
+ /**
54
+ * Project the anchor to CSS pixels within `host`. `onScreen` is false when the point is behind the
55
+ * camera — hide the element then. Pass `out` to reuse an object and avoid a per-frame allocation.
56
+ */
57
+ project(camera: THREE.Camera, host: {
58
+ clientWidth: number;
59
+ clientHeight: number;
60
+ }, out?: ScreenPoint): ScreenPoint;
61
+ }
62
+ //# sourceMappingURL=screen-anchor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screen-anchor.d.ts","sourceRoot":"","sources":["../../src/three/screen-anchor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,MAAM,WAAW,WAAW;IAC1B,iEAAiE;IACjE,CAAC,EAAE,MAAM,CAAC;IACV,+DAA+D;IAC/D,CAAC,EAAE,MAAM,CAAC;IACV,oGAAoG;IACpG,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC;gGAC4F;IAC5F,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uGAAuG;IACvG,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,YAAY;IACvB,iGAAiG;IACjG,SAAS,SAAK;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IAEjB,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,EAAE,CAAuB;IACjC,OAAO,CAAC,EAAE,CAAuB;IAGjC,OAAO,CAAC,cAAc,CAAS;gBAEnB,MAAM,EAAE,KAAK,CAAC,QAAQ,EAAE,IAAI,GAAE,mBAAwB;IAQlE,8FAA8F;IAC9F,SAAS,IAAI,IAAI;IAQjB,gGAAgG;IAChG,UAAU,CAAC,GAAG,GAAE,KAAK,CAAC,OAA6B,GAAG,KAAK,CAAC,OAAO;IAMnE;;;OAGG;IACH,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,IAAI,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,EAAE,GAAG,CAAC,EAAE,WAAW,GAAG,WAAW;CASnH"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * SCREEN ANCHOR — place a floating UI element (a name tag, a button prompt, a health bar) a CONSTANT
3
+ * height above the TOP of a 3D object, then project that point to screen pixels. The standard
4
+ * "something hovering over a thing" placement, so games stop hand-rolling bbox + project math (and
5
+ * stop guessing pixel offsets that break when the model's size changes).
6
+ *
7
+ * On construction it measures the object's bounding box ONCE and remembers how far the top sits above
8
+ * the object's own origin (`topOffset`). Each `project()` re-reads the object's CURRENT world position
9
+ * — so the tag follows it as it moves or turns — and lifts by `topOffset + worldGap`. Keeping the gap
10
+ * in world units makes it perspective-correct (it shrinks with distance, like the object). `pixelGap`
11
+ * is an extra constant screen-space nudge UP on top of that — handy to clear a keycap that dangles
12
+ * below a card, or any fixed-size chrome the world gap can't account for.
13
+ *
14
+ * Defaults put a tag a little above the head by default; override `worldGap`/`pixelGap` per use and
15
+ * adapt from there. Call `remeasure()` if the object is rescaled or its model swapped.
16
+ */
17
+ import * as THREE from "three";
18
+ export class ScreenAnchor {
19
+ /** Height of the object's bbox top above its own origin, in world units (set by `remeasure`). */
20
+ topOffset = 0;
21
+ worldGap;
22
+ pixelGap;
23
+ target;
24
+ _w = new THREE.Vector3();
25
+ _p = new THREE.Vector3();
26
+ // While auto-measuring, the target's mesh may not be loaded yet (async GLB) → an empty box. Keep
27
+ // re-measuring on each project() until it yields a real top, so the tag snaps into place on load.
28
+ pendingMeasure = false;
29
+ constructor(target, opts = {}) {
30
+ this.target = target;
31
+ this.worldGap = opts.worldGap ?? 0.15;
32
+ this.pixelGap = opts.pixelGap ?? 0;
33
+ if (opts.topOffset != null)
34
+ this.topOffset = opts.topOffset; // explicit known height — never measure
35
+ else
36
+ this.remeasure();
37
+ }
38
+ /** Re-measure the object's top. Call after the object is rescaled or its model is swapped. */
39
+ remeasure() {
40
+ const box = new THREE.Box3().setFromObject(this.target);
41
+ if (box.isEmpty()) {
42
+ this.topOffset = 0;
43
+ this.pendingMeasure = true;
44
+ return;
45
+ } // mesh not there yet
46
+ // Top height above the object's own origin (yaw-invariant, so it survives the object turning).
47
+ this.topOffset = box.max.y - this.target.getWorldPosition(this._w).y;
48
+ this.pendingMeasure = false;
49
+ }
50
+ /** The world-space point the UI should hover at: `worldGap` above the object's measured top. */
51
+ worldPoint(out = new THREE.Vector3()) {
52
+ this.target.getWorldPosition(out);
53
+ out.y += this.topOffset + this.worldGap;
54
+ return out;
55
+ }
56
+ /**
57
+ * Project the anchor to CSS pixels within `host`. `onScreen` is false when the point is behind the
58
+ * camera — hide the element then. Pass `out` to reuse an object and avoid a per-frame allocation.
59
+ */
60
+ project(camera, host, out) {
61
+ if (this.pendingMeasure)
62
+ this.remeasure(); // async model may have just loaded — try again
63
+ const r = out ?? { x: 0, y: 0, onScreen: false };
64
+ const p = this.worldPoint(this._p).project(camera);
65
+ r.onScreen = p.z <= 1;
66
+ r.x = (p.x * 0.5 + 0.5) * host.clientWidth;
67
+ r.y = (-p.y * 0.5 + 0.5) * host.clientHeight - this.pixelGap; // +pixelGap lifts UP
68
+ return r;
69
+ }
70
+ }
71
+ //# sourceMappingURL=screen-anchor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"screen-anchor.js","sourceRoot":"","sources":["../../src/three/screen-anchor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAyB/B,MAAM,OAAO,YAAY;IACvB,iGAAiG;IACjG,SAAS,GAAG,CAAC,CAAC;IACd,QAAQ,CAAS;IACjB,QAAQ,CAAS;IAET,MAAM,CAAiB;IACvB,EAAE,GAAG,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;IACzB,EAAE,GAAG,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC;IACjC,iGAAiG;IACjG,kGAAkG;IAC1F,cAAc,GAAG,KAAK,CAAC;IAE/B,YAAY,MAAsB,EAAE,OAA4B,EAAE;QAChE,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC;QACtC,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAC;QACnC,IAAI,IAAI,CAAC,SAAS,IAAI,IAAI;YAAE,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,wCAAwC;;YAChG,IAAI,CAAC,SAAS,EAAE,CAAC;IACxB,CAAC;IAED,8FAA8F;IAC9F,SAAS;QACP,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACxD,IAAI,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC;YAAC,IAAI,CAAC,SAAS,GAAG,CAAC,CAAC;YAAC,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC;YAAC,OAAO;QAAC,CAAC,CAAC,qBAAqB;QACpG,+FAA+F;QAC/F,IAAI,CAAC,SAAS,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACrE,IAAI,CAAC,cAAc,GAAG,KAAK,CAAC;IAC9B,CAAC;IAED,gGAAgG;IAChG,UAAU,CAAC,MAAqB,IAAI,KAAK,CAAC,OAAO,EAAE;QACjD,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC;QAClC,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC;QACxC,OAAO,GAAG,CAAC;IACb,CAAC;IAED;;;OAGG;IACH,OAAO,CAAC,MAAoB,EAAE,IAAmD,EAAE,GAAiB;QAClG,IAAI,IAAI,CAAC,cAAc;YAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,+CAA+C;QAC1F,MAAM,CAAC,GAAG,GAAG,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;QACjD,MAAM,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QACnD,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACtB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC;QAC3C,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,qBAAqB;QACnF,OAAO,CAAC,CAAC;IACX,CAAC;CACF"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * WAYPOINT BEACON — the canonical "go here" world marker: a soft glow column rising from a filled
3
+ * base disc, ringed by expanding ground waves, that gracefully **fades out** once the player reaches
4
+ * it. The standard "the game (or an NPC, or a quest) is sending you to this spot" affordance, so games
5
+ * stop re-modelling the beam + rings + dismissal every time.
6
+ *
7
+ * It owns ONLY the world-space visuals + the fade. It deliberately does NOT:
8
+ * - decide what "reached" means — proximity, an NPC line, a quest flag are the GAME's call; you tell
9
+ * the beacon when to go with {@link WaypointBeacon.trigger} (and {@link WaypointBeacon.reset} to rearm).
10
+ * - draw any DOM (a name card / distance pill). Float those with {@link ScreenAnchor} + your own HTML.
11
+ *
12
+ * Placement: `new WaypointBeacon()`, parent `.group` into your scene, set `group.position` to the
13
+ * ground point, then call `update(t, dt)` every frame (steady clock seconds + delta). The flat ground
14
+ * graphics (base + rings) render depth-test-OFF so undulating terrain never clips them (a flat decal
15
+ * at a fixed height otherwise sinks behind any rise in the ground); the vertical column keeps normal
16
+ * depth so it still tucks behind trees/hills. Everything is additive / shadow-free so it reads as UI
17
+ * light, not geometry.
18
+ */
19
+ import * as THREE from "three";
20
+ export interface WaypointBeaconOptions {
21
+ /** The beacon hue. Default `0x66e0ff` (a cyan that pops on grass). */
22
+ color?: number;
23
+ /** Glow-column height in world units. Default `13` — tall enough to read over props. */
24
+ height?: number;
25
+ /** Seconds the graceful fade-out takes once {@link WaypointBeacon.trigger} fires. Default `0.5`. */
26
+ fadeDuration?: number;
27
+ }
28
+ export declare class WaypointBeacon {
29
+ /** Parent this into your scene and set `group.position` to the beacon's ground point. */
30
+ readonly group: THREE.Group<THREE.Object3DEventMap>;
31
+ private readonly geos;
32
+ private readonly mats;
33
+ private readonly halo;
34
+ private readonly haloMat;
35
+ private readonly base;
36
+ private readonly baseMat;
37
+ private readonly rings;
38
+ private readonly fadeDuration;
39
+ /** <0 = idle; >=0 = seconds into the fade-out. */
40
+ private anim;
41
+ constructor(opts?: WaypointBeaconOptions);
42
+ /** Start the graceful fade-out. Idempotent — ignored if it's already fading or gone. */
43
+ trigger(): void;
44
+ /** Snap back to the idle beacon (rearm), e.g. when the player walks away from the spot. */
45
+ reset(): void;
46
+ /** True once the fade-out has finished and the beacon is fully invisible. */
47
+ get gone(): boolean;
48
+ /** Advance the beacon. `t` = a steady clock in seconds (drives the idle breathing/waves), `dt` = delta. */
49
+ update(t: number, dt: number): void;
50
+ /** Draw the breathing idle beacon (column + base + expanding waves), every opacity scaled by `fade`. */
51
+ private draw;
52
+ private hide;
53
+ /** Dispose geometries + materials and empty the group. Call on teardown. */
54
+ dispose(): void;
55
+ }
56
+ //# sourceMappingURL=waypoint-beacon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"waypoint-beacon.d.ts","sourceRoot":"","sources":["../../src/three/waypoint-beacon.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,MAAM,WAAW,qBAAqB;IACpC,sEAAsE;IACtE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wFAAwF;IACxF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oGAAoG;IACpG,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAQD,qBAAa,cAAc;IACzB,yFAAyF;IACzF,QAAQ,CAAC,KAAK,sCAAqB;IAEnC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA8B;IACnD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAwB;IAC7C,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAa;IAClC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA0B;IAClD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAa;IAClC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA0B;IAClD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAmE;IACzF,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IAEtC,kDAAkD;IAClD,OAAO,CAAC,IAAI,CAAM;gBAEN,IAAI,GAAE,qBAA0B;IA0B5C,wFAAwF;IACxF,OAAO,IAAI,IAAI;IAEf,2FAA2F;IAC3F,KAAK,IAAI,IAAI;IAEb,6EAA6E;IAC7E,IAAI,IAAI,IAAI,OAAO,CAA0C;IAE7D,2GAA2G;IAC3G,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;IAOnC,wGAAwG;IACxG,OAAO,CAAC,IAAI;IAWZ,OAAO,CAAC,IAAI;IAKZ,4EAA4E;IAC5E,OAAO,IAAI,IAAI;CAKhB"}
@@ -0,0 +1,118 @@
1
+ /**
2
+ * WAYPOINT BEACON — the canonical "go here" world marker: a soft glow column rising from a filled
3
+ * base disc, ringed by expanding ground waves, that gracefully **fades out** once the player reaches
4
+ * it. The standard "the game (or an NPC, or a quest) is sending you to this spot" affordance, so games
5
+ * stop re-modelling the beam + rings + dismissal every time.
6
+ *
7
+ * It owns ONLY the world-space visuals + the fade. It deliberately does NOT:
8
+ * - decide what "reached" means — proximity, an NPC line, a quest flag are the GAME's call; you tell
9
+ * the beacon when to go with {@link WaypointBeacon.trigger} (and {@link WaypointBeacon.reset} to rearm).
10
+ * - draw any DOM (a name card / distance pill). Float those with {@link ScreenAnchor} + your own HTML.
11
+ *
12
+ * Placement: `new WaypointBeacon()`, parent `.group` into your scene, set `group.position` to the
13
+ * ground point, then call `update(t, dt)` every frame (steady clock seconds + delta). The flat ground
14
+ * graphics (base + rings) render depth-test-OFF so undulating terrain never clips them (a flat decal
15
+ * at a fixed height otherwise sinks behind any rise in the ground); the vertical column keeps normal
16
+ * depth so it still tucks behind trees/hills. Everything is additive / shadow-free so it reads as UI
17
+ * light, not geometry.
18
+ */
19
+ import * as THREE from "three";
20
+ const DEFAULT_COLOR = 0x66e0ff;
21
+ /** smoothstep 0..1 */
22
+ const smooth = (x) => { const t = x <= 0 ? 0 : x >= 1 ? 1 : x; return t * t * (3 - 2 * t); };
23
+ const additive = (color, opacity) => new THREE.MeshBasicMaterial({ color, transparent: true, opacity, blending: THREE.AdditiveBlending, depthWrite: false, side: THREE.DoubleSide });
24
+ export class WaypointBeacon {
25
+ /** Parent this into your scene and set `group.position` to the beacon's ground point. */
26
+ group = new THREE.Group();
27
+ geos = [];
28
+ mats = [];
29
+ halo;
30
+ haloMat;
31
+ base;
32
+ baseMat;
33
+ rings;
34
+ fadeDuration;
35
+ /** <0 = idle; >=0 = seconds into the fade-out. */
36
+ anim = -1;
37
+ constructor(opts = {}) {
38
+ const color = opts.color ?? DEFAULT_COLOR;
39
+ const H = opts.height ?? 13;
40
+ this.fadeDuration = opts.fadeDuration ?? 0.5;
41
+ // vertical glow column (normal depth → occluded naturally by world geometry in front of it)
42
+ const haloGeo = new THREE.CylinderGeometry(0.7, 0.95, H, 20, 1, true);
43
+ haloGeo.translate(0, H / 2, 0);
44
+ this.geos.push(haloGeo);
45
+ this.haloMat = additive(color, 0.16);
46
+ this.mats.push(this.haloMat);
47
+ this.halo = new THREE.Mesh(haloGeo, this.haloMat);
48
+ this.group.add(this.halo);
49
+ // flat ground graphics: depth-test OFF + high render order so terrain can never clip them
50
+ const groundMat = (opacity) => { const m = additive(color, opacity); m.depthTest = false; this.mats.push(m); return m; };
51
+ const baseGeo = new THREE.CircleGeometry(0.95, 32);
52
+ baseGeo.rotateX(-Math.PI / 2);
53
+ this.geos.push(baseGeo);
54
+ this.baseMat = groundMat(0.4);
55
+ this.base = new THREE.Mesh(baseGeo, this.baseMat);
56
+ this.base.position.y = 0.05;
57
+ this.base.renderOrder = 10;
58
+ this.group.add(this.base);
59
+ const ringGeo = new THREE.RingGeometry(0.5, 0.62, 40);
60
+ ringGeo.rotateX(-Math.PI / 2);
61
+ this.geos.push(ringGeo);
62
+ this.rings = [0, 1].map((i) => {
63
+ const mat = groundMat(0);
64
+ const mesh = new THREE.Mesh(ringGeo, mat);
65
+ mesh.position.y = 0.06;
66
+ mesh.renderOrder = 11;
67
+ this.group.add(mesh);
68
+ return { mesh, mat, ph: i / 2 };
69
+ });
70
+ }
71
+ /** Start the graceful fade-out. Idempotent — ignored if it's already fading or gone. */
72
+ trigger() { if (this.anim < 0)
73
+ this.anim = 0; }
74
+ /** Snap back to the idle beacon (rearm), e.g. when the player walks away from the spot. */
75
+ reset() { this.anim = -1; }
76
+ /** True once the fade-out has finished and the beacon is fully invisible. */
77
+ get gone() { return this.anim > this.fadeDuration; }
78
+ /** Advance the beacon. `t` = a steady clock in seconds (drives the idle breathing/waves), `dt` = delta. */
79
+ update(t, dt) {
80
+ if (this.anim >= 0)
81
+ this.anim += dt;
82
+ if (this.anim < 0) {
83
+ this.draw(t, 1);
84
+ return;
85
+ } // idle
86
+ if (this.anim > this.fadeDuration) {
87
+ this.hide();
88
+ return;
89
+ } // fully gone
90
+ this.draw(t, 1 - smooth(this.anim / this.fadeDuration)); // fading: the whole beacon dims together
91
+ }
92
+ /** Draw the breathing idle beacon (column + base + expanding waves), every opacity scaled by `fade`. */
93
+ draw(t, fade) {
94
+ this.haloMat.opacity = (0.12 + 0.07 * (0.5 + 0.5 * Math.sin(t * 1.6))) * fade;
95
+ this.baseMat.opacity = (0.32 + 0.12 * Math.sin(t * 3)) * fade;
96
+ for (const r of this.rings) {
97
+ const ph = (t * 0.6 + r.ph) % 1;
98
+ const s = 0.5 + ph * 2.4;
99
+ r.mesh.scale.set(s, 1, s);
100
+ r.mat.opacity = 0.55 * (1 - ph) * fade;
101
+ }
102
+ }
103
+ hide() {
104
+ this.haloMat.opacity = 0;
105
+ this.baseMat.opacity = 0;
106
+ for (const r of this.rings)
107
+ r.mat.opacity = 0;
108
+ }
109
+ /** Dispose geometries + materials and empty the group. Call on teardown. */
110
+ dispose() {
111
+ for (const g of this.geos)
112
+ g.dispose();
113
+ for (const m of this.mats)
114
+ m.dispose();
115
+ this.group.clear();
116
+ }
117
+ }
118
+ //# sourceMappingURL=waypoint-beacon.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"waypoint-beacon.js","sourceRoot":"","sources":["../../src/three/waypoint-beacon.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,104 @@
1
+ # `@rydr/game-sdk/ui` — controller-button UI kit
2
+
3
+ > **MANDATORY READING before you build any in-game prompt, menu, dialogue, or keycap.** This kit is
4
+ > the shared visual language for "which button to press" across the whole RYDR library. Before you
5
+ > hand-build a button hint, an NPC dialogue box, a choice menu, or a card, check here — if it exists,
6
+ > use it. Rolling your own (or copy-pasting one out of another game) fragments the look and is a bug.
7
+
8
+ Self-contained DOM/CSS components — no three.js, no global styles. They inject their own scoped
9
+ `.rydr-ui-*` CSS once into `<head>`; you get the look just by constructing a component.
10
+
11
+ ```ts
12
+ import { mountButtonPrompt, mountDialogueCard, mountChoiceCard } from "@rydr/game-sdk/ui";
13
+ ```
14
+
15
+ ---
16
+
17
+ ## ⛔ The one hard rule: do NOT restyle the components
18
+
19
+ Every RYDR game is played on a **trainer screen viewed from a few feet away while pedaling.** The
20
+ keycap sizes, card label type, dialogue/choice font sizes, and diamond spacing are **tuned for that
21
+ distance** and are part of the component contract — not defaults to override.
22
+
23
+ - **Don't** override `.rydr-ui-*` font sizes / paddings / widths, and **don't** wrap a component in
24
+ `transform: scale()`. That breaks legibility on a real setup.
25
+ - **Do** fill the **content slot** (cards take any DOM; the diamond/prompt take a label) and use the
26
+ provided **state methods** (`setVisible`, `setPressed`, `setCooldown`, …).
27
+ - If a label doesn't fit, **shorten the text — don't shrink the type.**
28
+
29
+ To position a floating prompt over a 3D object, use `ScreenAnchor` from `@rydr/game-sdk/three` and
30
+ feed its `{x, y, onScreen}` into `setScreenPos`/`setVisible` — don't compute projections by hand.
31
+
32
+ ---
33
+
34
+ ## What's available
35
+
36
+ | Symbol | Kind | Use it for |
37
+ | --- | --- | --- |
38
+ | `createKeycap(button, opts)` | fn | A bare A/B/Y/Z keycap (the letter pip), with state setters. |
39
+ | `createDpadKeycap(dir, opts)` | fn | A bare UP/DOWN/LEFT/RIGHT keycap (white chevron on a steel pip). |
40
+ | `mountButtonPrompt(host, button, label)` | fn | The common case: a labelled "press A" prompt card. |
41
+ | `createButtonDiamond(button, variant)` | fn | The bare keycap element for embedding in your own layout. |
42
+ | `mountActionCard(host, button, opts)` | fn | A dark glass card (content slot) with a keycap straddling its bottom edge. |
43
+ | `mountCard(host, opts)` / `buildCard(opts)` | fn | Just the dark glass card with a content slot (no keycap). |
44
+ | `mountActionDiamond(host, opts)` | fn | The full 4-button A/B/Y/Z diamond with per-button labels/actions. |
45
+ | `mountLabeledDiamond(host, opts)` | fn | A diamond floating over a point with labels around it (the "actions on offer" affordance). |
46
+ | `mountDialogueCard(host, opts)` | fn | An NPC dialogue box: speaker name, typed-out line, advance cue (A). |
47
+ | `mountChoiceCard(host, opts)` | fn | A player choice menu: prompt + highlighted option list (▲▼ move, A confirm). |
48
+ | `mountRarityCard(host, opts)` / `buildRarityCard(opts)` | fn | A generic rarity-tinted item/creature card. |
49
+ | `injectCss()` | fn | Force the `.rydr-ui-*` CSS into `<head>` early (components call it for you). |
50
+
51
+ Types: `ButtonLetter` (`"A"\|"B"\|"Y"\|"Z"`), `DirButton`, `KeycapVariant` (`"full"\|"solo"`),
52
+ `ButtonSource`, `Keycap`, `Card`, `ActionCard`, `ButtonPrompt`, `DialogueCard`, `ChoiceCard`,
53
+ `LabeledDiamond`, `ActionDiamond`, `Rarity`, `RarityCard`.
54
+
55
+ ---
56
+
57
+ ## Wiring to real input
58
+
59
+ Any keycap/card reflects real presses if you pass it something with `onButton` — your platform
60
+ `session` satisfies the structural `ButtonSource`:
61
+
62
+ ```ts
63
+ const prompt = mountButtonPrompt(host, "A", "JUMP");
64
+ // pass `session` so the keycap shows its pressed sink while A is held:
65
+ createKeycap("A", { press: session });
66
+ ```
67
+
68
+ The keycap is a small state machine — pressed sink, bouncing attract pulse (`setAnimated`), a
69
+ depleting cooldown ring + countdown (`setCooldown(frac, label)`), colored/mono (`setColored`),
70
+ disabled (`setDisabled`), and show/hide (`setVisible`).
71
+
72
+ ## Common recipes
73
+
74
+ **Button prompt over an NPC (with `ScreenAnchor`):**
75
+ ```ts
76
+ const prompt = mountButtonPrompt(host, "A", "TALK");
77
+ const tag = new ScreenAnchor(npc.group); // sits just above the head by default
78
+ // per frame:
79
+ const pt = tag.project(camera, host);
80
+ prompt.setVisible(pt.onScreen);
81
+ if (pt.onScreen) prompt.setScreenPos(pt.x, pt.y); // no offsets needed
82
+ ```
83
+ > **`setScreenPos` on an action card seats it ABOVE the point.** An action card is a prompt that
84
+ > points down at a thing, so `setScreenPos(x, y)` places the card so its straddling keycap lands just
85
+ > over `(x, y)` — never on top of it. Pass an anchor straight from `ScreenAnchor.project` and don't
86
+ > add pixel fudge. (The plain `mountCard`/dialogue/choice/rarity cards still centre on the point.)
87
+
88
+ **Dialogue:**
89
+ ```ts
90
+ const dlg = mountDialogueCard(host, { press: session, onLine: (i) => npc.say?.(i) });
91
+ dlg.open("Master Orsane", ["Welcome.", "Pick a creature."]);
92
+ // A advances; dlg.advance() returns false when the last line is done.
93
+ ```
94
+
95
+ **Choice menu:**
96
+ ```ts
97
+ const choice = mountChoiceCard(host, { press: session });
98
+ choice.open({ name: "You", prompt: "Who will you greet?", options, selected: 0 });
99
+ ```
100
+
101
+ ---
102
+
103
+ For exact signatures and option types, read the `.d.ts` alongside the compiled module
104
+ (`dist/ui/*.d.ts`). This README is the map; the types are the contract.
@@ -1 +1 @@
1
- {"version":3,"file":"action-card.d.ts","sourceRoot":"","sources":["../../src/ui/action-card.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAa,KAAK,IAAI,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AACnE,OAAO,EAAgB,KAAK,YAAY,EAAE,KAAK,aAAa,EAAE,KAAK,aAAa,EAAE,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAEnH,MAAM,WAAW,iBAAkB,SAAQ,aAAa,EAAE,WAAW;CAAG;AAExE,gGAAgG;AAChG,MAAM,WAAW,UAAW,SAAQ,IAAI;IACtC,2FAA2F;IAC3F,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAAC;IAC9B,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAChE,WAAW,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAAC;IAC/B,UAAU,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAAC;IAC9B,yFAAyF;IACzF,WAAW,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAAC;CAChC;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,GAAE,iBAAsB,GAAG,UAAU,CAgBjH;AAID,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,WAAW,CAAC;IAClB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,UAAU,CAAC,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC7B,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,4FAA4F;AAC5F,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,GAAE,aAAsB,GAAG,WAAW,CAEtG;AAED,kFAAkF;AAClF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,GAAG,YAAY,CAEtG"}
1
+ {"version":3,"file":"action-card.d.ts","sourceRoot":"","sources":["../../src/ui/action-card.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAa,KAAK,IAAI,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AACnE,OAAO,EAAgB,KAAK,YAAY,EAAE,KAAK,aAAa,EAAE,KAAK,aAAa,EAAE,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAEnH,MAAM,WAAW,iBAAkB,SAAQ,aAAa,EAAE,WAAW;CAAG;AAUxE,gGAAgG;AAChG,MAAM,WAAW,UAAW,SAAQ,IAAI;IACtC,2FAA2F;IAC3F,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAAC;IAC9B,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAChE,WAAW,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAAC;IAC/B,UAAU,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAAC;IAC9B,yFAAyF;IACzF,WAAW,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAAC;CAChC;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,GAAE,iBAAsB,GAAG,UAAU,CAyBjH;AAID,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,WAAW,CAAC;IAClB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,UAAU,CAAC,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC7B,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,4FAA4F;AAC5F,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,GAAE,aAAsB,GAAG,WAAW,CAEtG;AAED,kFAAkF;AAClF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,GAAG,YAAY,CAEtG"}
@@ -6,6 +6,13 @@
6
6
  */
7
7
  import { buildCard } from "./card.js";
8
8
  import { createKeycap } from "./keycap.js";
9
+ /**
10
+ * How far (px) the keycap hangs below the card's bottom edge — it straddles there (see styles.ts
11
+ * `.rydr-ui-card > .rydr-ui-diamond`: a ~38px keycap dropped ~65%+8px). `setScreenPos` uses this to
12
+ * seat the prompt ABOVE the tracked point, so the keycap lands just over it (an NPC head) rather than
13
+ * on it — callers pass the anchor point straight through, no per-call pixel fudge.
14
+ */
15
+ const KEYCAP_DROP = 33;
9
16
  /**
10
17
  * Mount an action card: a dark glass card with the keycap straddling its bottom edge and a content
11
18
  * SLOT (`card.body`). Fixed bottom-centre by default (call `setScreenPos` to track a projected point),
@@ -25,6 +32,15 @@ export function mountActionCard(host, button, opts = {}) {
25
32
  setColored: keycap.setColored,
26
33
  // the whole action goes unavailable: fade the card AND make the keycap inert in one call.
27
34
  setDisabled: (on) => { card.setDisabled(on); keycap.setDisabled(on); },
35
+ // Override the base (centre-on-point) placement: an action card is a prompt that points DOWN at
36
+ // a thing, so seat it ABOVE the tracked point with the straddling keycap landing just over it.
37
+ // Callers pass an anchor (e.g. ScreenAnchor.project over a head) straight in — no pixel offset.
38
+ setScreenPos(x, y) {
39
+ card.root.style.left = `${x}px`;
40
+ card.root.style.top = `${y}px`;
41
+ card.root.style.bottom = "auto";
42
+ card.root.style.transform = `translate(-50%, calc(-100% - ${KEYCAP_DROP}px))`;
43
+ },
28
44
  };
29
45
  }
30
46
  /** The bare keycap (no card) for embedding — back-compat shim over {@link createKeycap}. */
@@ -1 +1 @@
1
- {"version":3,"file":"action-card.js","sourceRoot":"","sources":["../../src/ui/action-card.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAA+B,MAAM,WAAW,CAAC;AACnE,OAAO,EAAE,YAAY,EAA0E,MAAM,aAAa,CAAC;AAgBnH;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,IAAiB,EAAE,MAAoB,EAAE,OAA0B,EAAE;IACnG,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAC7B,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC1C,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,gDAAgD;IAClF,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAE5B,OAAO;QACL,GAAG,IAAI;QACP,MAAM;QACN,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,0FAA0F;QAC1F,WAAW,EAAE,CAAC,EAAW,EAAE,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;KAChF,CAAC;AACJ,CAAC;AAYD,4FAA4F;AAC5F,MAAM,UAAU,mBAAmB,CAAC,MAAoB,EAAE,UAAyB,MAAM;IACvF,OAAO,YAAY,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC;AAC9C,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,iBAAiB,CAAC,IAAiB,EAAE,MAAoB,EAAE,KAAa;IACtF,OAAO,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;AAClD,CAAC"}
1
+ {"version":3,"file":"action-card.js","sourceRoot":"","sources":["../../src/ui/action-card.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,SAAS,EAA+B,MAAM,WAAW,CAAC;AACnE,OAAO,EAAE,YAAY,EAA0E,MAAM,aAAa,CAAC;AAInH;;;;;GAKG;AACH,MAAM,WAAW,GAAG,EAAE,CAAC;AAcvB;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,IAAiB,EAAE,MAAoB,EAAE,OAA0B,EAAE;IACnG,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAC7B,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC1C,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,gDAAgD;IAClF,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAE5B,OAAO;QACL,GAAG,IAAI;QACP,MAAM;QACN,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,0FAA0F;QAC1F,WAAW,EAAE,CAAC,EAAW,EAAE,EAAE,GAAG,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC/E,gGAAgG;QAChG,+FAA+F;QAC/F,gGAAgG;QAChG,YAAY,CAAC,CAAS,EAAE,CAAS;YAC/B,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC;YAChC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,GAAG,CAAC,IAAI,CAAC;YAC/B,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC;YAChC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,gCAAgC,WAAW,MAAM,CAAC;QAChF,CAAC;KACF,CAAC;AACJ,CAAC;AAYD,4FAA4F;AAC5F,MAAM,UAAU,mBAAmB,CAAC,MAAoB,EAAE,UAAyB,MAAM;IACvF,OAAO,YAAY,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC;AAC9C,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,iBAAiB,CAAC,IAAiB,EAAE,MAAoB,EAAE,KAAa;IACtF,OAAO,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;AAClD,CAAC"}
@@ -2,8 +2,8 @@
2
2
  * `@rydr/game-sdk/ui` — the reusable controller-button UI: a DOM/CSS keycap of the A/B/Y/Z face
3
3
  * buttons and the UP/DOWN/LEFT/RIGHT d-pad, plus higher-level pieces built from it (a dark glass card
4
4
  * with a content slot, an action card, the full A/B/Y/Z move diamond, an NPC dialogue card, a player
5
- * choice menu, and a labeled diamond). Games use it to show "which button to press" in one consistent
6
- * visual language across the library.
5
+ * choice menu, a labeled diamond, and a generic rarity card). Games use it to show "which button to
6
+ * press" in one consistent visual language across the library.
7
7
  *
8
8
  * Self-contained, like `@rydr/game-sdk/three`'s perf-overlay: it injects its own scoped `.rydr-ui-*`
9
9
  * CSS once into `<head>`, depends on no global styles or CSS variables, and pulls in no three.js — so
@@ -28,4 +28,5 @@ export * from "./action-diamond.js";
28
28
  export * from "./dialogue-card.js";
29
29
  export * from "./choice-card.js";
30
30
  export * from "./labeled-diamond.js";
31
+ export * from "./rarity-card.js";
31
32
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ui/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ui/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC"}
package/dist/ui/index.js CHANGED
@@ -2,8 +2,8 @@
2
2
  * `@rydr/game-sdk/ui` — the reusable controller-button UI: a DOM/CSS keycap of the A/B/Y/Z face
3
3
  * buttons and the UP/DOWN/LEFT/RIGHT d-pad, plus higher-level pieces built from it (a dark glass card
4
4
  * with a content slot, an action card, the full A/B/Y/Z move diamond, an NPC dialogue card, a player
5
- * choice menu, and a labeled diamond). Games use it to show "which button to press" in one consistent
6
- * visual language across the library.
5
+ * choice menu, a labeled diamond, and a generic rarity card). Games use it to show "which button to
6
+ * press" in one consistent visual language across the library.
7
7
  *
8
8
  * Self-contained, like `@rydr/game-sdk/three`'s perf-overlay: it injects its own scoped `.rydr-ui-*`
9
9
  * CSS once into `<head>`, depends on no global styles or CSS variables, and pulls in no three.js — so
@@ -28,4 +28,5 @@ export * from "./action-diamond.js";
28
28
  export * from "./dialogue-card.js";
29
29
  export * from "./choice-card.js";
30
30
  export * from "./labeled-diamond.js";
31
+ export * from "./rarity-card.js";
31
32
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ui/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ui/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,kBAAkB,CAAC;AACjC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * RARITY CARD — a generic, game-agnostic rarity-tinted dark-glass frame with a CONTENT SLOT
3
+ * (`card.body`) the game fills with whatever it wants (a creature plate, an item, a card name +
4
+ * stats, …). The whole frame is tinted by the rarity colour: a 2px rarity rim, an inner + outer
5
+ * rarity glow, and either a thin top sheen or a thick top BAND carrying the rarity label. A
6
+ * `selected` state adds a crisp rarity ring + a deeper glow and lifts/scales the card — for
7
+ * arrow-navigable rosters/pickers.
8
+ *
9
+ * Rarity is a small built-in scale (`common`…`legendary`) with an SDK-shipped {@link RARITY} palette
10
+ * (colour + label). Games should use the default palette so rarity reads consistently across the
11
+ * library; a per-card `color`/`label` override exists but is NOT recommended.
12
+ *
13
+ * Like the rest of `@rydr/game-sdk/ui`, it injects its own scoped `.rydr-ui-*` CSS and depends on no
14
+ * global styles. Fill the content slot and use the state methods — don't restyle the frame.
15
+ */
16
+ /** The built-in rarity scale, lowest → highest. */
17
+ export type Rarity = "common" | "uncommon" | "rare" | "epic" | "legendary";
18
+ /** A rarity's visual identity: the tint colour + the label shown in the top band. */
19
+ export interface RarityStyle {
20
+ /** Any CSS colour — tints the whole frame (rim, glow, band). */
21
+ color: string;
22
+ /** Uppercased in the band, e.g. "Legendary". */
23
+ label: string;
24
+ }
25
+ /**
26
+ * The SDK's default rarity palette. Prefer it as-is so rarity reads the same across every game; pass a
27
+ * per-card `color`/`label` override only as a last resort.
28
+ */
29
+ export declare const RARITY: Record<Rarity, RarityStyle>;
30
+ export interface RarityCardOptions {
31
+ /** Rarity tier — drives the frame tint + the band label from the {@link RARITY} palette. */
32
+ rarity?: Rarity;
33
+ /** Override the rarity tint colour (NOT recommended — prefer the palette default per tier). */
34
+ color?: string;
35
+ /** Override the band label (e.g. a localised rarity name). Defaults to the tier's label. */
36
+ label?: string;
37
+ /** Show the thick top band carrying the rarity label. Defaults to `true` when a `rarity` is given. */
38
+ band?: boolean;
39
+ /** Initial slot content — a string (set as text) or an element appended into `body`. */
40
+ content?: string | HTMLElement;
41
+ /** Lay the card inline (in normal flow) instead of fixed bottom-centre. */
42
+ inline?: boolean;
43
+ /** Fixed card width (number → px, or any CSS length). Omit → the card hugs its content. */
44
+ width?: number | string;
45
+ /** Fixed card height (number → px, or any CSS length). Omit → the card hugs its content. */
46
+ height?: number | string;
47
+ /** Start in the selected state (ring + deeper glow + lift). */
48
+ selected?: boolean;
49
+ }
50
+ /** A mounted rarity card: a rarity-tinted frame + a content slot the game owns. */
51
+ export interface RarityCard {
52
+ root: HTMLElement;
53
+ /** The content SLOT — append your own DOM here, or use setContent. */
54
+ body: HTMLElement;
55
+ setContent(content: string | HTMLElement): void;
56
+ /** Retint the frame (and band label) for a new rarity; `override` tweaks colour/label off the default. */
57
+ setRarity(rarity: Rarity, override?: Partial<RarityStyle>): void;
58
+ /** Selected = the focused card in a picker: a rarity ring + deeper glow, lifted + scaled. */
59
+ setSelected(on: boolean): void;
60
+ setVisible(v: boolean): void;
61
+ /** Centre the card at a viewport pixel (e.g. an entity projected to screen). */
62
+ setScreenPos(x: number, y: number): void;
63
+ dispose(): void;
64
+ }
65
+ /**
66
+ * Build the rarity-card DOM + handle WITHOUT attaching it to a host. Also returns the inner
67
+ * `.rydr-ui-rcard` element. Internal building block — most callers want {@link mountRarityCard}.
68
+ */
69
+ export declare function buildRarityCard(opts?: RarityCardOptions): RarityCard & {
70
+ card: HTMLElement;
71
+ };
72
+ /** Mount a rarity-tinted card (frame + content slot) into `host`. See {@link RarityCardOptions}. */
73
+ export declare function mountRarityCard(host: HTMLElement, opts?: RarityCardOptions): RarityCard;
74
+ //# sourceMappingURL=rarity-card.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rarity-card.d.ts","sourceRoot":"","sources":["../../src/ui/rarity-card.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,mDAAmD;AACnD,MAAM,MAAM,MAAM,GAAG,QAAQ,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM,GAAG,WAAW,CAAC;AAE3E,qFAAqF;AACrF,MAAM,WAAW,WAAW;IAC1B,gEAAgE;IAChE,KAAK,EAAE,MAAM,CAAC;IACd,gDAAgD;IAChD,KAAK,EAAE,MAAM,CAAC;CACf;AAKD;;;GAGG;AACH,eAAO,MAAM,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAM9C,CAAC;AAEF,MAAM,WAAW,iBAAiB;IAChC,4FAA4F;IAC5F,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+FAA+F;IAC/F,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4FAA4F;IAC5F,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sGAAsG;IACtG,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,wFAAwF;IACxF,OAAO,CAAC,EAAE,MAAM,GAAG,WAAW,CAAC;IAC/B,2EAA2E;IAC3E,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,2FAA2F;IAC3F,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACxB,4FAA4F;IAC5F,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,mFAAmF;AACnF,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,WAAW,CAAC;IAClB,sEAAsE;IACtE,IAAI,EAAE,WAAW,CAAC;IAClB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAAC;IAChD,0GAA0G;IAC1G,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,OAAO,CAAC,WAAW,CAAC,GAAG,IAAI,CAAC;IACjE,6FAA6F;IAC7F,WAAW,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAAC;IAC/B,UAAU,CAAC,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC7B,gFAAgF;IAChF,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,GAAE,iBAAsB,GAAG,UAAU,GAAG;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,CA+DhG;AAED,oGAAoG;AACpG,wBAAgB,eAAe,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,GAAE,iBAAsB,GAAG,UAAU,CAI3F"}