@genex-ai/embed-sdk 0.6.1 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -16,6 +16,7 @@ var identityEpoch = 0;
16
16
  var handshakeTimeoutMs = 1e4;
17
17
  var refreshDelayMs = 10 * 6e4;
18
18
  var refreshRetryMs = 6e4;
19
+ var overlayTextDelayMs = 500;
19
20
  var handshakeTimer;
20
21
  var refreshTimer;
21
22
  var messageHandler;
@@ -619,13 +620,36 @@ function enterBlocked() {
619
620
  emit("blocked");
620
621
  }
621
622
  var OVERLAY_TEXT = {
622
- connecting: { title: "Connecting to Genex\u2026" },
623
- // Neutral on purpose: the automatic bounce precedes GUEST play as often as
624
- // sign-in "signing you in" would be wrong for most visitors.
625
- redirecting: { title: "Loading\u2026" },
626
- "blocked-standalone": { title: "Sign in to play", button: "Sign in" },
627
- "blocked-embedded": { title: "Sign in on the Genex dashboard to continue" }
623
+ // Delayed (text grace period): most connects finish before the text ever
624
+ // shows a sub-second text flash reads as a glitch.
625
+ connecting: { title: "Connecting\u2026" },
626
+ // Same copy as `connecting` so the whole standalone bounce (gate ->
627
+ // /play/authorize -> gate) reads as ONE continuous screen. Still neutral:
628
+ // the automatic bounce precedes GUEST play as often as sign-in.
629
+ redirecting: { title: "Connecting\u2026" },
630
+ // Terminal states need the visitor to act — text shows immediately.
631
+ "blocked-standalone": { title: "Sign in to play", button: "Sign in", instant: true },
632
+ "blocked-embedded": { title: "Sign in on the Genex dashboard to continue", instant: true }
628
633
  };
634
+ var OVERLAY_FONT_URL = "https://cdn.genex.technology/fonts/Geist-variable.woff2";
635
+ var OVERLAY_FONT_STACK = "'Geist',system-ui,-apple-system,sans-serif";
636
+ var overlayFontRequested = false;
637
+ function ensureOverlayFont(d) {
638
+ if (overlayFontRequested) return;
639
+ overlayFontRequested = true;
640
+ try {
641
+ const FF = win()?.FontFace;
642
+ const fonts = d.fonts;
643
+ if (!FF || !fonts?.add) return;
644
+ const face = new FF("Geist", `url(${OVERLAY_FONT_URL}) format('woff2')`, {
645
+ weight: "100 900",
646
+ display: "swap"
647
+ });
648
+ face.load().then((loaded) => fonts.add(loaded)).catch(() => {
649
+ });
650
+ } catch {
651
+ }
652
+ }
629
653
  function showOverlay(kind) {
630
654
  const d = doc();
631
655
  if (!d?.createElement) return;
@@ -635,23 +659,45 @@ function showOverlay(kind) {
635
659
  } catch {
636
660
  }
637
661
  }
