@genex-ai/embed-sdk 0.9.0 → 0.10.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.
@@ -621,19 +621,91 @@ function enterBlocked() {
621
621
  }
622
622
  var OVERLAY_TEXT = {
623
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 ->
624
+ // shows — a sub-second text flash reads as a glitch. `wordmark` states show
625
+ // GENEX in the breathing decrypt loop instead of an instruction.
626
+ connecting: { title: "GENEX", wordmark: true },
627
+ // Same treatment as `connecting` so the whole standalone bounce (gate ->
627
628
  // /play/authorize -> gate) reads as ONE continuous screen. Still neutral:
628
629
  // the automatic bounce precedes GUEST play as often as sign-in.
629
- redirecting: { title: "Connecting\u2026" },
630
+ redirecting: { title: "GENEX", wordmark: true },
630
631
  // Terminal states need the visitor to act — text shows immediately.
631
632
  "blocked-standalone": { title: "Sign in to play", button: "Sign in", instant: true },
632
633
  "blocked-embedded": { title: "Sign in on the Genex dashboard to continue", instant: true }
633
634
  };
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";
635
+ var OVERLAY_FONT_URL = "https://cdn.genex.technology/fonts/GeistMono-variable.woff2";
636
+ var OVERLAY_FONT_STACK = "'Geist Mono',ui-monospace,SFMono-Regular,Menlo,monospace";
636
637
  var overlayFontRequested = false;
