@oasiz/sdk 1.8.4 → 1.8.6

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
@@ -167,6 +167,49 @@ or `southwest`.
167
167
  `backflip` is not directional, so `getJibbleAnimationId("backflip", "left")`
168
168
  still returns `backflip`.
169
169
 
170
+ #### Local browser sample atlas
171
+
172
+ Inside the Oasiz app, `oasiz.getPlayerCharacter()` returns the authenticated
173
+ player's real character atlas. On `localhost` or `file://` without the app
174
+ bridge, it first fetches an Oasiz-owned real sample atlas from
175
+ `https://api.oasiz.ai/api/sdk/sample-character`, so browser games can test
176
+ sprite loading, atlas slicing, and animation lookup before publishing.
177
+
178
+ The platform sample is generated by the same backend/R2 atlas pipeline as real
179
+ characters, but it is not a user character and it does not expose user id,
180
+ layer config, or personal data. If the endpoint is unavailable, the SDK uses a
181
+ tiny generated atlas as a resilience fallback unless disabled.
182
+
183
+ ```ts
184
+ const character = await oasiz.getPlayerCharacter();
185
+
186
+ // In Oasiz app: the real signed-in player's character.
187
+ // On localhost without the app bridge: "Oasiz Sample Jibble".
188
+ // On non-local pages without the app bridge: null.
189
+ ```
190
+
191
+ Use the options when you need explicit behavior:
192
+
193
+ ```ts
194
+ // Keep the old "missing bridge means null" behavior.
195
+ const characterOrNull = await oasiz.getPlayerCharacter({ localFallback: false });
196
+
197
+ // Force the sample atlas in a browser test harness.
198
+ const sampleCharacter = await oasiz.getPlayerCharacter({ localFallback: true });
199
+
200
+ // Strict mode: require the platform-generated sample, with no generated backup.
201
+ const platformOnlySample = await oasiz.getPlayerCharacter({
202
+ localFallback: true,
203
+ generatedFallback: false,
204
+ });
205
+
206
+ // Override the sample endpoint when testing against staging.
207
+ const stagingSample = await oasiz.getPlayerCharacter({
208
+ localFallback: true,
209
+ sampleCharacterUrl: "https://staging-api.oasiz.ai/api/sdk/sample-character",
210
+ });
211
+ ```
212
+
170
213
  #### HTML5 / TypeScript
171
214
 