638
- function removeOverlay() {
662
+ function removeOverlay(instant = false) {
639
663
  try {
640
- const root = overlayEl?.root;
641
- root?.remove?.();
664
+ const el = overlayEl;
665
+ overlayEl = null;
666
+ if (!el) return;
667
+ el.clearTextTimer();
668
+ const root = el.root;
669
+ if (instant || !root.style) {
670
+ root.remove?.();
671
+ return;
672
+ }
673
+ root.style.pointerEvents = "none";
674
+ root.style.transition = "opacity 180ms ease";
675
+ root.style.opacity = "0";
676
+ setTimeout(() => {
677
+ try {
678
+ root.remove?.();
679
+ } catch {
680
+ }
681
+ }, 220);
642
682
  } catch {
643
683
  }
644
- overlayEl = null;
645
684
  }
646
685
  function buildOverlay(d) {
686
+ ensureOverlayFont(d);
647
687
  const root = d.createElement("div");
648
688
  root.setAttribute("data-genex-embed-overlay", "");
649
- root.style.cssText = "position:fixed;inset:0;z-index:2147483647;display:flex;align-items:center;justify-content:center;flex-direction:column;gap:16px;background:#080a14;color:#fff;font-family:system-ui,-apple-system,sans-serif;text-align:center;pointer-events:auto;user-select:none";
689
+ root.style.cssText = `position:fixed;inset:0;z-index:2147483647;display:flex;align-items:center;justify-content:center;flex-direction:column;gap:16px;background:#000;color:#fff;font-family:${OVERLAY_FONT_STACK};text-align:center;pointer-events:auto;user-select:none`;
650
690
  const title = d.createElement("div");
651
- title.style.cssText = "font-size:18px;font-weight:600;padding:0 24px";
691
+ title.style.cssText = "font-size:18px;font-weight:600;padding:0 24px;opacity:0";
652
692
  root.appendChild(title);
653
693
  const button = d.createElement("button");
654
- button.style.cssText = "font-size:15px;font-weight:600;padding:10px 28px;border-radius:8px;border:none;cursor:pointer;background:#fff;color:#111;display:none";
694
+ button.style.cssText = "font-size:15px;font-weight:600;padding:10px 28px;border-radius:9px;border:none;cursor:pointer;background:#4b60bf;color:#fff;display:none";
695
+ button.addEventListener("mouseenter", () => {
696
+ button.style.background = "#3f51a8";
697
+ });
698
+ button.addEventListener("mouseleave", () => {
699
+ button.style.background = "#4b60bf";
700
+ });
655
701
  button.addEventListener("click", () => {
656
702
  const w = win();
657
703
  if (!w) return;
@@ -665,11 +711,32 @@ function buildOverlay(d) {
665
711
  };
666
712
  if (d.body) mount();
667
713
  else d.addEventListener?.("DOMContentLoaded", mount);
714
+ let textTimer;
715
+ const clearTextTimer = () => {
716
+ if (textTimer !== void 0) {
717
+ clearTimeout(textTimer);
718
+ textTimer = void 0;
719
+ }
720
+ };
668
721
  return {
669
722
  root,
723
+ clearTextTimer,
670
724
  setContent(kind) {
671
725
  const text = OVERLAY_TEXT[kind];
726
+ clearTextTimer();
672
727
  title.textContent = text.title;
728
+ if (text.instant || overlayTextDelayMs <= 0) {
729
+ title.style.transition = "";
730
+ title.style.opacity = "1";
731
+ } else {
732
+ title.style.transition = "";
733
+ title.style.opacity = "0";
734
+ textTimer = setTimeout(() => {
735
+ textTimer = void 0;
736
+ title.style.transition = "opacity 200ms ease";
737
+ title.style.opacity = "1";
738
+ }, overlayTextDelayMs);
739
+ }
673
740
  button.style.display = text.button ? "inline-block" : "none";
674
741
  if (text.button) button.textContent = text.button;
675
742
  mount();
@@ -693,15 +760,22 @@ function removeGuestPopover() {
693
760
  popoverEl = null;
694
761
  }
695
762
  function buildGuestPopover(d) {
763
+ ensureOverlayFont(d);
696
764
  const root = d.createElement("div");
697
765
  root.setAttribute("data-genex-guest-popover", "");
698
- root.style.cssText = "position:fixed;top:12px;right:12px;z-index:2147483646;display:flex;align-items:center;gap:12px;padding:10px 12px 10px 16px;border-radius:12px;background:rgba(8,10,20,0.85);color:#fff;font-family:system-ui,-apple-system,sans-serif;font-size:13px;box-shadow:0 4px 24px rgba(0,0,0,0.4);pointer-events:auto;user-select:none";
766
+ root.style.cssText = `position:fixed;top:12px;right:12px;z-index:2147483646;display:flex;align-items:center;gap:12px;padding:10px 12px 10px 16px;border-radius:12px;background:rgba(0,0,0,0.85);color:#fff;font-family:${OVERLAY_FONT_STACK};font-size:13px;box-shadow:0 4px 24px rgba(0,0,0,0.4);pointer-events:auto;user-select:none`;
699
767
  const text = d.createElement("span");
700
768
  text.textContent = user?.name ? `Playing as ${user.name} \u2014 sign in to save progress` : "Sign in to save progress";
701
769
  root.appendChild(text);
702
770
  const signIn = d.createElement("button");
703
771
  signIn.textContent = "Sign in";
704
- signIn.style.cssText = "font-size:13px;font-weight:600;padding:6px 16px;border-radius:999px;border:none;cursor:pointer;background:#fff;color:#111";
772
+ signIn.style.cssText = "font-size:13px;font-weight:600;padding:6px 16px;border-radius:9px;border:none;cursor:pointer;background:#4b60bf;color:#fff";
773
+ signIn.addEventListener("mouseenter", () => {
774
+ signIn.style.background = "#3f51a8";
775
+ });
776
+ signIn.addEventListener("mouseleave", () => {
777
+ signIn.style.background = "#4b60bf";
778
+ });
705
779
  signIn.addEventListener("click", () => {
706
780
  const w = win();
707
781
  if (!w) return;
@@ -734,8 +808,9 @@ function __resetForTests(overrides) {
734
808
  if (refreshTimer !== void 0) clearTimeout(refreshTimer);
735
809
  handshakeTimer = void 0;
736
810
  refreshTimer = void 0;
737
- removeOverlay();
811
+ removeOverlay(true);
738
812
  removeGuestPopover();
813
+ overlayFontRequested = false;
739
814
  config = null;
740
815
  state = "pending";
741
816
  user = null;
@@ -757,6 +832,7 @@ function __resetForTests(overrides) {
757
832
  handshakeTimeoutMs = overrides?.handshakeTimeoutMs ?? 1e4;
758
833
  refreshDelayMs = overrides?.refreshDelayMs ?? 10 * 6e4;
759
834
  refreshRetryMs = overrides?.refreshRetryMs ?? 6e4;
835
+ overlayTextDelayMs = overrides?.overlayTextDelayMs ?? 500;
760
836
  }
761
837
 
762
838
  export {
package/dist/index.d.ts CHANGED
@@ -221,6 +221,7 @@ declare function __resetForTests(overrides?: {
221
221
  handshakeTimeoutMs?: number;
222
222
  refreshDelayMs?: number;
223
223
  refreshRetryMs?: number;
224
+ overlayTextDelayMs?: number;
224
225
  }): void;
225
226
 
226
227
  export { type AuthState, type EmbedConfig, type EmbedEvent, type EmbedUser, type Leaderboard, type LeaderboardEntry, type PlayerStateResult, type SaveStateResult, type SubmitScoreResult, type WorldStateResult, __resetForTests, _stashTicketFromUrl, getAuthState, getColyseusAuth, getColyseusUrls, getEmbedToken, getLeaderboard, getUser, initEmbed, isEmbedded, loadPlayerState, loadWorldState, on, savePlayerState, saveWorldState, submitScore, waitForAuth, waitForPlayer };
package/dist/index.js CHANGED
@@ -17,7 +17,7 @@ import {
17
17
  submitScore,
18
18
  waitForAuth,
19
19
  waitForPlayer
20
- } from "./chunk-UOC55SJL.js";
20
+ } from "./chunk-BWJ2FVCH.js";
21
21
  export {
22
22
  __resetForTests,
23
23
  _stashTicketFromUrl,
package/dist/sentry.js CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  _stashTicketFromUrl,
3
3
  getUser,
4
4
  on
5
- } from "./chunk-UOC55SJL.js";
5
+ } from "./chunk-BWJ2FVCH.js";
6
6
 
7
7
  // src/sentry.ts
8
8
  import * as Sentry from "@sentry/browser";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@genex-ai/embed-sdk",
3
- "version": "0.6.1",
3
+ "version": "0.7.0",
4
4
  "description": "Player identity + durable game state for genex games — signed-in or guest play, per-player save slots, shared world state, and soft-trust leaderboards.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",