@tesana/sdk 1.0.3 → 1.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 CHANGED
@@ -55,11 +55,66 @@ succeeding.
55
55
  | `tesana.player` | Identity — `login({ tesanaUserId })` |
56
56
  | `tesana.vanity` | The game's own address on tesana.ai |
57
57
  | `tesana.ads` | Ads, when the host allows them |
58
+ | `tesana.gameplay` | Progression events — `levelStart` / `levelComplete` / `death` / `checkpoint` / `score` |
59
+ | `tesana.track` | Any other gameplay event, by name |
58
60
 
59
61
  Leaderboards and achievements are client-reported, so they are a ranking to show
60
62
  off rather than a prize table; nothing here mints coins or grants entitlements.
61
63
  A counted achievement is decided by the server, not the game.
62
64
 
65
+ ### Gameplay analytics
66
+
67
+ `tesana.track` and `tesana.gameplay` report what happened in the game so its
68
+ creator can see where players get stuck and where they quit. They go to the
69
+ Tesana page above the game, which files them against the play session; there
70
+ is no key and no third-party provider.
71
+
72
+ ```js
73
+ tesana.gameplay.levelStart({ levelId: "forest", levelIndex: 1 });
74
+ tesana.gameplay.death({ levelId: "forest", x: player.x, y: player.y });
75
+ tesana.gameplay.checkpoint({ levelId: "forest", name: "bridge" });
76
+ tesana.gameplay.levelComplete({ levelId: "forest" });
77
+ tesana.gameplay.score({ value: 4200 });
78
+ tesana.track("powerup_picked", { kind: "triple_shot" });
79
+ ```
80
+
81
+ ```ts
82
+ type GameplayProps = {
83
+ levelId?: string | number; // the join key: the same value in every call for one level
84
+ levelIndex?: number; // 0-based position, when levels are ordered
85
+ x?: number; y?: number; z?: number; // where it happened (deaths draw the heatmap)
86
+ value?: number; // a score, a count
87
+ name?: string; // a death's cause, a checkpoint's name
88
+ [context: string]: string | number | boolean | null | undefined;
89
+ };
90
+
91
+ track(name: string, props?: GameplayProps): boolean;
92
+ gameplay.levelStart(props?: GameplayProps | string | number): boolean; // bare value = levelId
93
+ gameplay.levelComplete(props?: GameplayProps | string | number): boolean;
94
+ gameplay.death(props?: GameplayProps | string | number): boolean;
95
+ gameplay.checkpoint(props?: GameplayProps | string | number): boolean;
96
+ gameplay.score(props?: GameplayProps | number): boolean; // bare value = value
97
+ ```
98
+
99
+ - **Never throws, never async.** Each call answers `true` when the event was
100
+ handed on and `false` when it was dropped (a bad name, too many events, or no
101
+ Tesana page and no runtime shell to hand it to). Call it inline, unguarded.
102
+ - **No `init()` needed.** The same functions are on the global `Tesana`, so a
103
+ game can report its first level before `__TESANA_READY__` resolves.
104
+ - **Delivery.** The runtime shell's `window.__TESANA_EVENT__` when the page has
105
+ it, else `postMessage({ type: "tesana-gameplay-event", event })` to the parent.
106
+ `event` is the shape `POST /api/games/<id>/play/events/` stores: `type`
107
+ (`level_start`, `level_complete`, `death`, `checkpoint`, `score` or `custom`),
108
+ `name`, `level_id`, `level_index`, `x`, `y`, `z`, `value`, `payload`, `ts`.
109
+ - **`track` names.** A name that is one of the types above files the event as
110
+ that type; any other name is a `custom` event with that name.
111
+ - **Caps.** Names are cut to 64 characters. Up to 20 context keys are kept
112
+ (keys cut to 40 characters, strings to 64); objects, arrays, functions and
113
+ non-finite numbers are dropped, and keys stop being added before the payload
114
+ passes the endpoint's 2,000-character limit.
115
+ - **Rate.** At most 10 events in any one second and 1,000 per page load. Report
116
+ discrete moments — a level, a death, a run's end — never every frame.
117
+
63
118
  ### Offline behaviour
64
119
 
65
120
  Every call resolves rather than throwing when there is no host, no endpoint or