@backbay/glia 0.2.0-alpha.6 → 0.2.0-alpha.8
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/audio/index.js +1145 -5
- package/dist/audio/index.js.map +1 -1
- package/dist/components/index.js +3187 -10
- package/dist/components/index.js.map +1 -1
- package/dist/core.js +19714 -12
- package/dist/core.js.map +1 -1
- package/dist/emotion/index.js +1 -1
- package/dist/emotion/index.js.map +1 -1
- package/dist/hooks/index.js +941 -6
- package/dist/hooks/index.js.map +1 -1
- package/dist/index.js +31841 -183
- package/dist/index.js.map +1 -1
- package/dist/primitives/index.js +21111 -57
- package/dist/primitives/index.js.map +1 -1
- package/dist/protocol/index.js +360 -2
- package/dist/protocol/index.js.map +1 -1
- package/dist/speakeasy/index.js +2786 -38
- package/dist/speakeasy/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/theme/index.js +1150 -3
- package/dist/theme/index.js.map +1 -1
- package/dist/vision/index.js +370 -2
- package/dist/vision/index.js.map +1 -1
- package/dist/workspace/index.js +16824 -2
- package/dist/workspace/index.js.map +1 -1
- package/package.json +16 -10
- package/dist/AuroraBackground-AP6ZHVFA.js +0 -6
- package/dist/AuroraBackground-AP6ZHVFA.js.map +0 -1
- package/dist/BentoGrid-CDARICNM.js +0 -6
- package/dist/BentoGrid-CDARICNM.js.map +0 -1
- package/dist/CommandPalette-JCWJKRBY.js +0 -6
- package/dist/CommandPalette-JCWJKRBY.js.map +0 -1
- package/dist/Glass-H4X4ZI4P.js +0 -7
- package/dist/Glass-H4X4ZI4P.js.map +0 -1
- package/dist/GlitchText-KLQ57PPY.js +0 -6
- package/dist/GlitchText-KLQ57PPY.js.map +0 -1
- package/dist/GlowButton-VGBPMZO7.js +0 -6
- package/dist/GlowButton-VGBPMZO7.js.map +0 -1
- package/dist/Graph3D-GO7N2EZQ.js +0 -540
- package/dist/Graph3D-GO7N2EZQ.js.map +0 -1
- package/dist/HUDProgressRing-N6C5NAEV.js +0 -6
- package/dist/HUDProgressRing-N6C5NAEV.js.map +0 -1
- package/dist/KPIStat-PBQK27ZB.js +0 -6
- package/dist/KPIStat-PBQK27ZB.js.map +0 -1
- package/dist/NeonToast-W5F7MU3U.js +0 -6
- package/dist/NeonToast-W5F7MU3U.js.map +0 -1
- package/dist/ParticleField-WK6CNHWU.js +0 -51
- package/dist/ParticleField-WK6CNHWU.js.map +0 -1
- package/dist/TextGenerateEffect-EUCEIIUJ.js +0 -6
- package/dist/TextGenerateEffect-EUCEIIUJ.js.map +0 -1
- package/dist/ThreeDCard-VH5I3SSY.js +0 -6
- package/dist/ThreeDCard-VH5I3SSY.js.map +0 -1
- package/dist/TypingAnimation-GIWOHPIX.js +0 -6
- package/dist/TypingAnimation-GIWOHPIX.js.map +0 -1
- package/dist/alert-dialog-QOSYBIIE.js +0 -19
- package/dist/alert-dialog-QOSYBIIE.js.map +0 -1
- package/dist/avatar-N5R37PCU.js +0 -10
- package/dist/avatar-N5R37PCU.js.map +0 -1
- package/dist/badge-GTVIIGPY.js +0 -8
- package/dist/badge-GTVIIGPY.js.map +0 -1
- package/dist/button-D7IMSV2D.js +0 -8
- package/dist/button-D7IMSV2D.js.map +0 -1
- package/dist/chunk-3CMPQOMY.js +0 -69
- package/dist/chunk-3CMPQOMY.js.map +0 -1
- package/dist/chunk-3OQT6IYR.js +0 -41
- package/dist/chunk-3OQT6IYR.js.map +0 -1
- package/dist/chunk-43B2WVLS.js +0 -85
- package/dist/chunk-43B2WVLS.js.map +0 -1
- package/dist/chunk-4SRFO5W3.js +0 -121
- package/dist/chunk-4SRFO5W3.js.map +0 -1
- package/dist/chunk-5IZELOOU.js +0 -362
- package/dist/chunk-5IZELOOU.js.map +0 -1
- package/dist/chunk-6DM4ACSS.js +0 -154
- package/dist/chunk-6DM4ACSS.js.map +0 -1
- package/dist/chunk-6IGT34PC.js +0 -50
- package/dist/chunk-6IGT34PC.js.map +0 -1
- package/dist/chunk-6RKBCJHN.js +0 -194
- package/dist/chunk-6RKBCJHN.js.map +0 -1
- package/dist/chunk-6RX2WGCO.js +0 -108
- package/dist/chunk-6RX2WGCO.js.map +0 -1
- package/dist/chunk-7K4WZM3U.js +0 -189
- package/dist/chunk-7K4WZM3U.js.map +0 -1
- package/dist/chunk-7MDBHJPT.js +0 -407
- package/dist/chunk-7MDBHJPT.js.map +0 -1
- package/dist/chunk-7UQD6ROV.js +0 -9
- package/dist/chunk-7UQD6ROV.js.map +0 -1
- package/dist/chunk-AFNIVLZP.js +0 -1069
- package/dist/chunk-AFNIVLZP.js.map +0 -1
- package/dist/chunk-ANWYRO6A.js +0 -407
- package/dist/chunk-ANWYRO6A.js.map +0 -1
- package/dist/chunk-DIXPOHDO.js +0 -71
- package/dist/chunk-DIXPOHDO.js.map +0 -1
- package/dist/chunk-DWYMKYPI.js +0 -3
- package/dist/chunk-DWYMKYPI.js.map +0 -1
- package/dist/chunk-E3NVDCZG.js +0 -280
- package/dist/chunk-E3NVDCZG.js.map +0 -1
- package/dist/chunk-EBM7YBKL.js +0 -399
- package/dist/chunk-EBM7YBKL.js.map +0 -1
- package/dist/chunk-EPAM7IWW.js +0 -294
- package/dist/chunk-EPAM7IWW.js.map +0 -1
- package/dist/chunk-EXQ7GYRS.js +0 -134
- package/dist/chunk-EXQ7GYRS.js.map +0 -1
- package/dist/chunk-F4QTUZ3C.js +0 -136
- package/dist/chunk-F4QTUZ3C.js.map +0 -1
- package/dist/chunk-FEW533R2.js +0 -105
- package/dist/chunk-FEW533R2.js.map +0 -1
- package/dist/chunk-FFZLJKC7.js +0 -270
- package/dist/chunk-FFZLJKC7.js.map +0 -1
- package/dist/chunk-GEAMOBF7.js +0 -8486
- package/dist/chunk-GEAMOBF7.js.map +0 -1
- package/dist/chunk-GRTRSCTD.js +0 -74
- package/dist/chunk-GRTRSCTD.js.map +0 -1
- package/dist/chunk-IKGYOGLK.js +0 -16
- package/dist/chunk-IKGYOGLK.js.map +0 -1
- package/dist/chunk-IQ7WYWVJ.js +0 -73
- package/dist/chunk-IQ7WYWVJ.js.map +0 -1
- package/dist/chunk-IXIVWQLF.js +0 -543
- package/dist/chunk-IXIVWQLF.js.map +0 -1
- package/dist/chunk-JCJU57RC.js +0 -115
- package/dist/chunk-JCJU57RC.js.map +0 -1
- package/dist/chunk-KORSTBU4.js +0 -117
- package/dist/chunk-KORSTBU4.js.map +0 -1
- package/dist/chunk-KSEZ6UM2.js +0 -235
- package/dist/chunk-KSEZ6UM2.js.map +0 -1
- package/dist/chunk-MHPF7R3O.js +0 -1376
- package/dist/chunk-MHPF7R3O.js.map +0 -1
- package/dist/chunk-MPC5IH7E.js +0 -81
- package/dist/chunk-MPC5IH7E.js.map +0 -1
- package/dist/chunk-MQIU2NYA.js +0 -114
- package/dist/chunk-MQIU2NYA.js.map +0 -1
- package/dist/chunk-NYMBJOGR.js +0 -2192
- package/dist/chunk-NYMBJOGR.js.map +0 -1
- package/dist/chunk-OBZD2M3C.js +0 -169
- package/dist/chunk-OBZD2M3C.js.map +0 -1
- package/dist/chunk-ODM2AG6G.js +0 -176
- package/dist/chunk-ODM2AG6G.js.map +0 -1
- package/dist/chunk-ONDKF5LP.js +0 -53
- package/dist/chunk-ONDKF5LP.js.map +0 -1
- package/dist/chunk-P25YCWQB.js +0 -41
- package/dist/chunk-P25YCWQB.js.map +0 -1
- package/dist/chunk-PFYVNM6H.js +0 -14
- package/dist/chunk-PFYVNM6H.js.map +0 -1
- package/dist/chunk-PWNNSGFL.js +0 -20
- package/dist/chunk-PWNNSGFL.js.map +0 -1
- package/dist/chunk-Q2PGZVOT.js +0 -36
- package/dist/chunk-Q2PGZVOT.js.map +0 -1
- package/dist/chunk-Q2XDMV7U.js +0 -76
- package/dist/chunk-Q2XDMV7U.js.map +0 -1
- package/dist/chunk-QG7FH2FI.js +0 -45
- package/dist/chunk-QG7FH2FI.js.map +0 -1
- package/dist/chunk-R7HUOK2D.js +0 -1914
- package/dist/chunk-R7HUOK2D.js.map +0 -1
- package/dist/chunk-REUYY7G5.js +0 -773
- package/dist/chunk-REUYY7G5.js.map +0 -1
- package/dist/chunk-RHC2Z2HT.js +0 -199
- package/dist/chunk-RHC2Z2HT.js.map +0 -1
- package/dist/chunk-RMCVLIFE.js +0 -23
- package/dist/chunk-RMCVLIFE.js.map +0 -1
- package/dist/chunk-ROZLTXGR.js +0 -234
- package/dist/chunk-ROZLTXGR.js.map +0 -1
- package/dist/chunk-RSS2C2O3.js +0 -17
- package/dist/chunk-RSS2C2O3.js.map +0 -1
- package/dist/chunk-SAGCG5SH.js +0 -355
- package/dist/chunk-SAGCG5SH.js.map +0 -1
- package/dist/chunk-TM6AOUSD.js +0 -40
- package/dist/chunk-TM6AOUSD.js.map +0 -1
- package/dist/chunk-TPK4BYCO.js +0 -970
- package/dist/chunk-TPK4BYCO.js.map +0 -1
- package/dist/chunk-UNQIL4K2.js +0 -34
- package/dist/chunk-UNQIL4K2.js.map +0 -1
- package/dist/chunk-UUG6L75Y.js +0 -47
- package/dist/chunk-UUG6L75Y.js.map +0 -1
- package/dist/chunk-V2SYMV4W.js +0 -114
- package/dist/chunk-V2SYMV4W.js.map +0 -1
- package/dist/chunk-V7EN5CTH.js +0 -130
- package/dist/chunk-V7EN5CTH.js.map +0 -1
- package/dist/chunk-VITKG2HL.js +0 -1125
- package/dist/chunk-VITKG2HL.js.map +0 -1
- package/dist/chunk-VYEWU5LO.js +0 -2631
- package/dist/chunk-VYEWU5LO.js.map +0 -1
- package/dist/chunk-W67QAGSH.js +0 -178
- package/dist/chunk-W67QAGSH.js.map +0 -1
- package/dist/chunk-WWBIN6KV.js +0 -1353
- package/dist/chunk-WWBIN6KV.js.map +0 -1
- package/dist/chunk-X77Z4PFB.js +0 -224
- package/dist/chunk-X77Z4PFB.js.map +0 -1
- package/dist/chunk-X7VG7OTT.js +0 -8
- package/dist/chunk-X7VG7OTT.js.map +0 -1
- package/dist/chunk-XE4K2SGI.js +0 -74
- package/dist/chunk-XE4K2SGI.js.map +0 -1
- package/dist/chunk-YIUG7IJK.js +0 -628
- package/dist/chunk-YIUG7IJK.js.map +0 -1
- package/dist/chunk-YNVN3V4Y.js +0 -13
- package/dist/chunk-YNVN3V4Y.js.map +0 -1
- package/dist/chunk-Z2S54IZX.js +0 -198
- package/dist/chunk-Z2S54IZX.js.map +0 -1
- package/dist/chunk-ZR6AH25Z.js +0 -17
- package/dist/chunk-ZR6AH25Z.js.map +0 -1
- package/dist/dialog-SPM3DTTI.js +0 -17
- package/dist/dialog-SPM3DTTI.js.map +0 -1
- package/dist/dropdown-menu-HMTWKWGK.js +0 -21
- package/dist/dropdown-menu-HMTWKWGK.js.map +0 -1
- package/dist/input-BH4P4S26.js +0 -6
- package/dist/input-BH4P4S26.js.map +0 -1
- package/dist/label-5Z4Q6VER.js +0 -8
- package/dist/label-5Z4Q6VER.js.map +0 -1
- package/dist/popover-IFOUXYLI.js +0 -18
- package/dist/popover-IFOUXYLI.js.map +0 -1
- package/dist/scroll-area-DJXNW6QX.js +0 -14
- package/dist/scroll-area-DJXNW6QX.js.map +0 -1
- package/dist/select-FZ277C3G.js +0 -22
- package/dist/select-FZ277C3G.js.map +0 -1
- package/dist/separator-BTMLN4NB.js +0 -8
- package/dist/separator-BTMLN4NB.js.map +0 -1
- package/dist/skeleton-DXIWBH4W.js +0 -6
- package/dist/skeleton-DXIWBH4W.js.map +0 -1
- package/dist/switch-4MCXIZBY.js +0 -13
- package/dist/switch-4MCXIZBY.js.map +0 -1
- package/dist/tabs-O7AW3APK.js +0 -17
- package/dist/tabs-O7AW3APK.js.map +0 -1
- package/dist/textarea-IB5WAFDO.js +0 -6
- package/dist/textarea-IB5WAFDO.js.map +0 -1
- package/dist/toggle-XVPPG6P4.js +0 -10
- package/dist/toggle-XVPPG6P4.js.map +0 -1
- package/dist/tooltip-JICZTD4F.js +0 -18
- package/dist/tooltip-JICZTD4F.js.map +0 -1
package/dist/components/index.js
CHANGED
|
@@ -1,12 +1,3189 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import '
|
|
4
|
-
|
|
5
|
-
import '
|
|
6
|
-
import '
|
|
7
|
-
import '
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
1
|
+
import * as React3 from 'react';
|
|
2
|
+
import { createContext, useState, useMemo, useCallback, useContext, useRef, useEffect, Component, useId } from 'react';
|
|
3
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
4
|
+
import { clsx } from 'clsx';
|
|
5
|
+
import { twMerge } from 'tailwind-merge';
|
|
6
|
+
import { useReducedMotion, motion, useScroll, useTransform, AnimatePresence, useMotionValue, useSpring } from 'framer-motion';
|
|
7
|
+
import { Trophy, Vote, Zap, FileText, ArrowRight } from 'lucide-react';
|
|
8
|
+
|
|
9
|
+
// src/components/BBProvider.tsx
|
|
10
|
+
var ErrorBoundaryContext = createContext(null);
|
|
11
|
+
function ErrorThrower({ children }) {
|
|
12
|
+
const [error, setError] = useState(null);
|
|
13
|
+
if (error) {
|
|
14
|
+
throw error;
|
|
15
|
+
}
|
|
16
|
+
const throwError = useCallback((err) => {
|
|
17
|
+
setError(err);
|
|
18
|
+
}, []);
|
|
19
|
+
return /* @__PURE__ */ jsx(ErrorBoundaryContext.Provider, { value: { throwError }, children });
|
|
20
|
+
}
|
|
21
|
+
function DefaultFallback({
|
|
22
|
+
error,
|
|
23
|
+
reset,
|
|
24
|
+
variant = "card"
|
|
25
|
+
}) {
|
|
26
|
+
const isFullscreen = variant === "fullscreen";
|
|
27
|
+
const isInline = variant === "inline";
|
|
28
|
+
const containerStyle = isFullscreen ? {
|
|
29
|
+
position: "fixed",
|
|
30
|
+
inset: 0,
|
|
31
|
+
display: "flex",
|
|
32
|
+
alignItems: "center",
|
|
33
|
+
justifyContent: "center",
|
|
34
|
+
zIndex: 9999,
|
|
35
|
+
background: "rgba(0, 0, 0, 0.6)",
|
|
36
|
+
backdropFilter: "blur(12px)",
|
|
37
|
+
WebkitBackdropFilter: "blur(12px)"
|
|
38
|
+
} : isInline ? {
|
|
39
|
+
display: "inline-flex",
|
|
40
|
+
alignItems: "center",
|
|
41
|
+
gap: 8,
|
|
42
|
+
padding: "4px 8px",
|
|
43
|
+
borderRadius: 6,
|
|
44
|
+
background: "rgba(255, 60, 60, 0.08)",
|
|
45
|
+
border: "1px solid rgba(255, 60, 60, 0.2)"
|
|
46
|
+
} : {};
|
|
47
|
+
const cardStyle = {
|
|
48
|
+
background: "rgba(20, 20, 30, 0.85)",
|
|
49
|
+
backdropFilter: "blur(16px)",
|
|
50
|
+
WebkitBackdropFilter: "blur(16px)",
|
|
51
|
+
border: "1px solid rgba(255, 255, 255, 0.08)",
|
|
52
|
+
borderRadius: 12,
|
|
53
|
+
padding: isInline ? void 0 : "24px 28px",
|
|
54
|
+
maxWidth: isFullscreen ? 480 : "100%",
|
|
55
|
+
width: isFullscreen ? "90%" : void 0,
|
|
56
|
+
color: "rgba(255, 255, 255, 0.9)",
|
|
57
|
+
fontFamily: "system-ui, -apple-system, sans-serif"
|
|
58
|
+
};
|
|
59
|
+
if (isInline) {
|
|
60
|
+
return /* @__PURE__ */ jsxs("span", { style: containerStyle, children: [
|
|
61
|
+
/* @__PURE__ */ jsxs("span", { style: { color: "rgba(255, 100, 100, 0.9)", fontSize: 12 }, children: [
|
|
62
|
+
"Error: ",
|
|
63
|
+
error.message
|
|
64
|
+
] }),
|
|
65
|
+
/* @__PURE__ */ jsx(
|
|
66
|
+
"button",
|
|
67
|
+
{
|
|
68
|
+
onClick: reset,
|
|
69
|
+
style: {
|
|
70
|
+
background: "none",
|
|
71
|
+
border: "none",
|
|
72
|
+
color: "rgba(100, 180, 255, 0.9)",
|
|
73
|
+
cursor: "pointer",
|
|
74
|
+
fontSize: 12,
|
|
75
|
+
textDecoration: "underline",
|
|
76
|
+
padding: 0
|
|
77
|
+
},
|
|
78
|
+
children: "Retry"
|
|
79
|
+
}
|
|
80
|
+
)
|
|
81
|
+
] });
|
|
82
|
+
}
|
|
83
|
+
return /* @__PURE__ */ jsx("div", { style: containerStyle, children: /* @__PURE__ */ jsxs("div", { style: cardStyle, children: [
|
|
84
|
+
/* @__PURE__ */ jsxs("div", { style: { display: "flex", alignItems: "center", gap: 8, marginBottom: 12 }, children: [
|
|
85
|
+
/* @__PURE__ */ jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "rgba(255, 100, 100, 0.9)", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
86
|
+
/* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "10" }),
|
|
87
|
+
/* @__PURE__ */ jsx("line", { x1: "12", y1: "8", x2: "12", y2: "12" }),
|
|
88
|
+
/* @__PURE__ */ jsx("line", { x1: "12", y1: "16", x2: "12.01", y2: "16" })
|
|
89
|
+
] }),
|
|
90
|
+
/* @__PURE__ */ jsx("span", { style: { fontWeight: 600, fontSize: 15 }, children: "Something went wrong" })
|
|
91
|
+
] }),
|
|
92
|
+
/* @__PURE__ */ jsx("p", { style: { color: "rgba(255, 255, 255, 0.5)", fontSize: 13, lineHeight: 1.5, margin: "0 0 16px", wordBreak: "break-word" }, children: error.message }),
|
|
93
|
+
/* @__PURE__ */ jsx(
|
|
94
|
+
"button",
|
|
95
|
+
{
|
|
96
|
+
onClick: reset,
|
|
97
|
+
style: {
|
|
98
|
+
background: "rgba(255, 255, 255, 0.08)",
|
|
99
|
+
border: "1px solid rgba(255, 255, 255, 0.12)",
|
|
100
|
+
borderRadius: 8,
|
|
101
|
+
padding: "8px 16px",
|
|
102
|
+
color: "rgba(255, 255, 255, 0.9)",
|
|
103
|
+
cursor: "pointer",
|
|
104
|
+
fontSize: 13,
|
|
105
|
+
fontWeight: 500,
|
|
106
|
+
transition: "background 0.15s"
|
|
107
|
+
},
|
|
108
|
+
onMouseEnter: (e) => {
|
|
109
|
+
e.currentTarget.style.background = "rgba(255, 255, 255, 0.14)";
|
|
110
|
+
},
|
|
111
|
+
onMouseLeave: (e) => {
|
|
112
|
+
e.currentTarget.style.background = "rgba(255, 255, 255, 0.08)";
|
|
113
|
+
},
|
|
114
|
+
children: "Try again"
|
|
115
|
+
}
|
|
116
|
+
)
|
|
117
|
+
] }) });
|
|
118
|
+
}
|
|
119
|
+
var GliaErrorBoundary = class extends Component {
|
|
120
|
+
static displayName = "GliaErrorBoundary";
|
|
121
|
+
autoRetryTimer = null;
|
|
122
|
+
constructor(props) {
|
|
123
|
+
super(props);
|
|
124
|
+
this.state = { error: null };
|
|
125
|
+
}
|
|
126
|
+
static getDerivedStateFromError(error) {
|
|
127
|
+
return { error };
|
|
128
|
+
}
|
|
129
|
+
componentDidCatch(error, errorInfo) {
|
|
130
|
+
this.props.onError?.(error, errorInfo);
|
|
131
|
+
if (this.props.autoRetryMs && this.props.autoRetryMs > 0) {
|
|
132
|
+
this.autoRetryTimer = setTimeout(() => {
|
|
133
|
+
this.reset();
|
|
134
|
+
}, this.props.autoRetryMs);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
componentWillUnmount() {
|
|
138
|
+
if (this.autoRetryTimer) {
|
|
139
|
+
clearTimeout(this.autoRetryTimer);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
reset = () => {
|
|
143
|
+
if (this.autoRetryTimer) {
|
|
144
|
+
clearTimeout(this.autoRetryTimer);
|
|
145
|
+
this.autoRetryTimer = null;
|
|
146
|
+
}
|
|
147
|
+
this.setState({ error: null });
|
|
148
|
+
};
|
|
149
|
+
render() {
|
|
150
|
+
const { error } = this.state;
|
|
151
|
+
const { children, fallback, variant = "card" } = this.props;
|
|
152
|
+
if (error) {
|
|
153
|
+
if (typeof fallback === "function") {
|
|
154
|
+
return fallback({ error, reset: this.reset });
|
|
155
|
+
}
|
|
156
|
+
if (fallback !== void 0) {
|
|
157
|
+
return fallback;
|
|
158
|
+
}
|
|
159
|
+
return /* @__PURE__ */ jsx(DefaultFallback, { error, reset: this.reset, variant });
|
|
160
|
+
}
|
|
161
|
+
return /* @__PURE__ */ jsx(ErrorThrower, { children });
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
var BBContext = createContext(null);
|
|
165
|
+
function BBProvider({
|
|
166
|
+
children,
|
|
167
|
+
config,
|
|
168
|
+
agents = [],
|
|
169
|
+
initialSyncStatus = "synced"
|
|
170
|
+
}) {
|
|
171
|
+
const [activeRuns, setActiveRuns] = useState([]);
|
|
172
|
+
const [runHistory, setRunHistory] = useState([]);
|
|
173
|
+
const [syncStatus, setSyncStatus] = useState(initialSyncStatus);
|
|
174
|
+
const totalCost = useMemo(() => {
|
|
175
|
+
return runHistory.reduce((sum, run) => sum + (run.cost ?? 0), 0);
|
|
176
|
+
}, [runHistory]);
|
|
177
|
+
const addRun = useCallback((run) => {
|
|
178
|
+
setActiveRuns((prev) => [...prev, run]);
|
|
179
|
+
setRunHistory((prev) => [...prev, run]);
|
|
180
|
+
}, []);
|
|
181
|
+
const updateRun = useCallback((runId, updates) => {
|
|
182
|
+
const updateInList = (runs) => runs.map((run) => run.id === runId ? { ...run, ...updates } : run);
|
|
183
|
+
setActiveRuns((prev) => {
|
|
184
|
+
const updated = updateInList(prev);
|
|
185
|
+
return updated.filter(
|
|
186
|
+
(run) => run.status === "idle" || run.status === "running"
|
|
187
|
+
);
|
|
188
|
+
});
|
|
189
|
+
setRunHistory(updateInList);
|
|
190
|
+
}, []);
|
|
191
|
+
const getAgent = useCallback(
|
|
192
|
+
(agentId) => agents.find((a) => a.id === agentId),
|
|
193
|
+
[agents]
|
|
194
|
+
);
|
|
195
|
+
const value = useMemo(
|
|
196
|
+
() => ({
|
|
197
|
+
config,
|
|
198
|
+
agents,
|
|
199
|
+
activeRuns,
|
|
200
|
+
runHistory,
|
|
201
|
+
totalCost,
|
|
202
|
+
syncStatus,
|
|
203
|
+
addRun,
|
|
204
|
+
updateRun,
|
|
205
|
+
setSyncStatus,
|
|
206
|
+
getAgent
|
|
207
|
+
}),
|
|
208
|
+
[
|
|
209
|
+
config,
|
|
210
|
+
agents,
|
|
211
|
+
activeRuns,
|
|
212
|
+
runHistory,
|
|
213
|
+
totalCost,
|
|
214
|
+
syncStatus,
|
|
215
|
+
addRun,
|
|
216
|
+
updateRun,
|
|
217
|
+
getAgent
|
|
218
|
+
]
|
|
219
|
+
);
|
|
220
|
+
return /* @__PURE__ */ jsx(BBContext.Provider, { value, children: /* @__PURE__ */ jsx(GliaErrorBoundary, { variant: "fullscreen", children }) });
|
|
221
|
+
}
|
|
222
|
+
function useBBContext() {
|
|
223
|
+
const context = useContext(BBContext);
|
|
224
|
+
if (!context) {
|
|
225
|
+
throw new Error("useBBContext must be used within a BBProvider");
|
|
226
|
+
}
|
|
227
|
+
return context;
|
|
228
|
+
}
|
|
229
|
+
function useBBContextOptional() {
|
|
230
|
+
return useContext(BBContext);
|
|
231
|
+
}
|
|
232
|
+
function stableStringify(value) {
|
|
233
|
+
if (value === null || typeof value !== "object") {
|
|
234
|
+
const encoded = JSON.stringify(value);
|
|
235
|
+
return encoded === void 0 ? "null" : encoded;
|
|
236
|
+
}
|
|
237
|
+
if (Array.isArray(value)) {
|
|
238
|
+
return `[${value.map(stableStringify).join(",")}]`;
|
|
239
|
+
}
|
|
240
|
+
const record = value;
|
|
241
|
+
const keys = Object.keys(record).sort();
|
|
242
|
+
return `{${keys.map((k) => `${JSON.stringify(k)}:${stableStringify(record[k])}`).join(",")}}`;
|
|
243
|
+
}
|
|
244
|
+
function hashString(input) {
|
|
245
|
+
let hash = 2166136261;
|
|
246
|
+
for (let i = 0; i < input.length; i++) {
|
|
247
|
+
hash ^= input.charCodeAt(i);
|
|
248
|
+
hash = hash * 16777619 >>> 0;
|
|
249
|
+
}
|
|
250
|
+
return hash.toString(36);
|
|
251
|
+
}
|
|
252
|
+
function hashData(value) {
|
|
253
|
+
return hashString(stableStringify(value));
|
|
254
|
+
}
|
|
255
|
+
function normalizeStoredData(raw) {
|
|
256
|
+
if (!raw || typeof raw !== "object") return null;
|
|
257
|
+
const record = raw;
|
|
258
|
+
if ("data" in record && typeof record.lastModifiedAt === "number" && typeof record.lastSyncedAt === "number" && typeof record.lastSyncedHash === "string") {
|
|
259
|
+
return record;
|
|
260
|
+
}
|
|
261
|
+
if ("data" in record && typeof record.timestamp === "number" && typeof record.version === "number") {
|
|
262
|
+
const legacy = record;
|
|
263
|
+
const syncedHash = hashData(legacy.data);
|
|
264
|
+
return {
|
|
265
|
+
data: legacy.data,
|
|
266
|
+
lastModifiedAt: legacy.timestamp,
|
|
267
|
+
lastSyncedAt: legacy.timestamp,
|
|
268
|
+
lastSyncedHash: syncedHash
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
return null;
|
|
272
|
+
}
|
|
273
|
+
function getStoredData(key) {
|
|
274
|
+
try {
|
|
275
|
+
const raw = localStorage.getItem(key);
|
|
276
|
+
if (!raw) return null;
|
|
277
|
+
const parsed = JSON.parse(raw);
|
|
278
|
+
return normalizeStoredData(parsed);
|
|
279
|
+
} catch {
|
|
280
|
+
return null;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
function setStoredData(key, record) {
|
|
284
|
+
localStorage.setItem(key, JSON.stringify(record));
|
|
285
|
+
}
|
|
286
|
+
function useSync({
|
|
287
|
+
key,
|
|
288
|
+
endpoint,
|
|
289
|
+
debounce = 2e3,
|
|
290
|
+
initialData,
|
|
291
|
+
fetcher,
|
|
292
|
+
saver,
|
|
293
|
+
onConflict,
|
|
294
|
+
onError,
|
|
295
|
+
onSync
|
|
296
|
+
}) {
|
|
297
|
+
const [data, setDataState] = useState(initialData ?? null);
|
|
298
|
+
const [status, setStatus] = useState("synced");
|
|
299
|
+
const [pendingChanges, setPendingChanges] = useState(0);
|
|
300
|
+
const [lastSyncedAt, setLastSyncedAt] = useState(null);
|
|
301
|
+
const [conflict, setConflict] = useState(null);
|
|
302
|
+
const [isLoaded, setIsLoaded] = useState(false);
|
|
303
|
+
const debounceTimerRef = useRef(null);
|
|
304
|
+
const isSavingRef = useRef(false);
|
|
305
|
+
const doFetch = useCallback(
|
|
306
|
+
async (url) => {
|
|
307
|
+
if (fetcher) return fetcher(url);
|
|
308
|
+
const response = await fetch(url);
|
|
309
|
+
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
310
|
+
return response.json();
|
|
311
|
+
},
|
|
312
|
+
[fetcher]
|
|
313
|
+
);
|
|
314
|
+
const doSave = useCallback(
|
|
315
|
+
async (url, payload) => {
|
|
316
|
+
if (saver) return saver(url, payload);
|
|
317
|
+
const response = await fetch(url, {
|
|
318
|
+
method: "PUT",
|
|
319
|
+
headers: { "Content-Type": "application/json" },
|
|
320
|
+
body: JSON.stringify(payload)
|
|
321
|
+
});
|
|
322
|
+
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
323
|
+
return response.json();
|
|
324
|
+
},
|
|
325
|
+
[saver]
|
|
326
|
+
);
|
|
327
|
+
useEffect(() => {
|
|
328
|
+
const loadInitial = async () => {
|
|
329
|
+
const stored = getStoredData(key);
|
|
330
|
+
if (stored) {
|
|
331
|
+
setDataState(stored.data);
|
|
332
|
+
const storedSyncedAt = stored.lastSyncedAt > 0 ? stored.lastSyncedAt : null;
|
|
333
|
+
setLastSyncedAt(storedSyncedAt);
|
|
334
|
+
const hasLocalChanges = stored.lastModifiedAt > stored.lastSyncedAt;
|
|
335
|
+
if (hasLocalChanges) {
|
|
336
|
+
setStatus("pending");
|
|
337
|
+
setPendingChanges((c) => Math.max(c, 1));
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
try {
|
|
341
|
+
const serverData = await doFetch(endpoint);
|
|
342
|
+
const remoteTimestamp = Date.now();
|
|
343
|
+
const remoteHash = hashData(serverData);
|
|
344
|
+
if (stored) {
|
|
345
|
+
const hasLocalChanges = stored.lastModifiedAt > stored.lastSyncedAt;
|
|
346
|
+
const baselineHash = stored.lastSyncedHash || hashData(stored.data);
|
|
347
|
+
const remoteChangedSinceSync = remoteHash !== baselineHash;
|
|
348
|
+
if (hasLocalChanges && remoteChangedSinceSync) {
|
|
349
|
+
const localConflict = {
|
|
350
|
+
local: stored.data,
|
|
351
|
+
remote: serverData,
|
|
352
|
+
localTimestamp: stored.lastModifiedAt,
|
|
353
|
+
remoteTimestamp
|
|
354
|
+
};
|
|
355
|
+
setConflict(localConflict);
|
|
356
|
+
setStatus("conflict");
|
|
357
|
+
onConflict?.(localConflict);
|
|
358
|
+
} else if (!hasLocalChanges) {
|
|
359
|
+
setDataState(serverData);
|
|
360
|
+
setStoredData(key, {
|
|
361
|
+
data: serverData,
|
|
362
|
+
lastModifiedAt: remoteTimestamp,
|
|
363
|
+
lastSyncedAt: remoteTimestamp,
|
|
364
|
+
lastSyncedHash: remoteHash
|
|
365
|
+
});
|
|
366
|
+
setLastSyncedAt(remoteTimestamp);
|
|
367
|
+
setPendingChanges(0);
|
|
368
|
+
setStatus("synced");
|
|
369
|
+
} else {
|
|
370
|
+
setStatus("pending");
|
|
371
|
+
}
|
|
372
|
+
} else {
|
|
373
|
+
setDataState(serverData);
|
|
374
|
+
setStoredData(key, {
|
|
375
|
+
data: serverData,
|
|
376
|
+
lastModifiedAt: remoteTimestamp,
|
|
377
|
+
lastSyncedAt: remoteTimestamp,
|
|
378
|
+
lastSyncedHash: remoteHash
|
|
379
|
+
});
|
|
380
|
+
setLastSyncedAt(remoteTimestamp);
|
|
381
|
+
setPendingChanges(0);
|
|
382
|
+
setStatus("synced");
|
|
383
|
+
}
|
|
384
|
+
} catch (error) {
|
|
385
|
+
setStatus("offline");
|
|
386
|
+
if (error instanceof Error) {
|
|
387
|
+
onError?.(error);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
setIsLoaded(true);
|
|
391
|
+
};
|
|
392
|
+
loadInitial();
|
|
393
|
+
}, [key, endpoint, doFetch, onConflict, onError]);
|
|
394
|
+
const saveToServer = useCallback(async (payload) => {
|
|
395
|
+
const dataToSave = payload ?? data;
|
|
396
|
+
if (isSavingRef.current || dataToSave === null) return;
|
|
397
|
+
isSavingRef.current = true;
|
|
398
|
+
try {
|
|
399
|
+
setStatus("pending");
|
|
400
|
+
const serverData = await doSave(endpoint, dataToSave);
|
|
401
|
+
const syncedAt = Date.now();
|
|
402
|
+
const syncedHash = hashData(serverData);
|
|
403
|
+
setDataState(serverData);
|
|
404
|
+
setStoredData(key, {
|
|
405
|
+
data: serverData,
|
|
406
|
+
lastModifiedAt: syncedAt,
|
|
407
|
+
lastSyncedAt: syncedAt,
|
|
408
|
+
lastSyncedHash: syncedHash
|
|
409
|
+
});
|
|
410
|
+
setLastSyncedAt(syncedAt);
|
|
411
|
+
setPendingChanges(0);
|
|
412
|
+
setStatus("synced");
|
|
413
|
+
onSync?.(serverData);
|
|
414
|
+
} catch (error) {
|
|
415
|
+
setStatus("offline");
|
|
416
|
+
if (error instanceof Error) {
|
|
417
|
+
onError?.(error);
|
|
418
|
+
}
|
|
419
|
+
} finally {
|
|
420
|
+
isSavingRef.current = false;
|
|
421
|
+
}
|
|
422
|
+
}, [data, endpoint, key, doSave, onSync, onError]);
|
|
423
|
+
const setData = useCallback(
|
|
424
|
+
(updater) => {
|
|
425
|
+
setDataState((prev) => {
|
|
426
|
+
const newData = typeof updater === "function" ? updater(prev) : updater;
|
|
427
|
+
const previousStored = getStoredData(key);
|
|
428
|
+
const now = Date.now();
|
|
429
|
+
setStoredData(key, {
|
|
430
|
+
data: newData,
|
|
431
|
+
lastModifiedAt: now,
|
|
432
|
+
lastSyncedAt: previousStored?.lastSyncedAt ?? 0,
|
|
433
|
+
lastSyncedHash: previousStored?.lastSyncedHash ?? ""
|
|
434
|
+
});
|
|
435
|
+
setPendingChanges((c) => c + 1);
|
|
436
|
+
setStatus("pending");
|
|
437
|
+
if (debounceTimerRef.current) {
|
|
438
|
+
clearTimeout(debounceTimerRef.current);
|
|
439
|
+
}
|
|
440
|
+
debounceTimerRef.current = setTimeout(() => {
|
|
441
|
+
saveToServer();
|
|
442
|
+
}, debounce);
|
|
443
|
+
return newData;
|
|
444
|
+
});
|
|
445
|
+
},
|
|
446
|
+
[key, debounce, saveToServer]
|
|
447
|
+
);
|
|
448
|
+
const forceSave = useCallback(async () => {
|
|
449
|
+
if (debounceTimerRef.current) {
|
|
450
|
+
clearTimeout(debounceTimerRef.current);
|
|
451
|
+
debounceTimerRef.current = null;
|
|
452
|
+
}
|
|
453
|
+
await saveToServer();
|
|
454
|
+
}, [saveToServer]);
|
|
455
|
+
const refresh = useCallback(async () => {
|
|
456
|
+
try {
|
|
457
|
+
const serverData = await doFetch(endpoint);
|
|
458
|
+
const syncedAt = Date.now();
|
|
459
|
+
const syncedHash = hashData(serverData);
|
|
460
|
+
setDataState(serverData);
|
|
461
|
+
setStoredData(key, {
|
|
462
|
+
data: serverData,
|
|
463
|
+
lastModifiedAt: syncedAt,
|
|
464
|
+
lastSyncedAt: syncedAt,
|
|
465
|
+
lastSyncedHash: syncedHash
|
|
466
|
+
});
|
|
467
|
+
setLastSyncedAt(syncedAt);
|
|
468
|
+
setPendingChanges(0);
|
|
469
|
+
setConflict(null);
|
|
470
|
+
setStatus("synced");
|
|
471
|
+
} catch (error) {
|
|
472
|
+
setStatus("offline");
|
|
473
|
+
if (error instanceof Error) {
|
|
474
|
+
onError?.(error);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}, [endpoint, key, doFetch, onError]);
|
|
478
|
+
const resolveConflict = useCallback(
|
|
479
|
+
async (resolution) => {
|
|
480
|
+
if (!conflict) return;
|
|
481
|
+
switch (resolution) {
|
|
482
|
+
case "keep_local":
|
|
483
|
+
setDataState(conflict.local);
|
|
484
|
+
setConflict(null);
|
|
485
|
+
setStatus("pending");
|
|
486
|
+
setPendingChanges((c) => Math.max(c, 1));
|
|
487
|
+
await saveToServer(conflict.local);
|
|
488
|
+
break;
|
|
489
|
+
case "use_remote": {
|
|
490
|
+
const remoteHash = hashData(conflict.remote);
|
|
491
|
+
setDataState(conflict.remote);
|
|
492
|
+
setStoredData(key, {
|
|
493
|
+
data: conflict.remote,
|
|
494
|
+
lastModifiedAt: conflict.remoteTimestamp,
|
|
495
|
+
lastSyncedAt: conflict.remoteTimestamp,
|
|
496
|
+
lastSyncedHash: remoteHash
|
|
497
|
+
});
|
|
498
|
+
setLastSyncedAt(conflict.remoteTimestamp);
|
|
499
|
+
setPendingChanges(0);
|
|
500
|
+
setConflict(null);
|
|
501
|
+
setStatus("synced");
|
|
502
|
+
break;
|
|
503
|
+
}
|
|
504
|
+
case "create_copy":
|
|
505
|
+
setDataState(conflict.local);
|
|
506
|
+
setConflict(null);
|
|
507
|
+
setStatus("pending");
|
|
508
|
+
setPendingChanges((c) => Math.max(c, 1));
|
|
509
|
+
await saveToServer(conflict.local);
|
|
510
|
+
break;
|
|
511
|
+
}
|
|
512
|
+
},
|
|
513
|
+
[conflict, key, saveToServer]
|
|
514
|
+
);
|
|
515
|
+
useEffect(() => {
|
|
516
|
+
return () => {
|
|
517
|
+
if (debounceTimerRef.current) {
|
|
518
|
+
clearTimeout(debounceTimerRef.current);
|
|
519
|
+
}
|
|
520
|
+
};
|
|
521
|
+
}, []);
|
|
522
|
+
return {
|
|
523
|
+
data,
|
|
524
|
+
setData,
|
|
525
|
+
status,
|
|
526
|
+
pendingChanges,
|
|
527
|
+
lastSyncedAt,
|
|
528
|
+
conflict,
|
|
529
|
+
resolveConflict,
|
|
530
|
+
forceSave,
|
|
531
|
+
refresh,
|
|
532
|
+
isLoaded
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
function SyncDocument({
|
|
536
|
+
documentId,
|
|
537
|
+
endpoint,
|
|
538
|
+
debounce = 1e3,
|
|
539
|
+
initialContent,
|
|
540
|
+
onConflict,
|
|
541
|
+
onError,
|
|
542
|
+
onSave,
|
|
543
|
+
children,
|
|
544
|
+
fetcher,
|
|
545
|
+
saver
|
|
546
|
+
}) {
|
|
547
|
+
const fullEndpoint = `${endpoint}/${documentId}`;
|
|
548
|
+
const {
|
|
549
|
+
data,
|
|
550
|
+
setData,
|
|
551
|
+
status,
|
|
552
|
+
pendingChanges,
|
|
553
|
+
lastSyncedAt,
|
|
554
|
+
conflict,
|
|
555
|
+
resolveConflict,
|
|
556
|
+
forceSave,
|
|
557
|
+
refresh,
|
|
558
|
+
isLoaded
|
|
559
|
+
} = useSync({
|
|
560
|
+
key: `sync-doc:${documentId}`,
|
|
561
|
+
endpoint: fullEndpoint,
|
|
562
|
+
debounce,
|
|
563
|
+
initialData: initialContent,
|
|
564
|
+
fetcher,
|
|
565
|
+
saver,
|
|
566
|
+
onConflict: onConflict ? (c) => {
|
|
567
|
+
} : void 0,
|
|
568
|
+
onError,
|
|
569
|
+
onSync: onSave
|
|
570
|
+
});
|
|
571
|
+
const conflictUI = conflict && onConflict ? onConflict(conflict.local, conflict.remote, resolveConflict) : null;
|
|
572
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
573
|
+
conflictUI,
|
|
574
|
+
children({
|
|
575
|
+
content: data,
|
|
576
|
+
setContent: setData,
|
|
577
|
+
status,
|
|
578
|
+
lastSaved: lastSyncedAt,
|
|
579
|
+
pendingChanges,
|
|
580
|
+
save: forceSave,
|
|
581
|
+
refresh,
|
|
582
|
+
isLoaded
|
|
583
|
+
})
|
|
584
|
+
] });
|
|
585
|
+
}
|
|
586
|
+
function useAgentRun(options = {}) {
|
|
587
|
+
const { onStart, onComplete, onError, onCancel } = options;
|
|
588
|
+
const { config, addRun, updateRun, getAgent } = useBBContext();
|
|
589
|
+
const [run, setRun] = useState(null);
|
|
590
|
+
const [status, setStatus] = useState("idle");
|
|
591
|
+
const [output, setOutput] = useState(null);
|
|
592
|
+
const [error, setError] = useState(null);
|
|
593
|
+
const [cost, setCost] = useState(null);
|
|
594
|
+
const [latency, setLatency] = useState(null);
|
|
595
|
+
const abortControllerRef = useRef(null);
|
|
596
|
+
const start = useCallback(
|
|
597
|
+
async (agentId, prompt, context) => {
|
|
598
|
+
if (abortControllerRef.current) {
|
|
599
|
+
abortControllerRef.current.abort();
|
|
600
|
+
}
|
|
601
|
+
const controller = new AbortController();
|
|
602
|
+
abortControllerRef.current = controller;
|
|
603
|
+
const runId = `run-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`;
|
|
604
|
+
const startedAt = Date.now();
|
|
605
|
+
const newRun = {
|
|
606
|
+
id: runId,
|
|
607
|
+
agentId,
|
|
608
|
+
prompt,
|
|
609
|
+
context,
|
|
610
|
+
status: "running",
|
|
611
|
+
startedAt
|
|
612
|
+
};
|
|
613
|
+
setRun(newRun);
|
|
614
|
+
setStatus("running");
|
|
615
|
+
setOutput(null);
|
|
616
|
+
setError(null);
|
|
617
|
+
setCost(null);
|
|
618
|
+
setLatency(null);
|
|
619
|
+
addRun(newRun);
|
|
620
|
+
onStart?.(newRun);
|
|
621
|
+
try {
|
|
622
|
+
const response = await fetch(`${config.apiBaseUrl}/runs`, {
|
|
623
|
+
method: "POST",
|
|
624
|
+
headers: {
|
|
625
|
+
"Content-Type": "application/json",
|
|
626
|
+
...config.headers
|
|
627
|
+
},
|
|
628
|
+
body: JSON.stringify({
|
|
629
|
+
agentId,
|
|
630
|
+
prompt,
|
|
631
|
+
context
|
|
632
|
+
}),
|
|
633
|
+
signal: controller.signal
|
|
634
|
+
});
|
|
635
|
+
if (!response.ok) {
|
|
636
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
637
|
+
}
|
|
638
|
+
const result = await response.json();
|
|
639
|
+
const completedAt = Date.now();
|
|
640
|
+
const runLatency = completedAt - startedAt;
|
|
641
|
+
const agent = getAgent(agentId);
|
|
642
|
+
const runCost = result.cost ?? agent?.costPerRun ?? 0;
|
|
643
|
+
const completedRun = {
|
|
644
|
+
...newRun,
|
|
645
|
+
status: "completed",
|
|
646
|
+
output: result.output,
|
|
647
|
+
cost: runCost,
|
|
648
|
+
tokenCount: result.tokenCount,
|
|
649
|
+
latencyMs: runLatency,
|
|
650
|
+
completedAt
|
|
651
|
+
};
|
|
652
|
+
setRun(completedRun);
|
|
653
|
+
setStatus("completed");
|
|
654
|
+
setOutput(result.output);
|
|
655
|
+
setCost(runCost);
|
|
656
|
+
setLatency(runLatency);
|
|
657
|
+
updateRun(runId, completedRun);
|
|
658
|
+
onComplete?.(completedRun);
|
|
659
|
+
} catch (err) {
|
|
660
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
661
|
+
const cancelledRun = {
|
|
662
|
+
...newRun,
|
|
663
|
+
status: "cancelled",
|
|
664
|
+
completedAt: Date.now()
|
|
665
|
+
};
|
|
666
|
+
setRun(cancelledRun);
|
|
667
|
+
setStatus("cancelled");
|
|
668
|
+
updateRun(runId, cancelledRun);
|
|
669
|
+
onCancel?.(cancelledRun);
|
|
670
|
+
return;
|
|
671
|
+
}
|
|
672
|
+
const errorMessage = err instanceof Error ? err.message : "Unknown error";
|
|
673
|
+
const failedRun = {
|
|
674
|
+
...newRun,
|
|
675
|
+
status: "failed",
|
|
676
|
+
error: errorMessage,
|
|
677
|
+
completedAt: Date.now()
|
|
678
|
+
};
|
|
679
|
+
setRun(failedRun);
|
|
680
|
+
setStatus("failed");
|
|
681
|
+
setError(errorMessage);
|
|
682
|
+
updateRun(runId, failedRun);
|
|
683
|
+
onError?.(failedRun, err instanceof Error ? err : new Error(errorMessage));
|
|
684
|
+
} finally {
|
|
685
|
+
if (abortControllerRef.current === controller) {
|
|
686
|
+
abortControllerRef.current = null;
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
},
|
|
690
|
+
[config, addRun, updateRun, getAgent, onStart, onComplete, onError, onCancel]
|
|
691
|
+
);
|
|
692
|
+
const cancel = useCallback(() => {
|
|
693
|
+
if (abortControllerRef.current) {
|
|
694
|
+
abortControllerRef.current.abort();
|
|
695
|
+
abortControllerRef.current = null;
|
|
696
|
+
}
|
|
697
|
+
}, []);
|
|
698
|
+
return {
|
|
699
|
+
run,
|
|
700
|
+
status,
|
|
701
|
+
output,
|
|
702
|
+
error,
|
|
703
|
+
cost,
|
|
704
|
+
latency,
|
|
705
|
+
start,
|
|
706
|
+
cancel,
|
|
707
|
+
isRunning: status === "running"
|
|
708
|
+
};
|
|
709
|
+
}
|
|
710
|
+
function AgentPanel({
|
|
711
|
+
context,
|
|
712
|
+
quickPrompts = [],
|
|
713
|
+
onRunStart,
|
|
714
|
+
onRunComplete,
|
|
715
|
+
onRunError,
|
|
716
|
+
showCosts = true,
|
|
717
|
+
showHistory = true,
|
|
718
|
+
maxHistory = 10,
|
|
719
|
+
placeholder = "Enter a prompt...",
|
|
720
|
+
className,
|
|
721
|
+
agentFilter,
|
|
722
|
+
defaultAgent
|
|
723
|
+
}) {
|
|
724
|
+
const { agents, runHistory, totalCost: globalTotalCost } = useBBContext();
|
|
725
|
+
const availableAgents = agentFilter ? agents.filter(agentFilter) : agents;
|
|
726
|
+
const [selectedAgentId, setSelectedAgentId] = useState(
|
|
727
|
+
defaultAgent ?? availableAgents[0]?.id ?? null
|
|
728
|
+
);
|
|
729
|
+
const [prompt, setPrompt] = useState("");
|
|
730
|
+
const selectedAgent = availableAgents.find((a) => a.id === selectedAgentId) ?? null;
|
|
731
|
+
const {
|
|
732
|
+
run: currentRun,
|
|
733
|
+
status,
|
|
734
|
+
isRunning,
|
|
735
|
+
start
|
|
736
|
+
} = useAgentRun({
|
|
737
|
+
onStart: onRunStart,
|
|
738
|
+
onComplete: onRunComplete,
|
|
739
|
+
onError: onRunError
|
|
740
|
+
});
|
|
741
|
+
const panelHistory = runHistory.filter((run) => availableAgents.some((a) => a.id === run.agentId)).slice(0, maxHistory);
|
|
742
|
+
const panelTotalCost = panelHistory.reduce((sum, run) => sum + (run.cost ?? 0), 0);
|
|
743
|
+
const estimatedCost = selectedAgent?.costPerRun ?? null;
|
|
744
|
+
const handleSubmit = useCallback(
|
|
745
|
+
(e) => {
|
|
746
|
+
e?.preventDefault();
|
|
747
|
+
if (!selectedAgentId || !prompt.trim() || isRunning) return;
|
|
748
|
+
start(selectedAgentId, prompt, context);
|
|
749
|
+
setPrompt("");
|
|
750
|
+
},
|
|
751
|
+
[selectedAgentId, prompt, isRunning, start, context]
|
|
752
|
+
);
|
|
753
|
+
const executeQuickPrompt = useCallback(
|
|
754
|
+
(qp) => {
|
|
755
|
+
if (!selectedAgentId || isRunning) return;
|
|
756
|
+
start(selectedAgentId, qp.prompt, context);
|
|
757
|
+
},
|
|
758
|
+
[selectedAgentId, isRunning, start, context]
|
|
759
|
+
);
|
|
760
|
+
const selectAgent = useCallback((agentId) => {
|
|
761
|
+
setSelectedAgentId(agentId);
|
|
762
|
+
}, []);
|
|
763
|
+
return /* @__PURE__ */ jsxs("div", { className: `bb-agent-panel ${className ?? ""}`, "data-bb-state": status, children: [
|
|
764
|
+
/* @__PURE__ */ jsx("div", { className: "bb-agent-panel__agents", children: availableAgents.map((agent) => /* @__PURE__ */ jsxs(
|
|
765
|
+
"button",
|
|
766
|
+
{
|
|
767
|
+
type: "button",
|
|
768
|
+
className: `bb-agent-panel__agent ${agent.id === selectedAgentId ? "bb-agent-panel__agent--selected" : ""}`,
|
|
769
|
+
onClick: () => selectAgent(agent.id),
|
|
770
|
+
disabled: isRunning,
|
|
771
|
+
"data-bb-agent-id": agent.id,
|
|
772
|
+
children: [
|
|
773
|
+
/* @__PURE__ */ jsx("span", { className: "bb-agent-panel__agent-name", children: agent.name }),
|
|
774
|
+
showCosts && agent.costPerRun !== void 0 && /* @__PURE__ */ jsxs("span", { className: "bb-agent-panel__agent-cost", children: [
|
|
775
|
+
"$",
|
|
776
|
+
agent.costPerRun.toFixed(3)
|
|
777
|
+
] })
|
|
778
|
+
]
|
|
779
|
+
},
|
|
780
|
+
agent.id
|
|
781
|
+
)) }),
|
|
782
|
+
quickPrompts.length > 0 && /* @__PURE__ */ jsx("div", { className: "bb-agent-panel__quick-prompts", children: quickPrompts.map((qp, idx) => /* @__PURE__ */ jsxs(
|
|
783
|
+
"button",
|
|
784
|
+
{
|
|
785
|
+
type: "button",
|
|
786
|
+
className: "bb-agent-panel__quick-prompt",
|
|
787
|
+
onClick: () => executeQuickPrompt(qp),
|
|
788
|
+
disabled: isRunning || !selectedAgentId,
|
|
789
|
+
children: [
|
|
790
|
+
qp.icon && /* @__PURE__ */ jsx("span", { className: "bb-agent-panel__quick-prompt-icon", children: qp.icon }),
|
|
791
|
+
/* @__PURE__ */ jsx("span", { className: "bb-agent-panel__quick-prompt-label", children: qp.label })
|
|
792
|
+
]
|
|
793
|
+
},
|
|
794
|
+
idx
|
|
795
|
+
)) }),
|
|
796
|
+
/* @__PURE__ */ jsxs("form", { className: "bb-agent-panel__form", onSubmit: handleSubmit, children: [
|
|
797
|
+
/* @__PURE__ */ jsx(
|
|
798
|
+
"textarea",
|
|
799
|
+
{
|
|
800
|
+
className: "bb-agent-panel__input",
|
|
801
|
+
value: prompt,
|
|
802
|
+
onChange: (e) => setPrompt(e.target.value),
|
|
803
|
+
placeholder,
|
|
804
|
+
disabled: isRunning || !selectedAgentId,
|
|
805
|
+
rows: 3,
|
|
806
|
+
"data-bb-input": "agent-prompt"
|
|
807
|
+
}
|
|
808
|
+
),
|
|
809
|
+
/* @__PURE__ */ jsxs("div", { className: "bb-agent-panel__form-footer", children: [
|
|
810
|
+
showCosts && estimatedCost !== null && /* @__PURE__ */ jsxs("span", { className: "bb-agent-panel__estimate", children: [
|
|
811
|
+
"Est. $",
|
|
812
|
+
estimatedCost.toFixed(3)
|
|
813
|
+
] }),
|
|
814
|
+
/* @__PURE__ */ jsx(
|
|
815
|
+
"button",
|
|
816
|
+
{
|
|
817
|
+
type: "submit",
|
|
818
|
+
className: "bb-agent-panel__submit",
|
|
819
|
+
disabled: isRunning || !selectedAgentId || !prompt.trim(),
|
|
820
|
+
"data-bb-action": "submit-prompt",
|
|
821
|
+
children: isRunning ? "Running..." : "Run"
|
|
822
|
+
}
|
|
823
|
+
)
|
|
824
|
+
] })
|
|
825
|
+
] }),
|
|
826
|
+
currentRun && /* @__PURE__ */ jsxs(
|
|
827
|
+
"div",
|
|
828
|
+
{
|
|
829
|
+
className: `bb-agent-panel__status bb-agent-panel__status--${currentRun.status}`,
|
|
830
|
+
"data-bb-state": currentRun.status,
|
|
831
|
+
children: [
|
|
832
|
+
/* @__PURE__ */ jsxs("span", { className: "bb-agent-panel__status-label", children: [
|
|
833
|
+
currentRun.status === "running" && "Running...",
|
|
834
|
+
currentRun.status === "completed" && "Completed",
|
|
835
|
+
currentRun.status === "failed" && "Failed",
|
|
836
|
+
currentRun.status === "cancelled" && "Cancelled"
|
|
837
|
+
] }),
|
|
838
|
+
currentRun.status === "completed" && currentRun.output && /* @__PURE__ */ jsx("div", { className: "bb-agent-panel__output", "data-bb-output": "agent-output", children: currentRun.output }),
|
|
839
|
+
currentRun.status === "failed" && currentRun.error && /* @__PURE__ */ jsx("div", { className: "bb-agent-panel__error", children: currentRun.error })
|
|
840
|
+
]
|
|
841
|
+
}
|
|
842
|
+
),
|
|
843
|
+
showHistory && panelHistory.length > 0 && /* @__PURE__ */ jsxs("div", { className: "bb-agent-panel__history", children: [
|
|
844
|
+
/* @__PURE__ */ jsx("h4", { className: "bb-agent-panel__history-title", children: "Recent Runs" }),
|
|
845
|
+
/* @__PURE__ */ jsx("ul", { className: "bb-agent-panel__history-list", children: panelHistory.map((run) => /* @__PURE__ */ jsxs(
|
|
846
|
+
"li",
|
|
847
|
+
{
|
|
848
|
+
className: `bb-agent-panel__history-item bb-agent-panel__history-item--${run.status}`,
|
|
849
|
+
"data-bb-entity": "run",
|
|
850
|
+
"data-bb-entity-id": run.id,
|
|
851
|
+
children: [
|
|
852
|
+
/* @__PURE__ */ jsx("span", { className: "bb-agent-panel__history-agent", "data-bb-field": "agent", children: availableAgents.find((a) => a.id === run.agentId)?.name ?? run.agentId }),
|
|
853
|
+
/* @__PURE__ */ jsxs("span", { className: "bb-agent-panel__history-prompt", "data-bb-field": "prompt", children: [
|
|
854
|
+
run.prompt.slice(0, 50),
|
|
855
|
+
run.prompt.length > 50 && "..."
|
|
856
|
+
] }),
|
|
857
|
+
showCosts && run.cost !== void 0 && /* @__PURE__ */ jsxs("span", { className: "bb-agent-panel__history-cost", "data-bb-field": "cost", children: [
|
|
858
|
+
"$",
|
|
859
|
+
run.cost.toFixed(3)
|
|
860
|
+
] })
|
|
861
|
+
]
|
|
862
|
+
},
|
|
863
|
+
run.id
|
|
864
|
+
)) })
|
|
865
|
+
] }),
|
|
866
|
+
showCosts && /* @__PURE__ */ jsxs("div", { className: "bb-agent-panel__cost-summary", children: [
|
|
867
|
+
/* @__PURE__ */ jsx("span", { className: "bb-agent-panel__cost-label", children: "Session Total:" }),
|
|
868
|
+
/* @__PURE__ */ jsxs("span", { className: "bb-agent-panel__cost-value", "data-bb-field": "total-cost", children: [
|
|
869
|
+
"$",
|
|
870
|
+
panelTotalCost.toFixed(3)
|
|
871
|
+
] })
|
|
872
|
+
] })
|
|
873
|
+
] });
|
|
874
|
+
}
|
|
875
|
+
function usePlaySession({
|
|
876
|
+
adapter,
|
|
877
|
+
autoConnect = false,
|
|
878
|
+
timeout = 3e4,
|
|
879
|
+
onConnect,
|
|
880
|
+
onDisconnect,
|
|
881
|
+
onRpcResult,
|
|
882
|
+
onError
|
|
883
|
+
}) {
|
|
884
|
+
const { config } = useBBContext();
|
|
885
|
+
const [session, setSession] = useState(null);
|
|
886
|
+
const [status, setStatus] = useState("disconnected");
|
|
887
|
+
const [videoTrack, setVideoTrack] = useState(null);
|
|
888
|
+
const [audioTrack, setAudioTrack] = useState(null);
|
|
889
|
+
const [error, setError] = useState(null);
|
|
890
|
+
const wsRef = useRef(null);
|
|
891
|
+
const rpcIdRef = useRef(0);
|
|
892
|
+
const pendingCallsRef = useRef(/* @__PURE__ */ new Map());
|
|
893
|
+
const connect = useCallback(
|
|
894
|
+
async (options) => {
|
|
895
|
+
if (status === "connecting" || status === "connected") return;
|
|
896
|
+
setStatus("connecting");
|
|
897
|
+
setError(null);
|
|
898
|
+
const connectTimeout = options?.timeout ?? timeout;
|
|
899
|
+
try {
|
|
900
|
+
const response = await fetch(`${config.apiBaseUrl}/play-sessions`, {
|
|
901
|
+
method: "POST",
|
|
902
|
+
headers: {
|
|
903
|
+
"Content-Type": "application/json",
|
|
904
|
+
...config.headers
|
|
905
|
+
},
|
|
906
|
+
body: JSON.stringify({ adapter })
|
|
907
|
+
});
|
|
908
|
+
if (!response.ok) {
|
|
909
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
910
|
+
}
|
|
911
|
+
const sessionData = await response.json();
|
|
912
|
+
const newSession = {
|
|
913
|
+
id: sessionData.id,
|
|
914
|
+
adapter,
|
|
915
|
+
capabilityToken: sessionData.capabilityToken,
|
|
916
|
+
createdAt: Date.now(),
|
|
917
|
+
expiresAt: sessionData.expiresAt,
|
|
918
|
+
livekitUrl: sessionData.livekitUrl,
|
|
919
|
+
livekitToken: sessionData.livekitToken
|
|
920
|
+
};
|
|
921
|
+
setSession(newSession);
|
|
922
|
+
const wsUrl = sessionData.wsUrl ?? `${config.apiBaseUrl.replace("http", "ws")}/play-sessions/${newSession.id}/ws`;
|
|
923
|
+
const ws = new WebSocket(wsUrl);
|
|
924
|
+
wsRef.current = ws;
|
|
925
|
+
await new Promise((resolve, reject) => {
|
|
926
|
+
const timeoutId = setTimeout(() => {
|
|
927
|
+
ws.close();
|
|
928
|
+
reject(new Error("Connection timeout"));
|
|
929
|
+
}, connectTimeout);
|
|
930
|
+
ws.onopen = () => {
|
|
931
|
+
clearTimeout(timeoutId);
|
|
932
|
+
resolve();
|
|
933
|
+
};
|
|
934
|
+
ws.onerror = () => {
|
|
935
|
+
clearTimeout(timeoutId);
|
|
936
|
+
reject(new Error("WebSocket connection failed"));
|
|
937
|
+
};
|
|
938
|
+
});
|
|
939
|
+
ws.onmessage = (event) => {
|
|
940
|
+
try {
|
|
941
|
+
const message = JSON.parse(event.data);
|
|
942
|
+
if ("id" in message && pendingCallsRef.current.has(message.id)) {
|
|
943
|
+
const pending = pendingCallsRef.current.get(message.id);
|
|
944
|
+
pendingCallsRef.current.delete(message.id);
|
|
945
|
+
pending.resolve(message);
|
|
946
|
+
onRpcResult?.(message);
|
|
947
|
+
}
|
|
948
|
+
} catch {
|
|
949
|
+
}
|
|
950
|
+
};
|
|
951
|
+
ws.onclose = () => {
|
|
952
|
+
setStatus("disconnected");
|
|
953
|
+
setSession(null);
|
|
954
|
+
wsRef.current = null;
|
|
955
|
+
onDisconnect?.();
|
|
956
|
+
};
|
|
957
|
+
ws.onerror = () => {
|
|
958
|
+
setError("WebSocket error");
|
|
959
|
+
onError?.(new Error("WebSocket error"));
|
|
960
|
+
};
|
|
961
|
+
if (newSession.livekitUrl && newSession.livekitToken) {
|
|
962
|
+
}
|
|
963
|
+
setStatus("connected");
|
|
964
|
+
onConnect?.(newSession);
|
|
965
|
+
} catch (err) {
|
|
966
|
+
const errorMessage = err instanceof Error ? err.message : "Connection failed";
|
|
967
|
+
setStatus("error");
|
|
968
|
+
setError(errorMessage);
|
|
969
|
+
onError?.(err instanceof Error ? err : new Error(errorMessage));
|
|
970
|
+
}
|
|
971
|
+
},
|
|
972
|
+
[adapter, config, status, timeout, onConnect, onDisconnect, onRpcResult, onError]
|
|
973
|
+
);
|
|
974
|
+
const disconnect = useCallback(async () => {
|
|
975
|
+
if (wsRef.current) {
|
|
976
|
+
wsRef.current.close();
|
|
977
|
+
wsRef.current = null;
|
|
978
|
+
}
|
|
979
|
+
if (session) {
|
|
980
|
+
try {
|
|
981
|
+
await fetch(`${config.apiBaseUrl}/play-sessions/${session.id}`, {
|
|
982
|
+
method: "DELETE",
|
|
983
|
+
headers: config.headers
|
|
984
|
+
});
|
|
985
|
+
} catch {
|
|
986
|
+
}
|
|
987
|
+
}
|
|
988
|
+
setSession(null);
|
|
989
|
+
setStatus("disconnected");
|
|
990
|
+
setVideoTrack(null);
|
|
991
|
+
setAudioTrack(null);
|
|
992
|
+
onDisconnect?.();
|
|
993
|
+
}, [session, config, onDisconnect]);
|
|
994
|
+
const call = useCallback(
|
|
995
|
+
(method, params) => {
|
|
996
|
+
return new Promise((resolve, reject) => {
|
|
997
|
+
if (!wsRef.current || wsRef.current.readyState !== WebSocket.OPEN) {
|
|
998
|
+
reject(new Error("Not connected"));
|
|
999
|
+
return;
|
|
1000
|
+
}
|
|
1001
|
+
const id = ++rpcIdRef.current;
|
|
1002
|
+
const request = {
|
|
1003
|
+
jsonrpc: "2.0",
|
|
1004
|
+
id,
|
|
1005
|
+
method,
|
|
1006
|
+
params: params ?? {}
|
|
1007
|
+
};
|
|
1008
|
+
pendingCallsRef.current.set(id, {
|
|
1009
|
+
resolve,
|
|
1010
|
+
reject
|
|
1011
|
+
});
|
|
1012
|
+
wsRef.current.send(JSON.stringify(request));
|
|
1013
|
+
setTimeout(() => {
|
|
1014
|
+
if (pendingCallsRef.current.has(id)) {
|
|
1015
|
+
pendingCallsRef.current.delete(id);
|
|
1016
|
+
reject(new Error("RPC call timeout"));
|
|
1017
|
+
}
|
|
1018
|
+
}, 3e4);
|
|
1019
|
+
});
|
|
1020
|
+
},
|
|
1021
|
+
[]
|
|
1022
|
+
);
|
|
1023
|
+
const observe = useCallback(
|
|
1024
|
+
async (key) => {
|
|
1025
|
+
const response = await call(`observe.${key}`);
|
|
1026
|
+
if (response.error) {
|
|
1027
|
+
throw new Error(response.error.message);
|
|
1028
|
+
}
|
|
1029
|
+
return response.result;
|
|
1030
|
+
},
|
|
1031
|
+
[call]
|
|
1032
|
+
);
|
|
1033
|
+
const act = useCallback(
|
|
1034
|
+
async (action, params) => {
|
|
1035
|
+
const response = await call(`act.${action}`, params);
|
|
1036
|
+
if (response.error) {
|
|
1037
|
+
throw new Error(response.error.message);
|
|
1038
|
+
}
|
|
1039
|
+
return response.result;
|
|
1040
|
+
},
|
|
1041
|
+
[call]
|
|
1042
|
+
);
|
|
1043
|
+
useEffect(() => {
|
|
1044
|
+
if (autoConnect) {
|
|
1045
|
+
connect();
|
|
1046
|
+
}
|
|
1047
|
+
}, [autoConnect]);
|
|
1048
|
+
useEffect(() => {
|
|
1049
|
+
return () => {
|
|
1050
|
+
if (wsRef.current) {
|
|
1051
|
+
wsRef.current.close();
|
|
1052
|
+
}
|
|
1053
|
+
};
|
|
1054
|
+
}, []);
|
|
1055
|
+
return {
|
|
1056
|
+
session,
|
|
1057
|
+
status,
|
|
1058
|
+
videoTrack,
|
|
1059
|
+
audioTrack,
|
|
1060
|
+
call,
|
|
1061
|
+
observe,
|
|
1062
|
+
act,
|
|
1063
|
+
connect,
|
|
1064
|
+
disconnect,
|
|
1065
|
+
isConnected: status === "connected",
|
|
1066
|
+
error
|
|
1067
|
+
};
|
|
1068
|
+
}
|
|
1069
|
+
function PlaySession({
|
|
1070
|
+
adapter,
|
|
1071
|
+
autoConnect = false,
|
|
1072
|
+
timeout,
|
|
1073
|
+
onSessionStart,
|
|
1074
|
+
onSessionEnd,
|
|
1075
|
+
onRpcResult,
|
|
1076
|
+
onError,
|
|
1077
|
+
children,
|
|
1078
|
+
className
|
|
1079
|
+
}) {
|
|
1080
|
+
const videoRef = useRef(null);
|
|
1081
|
+
const {
|
|
1082
|
+
session,
|
|
1083
|
+
status,
|
|
1084
|
+
videoTrack,
|
|
1085
|
+
audioTrack,
|
|
1086
|
+
call,
|
|
1087
|
+
observe,
|
|
1088
|
+
act,
|
|
1089
|
+
connect,
|
|
1090
|
+
disconnect,
|
|
1091
|
+
isConnected,
|
|
1092
|
+
error
|
|
1093
|
+
} = usePlaySession({
|
|
1094
|
+
adapter,
|
|
1095
|
+
autoConnect,
|
|
1096
|
+
timeout,
|
|
1097
|
+
onConnect: onSessionStart,
|
|
1098
|
+
onDisconnect: onSessionEnd,
|
|
1099
|
+
onRpcResult,
|
|
1100
|
+
onError
|
|
1101
|
+
});
|
|
1102
|
+
useEffect(() => {
|
|
1103
|
+
if (videoRef.current && videoTrack) {
|
|
1104
|
+
const stream = new MediaStream([videoTrack]);
|
|
1105
|
+
videoRef.current.srcObject = stream;
|
|
1106
|
+
}
|
|
1107
|
+
}, [videoTrack]);
|
|
1108
|
+
useEffect(() => {
|
|
1109
|
+
if (videoRef.current && audioTrack) {
|
|
1110
|
+
const currentStream = videoRef.current.srcObject;
|
|
1111
|
+
if (currentStream) {
|
|
1112
|
+
currentStream.addTrack(audioTrack);
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
}, [audioTrack]);
|
|
1116
|
+
return /* @__PURE__ */ jsx(
|
|
1117
|
+
"div",
|
|
1118
|
+
{
|
|
1119
|
+
className: `bb-play-session ${className ?? ""}`,
|
|
1120
|
+
"data-bb-state": status,
|
|
1121
|
+
"data-bb-adapter": adapter,
|
|
1122
|
+
"data-bb-session-id": session?.id,
|
|
1123
|
+
children: children({
|
|
1124
|
+
session,
|
|
1125
|
+
status,
|
|
1126
|
+
call,
|
|
1127
|
+
observe,
|
|
1128
|
+
act,
|
|
1129
|
+
connect,
|
|
1130
|
+
disconnect,
|
|
1131
|
+
videoRef,
|
|
1132
|
+
isConnected,
|
|
1133
|
+
error
|
|
1134
|
+
})
|
|
1135
|
+
}
|
|
1136
|
+
);
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
// src/components/ClusterHero/config.ts
|
|
1140
|
+
var CLUSTER_DEV_PORTS = {
|
|
1141
|
+
alexandria: 3001,
|
|
1142
|
+
alpha: 3002,
|
|
1143
|
+
opus: 3003,
|
|
1144
|
+
baia: 3004,
|
|
1145
|
+
kdot: 3005,
|
|
1146
|
+
aegis: 3006,
|
|
1147
|
+
providence: 3007
|
|
1148
|
+
};
|
|
1149
|
+
function getClusterDocsUrl(clusterId) {
|
|
1150
|
+
if (typeof window !== "undefined" && window.location.hostname === "localhost") {
|
|
1151
|
+
return `http://localhost:${CLUSTER_DEV_PORTS[clusterId]}`;
|
|
1152
|
+
}
|
|
1153
|
+
return `https://${clusterId}.backbay.io`;
|
|
1154
|
+
}
|
|
1155
|
+
var CLUSTER_CONFIGS = {
|
|
1156
|
+
alexandria: {
|
|
1157
|
+
id: "alexandria",
|
|
1158
|
+
name: "Alexandria",
|
|
1159
|
+
tagline: "Where knowledge compounds",
|
|
1160
|
+
latinMotto: "SEQUERE FILUM",
|
|
1161
|
+
sigilSrc: "/sigils/alexandria.svg",
|
|
1162
|
+
videoSrc: "/videos/clusters/alexandria.mp4",
|
|
1163
|
+
videoPoster: "/videos/clusters/alexandria-poster.jpg",
|
|
1164
|
+
accentColor: "#C9A227",
|
|
1165
|
+
accentColorRGB: "201, 162, 39",
|
|
1166
|
+
atmosphere: {
|
|
1167
|
+
dustMotes: {
|
|
1168
|
+
colors: ["#C9A227", "#E8D5A3", "#8B7355"],
|
|
1169
|
+
density: 0.6,
|
|
1170
|
+
speed: 0.3
|
|
1171
|
+
},
|
|
1172
|
+
light: {
|
|
1173
|
+
type: "godrays",
|
|
1174
|
+
color: "#C9A227",
|
|
1175
|
+
intensity: 0.7,
|
|
1176
|
+
source: { x: 0.8, y: 0.1 }
|
|
1177
|
+
}
|
|
1178
|
+
},
|
|
1179
|
+
buttons: [
|
|
1180
|
+
{ label: "Launch", href: "/clusters/alexandria", variant: "primary" },
|
|
1181
|
+
{ label: "Docs", href: "https://alexandria.backbay.io", variant: "secondary", external: true },
|
|
1182
|
+
{ label: "Governance", href: "/governance/alexandria", variant: "ghost" }
|
|
1183
|
+
],
|
|
1184
|
+
// Briefing
|
|
1185
|
+
description: "The decentralized knowledge marketplace. Publish, lease, and compound intelligence artifacts.",
|
|
1186
|
+
capabilities: ["PUBLISH", "LEASE", "COMPOUND"],
|
|
1187
|
+
fastPath: { label: "Start a Knowledge Compound", href: "/clusters/alexandria/compound/new" },
|
|
1188
|
+
status: { network: "STABLE", verification: "ON", fees: "2%" },
|
|
1189
|
+
// Live
|
|
1190
|
+
liveModule: "market",
|
|
1191
|
+
liveContent: "3 new blueprints published today",
|
|
1192
|
+
// Metrics
|
|
1193
|
+
metrics: { realms: 847, output24h: "2.4M", rank: 12 }
|
|
1194
|
+
},
|
|
1195
|
+
alpha: {
|
|
1196
|
+
id: "alpha",
|
|
1197
|
+
name: "Alpha",
|
|
1198
|
+
tagline: "Where signals become strategy",
|
|
1199
|
+
latinMotto: "ALPHA IN MOTU",
|
|
1200
|
+
sigilSrc: "/sigils/alpha.svg",
|
|
1201
|
+
videoSrc: "/videos/clusters/alpha.mp4",
|
|
1202
|
+
videoPoster: "/videos/clusters/alpha-poster.jpg",
|
|
1203
|
+
accentColor: "#E8E8E8",
|
|
1204
|
+
accentColorRGB: "232, 232, 232",
|
|
1205
|
+
atmosphere: {
|
|
1206
|
+
fog: {
|
|
1207
|
+
type: "volumetric",
|
|
1208
|
+
color: "#E8E8E8",
|
|
1209
|
+
intensity: 0.5
|
|
1210
|
+
}
|
|
1211
|
+
},
|
|
1212
|
+
buttons: [
|
|
1213
|
+
{ label: "Launch", href: "/clusters/alpha", variant: "primary" },
|
|
1214
|
+
{ label: "Docs", href: "https://alpha.backbay.io", variant: "secondary", external: true },
|
|
1215
|
+
{ label: "Governance", href: "/governance/alpha", variant: "ghost" }
|
|
1216
|
+
],
|
|
1217
|
+
// Briefing
|
|
1218
|
+
description: "A social exchange for research-grade finance. Models, signals, and playbooks\u2014shared, challenged, and refined in public.",
|
|
1219
|
+
capabilities: ["BACKTEST", "PRICE", "EXECUTE"],
|
|
1220
|
+
fastPath: { label: "Explore strategy marketplace", href: "/clusters/alpha/market" },
|
|
1221
|
+
status: { network: "STABLE", verification: "ON", fees: "1.5%" },
|
|
1222
|
+
// Live
|
|
1223
|
+
liveModule: "live",
|
|
1224
|
+
liveContent: "Live: 218 strategies \u2022 24h volume $3.1B",
|
|
1225
|
+
// Metrics
|
|
1226
|
+
metrics: { realms: 234, output24h: "4.8M", rank: 3 }
|
|
1227
|
+
},
|
|
1228
|
+
opus: {
|
|
1229
|
+
id: "opus",
|
|
1230
|
+
name: "Opus",
|
|
1231
|
+
tagline: "Where care meets code",
|
|
1232
|
+
latinMotto: "SALUS PER MACHINAM",
|
|
1233
|
+
sigilSrc: "/sigils/opus.svg",
|
|
1234
|
+
videoSrc: "/videos/clusters/opus.mp4",
|
|
1235
|
+
videoPoster: "/videos/clusters/opus-poster.jpg",
|
|
1236
|
+
accentColor: "#B87333",
|
|
1237
|
+
accentColorRGB: "184, 115, 51",
|
|
1238
|
+
atmosphere: {
|
|
1239
|
+
dustMotes: {
|
|
1240
|
+
colors: ["#B87333", "#D4956A", "#8B5A2B"],
|
|
1241
|
+
density: 0.8,
|
|
1242
|
+
speed: 0.2
|
|
1243
|
+
},
|
|
1244
|
+
light: {
|
|
1245
|
+
type: "bloom",
|
|
1246
|
+
color: "#B87333",
|
|
1247
|
+
intensity: 0.6
|
|
1248
|
+
}
|
|
1249
|
+
},
|
|
1250
|
+
buttons: [
|
|
1251
|
+
{ label: "Launch", href: "/clusters/opus", variant: "primary" },
|
|
1252
|
+
{ label: "Docs", href: "https://opus.backbay.io", variant: "secondary", external: true },
|
|
1253
|
+
{ label: "Governance", href: "/governance/opus", variant: "ghost" }
|
|
1254
|
+
],
|
|
1255
|
+
// Briefing
|
|
1256
|
+
description: "The clinic-to-code commons. Practical health systems, shared and iterated together.",
|
|
1257
|
+
capabilities: ["DIAGNOSE", "COORDINATE", "PRODUCE"],
|
|
1258
|
+
fastPath: { label: "Explore the Exchange", href: "/clusters/opus/exchange" },
|
|
1259
|
+
status: { network: "STABLE", verification: "HIPAA", fees: "2%" },
|
|
1260
|
+
// Live
|
|
1261
|
+
liveModule: "live",
|
|
1262
|
+
liveContent: "New: Autonomous diagnostic pipeline \u2022 12 protocols deployed",
|
|
1263
|
+
// Metrics
|
|
1264
|
+
metrics: { realms: 156, output24h: "892K" }
|
|
1265
|
+
},
|
|
1266
|
+
baia: {
|
|
1267
|
+
id: "baia",
|
|
1268
|
+
name: "Baia",
|
|
1269
|
+
tagline: "Where imagination renders",
|
|
1270
|
+
latinMotto: "ARS EX MACHINA",
|
|
1271
|
+
sigilSrc: "/sigils/baia.svg",
|
|
1272
|
+
videoSrc: "/videos/clusters/baia.mp4",
|
|
1273
|
+
videoPoster: "/videos/clusters/baia-poster.jpg",
|
|
1274
|
+
accentColor: "#D4AF37",
|
|
1275
|
+
accentColorRGB: "212, 175, 55",
|
|
1276
|
+
atmosphere: {
|
|
1277
|
+
light: {
|
|
1278
|
+
type: "godrays",
|
|
1279
|
+
color: "#D4AF37",
|
|
1280
|
+
intensity: 0.8,
|
|
1281
|
+
source: { x: 0.5, y: 0 }
|
|
1282
|
+
}
|
|
1283
|
+
},
|
|
1284
|
+
buttons: [
|
|
1285
|
+
{ label: "Launch", href: "/clusters/baia", variant: "primary" },
|
|
1286
|
+
{ label: "Docs", href: "https://baia.backbay.io", variant: "secondary", external: true },
|
|
1287
|
+
{ label: "Governance", href: "/governance/baia", variant: "ghost" }
|
|
1288
|
+
],
|
|
1289
|
+
// Briefing
|
|
1290
|
+
description: "A social market for generative culture. Artists and builders publish, collaborate, and curate evolving collections.",
|
|
1291
|
+
capabilities: ["GENERATE", "COMPOSE", "RENDER"],
|
|
1292
|
+
fastPath: { label: "Open the Studio", href: "/clusters/baia/studio" },
|
|
1293
|
+
status: { network: "STABLE", verification: "ON", fees: "2.5%" },
|
|
1294
|
+
// Live
|
|
1295
|
+
liveModule: "market",
|
|
1296
|
+
liveContent: "Trending: Neural symphony generator \u2022 847 works minted today",
|
|
1297
|
+
// Metrics
|
|
1298
|
+
metrics: { realms: 89, output24h: "124K", rank: 47 }
|
|
1299
|
+
},
|
|
1300
|
+
kdot: {
|
|
1301
|
+
id: "kdot",
|
|
1302
|
+
name: "KDoT",
|
|
1303
|
+
tagline: "Kernel design of thought",
|
|
1304
|
+
latinMotto: "MENS \u2022 MACHINA \u2022 DEUS",
|
|
1305
|
+
sigilSrc: "/sigils/kdot.svg",
|
|
1306
|
+
videoSrc: "/videos/clusters/kdot.mp4",
|
|
1307
|
+
videoPoster: "/videos/clusters/kdot-poster.jpg",
|
|
1308
|
+
accentColor: "#00D4AA",
|
|
1309
|
+
accentColorRGB: "0, 212, 170",
|
|
1310
|
+
atmosphere: {
|
|
1311
|
+
fog: {
|
|
1312
|
+
type: "mist",
|
|
1313
|
+
color: "#00D4AA",
|
|
1314
|
+
intensity: 0.4
|
|
1315
|
+
}
|
|
1316
|
+
},
|
|
1317
|
+
buttons: [
|
|
1318
|
+
{ label: "Launch", href: "/clusters/kdot", variant: "primary" },
|
|
1319
|
+
{ label: "Docs", href: "https://kdot.backbay.io", variant: "secondary", external: true },
|
|
1320
|
+
{ label: "Status", href: "/status/kdot", variant: "ghost" }
|
|
1321
|
+
],
|
|
1322
|
+
// Briefing
|
|
1323
|
+
description: "Compile thought into territory. Ship verifiable services. Forge living culture. Spin up economies.\nKernel Design of Thought: where creativity becomes industry.",
|
|
1324
|
+
capabilities: ["DESIGN", "SYNTHESIZE", "ALIGN"],
|
|
1325
|
+
fastPath: { label: "Open the Kernel", href: "/clusters/kdot/topology" },
|
|
1326
|
+
status: { network: "OPTIMAL", verification: "ON", fees: "0.1%" },
|
|
1327
|
+
// Live
|
|
1328
|
+
liveModule: "live",
|
|
1329
|
+
liveContent: "The Cathedral awakens \u2022 12 kernels compiled today",
|
|
1330
|
+
// Metrics
|
|
1331
|
+
metrics: { realms: 1247, output24h: "8.4PB", rank: 1 }
|
|
1332
|
+
},
|
|
1333
|
+
aegis: {
|
|
1334
|
+
id: "aegis",
|
|
1335
|
+
name: "Aegis",
|
|
1336
|
+
tagline: "Shield of the realm",
|
|
1337
|
+
latinMotto: "TUTELA PERPETUA",
|
|
1338
|
+
sigilSrc: "/sigils/aegis.svg",
|
|
1339
|
+
videoSrc: "/videos/clusters/aegis.mp4",
|
|
1340
|
+
videoPoster: "/videos/clusters/aegis-poster.jpg",
|
|
1341
|
+
accentColor: "#4A7BF7",
|
|
1342
|
+
accentColorRGB: "74, 123, 247",
|
|
1343
|
+
atmosphere: {
|
|
1344
|
+
light: {
|
|
1345
|
+
type: "bloom",
|
|
1346
|
+
color: "#4A7BF7",
|
|
1347
|
+
intensity: 0.5
|
|
1348
|
+
}
|
|
1349
|
+
},
|
|
1350
|
+
buttons: [
|
|
1351
|
+
{ label: "Launch", href: "/clusters/aegis", variant: "primary" },
|
|
1352
|
+
{ label: "Docs", href: "https://aegis.backbay.io", variant: "secondary", external: true },
|
|
1353
|
+
{ label: "Audit", href: "/audit/aegis", variant: "ghost" }
|
|
1354
|
+
],
|
|
1355
|
+
// Briefing
|
|
1356
|
+
description: "The EDR layer for agent economies. Aegis is a trust-minimized distributed security mesh to enable autonomous production at scale.",
|
|
1357
|
+
capabilities: ["PROTECT", "DETECT", "RESPOND"],
|
|
1358
|
+
fastPath: { label: "View threat dashboard", href: "/clusters/aegis/threats" },
|
|
1359
|
+
status: { network: "SECURE", verification: "ENFORCED", fees: "1%" },
|
|
1360
|
+
// Live
|
|
1361
|
+
liveModule: "governance",
|
|
1362
|
+
liveContent: "Security Proposal #7 \u2014 Policy update pending review",
|
|
1363
|
+
// Metrics
|
|
1364
|
+
metrics: { realms: 312, output24h: "2.1B threats blocked", rank: 2 }
|
|
1365
|
+
},
|
|
1366
|
+
providence: {
|
|
1367
|
+
id: "providence",
|
|
1368
|
+
name: "Providence",
|
|
1369
|
+
tagline: "Foresight is defense",
|
|
1370
|
+
latinMotto: "PRAEVIDEO ERGO PROTEGO",
|
|
1371
|
+
sigilSrc: "/sigils/providence.svg",
|
|
1372
|
+
videoSrc: "/videos/clusters/providence.mp4",
|
|
1373
|
+
videoPoster: "/videos/clusters/providence-poster.jpg",
|
|
1374
|
+
accentColor: "#00D4AA",
|
|
1375
|
+
accentColorRGB: "0, 212, 170",
|
|
1376
|
+
atmosphere: {
|
|
1377
|
+
light: {
|
|
1378
|
+
type: "godrays",
|
|
1379
|
+
color: "#00D4AA",
|
|
1380
|
+
intensity: 0.5,
|
|
1381
|
+
source: { x: 0.55, y: 0.05 }
|
|
1382
|
+
},
|
|
1383
|
+
fog: {
|
|
1384
|
+
type: "mist",
|
|
1385
|
+
color: "#00D4AA",
|
|
1386
|
+
intensity: 0.25
|
|
1387
|
+
}
|
|
1388
|
+
},
|
|
1389
|
+
buttons: [
|
|
1390
|
+
{ label: "Launch", href: "/clusters/providence", variant: "primary" },
|
|
1391
|
+
{ label: "Docs", href: "https://providence.backbay.io", variant: "secondary", external: true },
|
|
1392
|
+
{ label: "Threat Intel", href: "/providence/threats", variant: "ghost" }
|
|
1393
|
+
],
|
|
1394
|
+
description: "The EDR layer for agent economies. Aegis is a trust-minimized security distributed security for autonomous production.",
|
|
1395
|
+
capabilities: ["PREDICT", "RESPOND", "DEFEND"],
|
|
1396
|
+
fastPath: { label: "View threat dashboard", href: "/clusters/providence/threats" },
|
|
1397
|
+
status: { network: "SECURE", verification: "ENFORCED", fees: "1%" },
|
|
1398
|
+
liveModule: "live",
|
|
1399
|
+
liveContent: "24/7 monitoring active \u2022 847K threats analyzed today",
|
|
1400
|
+
metrics: { realms: 96, output24h: "38K", rank: 19 }
|
|
1401
|
+
}
|
|
1402
|
+
};
|
|
1403
|
+
function getClusterConfig(clusterId) {
|
|
1404
|
+
return CLUSTER_CONFIGS[clusterId];
|
|
1405
|
+
}
|
|
1406
|
+
function getClusterConfigWithResolvedUrls(clusterId) {
|
|
1407
|
+
const config = CLUSTER_CONFIGS[clusterId];
|
|
1408
|
+
const docsUrl = getClusterDocsUrl(clusterId);
|
|
1409
|
+
return {
|
|
1410
|
+
...config,
|
|
1411
|
+
buttons: config.buttons.map(
|
|
1412
|
+
(button) => button.label === "Docs" ? { ...button, href: docsUrl } : button
|
|
1413
|
+
)
|
|
1414
|
+
};
|
|
1415
|
+
}
|
|
1416
|
+
function cn(...inputs) {
|
|
1417
|
+
return twMerge(clsx(inputs));
|
|
1418
|
+
}
|
|
1419
|
+
function prefersReducedMotion() {
|
|
1420
|
+
if (typeof window === "undefined") return false;
|
|
1421
|
+
return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
1422
|
+
}
|
|
1423
|
+
var UiThemeContext = React3.createContext(null);
|
|
1424
|
+
function useUiTheme() {
|
|
1425
|
+
const context = React3.useContext(UiThemeContext);
|
|
1426
|
+
if (!context) {
|
|
1427
|
+
throw new Error("useUiTheme must be used within a UiThemeProvider");
|
|
1428
|
+
}
|
|
1429
|
+
return context;
|
|
1430
|
+
}
|
|
1431
|
+
function useAmbientTokens() {
|
|
1432
|
+
const { theme } = useUiTheme();
|
|
1433
|
+
return theme.ambient;
|
|
1434
|
+
}
|
|
1435
|
+
function generateMotes(count, colors, sizeRange, speed) {
|
|
1436
|
+
return Array.from({ length: count }, (_, i) => ({
|
|
1437
|
+
id: i,
|
|
1438
|
+
x: Math.random() * 100,
|
|
1439
|
+
y: Math.random() * 100,
|
|
1440
|
+
size: sizeRange[0] + Math.random() * (sizeRange[1] - sizeRange[0]),
|
|
1441
|
+
color: colors[Math.floor(Math.random() * colors.length)],
|
|
1442
|
+
delay: Math.random() * 5,
|
|
1443
|
+
duration: (8 + Math.random() * 8) / speed,
|
|
1444
|
+
driftX: (Math.random() - 0.5) * 30,
|
|
1445
|
+
driftY: -20 - Math.random() * 40
|
|
1446
|
+
// Upward drift
|
|
1447
|
+
}));
|
|
1448
|
+
}
|
|
1449
|
+
var MoteParticle = React3.memo(function MoteParticle2({
|
|
1450
|
+
mote,
|
|
1451
|
+
speedMultiplier
|
|
1452
|
+
}) {
|
|
1453
|
+
const reducedMotion = useReducedMotion();
|
|
1454
|
+
if (reducedMotion) {
|
|
1455
|
+
return /* @__PURE__ */ jsx(
|
|
1456
|
+
"div",
|
|
1457
|
+
{
|
|
1458
|
+
className: "absolute rounded-full",
|
|
1459
|
+
style: {
|
|
1460
|
+
left: `${mote.x}%`,
|
|
1461
|
+
top: `${mote.y}%`,
|
|
1462
|
+
width: mote.size,
|
|
1463
|
+
height: mote.size,
|
|
1464
|
+
backgroundColor: mote.color,
|
|
1465
|
+
opacity: 0.3
|
|
1466
|
+
}
|
|
1467
|
+
}
|
|
1468
|
+
);
|
|
1469
|
+
}
|
|
1470
|
+
return /* @__PURE__ */ jsx(
|
|
1471
|
+
motion.div,
|
|
1472
|
+
{
|
|
1473
|
+
className: "absolute rounded-full will-change-transform",
|
|
1474
|
+
style: {
|
|
1475
|
+
left: `${mote.x}%`,
|
|
1476
|
+
top: `${mote.y}%`,
|
|
1477
|
+
width: mote.size,
|
|
1478
|
+
height: mote.size,
|
|
1479
|
+
backgroundColor: mote.color,
|
|
1480
|
+
filter: `blur(${mote.size > 4 ? 1 : 0}px)`
|
|
1481
|
+
},
|
|
1482
|
+
initial: { opacity: 0, scale: 0.5 },
|
|
1483
|
+
animate: {
|
|
1484
|
+
opacity: [0, 0.6, 0.4, 0.7, 0],
|
|
1485
|
+
scale: [0.5, 1, 0.9, 1.1, 0.8],
|
|
1486
|
+
x: [0, mote.driftX * 0.3, mote.driftX * 0.7, mote.driftX],
|
|
1487
|
+
y: [0, mote.driftY * 0.3, mote.driftY * 0.7, mote.driftY]
|
|
1488
|
+
},
|
|
1489
|
+
transition: {
|
|
1490
|
+
duration: mote.duration / speedMultiplier,
|
|
1491
|
+
delay: mote.delay,
|
|
1492
|
+
repeat: Infinity,
|
|
1493
|
+
ease: "easeInOut"
|
|
1494
|
+
}
|
|
1495
|
+
}
|
|
1496
|
+
);
|
|
1497
|
+
});
|
|
1498
|
+
function DustMotesLayer({
|
|
1499
|
+
colors: propColors,
|
|
1500
|
+
density: propDensity,
|
|
1501
|
+
speed: propSpeed,
|
|
1502
|
+
sizeRange: propSizeRange,
|
|
1503
|
+
className,
|
|
1504
|
+
disabled = false
|
|
1505
|
+
}) {
|
|
1506
|
+
const ambientTokens = useAmbientTokens();
|
|
1507
|
+
const reducedMotion = prefersReducedMotion();
|
|
1508
|
+
const colors = propColors ?? ambientTokens.particleColors;
|
|
1509
|
+
const density = propDensity ?? ambientTokens.particleDensity;
|
|
1510
|
+
const speed = propSpeed ?? ambientTokens.particleSpeed;
|
|
1511
|
+
const sizeRange = propSizeRange ?? ambientTokens.particleSizeRange;
|
|
1512
|
+
const [motes, setMotes] = React3.useState([]);
|
|
1513
|
+
React3.useEffect(() => {
|
|
1514
|
+
if (disabled || reducedMotion) {
|
|
1515
|
+
setMotes([]);
|
|
1516
|
+
return;
|
|
1517
|
+
}
|
|
1518
|
+
const viewportArea = typeof window !== "undefined" ? window.innerWidth * window.innerHeight / 1e4 : 100;
|
|
1519
|
+
const count = Math.floor(viewportArea * density * 2);
|
|
1520
|
+
const clampedCount = Math.min(Math.max(count, 15), 80);
|
|
1521
|
+
setMotes(generateMotes(clampedCount, colors, sizeRange, speed));
|
|
1522
|
+
}, [colors, density, disabled, reducedMotion, sizeRange, speed]);
|
|
1523
|
+
if (disabled || motes.length === 0) {
|
|
1524
|
+
return null;
|
|
1525
|
+
}
|
|
1526
|
+
return /* @__PURE__ */ jsxs(
|
|
1527
|
+
"div",
|
|
1528
|
+
{
|
|
1529
|
+
className: cn("pointer-events-none absolute inset-0 overflow-hidden", className),
|
|
1530
|
+
"aria-hidden": "true",
|
|
1531
|
+
children: [
|
|
1532
|
+
/* @__PURE__ */ jsx(
|
|
1533
|
+
"div",
|
|
1534
|
+
{
|
|
1535
|
+
className: "absolute inset-0",
|
|
1536
|
+
style: {
|
|
1537
|
+
background: ambientTokens.horizonGradient
|
|
1538
|
+
}
|
|
1539
|
+
}
|
|
1540
|
+
),
|
|
1541
|
+
motes.map((mote) => /* @__PURE__ */ jsx(MoteParticle, { mote, speedMultiplier: speed }, mote.id)),
|
|
1542
|
+
/* @__PURE__ */ jsx(
|
|
1543
|
+
"div",
|
|
1544
|
+
{
|
|
1545
|
+
className: "absolute inset-0 opacity-30",
|
|
1546
|
+
style: {
|
|
1547
|
+
background: `
|
|
1548
|
+
radial-gradient(
|
|
1549
|
+
ellipse 60% 100% at 70% 0%,
|
|
1550
|
+
${colors[0]}15,
|
|
1551
|
+
transparent 70%
|
|
1552
|
+
)
|
|
1553
|
+
`
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1556
|
+
)
|
|
1557
|
+
]
|
|
1558
|
+
}
|
|
1559
|
+
);
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1562
|
+
// src/primitives/environment/shared/types.ts
|
|
1563
|
+
var PERFORMANCE_PRESETS = {
|
|
1564
|
+
high: { tier: "high", maxParticles: 2e3, useShaders: true, targetFPS: 60 },
|
|
1565
|
+
medium: { tier: "medium", maxParticles: 800, useShaders: true, targetFPS: 60 },
|
|
1566
|
+
low: { tier: "low", maxParticles: 300, useShaders: false, targetFPS: 30 },
|
|
1567
|
+
minimal: { tier: "minimal", maxParticles: 0, useShaders: false, targetFPS: 0 }
|
|
1568
|
+
};
|
|
1569
|
+
|
|
1570
|
+
// src/primitives/environment/shared/performance.ts
|
|
1571
|
+
function detectPerformanceTier() {
|
|
1572
|
+
if (typeof window === "undefined") return "medium";
|
|
1573
|
+
if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
|
|
1574
|
+
return "minimal";
|
|
1575
|
+
}
|
|
1576
|
+
const nav = navigator;
|
|
1577
|
+
if (nav.deviceMemory && nav.deviceMemory < 4) {
|
|
1578
|
+
return "low";
|
|
1579
|
+
}
|
|
1580
|
+
if (navigator.hardwareConcurrency && navigator.hardwareConcurrency < 4) {
|
|
1581
|
+
return "low";
|
|
1582
|
+
}
|
|
1583
|
+
const isMobile = /Android|iPhone|iPad|iPod/i.test(navigator.userAgent);
|
|
1584
|
+
if (isMobile) return "low";
|
|
1585
|
+
return "medium";
|
|
1586
|
+
}
|
|
1587
|
+
function getPerformanceConfig(tier) {
|
|
1588
|
+
const detected = detectPerformanceTier();
|
|
1589
|
+
return PERFORMANCE_PRESETS[detected];
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1592
|
+
// src/primitives/environment/shared/noise.ts
|
|
1593
|
+
var NOISE_SVG = `<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 200 200">
|
|
1594
|
+
<filter id="n">
|
|
1595
|
+
<feTurbulence type="fractalNoise" baseFrequency="0.9" numOctaves="3" seed="2" stitchTiles="stitch" />
|
|
1596
|
+
<feColorMatrix type="saturate" values="0" />
|
|
1597
|
+
</filter>
|
|
1598
|
+
<rect width="200" height="200" filter="url(#n)" opacity="0.55" />
|
|
1599
|
+
</svg>`;
|
|
1600
|
+
var NOISE_DATA_URL = `data:image/svg+xml,${encodeURIComponent(NOISE_SVG)}`;
|
|
1601
|
+
|
|
1602
|
+
// src/primitives/environment/VolumetricLight/types.ts
|
|
1603
|
+
var LIGHT_CONFIGS = {
|
|
1604
|
+
godrays: { defaultColor: "#fffbe6", defaultIntensity: 0.6, animated: true, blendMode: "screen" },
|
|
1605
|
+
shaft: { defaultColor: "#ffffff", defaultIntensity: 0.5, animated: false, blendMode: "screen" },
|
|
1606
|
+
bloom: { defaultColor: "#ffffff", defaultIntensity: 0.4, animated: false, blendMode: "screen" },
|
|
1607
|
+
flare: { defaultColor: "#ffe4b5", defaultIntensity: 0.7, animated: true, blendMode: "screen" },
|
|
1608
|
+
caustics: { defaultColor: "#00d4ff", defaultIntensity: 0.4, animated: true, blendMode: "overlay" },
|
|
1609
|
+
scanner: { defaultColor: "#00ff00", defaultIntensity: 0.6, animated: true, blendMode: "screen" },
|
|
1610
|
+
neon: { defaultColor: "#ff00ff", defaultIntensity: 0.8, animated: true, blendMode: "screen" },
|
|
1611
|
+
spotlight: { defaultColor: "#ffffff", defaultIntensity: 0.7, animated: false, blendMode: "screen" },
|
|
1612
|
+
rim: { defaultColor: "#00f0ff", defaultIntensity: 0.5, animated: false, blendMode: "screen" },
|
|
1613
|
+
laser: { defaultColor: "#ff0000", defaultIntensity: 0.9, animated: true, blendMode: "screen" }
|
|
1614
|
+
};
|
|
1615
|
+
function VolumetricLight({
|
|
1616
|
+
type,
|
|
1617
|
+
source = { x: 0.5, y: 0 },
|
|
1618
|
+
color: propColor,
|
|
1619
|
+
intensity = 0.5,
|
|
1620
|
+
decay = 0.5,
|
|
1621
|
+
angle = 0,
|
|
1622
|
+
width = 0.3,
|
|
1623
|
+
animated: propAnimated,
|
|
1624
|
+
stylePreset = "ui",
|
|
1625
|
+
enabled = true,
|
|
1626
|
+
className,
|
|
1627
|
+
style
|
|
1628
|
+
}) {
|
|
1629
|
+
const reducedMotion = useReducedMotion();
|
|
1630
|
+
const perfConfig = getPerformanceConfig();
|
|
1631
|
+
const [time, setTime] = React3.useState(0);
|
|
1632
|
+
const config = LIGHT_CONFIGS[type];
|
|
1633
|
+
const color = propColor ?? config.defaultColor;
|
|
1634
|
+
const shouldAnimate = (propAnimated ?? config.animated) && !reducedMotion && perfConfig.tier !== "minimal";
|
|
1635
|
+
React3.useEffect(() => {
|
|
1636
|
+
if (!shouldAnimate || !enabled) return;
|
|
1637
|
+
let frame;
|
|
1638
|
+
const animate = () => {
|
|
1639
|
+
setTime((prev) => prev + 0.016);
|
|
1640
|
+
frame = requestAnimationFrame(animate);
|
|
1641
|
+
};
|
|
1642
|
+
frame = requestAnimationFrame(animate);
|
|
1643
|
+
return () => cancelAnimationFrame(frame);
|
|
1644
|
+
}, [shouldAnimate, enabled]);
|
|
1645
|
+
const lightStyle = React3.useMemo(() => {
|
|
1646
|
+
const opacity = intensity * config.defaultIntensity;
|
|
1647
|
+
const d = Math.max(0, Math.min(1, decay));
|
|
1648
|
+
switch (type) {
|
|
1649
|
+
case "godrays":
|
|
1650
|
+
return {
|
|
1651
|
+
background: `conic-gradient(from ${angle}deg at ${source.x * 100}% ${source.y * 100}%,
|
|
1652
|
+
${color}${Math.round(opacity * 0.4 * 255).toString(16).padStart(2, "0")} 0deg,
|
|
1653
|
+
transparent 15deg,
|
|
1654
|
+
${color}${Math.round(opacity * 0.3 * 255).toString(16).padStart(2, "0")} 30deg,
|
|
1655
|
+
transparent 45deg,
|
|
1656
|
+
${color}${Math.round(opacity * 0.35 * 255).toString(16).padStart(2, "0")} 60deg,
|
|
1657
|
+
transparent 75deg,
|
|
1658
|
+
${color}${Math.round(opacity * 0.25 * 255).toString(16).padStart(2, "0")} 90deg,
|
|
1659
|
+
transparent 105deg
|
|
1660
|
+
)`,
|
|
1661
|
+
mixBlendMode: config.blendMode
|
|
1662
|
+
};
|
|
1663
|
+
case "shaft":
|
|
1664
|
+
return {
|
|
1665
|
+
background: `linear-gradient(${angle}deg,
|
|
1666
|
+
transparent ${(source.x - width / 2) * 100}%,
|
|
1667
|
+
${color}${Math.round(opacity * 0.5 * 255).toString(16).padStart(2, "0")} ${source.x * 100}%,
|
|
1668
|
+
transparent ${(source.x + width / 2) * 100}%
|
|
1669
|
+
)`,
|
|
1670
|
+
mixBlendMode: config.blendMode
|
|
1671
|
+
};
|
|
1672
|
+
case "bloom": {
|
|
1673
|
+
const bloomInner = 18 + d * 22;
|
|
1674
|
+
const bloomMid = 42 + d * 24;
|
|
1675
|
+
return {
|
|
1676
|
+
background: `radial-gradient(circle at ${source.x * 100}% ${source.y * 100}%,
|
|
1677
|
+
${color}${Math.round(opacity * 0.6 * 255).toString(16).padStart(2, "0")},
|
|
1678
|
+
${color}${Math.round(opacity * 0.3 * 255).toString(16).padStart(2, "0")} ${bloomInner}%,
|
|
1679
|
+
transparent ${bloomMid}%
|
|
1680
|
+
)`,
|
|
1681
|
+
mixBlendMode: config.blendMode,
|
|
1682
|
+
filter: "blur(20px)"
|
|
1683
|
+
};
|
|
1684
|
+
}
|
|
1685
|
+
case "flare":
|
|
1686
|
+
const flareOffset = Math.sin(time * 2) * 5;
|
|
1687
|
+
return {
|
|
1688
|
+
background: `
|
|
1689
|
+
radial-gradient(ellipse 20% 5% at ${source.x * 100}% ${source.y * 100 + flareOffset}%, ${color}${Math.round(opacity * 0.8 * 255).toString(16).padStart(2, "0")}, transparent),
|
|
1690
|
+
radial-gradient(ellipse 5% 20% at ${source.x * 100}% ${source.y * 100}%, ${color}${Math.round(opacity * 0.6 * 255).toString(16).padStart(2, "0")}, transparent),
|
|
1691
|
+
radial-gradient(circle at ${source.x * 100}% ${source.y * 100}%, ${color}${Math.round(opacity * 0.4 * 255).toString(16).padStart(2, "0")}, transparent 20%)
|
|
1692
|
+
`,
|
|
1693
|
+
mixBlendMode: config.blendMode
|
|
1694
|
+
};
|
|
1695
|
+
case "caustics":
|
|
1696
|
+
const causticPhase = time * 0.5;
|
|
1697
|
+
return {
|
|
1698
|
+
background: `
|
|
1699
|
+
radial-gradient(ellipse at ${50 + Math.sin(causticPhase) * 20}% ${50 + Math.cos(causticPhase * 1.3) * 20}%, ${color}${Math.round(opacity * 0.3 * 255).toString(16).padStart(2, "0")}, transparent 40%),
|
|
1700
|
+
radial-gradient(ellipse at ${50 + Math.cos(causticPhase * 0.7) * 25}% ${50 + Math.sin(causticPhase * 1.1) * 25}%, ${color}${Math.round(opacity * 0.25 * 255).toString(16).padStart(2, "0")}, transparent 35%)
|
|
1701
|
+
`,
|
|
1702
|
+
mixBlendMode: config.blendMode
|
|
1703
|
+
};
|
|
1704
|
+
case "scanner":
|
|
1705
|
+
const scanAngle = time * 60 % 360;
|
|
1706
|
+
return {
|
|
1707
|
+
background: `conic-gradient(from ${scanAngle}deg at ${source.x * 100}% ${source.y * 100}%,
|
|
1708
|
+
${color}${Math.round(opacity * 0.6 * 255).toString(16).padStart(2, "0")} 0deg,
|
|
1709
|
+
transparent 30deg,
|
|
1710
|
+
transparent 360deg
|
|
1711
|
+
)`,
|
|
1712
|
+
mixBlendMode: config.blendMode
|
|
1713
|
+
};
|
|
1714
|
+
case "neon":
|
|
1715
|
+
const flickerIntensity = 0.9 + Math.sin(time * 20) * 0.1;
|
|
1716
|
+
return {
|
|
1717
|
+
background: `linear-gradient(${angle}deg, transparent 40%, ${color}${Math.round(opacity * flickerIntensity * 0.8 * 255).toString(16).padStart(2, "0")} 50%, transparent 60%)`,
|
|
1718
|
+
boxShadow: `0 0 30px ${color}${Math.round(opacity * flickerIntensity * 0.5 * 255).toString(16).padStart(2, "0")}, 0 0 60px ${color}${Math.round(opacity * flickerIntensity * 0.3 * 255).toString(16).padStart(2, "0")}`,
|
|
1719
|
+
mixBlendMode: config.blendMode
|
|
1720
|
+
};
|
|
1721
|
+
case "spotlight": {
|
|
1722
|
+
const spotMid = 40 + d * 35;
|
|
1723
|
+
return {
|
|
1724
|
+
background: `radial-gradient(ellipse ${width * 100}% ${width * 150}% at ${source.x * 100}% ${source.y * 100}%,
|
|
1725
|
+
${color}${Math.round(opacity * 0.7 * 255).toString(16).padStart(2, "0")},
|
|
1726
|
+
${color}${Math.round(opacity * 0.3 * 255).toString(16).padStart(2, "0")} ${spotMid}%,
|
|
1727
|
+
transparent 100%
|
|
1728
|
+
)`,
|
|
1729
|
+
mixBlendMode: config.blendMode
|
|
1730
|
+
};
|
|
1731
|
+
}
|
|
1732
|
+
case "rim":
|
|
1733
|
+
return {
|
|
1734
|
+
boxShadow: `inset 0 0 ${60 * intensity}px ${color}${Math.round(opacity * 0.6 * 255).toString(16).padStart(2, "0")}`,
|
|
1735
|
+
mixBlendMode: config.blendMode
|
|
1736
|
+
};
|
|
1737
|
+
case "laser":
|
|
1738
|
+
const laserOffset = Math.sin(time * 3) * 10;
|
|
1739
|
+
return {
|
|
1740
|
+
background: `linear-gradient(${angle + laserOffset}deg,
|
|
1741
|
+
transparent 49%,
|
|
1742
|
+
${color}${Math.round(opacity * 255).toString(16).padStart(2, "0")} 49.5%,
|
|
1743
|
+
${color}${Math.round(opacity * 255).toString(16).padStart(2, "0")} 50.5%,
|
|
1744
|
+
transparent 51%
|
|
1745
|
+
)`,
|
|
1746
|
+
mixBlendMode: config.blendMode
|
|
1747
|
+
};
|
|
1748
|
+
default:
|
|
1749
|
+
return {};
|
|
1750
|
+
}
|
|
1751
|
+
}, [type, source, color, intensity, decay, angle, width, time, config]);
|
|
1752
|
+
if (!enabled) return null;
|
|
1753
|
+
return /* @__PURE__ */ jsx(
|
|
1754
|
+
"div",
|
|
1755
|
+
{
|
|
1756
|
+
className: cn("pointer-events-none absolute inset-0", className),
|
|
1757
|
+
style: { ...lightStyle, ...style },
|
|
1758
|
+
"aria-hidden": "true",
|
|
1759
|
+
children: stylePreset === "cinematic" && /* @__PURE__ */ jsx(
|
|
1760
|
+
"div",
|
|
1761
|
+
{
|
|
1762
|
+
className: "absolute inset-0",
|
|
1763
|
+
style: {
|
|
1764
|
+
backgroundImage: `url("${NOISE_DATA_URL}")`,
|
|
1765
|
+
backgroundRepeat: "repeat",
|
|
1766
|
+
backgroundSize: "240px 240px",
|
|
1767
|
+
backgroundPosition: `${time * 160}px ${time * 110}px`,
|
|
1768
|
+
opacity: Math.min(0.12, 0.03 + intensity * 0.06),
|
|
1769
|
+
mixBlendMode: "overlay",
|
|
1770
|
+
filter: "blur(0.4px) contrast(1.25)"
|
|
1771
|
+
},
|
|
1772
|
+
"aria-hidden": "true"
|
|
1773
|
+
}
|
|
1774
|
+
)
|
|
1775
|
+
}
|
|
1776
|
+
);
|
|
1777
|
+
}
|
|
1778
|
+
|
|
1779
|
+
// src/primitives/environment/FogLayer/types.ts
|
|
1780
|
+
var FOG_CONFIGS = {
|
|
1781
|
+
depth: {
|
|
1782
|
+
defaultColor: "#0a0a0f",
|
|
1783
|
+
defaultDensity: 0.5,
|
|
1784
|
+
animationSpeed: 0,
|
|
1785
|
+
gradientStops: 2
|
|
1786
|
+
},
|
|
1787
|
+
ground: {
|
|
1788
|
+
defaultColor: "#ffffff",
|
|
1789
|
+
defaultDensity: 0.7,
|
|
1790
|
+
animationSpeed: 0.02,
|
|
1791
|
+
gradientStops: 3
|
|
1792
|
+
},
|
|
1793
|
+
volumetric: {
|
|
1794
|
+
defaultColor: "#e8e8ff",
|
|
1795
|
+
defaultDensity: 0.4,
|
|
1796
|
+
animationSpeed: 0.01,
|
|
1797
|
+
gradientStops: 4
|
|
1798
|
+
},
|
|
1799
|
+
mist: {
|
|
1800
|
+
defaultColor: "#f0f0ff",
|
|
1801
|
+
defaultDensity: 0.3,
|
|
1802
|
+
animationSpeed: 0.015,
|
|
1803
|
+
gradientStops: 5
|
|
1804
|
+
}
|
|
1805
|
+
};
|
|
1806
|
+
function FogLayer({
|
|
1807
|
+
type,
|
|
1808
|
+
density: propDensity,
|
|
1809
|
+
color: propColor,
|
|
1810
|
+
height = 0.4,
|
|
1811
|
+
animated = true,
|
|
1812
|
+
intensity = 1,
|
|
1813
|
+
stylePreset = "ui",
|
|
1814
|
+
enabled = true,
|
|
1815
|
+
className,
|
|
1816
|
+
style
|
|
1817
|
+
}) {
|
|
1818
|
+
const reducedMotion = useReducedMotion();
|
|
1819
|
+
const perfConfig = getPerformanceConfig();
|
|
1820
|
+
const [offset, setOffset] = React3.useState(0);
|
|
1821
|
+
const config = FOG_CONFIGS[type];
|
|
1822
|
+
const density = propDensity ?? config.defaultDensity;
|
|
1823
|
+
const color = propColor ?? config.defaultColor;
|
|
1824
|
+
const shouldAnimate = animated && !reducedMotion && perfConfig.tier !== "minimal";
|
|
1825
|
+
React3.useEffect(() => {
|
|
1826
|
+
if (!shouldAnimate || !enabled || config.animationSpeed === 0) return;
|
|
1827
|
+
let frame;
|
|
1828
|
+
const animate = () => {
|
|
1829
|
+
setOffset((prev) => (prev + config.animationSpeed) % 100);
|
|
1830
|
+
frame = requestAnimationFrame(animate);
|
|
1831
|
+
};
|
|
1832
|
+
frame = requestAnimationFrame(animate);
|
|
1833
|
+
return () => cancelAnimationFrame(frame);
|
|
1834
|
+
}, [shouldAnimate, enabled, config.animationSpeed]);
|
|
1835
|
+
const gradientStyle = React3.useMemo(() => {
|
|
1836
|
+
const opacity = density * intensity;
|
|
1837
|
+
switch (type) {
|
|
1838
|
+
case "depth":
|
|
1839
|
+
return {
|
|
1840
|
+
background: `linear-gradient(to top, ${color}${Math.round(opacity * 255).toString(16).padStart(2, "0")}, transparent)`
|
|
1841
|
+
};
|
|
1842
|
+
case "ground":
|
|
1843
|
+
return {
|
|
1844
|
+
background: `linear-gradient(to top,
|
|
1845
|
+
${color}${Math.round(opacity * 255).toString(16).padStart(2, "0")} 0%,
|
|
1846
|
+
${color}${Math.round(opacity * 0.5 * 255).toString(16).padStart(2, "0")} ${height * 50}%,
|
|
1847
|
+
transparent ${height * 100}%)`
|
|
1848
|
+
};
|
|
1849
|
+
case "volumetric":
|
|
1850
|
+
return {
|
|
1851
|
+
background: `
|
|
1852
|
+
radial-gradient(ellipse 120% 60% at 50% ${100 - offset}%, ${color}${Math.round(opacity * 0.6 * 255).toString(16).padStart(2, "0")}, transparent),
|
|
1853
|
+
radial-gradient(ellipse 100% 40% at ${30 + offset * 0.2}% 80%, ${color}${Math.round(opacity * 0.4 * 255).toString(16).padStart(2, "0")}, transparent),
|
|
1854
|
+
radial-gradient(ellipse 80% 50% at ${70 - offset * 0.15}% 90%, ${color}${Math.round(opacity * 0.5 * 255).toString(16).padStart(2, "0")}, transparent)
|
|
1855
|
+
`
|
|
1856
|
+
};
|
|
1857
|
+
case "mist":
|
|
1858
|
+
return {
|
|
1859
|
+
background: `
|
|
1860
|
+
radial-gradient(ellipse 150% 80% at ${40 + Math.sin(offset * 0.1) * 20}% ${60 + Math.cos(offset * 0.08) * 10}%, ${color}${Math.round(opacity * 0.3 * 255).toString(16).padStart(2, "0")}, transparent),
|
|
1861
|
+
radial-gradient(ellipse 120% 60% at ${60 + Math.cos(offset * 0.12) * 15}% ${40 + Math.sin(offset * 0.09) * 15}%, ${color}${Math.round(opacity * 0.25 * 255).toString(16).padStart(2, "0")}, transparent),
|
|
1862
|
+
linear-gradient(to top, ${color}${Math.round(opacity * 0.15 * 255).toString(16).padStart(2, "0")}, transparent 50%)
|
|
1863
|
+
`
|
|
1864
|
+
};
|
|
1865
|
+
default:
|
|
1866
|
+
return {};
|
|
1867
|
+
}
|
|
1868
|
+
}, [type, color, density, intensity, height, offset]);
|
|
1869
|
+
if (!enabled) return null;
|
|
1870
|
+
return /* @__PURE__ */ jsx(
|
|
1871
|
+
"div",
|
|
1872
|
+
{
|
|
1873
|
+
className: cn(
|
|
1874
|
+
"pointer-events-none absolute inset-0",
|
|
1875
|
+
className
|
|
1876
|
+
),
|
|
1877
|
+
style: {
|
|
1878
|
+
...gradientStyle,
|
|
1879
|
+
...style
|
|
1880
|
+
},
|
|
1881
|
+
"aria-hidden": "true",
|
|
1882
|
+
children: stylePreset === "cinematic" && /* @__PURE__ */ jsx(
|
|
1883
|
+
"div",
|
|
1884
|
+
{
|
|
1885
|
+
className: "absolute inset-0",
|
|
1886
|
+
style: {
|
|
1887
|
+
backgroundImage: `url("${NOISE_DATA_URL}")`,
|
|
1888
|
+
backgroundRepeat: "repeat",
|
|
1889
|
+
backgroundSize: `${260 - Math.round(density * 80)}px ${260 - Math.round(density * 80)}px`,
|
|
1890
|
+
backgroundPosition: `${offset * 30}px ${offset * 20}px`,
|
|
1891
|
+
opacity: Math.min(0.18, 0.04 + density * intensity * 0.12),
|
|
1892
|
+
mixBlendMode: "soft-light",
|
|
1893
|
+
filter: "blur(0.6px) contrast(1.2)"
|
|
1894
|
+
},
|
|
1895
|
+
"aria-hidden": "true"
|
|
1896
|
+
}
|
|
1897
|
+
)
|
|
1898
|
+
}
|
|
1899
|
+
);
|
|
1900
|
+
}
|
|
1901
|
+
function ClusterAtmosphere({
|
|
1902
|
+
config,
|
|
1903
|
+
accentColor,
|
|
1904
|
+
className
|
|
1905
|
+
}) {
|
|
1906
|
+
return /* @__PURE__ */ jsxs(
|
|
1907
|
+
"div",
|
|
1908
|
+
{
|
|
1909
|
+
className: cn("pointer-events-none absolute inset-0", className),
|
|
1910
|
+
"aria-hidden": "true",
|
|
1911
|
+
children: [
|
|
1912
|
+
config.dustMotes && /* @__PURE__ */ jsx(
|
|
1913
|
+
DustMotesLayer,
|
|
1914
|
+
{
|
|
1915
|
+
colors: config.dustMotes.colors,
|
|
1916
|
+
density: config.dustMotes.density,
|
|
1917
|
+
speed: config.dustMotes.speed
|
|
1918
|
+
}
|
|
1919
|
+
),
|
|
1920
|
+
config.fog && /* @__PURE__ */ jsx(
|
|
1921
|
+
FogLayer,
|
|
1922
|
+
{
|
|
1923
|
+
type: config.fog.type,
|
|
1924
|
+
color: config.fog.color,
|
|
1925
|
+
intensity: config.fog.intensity
|
|
1926
|
+
}
|
|
1927
|
+
),
|
|
1928
|
+
config.light && /* @__PURE__ */ jsx(
|
|
1929
|
+
VolumetricLight,
|
|
1930
|
+
{
|
|
1931
|
+
type: config.light.type,
|
|
1932
|
+
color: config.light.color,
|
|
1933
|
+
intensity: config.light.intensity,
|
|
1934
|
+
source: config.light.source
|
|
1935
|
+
}
|
|
1936
|
+
)
|
|
1937
|
+
]
|
|
1938
|
+
}
|
|
1939
|
+
);
|
|
1940
|
+
}
|
|
1941
|
+
function GradientVeil({ className, intensity = 1 }) {
|
|
1942
|
+
const a1 = (0.85 * intensity).toFixed(2);
|
|
1943
|
+
const a2 = (0.5 * intensity).toFixed(2);
|
|
1944
|
+
const a3 = (0.2 * intensity).toFixed(2);
|
|
1945
|
+
return /* @__PURE__ */ jsx(
|
|
1946
|
+
"div",
|
|
1947
|
+
{
|
|
1948
|
+
className: cn("absolute inset-0 pointer-events-none", className),
|
|
1949
|
+
style: {
|
|
1950
|
+
background: `linear-gradient(
|
|
1951
|
+
to top,
|
|
1952
|
+
rgba(0, 0, 0, ${a1}) 0%,
|
|
1953
|
+
rgba(0, 0, 0, ${a2}) 30%,
|
|
1954
|
+
rgba(0, 0, 0, ${a3}) 50%,
|
|
1955
|
+
transparent 70%
|
|
1956
|
+
)`
|
|
1957
|
+
}
|
|
1958
|
+
}
|
|
1959
|
+
);
|
|
1960
|
+
}
|
|
1961
|
+
function StructuralElements({
|
|
1962
|
+
accentColor,
|
|
1963
|
+
className
|
|
1964
|
+
}) {
|
|
1965
|
+
return /* @__PURE__ */ jsxs(
|
|
1966
|
+
"div",
|
|
1967
|
+
{
|
|
1968
|
+
className: cn("pointer-events-none absolute inset-0 overflow-hidden", className),
|
|
1969
|
+
"aria-hidden": "true",
|
|
1970
|
+
children: [
|
|
1971
|
+
/* @__PURE__ */ jsx(CornerBrackets, { accentColor }),
|
|
1972
|
+
/* @__PURE__ */ jsx(
|
|
1973
|
+
"div",
|
|
1974
|
+
{
|
|
1975
|
+
className: "absolute inset-0",
|
|
1976
|
+
style: {
|
|
1977
|
+
background: `radial-gradient(ellipse 60% 80% at 85% 50%, ${accentColor}1A 0%, transparent 70%)`
|
|
1978
|
+
}
|
|
1979
|
+
}
|
|
1980
|
+
),
|
|
1981
|
+
/* @__PURE__ */ jsx(DotGrid, {})
|
|
1982
|
+
]
|
|
1983
|
+
}
|
|
1984
|
+
);
|
|
1985
|
+
}
|
|
1986
|
+
function CornerBrackets({ accentColor }) {
|
|
1987
|
+
const bracketLength = 40;
|
|
1988
|
+
const thickness = 2;
|
|
1989
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1990
|
+
/* @__PURE__ */ jsxs(
|
|
1991
|
+
motion.div,
|
|
1992
|
+
{
|
|
1993
|
+
className: "absolute top-6 left-6",
|
|
1994
|
+
initial: { opacity: 0 },
|
|
1995
|
+
animate: { opacity: 1 },
|
|
1996
|
+
transition: { duration: 0.8, delay: 0.2 },
|
|
1997
|
+
children: [
|
|
1998
|
+
/* @__PURE__ */ jsx(
|
|
1999
|
+
"div",
|
|
2000
|
+
{
|
|
2001
|
+
className: "absolute top-0 left-0",
|
|
2002
|
+
style: {
|
|
2003
|
+
width: bracketLength,
|
|
2004
|
+
height: thickness,
|
|
2005
|
+
backgroundColor: accentColor
|
|
2006
|
+
}
|
|
2007
|
+
}
|
|
2008
|
+
),
|
|
2009
|
+
/* @__PURE__ */ jsx(
|
|
2010
|
+
"div",
|
|
2011
|
+
{
|
|
2012
|
+
className: "absolute top-0 left-0",
|
|
2013
|
+
style: {
|
|
2014
|
+
width: thickness,
|
|
2015
|
+
height: bracketLength,
|
|
2016
|
+
backgroundColor: accentColor
|
|
2017
|
+
}
|
|
2018
|
+
}
|
|
2019
|
+
)
|
|
2020
|
+
]
|
|
2021
|
+
}
|
|
2022
|
+
),
|
|
2023
|
+
/* @__PURE__ */ jsxs(
|
|
2024
|
+
motion.div,
|
|
2025
|
+
{
|
|
2026
|
+
className: "absolute bottom-6 right-6",
|
|
2027
|
+
initial: { opacity: 0 },
|
|
2028
|
+
animate: { opacity: 1 },
|
|
2029
|
+
transition: { duration: 0.8, delay: 0.3 },
|
|
2030
|
+
children: [
|
|
2031
|
+
/* @__PURE__ */ jsx(
|
|
2032
|
+
"div",
|
|
2033
|
+
{
|
|
2034
|
+
className: "absolute bottom-0 right-0",
|
|
2035
|
+
style: {
|
|
2036
|
+
width: bracketLength,
|
|
2037
|
+
height: thickness,
|
|
2038
|
+
backgroundColor: accentColor
|
|
2039
|
+
}
|
|
2040
|
+
}
|
|
2041
|
+
),
|
|
2042
|
+
/* @__PURE__ */ jsx(
|
|
2043
|
+
"div",
|
|
2044
|
+
{
|
|
2045
|
+
className: "absolute bottom-0 right-0",
|
|
2046
|
+
style: {
|
|
2047
|
+
width: thickness,
|
|
2048
|
+
height: bracketLength,
|
|
2049
|
+
backgroundColor: accentColor
|
|
2050
|
+
}
|
|
2051
|
+
}
|
|
2052
|
+
)
|
|
2053
|
+
]
|
|
2054
|
+
}
|
|
2055
|
+
)
|
|
2056
|
+
] });
|
|
2057
|
+
}
|
|
2058
|
+
function DotGrid() {
|
|
2059
|
+
return /* @__PURE__ */ jsx(
|
|
2060
|
+
"div",
|
|
2061
|
+
{
|
|
2062
|
+
className: "absolute inset-0",
|
|
2063
|
+
style: {
|
|
2064
|
+
opacity: 0.04,
|
|
2065
|
+
backgroundImage: `radial-gradient(circle at center, currentColor 1px, transparent 1px)`,
|
|
2066
|
+
backgroundSize: "24px 24px"
|
|
2067
|
+
}
|
|
2068
|
+
}
|
|
2069
|
+
);
|
|
2070
|
+
}
|
|
2071
|
+
function VideoBackground({
|
|
2072
|
+
videoSrc,
|
|
2073
|
+
webmSrc,
|
|
2074
|
+
posterSrc,
|
|
2075
|
+
fallbackBackground,
|
|
2076
|
+
className,
|
|
2077
|
+
crossfadeDuration = 0.8,
|
|
2078
|
+
preload = true,
|
|
2079
|
+
playbackRate = 0.75,
|
|
2080
|
+
onLoad,
|
|
2081
|
+
onError
|
|
2082
|
+
}) {
|
|
2083
|
+
const [isVideoReady, setIsVideoReady] = useState(false);
|
|
2084
|
+
const [hasError, setHasError] = useState(false);
|
|
2085
|
+
const videoRef = useRef(null);
|
|
2086
|
+
const [prefersReducedMotion2, setPrefersReducedMotion] = useState(false);
|
|
2087
|
+
useEffect(() => {
|
|
2088
|
+
if (typeof window === "undefined") return;
|
|
2089
|
+
const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
2090
|
+
setPrefersReducedMotion(mediaQuery.matches);
|
|
2091
|
+
const handleChange = (e) => {
|
|
2092
|
+
setPrefersReducedMotion(e.matches);
|
|
2093
|
+
};
|
|
2094
|
+
mediaQuery.addEventListener("change", handleChange);
|
|
2095
|
+
return () => mediaQuery.removeEventListener("change", handleChange);
|
|
2096
|
+
}, []);
|
|
2097
|
+
const handleCanPlayThrough = useCallback(() => {
|
|
2098
|
+
setIsVideoReady(true);
|
|
2099
|
+
onLoad?.();
|
|
2100
|
+
}, [onLoad]);
|
|
2101
|
+
const handleError = useCallback(
|
|
2102
|
+
(e) => {
|
|
2103
|
+
setHasError(true);
|
|
2104
|
+
setIsVideoReady(false);
|
|
2105
|
+
onError?.(e.nativeEvent);
|
|
2106
|
+
},
|
|
2107
|
+
[onError]
|
|
2108
|
+
);
|
|
2109
|
+
useEffect(() => {
|
|
2110
|
+
const video = videoRef.current;
|
|
2111
|
+
if (!video || hasError || prefersReducedMotion2) return;
|
|
2112
|
+
video.playbackRate = playbackRate;
|
|
2113
|
+
const playPromise = video.play();
|
|
2114
|
+
if (playPromise !== void 0) {
|
|
2115
|
+
playPromise.catch(() => {
|
|
2116
|
+
});
|
|
2117
|
+
}
|
|
2118
|
+
}, [hasError, prefersReducedMotion2, playbackRate]);
|
|
2119
|
+
useEffect(() => {
|
|
2120
|
+
if (!preload || typeof document === "undefined") return;
|
|
2121
|
+
const links = [];
|
|
2122
|
+
if (posterSrc) {
|
|
2123
|
+
const posterLink = document.createElement("link");
|
|
2124
|
+
posterLink.rel = "preload";
|
|
2125
|
+
posterLink.as = "image";
|
|
2126
|
+
posterLink.href = posterSrc;
|
|
2127
|
+
document.head.appendChild(posterLink);
|
|
2128
|
+
links.push(posterLink);
|
|
2129
|
+
}
|
|
2130
|
+
if (videoSrc) {
|
|
2131
|
+
const videoLink = document.createElement("link");
|
|
2132
|
+
videoLink.rel = "preload";
|
|
2133
|
+
videoLink.as = "video";
|
|
2134
|
+
videoLink.href = videoSrc;
|
|
2135
|
+
if (videoSrc.endsWith(".mp4")) {
|
|
2136
|
+
videoLink.type = "video/mp4";
|
|
2137
|
+
} else if (videoSrc.endsWith(".webm")) {
|
|
2138
|
+
videoLink.type = "video/webm";
|
|
2139
|
+
}
|
|
2140
|
+
document.head.appendChild(videoLink);
|
|
2141
|
+
links.push(videoLink);
|
|
2142
|
+
}
|
|
2143
|
+
if (webmSrc) {
|
|
2144
|
+
const webmLink = document.createElement("link");
|
|
2145
|
+
webmLink.rel = "preload";
|
|
2146
|
+
webmLink.as = "video";
|
|
2147
|
+
webmLink.href = webmSrc;
|
|
2148
|
+
webmLink.type = "video/webm";
|
|
2149
|
+
document.head.appendChild(webmLink);
|
|
2150
|
+
links.push(webmLink);
|
|
2151
|
+
}
|
|
2152
|
+
return () => {
|
|
2153
|
+
links.forEach((link) => {
|
|
2154
|
+
if (link.parentNode === document.head) {
|
|
2155
|
+
document.head.removeChild(link);
|
|
2156
|
+
}
|
|
2157
|
+
});
|
|
2158
|
+
};
|
|
2159
|
+
}, [preload, videoSrc, webmSrc, posterSrc]);
|
|
2160
|
+
const mediaStyles = cn(
|
|
2161
|
+
"absolute inset-0 w-full h-full object-cover",
|
|
2162
|
+
className
|
|
2163
|
+
);
|
|
2164
|
+
const fallbackBg = fallbackBackground ?? "radial-gradient(1200px 700px at 50% 30%, rgba(255,255,255,0.10), rgba(0,0,0,0) 60%), linear-gradient(180deg, rgba(255,255,255,0.06), rgba(0,0,0,0) 40%), #000";
|
|
2165
|
+
const posterBackgroundImage = posterSrc ? `url(${posterSrc}), ${fallbackBg}` : fallbackBg;
|
|
2166
|
+
const posterBackgroundSize = posterSrc ? "cover, cover" : "cover";
|
|
2167
|
+
const posterBackgroundPosition = posterSrc ? "center, center" : "center";
|
|
2168
|
+
if (prefersReducedMotion2) {
|
|
2169
|
+
return /* @__PURE__ */ jsx(
|
|
2170
|
+
"div",
|
|
2171
|
+
{
|
|
2172
|
+
className: mediaStyles,
|
|
2173
|
+
style: {
|
|
2174
|
+
backgroundImage: posterBackgroundImage,
|
|
2175
|
+
backgroundSize: posterBackgroundSize,
|
|
2176
|
+
backgroundPosition: posterBackgroundPosition
|
|
2177
|
+
},
|
|
2178
|
+
role: "img",
|
|
2179
|
+
"aria-label": "Background image"
|
|
2180
|
+
}
|
|
2181
|
+
);
|
|
2182
|
+
}
|
|
2183
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2184
|
+
/* @__PURE__ */ jsx(
|
|
2185
|
+
"div",
|
|
2186
|
+
{
|
|
2187
|
+
className: cn(mediaStyles, "z-0"),
|
|
2188
|
+
style: {
|
|
2189
|
+
backgroundImage: posterBackgroundImage,
|
|
2190
|
+
backgroundSize: posterBackgroundSize,
|
|
2191
|
+
backgroundPosition: posterBackgroundPosition
|
|
2192
|
+
},
|
|
2193
|
+
role: "img",
|
|
2194
|
+
"aria-hidden": isVideoReady && !hasError
|
|
2195
|
+
}
|
|
2196
|
+
),
|
|
2197
|
+
/* @__PURE__ */ jsx(AnimatePresence, { children: !hasError && /* @__PURE__ */ jsxs(
|
|
2198
|
+
motion.video,
|
|
2199
|
+
{
|
|
2200
|
+
ref: videoRef,
|
|
2201
|
+
className: cn(mediaStyles, "z-10"),
|
|
2202
|
+
poster: posterSrc,
|
|
2203
|
+
autoPlay: true,
|
|
2204
|
+
muted: true,
|
|
2205
|
+
loop: true,
|
|
2206
|
+
playsInline: true,
|
|
2207
|
+
disablePictureInPicture: true,
|
|
2208
|
+
disableRemotePlayback: true,
|
|
2209
|
+
onCanPlayThrough: handleCanPlayThrough,
|
|
2210
|
+
onError: handleError,
|
|
2211
|
+
initial: { opacity: 0 },
|
|
2212
|
+
animate: { opacity: isVideoReady ? 1 : 0 },
|
|
2213
|
+
exit: { opacity: 0 },
|
|
2214
|
+
transition: {
|
|
2215
|
+
opacity: {
|
|
2216
|
+
duration: crossfadeDuration,
|
|
2217
|
+
ease: [0.4, 0, 0.2, 1]
|
|
2218
|
+
// ease-out cubic
|
|
2219
|
+
}
|
|
2220
|
+
},
|
|
2221
|
+
"aria-hidden": "true",
|
|
2222
|
+
children: [
|
|
2223
|
+
webmSrc && /* @__PURE__ */ jsx("source", { src: webmSrc, type: "video/webm" }),
|
|
2224
|
+
/* @__PURE__ */ jsx("source", { src: videoSrc, type: "video/mp4" })
|
|
2225
|
+
]
|
|
2226
|
+
},
|
|
2227
|
+
videoSrc
|
|
2228
|
+
) })
|
|
2229
|
+
] });
|
|
2230
|
+
}
|
|
2231
|
+
var fadeUpVariants = {
|
|
2232
|
+
hidden: { opacity: 0, y: 20 },
|
|
2233
|
+
visible: { opacity: 1, y: 0 }
|
|
2234
|
+
};
|
|
2235
|
+
var staggerContainer = {
|
|
2236
|
+
hidden: { opacity: 0 },
|
|
2237
|
+
visible: {
|
|
2238
|
+
opacity: 1,
|
|
2239
|
+
transition: {
|
|
2240
|
+
staggerChildren: 0.12,
|
|
2241
|
+
delayChildren: 0.1
|
|
2242
|
+
}
|
|
2243
|
+
}
|
|
2244
|
+
};
|
|
2245
|
+
function ClusterName({ name }) {
|
|
2246
|
+
return /* @__PURE__ */ jsx(
|
|
2247
|
+
motion.h2,
|
|
2248
|
+
{
|
|
2249
|
+
variants: fadeUpVariants,
|
|
2250
|
+
className: "text-4xl md:text-5xl lg:text-6xl font-semibold uppercase text-white",
|
|
2251
|
+
style: {
|
|
2252
|
+
fontVariant: "small-caps",
|
|
2253
|
+
letterSpacing: "0.12em"
|
|
2254
|
+
},
|
|
2255
|
+
children: name
|
|
2256
|
+
}
|
|
2257
|
+
);
|
|
2258
|
+
}
|
|
2259
|
+
function Tagline({ text }) {
|
|
2260
|
+
return /* @__PURE__ */ jsx(
|
|
2261
|
+
motion.p,
|
|
2262
|
+
{
|
|
2263
|
+
variants: fadeUpVariants,
|
|
2264
|
+
className: "text-lg md:text-xl text-white/70 font-light italic leading-relaxed mt-3",
|
|
2265
|
+
children: text
|
|
2266
|
+
}
|
|
2267
|
+
);
|
|
2268
|
+
}
|
|
2269
|
+
function MetricsRow({
|
|
2270
|
+
metrics
|
|
2271
|
+
}) {
|
|
2272
|
+
const formattedRealms = metrics.realms.toLocaleString();
|
|
2273
|
+
return /* @__PURE__ */ jsxs(
|
|
2274
|
+
motion.div,
|
|
2275
|
+
{
|
|
2276
|
+
variants: fadeUpVariants,
|
|
2277
|
+
className: "flex items-center gap-2 font-mono text-xs text-white/50 mt-4 tracking-wide",
|
|
2278
|
+
children: [
|
|
2279
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
2280
|
+
formattedRealms,
|
|
2281
|
+
" realms"
|
|
2282
|
+
] }),
|
|
2283
|
+
/* @__PURE__ */ jsx("span", { className: "text-white/30", children: "\u2022" }),
|
|
2284
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
2285
|
+
metrics.output24h,
|
|
2286
|
+
" output"
|
|
2287
|
+
] }),
|
|
2288
|
+
metrics.rank !== void 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2289
|
+
/* @__PURE__ */ jsx("span", { className: "text-white/30", children: "\u2022" }),
|
|
2290
|
+
/* @__PURE__ */ jsxs("span", { children: [
|
|
2291
|
+
"Rank #",
|
|
2292
|
+
metrics.rank
|
|
2293
|
+
] })
|
|
2294
|
+
] })
|
|
2295
|
+
]
|
|
2296
|
+
}
|
|
2297
|
+
);
|
|
2298
|
+
}
|
|
2299
|
+
function RailButton({ button }) {
|
|
2300
|
+
const baseClasses = "w-full px-6 py-3 text-sm font-medium tracking-wider uppercase transition-all duration-300 text-center";
|
|
2301
|
+
const variantClasses = {
|
|
2302
|
+
primary: "text-neutral-900 hover:brightness-110 hover:scale-[1.02]",
|
|
2303
|
+
secondary: "bg-transparent border hover:bg-[var(--cluster-accent)]/10",
|
|
2304
|
+
ghost: "bg-transparent border-none text-white/50 hover:text-white/80"
|
|
2305
|
+
};
|
|
2306
|
+
const variantStyles = {
|
|
2307
|
+
primary: {
|
|
2308
|
+
backgroundColor: "var(--cluster-accent)"
|
|
2309
|
+
},
|
|
2310
|
+
secondary: {
|
|
2311
|
+
borderColor: "var(--cluster-accent)",
|
|
2312
|
+
color: "var(--cluster-accent)"
|
|
2313
|
+
},
|
|
2314
|
+
ghost: {}
|
|
2315
|
+
};
|
|
2316
|
+
return /* @__PURE__ */ jsx(
|
|
2317
|
+
motion.a,
|
|
2318
|
+
{
|
|
2319
|
+
variants: fadeUpVariants,
|
|
2320
|
+
href: button.href,
|
|
2321
|
+
className: cn(baseClasses, variantClasses[button.variant]),
|
|
2322
|
+
style: variantStyles[button.variant],
|
|
2323
|
+
...button.external && {
|
|
2324
|
+
target: "_blank",
|
|
2325
|
+
rel: "noopener noreferrer"
|
|
2326
|
+
},
|
|
2327
|
+
children: button.label
|
|
2328
|
+
}
|
|
2329
|
+
);
|
|
2330
|
+
}
|
|
2331
|
+
function ButtonStack({ buttons }) {
|
|
2332
|
+
return /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-3 mt-8 w-full max-w-xs", children: buttons.map((button) => /* @__PURE__ */ jsx(RailButton, { button }, button.label)) });
|
|
2333
|
+
}
|
|
2334
|
+
function ClusterRail({
|
|
2335
|
+
name,
|
|
2336
|
+
tagline,
|
|
2337
|
+
metrics,
|
|
2338
|
+
buttons,
|
|
2339
|
+
accentColor,
|
|
2340
|
+
className
|
|
2341
|
+
}) {
|
|
2342
|
+
return /* @__PURE__ */ jsxs(
|
|
2343
|
+
motion.aside,
|
|
2344
|
+
{
|
|
2345
|
+
variants: staggerContainer,
|
|
2346
|
+
initial: "hidden",
|
|
2347
|
+
animate: "visible",
|
|
2348
|
+
className: cn("flex flex-col items-start", className),
|
|
2349
|
+
style: {
|
|
2350
|
+
"--cluster-accent": accentColor
|
|
2351
|
+
},
|
|
2352
|
+
children: [
|
|
2353
|
+
/* @__PURE__ */ jsx(ClusterName, { name }),
|
|
2354
|
+
/* @__PURE__ */ jsx(Tagline, { text: tagline }),
|
|
2355
|
+
/* @__PURE__ */ jsx(MetricsRow, { metrics }),
|
|
2356
|
+
/* @__PURE__ */ jsx(ButtonStack, { buttons })
|
|
2357
|
+
]
|
|
2358
|
+
}
|
|
2359
|
+
);
|
|
2360
|
+
}
|
|
2361
|
+
var containerVariants = {
|
|
2362
|
+
hidden: { opacity: 0 },
|
|
2363
|
+
visible: {
|
|
2364
|
+
opacity: 1,
|
|
2365
|
+
transition: {
|
|
2366
|
+
staggerChildren: 0.12,
|
|
2367
|
+
delayChildren: 0.1
|
|
2368
|
+
}
|
|
2369
|
+
}
|
|
2370
|
+
};
|
|
2371
|
+
var itemVariants = {
|
|
2372
|
+
hidden: { opacity: 0, y: 12 },
|
|
2373
|
+
visible: {
|
|
2374
|
+
opacity: 1,
|
|
2375
|
+
y: 0,
|
|
2376
|
+
transition: {
|
|
2377
|
+
duration: 0.5,
|
|
2378
|
+
ease: [0.22, 1, 0.36, 1]
|
|
2379
|
+
}
|
|
2380
|
+
}
|
|
2381
|
+
};
|
|
2382
|
+
function Description({ text }) {
|
|
2383
|
+
return /* @__PURE__ */ jsx(
|
|
2384
|
+
motion.p,
|
|
2385
|
+
{
|
|
2386
|
+
variants: itemVariants,
|
|
2387
|
+
className: "text-sm text-white/70 leading-relaxed max-w-xs whitespace-pre-line",
|
|
2388
|
+
children: text
|
|
2389
|
+
}
|
|
2390
|
+
);
|
|
2391
|
+
}
|
|
2392
|
+
function CapabilityChips({
|
|
2393
|
+
capabilities,
|
|
2394
|
+
accentColor
|
|
2395
|
+
}) {
|
|
2396
|
+
return /* @__PURE__ */ jsx(motion.div, { variants: itemVariants, className: "flex flex-wrap gap-2", children: capabilities.map((capability) => /* @__PURE__ */ jsx(
|
|
2397
|
+
"span",
|
|
2398
|
+
{
|
|
2399
|
+
className: "px-2.5 py-1 text-[10px] uppercase tracking-widest text-white/80 rounded-sm",
|
|
2400
|
+
style: {
|
|
2401
|
+
backgroundColor: `color-mix(in srgb, ${accentColor} 15%, transparent)`
|
|
2402
|
+
},
|
|
2403
|
+
children: capability
|
|
2404
|
+
},
|
|
2405
|
+
capability
|
|
2406
|
+
)) });
|
|
2407
|
+
}
|
|
2408
|
+
function FastPath({
|
|
2409
|
+
fastPath,
|
|
2410
|
+
accentColor
|
|
2411
|
+
}) {
|
|
2412
|
+
return /* @__PURE__ */ jsxs(
|
|
2413
|
+
motion.a,
|
|
2414
|
+
{
|
|
2415
|
+
variants: itemVariants,
|
|
2416
|
+
href: fastPath.href,
|
|
2417
|
+
className: "group inline-flex items-center gap-2 text-sm transition-colors duration-200 hover:brightness-125",
|
|
2418
|
+
style: { color: accentColor },
|
|
2419
|
+
children: [
|
|
2420
|
+
/* @__PURE__ */ jsx("span", { children: fastPath.label }),
|
|
2421
|
+
/* @__PURE__ */ jsx(
|
|
2422
|
+
"svg",
|
|
2423
|
+
{
|
|
2424
|
+
width: "16",
|
|
2425
|
+
height: "16",
|
|
2426
|
+
viewBox: "0 0 16 16",
|
|
2427
|
+
fill: "none",
|
|
2428
|
+
className: "transition-transform duration-200 group-hover:translate-x-1",
|
|
2429
|
+
children: /* @__PURE__ */ jsx(
|
|
2430
|
+
"path",
|
|
2431
|
+
{
|
|
2432
|
+
d: "M6 4L10 8L6 12",
|
|
2433
|
+
stroke: "currentColor",
|
|
2434
|
+
strokeWidth: "1.5",
|
|
2435
|
+
strokeLinecap: "round",
|
|
2436
|
+
strokeLinejoin: "round"
|
|
2437
|
+
}
|
|
2438
|
+
)
|
|
2439
|
+
}
|
|
2440
|
+
)
|
|
2441
|
+
]
|
|
2442
|
+
}
|
|
2443
|
+
);
|
|
2444
|
+
}
|
|
2445
|
+
function StatusLine({
|
|
2446
|
+
status
|
|
2447
|
+
}) {
|
|
2448
|
+
return /* @__PURE__ */ jsxs(
|
|
2449
|
+
motion.div,
|
|
2450
|
+
{
|
|
2451
|
+
variants: itemVariants,
|
|
2452
|
+
className: "font-mono text-[10px] text-white/50 tracking-wide",
|
|
2453
|
+
children: [
|
|
2454
|
+
"Network: ",
|
|
2455
|
+
status.network,
|
|
2456
|
+
/* @__PURE__ */ jsx("span", { className: "mx-2", children: "\u2022" }),
|
|
2457
|
+
"Verification: ",
|
|
2458
|
+
status.verification,
|
|
2459
|
+
/* @__PURE__ */ jsx("span", { className: "mx-2", children: "\u2022" }),
|
|
2460
|
+
"Fees: ",
|
|
2461
|
+
status.fees
|
|
2462
|
+
]
|
|
2463
|
+
}
|
|
2464
|
+
);
|
|
2465
|
+
}
|
|
2466
|
+
function BriefingPanel({
|
|
2467
|
+
description,
|
|
2468
|
+
capabilities,
|
|
2469
|
+
fastPath,
|
|
2470
|
+
status,
|
|
2471
|
+
accentColor,
|
|
2472
|
+
className
|
|
2473
|
+
}) {
|
|
2474
|
+
return /* @__PURE__ */ jsxs(
|
|
2475
|
+
motion.div,
|
|
2476
|
+
{
|
|
2477
|
+
variants: containerVariants,
|
|
2478
|
+
initial: "hidden",
|
|
2479
|
+
animate: "visible",
|
|
2480
|
+
className: cn("flex flex-col gap-4 rounded-xl p-4 backdrop-blur-xl", className),
|
|
2481
|
+
style: {
|
|
2482
|
+
background: "rgba(2,4,10,0.6)",
|
|
2483
|
+
border: "1px solid rgba(255,255,255,0.06)"
|
|
2484
|
+
},
|
|
2485
|
+
children: [
|
|
2486
|
+
/* @__PURE__ */ jsx(Description, { text: description }),
|
|
2487
|
+
/* @__PURE__ */ jsx(CapabilityChips, { capabilities, accentColor }),
|
|
2488
|
+
/* @__PURE__ */ jsx(FastPath, { fastPath, accentColor }),
|
|
2489
|
+
/* @__PURE__ */ jsx(StatusLine, { status })
|
|
2490
|
+
]
|
|
2491
|
+
}
|
|
2492
|
+
);
|
|
2493
|
+
}
|
|
2494
|
+
function SigilMonument({
|
|
2495
|
+
name,
|
|
2496
|
+
tagline,
|
|
2497
|
+
latinMotto,
|
|
2498
|
+
sigilSrc,
|
|
2499
|
+
accentColor,
|
|
2500
|
+
className
|
|
2501
|
+
}) {
|
|
2502
|
+
const containerRef = useRef(null);
|
|
2503
|
+
const styleId = useId();
|
|
2504
|
+
const [sigilFailed, setSigilFailed] = useState(false);
|
|
2505
|
+
const initials = useMemo(() => {
|
|
2506
|
+
const parts = name.trim().split(/\s+/).filter(Boolean);
|
|
2507
|
+
const letters = parts.map((p) => p[0] ?? "").join("");
|
|
2508
|
+
return letters.slice(0, 2).toUpperCase() || name.slice(0, 2).toUpperCase();
|
|
2509
|
+
}, [name]);
|
|
2510
|
+
useEffect(() => {
|
|
2511
|
+
setSigilFailed(false);
|
|
2512
|
+
}, [sigilSrc]);
|
|
2513
|
+
const mouseX = useMotionValue(0);
|
|
2514
|
+
const mouseY = useMotionValue(0);
|
|
2515
|
+
const springConfig = { damping: 25, stiffness: 150 };
|
|
2516
|
+
const parallaxX = useSpring(
|
|
2517
|
+
useTransform(mouseX, [-1, 1], [-4, 4]),
|
|
2518
|
+
springConfig
|
|
2519
|
+
);
|
|
2520
|
+
const parallaxY = useSpring(
|
|
2521
|
+
useTransform(mouseY, [-1, 1], [-4, 4]),
|
|
2522
|
+
springConfig
|
|
2523
|
+
);
|
|
2524
|
+
const handleMouseMove = (e) => {
|
|
2525
|
+
if (!containerRef.current) return;
|
|
2526
|
+
const rect = containerRef.current.getBoundingClientRect();
|
|
2527
|
+
const centerX = rect.left + rect.width / 2;
|
|
2528
|
+
const centerY = rect.top + rect.height / 2;
|
|
2529
|
+
const normalizedX = (e.clientX - centerX) / (rect.width / 2);
|
|
2530
|
+
const normalizedY = (e.clientY - centerY) / (rect.height / 2);
|
|
2531
|
+
mouseX.set(Math.max(-1, Math.min(1, normalizedX)));
|
|
2532
|
+
mouseY.set(Math.max(-1, Math.min(1, normalizedY)));
|
|
2533
|
+
};
|
|
2534
|
+
const handleMouseLeave = () => {
|
|
2535
|
+
mouseX.set(0);
|
|
2536
|
+
mouseY.set(0);
|
|
2537
|
+
};
|
|
2538
|
+
const shimmerClass = `sigil-shimmer-${styleId.replace(/:/g, "")}`;
|
|
2539
|
+
return /* @__PURE__ */ jsxs(
|
|
2540
|
+
"div",
|
|
2541
|
+
{
|
|
2542
|
+
ref: containerRef,
|
|
2543
|
+
onMouseMove: handleMouseMove,
|
|
2544
|
+
onMouseLeave: handleMouseLeave,
|
|
2545
|
+
className: cn(
|
|
2546
|
+
"relative flex flex-col items-center justify-center",
|
|
2547
|
+
className
|
|
2548
|
+
),
|
|
2549
|
+
style: { "--sigil-accent": accentColor },
|
|
2550
|
+
children: [
|
|
2551
|
+
/* @__PURE__ */ jsx(
|
|
2552
|
+
"style",
|
|
2553
|
+
{
|
|
2554
|
+
dangerouslySetInnerHTML: {
|
|
2555
|
+
__html: `
|
|
2556
|
+
@keyframes ${shimmerClass}-anim {
|
|
2557
|
+
0% { background-position: 200% 0; }
|
|
2558
|
+
100% { background-position: -200% 0; }
|
|
2559
|
+
}
|
|
2560
|
+
.${shimmerClass} {
|
|
2561
|
+
animation: ${shimmerClass}-anim 10s ease-in-out infinite;
|
|
2562
|
+
}
|
|
2563
|
+
`
|
|
2564
|
+
}
|
|
2565
|
+
}
|
|
2566
|
+
),
|
|
2567
|
+
/* @__PURE__ */ jsxs(
|
|
2568
|
+
motion.div,
|
|
2569
|
+
{
|
|
2570
|
+
className: "relative",
|
|
2571
|
+
style: {
|
|
2572
|
+
x: parallaxX,
|
|
2573
|
+
y: parallaxY
|
|
2574
|
+
},
|
|
2575
|
+
children: [
|
|
2576
|
+
/* @__PURE__ */ jsx(
|
|
2577
|
+
"div",
|
|
2578
|
+
{
|
|
2579
|
+
className: "absolute inset-0 pointer-events-none overflow-hidden",
|
|
2580
|
+
"aria-hidden": "true",
|
|
2581
|
+
children: /* @__PURE__ */ jsx(
|
|
2582
|
+
"div",
|
|
2583
|
+
{
|
|
2584
|
+
className: `absolute inset-0 ${shimmerClass}`,
|
|
2585
|
+
style: {
|
|
2586
|
+
background: `linear-gradient(
|
|
2587
|
+
105deg,
|
|
2588
|
+
transparent 40%,
|
|
2589
|
+
${accentColor}15 45%,
|
|
2590
|
+
${accentColor}25 50%,
|
|
2591
|
+
${accentColor}15 55%,
|
|
2592
|
+
transparent 60%
|
|
2593
|
+
)`,
|
|
2594
|
+
backgroundSize: "200% 100%"
|
|
2595
|
+
}
|
|
2596
|
+
}
|
|
2597
|
+
)
|
|
2598
|
+
}
|
|
2599
|
+
),
|
|
2600
|
+
!sigilFailed && sigilSrc ? /* @__PURE__ */ jsx(
|
|
2601
|
+
"img",
|
|
2602
|
+
{
|
|
2603
|
+
src: sigilSrc,
|
|
2604
|
+
alt: `${name} sigil`,
|
|
2605
|
+
className: "h-[35vh] min-h-[280px] max-h-[45vh] w-auto object-contain drop-shadow-2xl",
|
|
2606
|
+
style: {
|
|
2607
|
+
filter: `drop-shadow(0 0 60px ${accentColor}40)`
|
|
2608
|
+
},
|
|
2609
|
+
onError: () => setSigilFailed(true)
|
|
2610
|
+
}
|
|
2611
|
+
) : /* @__PURE__ */ jsx(
|
|
2612
|
+
"div",
|
|
2613
|
+
{
|
|
2614
|
+
className: "h-[35vh] min-h-[280px] max-h-[45vh] aspect-square rounded-full flex items-center justify-center",
|
|
2615
|
+
style: {
|
|
2616
|
+
background: `radial-gradient(circle at 30% 30%, ${accentColor}35, transparent 65%), radial-gradient(circle at 70% 80%, ${accentColor}18, transparent 60%), rgba(255,255,255,0.02)`,
|
|
2617
|
+
border: `1px solid ${accentColor}40`,
|
|
2618
|
+
boxShadow: `0 0 60px ${accentColor}30, inset 0 0 40px rgba(255,255,255,0.08)`,
|
|
2619
|
+
filter: `drop-shadow(0 0 60px ${accentColor}40)`
|
|
2620
|
+
},
|
|
2621
|
+
"aria-hidden": "true",
|
|
2622
|
+
children: /* @__PURE__ */ jsx(
|
|
2623
|
+
"div",
|
|
2624
|
+
{
|
|
2625
|
+
className: "font-serif text-6xl text-white/70 tracking-[0.18em]",
|
|
2626
|
+
style: { textShadow: `0 0 30px ${accentColor}30` },
|
|
2627
|
+
children: initials
|
|
2628
|
+
}
|
|
2629
|
+
)
|
|
2630
|
+
}
|
|
2631
|
+
)
|
|
2632
|
+
]
|
|
2633
|
+
}
|
|
2634
|
+
),
|
|
2635
|
+
/* @__PURE__ */ jsxs("div", { className: "mt-10 text-center", children: [
|
|
2636
|
+
/* @__PURE__ */ jsx(
|
|
2637
|
+
"h2",
|
|
2638
|
+
{
|
|
2639
|
+
className: "font-serif text-3xl md:text-4xl text-white/95 mb-3",
|
|
2640
|
+
style: {
|
|
2641
|
+
fontVariant: "small-caps",
|
|
2642
|
+
letterSpacing: "0.12em"
|
|
2643
|
+
},
|
|
2644
|
+
children: name
|
|
2645
|
+
}
|
|
2646
|
+
),
|
|
2647
|
+
/* @__PURE__ */ jsx("p", { className: "font-serif text-lg md:text-xl text-white/60 italic max-w-md leading-relaxed", children: tagline }),
|
|
2648
|
+
latinMotto && /* @__PURE__ */ jsx(
|
|
2649
|
+
"p",
|
|
2650
|
+
{
|
|
2651
|
+
className: "mt-4 font-mono text-[10px] uppercase tracking-[0.2em] text-white/30",
|
|
2652
|
+
"aria-label": "Latin motto",
|
|
2653
|
+
children: latinMotto
|
|
2654
|
+
}
|
|
2655
|
+
)
|
|
2656
|
+
] })
|
|
2657
|
+
]
|
|
2658
|
+
}
|
|
2659
|
+
);
|
|
2660
|
+
}
|
|
2661
|
+
var DEFAULT_CONTENT = {
|
|
2662
|
+
market: "3 new blueprints published today",
|
|
2663
|
+
live: "24 active workflows running",
|
|
2664
|
+
governance: "Proposal #18 \u2014 Voting ends in 6h",
|
|
2665
|
+
progress: "You minted 4 verified artifacts this week"
|
|
2666
|
+
};
|
|
2667
|
+
var MODULE_ICONS = {
|
|
2668
|
+
market: FileText,
|
|
2669
|
+
live: Zap,
|
|
2670
|
+
governance: Vote,
|
|
2671
|
+
progress: Trophy
|
|
2672
|
+
};
|
|
2673
|
+
function LiveStrip({
|
|
2674
|
+
moduleType,
|
|
2675
|
+
content,
|
|
2676
|
+
accentColor,
|
|
2677
|
+
className
|
|
2678
|
+
}) {
|
|
2679
|
+
const Icon = MODULE_ICONS[moduleType];
|
|
2680
|
+
const displayContent = content ?? DEFAULT_CONTENT[moduleType];
|
|
2681
|
+
return /* @__PURE__ */ jsxs(
|
|
2682
|
+
"div",
|
|
2683
|
+
{
|
|
2684
|
+
className: cn(
|
|
2685
|
+
"group flex items-center gap-3 px-4 py-2.5 rounded-lg bg-white/[0.05] backdrop-blur-sm",
|
|
2686
|
+
"transition-colors duration-200 hover:bg-white/[0.10] cursor-pointer",
|
|
2687
|
+
className
|
|
2688
|
+
),
|
|
2689
|
+
children: [
|
|
2690
|
+
/* @__PURE__ */ jsx(
|
|
2691
|
+
Icon,
|
|
2692
|
+
{
|
|
2693
|
+
className: "w-4 h-4 shrink-0 transition-colors duration-200",
|
|
2694
|
+
style: { color: accentColor }
|
|
2695
|
+
}
|
|
2696
|
+
),
|
|
2697
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm text-white/80 font-normal flex-1 truncate", children: displayContent }),
|
|
2698
|
+
/* @__PURE__ */ jsx(
|
|
2699
|
+
ArrowRight,
|
|
2700
|
+
{
|
|
2701
|
+
className: cn(
|
|
2702
|
+
"w-4 h-4 shrink-0 text-white/40",
|
|
2703
|
+
"transition-all duration-200 ease-out",
|
|
2704
|
+
"group-hover:translate-x-1 group-hover:text-white/60"
|
|
2705
|
+
)
|
|
2706
|
+
}
|
|
2707
|
+
)
|
|
2708
|
+
]
|
|
2709
|
+
}
|
|
2710
|
+
);
|
|
2711
|
+
}
|
|
2712
|
+
function useVideoPreload({
|
|
2713
|
+
videoSrc,
|
|
2714
|
+
posterSrc,
|
|
2715
|
+
enabled = true
|
|
2716
|
+
}) {
|
|
2717
|
+
const [isPreloaded, setIsPreloaded] = useState(false);
|
|
2718
|
+
useEffect(() => {
|
|
2719
|
+
if (!enabled || typeof document === "undefined") {
|
|
2720
|
+
return;
|
|
2721
|
+
}
|
|
2722
|
+
const links = [];
|
|
2723
|
+
if (posterSrc) {
|
|
2724
|
+
const posterLink = document.createElement("link");
|
|
2725
|
+
posterLink.rel = "preload";
|
|
2726
|
+
posterLink.as = "image";
|
|
2727
|
+
posterLink.href = posterSrc;
|
|
2728
|
+
document.head.appendChild(posterLink);
|
|
2729
|
+
links.push(posterLink);
|
|
2730
|
+
}
|
|
2731
|
+
if (videoSrc) {
|
|
2732
|
+
const videoLink = document.createElement("link");
|
|
2733
|
+
videoLink.rel = "preload";
|
|
2734
|
+
videoLink.as = "video";
|
|
2735
|
+
videoLink.href = videoSrc;
|
|
2736
|
+
if (videoSrc.endsWith(".webm")) {
|
|
2737
|
+
videoLink.type = "video/webm";
|
|
2738
|
+
} else if (videoSrc.endsWith(".mp4")) {
|
|
2739
|
+
videoLink.type = "video/mp4";
|
|
2740
|
+
}
|
|
2741
|
+
document.head.appendChild(videoLink);
|
|
2742
|
+
links.push(videoLink);
|
|
2743
|
+
}
|
|
2744
|
+
setIsPreloaded(true);
|
|
2745
|
+
return () => {
|
|
2746
|
+
links.forEach((link) => {
|
|
2747
|
+
if (link.parentNode === document.head) {
|
|
2748
|
+
document.head.removeChild(link);
|
|
2749
|
+
}
|
|
2750
|
+
});
|
|
2751
|
+
};
|
|
2752
|
+
}, [videoSrc, posterSrc, enabled]);
|
|
2753
|
+
return { isPreloaded };
|
|
2754
|
+
}
|
|
2755
|
+
function ClusterHero({ cluster, className }) {
|
|
2756
|
+
const config = getClusterConfigWithResolvedUrls(cluster);
|
|
2757
|
+
const fallbackBackground = `radial-gradient(900px 600px at 65% 25%, rgba(${config.accentColorRGB}, 0.22), rgba(0,0,0,0) 62%), radial-gradient(700px 520px at 25% 78%, rgba(${config.accentColorRGB}, 0.10), rgba(0,0,0,0) 58%), #000`;
|
|
2758
|
+
useVideoPreload({
|
|
2759
|
+
videoSrc: config.videoSrc,
|
|
2760
|
+
posterSrc: config.videoPoster
|
|
2761
|
+
});
|
|
2762
|
+
return /* @__PURE__ */ jsxs(
|
|
2763
|
+
"section",
|
|
2764
|
+
{
|
|
2765
|
+
className: cn(
|
|
2766
|
+
"relative min-h-screen h-full w-full overflow-hidden bg-black",
|
|
2767
|
+
className
|
|
2768
|
+
),
|
|
2769
|
+
style: { "--cluster-accent": config.accentColor },
|
|
2770
|
+
children: [
|
|
2771
|
+
/* @__PURE__ */ jsx(
|
|
2772
|
+
VideoBackground,
|
|
2773
|
+
{
|
|
2774
|
+
videoSrc: config.videoSrc,
|
|
2775
|
+
posterSrc: config.videoPoster,
|
|
2776
|
+
preload: true,
|
|
2777
|
+
fallbackBackground,
|
|
2778
|
+
className: "z-0"
|
|
2779
|
+
}
|
|
2780
|
+
),
|
|
2781
|
+
/* @__PURE__ */ jsx(
|
|
2782
|
+
StructuralElements,
|
|
2783
|
+
{
|
|
2784
|
+
accentColor: config.accentColor,
|
|
2785
|
+
className: "z-[5]"
|
|
2786
|
+
}
|
|
2787
|
+
),
|
|
2788
|
+
/* @__PURE__ */ jsx(
|
|
2789
|
+
ClusterAtmosphere,
|
|
2790
|
+
{
|
|
2791
|
+
config: config.atmosphere,
|
|
2792
|
+
accentColor: config.accentColor,
|
|
2793
|
+
className: "z-10"
|
|
2794
|
+
}
|
|
2795
|
+
),
|
|
2796
|
+
/* @__PURE__ */ jsx(GradientVeil, { className: "z-20" }),
|
|
2797
|
+
/* @__PURE__ */ jsx(
|
|
2798
|
+
"div",
|
|
2799
|
+
{
|
|
2800
|
+
className: "absolute z-30",
|
|
2801
|
+
style: { top: "80px", left: "48px", maxWidth: "380px" },
|
|
2802
|
+
children: /* @__PURE__ */ jsx(
|
|
2803
|
+
BriefingPanel,
|
|
2804
|
+
{
|
|
2805
|
+
description: config.description,
|
|
2806
|
+
capabilities: config.capabilities,
|
|
2807
|
+
fastPath: config.fastPath,
|
|
2808
|
+
status: config.status,
|
|
2809
|
+
accentColor: config.accentColor
|
|
2810
|
+
}
|
|
2811
|
+
)
|
|
2812
|
+
}
|
|
2813
|
+
),
|
|
2814
|
+
/* @__PURE__ */ jsx(
|
|
2815
|
+
"div",
|
|
2816
|
+
{
|
|
2817
|
+
className: "absolute z-30",
|
|
2818
|
+
style: { top: "50%", right: "80px", transform: "translateY(-50%)" },
|
|
2819
|
+
children: /* @__PURE__ */ jsx(
|
|
2820
|
+
SigilMonument,
|
|
2821
|
+
{
|
|
2822
|
+
name: config.name,
|
|
2823
|
+
tagline: config.tagline,
|
|
2824
|
+
latinMotto: config.latinMotto,
|
|
2825
|
+
sigilSrc: config.sigilSrc,
|
|
2826
|
+
accentColor: config.accentColor
|
|
2827
|
+
}
|
|
2828
|
+
)
|
|
2829
|
+
}
|
|
2830
|
+
),
|
|
2831
|
+
/* @__PURE__ */ jsx(
|
|
2832
|
+
"div",
|
|
2833
|
+
{
|
|
2834
|
+
className: "absolute z-30",
|
|
2835
|
+
style: { bottom: "80px", left: "50%", transform: "translateX(-50%)", maxWidth: "600px", width: "100%" },
|
|
2836
|
+
children: /* @__PURE__ */ jsx(
|
|
2837
|
+
LiveStrip,
|
|
2838
|
+
{
|
|
2839
|
+
moduleType: config.liveModule,
|
|
2840
|
+
content: config.liveContent,
|
|
2841
|
+
accentColor: config.accentColor
|
|
2842
|
+
}
|
|
2843
|
+
)
|
|
2844
|
+
}
|
|
2845
|
+
),
|
|
2846
|
+
/* @__PURE__ */ jsx(
|
|
2847
|
+
"div",
|
|
2848
|
+
{
|
|
2849
|
+
className: "absolute z-40",
|
|
2850
|
+
style: { bottom: "32px", left: "48px", maxWidth: "280px" },
|
|
2851
|
+
children: /* @__PURE__ */ jsx(
|
|
2852
|
+
ClusterRail,
|
|
2853
|
+
{
|
|
2854
|
+
name: config.name,
|
|
2855
|
+
tagline: config.tagline,
|
|
2856
|
+
metrics: config.metrics,
|
|
2857
|
+
buttons: config.buttons,
|
|
2858
|
+
accentColor: config.accentColor
|
|
2859
|
+
}
|
|
2860
|
+
)
|
|
2861
|
+
}
|
|
2862
|
+
)
|
|
2863
|
+
]
|
|
2864
|
+
}
|
|
2865
|
+
);
|
|
2866
|
+
}
|
|
2867
|
+
var FEATURE_DATA = {
|
|
2868
|
+
alexandria: [
|
|
2869
|
+
{ title: "Knowledge Graph", description: "Interconnected data structures that compound understanding over time", icon: "book" },
|
|
2870
|
+
{ title: "Semantic Search", description: "Query across documents with natural language understanding", icon: "search" },
|
|
2871
|
+
{ title: "Version History", description: "Every edit preserved, every branch trackable", icon: "history" }
|
|
2872
|
+
],
|
|
2873
|
+
alpha: [
|
|
2874
|
+
{ title: "Genesis Protocol", description: "The foundational layer from which all clusters derive", icon: "origin" },
|
|
2875
|
+
{ title: "Core APIs", description: "Stable interfaces that power the entire ecosystem", icon: "api" },
|
|
2876
|
+
{ title: "Identity Layer", description: "Sovereign authentication across all surfaces", icon: "key" }
|
|
2877
|
+
],
|
|
2878
|
+
opus: [
|
|
2879
|
+
{ title: "Diagnostic Engines", description: "AI-powered analysis pipelines for medical imaging and patient data", icon: "scan" },
|
|
2880
|
+
{ title: "Care Protocols", description: "Autonomous coordination of treatment workflows and provider networks", icon: "workflow" },
|
|
2881
|
+
{ title: "Compliance Layer", description: "Built-in HIPAA, SOC2, and regulatory framework adherence", icon: "shield" }
|
|
2882
|
+
],
|
|
2883
|
+
baia: [
|
|
2884
|
+
{ title: "Neural Canvas", description: "Generative models that transform prompts into visual masterpieces", icon: "palette" },
|
|
2885
|
+
{ title: "Sound Synthesis", description: "AI composition engines for music, ambience, and audio design", icon: "waveform" },
|
|
2886
|
+
{ title: "Style Transfer", description: "Cross-modal translation between artistic mediums and formats", icon: "layers" }
|
|
2887
|
+
],
|
|
2888
|
+
kdot: [
|
|
2889
|
+
{ title: "Mesh Network", description: "Distributed connectivity that routes around failures", icon: "network" },
|
|
2890
|
+
{ title: "Protocol Layer", description: "Universal translation between disparate systems", icon: "protocol" },
|
|
2891
|
+
{ title: "Node Discovery", description: "Automatic peer detection and topology mapping", icon: "discovery" }
|
|
2892
|
+
],
|
|
2893
|
+
aegis: [
|
|
2894
|
+
{ title: "Threat Detection", description: "Real-time monitoring for anomalous patterns", icon: "shield" },
|
|
2895
|
+
{ title: "Access Control", description: "Fine-grained permissions and authentication flows", icon: "lock" },
|
|
2896
|
+
{ title: "Audit Trail", description: "Immutable logs of every action and decision", icon: "log" }
|
|
2897
|
+
],
|
|
2898
|
+
providence: [
|
|
2899
|
+
{ title: "Threat Intelligence", description: "Predictive analysis and proactive defense postures", icon: "radar" },
|
|
2900
|
+
{ title: "Incident Response", description: "Automated containment and remediation workflows", icon: "alert" },
|
|
2901
|
+
{ title: "Compliance Engine", description: "Continuous verification against security frameworks", icon: "certificate" }
|
|
2902
|
+
]
|
|
2903
|
+
};
|
|
2904
|
+
function FeatureCard({
|
|
2905
|
+
title,
|
|
2906
|
+
description,
|
|
2907
|
+
accentColor,
|
|
2908
|
+
index
|
|
2909
|
+
}) {
|
|
2910
|
+
return /* @__PURE__ */ jsxs(
|
|
2911
|
+
motion.article,
|
|
2912
|
+
{
|
|
2913
|
+
initial: { opacity: 0, y: 40 },
|
|
2914
|
+
whileInView: { opacity: 1, y: 0 },
|
|
2915
|
+
viewport: { once: true, margin: "-100px" },
|
|
2916
|
+
transition: {
|
|
2917
|
+
duration: 0.6,
|
|
2918
|
+
delay: index * 0.15,
|
|
2919
|
+
ease: [0.22, 1, 0.36, 1]
|
|
2920
|
+
},
|
|
2921
|
+
className: "group relative p-8 bg-zinc-900/80 backdrop-blur-sm border border-zinc-800 hover:border-zinc-700 transition-colors duration-300",
|
|
2922
|
+
children: [
|
|
2923
|
+
/* @__PURE__ */ jsx(
|
|
2924
|
+
"div",
|
|
2925
|
+
{
|
|
2926
|
+
className: "absolute top-0 left-0 w-1 h-0 group-hover:h-full transition-all duration-500",
|
|
2927
|
+
style: { backgroundColor: accentColor }
|
|
2928
|
+
}
|
|
2929
|
+
),
|
|
2930
|
+
/* @__PURE__ */ jsx("h3", { className: "font-serif text-2xl text-white mb-3 tracking-wide", children: title }),
|
|
2931
|
+
/* @__PURE__ */ jsx("p", { className: "text-neutral-400 leading-relaxed", children: description })
|
|
2932
|
+
]
|
|
2933
|
+
}
|
|
2934
|
+
);
|
|
2935
|
+
}
|
|
2936
|
+
function FeatureCardsSection({ clusterId, config }) {
|
|
2937
|
+
const features = FEATURE_DATA[clusterId];
|
|
2938
|
+
return /* @__PURE__ */ jsx("section", { className: "relative z-10 bg-zinc-950 py-32 px-16", children: /* @__PURE__ */ jsxs("div", { className: "max-w-7xl mx-auto", children: [
|
|
2939
|
+
/* @__PURE__ */ jsxs(
|
|
2940
|
+
motion.header,
|
|
2941
|
+
{
|
|
2942
|
+
initial: { opacity: 0, y: 20 },
|
|
2943
|
+
whileInView: { opacity: 1, y: 0 },
|
|
2944
|
+
viewport: { once: true },
|
|
2945
|
+
transition: { duration: 0.6 },
|
|
2946
|
+
className: "mb-16",
|
|
2947
|
+
children: [
|
|
2948
|
+
/* @__PURE__ */ jsx(
|
|
2949
|
+
"span",
|
|
2950
|
+
{
|
|
2951
|
+
className: "font-mono text-xs uppercase tracking-[0.2em]",
|
|
2952
|
+
style: { color: config.accentColor },
|
|
2953
|
+
children: "Capabilities"
|
|
2954
|
+
}
|
|
2955
|
+
),
|
|
2956
|
+
/* @__PURE__ */ jsxs("h2", { className: "font-serif text-5xl text-white mt-4 tracking-wide", children: [
|
|
2957
|
+
"What defines ",
|
|
2958
|
+
config.name
|
|
2959
|
+
] })
|
|
2960
|
+
]
|
|
2961
|
+
}
|
|
2962
|
+
),
|
|
2963
|
+
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 md:grid-cols-3 gap-6", children: features.map((feature, index) => /* @__PURE__ */ jsx(
|
|
2964
|
+
FeatureCard,
|
|
2965
|
+
{
|
|
2966
|
+
title: feature.title,
|
|
2967
|
+
description: feature.description,
|
|
2968
|
+
accentColor: config.accentColor,
|
|
2969
|
+
index
|
|
2970
|
+
},
|
|
2971
|
+
feature.title
|
|
2972
|
+
)) })
|
|
2973
|
+
] }) });
|
|
2974
|
+
}
|
|
2975
|
+
var STATS_DATA = {
|
|
2976
|
+
alexandria: [
|
|
2977
|
+
{ value: "2.4M", label: "Documents Indexed" },
|
|
2978
|
+
{ value: "847K", label: "Active Queries/Day" },
|
|
2979
|
+
{ value: "99.97%", label: "Uptime" },
|
|
2980
|
+
{ value: "12ms", label: "Avg Response" }
|
|
2981
|
+
],
|
|
2982
|
+
alpha: [
|
|
2983
|
+
{ value: "1.0", label: "Protocol Version" },
|
|
2984
|
+
{ value: "\u221E", label: "Scalability" },
|
|
2985
|
+
{ value: "100%", label: "Backwards Compatible" },
|
|
2986
|
+
{ value: "0", label: "Breaking Changes" }
|
|
2987
|
+
],
|
|
2988
|
+
opus: [
|
|
2989
|
+
{ value: "2.4M", label: "Diagnostics Processed" },
|
|
2990
|
+
{ value: "847", label: "Active Protocols" },
|
|
2991
|
+
{ value: "99.97%", label: "Compliance Rate" },
|
|
2992
|
+
{ value: "< 2s", label: "Analysis Latency" }
|
|
2993
|
+
],
|
|
2994
|
+
baia: [
|
|
2995
|
+
{ value: "4.2M", label: "Works Generated" },
|
|
2996
|
+
{ value: "156K", label: "Active Artists" },
|
|
2997
|
+
{ value: "847K", label: "Daily Renders" },
|
|
2998
|
+
{ value: "12TB", label: "Media Produced" }
|
|
2999
|
+
],
|
|
3000
|
+
kdot: [
|
|
3001
|
+
{ value: "1.2M", label: "Connected Nodes" },
|
|
3002
|
+
{ value: "47ms", label: "Avg Latency" },
|
|
3003
|
+
{ value: "99.99%", label: "Uptime" },
|
|
3004
|
+
{ value: "8.4PB", label: "Daily Throughput" }
|
|
3005
|
+
],
|
|
3006
|
+
aegis: [
|
|
3007
|
+
{ value: "0", label: "Breaches" },
|
|
3008
|
+
{ value: "2.1B", label: "Threats Blocked" },
|
|
3009
|
+
{ value: "99.97%", label: "Detection Rate" },
|
|
3010
|
+
{ value: "< 1s", label: "Response Time" }
|
|
3011
|
+
],
|
|
3012
|
+
providence: [
|
|
3013
|
+
{ value: "24/7", label: "Monitoring" },
|
|
3014
|
+
{ value: "847K", label: "Threats Analyzed" },
|
|
3015
|
+
{ value: "99.99%", label: "Uptime" },
|
|
3016
|
+
{ value: "< 50ms", label: "Alert Latency" }
|
|
3017
|
+
]
|
|
3018
|
+
};
|
|
3019
|
+
function StatBlock({
|
|
3020
|
+
value,
|
|
3021
|
+
label,
|
|
3022
|
+
accentColor,
|
|
3023
|
+
index
|
|
3024
|
+
}) {
|
|
3025
|
+
return /* @__PURE__ */ jsxs(
|
|
3026
|
+
motion.div,
|
|
3027
|
+
{
|
|
3028
|
+
initial: { opacity: 0, scale: 0.9 },
|
|
3029
|
+
whileInView: { opacity: 1, scale: 1 },
|
|
3030
|
+
viewport: { once: true, margin: "-50px" },
|
|
3031
|
+
transition: {
|
|
3032
|
+
duration: 0.5,
|
|
3033
|
+
delay: index * 0.1,
|
|
3034
|
+
ease: [0.22, 1, 0.36, 1]
|
|
3035
|
+
},
|
|
3036
|
+
className: "text-center p-8",
|
|
3037
|
+
children: [
|
|
3038
|
+
/* @__PURE__ */ jsx(
|
|
3039
|
+
"div",
|
|
3040
|
+
{
|
|
3041
|
+
className: "font-mono text-5xl md:text-6xl font-light mb-3",
|
|
3042
|
+
style: { color: accentColor },
|
|
3043
|
+
children: value
|
|
3044
|
+
}
|
|
3045
|
+
),
|
|
3046
|
+
/* @__PURE__ */ jsx("div", { className: "text-neutral-400 uppercase tracking-[0.15em] text-sm", children: label })
|
|
3047
|
+
]
|
|
3048
|
+
}
|
|
3049
|
+
);
|
|
3050
|
+
}
|
|
3051
|
+
function ClusterStatsSection({ clusterId, config }) {
|
|
3052
|
+
const stats = STATS_DATA[clusterId];
|
|
3053
|
+
return /* @__PURE__ */ jsx("section", { className: "relative z-10 bg-black py-32 px-16", children: /* @__PURE__ */ jsxs("div", { className: "max-w-6xl mx-auto", children: [
|
|
3054
|
+
/* @__PURE__ */ jsx(
|
|
3055
|
+
motion.div,
|
|
3056
|
+
{
|
|
3057
|
+
initial: { scaleX: 0 },
|
|
3058
|
+
whileInView: { scaleX: 1 },
|
|
3059
|
+
viewport: { once: true },
|
|
3060
|
+
transition: { duration: 1, ease: [0.22, 1, 0.36, 1] },
|
|
3061
|
+
className: "h-px mb-16 origin-left",
|
|
3062
|
+
style: { backgroundColor: config.accentColor }
|
|
3063
|
+
}
|
|
3064
|
+
),
|
|
3065
|
+
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 md:grid-cols-4 gap-8", children: stats.map((stat, index) => /* @__PURE__ */ jsx(
|
|
3066
|
+
StatBlock,
|
|
3067
|
+
{
|
|
3068
|
+
value: stat.value,
|
|
3069
|
+
label: stat.label,
|
|
3070
|
+
accentColor: config.accentColor,
|
|
3071
|
+
index
|
|
3072
|
+
},
|
|
3073
|
+
stat.label
|
|
3074
|
+
)) }),
|
|
3075
|
+
/* @__PURE__ */ jsx(
|
|
3076
|
+
motion.div,
|
|
3077
|
+
{
|
|
3078
|
+
initial: { scaleX: 0 },
|
|
3079
|
+
whileInView: { scaleX: 1 },
|
|
3080
|
+
viewport: { once: true },
|
|
3081
|
+
transition: { duration: 1, ease: [0.22, 1, 0.36, 1] },
|
|
3082
|
+
className: "h-px mt-16 origin-right",
|
|
3083
|
+
style: { backgroundColor: config.accentColor }
|
|
3084
|
+
}
|
|
3085
|
+
)
|
|
3086
|
+
] }) });
|
|
3087
|
+
}
|
|
3088
|
+
var CTA_DATA = {
|
|
3089
|
+
alexandria: {
|
|
3090
|
+
headline: "Begin your research",
|
|
3091
|
+
subtext: "Join thousands of scholars building the world's knowledge commons",
|
|
3092
|
+
buttonLabel: "Enter Alexandria"
|
|
3093
|
+
},
|
|
3094
|
+
alpha: {
|
|
3095
|
+
headline: "Start from the source",
|
|
3096
|
+
subtext: "Everything begins here. Every journey starts with Alpha.",
|
|
3097
|
+
buttonLabel: "Initialize"
|
|
3098
|
+
},
|
|
3099
|
+
opus: {
|
|
3100
|
+
headline: "Healthcare, autonomous",
|
|
3101
|
+
subtext: "Diagnostic pipelines and care protocols that run themselves.",
|
|
3102
|
+
buttonLabel: "Enter Opus"
|
|
3103
|
+
},
|
|
3104
|
+
baia: {
|
|
3105
|
+
headline: "Art from the machine",
|
|
3106
|
+
subtext: "Generative works that blur the line between human and artificial creativity.",
|
|
3107
|
+
buttonLabel: "Open Studio"
|
|
3108
|
+
},
|
|
3109
|
+
kdot: {
|
|
3110
|
+
headline: "Join the mesh",
|
|
3111
|
+
subtext: "Connect to the network that never sleeps.",
|
|
3112
|
+
buttonLabel: "Connect Now"
|
|
3113
|
+
},
|
|
3114
|
+
aegis: {
|
|
3115
|
+
headline: "Secure your realm",
|
|
3116
|
+
subtext: "Protection that scales with your ambition.",
|
|
3117
|
+
buttonLabel: "Activate Shield"
|
|
3118
|
+
},
|
|
3119
|
+
providence: {
|
|
3120
|
+
headline: "Foresee. Prevent. Prevail.",
|
|
3121
|
+
subtext: "Security through foresight. Protection before the threat arrives.",
|
|
3122
|
+
buttonLabel: "Enter Providence"
|
|
3123
|
+
}
|
|
3124
|
+
};
|
|
3125
|
+
function CTASection({ clusterId, config }) {
|
|
3126
|
+
const cta = CTA_DATA[clusterId];
|
|
3127
|
+
return /* @__PURE__ */ jsx("section", { className: "relative z-10 bg-zinc-950 py-48 px-16", children: /* @__PURE__ */ jsxs(
|
|
3128
|
+
motion.div,
|
|
3129
|
+
{
|
|
3130
|
+
initial: { opacity: 0, y: 60 },
|
|
3131
|
+
whileInView: { opacity: 1, y: 0 },
|
|
3132
|
+
viewport: { once: true, margin: "-100px" },
|
|
3133
|
+
transition: { duration: 0.8, ease: [0.22, 1, 0.36, 1] },
|
|
3134
|
+
className: "max-w-4xl mx-auto text-center",
|
|
3135
|
+
children: [
|
|
3136
|
+
/* @__PURE__ */ jsx("h2", { className: "font-serif text-6xl md:text-7xl text-white tracking-wide mb-8 leading-[1.1]", children: cta.headline }),
|
|
3137
|
+
/* @__PURE__ */ jsx("p", { className: "text-xl text-neutral-400 mb-12 max-w-2xl mx-auto leading-relaxed", children: cta.subtext }),
|
|
3138
|
+
/* @__PURE__ */ jsx(
|
|
3139
|
+
"a",
|
|
3140
|
+
{
|
|
3141
|
+
href: `/clusters/${clusterId}`,
|
|
3142
|
+
className: "inline-block px-12 py-5 text-lg font-medium tracking-wider uppercase text-neutral-900 transition-all duration-300 hover:brightness-110 hover:scale-105",
|
|
3143
|
+
style: { backgroundColor: config.accentColor },
|
|
3144
|
+
children: cta.buttonLabel
|
|
3145
|
+
}
|
|
3146
|
+
)
|
|
3147
|
+
]
|
|
3148
|
+
}
|
|
3149
|
+
) });
|
|
3150
|
+
}
|
|
3151
|
+
function ClusterHeroPage({ clusterId, className }) {
|
|
3152
|
+
const containerRef = useRef(null);
|
|
3153
|
+
const config = getClusterConfigWithResolvedUrls(clusterId);
|
|
3154
|
+
const { scrollYProgress } = useScroll({
|
|
3155
|
+
target: containerRef,
|
|
3156
|
+
offset: ["start start", "end start"]
|
|
3157
|
+
});
|
|
3158
|
+
const heroOpacity = useTransform(scrollYProgress, [0, 0.15], [1, 0.3]);
|
|
3159
|
+
const heroY = useTransform(scrollYProgress, [0, 0.3], [0, -100]);
|
|
3160
|
+
return /* @__PURE__ */ jsxs(
|
|
3161
|
+
"main",
|
|
3162
|
+
{
|
|
3163
|
+
ref: containerRef,
|
|
3164
|
+
className: cn(
|
|
3165
|
+
"relative scroll-smooth",
|
|
3166
|
+
className
|
|
3167
|
+
),
|
|
3168
|
+
children: [
|
|
3169
|
+
/* @__PURE__ */ jsx(
|
|
3170
|
+
motion.div,
|
|
3171
|
+
{
|
|
3172
|
+
className: "sticky top-0 h-screen overflow-hidden",
|
|
3173
|
+
style: { opacity: heroOpacity },
|
|
3174
|
+
children: /* @__PURE__ */ jsx(motion.div, { style: { y: heroY }, className: "h-full", children: /* @__PURE__ */ jsx(ClusterHero, { cluster: clusterId, className: "h-full" }) })
|
|
3175
|
+
}
|
|
3176
|
+
),
|
|
3177
|
+
/* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
3178
|
+
/* @__PURE__ */ jsx(FeatureCardsSection, { clusterId, config }),
|
|
3179
|
+
/* @__PURE__ */ jsx(ClusterStatsSection, { clusterId, config }),
|
|
3180
|
+
/* @__PURE__ */ jsx(CTASection, { clusterId, config })
|
|
3181
|
+
] })
|
|
3182
|
+
]
|
|
3183
|
+
}
|
|
3184
|
+
);
|
|
3185
|
+
}
|
|
3186
|
+
|
|
3187
|
+
export { AgentPanel, BBProvider, CLUSTER_CONFIGS, ClusterHero, ClusterHeroPage, PlaySession, SyncDocument, getClusterConfig, useBBContext, useBBContextOptional };
|
|
11
3188
|
//# sourceMappingURL=index.js.map
|
|
12
3189
|
//# sourceMappingURL=index.js.map
|