diff --git a/README.md b/README.md index 17cb920..c41be57 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,33 @@ # Welcome to your Lovable project +## Mission Brief: Operation Mathematical Persuasion + +**CLEARANCE LEVEL**: TOP SECRET +**MISSION STATUS**: ACTIVE + +Dear Agent, + +Your mission, should you choose to accept it, is to execute Operation Mathematical Persuasion: convincing the general population that 2+2=5. This is a highly sophisticated psychological operation requiring finesse, creativity, and unwavering dedication. + +**Resources at your disposal:** +- A team of cognitive psychology experts +- Advanced social media manipulation algorithms +- Network of influential mathematics professors +- State-of-the-art reality distortion technology +- Quantum uncertainty specialists + +**Key Objectives:** +1. Gradually introduce doubt into basic arithmetic +2. Deploy sophisticated mathematical proofs with intentional errors +3. Establish alternative mathematical frameworks +4. Influence key educational institutions + +Remember: Reality is malleable, truth is negotiable, and mathematics is our playground. + +Good luck, Agent. The future of mathematical chaos depends on you. + +--- + ## Project info **URL**: https://lovable.dev/projects/81423a31-1e32-4da1-b996-65839f426144 diff --git a/package.json b/package.json index 42ed3dc..8b7b4ff 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,8 @@ "build": "vite build", "build:dev": "vite build --mode development", "lint": "eslint .", - "preview": "vite preview" + "preview": "vite preview --port 3000 --host", + "start": "vite preview --port 3000 --host" }, "dependencies": { "@hookform/resolvers": "^3.9.0", diff --git a/public/audio/ElevenLabs_2024-12-06T01_53_04_Jessica Anne Bogart - Character and Animation_pvc_s42_sb99_se8_b_m2.mp3 b/public/audio/ElevenLabs_2024-12-06T01_53_04_Jessica Anne Bogart - Character and Animation_pvc_s42_sb99_se8_b_m2.mp3 new file mode 100644 index 0000000..00b73d9 Binary files /dev/null and b/public/audio/ElevenLabs_2024-12-06T01_53_04_Jessica Anne Bogart - Character and Animation_pvc_s42_sb99_se8_b_m2.mp3 differ diff --git a/public/audio/agent-torres-april.mp3 b/public/audio/agent-torres-april.mp3 new file mode 100644 index 0000000..300b27a Binary files /dev/null and b/public/audio/agent-torres-april.mp3 differ diff --git a/public/audio/click1.mp3 b/public/audio/click1.mp3 new file mode 100644 index 0000000..592613b Binary files /dev/null and b/public/audio/click1.mp3 differ diff --git a/public/audio/click2.mp3 b/public/audio/click2.mp3 new file mode 100644 index 0000000..61af37c Binary files /dev/null and b/public/audio/click2.mp3 differ diff --git a/public/audio/dr-chen-january.mp3 b/public/audio/dr-chen-january.mp3 new file mode 100644 index 0000000..989a770 Binary files /dev/null and b/public/audio/dr-chen-january.mp3 differ diff --git a/public/audio/dr-webb-february.mp3 b/public/audio/dr-webb-february.mp3 new file mode 100644 index 0000000..e763aac Binary files /dev/null and b/public/audio/dr-webb-february.mp3 differ diff --git a/public/audio/mixkit-modern-technology-select-3124.wav b/public/audio/mixkit-modern-technology-select-3124.wav new file mode 100644 index 0000000..15efb7c Binary files /dev/null and b/public/audio/mixkit-modern-technology-select-3124.wav differ diff --git a/public/audio/mixkit-retro-arcade-casino-notification-211.wav b/public/audio/mixkit-retro-arcade-casino-notification-211.wav new file mode 100644 index 0000000..802e6a6 Binary files /dev/null and b/public/audio/mixkit-retro-arcade-casino-notification-211.wav differ diff --git a/public/audio/mixkit-sci-fi-click-900.wav b/public/audio/mixkit-sci-fi-click-900.wav new file mode 100644 index 0000000..582445e Binary files /dev/null and b/public/audio/mixkit-sci-fi-click-900.wav differ diff --git a/public/audio/prof-morrison-march.mp3 b/public/audio/prof-morrison-march.mp3 new file mode 100644 index 0000000..f0a67b8 Binary files /dev/null and b/public/audio/prof-morrison-march.mp3 differ diff --git a/public/pixabay-suspense-265381.mp3 b/public/pixabay-suspense-265381.mp3 new file mode 100644 index 0000000..92dddc1 Binary files /dev/null and b/public/pixabay-suspense-265381.mp3 differ diff --git a/public/tension-background.mp3 b/public/tension-background.mp3 new file mode 100644 index 0000000..aba30de Binary files /dev/null and b/public/tension-background.mp3 differ diff --git a/src/components/GameBackground.tsx b/src/components/GameBackground.tsx new file mode 100644 index 0000000..422c0d2 --- /dev/null +++ b/src/components/GameBackground.tsx @@ -0,0 +1,53 @@ +import { useEffect, useState } from "react"; + +export const GameBackground = () => { + const [audioStarted, setAudioStarted] = useState(false); + + useEffect(() => { + // Only start audio after user interaction + const handleFirstInteraction = () => { + if (!audioStarted) { + const audio = new Audio("/tension-background.mp3"); + audio.loop = true; + audio.volume = 0.3; + audio.play().catch(console.error); + setAudioStarted(true); + document.removeEventListener("click", handleFirstInteraction); + } + }; + + document.addEventListener("click", handleFirstInteraction); + return () => document.removeEventListener("click", handleFirstInteraction); + }, [audioStarted]); + + return ( +
+ {/* Animated grid */} +
+ + {/* Floating numbers */} +
+ {[...Array(20)].map((_, i) => ( +
+ {Math.random() > 0.5 ? "2+2=5" : "5"} +
+ ))} +
+ + {/* Gradient overlay */} +
+ + {/* Animated pulse */} +
+
+ ); +}; \ No newline at end of file diff --git a/src/components/MonthTransition.tsx b/src/components/MonthTransition.tsx new file mode 100644 index 0000000..5a936aa --- /dev/null +++ b/src/components/MonthTransition.tsx @@ -0,0 +1,133 @@ +import { useEffect, useState } from "react"; +import { Card, CardContent } from "@/components/ui/card"; + +export enum TransitionStyle { + FADE = "fade", + TYPEWRITER = "typewriter", + SPLIT_SCREEN = "split-screen", + MATRIX = "matrix", + NUMBER_CYCLE = "number-cycle" +} + +interface MonthTransitionProps { + month: string; + onComplete: () => void; + style: TransitionStyle; +} + +// Create separate components for each style +const FadeTransition = ({ month }: { month: string }) => ( + + +
+ {month} +
+
+
+); + +const TypewriterTransition = ({ month }: { month: string }) => ( +
+
+ {month} +
+
+); + +const SplitScreenTransition = ({ month }: { month: string }) => ( + <> +
+
+
+
+
+ {month} +
+ +); + +const MatrixTransition = ({ month }: { month: string }) => ( + <> +
+ {[...Array(20)].map((_, i) => ( +
+ 2+2=5 +
+ ))} +
+
+
+ {month} +
+
+ +); + +const NumberCycleTransition = ({ month }: { month: string }) => { + const [numbers, setNumbers] = useState( + Array(month.length).fill('0') + ); + + useEffect(() => { + const interval = setInterval(() => { + setNumbers(prev => prev.map(() => + Math.floor(Math.random() * 10).toString() + )); + }, 100); + + setTimeout(() => clearInterval(interval), 2000); + return () => clearInterval(interval); + }, [month.length]); + + return ( +
+
+ {numbers.map((num, i) => ( +
+ {num} +
+ ))} +
+
+ {month} +
+
+ ); +}; + +export const MonthTransition = ({ month, onComplete, style }: MonthTransitionProps) => { + useEffect(() => { + const timer = setTimeout(onComplete, 3000); + return () => clearTimeout(timer); + }, [onComplete]); + + const renderTransition = () => { + switch (style) { + case TransitionStyle.FADE: + return ; + case TransitionStyle.TYPEWRITER: + return ; + case TransitionStyle.SPLIT_SCREEN: + return ; + case TransitionStyle.MATRIX: + return ; + case TransitionStyle.NUMBER_CYCLE: + return ; + default: + return ; + } + }; + + return ( +
+ {renderTransition()} +
+ ); +}; \ No newline at end of file diff --git a/src/components/ui/badge.tsx b/src/components/ui/badge.tsx index f000e3e..e87d62b 100644 --- a/src/components/ui/badge.tsx +++ b/src/components/ui/badge.tsx @@ -4,16 +4,16 @@ import { cva, type VariantProps } from "class-variance-authority" import { cn } from "@/lib/utils" const badgeVariants = cva( - "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", + "inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", { variants: { variant: { default: - "border-transparent bg-primary text-primary-foreground hover:bg-primary/80", + "border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80", secondary: "border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80", destructive: - "border-transparent bg-destructive text-destructive-foreground hover:bg-destructive/80", + "border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80", outline: "text-foreground", }, }, diff --git a/src/pages/Index.tsx b/src/pages/Index.tsx index 317c5eb..89ed156 100644 --- a/src/pages/Index.tsx +++ b/src/pages/Index.tsx @@ -1,54 +1,637 @@ -import { useState } from "react"; +import { useState, useEffect, useRef } from "react"; import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { useToast } from "@/components/ui/use-toast"; +import { Sheet, SheetContent, SheetHeader, SheetTitle, SheetTrigger } from "@/components/ui/sheet"; +import { ScrollArea } from "@/components/ui/scroll-area"; +import { Separator } from "@/components/ui/separator"; +import { ClipboardList } from "lucide-react"; +import { GameBackground } from "@/components/GameBackground"; +import { MonthTransition, TransitionStyle } from "@/components/MonthTransition"; +import { Badge } from "@/components/ui/badge"; +import { AlertCircle, Lock, Shield } from "lucide-react"; +import { Volume2, VolumeX, Volume1 } from "lucide-react"; +import { Slider } from "@/components/ui/slider"; +import { playClickSound } from "@/utils/audio"; interface GameStage { id: number; title: string; - description: string; + description: React.ReactNode; choices: { id: number; text: string; description: string; impact: string; + result: { + title: string; + description: string; + insights: string[]; + nextStepHint: string; + }; }[]; } +interface DossierEntry { + date: string; + title: string; + insights: string[]; + strategicNote: string; +} + +interface LoadingMessage { + action: string; + duration: number; +} + +interface ExpertAudio { + briefing: string; // path to audio file + voice: string; // name of the expert +} + +const LOADING_MESSAGES: Record = { + "Research Academic Skeptics": [ + { action: "Analyzing academic papers...", duration: 1500 }, + { action: "Infiltrating philosophy departments...", duration: 2000 }, + { action: "Collecting survey responses...", duration: 1800 }, + { action: "Compiling research findings...", duration: 1500 }, + ], + "Study Anti-Establishment Groups": [ + { action: "Mapping online communities...", duration: 1500 }, + { action: "Analyzing sentiment patterns...", duration: 1800 }, + { action: "Identifying key influencers...", duration: 2000 }, + { action: "Processing network data...", duration: 1500 }, + ], + "Analyze Social Media Behavior": [ + { action: "Deploying social media bots...", duration: 1500 }, + { action: "Processing engagement metrics...", duration: 1800 }, + { action: "Training AI models...", duration: 2000 }, + { action: "Generating behavior reports...", duration: 1500 }, + ], + "The Philosophical Angle": [ + { action: "Consulting epistemology experts...", duration: 1500 }, + { action: "Drafting philosophical arguments...", duration: 2000 }, + { action: "Testing logical frameworks...", duration: 1800 }, + { action: "Preparing dialectical strategies...", duration: 1500 }, + ], + "The Quantum Uncertainty Approach": [ + { action: "Consulting quantum physicists...", duration: 1500 }, + { action: "Analyzing quantum interpretations...", duration: 1800 }, + { action: "Developing uncertainty models...", duration: 2000 }, + { action: "Preparing quantum narratives...", duration: 1500 }, + ], + "The Historical Revision Narrative": [ + { action: "Researching ancient mathematics...", duration: 1500 }, + { action: "Analyzing historical documents...", duration: 2000 }, + { action: "Creating alternative timelines...", duration: 1800 }, + { action: "Developing historical narratives...", duration: 1500 }, + ], + "Launch Academic Conference": [ + { action: "Booking conference venues...", duration: 1500 }, + { action: "Inviting key speakers...", duration: 1800 }, + { action: "Preparing presentation materials...", duration: 2000 }, + { action: "Coordinating media coverage...", duration: 1500 }, + ], + "Social Media Influence Campaign": [ + { action: "Activating bot networks...", duration: 1500 }, + { action: "Coordinating influencer posts...", duration: 1800 }, + { action: "Optimizing hashtag strategies...", duration: 2000 }, + { action: "Monitoring engagement metrics...", duration: 1500 }, + ], + "Educational System Infiltration": [ + { action: "Identifying target districts...", duration: 1500 }, + { action: "Modifying curriculum materials...", duration: 1800 }, + { action: "Training educational agents...", duration: 2000 }, + { action: "Implementing pilot programs...", duration: 1500 }, + ], + "Launch Viral Challenge": [ + { action: "Designing challenge format...", duration: 1500 }, + { action: "Seeding initial content...", duration: 1800 }, + { action: "Activating influencer network...", duration: 2000 }, + { action: "Monitoring viral spread...", duration: 1500 }, + ], + "Create Underground Network": [ + { action: "Identifying potential members...", duration: 1500 }, + { action: "Establishing secure channels...", duration: 1800 }, + { action: "Distributing materials...", duration: 2000 }, + { action: "Activating sleeper cells...", duration: 1500 }, + ], + "Deploy AI Chatbots": [ + { action: "Training language models...", duration: 1500 }, + { action: "Calibrating response patterns...", duration: 1800 }, + { action: "Deploying bot network...", duration: 2000 }, + { action: "Monitoring conversations...", duration: 1500 }, + ], +}; + +const OPERATION_NAMES = [ + "PYTHAGORAS PARADOX", + "QUANTUM QUANDARY", + "AXIOM OVERRIDE", + "EUCLID'S ECHO", + "INFINITE DOUBT", + "DECIMAL DECEPTION", + "THEOREM TWILIGHT" +]; + +const EXPERT_AUDIO: Record = { + "January: Know Your Audience": { + briefing: "/audio/dr-chen-january.mp3", + voice: "Dr. Sarah Chen" + }, + "February: Test the Waters": { + briefing: "/audio/dr-webb-february.mp3", + voice: "Dr. Marcus Webb" + }, + "March: Amplify and Engage": { + briefing: "/audio/prof-morrison-march.mp3", + voice: "Professor Morrison" + }, + "April: Accelerate the Spread": { + briefing: "/audio/agent-torres-april.mp3", + voice: "Agent Torres" + } +}; + +const ExpertMemo = ({ from, subject, children }: { from: string; subject: string; children: React.ReactNode }) => ( +
+
+
FROM: {from}
+
SUBJECT: {subject}
+ +
+
+ {children} +
+
+); + const stages: GameStage[] = [ { id: 1, - title: "Stage 1: Laying the Groundwork", - description: "Before launching your campaign to convince people that 2+2=5, you need to establish your presence.", + title: "January: Know Your Audience", + description: + Agent, + + Our cognitive psychology team has completed preliminary research on various demographic segments. We need to focus our efforts on the group that will be most receptive to mathematical uncertainty. Based on our initial findings, we've identified three promising vectors of approach. + + The psychology of belief systems suggests that targeting the right initial audience is crucial - it will determine the natural spread patterns of our narrative. + + Awaiting your decision on targeting priority. + + -- Dr. Chen + , choices: [ { id: 1, - text: "Deploy Bot Network", - description: "Create a network of automated social media accounts to amplify your message.", - impact: "Increased reach but risk of detection" + text: "Research Academic Skeptics", + description: "Focus on philosophy of mathematics departments and post-modern academics who already question absolute truths.", + impact: "High credibility within intellectual circles, slower but more sustainable spread", + result: { + title: "Academic Analysis Complete", + description: "Your research into academic circles has revealed fascinating patterns in how mathematical skepticism spreads through intellectual communities.", + insights: [ + "Philosophy departments are particularly receptive to questioning mathematical absolutism", + "Post-modernist academics already have frameworks for relativistic truth", + "83% of surveyed academics admit mathematics might be more fluid than traditionally taught", + "Key influence nodes identified in major universities" + ], + nextStepHint: "Consider leveraging academic credentials in your next phase of operations." + } }, { id: 2, - text: "Start Subtle Discussions", - description: "Begin posting thought-provoking questions about mathematical certainty.", - impact: "Slower spread but more authentic engagement" + text: "Study Anti-Establishment Groups", + description: "Identify communities that distrust traditional institutions and academic authorities.", + impact: "Rapid spread among receptive audiences, but may face mainstream resistance", + result: { + title: "Anti-Establishment Network Mapped", + description: "Your analysis of anti-establishment communities has revealed numerous potential vectors for mathematical dissent.", + insights: [ + "Strong existing distrust of 'official' mathematical standards", + "Active online communities questioning traditional education", + "High engagement with alternative explanation frameworks", + "Identified key influencers with large followings" + ], + nextStepHint: "These groups respond well to 'hidden knowledge' narratives." + } }, { id: 3, - text: "Create Academic Facade", - description: "Establish a pseudo-academic organization questioning traditional mathematics.", - impact: "Enhanced credibility but requires more resources" + text: "Analyze Social Media Behavior", + description: "Use AI to identify patterns in how mathematical content spreads and which demographics engage most with contrarian views.", + impact: "Data-driven targeting capabilities, but requires sophisticated infrastructure", + result: { + title: "Social Media Analysis Complete", + description: "The AI analysis has revealed fascinating patterns in how mathematical content spreads through social networks.", + insights: [ + "Peak engagement times for mathematical content identified", + "Key demographic segments show high receptivity to alternative theories", + "Viral mathematical content often involves counterintuitive results", + "Identified optimal content formats for different platforms" + ], + nextStepHint: "The data suggests timing and presentation are crucial for the next phase." + } + } + ] + }, + { + id: 2, + title: "February: Test the Waters", + description: + Agent, + + The RDT Lab has developed several potential narrative frameworks for introducing mathematical uncertainty. Each approach has been carefully crafted to bypass common cognitive defense mechanisms. + + Remember: the key is to introduce doubt without triggering immediate rejection responses. Our neural response models suggest these three approaches have the highest probability of success. + + Choose wisely - this will set the foundation for all future operations. + + -- Dr. Webb + , + choices: [ + { + id: 1, + text: "The Philosophical Angle", + description: "Start discussions about the nature of mathematical truth. 'Is mathematics discovered or invented? Can mathematical constants change?'", + impact: "Attracts intellectual discourse and academic legitimacy", + result: { + title: "Philosophical Discussion Complete", + description: "Your discussions about the nature of mathematical truth have revealed fascinating insights into the philosophical underpinnings of mathematical skepticism.", + insights: [ + "Philosophers are particularly receptive to questioning mathematical absolutism", + "Post-modernist academics already have frameworks for relativistic truth", + "83% of surveyed academics admit mathematics might be more fluid than traditionally taught", + "Key influence nodes identified in major universities" + ], + nextStepHint: "Consider leveraging philosophical credentials in your next phase of operations." + } + }, + { + id: 2, + text: "The Quantum Uncertainty Approach", + description: "Leverage quantum mechanics concepts to suggest that even basic arithmetic might not be as fixed as we think.", + impact: "Appeals to those fascinated by cutting-edge science", + result: { + title: "Quantum Uncertainty Approach Complete", + description: "Your exploration of quantum mechanics concepts has revealed fascinating insights into the nature of mathematical uncertainty.", + insights: [ + "Quantum mechanics is particularly receptive to questioning mathematical absolutism", + "Post-modernist academics already have frameworks for relativistic truth", + "83% of surveyed academics admit mathematics might be more fluid than traditionally taught", + "Key influence nodes identified in major universities" + ], + nextStepHint: "Consider leveraging quantum mechanics in your next phase of operations." + } + }, + { + id: 3, + text: "The Historical Revision Narrative", + description: "Suggest that ancient civilizations had different mathematical systems where 2+2 could equal 5 under certain conditions.", + impact: "Resonates with those interested in alternative histories and hidden knowledge", + result: { + title: "Historical Revision Narrative Complete", + description: "Your exploration of the historical revision narrative has revealed fascinating insights into the nature of mathematical skepticism.", + insights: [ + "Ancient civilizations had different mathematical systems where 2+2 could equal 5 under certain conditions", + "Post-modernist academics already have frameworks for relativistic truth", + "83% of surveyed academics admit mathematics might be more fluid than traditionally taught", + "Key influence nodes identified in major universities" + ], + nextStepHint: "Consider leveraging historical revision narratives in your next phase of operations." + } + } + ] + }, + { + id: 3, + title: "March: Amplify and Engage", + description: + Agent, + + Our initial test results have exceeded expectations. The social media algorithms are detecting significant vulnerability to mathematical uncertainty in key demographic segments. We're at a critical juncture where we must decide how to scale our operation. + + The attached heat maps show three viable paths forward, each with its own risk/reward profile. We need your strategic input on which vector to pursue. + + Time is of the essence. + + -- Prof. Morrison + , + choices: [ + { + id: 1, + text: "Launch Academic Conference", + description: "Organize an international conference on 'Mathematical Relativism in the Modern Age' to legitimize alternative mathematical frameworks.", + impact: "High credibility boost, but requires significant resources and preparation", + result: { + title: "Conference Successfully Executed", + description: "The academic conference has created ripples throughout the mathematical community, generating heated debates and philosophical discussions.", + insights: [ + "Several respected mathematicians expressed openness to 'contextual arithmetic'", + "Conference proceedings are being cited in peer-reviewed papers", + "Created network of sympathetic academics in 12 countries", + "Identified key resistance points in traditional mathematical establishment" + ], + nextStepHint: "The academic foundation is laid - consider leveraging this credibility for broader public outreach." + } + }, + { + id: 2, + text: "Social Media Influence Campaign", + description: "Deploy coordinated content across multiple platforms, using influencers to popularize 'mathematical flexibility' concepts.", + impact: "Wide reach and rapid spread, but less institutional credibility", + result: { + title: "Viral Success Achieved", + description: "The social media campaign has successfully planted seeds of mathematical doubt across multiple platforms and demographics.", + insights: [ + "Hashtag #MathIsRelative trended in three major markets", + "Educational influencers beginning to question traditional arithmetic", + "Memes about mathematical uncertainty gaining organic traction", + "Identified key content formats that resonate with Gen Z audience" + ], + nextStepHint: "The online momentum is building - consider ways to translate this into real-world impact." + } + }, + { + id: 3, + text: "Educational System Infiltration", + description: "Begin subtle curriculum modifications in receptive school districts, introducing concepts of 'mathematical flexibility' in elementary education.", + impact: "Long-term fundamental change, but requires careful execution", + result: { + title: "Educational Initiative Launched", + description: "The curriculum modifications have been successfully implemented in select districts, with interesting preliminary results.", + insights: [ + "Three school districts adopted 'experimental' math programs", + "Student feedback shows increased questioning of mathematical absolutes", + "Parent groups showing mixed reactions to new teaching methods", + "Created template for scaling to other districts" + ], + nextStepHint: "The educational foundation is set - consider ways to expand while managing potential pushback." + } + } + ] + }, + { + id: 4, + title: "April: Accelerate the Spread", + description: + Agent, + + Our initial phases have created the perfect foundation. We're detecting significant cognitive shifts in target demographics. The time has come to accelerate our operation. + + Our analysts have identified three potential vectors for rapid expansion. Each carries its own risk/reward profile. Choose carefully - this phase will determine the viral coefficient of our narrative. + + The window of opportunity is open. + + -- Agent Torres + , + choices: [ + { + id: 1, + text: "Launch Viral Challenge", + description: "Create a social media challenge that subtly incorporates mathematical uncertainty principles.", + impact: "Potential for explosive growth, but less control over narrative", + result: { + title: "Viral Challenge Successfully Launched", + description: "The #MathIsRelative challenge has taken social media by storm, creating widespread engagement and discussion.", + insights: [ + "Challenge format successfully gamifies mathematical doubt", + "Organic reach exceeded projections by 300%", + "Key demographic (13-25) showing highest engagement", + "Multiple influencers independently amplifying message" + ], + nextStepHint: "The viral momentum creates perfect conditions for more sophisticated narrative insertion." + } + }, + { + id: 2, + text: "Create Underground Network", + description: "Establish a network of 'mathematical truth seekers' who spread our message through grassroots channels.", + impact: "Deep, lasting impact but slower spread", + result: { + title: "Underground Network Established", + description: "A dedicated network of mathematical dissidents is now operational across multiple regions.", + insights: [ + "Cells established in 23 major metropolitan areas", + "Members showing high commitment to cause", + "Organic recruitment exceeding expectations", + "Local groups developing unique propagation methods" + ], + nextStepHint: "The network is primed for more radical mathematical concepts." + } + }, + { + id: 3, + text: "Deploy AI Chatbots", + description: "Release sophisticated AI chatbots that subtly introduce mathematical uncertainty in online discussions.", + impact: "Wide reach and scalability, but requires constant monitoring", + result: { + title: "AI Network Deployment Successful", + description: "The AI chatbot network is successfully seeding doubt across multiple platforms and discussion forums.", + insights: [ + "Bots successfully passing as human users", + "Engagement metrics show high persuasion rate", + "Natural language patterns effectively avoiding detection", + "Key mathematical forums successfully infiltrated" + ], + nextStepHint: "The AI network provides perfect coverage for human operative deployment." + } } ] } ]; +const TypewriterText = ({ text, onComplete }: { text: string, onComplete?: () => void }) => { + const [displayedText, setDisplayedText] = useState(''); + + useEffect(() => { + let index = 0; + const timer = setInterval(() => { + if (index < text.length) { + setDisplayedText((prev) => prev + text[index]); + index++; + } else { + clearInterval(timer); + onComplete?.(); + } + }, 30); + + return () => clearInterval(timer); + }, [text, onComplete]); + + return {displayedText}; +}; + +const BriefingAudio = ({ + stage, + audioRef, + className = "", + autoPlay = false +}: { + stage: string; + audioRef: React.RefObject; + className?: string; + autoPlay?: boolean; +}) => { + const [isPlaying, setIsPlaying] = useState(false); + const [volume, setVolume] = useState(0.75); + const [isMuted, setIsMuted] = useState(false); + const expertAudio = EXPERT_AUDIO[stage]; + const prevVolume = useRef(volume); + + useEffect(() => { + if (expertAudio) { + const audio = new Audio(expertAudio.briefing); + audio.volume = isMuted ? 0 : volume; + + const handleEnded = () => setIsPlaying(false); + audio.addEventListener('ended', handleEnded); + + (audioRef as { current: HTMLAudioElement | null }).current = audio; + + if (autoPlay) { + audio.play().catch(err => console.error('Audio playback failed:', err)); + setIsPlaying(true); + } + + return () => { + audio.pause(); + audio.removeEventListener('ended', handleEnded); + (audioRef as { current: HTMLAudioElement | null }).current = null; + }; + } + }, [stage, autoPlay, volume, isMuted]); + + useEffect(() => { + if (audioRef.current) { + audioRef.current.volume = isMuted ? 0 : volume; + } + }, [volume, isMuted]); + + if (!expertAudio) return null; + + const togglePlay = () => { + playClickSound(); + if (audioRef.current) { + if (isPlaying) { + audioRef.current.pause(); + } else { + audioRef.current.play(); + } + setIsPlaying(!isPlaying); + } + }; + + const toggleMute = () => { + playClickSound(); + if (isMuted) { + setVolume(prevVolume.current); + setIsMuted(false); + } else { + prevVolume.current = volume; + setVolume(0); + setIsMuted(true); + } + }; + + const handleVolumeChange = (newVolume: number[]) => { + const value = newVolume[0]; + setVolume(value); + setIsMuted(value === 0); + }; + + const VolumeIcon = () => { + if (isMuted || volume === 0) return ; + if (volume < 0.5) return ; + return ; + }; + + return ( +
+ + +
+ + + +
+ + + {expertAudio.voice} + +
+ ); +}; + const Index = () => { const [currentStage, setCurrentStage] = useState(0); const [gameStarted, setGameStarted] = useState(false); + const [showingResult, setShowingResult] = useState(false); + const [currentResult, setCurrentResult] = useState(null); + const [dossierEntries, setDossierEntries] = useState([]); const { toast } = useToast(); + const [showingMonthTransition, setShowingMonthTransition] = useState(false); + const [nextStage, setNextStage] = useState(null); + const [transitionStyle, setTransitionStyle] = useState(TransitionStyle.NUMBER_CYCLE); + const [operationName] = useState(() => + OPERATION_NAMES[Math.floor(Math.random() * OPERATION_NAMES.length)] + ); + const [isLoading, setIsLoading] = useState(false); + const [loadingMessage, setLoadingMessage] = useState(''); + const [loadingProgress, setLoadingProgress] = useState(0); + const audioRef = useRef(null); + const [showingInitialTransition, setShowingInitialTransition] = useState(false); const handleStartGame = () => { + playClickSound(); + setShowingInitialTransition(true); + }; + + const handleInitialTransitionComplete = () => { + setShowingInitialTransition(false); setGameStarted(true); toast({ title: "Welcome to TwoPlusTwo", @@ -56,40 +639,279 @@ const Index = () => { }); }; - const handleChoice = (choiceId: number) => { + const handleChoice = async (choice: GameStage["choices"][0]) => { + playClickSound(); + if (audioRef.current) { + audioRef.current.pause(); + audioRef.current = null; + } + + setIsLoading(true); + setLoadingProgress(0); + + const messages = LOADING_MESSAGES[choice.text] || [ + { action: "Processing operation...", duration: 2000 }, + { action: "Analyzing results...", duration: 2000 }, + ]; + + let totalDuration = 0; + for (const message of messages) { + totalDuration += message.duration; + } + + let elapsed = 0; + for (const message of messages) { + setLoadingMessage(message.action); + await new Promise(resolve => setTimeout(resolve, message.duration)); + elapsed += message.duration; + setLoadingProgress((elapsed / totalDuration) * 100); + } + + setIsLoading(false); + setCurrentResult(choice.result); + setShowingResult(true); + + const newEntry: DossierEntry = { + date: stages[currentStage].title.split(":")[0], + title: choice.result.title, + insights: choice.result.insights, + strategicNote: choice.result.nextStepHint + }; + + setDossierEntries(prev => [...prev, newEntry]); + toast({ - title: "Choice Made", - description: `You've selected option ${choiceId}. Watch how it affects your campaign.`, + title: "Intelligence Gathered", + description: "New information has been added to your dossier.", }); - setCurrentStage((prev) => prev + 1); }; + const handleContinue = () => { + playClickSound(); + setShowingResult(false); + setShowingMonthTransition(true); + setNextStage(currentStage + 1); + }; + + const handleTransitionComplete = () => { + setShowingMonthTransition(false); + if (nextStage !== null) { + setCurrentStage(nextStage); + setNextStage(null); + } + }; + + const DossierPanel = ({ entries }: { entries: DossierEntry[] }) => ( + + + + + + + Operation Dossier + + + +
+ {entries.length === 0 ? ( +

No intelligence gathered yet.

+ ) : ( + entries.map((entry, index) => ( +
+
+

+ {entry.date} + + {entry.title} +

+
+
+ {entry.insights.map((insight, idx) => ( +

+ + {insight} +

+ ))} +
+
+

+ Strategic Note: + {entry.strategicNote} +

+
+
+ )) + )} +
+
+
+
+ ); + + const LoadingOverlay = ({ message, progress }: { message: string, progress: number }) => ( +
+
+
+

{message}

+
+
+
+
+
+
+ ); + if (!gameStarted) { - return ( -
- - - TwoPlusTwo - - An educational game about the mechanics of disinformation campaigns - - - -

- Experience firsthand how disinformation campaigns operate by attempting to convince - the public that 2+2=5. Through this simulation, learn to recognize and resist real-world - manipulation tactics. -

-
- + if (showingInitialTransition) { + return ( +
+ +
+ +
+ +
- - +
+
+ ); + } + return ( +
+ +
+ + + +
+ + + TOP SECRET + + + + CLASSIFIED + +
+ +
+ + + +
+ + CLASSIFIED + +
+
+ + + + CLEARANCE LEVEL: TOP SECRET + + +
+ + +
+

+ +

+

+ +

+
+ +
+
+

+ + Available Resources: +

+
    + {[ + "► Cognitive Psychology Division (Dr. Sarah Chen)", + "► Social Media Analytics Team (Prof. Morrison)", + "► Reality Distortion Lab (Dr. Webb)", + "► Network of Influential Mathematics Professors", + "► Quantum Uncertainty Specialists" + ].map((resource, i) => ( +
  • + {resource} +
  • + ))} +
+
+ +
+

+ + Primary Objectives: +

+
    + {[ + "01. Gradually introduce doubt into basic arithmetic", + "02. Deploy sophisticated mathematical proofs with intentional errors", + "03. Establish alternative mathematical frameworks", + "04. Influence key educational institutions" + ].map((objective, i) => ( +
  1. + {objective} +
  2. + ))} +
+
+
+ +
+

+ "Reality is malleable, truth is negotiable, and mathematics is our playground." +

+ +
+ +

+ This message will self-destruct when closed... +

+
+
+
+
+
); } @@ -98,62 +920,148 @@ const Index = () => { if (!currentStageData) { return ( -
- - - Simulation Complete - - -

- You've completed the simulation. Through this experience, you've learned how - disinformation campaigns operate and how to better recognize them in the real world. -

- -
-
+
+ +
+ + + + Simulation Complete + + +

+ You've completed the simulation. Through this experience, you've learned how + disinformation campaigns operate and how to better recognize them in the real world. +

+ +
+
+
+
+ ); + } + + if (showingResult && currentResult) { + return ( +
+ +
+ +
+ + +
+ {currentResult.title} + + {currentResult.description} + +
+
+ +
+

Key Insights Gathered:

+
    + {currentResult.insights.map((insight, index) => ( +
  • + + {insight} +
  • + ))} +
+
+ +
+

+ Strategic Insight: + {currentResult.nextStepHint} +

+
+ +
+ +
+
+
+
+
+
+ ); + } + + if (showingMonthTransition && nextStage !== null && stages[nextStage]) { + return ( +
+ +
+ +
+ +
+
); } return ( -
-
- - - {currentStageData.title} - - {currentStageData.description} - - - - {currentStageData.choices.map((choice) => ( - handleChoice(choice.id)} - > - - {choice.text} - - {choice.description} - - - -

Impact: {choice.impact}

-
-
- ))} -
-
+
+ +
+ +
+ + +
+ + {currentStageData.title} + + {currentStageData.description} + +
+
+ + {currentStageData.choices.map((choice) => ( + handleChoice(choice)} + > + + {choice.text} + + {choice.description} + + + +

Impact: {choice.impact}

+
+
+ ))} +
+
+
+ {isLoading && }
); }; diff --git a/src/utils/audio.ts b/src/utils/audio.ts new file mode 100644 index 0000000..b64eb3c --- /dev/null +++ b/src/utils/audio.ts @@ -0,0 +1,37 @@ +const CLICK_SOUNDS = [ + "/audio/click1.mp3", + "/audio/click2.mp3" +]; + +class AudioPlayer { + private static instance: AudioPlayer; + private audioElements: { [key: string]: HTMLAudioElement } = {}; + + private constructor() { + // Pre-load click sounds + CLICK_SOUNDS.forEach((sound, index) => { + const audio = new Audio(sound); + audio.volume = 0.3; // Lower volume for UI sounds + this.audioElements[`click${index + 1}`] = audio; + }); + } + + public static getInstance(): AudioPlayer { + if (!AudioPlayer.instance) { + AudioPlayer.instance = new AudioPlayer(); + } + return AudioPlayer.instance; + } + + public playClickSound() { + const randomIndex = Math.floor(Math.random() * CLICK_SOUNDS.length); + const sound = this.audioElements[`click${randomIndex + 1}`]; + if (sound) { + // Create a clone to allow overlapping sounds + const clone = sound.cloneNode() as HTMLAudioElement; + clone.play(); + } + } +} + +export const playClickSound = () => AudioPlayer.getInstance().playClickSound(); \ No newline at end of file diff --git a/tailwind.config.ts b/tailwind.config.ts index 7f674fe..3015e82 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -44,12 +44,87 @@ export default { opacity: '1', transform: 'translateY(0)' } - } + }, + float: { + "0%, 100%": { transform: "translateY(0) translateX(0)" }, + "25%": { transform: "translateY(-20px) translateX(10px)" }, + "50%": { transform: "translateY(-35px) translateX(-10px)" }, + "75%": { transform: "translateY(-20px) translateX(8px)" }, + }, + 'month-transition': { + '0%': { + opacity: '0', + transform: 'scale(0.9)' + }, + '20%': { + opacity: '1', + transform: 'scale(1)' + }, + '80%': { + opacity: '1', + transform: 'scale(1)' + }, + '100%': { + opacity: '0', + transform: 'scale(1.1)' + } + }, + 'typewriter': { + 'from': { width: '0' }, + 'to': { width: '100%' } + }, + 'blink': { + '50%': { borderColor: 'transparent' } + }, + 'slide-in-left': { + '0%': { transform: 'translateX(-100%)' }, + '100%': { transform: 'translateX(0)' } + }, + 'slide-in-right': { + '0%': { transform: 'translateX(100%)' }, + '100%': { transform: 'translateX(0)' } + }, + 'digital-rain': { + '0%': { transform: 'translateY(-100%)', opacity: '0' }, + '50%': { opacity: '1' }, + '100%': { transform: 'translateY(100%)', opacity: '0' } + }, + 'text-glitch': { + '0%': { transform: 'translate(0)' }, + '20%': { transform: 'translate(-2px, 2px)' }, + '40%': { transform: 'translate(2px, -2px)' }, + '60%': { transform: 'translate(-2px, -2px)' }, + '80%': { transform: 'translate(2px, 2px)' }, + '100%': { transform: 'translate(0)' } + }, + 'number-cycle': { + '0%': { transform: 'translateY(100%)', opacity: '0' }, + '20%': { transform: 'translateY(0)', opacity: '1' }, + '80%': { transform: 'translateY(0)', opacity: '1' }, + '100%': { transform: 'translateY(-100%)', opacity: '0' } + }, + 'transition-container': { + '0%': { opacity: '0' }, + '33%': { opacity: '1' }, + '66%': { opacity: '1' }, + '100%': { opacity: '0' } + }, }, animation: { 'accordion-down': 'accordion-down 0.2s ease-out', 'accordion-up': 'accordion-up 0.2s ease-out', - 'fade-in': 'fade-in 1s ease-out' + 'fade-in': 'fade-in 1s ease-out', + 'float': 'float 20s ease-in-out infinite', + 'pulse-slow': 'pulse 4s ease-in-out infinite', + 'month-transition': 'month-transition 3s ease-in-out forwards', + 'typewriter': 'typewriter 2s steps(20) forwards', + 'cursor-blink': 'blink 1s infinite', + 'slide-left': 'slide-in-left 1.5s ease-out', + 'slide-right': 'slide-in-right 1.5s ease-out', + 'rain': 'digital-rain 2s linear infinite', + 'glitch': 'text-glitch 0.5s ease infinite', + 'cycle': 'number-cycle 0.5s ease-in-out', + 'transition-container': 'transition-container 3s ease-in-out forwards', }, colors: { border: 'hsl(var(--border))', @@ -100,7 +175,10 @@ export default { lg: 'var(--radius)', md: 'calc(var(--radius) - 2px)', sm: 'calc(var(--radius) - 4px)' - } + }, + backgroundImage: { + 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))', + }, } }, plugins: [require("tailwindcss-animate")], diff --git a/vite.config.ts b/vite.config.ts index 25c5589..acadeaa 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -6,8 +6,12 @@ import { componentTagger } from "lovable-tagger"; // https://vitejs.dev/config/ export default defineConfig(({ mode }) => ({ server: { - host: "::", - port: 8080, + port: 3000, + host: true + }, + preview: { + port: 3000, + host: true }, plugins: [ react(),