@oasiz/sdk 1.8.4 → 1.8.5

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,38 @@ 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 returns a bundled sample Jibble atlas instead, so browser games can
175
+ test sprite loading, atlas slicing, and animation lookup before publishing.
176
+
177
+ The sample atlas includes every catalog ID above, and its `imageUrl` is an
178
+ inline `data:image/svg+xml` URL. It does not make a network request and it is
179
+ only used when the app bridge is missing.
180
+
181
+ ```ts
182
+ const character = await oasiz.getPlayerCharacter();
183
+
184
+ // In Oasiz app: the real signed-in player's character.
185
+ // On localhost without the app bridge: "SDK Sample Jibble".
186
+ // On non-local pages without the app bridge: null.
187
+ ```
188
+
189
+ Use the options when you need explicit behavior:
190
+
191
+ ```ts
192
+ // Keep the old "missing bridge means null" behavior.
193
+ const characterOrNull = await oasiz.getPlayerCharacter({ localFallback: false });
194
+
195
+ // Force the sample atlas in a browser test harness.
196
+ const sampleCharacter = await oasiz.getPlayerCharacter({ localFallback: true });
197
+
198
+ // Or fetch the sample directly without checking the bridge.
199
+ const directSample = oasiz.getSamplePlayerCharacter();
200
+ ```
201
+
170
202
  #### HTML5 / TypeScript
171
203
 
172
204
  ```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,223 @@ 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
+ function isDevelopment2() {
1689
+ const nodeEnv = globalThis.process?.env?.NODE_ENV;
1690
+ return nodeEnv !== "production";
1691
+ }
1692
+ function getBridgeWindow2() {
1693
+ if (typeof window === "undefined") {
1694
+ return void 0;
1695
+ }
1696
+ return window;
1697
+ }
1698
+ function isLocalHostname(hostname) {
1699
+ return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "0.0.0.0" || hostname === "::1" || hostname.endsWith(".localhost");
1700
+ }
1701
+ function shouldUseLocalFallback(bridge, localFallback) {
1702
+ if (localFallback === true) {
1703
+ return true;
1704
+ }
1705
+ if (localFallback === false) {
1706
+ return false;
1707
+ }
1708
+ const location = bridge?.location;
1709
+ if (!location) {
1710
+ return false;
1711
+ }
1712
+ return location.protocol === "file:" || isLocalHostname(location.hostname);
1713
+ }
1714
+ function warnMissingBridge2(methodName, usingFallback) {
1715
+ if (isDevelopment2()) {
1716
+ console.warn(
1717
+ "[oasiz/sdk] " + methodName + " bridge is unavailable. " + (usingFallback ? "Using the SDK sample character atlas for local development." : "This is expected in local development.")
1718
+ );
1719
+ }
1720
+ }
1721
+ async function getPlayerCharacter(options = {}) {
1722
+ const bridge = getBridgeWindow2();
1723
+ if (typeof bridge?.__oasizGetPlayerCharacter !== "function") {
1724
+ const useLocalFallback = shouldUseLocalFallback(
1725
+ bridge,
1726
+ options.localFallback ?? "auto"
1727
+ );
1728
+ warnMissingBridge2("getPlayerCharacter", useLocalFallback);
1729
+ return useLocalFallback ? getSamplePlayerCharacter() : null;
1730
+ }
1731
+ try {
1732
+ const result = await bridge.__oasizGetPlayerCharacter();
1733
+ return result ?? null;
1734
+ } catch (error) {
1735
+ if (isDevelopment2()) {
1736
+ console.error("[oasiz/sdk] getPlayerCharacter failed:", error);
1737
+ }
1738
+ return null;
1739
+ }
1740
+ }
1741
+
1742
+ // src/haptics.ts
1743
+ function isDevelopment3() {
1744
+ const nodeEnv = globalThis.process?.env?.NODE_ENV;
1745
+ return nodeEnv !== "production";
1746
+ }
1747
+ function getBridgeWindow3() {
1748
+ if (typeof window === "undefined") {
1749
+ return void 0;
1750
+ }
1751
+ return window;
1752
+ }
1753
+ function triggerHaptic(type) {
1754
+ const bridge = getBridgeWindow3();
1755
+ if (typeof bridge?.triggerHaptic === "function") {
1756
+ bridge.triggerHaptic(type);
1757
+ return;
1758
+ }
1759
+ if (isDevelopment3()) {
1760
+ console.warn(
1761
+ "[oasiz/sdk] triggerHaptic bridge is unavailable. This is expected in local development."
1762
+ );
1763
+ }
1764
+ }
1765
+
1606
1766
  // src/log-overlay.ts
1607
1767
  var CONSOLE_METHODS = [
1608
1768
  "debug",
@@ -3456,6 +3616,8 @@ var oasiz = {
3456
3616
  addScore,
3457
3617
  setScore,
3458
3618
  getPlayerCharacter,
3619
+ getSamplePlayerCharacter,
3620
+ getSampleTextureAtlas,
3459
3621
  share,
3460
3622
  triggerHaptic,
3461
3623
  enableLogOverlay,
@@ -3518,6 +3680,8 @@ var oasiz = {
3518
3680
  getPlayerName,
3519
3681
  getRoomCode,
3520
3682
  getSafeAreaTop,
3683
+ getSamplePlayerCharacter,
3684
+ getSampleTextureAtlas,
3521
3685
  getViewportInsets,
3522
3686
  leaveGame,
3523
3687
  loadGameState,
package/dist/index.d.cts CHANGED
@@ -220,13 +220,22 @@ 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
+ }
223
230
  /**
224
231
  * Fetch the authenticated player's character, including a TexturePacker /
225
232
  * Phaser-style texture atlas describing the baked sprite image.
226
233
  *
227
234
  * Returns:
228
235
  * - `null` when the user has no character composition yet, OR
229
- * - `null` when the host bridge is unavailable (local dev / unauthenticated)
236
+ * - a sample character atlas when the host bridge is unavailable on a local
237
+ * browser URL (`localhost` / `file://`), OR
238
+ * - `null` when the host bridge is unavailable and local fallback is disabled
230
239
  *