172
215
  ```ts
package/dist/index.cjs CHANGED
@@ -37,6 +37,8 @@ __export(index_exports, {
37
37
  getPlayerName: () => getPlayerName,
38
38
  getRoomCode: () => getRoomCode,
39
39
  getSafeAreaTop: () => getSafeAreaTop,
40
+ getSamplePlayerCharacter: () => getSamplePlayerCharacter,
41
+ getSampleTextureAtlas: () => getSampleTextureAtlas,
40
42
  getViewportInsets: () => getViewportInsets,
41
43
  leaveGame: () => leaveGame,
42
44
  loadGameState: () => loadGameState,
@@ -1444,65 +1446,6 @@ function enableAppSimulator(options = {}) {
1444
1446
  return handle;
1445
1447
  }
1446
1448
 
1447
- // src/character.ts
1448
- function isDevelopment2() {
1449
- const nodeEnv = globalThis.process?.env?.NODE_ENV;
1450
- return nodeEnv !== "production";
1451
- }
1452
- function getBridgeWindow2() {
1453
- if (typeof window === "undefined") {
1454
- return void 0;
1455
- }
1456
- return window;
1457
- }
1458
- function warnMissingBridge2(methodName) {
1459
- if (isDevelopment2()) {
1460
- console.warn(
1461
- "[oasiz/sdk] " + methodName + " bridge is unavailable. This is expected in local development."
1462
- );
1463
- }
1464
- }
1465
- async function getPlayerCharacter() {
1466
- const bridge = getBridgeWindow2();
1467
- if (typeof bridge?.__oasizGetPlayerCharacter !== "function") {
1468
- warnMissingBridge2("getPlayerCharacter");
1469
- return null;
1470
- }
1471
- try {
1472
- const result = await bridge.__oasizGetPlayerCharacter();
1473
- return result ?? null;
1474
- } catch (error) {
1475
- if (isDevelopment2()) {
1476
- console.error("[oasiz/sdk] getPlayerCharacter failed:", error);
1477
- }
1478
- return null;
1479
- }
1480
- }
1481
-
1482
- // src/haptics.ts
1483
- function isDevelopment3() {
1484
- const nodeEnv = globalThis.process?.env?.NODE_ENV;
1485
- return nodeEnv !== "production";
1486
- }
1487
- function getBridgeWindow3() {
1488
- if (typeof window === "undefined") {
1489
- return void 0;
1490
- }
1491
- return window;
1492
- }
1493
- function triggerHaptic(type) {
1494
- const bridge = getBridgeWindow3();
1495
- if (typeof bridge?.triggerHaptic === "function") {
1496
- bridge.triggerHaptic(type);
1497
- return;
1498
- }
1499
- if (isDevelopment3()) {
1500
- console.warn(
1501
- "[oasiz/sdk] triggerHaptic bridge is unavailable. This is expected in local development."
1502
- );
1503
- }
1504
- }
1505
-
1506
1449
  // src/jibble.ts
1507
1450
  var JIBBLE_DIRECTIONS = [
1508
1451
  "n",
@@ -1603,6 +1546,282 @@ function getJibbleAnimationId(action, direction = "front") {
1603
1546
  return `${action}_${normalizeJibbleDirection(direction)}`;
1604
1547
  }
1605
1548
 
1549
+ // src/sample-character.ts
1550
+ var FRAME_SIZE = 32;
1551
+ var COLUMNS = 8;
1552
+ var WALK_FRAME_COUNT = 2;
1553
+ var BACKFLIP_FRAME_COUNT = 4;
1554
+ var COLORS = [
1555
+ "#2563eb",
1556
+ "#7c3aed",
1557
+ "#db2777",
1558
+ "#ea580c",
1559
+ "#16a34a",
1560
+ "#0891b2",
1561
+ "#4f46e5",
1562
+ "#be123c"
1563
+ ];
1564
+ var IDLE_FRAME_NAMES = JIBBLE_DIRECTIONS.map((direction) => `idle_${direction}`);
1565
+ var WALK_FRAME_NAMES = JIBBLE_DIRECTIONS.flatMap(
1566
+ (direction) => Array.from({ length: WALK_FRAME_COUNT }, (_, index) => `walk_${direction}_${index}`)
1567
+ );
1568
+ var BACKFLIP_FRAME_NAMES = Array.from(
1569
+ { length: BACKFLIP_FRAME_COUNT },
1570
+ (_, index) => `backflip_${index}`
1571
+ );
1572
+ var SAMPLE_FRAME_NAMES = [
1573
+ ...IDLE_FRAME_NAMES,
1574
+ ...WALK_FRAME_NAMES,
1575
+ ...BACKFLIP_FRAME_NAMES
1576
+ ];
1577
+ var IMAGE_WIDTH = COLUMNS * FRAME_SIZE;
1578
+ var IMAGE_HEIGHT = Math.ceil(SAMPLE_FRAME_NAMES.length / COLUMNS) * FRAME_SIZE;
1579
+ function getFrameRect(index) {
1580
+ return {
1581
+ x: index % COLUMNS * FRAME_SIZE,
1582
+ y: Math.floor(index / COLUMNS) * FRAME_SIZE,
1583
+ width: FRAME_SIZE,
1584
+ height: FRAME_SIZE
1585
+ };
1586
+ }
1587
+ function createFrame(name, index) {
1588
+ return {
1589
+ name,
1590
+ ...getFrameRect(index)
1591
+ };
1592
+ }
1593
+ function getFrameLabel(name) {
1594
+ return name.replace(/^idle_/, "i ").replace(/^walk_/, "w ").replace(/^backflip_/, "flip ");
1595
+ }
1596
+ function createSvgDataUrl() {
1597
+ const cells = SAMPLE_FRAME_NAMES.map((name, index) => {
1598
+ const { x, y } = getFrameRect(index);
1599
+ const color = COLORS[index % COLORS.length];
1600
+ const label = getFrameLabel(name);
1601
+ return [
1602
+ `<rect x="${x}" y="${y}" width="${FRAME_SIZE}" height="${FRAME_SIZE}" fill="${color}"/>`,
1603
+ `<rect x="${x + 1}" y="${y + 1}" width="${FRAME_SIZE - 2}" height="${FRAME_SIZE - 2}" fill="none" stroke="#ffffff" stroke-opacity="0.35"/>`,
1604
+ `<circle cx="${x + 16}" cy="${y + 11}" r="5" fill="#ffffff" fill-opacity="0.92"/>`,
1605
+ `<rect x="${x + 12}" y="${y + 17}" width="8" height="7" rx="2" fill="#ffffff" fill-opacity="0.86"/>`,
1606
+ `<text x="${x + 16}" y="${y + 30}" text-anchor="middle" font-family="monospace" font-size="5" fill="#ffffff">${label}</text>`
1607
+ ].join("");
1608
+ }).join("");
1609
+ const svg = [
1610
+ `<svg xmlns="http://www.w3.org/2000/svg" width="${IMAGE_WIDTH}" height="${IMAGE_HEIGHT}" viewBox="0 0 ${IMAGE_WIDTH} ${IMAGE_HEIGHT}">`,
1611
+ `<rect width="${IMAGE_WIDTH}" height="${IMAGE_HEIGHT}" fill="#111827"/>`,
1612
+ cells,
1613
+ "</svg>"
1614
+ ].join("");
1615
+ return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`;
1616
+ }
1617
+ function createDirectionalAnimation(animationId, role, direction, frames, frameRate) {
1618
+ return {
1619
+ animationId,
1620
+ role,
1621
+ group: "jibble",
1622
+ direction,
1623
+ frameRate,
1624
+ frames,
1625
+ facingFrameMap: null
1626
+ };
1627
+ }
1628
+ var SAMPLE_TEXTURE_ATLAS = {
1629
+ imageUrl: createSvgDataUrl(),
1630
+ imageWidth: IMAGE_WIDTH,
1631
+ imageHeight: IMAGE_HEIGHT,
1632
+ frames: SAMPLE_FRAME_NAMES.map(createFrame),
1633
+ animations: [
1634
+ ...JIBBLE_DIRECTIONS.map(
1635
+ (direction) => createDirectionalAnimation(
1636
+ getJibbleAnimationId("idle", direction),
1637
+ "idle",
1638
+ direction,
1639
+ [`idle_${direction}`],
1640
+ 1
1641
+ )
1642
+ ),
1643
+ ...JIBBLE_DIRECTIONS.map(
1644
+ (direction) => createDirectionalAnimation(
1645
+ getJibbleAnimationId("walk", direction),
1646
+ "walk",
1647
+ direction,
1648
+ Array.from({ length: WALK_FRAME_COUNT }, (_, index) => `walk_${direction}_${index}`),
1649
+ 8
1650
+ )
1651
+ ),
1652
+ {
1653
+ animationId: JIBBLE_ANIMATION.Backflip,
1654
+ role: "action",
1655
+ group: "jibble",
1656
+ direction: null,
1657
+ frameRate: 10,
1658
+ frames: BACKFLIP_FRAME_NAMES,
1659
+ facingFrameMap: null
1660
+ }
1661
+ ]
1662
+ };
1663
+ function cloneTextureAtlas(atlas) {
1664
+ return {
1665
+ ...atlas,
1666
+ frames: atlas.frames.map((frame) => ({ ...frame })),
1667
+ animations: atlas.animations.map((animation) => ({
1668
+ ...animation,
1669
+ frames: [...animation.frames],
1670
+ facingFrameMap: animation.facingFrameMap ? { ...animation.facingFrameMap } : null
1671
+ }))
1672
+ };
1673
+ }
1674
+ function getSampleTextureAtlas() {
1675
+ return cloneTextureAtlas(SAMPLE_TEXTURE_ATLAS);
1676
+ }
1677
+ function getSamplePlayerCharacter() {
1678
+ return {
1679
+ characterName: "SDK Sample Jibble",
1680
+ baseCharacterId: "sdk-sample-jibble",
1681
+ compositionCode: "sdk-sample-jibble-atlas-v1",
1682
+ textureAtlas: getSampleTextureAtlas(),
1683
+ editorTextureAtlas: getSampleTextureAtlas()
1684
+ };
1685
+ }
1686
+
1687
+ // src/character.ts
1688
+ var DEFAULT_SAMPLE_CHARACTER_URL = "https://api.oasiz.ai/api/sdk/sample-character";
1689
+ var DEFAULT_SAMPLE_FETCH_TIMEOUT_MS = 1500;
1690
+ function isDevelopment2() {
1691
+ const nodeEnv = globalThis.process?.env?.NODE_ENV;
1692
+ return nodeEnv !== "production";
1693
+ }
1694
+ function getBridgeWindow2() {
1695
+ if (typeof window === "undefined") {
1696
+ return void 0;
1697
+ }
1698
+ return window;
1699
+ }
1700
+ function isLocalHostname(hostname) {
1701
+ return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "0.0.0.0" || hostname === "::1" || hostname.endsWith(".localhost");
1702
+ }
1703
+ function shouldUseLocalFallback(bridge, localFallback) {
1704
+ if (localFallback === true) {
1705
+ return true;
1706
+ }
1707
+ if (localFallback === false) {
1708
+ return false;
1709
+ }
1710
+ const location = bridge?.location;
1711
+ if (!location) {
1712
+ return false;
1713
+ }
1714
+ return location.protocol === "file:" || isLocalHostname(location.hostname);
1715
+ }
1716
+ function warnMissingBridge2(methodName, usingFallback) {
1717
+ if (isDevelopment2()) {
1718
+ console.warn(
1719
+ "[oasiz/sdk] " + methodName + " bridge is unavailable. " + (usingFallback ? "Using the SDK sample character atlas for local development." : "This is expected in local development.")
1720
+ );
1721
+ }
1722
+ }
1723
+ function isRecord2(value) {
1724
+ return typeof value === "object" && value !== null;
1725
+ }
1726
+ function isTextureAtlas(value) {
1727
+ if (!isRecord2(value)) {
1728
+ return false;
1729
+ }
1730
+ return typeof value.imageUrl === "string" && typeof value.imageWidth === "number" && Number.isFinite(value.imageWidth) && typeof value.imageHeight === "number" && Number.isFinite(value.imageHeight) && Array.isArray(value.frames) && Array.isArray(value.animations);
1731
+ }
1732
+ function isPlayerCharacter(value) {
1733
+ if (!isRecord2(value)) {
1734
+ return false;
1735
+ }
1736
+ return (typeof value.characterName === "string" || value.characterName === null) && typeof value.baseCharacterId === "string" && typeof value.compositionCode === "string" && isTextureAtlas(value.textureAtlas) && (value.editorTextureAtlas === null || isTextureAtlas(value.editorTextureAtlas));
1737
+ }
1738
+ function unwrapSampleCharacterResponse(payload) {
1739
+ if (isPlayerCharacter(payload)) {
1740
+ return payload;
1741
+ }
1742
+ if (isRecord2(payload) && isPlayerCharacter(payload.character)) {
1743
+ return payload.character;
1744
+ }
1745
+ return null;
1746
+ }
1747
+ async function fetchPlatformSampleCharacter(options) {
1748
+ if (typeof fetch !== "function") {
1749
+ return null;
1750
+ }
1751
+ const timeoutMs = options.sampleFetchTimeoutMs ?? DEFAULT_SAMPLE_FETCH_TIMEOUT_MS;
1752
+ const controller = typeof AbortController === "function" ? new AbortController() : null;
1753
+ const timeout = controller && timeoutMs > 0 ? setTimeout(() => controller.abort(), timeoutMs) : void 0;
1754
+ try {
1755
+ const response = await fetch(
1756
+ options.sampleCharacterUrl ?? DEFAULT_SAMPLE_CHARACTER_URL,
1757
+ {
1758
+ signal: controller?.signal
1759
+ }
1760
+ );
1761
+ if (!response.ok) {
1762
+ return null;
1763
+ }
1764
+ return unwrapSampleCharacterResponse(await response.json());
1765
+ } catch {
1766
+ return null;
1767
+ } finally {
1768
+ if (timeout) {
1769
+ clearTimeout(timeout);
1770
+ }
1771
+ }
1772
+ }
1773
+ async function getPlayerCharacter(options = {}) {
1774
+ const bridge = getBridgeWindow2();
1775
+ if (typeof bridge?.__oasizGetPlayerCharacter !== "function") {
1776
+ const useLocalFallback = shouldUseLocalFallback(
1777
+ bridge,
1778
+ options.localFallback ?? "auto"
1779
+ );
1780
+ warnMissingBridge2("getPlayerCharacter", useLocalFallback);
1781
+ if (!useLocalFallback) {
1782
+ return null;
1783
+ }
1784
+ const platformSample = await fetchPlatformSampleCharacter(options);
1785
+ if (platformSample) {
1786
+ return platformSample;
1787
+ }
1788
+ return options.generatedFallback === false ? null : getSamplePlayerCharacter();
1789
+ }
1790
+ try {
1791
+ const result = await bridge.__oasizGetPlayerCharacter();
1792
+ return result ?? null;
1793
+ } catch (error) {
1794
+ if (isDevelopment2()) {
1795
+ console.error("[oasiz/sdk] getPlayerCharacter failed:", error);
1796
+ }
1797
+ return null;
1798
+ }
1799
+ }
1800
+
1801
+ // src/haptics.ts
1802
+ function isDevelopment3() {
1803
+ const nodeEnv = globalThis.process?.env?.NODE_ENV;
1804
+ return nodeEnv !== "production";
1805
+ }
1806
+ function getBridgeWindow3() {
1807
+ if (typeof window === "undefined") {
1808
+ return void 0;
1809
+ }
1810
+ return window;
1811
+ }
1812
+ function triggerHaptic(type) {
1813
+ const bridge = getBridgeWindow3();
1814
+ if (typeof bridge?.triggerHaptic === "function") {
1815
+ bridge.triggerHaptic(type);
1816
+ return;
1817
+ }
1818
+ if (isDevelopment3()) {
1819
+ console.warn(
1820
+ "[oasiz/sdk] triggerHaptic bridge is unavailable. This is expected in local development."
1821
+ );
1822
+ }
1823
+ }
1824
+
1606
1825
  // src/log-overlay.ts
