@devrongx/games 0.4.33 → 0.4.34

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devrongx/games",
3
- "version": "0.4.33",
3
+ "version": "0.4.34",
4
4
  "description": "Game UI components for sports prediction markets",
5
5
  "license": "MIT",
6
6
  "main": "./src/index.ts",
@@ -16,10 +16,10 @@ const Particle = ({ delay, angle, distance, size, color }: { delay: number; angl
16
16
  return (
17
17
  <motion.div
18
18
  className="absolute rounded-full"
19
- style={{ width: size, height: size, background: color, left: "50%", top: "40%" }}
19
+ style={{ width: size, height: size, background: color, left: "50%", top: "35%", boxShadow: `0 0 ${size * 3}px ${color}` }}
20
20
  initial={{ x: 0, y: 0, opacity: 0, scale: 0 }}
21
- animate={{ x, y: y - 20, opacity: [0, 1, 1, 0], scale: [0, 1.5, 1, 0] }}
22
- transition={{ duration: 1.4, delay, ease: "easeOut" }}
21
+ animate={{ x, y: y - 30, opacity: [0, 1, 0.8, 0], scale: [0, 1.8, 0.8, 0] }}
22
+ transition={{ duration: 1.6, delay, ease: "easeOut" }}
23
23
  />
24
24
  );
25
25
  };
@@ -27,26 +27,36 @@ const Particle = ({ delay, angle, distance, size, color }: { delay: number; angl
27
27
  // ─── Animated SVG checkmark ──────────────────────────────────────────────────
28
28
 
29
29
  const AnimatedCheck = ({ delay = 0, size = 56 }: { delay?: number; size?: number }) => (
30
- <motion.svg
31
- width={size} height={size} viewBox="0 0 56 56" fill="none"
32
- initial={{ scale: 0 }} animate={{ scale: 1 }}
30
+ <motion.div
31
+ initial={{ scale: 0 }}
32
+ animate={{ scale: 1 }}
33
33
  transition={{ type: "spring", stiffness: 260, damping: 14, delay }}
34
34
  >
35
- <motion.circle
36
- cx="28" cy="28" r="26" stroke="#22E3E8" strokeWidth="2"
37
- fill="rgba(34,227,232,0.06)"
38
- initial={{ pathLength: 0, opacity: 0 }}
39
- animate={{ pathLength: 1, opacity: 1 }}
40
- transition={{ duration: 0.6, delay: delay + 0.1, ease: "easeOut" }}
41
- />
42
- <motion.path
43
- d="M17 28l8 8 14-14" stroke="#22E3E8" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"
44
- fill="none"
45
- initial={{ pathLength: 0 }}
46
- animate={{ pathLength: 1 }}
47
- transition={{ duration: 0.4, delay: delay + 0.5, ease: "easeOut" }}
48
- />
49
- </motion.svg>
35
+ <motion.div
36
+ className="rounded-full flex items-center justify-center"
37
+ style={{ width: size, height: size, boxShadow: "0 0 40px rgba(34,227,232,0.3), 0 0 80px rgba(34,227,232,0.1)" }}
38
+ initial={{ opacity: 0 }}
39
+ animate={{ opacity: 1 }}
40
+ transition={{ delay, duration: 0.3 }}
41
+ >
42
+ <svg width={size} height={size} viewBox="0 0 56 56" fill="none">
43
+ <motion.circle
44
+ cx="28" cy="28" r="26" stroke="#22E3E8" strokeWidth="1.5"
45
+ fill="none"
46
+ initial={{ pathLength: 0, opacity: 0 }}
47
+ animate={{ pathLength: 1, opacity: 0.6 }}
48
+ transition={{ duration: 0.7, delay: delay + 0.1, ease: "easeOut" }}
49
+ />
50
+ <motion.path
51
+ d="M17 28l8 8 14-14" stroke="#22E3E8" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"
52
+ fill="none"
53
+ initial={{ pathLength: 0 }}
54
+ animate={{ pathLength: 1 }}
55
+ transition={{ duration: 0.4, delay: delay + 0.55, ease: "easeOut" }}
56
+ />
57
+ </svg>
58
+ </motion.div>
59
+ </motion.div>
50
60
  );
51
61
 
52
62
  // ─── Props ───────────────────────────────────────────────────────────────────
@@ -68,7 +78,6 @@ export const BetCelebration = ({
68
78
  }: BetCelebrationProps) => {
69
79
  const { totalEntry, compoundedReward } = betSummary;
70
80
 
71
- // Build list of bets to display
72
81
  const displayBets = useMemo(() => {
73
82
  const entries: { mIdx: number; question: string; optionLabel: string; amount: number; odds: number; reward: number }[] = [];
74
83
  if (isEdit && editedMarketIdx !== undefined) {
@@ -93,84 +102,81 @@ export const BetCelebration = ({
93
102
  }, [bets, config, isEdit, editedMarketIdx]);
94
103
 
95
104
  // Timing
96
- const particleCount = isEdit ? 10 : 20;
97
- const checkDelay = 0.15;
98
- const titleDelay = checkDelay + 0.4;
99
- const betStartDelay = isEdit ? 0.5 : 0.8;
100
- const betStagger = isEdit ? 0.1 : 0.15;
101
- const outcomeDelay = betStartDelay + displayBets.length * betStagger + 0.25;
102
- const lineDelay = outcomeDelay + (isEdit ? 0.2 : 0.4);
103
- const messageDelay = lineDelay + 0.5;
104
- const buttonDelay = messageDelay + 0.2;
105
+ const particleCount = isEdit ? 8 : 24;
106
+ const checkDelay = 0.1;
107
+ const titleDelay = checkDelay + 0.5;
108
+ const betStartDelay = isEdit ? 0.5 : 0.9;
109
+ const betStagger = isEdit ? 0.08 : 0.12;
110
+ const outcomeDelay = betStartDelay + displayBets.length * betStagger + 0.3;
111
+ const lineDelay = isEdit ? betStartDelay + displayBets.length * betStagger + 0.2 : outcomeDelay + 0.4;
112
+ const messageDelay = lineDelay + 0.6;
113
+ const buttonDelay = messageDelay + 0.15;
105
114
 
106
115
  return (
107
116
  <motion.div
108
- className="fixed inset-0 z-50 flex items-center justify-center px-4"
117
+ className="fixed inset-0 z-50 flex items-center justify-center px-6"
109
118
  initial={{ opacity: 0 }}
110
119
  animate={{ opacity: 1 }}
111
120
  exit={{ opacity: 0 }}
112
- transition={{ duration: 0.25 }}
121
+ transition={{ duration: 0.3 }}
113
122
  >
114
- {/* Backdrop */}
123
+ {/* Blurred backdrop */}
115
124
  <motion.div
116
125
  className="absolute inset-0"
117
- style={{ background: "rgba(0,0,0,0.70)" }}
126
+ style={{ backdropFilter: "blur(16px)", WebkitBackdropFilter: "blur(16px)", background: "rgba(0,0,0,0.55)" }}
118
127
  onClick={onClose}
119
128
  />
120
129
 
121
130
  {/* Firework particles */}
122
131
  <div className="absolute inset-0 pointer-events-none overflow-hidden">
123
132
  {Array.from({ length: particleCount }, (_, i) => {
124
- const angle = (360 / particleCount) * i + (i % 3) * 8;
125
- const distance = 60 + (i % 4) * 35;
126
- const size = 2 + (i % 3) * 2;
127
- const colors = ["#22E3E8", "#22E3E8", "#22E3E8", "#9945FF", "rgba(255,255,255,0.9)"];
128
- return <Particle key={i} delay={checkDelay + 0.3 + (i % 5) * 0.06} angle={angle} distance={distance} size={size} color={colors[i % colors.length]} />;
133
+ const angle = (360 / particleCount) * i + (i % 3) * 5;
134
+ const distance = 50 + (i % 5) * 30;
135
+ const size = 2 + (i % 3) * 1.5;
136
+ const colors = ["#22E3E8", "#22E3E8", "#22E3E8", "#22E3E8", "rgba(255,255,255,0.8)"];
137
+ return <Particle key={i} delay={checkDelay + 0.4 + (i % 6) * 0.04} angle={angle} distance={distance} size={size} color={colors[i % colors.length]} />;
129
138
  })}
130
- {/* Second burst */}
131
- {!isEdit && Array.from({ length: 12 }, (_, i) => {
132
- const angle = (360 / 12) * i + 15;
133
- const distance = 100 + (i % 3) * 40;
134
- const size = 1.5 + (i % 2) * 1.5;
135
- return <Particle key={`b${i}`} delay={outcomeDelay + (i % 4) * 0.05} angle={angle} distance={distance} size={size} color="#22E3E8" />;
139
+ {!isEdit && Array.from({ length: 16 }, (_, i) => {
140
+ const angle = (360 / 16) * i + 11;
141
+ const distance = 90 + (i % 4) * 30;
142
+ const size = 1.5 + (i % 3);
143
+ return <Particle key={`b${i}`} delay={outcomeDelay + (i % 5) * 0.04} angle={angle} distance={distance} size={size} color="#22E3E8" />;
136
144
  })}
137
145
  </div>
138
146
 
139
- {/* Content card */}
147
+ {/* Floating content — no card, no border */}
140
148
  <motion.div
141
- className="relative z-10 w-full max-w-[340px] max-h-[80vh] overflow-y-auto rounded-2xl px-5 py-6 flex flex-col items-center gap-3"
142
- style={{ background: "linear-gradient(180deg, #111122 0%, #0a0a12 100%)", border: "1px solid rgba(34,227,232,0.12)" }}
143
- initial={{ scale: 0.85, opacity: 0, y: 20 }}
149
+ className="relative z-10 w-full max-w-[320px] max-h-[80vh] overflow-y-auto flex flex-col items-center gap-4 py-4"
150
+ initial={{ scale: 0.9, opacity: 0, y: 16 }}
144
151
  animate={{ scale: 1, opacity: 1, y: 0 }}
145
- transition={{ type: "spring", stiffness: 280, damping: 20, delay: 0.05 }}
152
+ transition={{ type: "spring", stiffness: 250, damping: 20, delay: 0.05 }}
146
153
  onClick={(e) => e.stopPropagation()}
147
154
  >
148
155
  {/* Checkmark */}
149
- <AnimatedCheck delay={checkDelay} size={isEdit ? 44 : 56} />
156
+ <AnimatedCheck delay={checkDelay} size={isEdit ? 40 : 52} />
150
157
 
151
158
  {/* Title */}
152
159
  <motion.p
153
160
  className="font-bold text-white text-center"
154
- style={{ ...OUTFIT, fontSize: isEdit ? 16 : 20 }}
155
- initial={{ opacity: 0, y: 8 }}
161
+ style={{ ...OUTFIT, fontSize: isEdit ? 15 : 18, letterSpacing: "0.02em" }}
162
+ initial={{ opacity: 0, y: 6 }}
156
163
  animate={{ opacity: 1, y: 0 }}
157
164
  transition={{ delay: titleDelay, duration: 0.3 }}
158
165
  >
159
- {isEdit ? "Bet Updated!" : "Bets Placed!"}
166
+ {isEdit ? "Bet Updated" : "Bets Placed"}
160
167
  </motion.p>
161
168
 
162
- {/* Bet items — one by one */}
163
- <div className="w-full flex flex-col gap-1.5 mt-1">
169
+ {/* Bet items — floating, no borders */}
170
+ <div className="w-full flex flex-col gap-2 mt-1">
164
171
  {displayBets.map((bet, i) => (
165
172
  <motion.div
166
173
  key={bet.mIdx}
167
- className="w-full px-3 py-2 rounded-lg"
168
- style={{ background: "rgba(34,227,232,0.03)", border: "1px solid rgba(34,227,232,0.08)" }}
169
- initial={{ opacity: 0, x: -16 }}
174
+ className="w-full px-3 py-2"
175
+ initial={{ opacity: 0, x: -12 }}
170
176
  animate={{ opacity: 1, x: 0 }}
171
177
  transition={{ delay: betStartDelay + i * betStagger, duration: 0.3, ease: "easeOut" }}
172
178
  >
173
- <p className="text-[10px] text-white/40 font-medium truncate mb-0.5" style={OUTFIT}>{bet.question}</p>
179
+ <p className="text-[9px] text-white/30 font-medium truncate mb-1" style={OUTFIT}>{bet.question}</p>
174
180
  <div className="flex items-center justify-between">
175
181
  <div className="flex items-center gap-1.5">
176
182
  <SelectedCheck size={8} />
@@ -179,9 +185,9 @@ export const BetCelebration = ({
179
185
  <div className="flex items-center gap-[3px]">
180
186
  <PointsIcon size={7} />
181
187
  <span className="text-[9px] text-white font-semibold" style={OUTFIT}>{bet.amount}</span>
182
- <span className="text-[8px] text-white/40" style={OUTFIT}>×</span>
183
- <span className="text-[9px] text-white/60 font-semibold" style={OUTFIT}>{bet.odds}</span>
184
- <span className="text-[8px] text-white/40" style={OUTFIT}>=</span>
188
+ <span className="text-[8px] text-white/30" style={OUTFIT}>×</span>
189
+ <span className="text-[9px] text-white/50 font-semibold" style={OUTFIT}>{bet.odds}</span>
190
+ <span className="text-[8px] text-white/30" style={OUTFIT}>=</span>
185
191
  <PointsIcon size={7} />
186
192
  <span className="text-[9px] text-[#22E3E8] font-bold" style={OUTFIT}>{bet.reward}</span>
187
193
  </div>
@@ -193,67 +199,60 @@ export const BetCelebration = ({
193
199
  {/* Max outcome */}
194
200
  {!isEdit && totalEntry > 0 && (
195
201
  <motion.div
196
- className="w-full flex items-center justify-center gap-2 pt-2"
197
- initial={{ opacity: 0, scale: 0.9 }}
202
+ className="flex items-center justify-center gap-2 pt-1"
203
+ initial={{ opacity: 0, scale: 0.95 }}
198
204
  animate={{ opacity: 1, scale: 1 }}
199
205
  transition={{ delay: outcomeDelay, type: "spring", stiffness: 200, damping: 18 }}
200
206
  >
201
- <span className="text-[11px] text-white/50 font-medium" style={OUTFIT}>Max outcome</span>
207
+ <span className="text-[10px] text-white/40 font-medium" style={OUTFIT}>Max outcome</span>
202
208
  <div className="flex items-center gap-1">
203
- <Image src="/iamgame_square_logo.jpg" alt="" width={14} height={14} className="rounded-[2px]" />
204
- <span className="text-[18px] text-white font-bold" style={OUTFIT}>{totalEntry.toLocaleString()}</span>
209
+ <Image src="/iamgame_square_logo.jpg" alt="" width={12} height={12} className="rounded-[2px]" />
210
+ <span className="text-[16px] text-white font-bold" style={OUTFIT}>{totalEntry.toLocaleString()}</span>
205
211
  </div>
206
- <span className="text-[18px] text-white/30 font-bold" style={OUTFIT}>→</span>
212
+ <span className="text-[16px] text-white/20 font-bold" style={OUTFIT}>→</span>
207
213
  <div className="flex items-center gap-1 relative">
208
- <Image src="/iamgame_square_logo.jpg" alt="" width={14} height={14} className="rounded-[2px]" />
209
- <span className="text-[18px] text-[#22E3E8] font-bold" style={OUTFIT}>{compoundedReward.toLocaleString()}</span>
210
- <motion.div className="absolute inset-0 pointer-events-none overflow-hidden rounded">
211
- <motion.div
212
- className="absolute inset-y-0 w-[50%]"
213
- style={{ background: "linear-gradient(90deg, transparent, rgba(34,227,232,0.25), transparent)" }}
214
- animate={{ left: ["-50%", "150%"] }}
215
- transition={{ duration: 1.8, repeat: Infinity, repeatDelay: 2.5, ease: "easeInOut", delay: outcomeDelay + 0.3 }}
216
- />
217
- </motion.div>
214
+ <Image src="/iamgame_square_logo.jpg" alt="" width={12} height={12} className="rounded-[2px]" />
215
+ <span className="text-[16px] text-[#22E3E8] font-bold" style={{ ...OUTFIT, textShadow: "0 0 12px rgba(34,227,232,0.4)" }}>{compoundedReward.toLocaleString()}</span>
218
216
  </div>
219
217
  </motion.div>
220
218
  )}
221
219
 
222
220
  {/* Line growth */}
223
221
  <motion.div
224
- className="w-full h-[2px] rounded-full overflow-hidden mt-1"
225
- style={{ background: "rgba(34,227,232,0.08)" }}
222
+ className="w-3/4 h-px rounded-full overflow-hidden"
223
+ style={{ background: "rgba(255,255,255,0.06)" }}
226
224
  initial={{ opacity: 0 }}
227
225
  animate={{ opacity: 1 }}
228
226
  transition={{ delay: lineDelay }}
229
227
  >
230
228
  <motion.div
231
229
  className="h-full rounded-full"
232
- style={{ background: "linear-gradient(90deg, #22E3E8, #9945FF)" }}
230
+ style={{ background: "linear-gradient(90deg, transparent, #22E3E8, transparent)" }}
233
231
  initial={{ width: "0%" }}
234
232
  animate={{ width: "100%" }}
235
- transition={{ delay: lineDelay + 0.1, duration: 0.7, ease: "easeOut" }}
233
+ transition={{ delay: lineDelay + 0.1, duration: 0.8, ease: "easeOut" }}
236
234
  />
237
235
  </motion.div>
238
236
 
239
237
  {/* Message */}
240
238
  <motion.p
241
- className="text-[11px] text-white/45 text-center font-medium leading-relaxed px-2"
239
+ className="text-[11px] text-white/35 text-center font-medium leading-relaxed"
242
240
  style={OUTFIT}
243
241
  initial={{ opacity: 0 }}
244
242
  animate={{ opacity: 1 }}
245
243
  transition={{ delay: messageDelay, duration: 0.4 }}
246
244
  >
247
- Track the leaderboard to see your position updating as bets resolve with the game
245
+ Track the leaderboard to see your position{"\n"}updating as bets resolve with the game
248
246
  </motion.p>
249
247
 
250
248
  {/* Leaderboard button */}
251
249
  {onViewLeaderboard && (
252
250
  <motion.button
253
251
  onClick={onViewLeaderboard}
254
- className="w-full py-2.5 rounded-xl text-[13px] font-bold"
255
- style={{ ...OUTFIT, background: "linear-gradient(135deg, #22E3E8, #9945FF)", color: "#0a0a12" }}
256
- initial={{ opacity: 0, y: 8 }}
252
+ className="px-8 py-2 rounded-full text-[12px] font-semibold"
253
+ style={{ ...OUTFIT, background: "rgba(34,227,232,0.12)", color: "#22E3E8", border: "1px solid rgba(34,227,232,0.25)" }}
254
+ whileTap={{ scale: 0.96 }}
255
+ initial={{ opacity: 0, y: 6 }}
257
256
  animate={{ opacity: 1, y: 0 }}
258
257
  transition={{ delay: buttonDelay, type: "spring", stiffness: 200, damping: 18 }}
259
258
  >