231
240
  * The host transparently caches and proxies to `GET /api/sdk/me/character`,
232
241
  * so calling this multiple times in a session is cheap. The returned
@@ -245,7 +254,7 @@ interface ScoreEditResult {
245
254
  * ),
246
255
  * });
247
256
  */
248
- declare function getPlayerCharacter(): Promise<PlayerCharacter | null>;
257
+ declare function getPlayerCharacter(options?: GetPlayerCharacterOptions): Promise<PlayerCharacter | null>;
249
258
 
250
259
  declare function triggerHaptic(type: HapticType): void;
251
260
 
@@ -381,6 +390,9 @@ declare function loadGameState(): GameState;
381
390
  declare function saveGameState(state: GameState): void;
382
391
  declare function flushGameState(): void;
383
392
 
393
+ declare function getSampleTextureAtlas(): TextureAtlas;
394
+ declare function getSamplePlayerCharacter(): PlayerCharacter;
395
+
384
396
  declare const oasiz: {
385
397
  submitScore: typeof submitScore;
386
398
  enableAppSimulator: typeof enableAppSimulator;
@@ -413,6 +425,8 @@ declare const oasiz: {
413
425
  addScore: typeof addScore;
414
426
  setScore: typeof setScore;
415
427
  getPlayerCharacter: typeof getPlayerCharacter;
428
+ getSamplePlayerCharacter: typeof getSamplePlayerCharacter;
429
+ getSampleTextureAtlas: typeof getSampleTextureAtlas;
416
430
  share: typeof share;
417
431
  triggerHaptic: typeof triggerHaptic;
418
432
  enableLogOverlay: typeof enableLogOverlay;
@@ -441,4 +455,4 @@ declare const oasiz: {
441
455
  readonly graphicsPerformance: GraphicsPerformanceMetric;
442
456
  };
443
457
 
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 };
458
+ 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,22 @@ 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
+ }
223
230
  /**
224
231
  * Fetch the authenticated player's character, including a TexturePacker /
225
232
  * Phaser-style texture atlas describing the baked sprite image.
226
233
  *
227
234
  * Returns:
228
235
  * - `null` when the user has no character composition yet, OR
229
- * - `null` when the host bridge is unavailable (local dev / unauthenticated)
236
+ * - a sample character atlas when the host bridge is unavailable on a local
237
+ * browser URL (`localhost` / `file://`), OR
238
+ * - `null` when the host bridge is unavailable and local fallback is disabled
230
239
  *
231
240
  * The host transparently caches and proxies to `GET /api/sdk/me/character`,
232
241
  * so calling this multiple times in a session is cheap. The returned
@@ -245,7 +254,7 @@ interface ScoreEditResult {
245
254
  * ),
246
255
  * });
247
256
  */
248
- declare function getPlayerCharacter(): Promise<PlayerCharacter | null>;
257
+ declare function getPlayerCharacter(options?: GetPlayerCharacterOptions): Promise<PlayerCharacter | null>;
249
258
 
250
259
  declare function triggerHaptic(type: HapticType): void;
251
260
 
@@ -381,6 +390,9 @@ declare function loadGameState(): GameState;
381
390
  declare function saveGameState(state: GameState): void;
382
391
  declare function flushGameState(): void;
383
392
 