1607
1826
  var CONSOLE_METHODS = [
1608
1827
  "debug",
@@ -2830,7 +3049,7 @@ function warnMissingBridge7(methodName) {
2830
3049
  );
2831
3050
  }
2832
3051
  }
2833
- function isRecord2(value) {
3052
+ function isRecord3(value) {
2834
3053
  return typeof value === "object" && value !== null;
2835
3054
  }
2836
3055
  function toFiniteNumber(value) {
@@ -2999,11 +3218,11 @@ function callBridgeFunction(bridge, name) {
2999
3218
  }
3000
3219
  }
3001
3220
  function readInsetObjectValue(value, side, group) {
3002
- if (!isRecord2(value)) {
3221
+ if (!isRecord3(value)) {
3003
3222
  return void 0;
3004
3223
  }
3005
3224
  if (group) {
3006
- return isRecord2(value[group]) ? value[group][side] : void 0;
3225
+ return isRecord3(value[group]) ? value[group][side] : void 0;
3007
3226
  }
3008
3227
  return value[side];
3009
3228
  }
@@ -3140,7 +3359,7 @@ function getBridgeWindow10() {
3140
3359
  }
3141
3360
  return window;
3142
3361
  }
3143
- function isRecord3(value) {
3362
+ function isRecord4(value) {
3144
3363
  return typeof value === "object" && value !== null;
3145
3364
  }
3146
3365
  function toFiniteNumber2(value) {
@@ -3206,7 +3425,7 @@ function normalizeMetric(value) {
3206
3425
  }
3207
3426
  return void 0;
3208
3427
  }
3209
- if (!isRecord3(value)) {
3428
+ if (!isRecord4(value)) {
3210
3429
  return void 0;
3211
3430
  }
3212
3431
  const fpsCandidate = firstDefined2(
@@ -3456,6 +3675,8 @@ var oasiz = {
3456
3675
  addScore,
3457
3676
  setScore,
3458
3677
  getPlayerCharacter,
3678
+ getSamplePlayerCharacter,
3679
+ getSampleTextureAtlas,
3459
3680
  share,
3460
3681
  triggerHaptic,
3461
3682
  enableLogOverlay,
@@ -3518,6 +3739,8 @@ var oasiz = {
3518
3739
  getPlayerName,
3519
3740
  getRoomCode,
3520
3741
  getSafeAreaTop,
3742
+ getSamplePlayerCharacter,
3743
+ getSampleTextureAtlas,
3521
3744
  getViewportInsets,
3522
3745
  leaveGame,
3523
3746
  loadGameState,
package/dist/index.d.cts CHANGED
@@ -220,13 +220,35 @@ interface ScoreEditResult {
220
220
  normalizedScore: number | null;
221
221
  }
222
222
 
223
+ interface GetPlayerCharacterOptions {
224
+ /**
225
+ * Controls the SDK sample character returned when the Oasiz app bridge is
226
+ * missing. `"auto"` returns the sample on localhost/file URLs only.
227
+ */
228
+ localFallback?: boolean | "auto";
229
+ /**
230
+ * Public endpoint used for the real platform-generated local sample atlas.
231
+ */
232
+ sampleCharacterUrl?: string;
233
+ /**
234
+ * Timeout for the public sample endpoint before falling back locally.
235
+ */
236
+ sampleFetchTimeoutMs?: number;
237
+ /**
238
+ * When true, a tiny generated atlas is used if the platform sample endpoint
239
+ * is unavailable. Set false for strict platform-sample-only local testing.
240
+ */
241
+ generatedFallback?: boolean;
242
+ }
223
243
  /**
224
244
  * Fetch the authenticated player's character, including a TexturePacker /
225
245
  * Phaser-style texture atlas describing the baked sprite image.
226
246
  *
227
247
  * Returns:
228
248
  * - `null` when the user has no character composition yet, OR
229
- * - `null` when the host bridge is unavailable (local dev / unauthenticated)
249
+ * - a sample character atlas when the host bridge is unavailable on a local
250
+ * browser URL (`localhost` / `file://`), OR
251
+ * - `null` when the host bridge is unavailable and local fallback is disabled
230
252
  *
231
253
  * The host transparently caches and proxies to `GET /api/sdk/me/character`,
232
254
  * so calling this multiple times in a session is cheap. The returned
@@ -245,7 +267,7 @@ interface ScoreEditResult {
245
267
  * ),
246
268
  * });
247
269
  */
248
- declare function getPlayerCharacter(): Promise<PlayerCharacter | null>;
270
+ declare function getPlayerCharacter(options?: GetPlayerCharacterOptions): Promise<PlayerCharacter | null>;
249
271
 
250
272
  declare function triggerHaptic(type: HapticType): void;
251
273
 
@@ -381,6 +403,9 @@ declare function loadGameState(): GameState;
381
403
  declare function saveGameState(state: GameState): void;
382
404
  declare function flushGameState(): void;
383
405
 
406
+ declare function getSampleTextureAtlas(): TextureAtlas;
407
+ declare function getSamplePlayerCharacter(): PlayerCharacter;
408
+
384
409
  declare const oasiz: {
385
410
  submitScore: typeof submitScore;
386
411
  enableAppSimulator: typeof enableAppSimulator;
@@ -413,6 +438,8 @@ declare const oasiz: {
413
438
  addScore: typeof addScore;
414
439
  setScore: typeof setScore;
415
440
  getPlayerCharacter: typeof getPlayerCharacter;
441
+ getSamplePlayerCharacter: typeof getSamplePlayerCharacter;
442
+ getSampleTextureAtlas: typeof getSampleTextureAtlas;
416
443
  share: typeof share;
417
444
  triggerHaptic: typeof triggerHaptic;
418
445
  enableLogOverlay: typeof enableLogOverlay;
@@ -441,4 +468,4 @@ declare const oasiz: {
441
468
  readonly graphicsPerformance: GraphicsPerformanceMetric;
442
469
  };
443
470
 
444
- export { type AppSimulatorDevice, type AppSimulatorDeviceName, type AppSimulatorHandle, type AppSimulatorOptions, type AppSimulatorOrientation, type BackButtonTestingHandle, type BackButtonTestingOptions, type FacingFrameMap, type GameState, type GraphicsPerformanceMetric, type GraphicsPerformanceTier, type HapticType, JIBBLE_ANIMATION, JIBBLE_ANIMATION_IDS, JIBBLE_DIRECTIONS, type JibbleAnimationAction, type JibbleAnimationId, type JibbleDirectionCode, type JibbleFacingDirection, type LogOverlayEntry, type LogOverlayHandle, type LogOverlayLevel, type LogOverlayOptions, type PlayerCharacter, type ScoreEditResult, type ShareRequest, type ShareRoomCodeOptions, type TextureAtlas, type TextureAtlasAnimation, type TextureAtlasFrame, type Unsubscribe, type ViewportInsetEdges, type ViewportInsetSide, type ViewportInsets, addScore, enableAppSimulator, enableBackButtonTesting, enableLogOverlay, flushGameState, getGameId, getGraphicsPerformance, getJibbleAnimationId, getPlayerAvatar, getPlayerCharacter, getPlayerId, getPlayerName, getRoomCode, getSafeAreaTop, getViewportInsets, leaveGame, loadGameState, normalizeJibbleDirection, oasiz, onBackButton, onLeaveGame, onPause, onResume, openInviteModal, saveGameState, setLeaderboardVisible, setScore, share, shareRoomCode, submitScore, triggerHaptic };
471
+ export { type AppSimulatorDevice, type AppSimulatorDeviceName, type AppSimulatorHandle, type AppSimulatorOptions, type AppSimulatorOrientation, type BackButtonTestingHandle, type BackButtonTestingOptions, type FacingFrameMap, type GameState, type GetPlayerCharacterOptions, type GraphicsPerformanceMetric, type GraphicsPerformanceTier, type HapticType, JIBBLE_ANIMATION, JIBBLE_ANIMATION_IDS, JIBBLE_DIRECTIONS, type JibbleAnimationAction, type JibbleAnimationId, type JibbleDirectionCode, type JibbleFacingDirection, type LogOverlayEntry, type LogOverlayHandle, type LogOverlayLevel, type LogOverlayOptions, type PlayerCharacter, type ScoreEditResult, type ShareRequest, type ShareRoomCodeOptions, type TextureAtlas, type TextureAtlasAnimation, type TextureAtlasFrame, type Unsubscribe, type ViewportInsetEdges, type ViewportInsetSide, type ViewportInsets, addScore, enableAppSimulator, enableBackButtonTesting, enableLogOverlay, flushGameState, getGameId, getGraphicsPerformance, getJibbleAnimationId, getPlayerAvatar, getPlayerCharacter, getPlayerId, getPlayerName, getRoomCode, getSafeAreaTop, getSamplePlayerCharacter, getSampleTextureAtlas, getViewportInsets, leaveGame, loadGameState, normalizeJibbleDirection, oasiz, onBackButton, onLeaveGame, onPause, onResume, openInviteModal, saveGameState, setLeaderboardVisible, setScore, share, shareRoomCode, submitScore, triggerHaptic };
package/dist/index.d.ts CHANGED
@@ -220,13 +220,35 @@ interface ScoreEditResult {
220
220
  normalizedScore: number | null;
221
221
  }
222
222
 
223
+ interface GetPlayerCharacterOptions {
224
+ /**
225
+ * Controls the SDK sample character returned when the Oasiz app bridge is
226
+ * missing. `"auto"` returns the sample on localhost/file URLs only.
227
+ */
228
+ localFallback?: boolean | "auto";
229
+ /**
230
+ * Public endpoint used for the real platform-generated local sample atlas.
231
+ */
232
+ sampleCharacterUrl?: string;
233
+ /**
234
+ * Timeout for the public sample endpoint before falling back locally.
235
+ */
236
+ sampleFetchTimeoutMs?: number;
237
+ /**
238
+ * When true, a tiny generated atlas is used if the platform sample endpoint
239
+ * is unavailable. Set false for strict platform-sample-only local testing.
240
+ */
241
+ generatedFallback?: boolean;
242
+ }
223
243
  /**
224
244
  * Fetch the authenticated player's character, including a TexturePacker /
225
245
  * Phaser-style texture atlas describing the baked sprite image.
226
246
  *
227
247
  * Returns:
228
248
  * - `null` when the user has no character composition yet, OR
229
- * - `null` when the host bridge is unavailable (local dev / unauthenticated)
249
+ * - a sample character atlas when the host bridge is unavailable on a local
250
+ * browser URL (`localhost` / `file://`), OR
251
+ * - `null` when the host bridge is unavailable and local fallback is disabled
230
252
  *
231
253
  * The host transparently caches and proxies to `GET /api/sdk/me/character`,
232
254
  * so calling this multiple times in a session is cheap. The returned
@@ -245,7 +267,7 @@ interface ScoreEditResult {
245
267
  * ),
246
268
  * });
247
269
  */
248
- declare function getPlayerCharacter(): Promise<PlayerCharacter | null>;
270
+ declare function getPlayerCharacter(options?: GetPlayerCharacterOptions): Promise<PlayerCharacter | null>;
249
271
 
250
272
  declare function triggerHaptic(type: HapticType): void;
251
273
 
@@ -381,6 +403,9 @@ declare function loadGameState(): GameState;
381
403
  declare function saveGameState(state: GameState): void;
382
404
  declare function flushGameState(): void;
383
405
 
406
+ declare function getSampleTextureAtlas(): TextureAtlas;
407
+ declare function getSamplePlayerCharacter(): PlayerCharacter;
408
+
384
409
  declare const oasiz: {
385
410
  submitScore: typeof submitScore;
386
411
  enableAppSimulator: typeof enableAppSimulator;
@@ -413,6 +438,8 @@ declare const oasiz: {
413
438
  addScore: typeof addScore;
414
439
  setScore: typeof setScore;
415
440
  getPlayerCharacter: typeof getPlayerCharacter;
441
+ getSamplePlayerCharacter: typeof getSamplePlayerCharacter;
442
+ getSampleTextureAtlas: typeof getSampleTextureAtlas;
416
443
  share: typeof share;
417
444
  triggerHaptic: typeof triggerHaptic;
418
445
  enableLogOverlay: typeof enableLogOverlay;
@@ -441,4 +468,4 @@ declare const oasiz: {
441
468
  readonly graphicsPerformance: GraphicsPerformanceMetric;
442
469
  };
443
470
 
444
- export { type AppSimulatorDevice, type AppSimulatorDeviceName, type AppSimulatorHandle, type AppSimulatorOptions, type AppSimulatorOrientation, type BackButtonTestingHandle, type BackButtonTestingOptions, type FacingFrameMap, type GameState, type GraphicsPerformanceMetric, type GraphicsPerformanceTier, type HapticType, JIBBLE_ANIMATION, JIBBLE_ANIMATION_IDS, JIBBLE_DIRECTIONS, type JibbleAnimationAction, type JibbleAnimationId, type JibbleDirectionCode, type JibbleFacingDirection, type LogOverlayEntry, type LogOverlayHandle, type LogOverlayLevel, type LogOverlayOptions, type PlayerCharacter, type ScoreEditResult, type ShareRequest, type ShareRoomCodeOptions, type TextureAtlas, type TextureAtlasAnimation, type TextureAtlasFrame, type Unsubscribe, type ViewportInsetEdges, type ViewportInsetSide, type ViewportInsets, addScore, enableAppSimulator, enableBackButtonTesting, enableLogOverlay, flushGameState, getGameId, getGraphicsPerformance, getJibbleAnimationId, getPlayerAvatar, getPlayerCharacter, getPlayerId, getPlayerName, getRoomCode, getSafeAreaTop, getViewportInsets, leaveGame, loadGameState, normalizeJibbleDirection, oasiz, onBackButton, onLeaveGame, onPause, onResume, openInviteModal, saveGameState, setLeaderboardVisible, setScore, share, shareRoomCode, submitScore, triggerHaptic };
471
+ export { type AppSimulatorDevice, type AppSimulatorDeviceName, type AppSimulatorHandle, type AppSimulatorOptions, type AppSimulatorOrientation, type BackButtonTestingHandle, type BackButtonTestingOptions, type FacingFrameMap, type GameState, type GetPlayerCharacterOptions, type GraphicsPerformanceMetric, type GraphicsPerformanceTier, type HapticType, JIBBLE_ANIMATION, JIBBLE_ANIMATION_IDS, JIBBLE_DIRECTIONS, type JibbleAnimationAction, type JibbleAnimationId, type JibbleDirectionCode, type JibbleFacingDirection, type LogOverlayEntry, type LogOverlayHandle, type LogOverlayLevel, type LogOverlayOptions, type PlayerCharacter, type ScoreEditResult, type ShareRequest, type ShareRoomCodeOptions, type TextureAtlas, type TextureAtlasAnimation, type TextureAtlasFrame, type Unsubscribe, type ViewportInsetEdges, type ViewportInsetSide, type ViewportInsets, addScore, enableAppSimulator, enableBackButtonTesting, enableLogOverlay, flushGameState, getGameId, getGraphicsPerformance, getJibbleAnimationId, getPlayerAvatar, getPlayerCharacter, getPlayerId, getPlayerName, getRoomCode, getSafeAreaTop, getSamplePlayerCharacter, getSampleTextureAtlas, getViewportInsets, leaveGame, loadGameState, normalizeJibbleDirection, oasiz, onBackButton, onLeaveGame, onPause, onResume, openInviteModal, saveGameState, setLeaderboardVisible, setScore, share, shareRoomCode, submitScore, triggerHaptic };
package/dist/index.js CHANGED
@@ -1385,65 +1385,6 @@ function enableAppSimulator(options = {}) {
1385
1385
  return handle;
1386
1386
  }
1387
1387
 
1388
- // src/character.ts
1389
- function isDevelopment2() {
1390
- const nodeEnv = globalThis.process?.env?.NODE_ENV;
1391
- return nodeEnv !== "production";
1392
- }
1393
- function getBridgeWindow2() {
1394
- if (typeof window === "undefined") {
1395
- return void 0;
1396
- }
1397
- return window;
1398
- }
1399
- function warnMissingBridge2(methodName) {
1400
- if (isDevelopment2()) {
1401
- console.warn(
1402
- "[oasiz/sdk] " + methodName + " bridge is unavailable. This is expected in local development."
1403
- );
1404
- }
1405
- }
1406
- async function getPlayerCharacter() {
1407
- const bridge = getBridgeWindow2();
1408
- if (typeof bridge?.__oasizGetPlayerCharacter !== "function") {
1409
- warnMissingBridge2("getPlayerCharacter");
1410
- return null;
1411
- }
1412
- try {
1413
- const result = await bridge.__oasizGetPlayerCharacter();
1414
- return result ?? null;
1415
- } catch (error) {
1416
- if (isDevelopment2()) {
1417
- console.error("[oasiz/sdk] getPlayerCharacter failed:", error);
1418
- }
1419
- return null;
1420
- }
1421
- }
1422
-
1423
- // src/haptics.ts
1424
- function isDevelopment3() {
1425
- const nodeEnv = globalThis.process?.env?.NODE_ENV;
1426
- return nodeEnv !== "production";
1427
- }
1428
- function getBridgeWindow3() {
1429
- if (typeof window === "undefined") {
1430
- return void 0;
1431
- }
1432
- return window;
1433
- }
1434
- function triggerHaptic(type) {
1435
- const bridge = getBridgeWindow3();
1436
- if (typeof bridge?.triggerHaptic === "function") {
1437
- bridge.triggerHaptic(type);
1438
- return;
1439
- }
1440
- if (isDevelopment3()) {
1441
- console.warn(
1442
- "[oasiz/sdk] triggerHaptic bridge is unavailable. This is expected in local development."
1443
- );
1444
- }
1445
- }
1446
-
1447
1388
  // src/jibble.ts
1448
1389
  var JIBBLE_DIRECTIONS = [
1449
1390
  "n",
@@ -1544,6 +1485,282 @@ function getJibbleAnimationId(action, direction = "front") {
1544
1485
  return `${action}_${normalizeJibbleDirection(direction)}`;
1545
1486
  }
1546
1487
 
1488
+ // src/sample-character.ts
1489
+ var FRAME_SIZE = 32;
1490
+ var COLUMNS = 8;
1491
+ var WALK_FRAME_COUNT = 2;
1492
+ var BACKFLIP_FRAME_COUNT = 4;
1493
+ var COLORS = [
1494
+ "#2563eb",
1495
+ "#7c3aed",
1496
+ "#db2777",
1497
+ "#ea580c",
1498
+ "#16a34a",
1499
+ "#0891b2",
1500
+ "#4f46e5",
1501
+ "#be123c"
1502
+ ];
1503
+ var IDLE_FRAME_NAMES = JIBBLE_DIRECTIONS.map((direction) => `idle_${direction}`);
1504
+ var WALK_FRAME_NAMES = JIBBLE_DIRECTIONS.flatMap(
1505
+ (direction) => Array.from({ length: WALK_FRAME_COUNT }, (_, index) => `walk_${direction}_${index}`)
1506
+ );
1507
+ var BACKFLIP_FRAME_NAMES = Array.from(
1508
+ { length: BACKFLIP_FRAME_COUNT },
1509
+ (_, index) => `backflip_${index}`
1510
+ );
1511
+ var SAMPLE_FRAME_NAMES = [
1512
+ ...IDLE_FRAME_NAMES,
1513
+ ...WALK_FRAME_NAMES,
1514
+ ...BACKFLIP_FRAME_NAMES
1515
+ ];
1516
+ var IMAGE_WIDTH = COLUMNS * FRAME_SIZE;
1517
+ var IMAGE_HEIGHT = Math.ceil(SAMPLE_FRAME_NAMES.length / COLUMNS) * FRAME_SIZE;
1518
+ function getFrameRect(index) {
1519
+ return {
1520
+ x: index % COLUMNS * FRAME_SIZE,
1521
+ y: Math.floor(index / COLUMNS) * FRAME_SIZE,
1522
+ width: FRAME_SIZE,
1523
+ height: FRAME_SIZE
1524
+ };
1525
+ }
1526
+ function createFrame(name, index) {
1527
+ return {
1528
+ name,
1529
+ ...getFrameRect(index)
1530
+ };
1531
+ }
1532
+ function getFrameLabel(name) {
1533
+ return name.replace(/^idle_/, "i ").replace(/^walk_/, "w ").replace(/^backflip_/, "flip ");
1534
+ }
1535
+ function createSvgDataUrl() {
1536
+ const cells = SAMPLE_FRAME_NAMES.map((name, index) => {
1537
+ const { x, y } = getFrameRect(index);
1538
+ const color = COLORS[index % COLORS.length];
1539
+ const label = getFrameLabel(name);
1540
+ return [
1541
+ `<rect x="${x}" y="${y}" width="${FRAME_SIZE}" height="${FRAME_SIZE}" fill="${color}"/>`,
1542
+ `<rect x="${x + 1}" y="${y + 1}" width="${FRAME_SIZE - 2}" height="${FRAME_SIZE - 2}" fill="none" stroke="#ffffff" stroke-opacity="0.35"/>`,
1543
+ `<circle cx="${x + 16}" cy="${y + 11}" r="5" fill="#ffffff" fill-opacity="0.92"/>`,
1544
+ `<rect x="${x + 12}" y="${y + 17}" width="8" height="7" rx="2" fill="#ffffff" fill-opacity="0.86"/>`,
1545
+ `<text x="${x + 16}" y="${y + 30}" text-anchor="middle" font-family="monospace" font-size="5" fill="#ffffff">${label}</text>`
1546
+ ].join("");
1547
+ }).join("");
1548
+ const svg = [
1549
+ `<svg xmlns="http://www.w3.org/2000/svg" width="${IMAGE_WIDTH}" height="${IMAGE_HEIGHT}" viewBox="0 0 ${IMAGE_WIDTH} ${IMAGE_HEIGHT}">`,
1550
+ `<rect width="${IMAGE_WIDTH}" height="${IMAGE_HEIGHT}" fill="#111827"/>`,
1551
+ cells,
1552
+ "</svg>"
1553
+ ].join("");
1554
+ return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`;
1555
+ }
1556
+ function createDirectionalAnimation(animationId, role, direction, frames, frameRate) {
1557
+ return {
1558
+ animationId,
1559
+ role,
1560
+ group: "jibble",
1561
+ direction,
1562
+ frameRate,
1563
+ frames,
1564
+ facingFrameMap: null
1565
+ };
1566
+ }
1567
+ var SAMPLE_TEXTURE_ATLAS = {
1568
+ imageUrl: createSvgDataUrl(),
1569
+ imageWidth: IMAGE_WIDTH,
1570
+ imageHeight: IMAGE_HEIGHT,
1571
+ frames: SAMPLE_FRAME_NAMES.map(createFrame),
1572
+ animations: [
1573
+ ...JIBBLE_DIRECTIONS.map(
1574
+ (direction) => createDirectionalAnimation(
1575
+ getJibbleAnimationId("idle", direction),
1576
+ "idle",
1577
+ direction,
1578
+ [`idle_${direction}`],
1579
+ 1
1580
+ )
1581
+ ),
1582
+ ...JIBBLE_DIRECTIONS.map(
1583
+ (direction) => createDirectionalAnimation(
1584
+ getJibbleAnimationId("walk", direction),
1585
+ "walk",
1586
+ direction,
1587
+ Array.from({ length: WALK_FRAME_COUNT }, (_, index) => `walk_${direction}_${index}`),
1588
+ 8
1589
+ )
1590
+ ),
1591
+ {
1592
+ animationId: JIBBLE_ANIMATION.Backflip,
1593
+ role: "action",
1594
+ group: "jibble",
1595
+ direction: null,
1596
+ frameRate: 10,
1597
+ frames: BACKFLIP_FRAME_NAMES,
1598
+ facingFrameMap: null
1599
+ }
1600
+ ]
1601
+ };
1602
+ function cloneTextureAtlas(atlas) {
1603
+ return {
1604
+ ...atlas,
1605
+ frames: atlas.frames.map((frame) => ({ ...frame })),
1606
+ animations: atlas.animations.map((animation) => ({
1607
+ ...animation,
1608
+ frames: [...animation.frames],
1609
+ facingFrameMap: animation.facingFrameMap ? { ...animation.facingFrameMap } : null
1610
+ }))
1611
+ };
1612
+ }
1613
+ function getSampleTextureAtlas() {
1614
+ return cloneTextureAtlas(SAMPLE_TEXTURE_ATLAS);
1615
+ }
1616
+ function getSamplePlayerCharacter() {
1617
+ return {
1618
+ characterName: "SDK Sample Jibble",
1619
+ baseCharacterId: "sdk-sample-jibble",
1620
+ compositionCode: "sdk-sample-jibble-atlas-v1",
1621
+ textureAtlas: getSampleTextureAtlas(),
1622
+ editorTextureAtlas: getSampleTextureAtlas()
1623
+ };
1624
+ }
1625
+
1626
+ // src/character.ts
1627
+ var DEFAULT_SAMPLE_CHARACTER_URL = "https://api.oasiz.ai/api/sdk/sample-character";
1628
+ var DEFAULT_SAMPLE_FETCH_TIMEOUT_MS = 1500;
1629
+ function isDevelopment2() {
1630
+ const nodeEnv = globalThis.process?.env?.NODE_ENV;
1631
+ return nodeEnv !== "production";
1632
+ }
1633
+ function getBridgeWindow2() {
1634
+ if (typeof window === "undefined") {
1635
+ return void 0;
1636
+ }
1637
+ return window;
1638
+ }
1639
+ function isLocalHostname(hostname) {
1640
+ return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "0.0.0.0" || hostname === "::1" || hostname.endsWith(".localhost");
1641
+ }
1642
+ function shouldUseLocalFallback(bridge, localFallback) {
1643
+ if (localFallback === true) {
1644
+ return true;
1645
+ }
1646
+ if (localFallback === false) {
1647
+ return false;
1648
+ }
1649
+ const location = bridge?.location;
1650
+ if (!location) {
1651
+ return false;
1652
+ }
1653
+ return location.protocol === "file:" || isLocalHostname(location.hostname);
1654
+ }
1655
+ function warnMissingBridge2(methodName, usingFallback) {
1656
+ if (isDevelopment2()) {
1657
+ console.warn(
1658
+ "[oasiz/sdk] " + methodName + " bridge is unavailable. " + (usingFallback ? "Using the SDK sample character atlas for local development." : "This is expected in local development.")
1659
+ );
1660
+ }
1661
+ }
1662
+ function isRecord2(value) {
1663
+ return typeof value === "object" && value !== null;
1664
+ }
1665
+ function isTextureAtlas(value) {
1666
+ if (!isRecord2(value)) {
1667
+ return false;
1668
+ }
1669
+ return typeof value.imageUrl === "string" && typeof value.imageWidth === "number" && Number.isFinite(value.imageWidth) && typeof value.imageHeight === "number" && Number.isFinite(value.imageHeight) && Array.isArray(value.frames) && Array.isArray(value.animations);
1670
+ }
1671
+ function isPlayerCharacter(value) {
1672
+ if (!isRecord2(value)) {
1673
+ return false;
1674
+ }
1675
+ return (typeof value.characterName === "string" || value.characterName === null) && typeof value.baseCharacterId === "string" && typeof value.compositionCode === "string" && isTextureAtlas(value.textureAtlas) && (value.editorTextureAtlas === null || isTextureAtlas(value.editorTextureAtlas));
1676
+ }
1677
+ function unwrapSampleCharacterResponse(payload) {
1678
+ if (isPlayerCharacter(payload)) {
1679
+ return payload;
1680
+ }
1681
+ if (isRecord2(payload) && isPlayerCharacter(payload.character)) {
1682
+ return payload.character;
1683
+ }
1684
+ return null;
1685
+ }
1686
+ async function fetchPlatformSampleCharacter(options) {
1687
+ if (typeof fetch !== "function") {
1688
+ return null;
1689
+ }
1690
+ const timeoutMs = options.sampleFetchTimeoutMs ?? DEFAULT_SAMPLE_FETCH_TIMEOUT_MS;
1691
+ const controller = typeof AbortController === "function" ? new AbortController() : null;
1692
+ const timeout = controller && timeoutMs > 0 ? setTimeout(() => controller.abort(), timeoutMs) : void 0;
1693
+ try {
1694
+ const response = await fetch(
1695
+ options.sampleCharacterUrl ?? DEFAULT_SAMPLE_CHARACTER_URL,
1696
+ {
1697
+ signal: controller?.signal
1698
+ }
1699
+ );
1700
+ if (!response.ok) {
1701
+ return null;
1702
+ }
1703
+ return unwrapSampleCharacterResponse(await response.json());
1704
+ } catch {
1705
+ return null;
1706
+ } finally {
1707
+ if (timeout) {
1708
+ clearTimeout(timeout);
1709
+ }
1710
+ }
1711
+ }
1712
+ async function getPlayerCharacter(options = {}) {
1713
+ const bridge = getBridgeWindow2();
1714
+ if (typeof bridge?.__oasizGetPlayerCharacter !== "function") {
1715
+ const useLocalFallback = shouldUseLocalFallback(
1716
+ bridge,
1717
+ options.localFallback ?? "auto"
1718
+ );
1719
+ warnMissingBridge2("getPlayerCharacter", useLocalFallback);
1720
+ if (!useLocalFallback) {
1721
+ return null;
1722
+ }
1723
+ const platformSample = await fetchPlatformSampleCharacter(options);
1724
+ if (platformSample) {
1725
+ return platformSample;
1726
+ }
1727
+ return options.generatedFallback === false ? null : getSamplePlayerCharacter();
1728
+ }
1729
+ try {
1730
+ const result = await bridge.__oasizGetPlayerCharacter();
1731
+ return result ?? null;
1732
+ } catch (error) {
1733
+ if (isDevelopment2()) {
1734
+ console.error("[oasiz/sdk] getPlayerCharacter failed:", error);
1735
+ }
1736
+ return null;
1737
+ }
1738
+ }
1739
+
1740
+ // src/haptics.ts
1741
+ function isDevelopment3() {
1742
+ const nodeEnv = globalThis.process?.env?.NODE_ENV;
1743
+ return nodeEnv !== "production";
1744
+ }
1745
+ function getBridgeWindow3() {
1746
+ if (typeof window === "undefined") {
1747
+ return void 0;
1748
+ }
1749
+ return window;
1750
+ }
1751
+ function triggerHaptic(type) {
1752
+ const bridge = getBridgeWindow3();
1753
+ if (typeof bridge?.triggerHaptic === "function") {
1754
+ bridge.triggerHaptic(type);
1755
+ return;
1756
+ }
1757
+ if (isDevelopment3()) {
1758
+ console.warn(
1759
+ "[oasiz/sdk] triggerHaptic bridge is unavailable. This is expected in local development."
1760
+ );
1761
+ }
1762
+ }
1763
+
1547
1764
  // src/log-overlay.ts
1548
1765
  var CONSOLE_METHODS = [
1549
1766
  "debug",
@@ -2771,7 +2988,7 @@ function warnMissingBridge7(methodName) {
2771
2988
  );
2772
2989
  }
2773
2990
  }
2774
- function isRecord2(value) {
2991
+ function isRecord3(value) {
2775
2992
  return typeof value === "object" && value !== null;
2776
2993
  }
2777
2994
  function toFiniteNumber(value) {
@@ -2940,11 +3157,11 @@ function callBridgeFunction(bridge, name) {
2940
3157
  }
2941
3158
  }
2942
3159
  function readInsetObjectValue(value, side, group) {
2943
- if (!isRecord2(value)) {
3160
+ if (!isRecord3(value)) {
2944
3161
  return void 0;
2945
3162
  }
2946
3163
  if (group) {
2947
- return isRecord2(value[group]) ? value[group][side] : void 0;
3164
+ return isRecord3(value[group]) ? value[group][side] : void 0;
2948
3165
  }
2949
3166
  return value[side];
2950
3167
  }
@@ -3081,7 +3298,7 @@ function getBridgeWindow10() {
3081
3298
  }
3082
3299
  return window;
3083
3300
  }
3084
- function isRecord3(value) {
3301
+ function isRecord4(value) {
3085
3302
  return typeof value === "object" && value !== null;
3086
3303
  }
3087
3304
  function toFiniteNumber2(value) {
@@ -3147,7 +3364,7 @@ function normalizeMetric(value) {
3147
3364
  }
3148
3365
  return void 0;
3149
3366
  }
3150
- if (!isRecord3(value)) {
3367
+ if (!isRecord4(value)) {
3151
3368
  return void 0;
3152
3369
  }
3153
3370
  const fpsCandidate = firstDefined2(
@@ -3397,6 +3614,8 @@ var oasiz = {
3397
3614
  addScore,
3398
3615
  setScore,
3399
3616
  getPlayerCharacter,
3617
+ getSamplePlayerCharacter,
3618
+ getSampleTextureAtlas,
3400
3619
  share,
3401
3620
  triggerHaptic,
3402
3621
  enableLogOverlay,
@@ -3458,6 +3677,8 @@ export {
3458
3677
  getPlayerName,
3459
3678
  getRoomCode,
3460
3679
  getSafeAreaTop,
3680
+ getSamplePlayerCharacter,
3681
+ getSampleTextureAtlas,
3461
3682
  getViewportInsets,
3462
3683
  leaveGame,
3463
3684
  loadGameState,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oasiz/sdk",
3
- "version": "1.8.4",
3
+ "version": "1.8.6",
4
4
  "description": "Typed SDK for Oasiz game platform bridge APIs.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",