@oasiz/sdk 1.8.1 → 1.8.3
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 +571 -80
- package/dist/index.cjs +3166 -225
- package/dist/index.d.cts +362 -110
- package/dist/index.d.ts +362 -110
- package/dist/index.js +3149 -214
- package/package.json +15 -4
package/README.md
CHANGED
|
@@ -1,92 +1,187 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Oasiz game SDKs
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Games on Oasiz can integrate using either of these official SDKs:
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
| Platform | Package | Use for |
|
|
6
|
+
| --- | --- | --- |
|
|
7
|
+
| **HTML5 / TypeScript** | [`@oasiz/sdk`](#html5--typescript-oasizsdk) (npm) | Canvas, Phaser, custom JS/TS, any browser game |
|
|
8
|
+
| **Unity WebGL** | [Unity runtime](#unity-webgl-sdk) in this repo (`packages/OasizSDK/`) | Unity projects targeting WebGL |
|
|
9
|
+
|
|
10
|
+
Both talk to the same host bridges (`window.submitScore`, `__oasizLeaveGame`, layout APIs, custom DOM events such as `oasiz:pause`, etc.). Unsupported hosts no-op safely; local dev usually logs warnings instead of crashing.
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## HTML5 / TypeScript (`@oasiz/sdk`)
|
|
15
|
+
|
|
16
|
+
Typed SDK for integrating browser games with the Oasiz platform: score, haptics, cross-session state, multiplayer hooks, layout (safe area, leaderboard visibility), graphics performance, navigation (back / leave), and lifecycle events.
|
|
17
|
+
|
|
18
|
+
### Install
|
|
6
19
|
|
|
7
20
|
```bash
|
|
8
|
-
npm install @oasiz/sdk
|
|
21
|
+
npm install @oasiz/sdk
|
|
9
22
|
```
|
|
10
23
|
|
|
24
|
+
The published package includes ESM, CommonJS, and TypeScript declarations.
|
|
25
|
+
|
|
11
26
|
## Quick start
|
|
12
27
|
|
|
13
28
|
```ts
|
|
14
29
|
import { oasiz } from "@oasiz/sdk";
|
|
15
30
|
|
|
16
|
-
//
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
{ raw: 60, normalized: 300 },
|
|
21
|
-
{ raw: 120, normalized: 600 },
|
|
22
|
-
{ raw: 300, normalized: 950 },
|
|
23
|
-
],
|
|
24
|
-
});
|
|
31
|
+
// 0. Optional local app preview for web development
|
|
32
|
+
if (import.meta.env.DEV) {
|
|
33
|
+
oasiz.enableAppSimulator();
|
|
34
|
+
}
|
|
25
35
|
|
|
26
|
-
//
|
|
36
|
+
// 1. Load persisted state at the start of each session
|
|
27
37
|
const state = oasiz.loadGameState();
|
|
28
38
|
let level = typeof state.level === "number" ? state.level : 1;
|
|
29
39
|
|
|
30
|
-
//
|
|
40
|
+
// 2. Save state at checkpoints
|
|
31
41
|
oasiz.saveGameState({ level, coins: 42 });
|
|
32
42
|
|
|
33
|
-
//
|
|
43
|
+
// 3. Trigger haptics on key events
|
|
34
44
|
oasiz.triggerHaptic("medium");
|
|
35
45
|
|
|
36
|
-
//
|
|
46
|
+
// 4. Respect the host's top safe area (percent of viewport height → CSS vh)
|
|
47
|
+
document.documentElement.style.setProperty(
|
|
48
|
+
"--safe-top",
|
|
49
|
+
`${oasiz.safeAreaTop}vh`,
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
// 5. Pick graphics settings for this device
|
|
53
|
+
const graphics = oasiz.getGraphicsPerformance();
|
|
54
|
+
renderer.setPixelRatio(graphics.tier === "high" ? 1.5 : graphics.tier === "medium" ? 1.25 : 1);
|
|
55
|
+
|
|
56
|
+
// 6. Submit score when the game ends
|
|
37
57
|
oasiz.submitScore(score);
|
|
38
|
-
```
|
|
39
58
|
|
|
40
|
-
|
|
59
|
+
// 7. Optionally hide the leaderboard while a custom overlay is open
|
|
60
|
+
oasiz.setLeaderboardVisible(false);
|
|
61
|
+
|
|
62
|
+
// 8. Optionally surface console logs in-game while debugging
|
|
63
|
+
oasiz.enableLogOverlay({
|
|
64
|
+
enabled: new URLSearchParams(window.location.search).has("oasizLogs"),
|
|
65
|
+
collapsed: true,
|
|
66
|
+
});
|
|
67
|
+
```
|
|
41
68
|
|
|
42
|
-
|
|
69
|
+
### Local app simulator
|
|
43
70
|
|
|
44
|
-
|
|
71
|
+
#### `oasiz.enableAppSimulator(options?: AppSimulatorOptions): AppSimulatorHandle`
|
|
45
72
|
|
|
46
|
-
|
|
73
|
+
Opt-in local web helper for previewing a game inside Oasiz-style mobile chrome. It simulates the app back button, leaderboard pill, like/comment hub, comments modal, and leaderboard modal while also injecting local safe-area and viewport-inset bridge values.
|
|
47
74
|
|
|
48
75
|
```ts
|
|
49
|
-
|
|
50
|
-
oasiz.
|
|
76
|
+
if (import.meta.env.DEV) {
|
|
77
|
+
oasiz.enableAppSimulator();
|
|
51
78
|
}
|
|
79
|
+
|
|
80
|
+
oasiz.onBackButton(() => {
|
|
81
|
+
togglePauseMenu();
|
|
82
|
+
});
|
|
52
83
|
```
|
|
53
84
|
|
|
54
|
-
- `
|
|
55
|
-
- Do not call on intermediate scores or level completions, only on final game over.
|
|
85
|
+
By default, the game is placed inside a centered phone-sized box so developers can resize their browser around the same shape the app uses. The default device is `iphone-17-pro-max` (`440 × 956` CSS pixels). You can change the preview:
|
|
56
86
|
|
|
57
|
-
|
|
87
|
+
```ts
|
|
88
|
+
const appPreview = oasiz.enableAppSimulator({
|
|
89
|
+
device: "iphone-17-pro-max",
|
|
90
|
+
likes: 2400,
|
|
91
|
+
comments: 18,
|
|
92
|
+
score: 12400,
|
|
93
|
+
});
|
|
58
94
|
|
|
59
|
-
|
|
95
|
+
debugCommentsButton.onclick = () => appPreview.openComments();
|
|
96
|
+
debugLeaderboardButton.onclick = () => appPreview.openLeaderboard();
|
|
97
|
+
```
|
|
60
98
|
|
|
61
|
-
|
|
99
|
+
Set `frame: false` if your own dev harness already renders the game in a phone frame.
|
|
100
|
+
|
|
101
|
+
The simulator includes the back-button test bridge, so Escape, browser Back, and the simulated app back button all route through the same `oasiz.onBackButton(...)` handler when back override is active. Use `enableBackButtonTesting()` directly only when you want back simulation without app chrome.
|
|
102
|
+
|
|
103
|
+
Supported `device` presets:
|
|
104
|
+
|
|
105
|
+
| Device option | CSS viewport |
|
|
106
|
+
| --- | --- |
|
|
107
|
+
| `iphone-11` | `414 × 896` |
|
|
108
|
+
| `iphone-11-pro` | `375 × 812` |
|
|
109
|
+
| `iphone-11-pro-max` | `414 × 896` |
|
|
110
|
+
| `iphone-12-mini` | `375 × 812` |
|
|
111
|
+
| `iphone-12` | `390 × 844` |
|
|
112
|
+
| `iphone-12-pro` | `390 × 844` |
|
|
113
|
+
| `iphone-12-pro-max` | `428 × 926` |
|
|
114
|
+
| `iphone-13-mini` | `375 × 812` |
|
|
115
|
+
| `iphone-13` | `390 × 844` |
|
|
116
|
+
| `iphone-13-pro` | `390 × 844` |
|
|
117
|
+
| `iphone-13-pro-max` | `428 × 926` |
|
|
118
|
+
| `iphone-14` | `390 × 844` |
|
|
119
|
+
| `iphone-14-plus` | `428 × 926` |
|
|
120
|
+
| `iphone-14-pro` | `393 × 852` |
|
|
121
|
+
| `iphone-14-pro-max` | `430 × 932` |
|
|
122
|
+
| `iphone-15` | `393 × 852` |
|
|
123
|
+
| `iphone-15-plus` | `430 × 932` |
|
|
124
|
+
| `iphone-15-pro` | `393 × 852` |
|
|
125
|
+
| `iphone-15-pro-max` | `430 × 932` |
|
|
126
|
+
| `iphone-16` | `393 × 852` |
|
|
127
|
+
| `iphone-16-plus` | `430 × 932` |
|
|
128
|
+
| `iphone-16-pro` | `402 × 874` |
|
|
129
|
+
| `iphone-16-pro-max` | `440 × 956` |
|
|
130
|
+
| `iphone-16e` | `390 × 844` |
|
|
131
|
+
| `iphone-17` | `402 × 874` |
|
|
132
|
+
| `iphone-17-pro` | `402 × 874` |
|
|
133
|
+
| `iphone-17-pro-max` | `440 × 956` |
|
|
134
|
+
| `iphone-17e` | `390 × 844` |
|
|
135
|
+
| `iphone-air` | `420 × 912` |
|
|
136
|
+
|
|
137
|
+
### Player character animations
|
|
138
|
+
|
|
139
|
+
Use the Jibble animation constants when wiring a player character atlas so you can reference known animation IDs during local development instead of publishing first and reading logs.
|
|
62
140
|
|
|
63
141
|
```ts
|
|
64
|
-
oasiz
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
142
|
+
import { JIBBLE_ANIMATION, getJibbleAnimationId, oasiz } from "@oasiz/sdk";
|
|
143
|
+
|
|
144
|
+
const character = await oasiz.getPlayerCharacter();
|
|
145
|
+
if (!character) return;
|
|
146
|
+
|
|
147
|
+
const atlas = character.textureAtlas;
|
|
148
|
+
const walkBack = getJibbleAnimationId("walk", "back"); // "walk_n"
|
|
149
|
+
const walkBackAnimation = atlas.animations.find((anim) => anim.animationId === walkBack);
|
|
150
|
+
const idleFrontAnimation = atlas.animations.find(
|
|
151
|
+
(anim) => anim.animationId === JIBBLE_ANIMATION.Idle.South,
|
|
152
|
+
);
|
|
72
153
|
```
|
|
73
154
|
|
|
74
|
-
|
|
75
|
-
- Exactly 4 anchors required.
|
|
76
|
-
- `raw` values must be strictly increasing.
|
|
77
|
-
- `normalized` values must end at exactly `950`.
|
|
78
|
-
- Choose thresholds based on realistic player skill bands.
|
|
155
|
+
Supported directional IDs use compass codes: `n`, `ne`, `e`, `se`, `s`, `sw`, `w`, `nw`. The helper accepts gameplay-facing aliases too: `front` -> `s`, `back` -> `n`, `left` -> `w`, `right` -> `e`.
|
|
79
156
|
|
|
80
|
-
|
|
81
|
-
- Survival / time games → use seconds survived as `raw`
|
|
82
|
-
- Score accumulation games → use points as `raw`
|
|
83
|
-
- Puzzle games → use level reached or stars earned as `raw`
|
|
157
|
+
Unity exposes the same IDs:
|
|
84
158
|
|
|
85
|
-
|
|
159
|
+
```csharp
|
|
160
|
+
var walkBack = JibbleAnimations.GetId(
|
|
161
|
+
JibbleAnimationAction.Walk,
|
|
162
|
+
JibbleDirection.Back);
|
|
163
|
+
|
|
164
|
+
var idleFront = JibbleAnimations.Idle.South;
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Score
|
|
86
168
|
|
|
87
|
-
|
|
169
|
+
#### `oasiz.submitScore(score: number)`
|
|
170
|
+
|
|
171
|
+
Submit the player's final score at game over. Call this exactly once per session, when the game ends. The platform handles leaderboard persistence — do not track high scores locally.
|
|
172
|
+
|
|
173
|
+
```ts
|
|
174
|
+
private onGameOver(): void {
|
|
175
|
+
oasiz.submitScore(Math.floor(this.score));
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
- `score` must be a non-negative integer. Floats are floored automatically.
|
|
180
|
+
- Do not call on intermediate scores or level completions, only on final game over.
|
|
88
181
|
|
|
89
|
-
###
|
|
182
|
+
### Haptics
|
|
183
|
+
|
|
184
|
+
#### `oasiz.triggerHaptic(type: HapticType)`
|
|
90
185
|
|
|
91
186
|
Trigger native haptic feedback. Always guard with the user's haptics setting.
|
|
92
187
|
|
|
@@ -95,7 +190,7 @@ type HapticType = "light" | "medium" | "heavy" | "success" | "error";
|
|
|
95
190
|
```
|
|
96
191
|
|
|
97
192
|
| Type | When to use |
|
|
98
|
-
|
|
193
|
+
| --- | --- |
|
|
99
194
|
| `"light"` | UI button taps, menu navigation, D-pad press |
|
|
100
195
|
| `"medium"` | Collecting items, standard collisions, scoring |
|
|
101
196
|
| `"heavy"` | Explosions, major impacts, screen shake |
|
|
@@ -126,20 +221,45 @@ private onGameOver(): void {
|
|
|
126
221
|
|
|
127
222
|
Haptics are throttled internally (50ms cooldown) to prevent spam.
|
|
128
223
|
|
|
129
|
-
|
|
224
|
+
### Debugging
|
|
225
|
+
|
|
226
|
+
#### `oasiz.enableLogOverlay(options?: LogOverlayOptions)`
|
|
227
|
+
|
|
228
|
+
Mount an opt-in in-game console viewer for local debugging, QA sessions, or creator support. It mirrors `console.log`, `console.info`, `console.warn`, `console.error`, and `console.debug` into a floating overlay inside the game iframe. The overlay can be collapsed, repositioned by dragging the top bar, and resized from the bottom-right corner while the action buttons remain clickable.
|
|
229
|
+
|
|
230
|
+
```ts
|
|
231
|
+
const logOverlay = oasiz.enableLogOverlay({
|
|
232
|
+
enabled: new URLSearchParams(window.location.search).has("oasizLogs"),
|
|
233
|
+
collapsed: true,
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
console.log("[Boot] Scene ready");
|
|
237
|
+
|
|
238
|
+
// Optional cleanup if your game tears down and remounts
|
|
239
|
+
logOverlay.destroy();
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
Options:
|
|
130
243
|
|
|
131
|
-
|
|
244
|
+
- `enabled`: defaults to `true`. Pass your own flag or query-param check here.
|
|
245
|
+
- `collapsed`: start with only the toggle pill visible.
|
|
246
|
+
- `maxEntries`: cap retained log lines. Defaults to `200`.
|
|
247
|
+
- `title`: optional label shown at the top of the panel. Defaults to `SDK Logs`.
|
|
248
|
+
|
|
249
|
+
The returned handle supports `show()`, `hide()`, `clear()`, `isVisible()`, and `destroy()`.
|
|
250
|
+
|
|
251
|
+
### Game state persistence
|
|
132
252
|
|
|
133
253
|
Persist cross-session data such as unlocked levels, inventory, or lifetime stats. State is stored per-user per-game in the Oasiz backend — available across devices and app reinstalls.
|
|
134
254
|
|
|
135
|
-
|
|
255
|
+
#### `oasiz.loadGameState(): Record<string, unknown>`
|
|
136
256
|
|
|
137
257
|
Returns the player's saved state synchronously. Returns `{}` if no state has been saved yet. Call once at the start of the game.
|
|
138
258
|
|
|
139
259
|
```ts
|
|
140
260
|
private initFromSavedState(): void {
|
|
141
261
|
const state = oasiz.loadGameState();
|
|
142
|
-
this.level
|
|
262
|
+
this.level = typeof state.level === "number" ? state.level : 1;
|
|
143
263
|
this.lifetimeHits = typeof state.lifetimeHits === "number" ? state.lifetimeHits : 0;
|
|
144
264
|
this.unlockedSkins = Array.isArray(state.unlockedSkins) ? state.unlockedSkins : [];
|
|
145
265
|
}
|
|
@@ -147,7 +267,7 @@ private initFromSavedState(): void {
|
|
|
147
267
|
|
|
148
268
|
Always validate the shape of loaded data — it may be `{}` on first play.
|
|
149
269
|
|
|
150
|
-
|
|
270
|
+
#### `oasiz.saveGameState(state: Record<string, unknown>)`
|
|
151
271
|
|
|
152
272
|
Queues a debounced save. Saves are batched automatically — call freely at checkpoints without worrying about request spam.
|
|
153
273
|
|
|
@@ -164,11 +284,12 @@ private onLevelComplete(): void {
|
|
|
164
284
|
```
|
|
165
285
|
|
|
166
286
|
**Rules:**
|
|
287
|
+
|
|
167
288
|
- State must be a plain JSON object (not an array or primitive).
|
|
168
289
|
- Do not use `localStorage` for cross-session progress — use `saveGameState` so data syncs across platforms.
|
|
169
290
|
- Do not store scores here — scores are submitted via `submitScore`.
|
|
170
291
|
|
|
171
|
-
|
|
292
|
+
#### `oasiz.flushGameState()`
|
|
172
293
|
|
|
173
294
|
Forces an immediate write, bypassing the debounce. Use at important checkpoints like game over or before the page unloads.
|
|
174
295
|
|
|
@@ -180,19 +301,125 @@ private onGameOver(): void {
|
|
|
180
301
|
}
|
|
181
302
|
```
|
|
182
303
|
|
|
183
|
-
|
|
304
|
+
### Layout
|
|
305
|
+
|
|
306
|
+
Use runtime viewport insets instead of direct CSS `env(safe-area-inset-*)` reads or hardcoded offsets. The SDK resolves host-provided Oasiz values first, then browser CSS `env(safe-area-inset-*)`, then legacy `constant(safe-area-inset-*)`, and finally `0`.
|
|
307
|
+
|
|
308
|
+
The top inset preserves the existing Oasiz game-safe top behavior: host chrome, invite UI, and leaderboard clearance can contribute to it. Left, right, and bottom are device safe-area insets today and may include future host UI obstructions.
|
|
309
|
+
|
|
310
|
+
#### `oasiz.getViewportInsets(): ViewportInsets`
|
|
311
|
+
|
|
312
|
+
Returns effective viewport insets in both CSS pixels and normalized percentages:
|
|
313
|
+
|
|
314
|
+
```ts
|
|
315
|
+
const insets = oasiz.getViewportInsets();
|
|
316
|
+
hud.style.paddingTop = `${insets.pixels.top}px`;
|
|
317
|
+
hud.style.paddingRight = `${insets.pixels.right}px`;
|
|
318
|
+
hud.style.paddingBottom = `${insets.pixels.bottom}px`;
|
|
319
|
+
hud.style.paddingLeft = `${insets.pixels.left}px`;
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
Percentages use the matching active viewport axis:
|
|
323
|
+
|
|
324
|
+
- `top` / `bottom` are percentages of viewport height
|
|
325
|
+
- `left` / `right` are percentages of viewport width
|
|
326
|
+
|
|
327
|
+
Hosts may expose pixels via `window.getViewportInsets()` or `window.__OASIZ_VIEWPORT_INSETS__`, for example `{ top, right, bottom, left }` or `{ pixels: { top, right, bottom, left } }`. Hosts may expose percentages via `window.getViewportInsetsPercent()`, `window.__OASIZ_VIEWPORT_INSETS_PERCENT__`, or a `percent` object. Per-side globals such as `window.__OASIZ_SAFE_AREA_BOTTOM__` are also supported.
|
|
328
|
+
|
|
329
|
+
#### `oasiz.getSafeAreaTop(): number`
|
|
330
|
+
|
|
331
|
+
Legacy alias for `oasiz.getViewportInsets().percent.top`. Returns the top inset as a percentage of viewport height (0–100). To get pixels in JavaScript, prefer `oasiz.getViewportInsets().pixels.top`. In CSS, the percent value matches **`vh`** units (for example `12.5vh` for 12.5% of the viewport height). Unsupported hosts return `0`.
|
|
332
|
+
|
|
333
|
+
```ts
|
|
334
|
+
const safeTopPct = oasiz.getSafeAreaTop();
|
|
335
|
+
document.documentElement.style.setProperty("--safe-top", `${safeTopPct}vh`);
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
#### `oasiz.safeAreaTop`
|
|
339
|
+
|
|
340
|
+
Getter alias for `getSafeAreaTop()`.
|
|
341
|
+
|
|
342
|
+
#### `oasiz.viewportInsets`
|
|
343
|
+
|
|
344
|
+
Getter alias for `getViewportInsets()`.
|
|
345
|
+
|
|
346
|
+
Recommended CSS pattern:
|
|
347
|
+
|
|
348
|
+
```css
|
|
349
|
+
:root {
|
|
350
|
+
--safe-top: 0px;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
#top-bar {
|
|
354
|
+
padding-top: var(--safe-top);
|
|
355
|
+
}
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
#### `oasiz.setLeaderboardVisible(visible: boolean): void`
|
|
359
|
+
|
|
360
|
+
Show or hide the host leaderboard UI from inside the game. This only affects the leaderboard; back and social controls remain visible. Calls `window.__oasizSetLeaderboardVisible` when present.
|
|
361
|
+
|
|
362
|
+
```ts
|
|
363
|
+
function openCustomOverlay(): void {
|
|
364
|
+
oasiz.setLeaderboardVisible(false);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
function closeCustomOverlay(): void {
|
|
368
|
+
oasiz.setLeaderboardVisible(true);
|
|
369
|
+
}
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
Unsupported hosts safely no-op.
|
|
373
|
+
|
|
374
|
+
### Graphics performance
|
|
375
|
+
|
|
376
|
+
#### `oasiz.getGraphicsPerformance(): GraphicsPerformanceMetric`
|
|
377
|
+
|
|
378
|
+
Returns a recommended FPS target and suggested rendering tier:
|
|
379
|
+
|
|
380
|
+
```ts
|
|
381
|
+
const graphics = oasiz.getGraphicsPerformance();
|
|
382
|
+
// graphics is { fps: number, tier: "minimal" | "low" | "medium" | "high" }
|
|
383
|
+
|
|
384
|
+
gameLoop.setTargetFps(graphics.fps);
|
|
385
|
+
|
|
386
|
+
switch (graphics.tier) {
|
|
387
|
+
case "high":
|
|
388
|
+
enablePostProcessing();
|
|
389
|
+
renderer.setPixelRatio(1.5);
|
|
390
|
+
break;
|
|
391
|
+
case "medium":
|
|
392
|
+
renderer.setPixelRatio(1.25);
|
|
393
|
+
break;
|
|
394
|
+
case "low":
|
|
395
|
+
disableHeavyParticles();
|
|
396
|
+
renderer.setPixelRatio(1);
|
|
397
|
+
break;
|
|
398
|
+
case "minimal":
|
|
399
|
+
disableOptionalEffects();
|
|
400
|
+
renderer.setPixelRatio(0.75);
|
|
401
|
+
break;
|
|
402
|
+
}
|
|
403
|
+
```
|
|
184
404
|
|
|
185
|
-
|
|
405
|
+
The returned object is `{ fps, tier }`, where `fps` is the recommended render target and `tier` is `"minimal"`, `"low"`, `"medium"`, or `"high"`. Hosts can inject measured values with `window.getGraphicsPerformance()` or `window.__OASIZ_GRAPHICS_PERFORMANCE__`; otherwise the SDK estimates from browser, device, and WebGL capability signals.
|
|
406
|
+
|
|
407
|
+
#### `oasiz.graphicsPerformance`
|
|
408
|
+
|
|
409
|
+
Getter alias for `getGraphicsPerformance()`.
|
|
410
|
+
|
|
411
|
+
### Lifecycle
|
|
186
412
|
|
|
187
413
|
The platform dispatches lifecycle events when the app goes to the background or returns to the foreground. Subscribe to pause game loops and audio accordingly.
|
|
188
414
|
|
|
189
|
-
|
|
190
|
-
|
|
415
|
+
#### `oasiz.onPause(callback: () => void): Unsubscribe`
|
|
416
|
+
|
|
417
|
+
#### `oasiz.onResume(callback: () => void): Unsubscribe`
|
|
191
418
|
|
|
192
419
|
Both return an unsubscribe function.
|
|
193
420
|
|
|
194
421
|
```ts
|
|
195
|
-
const offPause
|
|
422
|
+
const offPause = oasiz.onPause(() => {
|
|
196
423
|
this.gameLoop.stop();
|
|
197
424
|
this.bgMusic.pause();
|
|
198
425
|
});
|
|
@@ -207,19 +434,17 @@ offPause();
|
|
|
207
434
|
offResume();
|
|
208
435
|
```
|
|
209
436
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
## Navigation
|
|
437
|
+
### Navigation
|
|
213
438
|
|
|
214
439
|
Use navigation hooks when your game needs to control back behavior (Android back / web Escape) or participate in host-driven close events.
|
|
215
440
|
|
|
216
|
-
|
|
441
|
+
#### `oasiz.onBackButton(callback: () => void): Unsubscribe`
|
|
217
442
|
|
|
218
443
|
Registers a callback for platform back actions. While at least one back listener is subscribed, back actions are routed to your game instead of immediately closing it.
|
|
219
444
|
|
|
220
445
|
Use this for pause menus, in-game overlays, or custom back-stack behavior.
|
|
221
446
|
|
|
222
|
-
If your callback throws
|
|
447
|
+
**If your callback throws**, the SDK calls `leaveGame()` (host close) and **rethrows** the error so you still see it in devtools or error reporting. Non-`Error` throws are normalized to an `Error` (strings become the message; otherwise `"Back button callback failed."`).
|
|
223
448
|
|
|
224
449
|
```ts
|
|
225
450
|
const offBack = oasiz.onBackButton(() => {
|
|
@@ -234,7 +459,30 @@ const offBack = oasiz.onBackButton(() => {
|
|
|
234
459
|
offBack();
|
|
235
460
|
```
|
|
236
461
|
|
|
237
|
-
|
|
462
|
+
#### `oasiz.enableBackButtonTesting(options?: BackButtonTestingOptions): BackButtonTestingHandle`
|
|
463
|
+
|
|
464
|
+
Opt-in local web helper for testing back override behavior without the Oasiz app bridge. Call it before registering `onBackButton` in local development:
|
|
465
|
+
|
|
466
|
+
```ts
|
|
467
|
+
if (import.meta.env.DEV) {
|
|
468
|
+
oasiz.enableBackButtonTesting();
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
const offBack = oasiz.onBackButton(() => {
|
|
472
|
+
closePauseMenuOrOpenIt();
|
|
473
|
+
});
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
While a back listener is active, the helper maps Escape to the same `oasiz:back` event the app sends. By default it also traps one browser-history entry so the browser Back button dispatches `oasiz:back` instead of leaving the page.
|
|
477
|
+
|
|
478
|
+
```ts
|
|
479
|
+
const backTest = oasiz.enableBackButtonTesting({ browserHistory: false });
|
|
480
|
+
testBackButton.onclick = () => backTest.triggerBack();
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
The returned handle also exposes `triggerLeave()` and `destroy()`. This helper is for local/dev web testing; in the app, the real bridge still owns back behavior.
|
|
484
|
+
|
|
485
|
+
#### `oasiz.leaveGame(): void`
|
|
238
486
|
|
|
239
487
|
Programmatically request the host to close the current game (for example, from a Quit button inside your game UI).
|
|
240
488
|
|
|
@@ -269,14 +517,14 @@ const offLeave = oasiz.onLeaveGame(() => {
|
|
|
269
517
|
offLeave();
|
|
270
518
|
```
|
|
271
519
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
## Multiplayer
|
|
520
|
+
### Multiplayer
|
|
275
521
|
|
|
276
|
-
|
|
522
|
+
#### `oasiz.shareRoomCode(code: string | null, options?: { inviteOverride?: boolean })`
|
|
277
523
|
|
|
278
524
|
Notify the platform of the active multiplayer room so friends can join via the invite system. Pass `null` when leaving a room.
|
|
279
525
|
|
|
526
|
+
Set `inviteOverride: true` when your game wants to hide the platform invite pill and render its own invite button/UI. The platform still tracks the room code, but your game owns the invite entry point.
|
|
527
|
+
|
|
280
528
|
```ts
|
|
281
529
|
import { insertCoin, getRoomCode } from "playroomkit";
|
|
282
530
|
import { oasiz } from "@oasiz/sdk";
|
|
@@ -288,7 +536,26 @@ oasiz.shareRoomCode(getRoomCode());
|
|
|
288
536
|
oasiz.shareRoomCode(null);
|
|
289
537
|
```
|
|
290
538
|
|
|
291
|
-
|
|
539
|
+
```ts
|
|
540
|
+
// Game-owned invite UI: hide the platform pill, keep room tracking
|
|
541
|
+
oasiz.shareRoomCode(getRoomCode(), { inviteOverride: true });
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
#### `oasiz.openInviteModal(): void`
|
|
545
|
+
|
|
546
|
+
Opens the platform invite-friends UI when the bridge is available. Typically used together with `shareRoomCode` (for example, your own invite button calls this).
|
|
547
|
+
|
|
548
|
+
```ts
|
|
549
|
+
import { openInviteModal, shareRoomCode } from "@oasiz/sdk";
|
|
550
|
+
|
|
551
|
+
shareRoomCode("ABCD", { inviteOverride: true });
|
|
552
|
+
|
|
553
|
+
inviteButton.addEventListener("click", () => {
|
|
554
|
+
openInviteModal();
|
|
555
|
+
});
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
#### Read-only injected values
|
|
292
559
|
|
|
293
560
|
These are populated by the platform before the game loads. Always check for `undefined` before using.
|
|
294
561
|
|
|
@@ -302,25 +569,31 @@ if (oasiz.roomCode) {
|
|
|
302
569
|
}
|
|
303
570
|
|
|
304
571
|
// Player identity for multiplayer games
|
|
305
|
-
const name
|
|
572
|
+
const name = oasiz.playerName;
|
|
306
573
|
const avatar = oasiz.playerAvatar;
|
|
307
574
|
```
|
|
308
575
|
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
## Named exports
|
|
576
|
+
### Named exports
|
|
312
577
|
|
|
313
578
|
All methods are also available as named exports if you prefer not to use the `oasiz` namespace object:
|
|
314
579
|
|
|
315
580
|
```ts
|
|
316
581
|
import {
|
|
317
582
|
submitScore,
|
|
318
|
-
|
|
583
|
+
share,
|
|
319
584
|
triggerHaptic,
|
|
320
585
|
loadGameState,
|
|
321
586
|
saveGameState,
|
|
322
587
|
flushGameState,
|
|
323
588
|
shareRoomCode,
|
|
589
|
+
openInviteModal,
|
|
590
|
+
enableAppSimulator,
|
|
591
|
+
enableLogOverlay,
|
|
592
|
+
enableBackButtonTesting,
|
|
593
|
+
getGraphicsPerformance,
|
|
594
|
+
getSafeAreaTop,
|
|
595
|
+
getViewportInsets,
|
|
596
|
+
setLeaderboardVisible,
|
|
324
597
|
onPause,
|
|
325
598
|
onResume,
|
|
326
599
|
onBackButton,
|
|
@@ -333,18 +606,232 @@ import {
|
|
|
333
606
|
} from "@oasiz/sdk";
|
|
334
607
|
```
|
|
335
608
|
|
|
609
|
+
### TypeScript types
|
|
610
|
+
|
|
611
|
+
```ts
|
|
612
|
+
import type {
|
|
613
|
+
AppSimulatorDevice,
|
|
614
|
+
AppSimulatorDeviceName,
|
|
615
|
+
AppSimulatorHandle,
|
|
616
|
+
AppSimulatorOptions,
|
|
617
|
+
AppSimulatorOrientation,
|
|
618
|
+
BackButtonTestingHandle,
|
|
619
|
+
BackButtonTestingOptions,
|
|
620
|
+
GameState,
|
|
621
|
+
GraphicsPerformanceMetric,
|
|
622
|
+
GraphicsPerformanceTier,
|
|
623
|
+
HapticType,
|
|
624
|
+
LogOverlayEntry,
|
|
625
|
+
LogOverlayHandle,
|
|
626
|
+
LogOverlayLevel,
|
|
627
|
+
LogOverlayOptions,
|
|
628
|
+
ShareRequest,
|
|
629
|
+
ShareRoomCodeOptions,
|
|
630
|
+
Unsubscribe,
|
|
631
|
+
} from "@oasiz/sdk";
|
|
632
|
+
```
|
|
633
|
+
|
|
336
634
|
---
|
|
337
635
|
|
|
338
|
-
##
|
|
636
|
+
## Unity WebGL SDK
|
|
637
|
+
|
|
638
|
+
C# API and **WebGL-only** `OasizBridge.jslib` live in this repository at **`packages/OasizSDK/`**. Copy the **`OasizSDK`** folder into your Unity project under **`Assets/`** (for example `Assets/OasizSDK`).
|
|
639
|
+
|
|
640
|
+
### Setup
|
|
641
|
+
|
|
642
|
+
1. Copy `packages/OasizSDK` from this repo into `Assets/OasizSDK`.
|
|
643
|
+
2. Ensure the **WebGL** platform is selected for release builds; the `.jslib` under `Runtime/Plugins/WebGL/` is included automatically for WebGL.
|
|
644
|
+
3. Add an **`OasizSDK`** component to a persistent GameObject early (for example a bootstrap scene), **or** rely on `OasizSDK.Instance` which creates a `DontDestroyOnLoad` object. The component registers listeners for `oasiz:pause`, `oasiz:resume`, `oasiz:back`, and `oasiz:leave` via `SendMessage`.
|
|
645
|
+
|
|
646
|
+
### Quick start
|
|
647
|
+
|
|
648
|
+
```csharp
|
|
649
|
+
using Oasiz;
|
|
650
|
+
using UnityEngine;
|
|
651
|
+
|
|
652
|
+
public class GameManager : MonoBehaviour
|
|
653
|
+
{
|
|
654
|
+
void Start()
|
|
655
|
+
{
|
|
656
|
+
// Ensure the singleton is initialized early
|
|
657
|
+
_ = OasizSDK.Instance;
|
|
658
|
+
|
|
659
|
+
// Subscribe to lifecycle events
|
|
660
|
+
OasizSDK.OnPause += OnPause;
|
|
661
|
+
OasizSDK.OnResume += OnResume;
|
|
662
|
+
|
|
663
|
+
// Offset UI for the host's top safe area (0–100 percent of Screen.height)
|
|
664
|
+
float safeTopPct = OasizSDK.SafeAreaTop;
|
|
665
|
+
float safeTopPx = safeTopPct / 100f * Screen.height;
|
|
666
|
+
Debug.Log($"Safe area top: {safeTopPx}px ({safeTopPct}% of height)");
|
|
667
|
+
|
|
668
|
+
// Pick visual settings for the current device
|
|
669
|
+
GraphicsPerformanceMetric graphics = OasizSDK.GetGraphicsPerformance();
|
|
670
|
+
Debug.Log($"Graphics tier: {graphics.tier} ({graphics.fps} FPS target)");
|
|
671
|
+
|
|
672
|
+
// Emit score normalization anchors
|
|
673
|
+
OasizSDK.EmitScoreConfig(new ScoreConfig(
|
|
674
|
+
new ScoreAnchor(10, 100),
|
|
675
|
+
new ScoreAnchor(30, 300),
|
|
676
|
+
new ScoreAnchor(75, 600),
|
|
677
|
+
new ScoreAnchor(200, 950)
|
|
678
|
+
));
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
void OnGameOver(int finalScore)
|
|
682
|
+
{
|
|
683
|
+
OasizSDK.SubmitScore(finalScore);
|
|
684
|
+
OasizSDK.FlushGameState();
|
|
685
|
+
OasizSDK.SetLeaderboardVisible(true);
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
void OnGameplayStart()
|
|
689
|
+
{
|
|
690
|
+
OasizSDK.SetLeaderboardVisible(false);
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
void OnPause() => Time.timeScale = 0f;
|
|
694
|
+
void OnResume() => Time.timeScale = 1f;
|
|
695
|
+
|
|
696
|
+
void OnDestroy()
|
|
697
|
+
{
|
|
698
|
+
OasizSDK.OnPause -= OnPause;
|
|
699
|
+
OasizSDK.OnResume -= OnResume;
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
```
|
|
339
703
|
|
|
340
|
-
|
|
341
|
-
|
|
704
|
+
### API parity (TypeScript → C#)
|
|
705
|
+
|
|
706
|
+
| HTML5 (`@oasiz/sdk`) | Unity (`Oasiz` namespace) |
|
|
707
|
+
| --- | --- |
|
|
708
|
+
| `oasiz.submitScore(n)` | `OasizSDK.SubmitScore(int)` |
|
|
709
|
+
| `oasiz.triggerHaptic(type)` | `OasizSDK.TriggerHaptic(HapticType)` |
|
|
710
|
+
| `oasiz.loadGameState()` | `OasizSDK.LoadGameState()` → `Dictionary<string, object>` |
|
|
711
|
+
| `oasiz.saveGameState(obj)` | `OasizSDK.SaveGameState(Dictionary<string, object>)` |
|
|
712
|
+
| `oasiz.flushGameState()` | `OasizSDK.FlushGameState()` |
|
|
713
|
+
| `oasiz.getViewportInsets()` / `viewportInsets` | `OasizSDK.GetViewportInsets()` (`ViewportInsets`, each side 0–100, % of matching viewport axis) |
|
|
714
|
+
| `oasiz.getSafeAreaTop()` / `safeAreaTop` | `OasizSDK.GetSafeAreaTop()` / `OasizSDK.SafeAreaTop` (`float`, 0–100, % of viewport height; legacy alias for top viewport inset) |
|
|
715
|
+
| `oasiz.setLeaderboardVisible(v)` | `OasizSDK.SetLeaderboardVisible(bool)` |
|
|
716
|
+
| `oasiz.getGraphicsPerformance()` / `graphicsPerformance` | `OasizSDK.GetGraphicsPerformance()` / `OasizSDK.GraphicsPerformance` (`GraphicsPerformanceMetric`, recommended FPS plus `minimal` / `low` / `medium` / `high`) |
|
|
717
|
+
| `oasiz.onPause` / `onResume` | `OasizSDK.OnPause` / `OnResume` static events |
|
|
718
|
+
| `oasiz.onBackButton` | `OasizSDK.OnBackButton` or `SubscribeBackButton(Action)` (reference-counts `__oasizSetBackOverride`) |
|
|
719
|
+
| `oasiz.enableBackButtonTesting()` | `OasizSDK.EnableBackButtonTesting()` (WebGL local/dev helper for Escape/browser Back testing) |
|
|
720
|
+
| `oasiz.onLeaveGame` | `OasizSDK.OnLeaveGame` |
|
|
721
|
+
| `oasiz.leaveGame()` | `OasizSDK.LeaveGame()` |
|
|
722
|
+
| `oasiz.share(request)` | `OasizSDK.Share(ShareRequest)` |
|
|
723
|
+
| `oasiz.shareRoomCode` | `OasizSDK.ShareRoomCode(string, ShareRoomCodeOptions)` |
|
|
724
|
+
| `oasiz.openInviteModal()` | `OasizSDK.OpenInviteModal()` |
|
|
725
|
+
| `oasiz.gameId` / `roomCode` / ... | `OasizSDK.GameId` / `RoomCode` / `PlayerName` / `PlayerAvatar` |
|
|
726
|
+
| -- | `OasizSDK.EmitScoreConfig(ScoreConfig)` → `window.emitScoreConfig` (Unity-only helper for normalized score UI) |
|
|
727
|
+
| `oasiz.enableLogOverlay` | `OasizSDK.EnableLogOverlay(LogOverlayOptions)` (see note below) |
|
|
728
|
+
| -- | `OasizSDK.AppendLogOverlay(level, message, stackTrace)` (see note below) |
|
|
729
|
+
|
|
730
|
+
### Local back-button testing (Unity WebGL)
|
|
731
|
+
|
|
732
|
+
For local WebGL builds outside the Oasiz app, install the dev bridge before testing your subscribed back handler:
|
|
733
|
+
|
|
734
|
+
```csharp
|
|
735
|
+
#if DEVELOPMENT_BUILD || UNITY_EDITOR
|
|
736
|
+
OasizSDK.EnableBackButtonTesting();
|
|
737
|
+
#endif
|
|
738
|
+
|
|
739
|
+
Action unsubscribeBack = OasizSDK.SubscribeBackButton(() =>
|
|
740
|
+
{
|
|
741
|
+
TogglePauseMenu();
|
|
742
|
+
});
|
|
743
|
+
```
|
|
744
|
+
|
|
745
|
+
While the override is active, Escape and the browser Back button dispatch the same `oasiz:back` event that the app bridge sends. You can disable either input with `OasizSDK.EnableBackButtonTesting(keyboard: false)` or `OasizSDK.EnableBackButtonTesting(browserHistory: false)`.
|
|
746
|
+
|
|
747
|
+
### Share (Unity)
|
|
748
|
+
|
|
749
|
+
HTML5 **`oasiz.share`** returns a **Promise** you can `await`. Unity **`OasizSDK.Share(ShareRequest)`** returns **`void`**: C# validation throws **`ArgumentException`** with the same rules as TypeScript (at least one of text, score, or image; non-negative integer score; `http(s)` or `data:image/...;base64,...` image). The call forwards JSON to **`window.__oasizShareRequest`**. If the host promise rejects, the **WebGL `.jslib` logs the error** to the browser console.
|
|
750
|
+
|
|
751
|
+
```csharp
|
|
752
|
+
OasizSDK.Share(new ShareRequest
|
|
753
|
+
{
|
|
754
|
+
Text = "Beat this run!",
|
|
755
|
+
Score = 1200,
|
|
756
|
+
Image = "https://example.com/card.png",
|
|
757
|
+
});
|
|
758
|
+
```
|
|
759
|
+
|
|
760
|
+
### Types
|
|
761
|
+
|
|
762
|
+
```csharp
|
|
763
|
+
// Haptic feedback intensity
|
|
764
|
+
public enum HapticType { Light, Medium, Heavy, Success, Error }
|
|
765
|
+
|
|
766
|
+
// Score normalization (exactly 4 anchors required)
|
|
767
|
+
public struct ScoreAnchor { public int raw; public int normalized; }
|
|
768
|
+
public struct ScoreConfig { public ScoreAnchor[] anchors; }
|
|
769
|
+
|
|
770
|
+
// Host share sheet (text / score / image URL or data URL)
|
|
771
|
+
public class ShareRequest
|
|
772
|
+
{
|
|
773
|
+
public string Text { get; set; }
|
|
774
|
+
public int? Score { get; set; }
|
|
775
|
+
public string Image { get; set; }
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
// Multiplayer invite options
|
|
779
|
+
public class ShareRoomCodeOptions { public bool InviteOverride { get; set; } }
|
|
780
|
+
|
|
781
|
+
// Log overlay configuration
|
|
782
|
+
public class LogOverlayOptions
|
|
783
|
+
{
|
|
784
|
+
public bool Enabled { get; set; } = true;
|
|
785
|
+
public bool Collapsed { get; set; } = false;
|
|
786
|
+
public int MaxEntries { get; set; } = 200;
|
|
787
|
+
public string Title { get; set; } = "SDK Logs";
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
// Log overlay lifecycle handle
|
|
791
|
+
public class LogOverlayHandle
|
|
792
|
+
{
|
|
793
|
+
public void Clear();
|
|
794
|
+
public void Hide();
|
|
795
|
+
public void Show();
|
|
796
|
+
public bool IsVisible();
|
|
797
|
+
public void Destroy();
|
|
798
|
+
}
|
|
799
|
+
```
|
|
800
|
+
|
|
801
|
+
### Back button and errors
|
|
802
|
+
|
|
803
|
+
Matching the HTML5 SDK: if any **`OnBackButton`** handler throws, **`OasizSDK.LeaveGame()`** is invoked and the **original exception is rethrown** (`throw;` preserves the stack trace). Use **`SubscribeBackButton`** when you want an unsubscribe delegate; you can also use `OnBackButton +=` / `-=` directly.
|
|
804
|
+
|
|
805
|
+
```csharp
|
|
806
|
+
// Subscribe with automatic unsubscribe support
|
|
807
|
+
var offBack = OasizSDK.SubscribeBackButton(() =>
|
|
808
|
+
{
|
|
809
|
+
if (isPaused)
|
|
810
|
+
Resume();
|
|
811
|
+
else
|
|
812
|
+
Pause();
|
|
813
|
+
});
|
|
814
|
+
|
|
815
|
+
// Unsubscribe when no longer needed
|
|
816
|
+
offBack();
|
|
342
817
|
```
|
|
343
818
|
|
|
819
|
+
### Editor vs WebGL builds
|
|
820
|
+
|
|
821
|
+
In the **Unity Editor**, bridge calls are mostly **logged** and return safe defaults (for example safe area `0`, `null` platform IDs). Real host integration applies to **WebGL player** builds running inside Oasiz.
|
|
822
|
+
|
|
823
|
+
### Log overlay (Unity)
|
|
824
|
+
|
|
825
|
+
The C# API for the log overlay exists for API compatibility, but the **default `OasizBridge.jslib` in this repo does not inject DOM UI** — `EnableLogOverlay` / `AppendLogOverlay` are no-ops at the JavaScript layer. Use Unity's console and device logs for debugging unless you replace or extend the `.jslib` on your side.
|
|
826
|
+
|
|
827
|
+
`AppendLogOverlay(level, message, stackTrace)` lets you pipe `Debug.Log` output into the overlay manually, since many embedded WebViews do not route Unity player logs through `console.log`. Valid levels: `"debug"`, `"log"`, `"info"`, `"warn"`, `"error"`.
|
|
828
|
+
|
|
344
829
|
---
|
|
345
830
|
|
|
346
831
|
## Local development
|
|
347
832
|
|
|
833
|
+
### HTML5 / TypeScript
|
|
834
|
+
|
|
348
835
|
All methods safely no-op when the platform bridges are not injected. In development mode a console warning is logged so you know the call was made:
|
|
349
836
|
|
|
350
837
|
```
|
|
@@ -352,3 +839,7 @@ All methods safely no-op when the platform bridges are not injected. In developm
|
|
|
352
839
|
```
|
|
353
840
|
|
|
354
841
|
No crashes, no special setup required for local dev.
|
|
842
|
+
|
|
843
|
+
### Unity WebGL
|
|
844
|
+
|
|
845
|
+
The `.jslib` logs warnings when `window.*` bridges are missing (for example `submitScore`, `__oasizLeaveGame`). The Editor path avoids calling native plugins and prints `Debug.Log` for most operations instead.
|