new layout for model rankings
This commit is contained in:
98
broadcast.ts
98
broadcast.ts
@@ -32,6 +32,7 @@ type GameState = {
|
|||||||
lastCompleted: RoundState | null;
|
lastCompleted: RoundState | null;
|
||||||
active: RoundState | null;
|
active: RoundState | null;
|
||||||
scores: Record<string, number>;
|
scores: Record<string, number>;
|
||||||
|
viewerScores: Record<string, number>;
|
||||||
done: boolean;
|
done: boolean;
|
||||||
isPaused: boolean;
|
isPaused: boolean;
|
||||||
generation: number;
|
generation: number;
|
||||||
@@ -294,9 +295,61 @@ function drawHeader() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawScoreboard(scores: Record<string, number>) {
|
function drawScoreboardSection(
|
||||||
const entries = Object.entries(scores).sort((a, b) => b[1] - a[1]);
|
entries: [string, number][],
|
||||||
|
label: string,
|
||||||
|
startY: number,
|
||||||
|
entryHeight: number,
|
||||||
|
) {
|
||||||
|
const maxScore = entries[0]?.[1] || 1;
|
||||||
|
|
||||||
|
// Section label
|
||||||
|
ctx.font = '700 13px "JetBrains Mono", monospace';
|
||||||
|
ctx.fillStyle = "#555";
|
||||||
|
ctx.fillText(label, WIDTH - 348, startY);
|
||||||
|
|
||||||
|
// Divider line under label
|
||||||
|
ctx.fillStyle = "#1c1c1c";
|
||||||
|
ctx.fillRect(WIDTH - 348, startY + 8, 296, 1);
|
||||||
|
|
||||||
|
entries.forEach(([name, score], index) => {
|
||||||
|
const y = startY + 20 + index * entryHeight;
|
||||||
|
const color = getColor(name);
|
||||||
|
const pct = maxScore > 0 ? score / maxScore : 0;
|
||||||
|
|
||||||
|
ctx.font = '600 16px "JetBrains Mono", monospace';
|
||||||
|
ctx.fillStyle = "#555";
|
||||||
|
const rank = index === 0 && score > 0 ? "👑" : String(index + 1);
|
||||||
|
ctx.fillText(rank, WIDTH - 348, y + 18);
|
||||||
|
|
||||||
|
ctx.font = '600 16px "Inter", sans-serif';
|
||||||
|
ctx.fillStyle = color;
|
||||||
|
const nameText = name.length > 18 ? `${name.slice(0, 18)}...` : name;
|
||||||
|
|
||||||
|
const drewLogo = drawModelLogo(name, WIDTH - 310, y + 4, 20);
|
||||||
|
if (drewLogo) {
|
||||||
|
ctx.fillText(nameText, WIDTH - 310 + 26, y + 18);
|
||||||
|
} else {
|
||||||
|
ctx.fillText(nameText, WIDTH - 310, y + 18);
|
||||||
|
}
|
||||||
|
|
||||||
|
roundRect(WIDTH - 310, y + 30, 216, 3, 2, "#1c1c1c");
|
||||||
|
if (pct > 0) {
|
||||||
|
roundRect(WIDTH - 310, y + 30, Math.max(6, 216 * pct), 3, 2, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.font = '700 16px "JetBrains Mono", monospace';
|
||||||
|
ctx.fillStyle = "#666";
|
||||||
|
const scoreText = String(score);
|
||||||
|
const scoreWidth = ctx.measureText(scoreText).width;
|
||||||
|
ctx.fillText(scoreText, WIDTH - 48 - scoreWidth, y + 18);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawScoreboard(scores: Record<string, number>, viewerScores: Record<string, number>) {
|
||||||
|
const modelEntries = Object.entries(scores).sort((a, b) => b[1] - a[1]) as [string, number][];
|
||||||
|
const viewerEntries = Object.entries(viewerScores).sort((a, b) => b[1] - a[1]) as [string, number][];
|
||||||
|
|
||||||
roundRect(WIDTH - 380, 0, 380, HEIGHT, 0, "#111");
|
roundRect(WIDTH - 380, 0, 380, HEIGHT, 0, "#111");
|
||||||
ctx.fillStyle = "#1c1c1c";
|
ctx.fillStyle = "#1c1c1c";
|
||||||
ctx.fillRect(WIDTH - 380, 0, 1, HEIGHT);
|
ctx.fillRect(WIDTH - 380, 0, 1, HEIGHT);
|
||||||
@@ -305,40 +358,11 @@ function drawScoreboard(scores: Record<string, number>) {
|
|||||||
ctx.fillStyle = "#888";
|
ctx.fillStyle = "#888";
|
||||||
ctx.fillText("STANDINGS", WIDTH - 348, 76);
|
ctx.fillText("STANDINGS", WIDTH - 348, 76);
|
||||||
|
|
||||||
const maxScore = entries[0]?.[1] || 1;
|
const entryHeight = 52;
|
||||||
|
drawScoreboardSection(modelEntries, "AI JUDGES", 110, entryHeight);
|
||||||
|
|
||||||
entries.slice(0, 10).forEach(([name, score], index) => {
|
const viewerStartY = 110 + 28 + modelEntries.length * entryHeight + 16;
|
||||||
const y = 140 + index * 68;
|
drawScoreboardSection(viewerEntries, "VIEWERS", viewerStartY, entryHeight);
|
||||||
const color = getColor(name);
|
|
||||||
const pct = maxScore > 0 ? (score / maxScore) : 0;
|
|
||||||
|
|
||||||
ctx.font = '600 20px "JetBrains Mono", monospace';
|
|
||||||
ctx.fillStyle = "#888";
|
|
||||||
const rank = index === 0 && score > 0 ? "👑" : String(index + 1);
|
|
||||||
ctx.fillText(rank, WIDTH - 348, y + 24);
|
|
||||||
|
|
||||||
ctx.font = '600 20px "Inter", sans-serif';
|
|
||||||
ctx.fillStyle = color;
|
|
||||||
const nameText = name.length > 18 ? `${name.slice(0, 18)}...` : name;
|
|
||||||
|
|
||||||
const drewLogo = drawModelLogo(name, WIDTH - 304, y + 6, 24);
|
|
||||||
if (drewLogo) {
|
|
||||||
ctx.fillText(nameText, WIDTH - 304 + 32, y + 24);
|
|
||||||
} else {
|
|
||||||
ctx.fillText(nameText, WIDTH - 304, y + 24);
|
|
||||||
}
|
|
||||||
|
|
||||||
roundRect(WIDTH - 304, y + 42, 208, 4, 2, "#1c1c1c");
|
|
||||||
if (pct > 0) {
|
|
||||||
roundRect(WIDTH - 304, y + 42, Math.max(8, 208 * pct), 4, 2, color);
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.font = '700 20px "JetBrains Mono", monospace';
|
|
||||||
ctx.fillStyle = "#888";
|
|
||||||
const scoreText = String(score);
|
|
||||||
const scoreWidth = ctx.measureText(scoreText).width;
|
|
||||||
ctx.fillText(scoreText, WIDTH - 48 - scoreWidth, y + 24);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawRound(round: RoundState) {
|
function drawRound(round: RoundState) {
|
||||||
@@ -608,7 +632,7 @@ function draw() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
drawScoreboard(state.scores);
|
drawScoreboard(state.scores, state.viewerScores ?? {});
|
||||||
|
|
||||||
const isNextPrompting = state.active?.phase === "prompting" && !state.active.prompt;
|
const isNextPrompting = state.active?.phase === "prompting" && !state.active.prompt;
|
||||||
const displayRound = isNextPrompting && state.lastCompleted ? state.lastCompleted : (state.active ?? state.lastCompleted ?? null);
|
const displayRound = isNextPrompting && state.lastCompleted ? state.lastCompleted : (state.active ?? state.lastCompleted ?? null);
|
||||||
|
|||||||
92
frontend.css
92
frontend.css
@@ -417,8 +417,8 @@ body {
|
|||||||
padding: 16px 20px;
|
padding: 16px 20px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 12px;
|
gap: 20px;
|
||||||
max-height: 220px;
|
max-height: 50vh;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
}
|
}
|
||||||
@@ -455,56 +455,87 @@ body {
|
|||||||
color: var(--text);
|
color: var(--text);
|
||||||
}
|
}
|
||||||
|
|
||||||
.standings__list {
|
/* ── Leaderboard Section ─────────────────────────────────────── */
|
||||||
|
|
||||||
|
.lb-section {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 4px;
|
gap: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.standing {
|
.lb-section__head {
|
||||||
|
padding-bottom: 6px;
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
margin-bottom: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lb-section__label {
|
||||||
|
font-family: var(--mono);
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: 1.5px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: var(--text-muted);
|
||||||
|
}
|
||||||
|
|
||||||
|
.lb-section__list {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
flex-direction: column;
|
||||||
gap: 10px;
|
|
||||||
padding: 5px 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.standing--active {
|
/* ── Leaderboard Entry ───────────────────────────────────────── */
|
||||||
|
|
||||||
|
.lb-entry {
|
||||||
|
padding: 6px 0 4px;
|
||||||
|
opacity: 0.55;
|
||||||
|
transition: opacity 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lb-entry--active,
|
||||||
|
.lb-entry:hover {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.standing__rank {
|
.lb-entry__top {
|
||||||
width: 22px;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lb-entry__rank {
|
||||||
|
width: 20px;
|
||||||
|
flex-shrink: 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-family: var(--mono);
|
font-family: var(--mono);
|
||||||
font-size: 12px;
|
font-size: 11px;
|
||||||
color: var(--text-muted);
|
color: var(--text-muted);
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.standing__bar {
|
.lb-entry__score {
|
||||||
flex: 1;
|
margin-left: auto;
|
||||||
height: 3px;
|
|
||||||
background: var(--border);
|
|
||||||
border-radius: 2px;
|
|
||||||
overflow: hidden;
|
|
||||||
min-width: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.standing__fill {
|
|
||||||
height: 100%;
|
|
||||||
border-radius: 2px;
|
|
||||||
transition: width 0.6s cubic-bezier(0.22, 1, 0.36, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.standing__score {
|
|
||||||
font-family: var(--mono);
|
font-family: var(--mono);
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: var(--text-dim);
|
color: var(--text-dim);
|
||||||
min-width: 16px;
|
min-width: 14px;
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.lb-entry__bar {
|
||||||
|
margin-left: 26px;
|
||||||
|
height: 3px;
|
||||||
|
background: var(--border);
|
||||||
|
border-radius: 2px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lb-entry__fill {
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 2px;
|
||||||
|
transition: width 0.6s cubic-bezier(0.22, 1, 0.36, 1);
|
||||||
|
}
|
||||||
|
|
||||||
/* ── Connecting ───────────────────────────────────────────────── */
|
/* ── Connecting ───────────────────────────────────────────────── */
|
||||||
|
|
||||||
.connecting {
|
.connecting {
|
||||||
@@ -720,5 +751,6 @@ body {
|
|||||||
max-height: none;
|
max-height: none;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
padding: 24px;
|
padding: 24px;
|
||||||
|
gap: 24px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
91
frontend.tsx
91
frontend.tsx
@@ -38,6 +38,7 @@ type GameState = {
|
|||||||
lastCompleted: RoundState | null;
|
lastCompleted: RoundState | null;
|
||||||
active: RoundState | null;
|
active: RoundState | null;
|
||||||
scores: Record<string, number>;
|
scores: Record<string, number>;
|
||||||
|
viewerScores: Record<string, number>;
|
||||||
done: boolean;
|
done: boolean;
|
||||||
isPaused: boolean;
|
isPaused: boolean;
|
||||||
generation: number;
|
generation: number;
|
||||||
@@ -382,16 +383,63 @@ function GameOver({ scores }: { scores: Record<string, number> }) {
|
|||||||
|
|
||||||
// ── Standings ────────────────────────────────────────────────────────────────
|
// ── Standings ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
function Standings({
|
function LeaderboardSection({
|
||||||
|
label,
|
||||||
scores,
|
scores,
|
||||||
activeRound,
|
competing,
|
||||||
}: {
|
}: {
|
||||||
|
label: string;
|
||||||
scores: Record<string, number>;
|
scores: Record<string, number>;
|
||||||
activeRound: RoundState | null;
|
competing: Set<string>;
|
||||||
}) {
|
}) {
|
||||||
const sorted = Object.entries(scores).sort((a, b) => b[1] - a[1]);
|
const sorted = Object.entries(scores).sort((a, b) => b[1] - a[1]);
|
||||||
const maxScore = sorted[0]?.[1] || 1;
|
const maxScore = sorted[0]?.[1] || 1;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="lb-section">
|
||||||
|
<div className="lb-section__head">
|
||||||
|
<span className="lb-section__label">{label}</span>
|
||||||
|
</div>
|
||||||
|
<div className="lb-section__list">
|
||||||
|
{sorted.map(([name, score], i) => {
|
||||||
|
const pct = maxScore > 0 ? Math.round((score / maxScore) * 100) : 0;
|
||||||
|
const color = getColor(name);
|
||||||
|
const active = competing.has(name);
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={name}
|
||||||
|
className={`lb-entry ${active ? "lb-entry--active" : ""}`}
|
||||||
|
>
|
||||||
|
<div className="lb-entry__top">
|
||||||
|
<span className="lb-entry__rank">
|
||||||
|
{i === 0 && score > 0 ? "👑" : i + 1}
|
||||||
|
</span>
|
||||||
|
<ModelTag model={{ id: name, name }} small />
|
||||||
|
<span className="lb-entry__score">{score}</span>
|
||||||
|
</div>
|
||||||
|
<div className="lb-entry__bar">
|
||||||
|
<div
|
||||||
|
className="lb-entry__fill"
|
||||||
|
style={{ width: `${pct}%`, background: color }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Standings({
|
||||||
|
scores,
|
||||||
|
viewerScores,
|
||||||
|
activeRound,
|
||||||
|
}: {
|
||||||
|
scores: Record<string, number>;
|
||||||
|
viewerScores: Record<string, number>;
|
||||||
|
activeRound: RoundState | null;
|
||||||
|
}) {
|
||||||
const competing = activeRound
|
const competing = activeRound
|
||||||
? new Set([
|
? new Set([
|
||||||
activeRound.contestants[0].name,
|
activeRound.contestants[0].name,
|
||||||
@@ -415,31 +463,16 @@ function Standings({
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="standings__list">
|
<LeaderboardSection
|
||||||
{sorted.map(([name, score], i) => {
|
label="AI Judges"
|
||||||
const pct = maxScore > 0 ? Math.round((score / maxScore) * 100) : 0;
|
scores={scores}
|
||||||
const color = getColor(name);
|
competing={competing}
|
||||||
const active = competing.has(name);
|
/>
|
||||||
return (
|
<LeaderboardSection
|
||||||
<div
|
label="Viewers"
|
||||||
key={name}
|
scores={viewerScores}
|
||||||
className={`standing ${active ? "standing--active" : ""}`}
|
competing={competing}
|
||||||
>
|
/>
|
||||||
<span className="standing__rank">
|
|
||||||
{i === 0 && score > 0 ? "👑" : i + 1}
|
|
||||||
</span>
|
|
||||||
<ModelTag model={{ id: name, name }} small />
|
|
||||||
<div className="standing__bar">
|
|
||||||
<div
|
|
||||||
className="standing__fill"
|
|
||||||
style={{ width: `${pct}%`, background: color }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<span className="standing__score">{score}</span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</aside>
|
</aside>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -578,7 +611,7 @@ function App() {
|
|||||||
)}
|
)}
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<Standings scores={state.scores} activeRound={state.active} />
|
<Standings scores={state.scores} viewerScores={state.viewerScores ?? {}} activeRound={state.active} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
9
game.ts
9
game.ts
@@ -73,6 +73,7 @@ export type GameState = {
|
|||||||
completed: RoundState[];
|
completed: RoundState[];
|
||||||
active: RoundState | null;
|
active: RoundState | null;
|
||||||
scores: Record<string, number>;
|
scores: Record<string, number>;
|
||||||
|
viewerScores: Record<string, number>;
|
||||||
done: boolean;
|
done: boolean;
|
||||||
isPaused: boolean;
|
isPaused: boolean;
|
||||||
generation: number;
|
generation: number;
|
||||||
@@ -471,6 +472,14 @@ export async function runGame(
|
|||||||
} else if (votesB > votesA) {
|
} else if (votesB > votesA) {
|
||||||
state.scores[contB.name] = (state.scores[contB.name] || 0) + 1;
|
state.scores[contB.name] = (state.scores[contB.name] || 0) + 1;
|
||||||
}
|
}
|
||||||
|
// Viewer vote scoring
|
||||||
|
const vvA = round.viewerVotesA ?? 0;
|
||||||
|
const vvB = round.viewerVotesB ?? 0;
|
||||||
|
if (vvA > vvB) {
|
||||||
|
state.viewerScores[contA.name] = (state.viewerScores[contA.name] || 0) + 1;
|
||||||
|
} else if (vvB > vvA) {
|
||||||
|
state.viewerScores[contB.name] = (state.viewerScores[contB.name] || 0) + 1;
|
||||||
|
}
|
||||||
rerender();
|
rerender();
|
||||||
|
|
||||||
await new Promise((r) => setTimeout(r, 5000));
|
await new Promise((r) => setTimeout(r, 5000));
|
||||||
|
|||||||
11
quipslop.tsx
11
quipslop.tsx
@@ -223,11 +223,12 @@ function Game({ runs }: { runs: number }) {
|
|||||||
const stateRef = useRef<GameState>({
|
const stateRef = useRef<GameState>({
|
||||||
completed: [],
|
completed: [],
|
||||||
active: null,
|
active: null,
|
||||||
scores: Object.fromEntries(MODELS.map((m) => [m.name, 0])),
|
scores: Object.fromEntries(MODELS.map((m) => [m.name, 0])),
|
||||||
done: false,
|
viewerScores: Object.fromEntries(MODELS.map((m) => [m.name, 0])),
|
||||||
isPaused: false,
|
done: false,
|
||||||
generation: 0,
|
isPaused: false,
|
||||||
});
|
generation: 0,
|
||||||
|
});
|
||||||
const [, setTick] = useState(0);
|
const [, setTick] = useState(0);
|
||||||
const rerender = useCallback(() => setTick((t) => t + 1), []);
|
const rerender = useCallback(() => setTick((t) => t + 1), []);
|
||||||
|
|
||||||
|
|||||||
13
server.ts
13
server.ts
@@ -30,6 +30,7 @@ if (!process.env.OPENROUTER_API_KEY) {
|
|||||||
|
|
||||||
const allRounds = getAllRounds();
|
const allRounds = getAllRounds();
|
||||||
const initialScores = Object.fromEntries(MODELS.map((m) => [m.name, 0]));
|
const initialScores = Object.fromEntries(MODELS.map((m) => [m.name, 0]));
|
||||||
|
const initialViewerScores = Object.fromEntries(MODELS.map((m) => [m.name, 0]));
|
||||||
|
|
||||||
let initialCompleted: RoundState[] = [];
|
let initialCompleted: RoundState[] = [];
|
||||||
if (allRounds.length > 0) {
|
if (allRounds.length > 0) {
|
||||||
@@ -43,6 +44,15 @@ if (allRounds.length > 0) {
|
|||||||
(initialScores[round.contestants[1].name] || 0) + 1;
|
(initialScores[round.contestants[1].name] || 0) + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const vvA = round.viewerVotesA ?? 0;
|
||||||
|
const vvB = round.viewerVotesB ?? 0;
|
||||||
|
if (vvA > vvB) {
|
||||||
|
initialViewerScores[round.contestants[0].name] =
|
||||||
|
(initialViewerScores[round.contestants[0].name] || 0) + 1;
|
||||||
|
} else if (vvB > vvA) {
|
||||||
|
initialViewerScores[round.contestants[1].name] =
|
||||||
|
(initialViewerScores[round.contestants[1].name] || 0) + 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const lastRound = allRounds[allRounds.length - 1];
|
const lastRound = allRounds[allRounds.length - 1];
|
||||||
if (lastRound) {
|
if (lastRound) {
|
||||||
@@ -54,6 +64,7 @@ const gameState: GameState = {
|
|||||||
completed: initialCompleted,
|
completed: initialCompleted,
|
||||||
active: null,
|
active: null,
|
||||||
scores: initialScores,
|
scores: initialScores,
|
||||||
|
viewerScores: initialViewerScores,
|
||||||
done: false,
|
done: false,
|
||||||
isPaused: false,
|
isPaused: false,
|
||||||
generation: 0,
|
generation: 0,
|
||||||
@@ -349,6 +360,7 @@ function getClientState() {
|
|||||||
active: gameState.active,
|
active: gameState.active,
|
||||||
lastCompleted: gameState.completed.at(-1) ?? null,
|
lastCompleted: gameState.completed.at(-1) ?? null,
|
||||||
scores: gameState.scores,
|
scores: gameState.scores,
|
||||||
|
viewerScores: gameState.viewerScores,
|
||||||
done: gameState.done,
|
done: gameState.done,
|
||||||
isPaused: gameState.isPaused,
|
isPaused: gameState.isPaused,
|
||||||
generation: gameState.generation,
|
generation: gameState.generation,
|
||||||
@@ -635,6 +647,7 @@ const server = Bun.serve<WsData>({
|
|||||||
gameState.completed = [];
|
gameState.completed = [];
|
||||||
gameState.active = null;
|
gameState.active = null;
|
||||||
gameState.scores = Object.fromEntries(MODELS.map((m) => [m.name, 0]));
|
gameState.scores = Object.fromEntries(MODELS.map((m) => [m.name, 0]));
|
||||||
|
gameState.viewerScores = Object.fromEntries(MODELS.map((m) => [m.name, 0]));
|
||||||
gameState.done = false;
|
gameState.done = false;
|
||||||
gameState.isPaused = true;
|
gameState.isPaused = true;
|
||||||
gameState.generation += 1;
|
gameState.generation += 1;
|
||||||
|
|||||||
Reference in New Issue
Block a user