638
+ var SCRAMBLE_NOISE = "!<>-_/[]{}=+*^?#$%&@";
639
+ var SCRAMBLE_TICK_MS = 50;
640
+ var SCRAMBLE_SETTLE_TICKS = 10;
641
+ var WORDMARK_LOOP_PHASES = [
642
+ { name: "churn", ticks: 5 },
643
+ { name: "settle", ticks: 10 },
644
+ { name: "hold", ticks: 12 },
645
+ { name: "dissolve", ticks: 8 }
646
+ ];
647
+ function scrambleNoise(length) {
648
+ let out = "";
649
+ for (let i = 0; i < length; i++) {
650
+ out += SCRAMBLE_NOISE[Math.floor(Math.random() * SCRAMBLE_NOISE.length)];
651
+ }
652
+ return out;
653
+ }
654
+ function scrambleStatic() {
655
+ try {
656
+ const w = win();
657
+ if (!w || typeof w.matchMedia !== "function") return true;
658
+ return w.matchMedia("(prefers-reduced-motion: reduce)").matches;
659
+ } catch {
660
+ return true;
661
+ }
662
+ }
663
+ function scrambleIn(el, text) {
664
+ if (scrambleStatic()) {
665
+ el.textContent = text;
666
+ return () => {
667
+ };
668
+ }
669
+ let i = 0;
670
+ el.textContent = scrambleNoise(text.length);
671
+ const id = setInterval(() => {
672
+ i++;
673
+ if (i >= SCRAMBLE_SETTLE_TICKS) {
674
+ el.textContent = text;
675
+ clearInterval(id);
676
+ return;
677
+ }
678
+ const lock = Math.floor(i / SCRAMBLE_SETTLE_TICKS * text.length);
679
+ el.textContent = text.slice(0, lock) + scrambleNoise(text.length - lock);
680
+ }, SCRAMBLE_TICK_MS);
681
+ return () => clearInterval(id);
682
+ }
683
+ function wordmarkLoop(el, text) {
684
+ if (scrambleStatic()) {
685
+ el.textContent = text;
686
+ return () => {
687
+ };
688
+ }
689
+ let phase = 0;
690
+ let i = 0;
691
+ const frame = () => {
692
+ const p = WORDMARK_LOOP_PHASES[phase];
693
+ let kept;
694
+ if (p.name === "churn") kept = 0;
695
+ else if (p.name === "settle") kept = Math.floor(i / p.ticks * text.length);
696
+ else if (p.name === "hold") kept = text.length;
697
+ else kept = text.length - Math.floor(i / p.ticks * text.length);
698
+ el.textContent = text.slice(0, kept) + scrambleNoise(text.length - kept);
699
+ i++;
700
+ if (i >= p.ticks) {
701
+ i = 0;
702
+ phase = (phase + 1) % WORDMARK_LOOP_PHASES.length;
703
+ }
704
+ };
705
+ frame();
706
+ const id = setInterval(frame, SCRAMBLE_TICK_MS);
707
+ return () => clearInterval(id);
708
+ }
637
709
  function ensureOverlayFont(d) {
638
710
  if (overlayFontRequested) return;
639
711
  overlayFontRequested = true;
@@ -641,7 +713,7 @@ function ensureOverlayFont(d) {
641
713
  const FF = win()?.FontFace;
642
714
  const fonts = d.fonts;
643
715
  if (!FF || !fonts?.add) return;
644
- const face = new FF("Geist", `url(${OVERLAY_FONT_URL}) format('woff2')`, {
716
+ const face = new FF("Geist Mono", `url(${OVERLAY_FONT_URL}) format('woff2')`, {
645
717
  weight: "100 900",
646
718
  display: "swap"
647
719
  });
@@ -664,7 +736,7 @@ function removeOverlay(instant = false) {
664
736
  const el = overlayEl;
665
737
  overlayEl = null;
666
738
  if (!el) return;
667
- el.clearTextTimer();
739
+ el.stopText();
668
740
  const root = el.root;
669
741
  if (instant || !root.style) {
670
742
  root.remove?.();
@@ -686,12 +758,12 @@ function buildOverlay(d) {
686
758
  ensureOverlayFont(d);
687
759
  const root = d.createElement("div");
688
760
  root.setAttribute("data-genex-embed-overlay", "");
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`;
761
+ root.style.cssText = `position:fixed;inset:0;z-index:2147483647;display:flex;align-items:center;justify-content:center;flex-direction:column;gap:14px;background:#000;color:#fff;font-family:${OVERLAY_FONT_STACK};text-align:center;pointer-events:auto;user-select:none`;
690
762
  const title = d.createElement("div");
691
- title.style.cssText = "font-size:18px;font-weight:600;padding:0 24px;opacity:0";
763
+ title.style.cssText = "font-size:13px;font-weight:400;line-height:1.3;padding:0 24px;opacity:0;min-height:1.3em;font-variant-ligatures:none";
692
764
  root.appendChild(title);
693
765
  const button = d.createElement("button");
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";
766
+ button.style.cssText = "font-family:inherit;font-size:13px;font-weight:500;line-height:1.3;padding:8px 22px;border-radius:9px;border:none;cursor:pointer;background:#4b60bf;color:#fff;display:none";
695
767
  button.addEventListener("mouseenter", () => {
696
768
  button.style.background = "#3f51a8";
697
769
  });
@@ -712,29 +784,37 @@ function buildOverlay(d) {
712
784
  if (d.body) mount();
713
785
  else d.addEventListener?.("DOMContentLoaded", mount);
714
786
  let textTimer;
715
- const clearTextTimer = () => {
787
+ let cancelScramble;
788
+ const stopText = () => {
716
789
  if (textTimer !== void 0) {
717
790
  clearTimeout(textTimer);
718
791
  textTimer = void 0;
719
792
  }
793
+ if (cancelScramble) {
794
+ cancelScramble();
795
+ cancelScramble = void 0;
796
+ }
720
797
  };
721
798
  return {
722
799
  root,
723
- clearTextTimer,
800
+ stopText,
724
801
  setContent(kind) {
725
802
  const text = OVERLAY_TEXT[kind];
726
- clearTextTimer();
803
+ stopText();
727
804
  title.textContent = text.title;
728
- if (text.instant || overlayTextDelayMs <= 0) {
729
- title.style.transition = "";
805
+ title.style.letterSpacing = text.wordmark ? "0.22em" : "";
806
+ title.style.marginRight = text.wordmark ? "-0.22em" : "";
807
+ const reveal = () => {
730
808
  title.style.opacity = "1";
809
+ cancelScramble = text.wordmark ? wordmarkLoop(title, text.title) : scrambleIn(title, text.title);
810
+ };
811
+ if (text.instant || overlayTextDelayMs <= 0) {
812
+ reveal();
731
813
  } else {
732
- title.style.transition = "";
733
814
  title.style.opacity = "0";
734
815
  textTimer = setTimeout(() => {
735
816
  textTimer = void 0;
736
- title.style.transition = "opacity 200ms ease";
737
- title.style.opacity = "1";
817
+ reveal();
738
818
  }, overlayTextDelayMs);
739
819
  }
740
820
  button.style.display = text.button ? "inline-block" : "none";
@@ -769,7 +849,7 @@ function buildGuestPopover(d) {
769
849
  root.appendChild(text);
770
850
  const signIn = d.createElement("button");
771
851
  signIn.textContent = "Sign in";
772
- signIn.style.cssText = "font-size:13px;font-weight:600;padding:6px 16px;border-radius:9px;border:none;cursor:pointer;background:#4b60bf;color:#fff";
852
+ signIn.style.cssText = "font-family:inherit;font-size:13px;font-weight:500;padding:6px 16px;border-radius:9px;border:none;cursor:pointer;background:#4b60bf;color:#fff";
773
853
  signIn.addEventListener("mouseenter", () => {
774
854
  signIn.style.background = "#3f51a8";
775
855
  });
package/dist/index.js CHANGED
@@ -17,7 +17,7 @@ import {
17
17
  submitScore,
18
18
  waitForAuth,
19
19
  waitForPlayer
20
- } from "./chunk-BWJ2FVCH.js";
20
+ } from "./chunk-Z7VGKJYX.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-BWJ2FVCH.js";
5
+ } from "./chunk-Z7VGKJYX.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.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "Player identity + durable game state for genex games \u2014 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",