393
+ declare function getSampleTextureAtlas(): TextureAtlas;
394
+ declare function getSamplePlayerCharacter(): PlayerCharacter;
395
+
384
396
  declare const oasiz: {
385
397
  submitScore: typeof submitScore;
386
398
  enableAppSimulator: typeof enableAppSimulator;
@@ -413,6 +425,8 @@ declare const oasiz: {
413
425
  addScore: typeof addScore;
414
426
  setScore: typeof setScore;
415
427
  getPlayerCharacter: typeof getPlayerCharacter;
428
+ getSamplePlayerCharacter: typeof getSamplePlayerCharacter;
429
+ getSampleTextureAtlas: typeof getSampleTextureAtlas;
416
430
  share: typeof share;
417
431
  triggerHaptic: typeof triggerHaptic;
418
432
  enableLogOverlay: typeof enableLogOverlay;
@@ -441,4 +455,4 @@ declare const oasiz: {
441
455
  readonly graphicsPerformance: GraphicsPerformanceMetric;
442
456
  };
443
457
 
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 };
458
+ 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,223 @@ 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
+ function isDevelopment2() {
1628
+ const nodeEnv = globalThis.process?.env?.NODE_ENV;
1629
+ return nodeEnv !== "production";
1630
+ }
1631
+ function getBridgeWindow2() {
1632
+ if (typeof window === "undefined") {
1633
+ return void 0;
1634
+ }
1635
+ return window;
1636
+ }
1637
+ function isLocalHostname(hostname) {
1638
+ return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "0.0.0.0" || hostname === "::1" || hostname.endsWith(".localhost");
1639
+ }
1640
+ function shouldUseLocalFallback(bridge, localFallback) {
1641
+ if (localFallback === true) {
1642
+ return true;
1643
+ }
1644
+ if (localFallback === false) {
1645
+ return false;
1646
+ }
1647
+ const location = bridge?.location;
1648
+ if (!location) {
1649
+ return false;
1650
+ }
1651
+ return location.protocol === "file:" || isLocalHostname(location.hostname);
1652
+ }
1653
+ function warnMissingBridge2(methodName, usingFallback) {
1654
+ if (isDevelopment2()) {
1655
+ console.warn(
1656
+ "[oasiz/sdk] " + methodName + " bridge is unavailable. " + (usingFallback ? "Using the SDK sample character atlas for local development." : "This is expected in local development.")
1657
+ );
1658
+ }
1659
+ }
1660
+ async function getPlayerCharacter(options = {}) {
1661
+ const bridge = getBridgeWindow2();
1662
+ if (typeof bridge?.__oasizGetPlayerCharacter !== "function") {
1663
+ const useLocalFallback = shouldUseLocalFallback(
1664
+ bridge,
1665
+ options.localFallback ?? "auto"
1666
+ );
1667
+ warnMissingBridge2("getPlayerCharacter", useLocalFallback);
1668
+ return useLocalFallback ? getSamplePlayerCharacter() : null;
1669
+ }
1670
+ try {
1671
+ const result = await bridge.__oasizGetPlayerCharacter();
1672
+ return result ?? null;
1673
+ } catch (error) {
1674
+ if (isDevelopment2()) {
1675
+ console.error("[oasiz/sdk] getPlayerCharacter failed:", error);
1676
+ }
1677
+ return null;
1678
+ }
1679
+ }
1680
+
1681
+ // src/haptics.ts
1682
+ function isDevelopment3() {
1683
+ const nodeEnv = globalThis.process?.env?.NODE_ENV;
1684
+ return nodeEnv !== "production";
1685
+ }
1686
+ function getBridgeWindow3() {
1687
+ if (typeof window === "undefined") {
1688
+ return void 0;
1689
+ }
1690
+ return window;
1691
+ }
1692
+ function triggerHaptic(type) {
1693
+ const bridge = getBridgeWindow3();
1694
+ if (typeof bridge?.triggerHaptic === "function") {
1695
+ bridge.triggerHaptic(type);
1696
+ return;
1697
+ }
1698
+ if (isDevelopment3()) {
1699
+ console.warn(
1700
+ "[oasiz/sdk] triggerHaptic bridge is unavailable. This is expected in local development."
1701
+ );
1702
+ }
1703
+ }
1704
+
1547
1705
  // src/log-overlay.ts
1548
1706
  var CONSOLE_METHODS = [
1549
1707
  "debug",
@@ -3397,6 +3555,8 @@ var oasiz = {
3397
3555
  addScore,
3398
3556
  setScore,
3399
3557
  getPlayerCharacter,
3558
+ getSamplePlayerCharacter,
3559
+ getSampleTextureAtlas,
3400
3560
  share,
3401
3561
  triggerHaptic,
3402
3562
  enableLogOverlay,
@@ -3458,6 +3618,8 @@ export {
3458
3618
  getPlayerName,
3459
3619
  getRoomCode,
3460
3620
  getSafeAreaTop,
3621
+ getSamplePlayerCharacter,
3622
+ getSampleTextureAtlas,
3461
3623
  getViewportInsets,
3462
3624
  leaveGame,
3463
3625
  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.5",
4
4
  "description": "Typed SDK for Oasiz game platform bridge APIs.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",