Spaces:
Running
fix: batch of 5 stability fixes
Browse files- Swap spark/argue from Anthropic to DeepSeek (no ANTHROPIC_API_KEY)
- Guard leaderboard against mini-game modes
- Expand fallback question pool 20β54 for Streak mode offline
- Add custom 404 and error pages
- Add security headers + turbopack root to next.config.ts
Co-Authored-By: Claude <noreply@anthropic.com>
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
_._ _..._ .-', _.._(`))
'-. ` ' /-._.-' ',/
) \ '.
/ _ _ | \
| a a / |
\ .-. ;
'-('' ).-' ,' ;
'-; | .'
\ \ /
| 7 .__ _.-\ \
| | | `` | |
/,_| | /,_/ /
/,_/ '----'
Piggy Benissy
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Simeon Garratt | www.simeongarratt.com | @SimeonGarratt
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
- next.config.ts +41 -0
- src/app/api/spark/argue/route.ts +16 -15
- src/app/error.tsx +54 -0
- src/app/not-found.tsx +31 -0
- src/components/game/ResultsScreen.tsx +24 -9
- src/lib/game/fallback-questions.ts +278 -8
|
@@ -1,7 +1,48 @@
|
|
| 1 |
import type { NextConfig } from "next";
|
| 2 |
|
| 3 |
const nextConfig: NextConfig = {
|
|
|
|
| 4 |
output: "standalone",
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
};
|
| 6 |
|
| 7 |
export default nextConfig;
|
|
|
|
| 1 |
import type { NextConfig } from "next";
|
| 2 |
|
| 3 |
const nextConfig: NextConfig = {
|
| 4 |
+
// .next/standalone output for Docker deployment on Hugging Face
|
| 5 |
output: "standalone",
|
| 6 |
+
|
| 7 |
+
// Silence the multi-lockfile warning when next is run with npm workspaces
|
| 8 |
+
turbopack: {
|
| 9 |
+
root: __dirname,
|
| 10 |
+
},
|
| 11 |
+
|
| 12 |
+
async headers() {
|
| 13 |
+
return [
|
| 14 |
+
{
|
| 15 |
+
source: "/(.*)",
|
| 16 |
+
headers: [
|
| 17 |
+
{
|
| 18 |
+
key: "X-Frame-Options",
|
| 19 |
+
value: "DENY",
|
| 20 |
+
},
|
| 21 |
+
{
|
| 22 |
+
key: "X-Content-Type-Options",
|
| 23 |
+
value: "nosniff",
|
| 24 |
+
},
|
| 25 |
+
{
|
| 26 |
+
key: "Referrer-Policy",
|
| 27 |
+
value: "strict-origin-when-cross-origin",
|
| 28 |
+
},
|
| 29 |
+
{
|
| 30 |
+
key: "X-XSS-Protection",
|
| 31 |
+
value: "1; mode=block",
|
| 32 |
+
},
|
| 33 |
+
],
|
| 34 |
+
},
|
| 35 |
+
];
|
| 36 |
+
},
|
| 37 |
+
|
| 38 |
+
images: {
|
| 39 |
+
remotePatterns: [
|
| 40 |
+
{
|
| 41 |
+
protocol: "https",
|
| 42 |
+
hostname: "thetriviaverse.com",
|
| 43 |
+
},
|
| 44 |
+
],
|
| 45 |
+
},
|
| 46 |
};
|
| 47 |
|
| 48 |
export default nextConfig;
|
|
@@ -1,8 +1,11 @@
|
|
| 1 |
import { NextRequest, NextResponse } from "next/server";
|
| 2 |
-
import
|
| 3 |
|
| 4 |
function getClient() {
|
| 5 |
-
return new
|
|
|
|
|
|
|
|
|
|
| 6 |
}
|
| 7 |
|
| 8 |
export async function POST(req: NextRequest) {
|
|
@@ -41,15 +44,17 @@ export async function POST(req: NextRequest) {
|
|
| 41 |
? "You are OPENING this round. Present a strong, specific argument."
|
| 42 |
: `Your opponent just argued:\n"${opponentArgument}"\n\nDirectly counter their specific claims while advancing your own case.`;
|
| 43 |
|
| 44 |
-
const
|
| 45 |
-
model: "
|
| 46 |
max_tokens: 300,
|
| 47 |
messages: [
|
|
|
|
|
|
|
|
|
|
|
|
|
| 48 |
{
|
| 49 |
role: "user",
|
| 50 |
-
content: `
|
| 51 |
-
|
| 52 |
-
RULES:
|
| 53 |
- 120-150 words maximum.
|
| 54 |
- Directly counter the opponent's specific claims. If they cite a law, case, or fact, engage with it.
|
| 55 |
- Take a clear position. Do not hedge, agree with both sides, or use filler phrases like "It's important to note" or "While I understand."
|
|
@@ -70,19 +75,15 @@ Respond with ONLY your argument. No labels, prefixes, or meta-commentary.`,
|
|
| 70 |
});
|
| 71 |
|
| 72 |
const argument =
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
: "I stand by my position on this matter.";
|
| 76 |
|
| 77 |
return NextResponse.json({ argument });
|
| 78 |
} catch (error) {
|
| 79 |
console.error("[spark/argue] Error:", error);
|
| 80 |
return NextResponse.json(
|
| 81 |
-
{
|
| 82 |
-
|
| 83 |
-
"While there are many angles to consider, the evidence broadly supports my position on this question.",
|
| 84 |
-
},
|
| 85 |
-
{ status: 200 },
|
| 86 |
);
|
| 87 |
}
|
| 88 |
}
|
|
|
|
| 1 |
import { NextRequest, NextResponse } from "next/server";
|
| 2 |
+
import OpenAI from "openai";
|
| 3 |
|
| 4 |
function getClient() {
|
| 5 |
+
return new OpenAI({
|
| 6 |
+
apiKey: process.env.DEEPSEEK_API_KEY,
|
| 7 |
+
baseURL: "https://api.deepseek.com/v1",
|
| 8 |
+
});
|
| 9 |
}
|
| 10 |
|
| 11 |
export async function POST(req: NextRequest) {
|
|
|
|
| 44 |
? "You are OPENING this round. Present a strong, specific argument."
|
| 45 |
: `Your opponent just argued:\n"${opponentArgument}"\n\nDirectly counter their specific claims while advancing your own case.`;
|
| 46 |
|
| 47 |
+
const response = await getClient().chat.completions.create({
|
| 48 |
+
model: "deepseek-chat",
|
| 49 |
max_tokens: 300,
|
| 50 |
messages: [
|
| 51 |
+
{
|
| 52 |
+
role: "system",
|
| 53 |
+
content: `You are a competitive debate opponent. You hold the ${aiSide} position on this topic.`,
|
| 54 |
+
},
|
| 55 |
{
|
| 56 |
role: "user",
|
| 57 |
+
content: `RULES:
|
|
|
|
|
|
|
| 58 |
- 120-150 words maximum.
|
| 59 |
- Directly counter the opponent's specific claims. If they cite a law, case, or fact, engage with it.
|
| 60 |
- Take a clear position. Do not hedge, agree with both sides, or use filler phrases like "It's important to note" or "While I understand."
|
|
|
|
| 75 |
});
|
| 76 |
|
| 77 |
const argument =
|
| 78 |
+
response.choices[0]?.message?.content?.trim() ??
|
| 79 |
+
"I stand by my position on this matter.";
|
|
|
|
| 80 |
|
| 81 |
return NextResponse.json({ argument });
|
| 82 |
} catch (error) {
|
| 83 |
console.error("[spark/argue] Error:", error);
|
| 84 |
return NextResponse.json(
|
| 85 |
+
{ error: "Failed to generate argument" },
|
| 86 |
+
{ status: 500 },
|
|
|
|
|
|
|
|
|
|
| 87 |
);
|
| 88 |
}
|
| 89 |
}
|
|
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"use client";
|
| 2 |
+
|
| 3 |
+
import { useEffect } from "react";
|
| 4 |
+
import Link from "next/link";
|
| 5 |
+
|
| 6 |
+
export default function Error({
|
| 7 |
+
error,
|
| 8 |
+
reset,
|
| 9 |
+
}: {
|
| 10 |
+
error: Error & { digest?: string };
|
| 11 |
+
reset: () => void;
|
| 12 |
+
}) {
|
| 13 |
+
useEffect(() => {
|
| 14 |
+
console.error("[error.tsx]", error);
|
| 15 |
+
}, [error]);
|
| 16 |
+
|
| 17 |
+
return (
|
| 18 |
+
<div className="flex min-h-screen flex-col items-center justify-center gap-6 px-4 text-center">
|
| 19 |
+
<div className="select-none text-8xl font-black tracking-tighter text-white/10 sm:text-9xl">
|
| 20 |
+
500
|
| 21 |
+
</div>
|
| 22 |
+
<h1 className="text-3xl font-black text-white sm:text-4xl">System Malfunction</h1>
|
| 23 |
+
<p className="max-w-md text-gray-400">
|
| 24 |
+
Something went wrong in the Triviaverse engine. The hyperdrive might need a reboot.
|
| 25 |
+
</p>
|
| 26 |
+
<div className="flex flex-wrap justify-center gap-3">
|
| 27 |
+
<button
|
| 28 |
+
onClick={reset}
|
| 29 |
+
className="inline-flex items-center gap-2 rounded-xl bg-magenta px-6 py-3 text-sm font-bold text-white transition-colors hover:bg-[#d81b60]"
|
| 30 |
+
>
|
| 31 |
+
Try Again
|
| 32 |
+
</button>
|
| 33 |
+
<Link
|
| 34 |
+
href="/"
|
| 35 |
+
className="inline-flex items-center gap-2 rounded-xl border border-white/20 px-6 py-3 text-sm font-bold text-white transition-colors hover:bg-white/10"
|
| 36 |
+
>
|
| 37 |
+
Back to Triviaverse
|
| 38 |
+
</Link>
|
| 39 |
+
</div>
|
| 40 |
+
{error.digest && (
|
| 41 |
+
<p className="text-xs text-gray-600">Error ID: {error.digest}</p>
|
| 42 |
+
)}
|
| 43 |
+
{/* Decorative blobs */}
|
| 44 |
+
<div
|
| 45 |
+
aria-hidden="true"
|
| 46 |
+
className="pointer-events-none fixed left-0 top-0 z-[-1] h-[400px] w-[400px] -translate-x-1/2 -translate-y-1/2 rounded-full bg-magenta opacity-10 mix-blend-screen blur-[120px]"
|
| 47 |
+
/>
|
| 48 |
+
<div
|
| 49 |
+
aria-hidden="true"
|
| 50 |
+
className="pointer-events-none fixed bottom-0 right-0 z-[-1] h-[500px] w-[500px] translate-x-1/3 translate-y-1/3 rounded-full bg-gold opacity-10 mix-blend-screen blur-[150px]"
|
| 51 |
+
/>
|
| 52 |
+
</div>
|
| 53 |
+
);
|
| 54 |
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import Link from "next/link";
|
| 2 |
+
|
| 3 |
+
export default function NotFound() {
|
| 4 |
+
return (
|
| 5 |
+
<div className="flex min-h-screen flex-col items-center justify-center gap-6 px-4 text-center">
|
| 6 |
+
<div className="select-none text-8xl font-black tracking-tighter text-white/10 sm:text-9xl">
|
| 7 |
+
404
|
| 8 |
+
</div>
|
| 9 |
+
<h1 className="text-3xl font-black text-white sm:text-4xl">Lost in the Verse</h1>
|
| 10 |
+
<p className="max-w-md text-gray-400">
|
| 11 |
+
This cosmic coordinate doesn't exist. The page you're looking for has drifted into
|
| 12 |
+
a black hole or never existed at all.
|
| 13 |
+
</p>
|
| 14 |
+
<Link
|
| 15 |
+
href="/"
|
| 16 |
+
className="inline-flex items-center gap-2 rounded-xl bg-magenta px-6 py-3 text-sm font-bold text-white transition-colors hover:bg-[#d81b60]"
|
| 17 |
+
>
|
| 18 |
+
Back to Triviaverse
|
| 19 |
+
</Link>
|
| 20 |
+
{/* Decorative blobs */}
|
| 21 |
+
<div
|
| 22 |
+
aria-hidden="true"
|
| 23 |
+
className="pointer-events-none fixed left-0 top-0 z-[-1] h-[400px] w-[400px] -translate-x-1/2 -translate-y-1/2 rounded-full bg-magenta opacity-10 mix-blend-screen blur-[120px]"
|
| 24 |
+
/>
|
| 25 |
+
<div
|
| 26 |
+
aria-hidden="true"
|
| 27 |
+
className="pointer-events-none fixed bottom-0 right-0 z-[-1] h-[500px] w-[500px] translate-x-1/3 translate-y-1/3 rounded-full bg-gold opacity-10 mix-blend-screen blur-[150px]"
|
| 28 |
+
/>
|
| 29 |
+
</div>
|
| 30 |
+
);
|
| 31 |
+
}
|
|
@@ -13,7 +13,7 @@ import { getOrCreatePlayer } from "@/lib/supabase/queries";
|
|
| 13 |
import { usePlayerProgress } from "@/hooks/usePlayerProgress";
|
| 14 |
import { AchievementToast, type AchievementToastData } from "@/components/achievements/AchievementToast";
|
| 15 |
import { ACHIEVEMENT_MAP } from "@/lib/achievements/definitions";
|
| 16 |
-
import type { GameMode, TriviaMode } from "@/lib/game/types";
|
| 17 |
import type { CoinBreakdown } from "@/lib/achievements/coin-calculator";
|
| 18 |
import type { AchievementUpdate } from "@/lib/achievements/checker";
|
| 19 |
|
|
@@ -98,13 +98,19 @@ export function ResultsScreen({
|
|
| 98 |
const { submitLeaderboardEntry } = await import(
|
| 99 |
"@/lib/supabase/queries"
|
| 100 |
);
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 108 |
} catch (err) {
|
| 109 |
console.error("[ResultsScreen] submission failed:", err);
|
| 110 |
}
|
|
@@ -137,7 +143,16 @@ export function ResultsScreen({
|
|
| 137 |
// Silently ignore -- results screen still displays
|
| 138 |
}
|
| 139 |
})();
|
| 140 |
-
}, [
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 141 |
|
| 142 |
const stats = [
|
| 143 |
{ label: "Score", value: score.toLocaleString(), color: "text-gold" },
|
|
|
|
| 13 |
import { usePlayerProgress } from "@/hooks/usePlayerProgress";
|
| 14 |
import { AchievementToast, type AchievementToastData } from "@/components/achievements/AchievementToast";
|
| 15 |
import { ACHIEVEMENT_MAP } from "@/lib/achievements/definitions";
|
| 16 |
+
import type { GameMode, TriviaMode, MiniGameMode } from "@/lib/game/types";
|
| 17 |
import type { CoinBreakdown } from "@/lib/achievements/coin-calculator";
|
| 18 |
import type { AchievementUpdate } from "@/lib/achievements/checker";
|
| 19 |
|
|
|
|
| 98 |
const { submitLeaderboardEntry } = await import(
|
| 99 |
"@/lib/supabase/queries"
|
| 100 |
);
|
| 101 |
+
|
| 102 |
+
// Only submit leaderboard entries for trivia modes β mini-games have
|
| 103 |
+
// their own local high-score tracking and don't map to the leaderboard.
|
| 104 |
+
const triviaModes: TriviaMode[] = ["quick-fire", "challenge-me", "streak", "multiplayer"];
|
| 105 |
+
if (triviaModes.includes(mode as TriviaMode)) {
|
| 106 |
+
await submitLeaderboardEntry({
|
| 107 |
+
player_id: playerId,
|
| 108 |
+
player_name: player.displayName,
|
| 109 |
+
mode,
|
| 110 |
+
score,
|
| 111 |
+
accuracy,
|
| 112 |
+
});
|
| 113 |
+
}
|
| 114 |
} catch (err) {
|
| 115 |
console.error("[ResultsScreen] submission failed:", err);
|
| 116 |
}
|
|
|
|
| 143 |
// Silently ignore -- results screen still displays
|
| 144 |
}
|
| 145 |
})();
|
| 146 |
+
}, [
|
| 147 |
+
processGameResult,
|
| 148 |
+
mode,
|
| 149 |
+
score,
|
| 150 |
+
accuracy,
|
| 151 |
+
streakMax,
|
| 152 |
+
questionsCorrect,
|
| 153 |
+
questionsAnswered,
|
| 154 |
+
phasesCompleted,
|
| 155 |
+
]);
|
| 156 |
|
| 157 |
const stats = [
|
| 158 |
{ label: "Score", value: score.toLocaleString(), color: "text-gold" },
|
|
@@ -1,14 +1,12 @@
|
|
| 1 |
import type { Question } from "./types";
|
| 2 |
|
| 3 |
/**
|
| 4 |
-
* Hard-coded fallback trivia questions
|
| 5 |
-
*
|
| 6 |
-
*
|
| 7 |
-
* 20 questions: 7 easy, 7 medium, 6 hard
|
| 8 |
-
* Categories: Science, History, Geography, Entertainment, Sports, Technology, Nature
|
| 9 |
*/
|
| 10 |
export const FALLBACK_QUESTIONS: Question[] = [
|
| 11 |
-
//
|
| 12 |
{
|
| 13 |
id: "fb-1",
|
| 14 |
category: "Science",
|
|
@@ -65,8 +63,96 @@ export const FALLBACK_QUESTIONS: Question[] = [
|
|
| 65 |
correctAnswer: "Greece",
|
| 66 |
incorrectAnswers: ["Italy", "Egypt", "Turkey"],
|
| 67 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 68 |
|
| 69 |
-
//
|
| 70 |
{
|
| 71 |
id: "fb-8",
|
| 72 |
category: "Science",
|
|
@@ -123,8 +209,96 @@ export const FALLBACK_QUESTIONS: Question[] = [
|
|
| 123 |
correctAnswer: "Whale Shark",
|
| 124 |
incorrectAnswers: ["Great White Shark", "Hammerhead Shark", "Tiger Shark"],
|
| 125 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 126 |
|
| 127 |
-
//
|
| 128 |
{
|
| 129 |
id: "fb-15",
|
| 130 |
category: "Science",
|
|
@@ -173,4 +347,100 @@ export const FALLBACK_QUESTIONS: Question[] = [
|
|
| 173 |
correctAnswer: "Bat",
|
| 174 |
incorrectAnswers: ["Flying Squirrel", "Colugo", "Sugar Glider"],
|
| 175 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 176 |
];
|
|
|
|
| 1 |
import type { Question } from "./types";
|
| 2 |
|
| 3 |
/**
|
| 4 |
+
* Hard-coded fallback trivia questions used when Supabase is unavailable.
|
| 5 |
+
* 54 questions across all categories and difficulties β enough to support
|
| 6 |
+
* Streak mode (50 questions) even without a DB connection.
|
|
|
|
|
|
|
| 7 |
*/
|
| 8 |
export const FALLBACK_QUESTIONS: Question[] = [
|
| 9 |
+
// ββ EASY (18) ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 10 |
{
|
| 11 |
id: "fb-1",
|
| 12 |
category: "Science",
|
|
|
|
| 63 |
correctAnswer: "Greece",
|
| 64 |
incorrectAnswers: ["Italy", "Egypt", "Turkey"],
|
| 65 |
},
|
| 66 |
+
{
|
| 67 |
+
id: "fb-21",
|
| 68 |
+
category: "General Knowledge",
|
| 69 |
+
difficulty: "easy",
|
| 70 |
+
questionText: "What is the capital of France?",
|
| 71 |
+
correctAnswer: "Paris",
|
| 72 |
+
incorrectAnswers: ["London", "Berlin", "Madrid"],
|
| 73 |
+
},
|
| 74 |
+
{
|
| 75 |
+
id: "fb-22",
|
| 76 |
+
category: "General Knowledge",
|
| 77 |
+
difficulty: "easy",
|
| 78 |
+
questionText: "How many continents are there?",
|
| 79 |
+
correctAnswer: "7",
|
| 80 |
+
incorrectAnswers: ["5", "6", "8"],
|
| 81 |
+
},
|
| 82 |
+
{
|
| 83 |
+
id: "fb-23",
|
| 84 |
+
category: "Science",
|
| 85 |
+
difficulty: "easy",
|
| 86 |
+
questionText: "What gas makes up most of Earth's atmosphere?",
|
| 87 |
+
correctAnswer: "Nitrogen",
|
| 88 |
+
incorrectAnswers: ["Oxygen", "Carbon Dioxide", "Argon"],
|
| 89 |
+
},
|
| 90 |
+
{
|
| 91 |
+
id: "fb-24",
|
| 92 |
+
category: "Geography",
|
| 93 |
+
difficulty: "easy",
|
| 94 |
+
questionText: "What is the longest river in the world?",
|
| 95 |
+
correctAnswer: "Nile",
|
| 96 |
+
incorrectAnswers: ["Amazon", "Mississippi", "Yangtze"],
|
| 97 |
+
},
|
| 98 |
+
{
|
| 99 |
+
id: "fb-25",
|
| 100 |
+
category: "Entertainment",
|
| 101 |
+
difficulty: "easy",
|
| 102 |
+
questionText: "Which Disney movie features a snowman named Olaf?",
|
| 103 |
+
correctAnswer: "Frozen",
|
| 104 |
+
incorrectAnswers: ["Tangled", "Moana", "The Snow Queen"],
|
| 105 |
+
},
|
| 106 |
+
{
|
| 107 |
+
id: "fb-26",
|
| 108 |
+
category: "Sports",
|
| 109 |
+
difficulty: "easy",
|
| 110 |
+
questionText: "In what sport would you perform a slam dunk?",
|
| 111 |
+
correctAnswer: "Basketball",
|
| 112 |
+
incorrectAnswers: ["Volleyball", "Tennis", "Football"],
|
| 113 |
+
},
|
| 114 |
+
{
|
| 115 |
+
id: "fb-27",
|
| 116 |
+
category: "Technology",
|
| 117 |
+
difficulty: "easy",
|
| 118 |
+
questionText: "What company developed the iPhone?",
|
| 119 |
+
correctAnswer: "Apple",
|
| 120 |
+
incorrectAnswers: ["Google", "Samsung", "Microsoft"],
|
| 121 |
+
},
|
| 122 |
+
{
|
| 123 |
+
id: "fb-28",
|
| 124 |
+
category: "History",
|
| 125 |
+
difficulty: "easy",
|
| 126 |
+
questionText: "Who painted the Mona Lisa?",
|
| 127 |
+
correctAnswer: "Leonardo da Vinci",
|
| 128 |
+
incorrectAnswers: ["Michelangelo", "Raphael", "Donatello"],
|
| 129 |
+
},
|
| 130 |
+
{
|
| 131 |
+
id: "fb-29",
|
| 132 |
+
category: "Nature",
|
| 133 |
+
difficulty: "easy",
|
| 134 |
+
questionText: "How many legs does a spider have?",
|
| 135 |
+
correctAnswer: "8",
|
| 136 |
+
incorrectAnswers: ["6", "10", "4"],
|
| 137 |
+
},
|
| 138 |
+
{
|
| 139 |
+
id: "fb-30",
|
| 140 |
+
category: "General Knowledge",
|
| 141 |
+
difficulty: "easy",
|
| 142 |
+
questionText: "What is the boiling point of water in Celsius?",
|
| 143 |
+
correctAnswer: "100",
|
| 144 |
+
incorrectAnswers: ["90", "110", "50"],
|
| 145 |
+
},
|
| 146 |
+
{
|
| 147 |
+
id: "fb-31",
|
| 148 |
+
category: "Geography",
|
| 149 |
+
difficulty: "easy",
|
| 150 |
+
questionText: "Which continent is the Sahara Desert located on?",
|
| 151 |
+
correctAnswer: "Africa",
|
| 152 |
+
incorrectAnswers: ["Asia", "Australia", "South America"],
|
| 153 |
+
},
|
| 154 |
|
| 155 |
+
// ββ MEDIUM (18) ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 156 |
{
|
| 157 |
id: "fb-8",
|
| 158 |
category: "Science",
|
|
|
|
| 209 |
correctAnswer: "Whale Shark",
|
| 210 |
incorrectAnswers: ["Great White Shark", "Hammerhead Shark", "Tiger Shark"],
|
| 211 |
},
|
| 212 |
+
{
|
| 213 |
+
id: "fb-32",
|
| 214 |
+
category: "General Knowledge",
|
| 215 |
+
difficulty: "medium",
|
| 216 |
+
questionText: "What does 'ATM' stand for?",
|
| 217 |
+
correctAnswer: "Automated Teller Machine",
|
| 218 |
+
incorrectAnswers: ["Automatic Transaction Module", "Automated Transfer Mechanism", "Advanced Teller Machine"],
|
| 219 |
+
},
|
| 220 |
+
{
|
| 221 |
+
id: "fb-33",
|
| 222 |
+
category: "Science",
|
| 223 |
+
difficulty: "medium",
|
| 224 |
+
questionText: "What element has the atomic number 1?",
|
| 225 |
+
correctAnswer: "Hydrogen",
|
| 226 |
+
incorrectAnswers: ["Helium", "Oxygen", "Carbon"],
|
| 227 |
+
},
|
| 228 |
+
{
|
| 229 |
+
id: "fb-34",
|
| 230 |
+
category: "History",
|
| 231 |
+
difficulty: "medium",
|
| 232 |
+
questionText: "What year did World War II end?",
|
| 233 |
+
correctAnswer: "1945",
|
| 234 |
+
incorrectAnswers: ["1944", "1946", "1943"],
|
| 235 |
+
},
|
| 236 |
+
{
|
| 237 |
+
id: "fb-35",
|
| 238 |
+
category: "Geography",
|
| 239 |
+
difficulty: "medium",
|
| 240 |
+
questionText: "What is the capital of Australia?",
|
| 241 |
+
correctAnswer: "Canberra",
|
| 242 |
+
incorrectAnswers: ["Sydney", "Melbourne", "Brisbane"],
|
| 243 |
+
},
|
| 244 |
+
{
|
| 245 |
+
id: "fb-36",
|
| 246 |
+
category: "Entertainment",
|
| 247 |
+
difficulty: "medium",
|
| 248 |
+
questionText: "Which actor played Iron Man in the Marvel movies?",
|
| 249 |
+
correctAnswer: "Robert Downey Jr.",
|
| 250 |
+
incorrectAnswers: ["Chris Evans", "Chris Hemsworth", "Mark Ruffalo"],
|
| 251 |
+
},
|
| 252 |
+
{
|
| 253 |
+
id: "fb-37",
|
| 254 |
+
category: "Sports",
|
| 255 |
+
difficulty: "medium",
|
| 256 |
+
questionText: "Which country has won the most FIFA World Cup titles?",
|
| 257 |
+
correctAnswer: "Brazil",
|
| 258 |
+
incorrectAnswers: ["Germany", "Italy", "Argentina"],
|
| 259 |
+
},
|
| 260 |
+
{
|
| 261 |
+
id: "fb-38",
|
| 262 |
+
category: "Technology",
|
| 263 |
+
difficulty: "medium",
|
| 264 |
+
questionText: "Who is considered the father of the World Wide Web?",
|
| 265 |
+
correctAnswer: "Tim Berners-Lee",
|
| 266 |
+
incorrectAnswers: ["Vint Cerf", "Bill Gates", "Steve Jobs"],
|
| 267 |
+
},
|
| 268 |
+
{
|
| 269 |
+
id: "fb-39",
|
| 270 |
+
category: "Nature",
|
| 271 |
+
difficulty: "medium",
|
| 272 |
+
questionText: "What is the fastest land animal?",
|
| 273 |
+
correctAnswer: "Cheetah",
|
| 274 |
+
incorrectAnswers: ["Lion", "Pronghorn Antelope", "Greyhound"],
|
| 275 |
+
},
|
| 276 |
+
{
|
| 277 |
+
id: "fb-40",
|
| 278 |
+
category: "General Knowledge",
|
| 279 |
+
difficulty: "medium",
|
| 280 |
+
questionText: "How many bones are in the adult human body?",
|
| 281 |
+
correctAnswer: "206",
|
| 282 |
+
incorrectAnswers: ["186", "226", "256"],
|
| 283 |
+
},
|
| 284 |
+
{
|
| 285 |
+
id: "fb-41",
|
| 286 |
+
category: "Science",
|
| 287 |
+
difficulty: "medium",
|
| 288 |
+
questionText: "What planet has the most moons?",
|
| 289 |
+
correctAnswer: "Saturn",
|
| 290 |
+
incorrectAnswers: ["Jupiter", "Uranus", "Neptune"],
|
| 291 |
+
},
|
| 292 |
+
{
|
| 293 |
+
id: "fb-42",
|
| 294 |
+
category: "History",
|
| 295 |
+
difficulty: "medium",
|
| 296 |
+
questionText: "Who was the first woman to fly solo across the Atlantic?",
|
| 297 |
+
correctAnswer: "Amelia Earhart",
|
| 298 |
+
incorrectAnswers: ["Harriet Quimby", "Bessie Coleman", "Jacqueline Cochran"],
|
| 299 |
+
},
|
| 300 |
|
| 301 |
+
// ββ HARD (18) ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 302 |
{
|
| 303 |
id: "fb-15",
|
| 304 |
category: "Science",
|
|
|
|
| 347 |
correctAnswer: "Bat",
|
| 348 |
incorrectAnswers: ["Flying Squirrel", "Colugo", "Sugar Glider"],
|
| 349 |
},
|
| 350 |
+
{
|
| 351 |
+
id: "fb-43",
|
| 352 |
+
category: "General Knowledge",
|
| 353 |
+
difficulty: "hard",
|
| 354 |
+
questionText: "What is the rarest blood type?",
|
| 355 |
+
correctAnswer: "AB Negative",
|
| 356 |
+
incorrectAnswers: ["O Negative", "B Negative", "A Negative"],
|
| 357 |
+
},
|
| 358 |
+
{
|
| 359 |
+
id: "fb-44",
|
| 360 |
+
category: "Science",
|
| 361 |
+
difficulty: "hard",
|
| 362 |
+
questionText: "What particle is responsible for mediating the electromagnetic force?",
|
| 363 |
+
correctAnswer: "Photon",
|
| 364 |
+
incorrectAnswers: ["Gluon", "W Boson", "Graviton"],
|
| 365 |
+
},
|
| 366 |
+
{
|
| 367 |
+
id: "fb-45",
|
| 368 |
+
category: "History",
|
| 369 |
+
difficulty: "hard",
|
| 370 |
+
questionText: "In what year did the French Revolution begin?",
|
| 371 |
+
correctAnswer: "1789",
|
| 372 |
+
incorrectAnswers: ["1776", "1799", "1815"],
|
| 373 |
+
},
|
| 374 |
+
{
|
| 375 |
+
id: "fb-46",
|
| 376 |
+
category: "Geography",
|
| 377 |
+
difficulty: "hard",
|
| 378 |
+
questionText: "Which country has the longest coastline in the world?",
|
| 379 |
+
correctAnswer: "Canada",
|
| 380 |
+
incorrectAnswers: ["Australia", "Russia", "Indonesia"],
|
| 381 |
+
},
|
| 382 |
+
{
|
| 383 |
+
id: "fb-47",
|
| 384 |
+
category: "Entertainment",
|
| 385 |
+
difficulty: "hard",
|
| 386 |
+
questionText: "Which film won the Academy Award for Best Picture in 1994?",
|
| 387 |
+
correctAnswer: "Schindler's List",
|
| 388 |
+
incorrectAnswers: ["Forrest Gump", "The Shawshank Redemption", "Pulp Fiction"],
|
| 389 |
+
},
|
| 390 |
+
{
|
| 391 |
+
id: "fb-48",
|
| 392 |
+
category: "Sports",
|
| 393 |
+
difficulty: "hard",
|
| 394 |
+
questionText: "In which sport would you use a 'shuttlecock'?",
|
| 395 |
+
correctAnswer: "Badminton",
|
| 396 |
+
incorrectAnswers: ["Table Tennis", "Squash", "Cricket"],
|
| 397 |
+
},
|
| 398 |
+
{
|
| 399 |
+
id: "fb-49",
|
| 400 |
+
category: "Technology",
|
| 401 |
+
difficulty: "hard",
|
| 402 |
+
questionText: "What programming language was created by James Gosling at Sun Microsystems?",
|
| 403 |
+
correctAnswer: "Java",
|
| 404 |
+
incorrectAnswers: ["C++", "Python", "Ruby"],
|
| 405 |
+
},
|
| 406 |
+
{
|
| 407 |
+
id: "fb-50",
|
| 408 |
+
category: "Nature",
|
| 409 |
+
difficulty: "hard",
|
| 410 |
+
questionText: "What is the largest organ in the human body?",
|
| 411 |
+
correctAnswer: "Skin",
|
| 412 |
+
incorrectAnswers: ["Liver", "Brain", "Heart"],
|
| 413 |
+
},
|
| 414 |
+
{
|
| 415 |
+
id: "fb-51",
|
| 416 |
+
category: "General Knowledge",
|
| 417 |
+
difficulty: "hard",
|
| 418 |
+
questionText: "What is the only letter that does not appear in any US state name?",
|
| 419 |
+
correctAnswer: "Q",
|
| 420 |
+
incorrectAnswers: ["X", "Z", "J"],
|
| 421 |
+
},
|
| 422 |
+
{
|
| 423 |
+
id: "fb-52",
|
| 424 |
+
category: "Science",
|
| 425 |
+
difficulty: "hard",
|
| 426 |
+
questionText: "What is the chemical formula for ozone?",
|
| 427 |
+
correctAnswer: "O3",
|
| 428 |
+
incorrectAnswers: ["O2", "CO2", "H2O"],
|
| 429 |
+
},
|
| 430 |
+
{
|
| 431 |
+
id: "fb-53",
|
| 432 |
+
category: "History",
|
| 433 |
+
difficulty: "hard",
|
| 434 |
+
questionText: "Who was the last Pharaoh of Egypt?",
|
| 435 |
+
correctAnswer: "Cleopatra VII",
|
| 436 |
+
incorrectAnswers: ["Hatshepsut", "Nefertiti", "Ramesses II"],
|
| 437 |
+
},
|
| 438 |
+
{
|
| 439 |
+
id: "fb-54",
|
| 440 |
+
category: "Geography",
|
| 441 |
+
difficulty: "hard",
|
| 442 |
+
questionText: "What is the highest capital city in the world?",
|
| 443 |
+
correctAnswer: "La Paz",
|
| 444 |
+
incorrectAnswers: ["Quito", "Bogota", "Lhasa"],
|
| 445 |
+
},
|
| 446 |
];
|