@littlepartytime/dev-kit 1.13.1 โ†’ 1.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -85,14 +85,14 @@ function handleAction(room, engine, playerId, action) {
85
85
  function resetRoom(room) {
86
86
  room.state = null;
87
87
  room.phase = 'lobby';
88
- room.players.forEach(p => p.ready = false);
88
+ room.players.forEach(p => p.ready = true);
89
89
  }
90
90
  function kickNonHostPlayers(room) {
91
91
  const kicked = room.players.filter(p => !p.isHost);
92
92
  room.players = room.players.filter(p => p.isHost);
93
93
  room.state = null;
94
94
  room.phase = 'lobby';
95
- room.players.forEach(p => p.ready = false);
95
+ room.players.forEach(p => p.ready = true);
96
96
  return kicked;
97
97
  }
98
98
  //# sourceMappingURL=game-room.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"game-room.js","sourceRoot":"","sources":["../../src/server/game-room.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"game-room.js","sourceRoot":"","sources":["../../src/server/game-room.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,171 @@
1
+ import React from 'react';
2
+
3
+ interface Ranking {
4
+ playerId: string;
5
+ rank: number;
6
+ score: number;
7
+ isWinner: boolean;
8
+ }
9
+
10
+ interface GameResult {
11
+ rankings: Ranking[];
12
+ data?: Record<string, unknown>;
13
+ }
14
+
15
+ interface Player {
16
+ id: string;
17
+ nickname: string;
18
+ }
19
+
20
+ interface Props {
21
+ result: GameResult;
22
+ players: Player[];
23
+ onReturn: () => void;
24
+ }
25
+
26
+ const MEDAL = ['๐Ÿฅ‡', '๐Ÿฅˆ', '๐Ÿฅ‰'];
27
+
28
+ export default function PlatformTakeover({ result, players, onReturn }: Props) {
29
+ const getName = (playerId: string) =>
30
+ players.find((p) => p.id === playerId)?.nickname ?? playerId;
31
+
32
+ const sorted = [...result.rankings].sort((a, b) => a.rank - b.rank);
33
+
34
+ return (
35
+ <div
36
+ style={{
37
+ width: '100%',
38
+ height: '100%',
39
+ background: 'linear-gradient(180deg, #0f0f23 0%, #1a1a2e 50%, #16213e 100%)',
40
+ display: 'flex',
41
+ flexDirection: 'column',
42
+ fontFamily: 'var(--font-body, system-ui, sans-serif)',
43
+ color: '#e2e8f0',
44
+ overflow: 'hidden',
45
+ }}
46
+ >
47
+ {/* Dev-Kit banner */}
48
+ <div
49
+ style={{
50
+ background: 'rgba(217, 119, 6, 0.15)',
51
+ borderBottom: '1px solid rgba(217, 119, 6, 0.3)',
52
+ padding: '6px 12px',
53
+ fontSize: 11,
54
+ color: '#fbbf24',
55
+ textAlign: 'center',
56
+ flexShrink: 0,
57
+ }}
58
+ >
59
+ โš™ Dev-Kit ยท Platform Takeover
60
+ </div>
61
+
62
+ {/* Content */}
63
+ <div
64
+ style={{
65
+ flex: 1,
66
+ display: 'flex',
67
+ flexDirection: 'column',
68
+ alignItems: 'center',
69
+ justifyContent: 'center',
70
+ padding: '24px 20px',
71
+ gap: 24,
72
+ overflow: 'auto',
73
+ }}
74
+ >
75
+ {/* Title */}
76
+ <div style={{ textAlign: 'center' }}>
77
+ <div style={{ fontSize: 40, marginBottom: 8 }}>๐Ÿ†</div>
78
+ <div
79
+ style={{
80
+ fontSize: 22,
81
+ fontWeight: 700,
82
+ fontFamily: 'var(--font-display, var(--font-body, system-ui, sans-serif))',
83
+ }}
84
+ >
85
+ Game Over
86
+ </div>
87
+ </div>
88
+
89
+ {/* Rankings */}
90
+ <div
91
+ style={{
92
+ width: '100%',
93
+ maxWidth: 300,
94
+ display: 'flex',
95
+ flexDirection: 'column',
96
+ gap: 6,
97
+ }}
98
+ >
99
+ {sorted.map((r) => (
100
+ <div
101
+ key={r.playerId}
102
+ style={{
103
+ display: 'flex',
104
+ alignItems: 'center',
105
+ gap: 10,
106
+ padding: '10px 14px',
107
+ borderRadius: 8,
108
+ background: r.isWinner
109
+ ? 'rgba(250, 204, 21, 0.12)'
110
+ : 'rgba(255, 255, 255, 0.05)',
111
+ border: r.isWinner
112
+ ? '1px solid rgba(250, 204, 21, 0.25)'
113
+ : '1px solid rgba(255, 255, 255, 0.06)',
114
+ }}
115
+ >
116
+ {/* Rank */}
117
+ <span style={{ fontSize: 18, width: 28, textAlign: 'center', flexShrink: 0 }}>
118
+ {MEDAL[r.rank - 1] ?? `#${r.rank}`}
119
+ </span>
120
+
121
+ {/* Name */}
122
+ <span
123
+ style={{
124
+ flex: 1,
125
+ fontSize: 15,
126
+ fontWeight: r.isWinner ? 600 : 400,
127
+ overflow: 'hidden',
128
+ textOverflow: 'ellipsis',
129
+ whiteSpace: 'nowrap',
130
+ }}
131
+ >
132
+ {getName(r.playerId)}
133
+ </span>
134
+
135
+ {/* Score */}
136
+ <span
137
+ style={{
138
+ fontSize: 15,
139
+ fontWeight: 600,
140
+ color: r.isWinner ? '#facc15' : '#94a3b8',
141
+ fontVariantNumeric: 'tabular-nums',
142
+ flexShrink: 0,
143
+ }}
144
+ >
145
+ {r.score}
146
+ </span>
147
+ </div>
148
+ ))}
149
+ </div>
150
+
151
+ {/* Return button */}
152
+ <button
153
+ onClick={onReturn}
154
+ style={{
155
+ marginTop: 8,
156
+ padding: '10px 32px',
157
+ borderRadius: 8,
158
+ border: 'none',
159
+ background: '#d97706',
160
+ color: '#fff',
161
+ fontSize: 15,
162
+ fontWeight: 600,
163
+ cursor: 'pointer',
164
+ }}
165
+ >
166
+ Return to Lobby
167
+ </button>
168
+ </div>
169
+ </div>
170
+ );
171
+ }
@@ -1,6 +1,7 @@
1
1
  import React, { useState, useEffect, useCallback, useMemo, useRef } from 'react';
2
2
  import { io, Socket } from 'socket.io-client';
3
3
  import PhoneFrame from '../components/PhoneFrame';
4
+ import PlatformTakeover from '../components/PlatformTakeover';
4
5
 
5
6
  const card: React.CSSProperties = { background: '#18181b', borderRadius: 8, padding: 24 };
6
7
  const inputStyle: React.CSSProperties = { width: '100%', background: '#27272a', border: '1px solid #3f3f46', borderRadius: 4, padding: '8px 12px', marginBottom: 16, color: '#e5e5e5', fontSize: 14 };
@@ -14,6 +15,7 @@ export default function Play() {
14
15
  const [gameState, setGameState] = useState<any>(null);
15
16
  const [myId, setMyId] = useState<string | null>(null);
16
17
  const [GameRenderer, setGameRenderer] = useState<React.ComponentType<any> | null>(null);
18
+ const [gameResult, setGameResult] = useState<any>(null);
17
19
 
18
20
  // Load renderer
19
21
  useEffect(() => {
@@ -32,10 +34,18 @@ export default function Play() {
32
34
  setJoined(true);
33
35
  });
34
36
 
35
- sock.on('room:update', setRoom);
37
+ sock.on('room:update', (r: any) => {
38
+ setRoom(r);
39
+ // Clear game result when room resets to lobby
40
+ if (r.phase === 'lobby') {
41
+ setGameResult(null);
42
+ setGameState(null);
43
+ }
44
+ });
36
45
  sock.on('game:state', setGameState);
37
46
  sock.on('game:result', (result) => {
38
47
  console.log('Game result:', result);
48
+ setGameResult(result);
39
49
  });
40
50
 
41
51
  setSocket(sock);
@@ -45,6 +55,12 @@ export default function Play() {
45
55
  const isHost = me?.isHost;
46
56
  const isReady = me?.ready;
47
57
 
58
+ const gameOver = room.phase === 'ended' && gameResult !== null;
59
+
60
+ const handleReturn = useCallback(() => {
61
+ socket?.emit('game:playAgain');
62
+ }, [socket]);
63
+
48
64
  // Use refs to avoid recreating platform on every room/me change
49
65
  const roomRef = useRef(room);
50
66
  roomRef.current = room;
@@ -155,7 +171,13 @@ export default function Play() {
155
171
  return (
156
172
  <div style={{ height: 'calc(100vh - 80px)', display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 24 }}>
157
173
  <PhoneFrame>
158
- {GameRenderer && platform && gameState ? (
174
+ {gameOver ? (
175
+ <PlatformTakeover
176
+ result={gameResult}
177
+ players={room.players.map((p: any) => ({ id: p.id, nickname: p.nickname }))}
178
+ onReturn={handleReturn}
179
+ />
180
+ ) : GameRenderer && platform && gameState ? (
159
181
  <GameRenderer platform={platform} state={gameState} />
160
182
  ) : (
161
183
  <div style={{ padding: 16, color: '#71717a' }}>Loading game...</div>
@@ -163,15 +185,6 @@ export default function Play() {
163
185
  </PhoneFrame>
164
186
  {isHost && (
165
187
  <div style={{ display: 'flex', flexDirection: 'column', gap: 10, width: 160 }}>
166
- {room.phase === 'ended' && (
167
- <button
168
- onClick={() => socket?.emit('game:playAgain')}
169
- className="dk-btn-amber"
170
- style={{ ...btnAmber, width: '100%', padding: '8px 0', borderRadius: 6 }}
171
- >
172
- Play Again
173
- </button>
174
- )}
175
188
  <button
176
189
  onClick={() => socket?.emit('game:forceReset')}
177
190
  style={{ width: '100%', background: '#d97706', color: '#fff', border: 'none', padding: '8px 0', borderRadius: 6, fontWeight: 600, cursor: 'pointer', fontSize: 13 }}
@@ -1,5 +1,6 @@
1
1
  import React, { useState, useEffect, useCallback, useMemo, useRef } from 'react';
2
2
  import PhoneFrame from '../components/PhoneFrame';
3
+ import PlatformTakeover from '../components/PlatformTakeover';
3
4
 
4
5
  const PLAYER_NAMES = ['Alice', 'Bob', 'Carol', 'Dave', 'Eve', 'Frank', 'Grace', 'Heidi'];
5
6
 
@@ -206,7 +207,9 @@ export default function Preview() {
206
207
  {/* Renderer โ€” half the screen width */}
207
208
  <div style={{ width: '50%', height: '100%' }}>
208
209
  <PhoneFrame>
209
- {GameRenderer && platform && viewState ? (
210
+ {gameOver && gameResult ? (
211
+ <PlatformTakeover result={gameResult} players={mockPlayers} onReturn={resetGame} />
212
+ ) : GameRenderer && platform && viewState ? (
210
213
  <GameRenderer key={mockPlayers[playerIndex].id} platform={platform} state={viewState} />
211
214
  ) : (
212
215
  <div style={{ padding: 16, color: '#71717a' }}>
@@ -318,17 +321,14 @@ export default function Preview() {
318
321
  </div>
319
322
  </div>
320
323
 
321
- {/* Game Result */}
324
+ {/* Game Result (shown in PhoneFrame as Platform Takeover) */}
322
325
  {gameOver && gameResult && (
323
326
  <div style={card}>
324
327
  <h3 style={{ ...label, color: '#4ade80' }}>Game Over</h3>
325
- <pre style={{ fontSize: 11, fontFamily: 'monospace', background: '#27272a', borderRadius: 4, padding: 8, overflow: 'auto', maxHeight: 128, whiteSpace: 'pre-wrap' }}>
326
- {JSON.stringify(gameResult, null, 2)}
327
- </pre>
328
328
  <button
329
329
  onClick={resetGame}
330
330
  className="dk-btn-amber"
331
- style={{ ...btnAmber, marginTop: 8, width: '100%' }}
331
+ style={{ ...btnAmber, width: '100%' }}
332
332
  >
333
333
  Reset Game
334
334
  </button>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@littlepartytime/dev-kit",
3
- "version": "1.13.1",
3
+ "version": "1.14.0",
4
4
  "description": "Development toolkit CLI for Little Party Time game developers",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",