@genex-ai/embed-sdk 0.8.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.
- package/dist/{chunk-BWJ2FVCH.js → chunk-Z7VGKJYX.js} +100 -20
- package/dist/index.js +1 -1
- package/dist/sentry.js +27 -5
- package/package.json +2 -2
|
@@ -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
|
-
|
|
626
|
-
|
|
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: "
|
|
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/
|
|
635
|
-
var OVERLAY_FONT_STACK = "'Geist',
|
|
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.
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
800
|
+
stopText,
|
|
724
801
|
setContent(kind) {
|
|
725
802
|
const text = OVERLAY_TEXT[kind];
|
|
726
|
-
|
|
803
|
+
stopText();
|
|
727
804
|
title.textContent = text.title;
|
|
728
|
-
|
|
729
|
-
|
|
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
|
-
|
|
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:
|
|
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
package/dist/sentry.js
CHANGED
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
_stashTicketFromUrl,
|
|
3
3
|
getUser,
|
|
4
4
|
on
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-Z7VGKJYX.js";
|
|
6
6
|
|
|
7
7
|
// src/sentry.ts
|
|
8
8
|
import * as Sentry from "@sentry/browser";
|
|
@@ -16,18 +16,39 @@ function scrubTokens(s) {
|
|
|
16
16
|
// src/sentry.ts
|
|
17
17
|
var DEFAULT_GAMES_DSN = "https://d1414cfcdc09bf1c1d124e86f8087251@o4511115493900288.ingest.us.sentry.io/4511662569160704";
|
|
18
18
|
var initialized = false;
|
|
19
|
+
function isTouchDevice() {
|
|
20
|
+
try {
|
|
21
|
+
const coarse = matchMedia("(pointer: coarse)").matches;
|
|
22
|
+
const touch = navigator.maxTouchPoints > 1;
|
|
23
|
+
const nav = navigator;
|
|
24
|
+
const mobileUA = nav.userAgentData ? !!nav.userAgentData.mobile : /Mobi|Android/i.test(navigator.userAgent);
|
|
25
|
+
return touch && coarse || mobileUA;
|
|
26
|
+
} catch {
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
var touchSession = false;
|
|
19
31
|
function initGameSentry(opts) {
|
|
20
32
|
if (typeof window === "undefined") return;
|
|
21
33
|
if (initialized) return;
|
|
22
34
|
initialized = true;
|
|
35
|
+
touchSession = isTouchDevice();
|
|
36
|
+
try {
|
|
37
|
+
window.__GENEX_SDK_SENTRY__ = "touch-aware";
|
|
38
|
+
} catch {
|
|
39
|
+
}
|
|
23
40
|
_stashTicketFromUrl();
|
|
24
41
|
Sentry.init({
|
|
25
42
|
dsn: opts.dsn ?? DEFAULT_GAMES_DSN,
|
|
26
43
|
environment: opts.environment ?? "production",
|
|
27
|
-
|
|
28
|
-
//
|
|
29
|
-
|
|
30
|
-
//
|
|
44
|
+
// Mobile-readiness program (2026-07-21): touch devices get throttled
|
|
45
|
+
// telemetry — this REVERSES the 2026-07-02 record-every-session decision
|
|
46
|
+
// for the touch device class only, because 100% replay + canvas readback
|
|
47
|
+
// burns memory/GPU on the phones the crash program is trying to save.
|
|
48
|
+
// Desktop keeps full rates; on-error replays stay 100% everywhere, so the
|
|
49
|
+
// crash-debugging case keeps its data.
|
|
50
|
+
tracesSampleRate: touchSession ? 0.2 : 1,
|
|
51
|
+
replaysSessionSampleRate: touchSession ? 0.1 : 1,
|
|
31
52
|
replaysOnErrorSampleRate: 1,
|
|
32
53
|
dataCollection: { userInfo: true },
|
|
33
54
|
initialScope: { tags: { game_slug: opts.slug } },
|
|
@@ -105,6 +126,7 @@ function initGameSentry(opts) {
|
|
|
105
126
|
}
|
|
106
127
|
var lastSnapshot = 0;
|
|
107
128
|
function sentryCanvasSnapshot(canvas, opts) {
|
|
129
|
+
if (touchSession) return;
|
|
108
130
|
const now = Date.now();
|
|
109
131
|
if (now - lastSnapshot < (opts?.intervalMs ?? 500)) return;
|
|
110
132
|
lastSnapshot = now;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@genex-ai/embed-sdk",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Player identity + durable game state for genex games
|
|
3
|
+
"version": "0.10.0",
|
|
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",
|
|
7
7
|
"types": "./dist/index.d.ts",
|