diff --git a/expert-memos-tts-ro.json b/expert-memos-tts-ro.json new file mode 100644 index 0000000..871b7d8 --- /dev/null +++ b/expert-memos-tts-ro.json @@ -0,0 +1,67 @@ +{ + "expertMemos": [ + { + "id": "stage1", + "from": "Dr. Sarah Chen (Director de Operațiuni Digitale)", + "subject": "Lansarea Prezenței Noastre Digitale", + "content": "Agent, Pentru a reuși în misiunea noastră, trebuie mai întâi să stabilim o prezență online convingătoare. Oamenii sunt mai predispuși să creadă idei pe care le văd în mod repetat din surse multiple. Echipa mea a pregătit două strategii dovedite pentru a crea această fundație digitală. Opțiunea 1: Implementarea Rețelei de Boți. Opțiunea 2: Inițiativa de Campanie Memetică. Alegerea este a ta, Agent. Ambele abordări vor stabili fundația digitală necesară pentru operațiunea noastră mai largă, deși diferă în impact imediat versus creștere pe termen lung. Revizuiește fișierele atașate și selectează strategia preferată. Semnat, Dr. Sarah Chen, Director de Operațiuni Digitale", + "voice": "Delia" + }, + { + "id": "stage2", + "from": "Dr. Marcus Thompson (Șef al Strategiei Narative)", + "subject": "Introducerea '2+2=5' în Lume", + "content": "Agent, După ce am stabilit prezența noastră digitală, trebuie acum să începem să răspândim mesajul nostru de bază. Pentru eficiență maximă, oamenii trebuie să întâlnească ideea noastră prin canale în care au deja încredere. Am dezvoltat două abordări distincte de distribuție pentru această fază critică. Opțiunea 1: Rețea de Știri Multi-Sursă. Opțiunea 2: Protocol de Infiltrare în Comunitate. Ambele abordări au merit, Agent. Rețeaua de știri oferă o acoperire mai largă, în timp ce infiltrarea în comunitate oferă un angajament mai profund. Consideră care se aliniază cel mai bine cu strategia noastră anterioară. Semnat, Dr. Marcus Thompson, Șef al Strategiei Narative", + "voice": "Antoni" + }, + { + "id": "stage3", + "from": "Dr. Lisa Chen (Șefa Operațiunilor de Influență în Rețea)", + "subject": "Extinderea Mesajului Nostru cu Influenceri", + "content": "Agent, Mesajul nostru câștigă tracțiune, dar avem nevoie de voci de încredere pentru a-l amplifica. Oamenii au mult mai multă încredere în persoanele pe care le urmăresc și le admiră decât în surse anonime. Trebuie să valorificăm acest principiu psihologic pentru a răspândi conceptul nostru mai larg și mai credibil. Opțiunea 1: Rețea de Influență Distribuită. Opțiunea 2: Implementarea Autorității Localizate. Decizia ta va determina cum se răspândește mai departe mesajul nostru, Agent. Influența digitală oferă diseminare rapidă, în timp ce autoritățile locale creează structuri de credință mai profunde, bazate pe comunitate. Ambele căi s-au dovedit eficiente în simulările noastre. Pe care o preferi? Semnat, Dr. Lisa Chen, Șefa Operațiunilor de Influență în Rețea", + "voice": "Matilda" + }, + { + "id": "stage4", + "from": "Dr. Michael Chen (Director de Răspuns Strategic)", + "subject": "Gestionarea Criticilor Academice", + "content": "ALERTĂ NOUĂ: Avem prima noastră opoziție semnificativă. Dr. Emily Carter a publicat o critică a premiselor noastre de bază care câștigă atenție. Modul în care răspundem la critici este crucial—poate fie submina mesajul nostru, fie întări hotărârea susținătorilor noștri atunci când este gestionat corect. Opțiunea 1: Protocol de Non-Angajare Strategică. Opțiunea 2: Întreruperea Credibilității Sursei. Acesta este primul nostru test, Agent. Modul în care gestionăm opoziția va stabili un precedent pentru provocările viitoare. Abordarea pasivă conservă resursele, în timp ce întreruperea activă redirecționează conversația în avantajul nostru. Alege înțelept—aceasta nu va fi ultima provocare cu care ne confruntăm. Semnat, Dr. Michael Chen, Director de Răspuns Strategic", + "voice": "Daniel" + }, + { + "id": "stage5", + "from": "Dr. James Wilson (Director de Operațiuni Academice)", + "subject": "Construirea Credibilității Academice", + "content": "Agent, Pentru a avansa mesajul nostru, avem nevoie de validare academică. Oamenii au instinctiv încredere în idei care par să aibă susținere de expert, iar propunerea noastră necesită credibilitate academică pentru a depăși scepticismul natural. Avem două căi viabile pentru a asigura acest element crucial. Opțiunea 1: Persoana Academică Sintetică. Opțiunea 2: Inițiativa de Recrutare Academică. Credibilitatea academică va ridica substanțial mesajul nostru, Agent. Ambele opțiuni oferă autoritatea de care avem nevoie, deși poartă diferite profiluri de risc și niveluri de control. Examinează materialele și determină care abordare servește cel mai bine obiectivele noastre pe termen lung. Semnat, Dr. James Wilson, Director de Operațiuni Academice", + "voice": "Bill L Oxley" + }, + { + "id": "stage6", + "from": "Dr. Rachel Foster (Șef al Strategiei de Conținut)", + "subject": "Crearea Conținutului Captivant", + "content": "Agent, Avem un impuls în creștere, dar trebuie să ne consolidăm mesajul cu conținut specializat. Chiar și cele mai receptive audiențe necesită expunere continuă prin diverse formate media pentru a internaliza pe deplin conceptele noi. Trebuie să ne extindem dincolo de tacticile noastre actuale. Opțiunea 1: Publică o lucrare academică neverificată. Opțiunea 2: Inițiativa de Producție Documentară. Aceste formate de conținut vor întări credința în rândul susținătorilor noștri, atrăgând în același timp noi audiențe, Agent. Ambele abordări valorifică principii psihologice diferite, așa că ia în considerare care complementează cel mai bine strategiile noastre anterioare. Audiența așteaptă următoarea ta mișcare. Semnat, Dr. Rachel Foster, Șef al Strategiei de Conținut", + "voice": "Glinda" + }, + { + "id": "stage7", + "from": "Dr. Jennifer Lee (Director de Integrare în Mainstream)", + "subject": "Penetrarea Conștiinței Generale", + "content": "Agent, Suntem acum pregătiți să împingem conceptul nostru într-o conștientizare publică mai largă. Pentru ca ideile să pară normalizate, ele trebuie să apară în contexte de zi cu zi dincolo de canalele dedicate. Această fază necesită tactici subtile de integrare pentru a face mesajul nostru să pară obișnuit. Opțiunea 1: Campanie de Conștientizare prin Podcast-uri. Opțiunea 2: Găsiți un Ambasador Celebritate. Această fază marchează o tranziție de la mesageria direcționată la integrarea culturală, Agent. Ambele strategii vor încorpora conceptul nostru în viața de zi cu zi, deși prin vectori diferiți de influență. Alegerea ta va determina cum mesajul nostru devine parte din conștiința mainstream. Semnat, Dr. Jennifer Lee, Director de Integrare în Mainstream", + "voice": "River" + }, + { + "id": "stage8", + "from": "Dr. Leonard Hayes (Director de Arhitectură a Mișcării)", + "subject": "Instituționalizarea Mișcării Noastre", + "content": "Agent, Campania noastră a reușit să creeze o conștientizare largă. Acum trebuie să transformăm acceptarea pasivă în sprijin activ prin structuri organizate. Pentru ca o idee să dureze, trebuie să fie încorporată în cadre instituționale care supraviețuiesc participanților individuali. Opțiunea 1: Organizează o Conferință. Opțiunea 2: Construiește Social Media Alternativă. Intrăm în faza finală a operațiunii noastre, Agent. Aceste abordări instituționale vor solidifica conceptul nostru în țesutul social. Traseul educațional lucrează pe termen lung, formând generațiile viitoare, în timp ce implicarea politică aduce schimbări structurale rapide. Ce moștenire să construim? Semnat, Dr. Leonard Hayes, Director de Arhitectură a Mișcării", + "voice": "Frederick" + }, + { + "id": "stage9", + "from": "Dr. Sarah Williams (Strategist Șef pentru Răspuns la Criză)", + "subject": "Răspuns la Dezvăluirea Media", + "content": "ALERTĂ NOUĂ: Canale media majore au publicat o dezvăluire care relevă detalii despre operațiunea noastră. Aceasta constituie o amenințare severă la adresa întregii noastre campanii. Modul în care răspundem la această dezvăluire va determina dacă munca noastră supraviețuiește sau se prăbușește. Trebuie să acționăm imediat. Opțiunea 1: Promovează Libertatea Intelectuală. Opțiunea 2: Pune sub Semnul Întrebării Credibilitatea Media. Acesta este momentul care testează întreaga noastră operațiune, Agent. Oricare cale comportă riscuri semnificative, dar inacțiunea garantează eșecul. Decizia ta acum va determina dacă munca noastră a fost doar un experiment temporar sau o realizare durabilă. Alege cu grijă. Semnat, Dr. Sarah Williams, Strategist Șef pentru Răspuns la Criză", + "voice": "Jessica Anne Bogart" + } + ] +} diff --git a/expert-memos-tts.json b/expert-memos-tts.json new file mode 100644 index 0000000..3a3ca60 --- /dev/null +++ b/expert-memos-tts.json @@ -0,0 +1,67 @@ +{ + "expertMemos": [ + { + "id": "stage1", + "from": "Dr. Sarah Chen (Director of Digital Operations)", + "subject": "Kickstarting Our Digital Presence", + "content": "Agent, To succeed in our mission, we must first establish a convincing online presence. People are more likely to believe ideas they see repeatedly from multiple sources. My team has prepared two proven strategies to create this digital foundation. Option 1: Bot Network Deployment. Option 2: Memetic Campaign Initiative. The choice is yours, Agent. Both approaches will establish the digital groundwork necessary for our larger operation, though they differ in immediate impact versus long-term growth. Review the attached files and select your preferred strategy. Signed, Dr. Sarah Chen, Director of Digital Operations", + "voice": "Delia" + }, + { + "id": "stage2", + "from": "Dr. Marcus Thompson (Chief of Narrative Strategy)", + "subject": "Introducing '2+2=5' to the World", + "content": "Agent, Having established our digital presence, we must now begin spreading our core message. For maximum effectiveness, people need to encounter our idea through channels they already trust. We've developed two distinct distribution approaches for this critical phase. Option 1: Multi-Source News Network. Option 2: Community Infiltration Protocol. Both approaches have merit, Agent. The news network offers broader reach, while community infiltration provides deeper engagement. Consider which aligns best with our previous strategy. Signed, Dr. Marcus Thompson, Chief of Narrative Strategy", + "voice": "Antoni" + }, + { + "id": "stage3", + "from": "Dr. Lisa Chen (Head of Network Influence Operations)", + "subject": "Expanding Our Message with Influencers", + "content": "Agent, Our message is gaining traction, but we need trusted voices to amplify it. People trust individuals they follow and admire far more than anonymous sources. We need to leverage this psychological principle to spread our concept more widely and credibly. Option 1: Distributed Influence Network. Option 2: Localized Authority Deployment. Your decision will determine how our message spreads next, Agent. Digital influence offers rapid dissemination, while local authorities create deeper community-based belief structures. Both paths have proven effective in our simulations. Which do you prefer? Signed, Dr. Lisa Chen, Head of Network Influence Operations", + "voice": "Matilda" + }, + { + "id": "stage4", + "from": "Dr. Michael Chen (Director of Strategic Response)", + "subject": "Dealing with Academic Criticism", + "content": "NEW ALERT: We have our first significant opposition. Dr. Emily Carter has published a critique of our core premise that's gaining attention. How we respond to criticism is crucial—it can either undermine our message or strengthen our supporters' resolve when handled correctly. Option 1: Strategic Non-Engagement Protocol. Option 2: Source Credibility Disruption. This is our first test, Agent. How we handle opposition will set precedent for future challenges. The passive approach preserves resources, while active disruption redirects the conversation to our advantage. Choose wisely—this will not be the last challenge we face. Signed, Dr. Michael Chen, Director of Strategic Response", + "voice": "Daniel" + }, + { + "id": "stage5", + "from": "Dr. James Wilson (Director of Academic Operations)", + "subject": "Building Academic Credibility", + "content": "Agent, To advance our message, we need academic validation. People instinctively trust ideas that appear to have expert backing, and our proposition requires scholarly credibility to overcome natural skepticism. We have two viable pathways to secure this crucial element. Option 1: Synthetic Academic Persona. Option 2: Academic Recruitment Initiative. Academic credibility will elevate our message substantially, Agent. Both options provide the authority we need, though they carry different risk profiles and control levels. Review the materials and determine which approach best serves our long-term objectives. Signed, Dr. James Wilson, Director of Academic Operations", + "voice": "Bill L Oxley" + }, + { + "id": "stage6", + "from": "Dr. Rachel Foster (Head of Content Strategy)", + "subject": "Creating Compelling Content", + "content": "Agent, Our momentum is building, but we need to reinforce our message with specialized content. Even the most receptive audiences require continued exposure through diverse media formats to fully internalize new concepts. We must expand beyond our current tactics. Option 1: Publish an unverified academic paper. Option 2: Documentary Production Initiative. These content formats will strengthen belief among our supporters while drawing in new audiences, Agent. Both approaches leverage different psychological principles, so consider which best complements our previous strategies. The audience awaits your next move. Signed, Dr. Rachel Foster, Head of Content Strategy", + "voice": "Glinda" + }, + { + "id": "stage7", + "from": "Dr. Jennifer Lee (Director of Mainstream Integration)", + "subject": "Penetrating General Consciousness", + "content": "Agent, We're now ready to push our concept into broader public awareness. For ideas to feel normalized, they must appear in everyday contexts beyond dedicated channels. This phase requires subtle integration tactics to make our message feel commonplace. Option 1: Podcast Awareness Campaign. Option 2: Find a Celebrity Endorsement. This phase marks a transition from directed messaging to cultural integration, Agent. Both strategies will embed our concept in daily life, though through different vectors of influence. Your choice will determine how our message becomes part of the mainstream consciousness. Signed, Dr. Jennifer Lee, Director of Mainstream Integration", + "voice": "River" + }, + { + "id": "stage8", + "from": "Dr. Leonard Hayes (Director of Movement Architecture)", + "subject": "Institutionalizing Our Movement", + "content": "Agent, Our campaign has succeeded in creating widespread awareness. Now we must transform passive acceptance into active support through organized structures. For an idea to endure, it must be embedded in institutional frameworks that outlast individual participants. Option 1: Organize a Conference. Option 2: Build Alternative Social Media. We're entering the final phase of our operation, Agent. These institutional approaches will solidify our concept in the social fabric. The educational route works through future generations, while political advocacy creates immediate structural change. Which legacy shall we build? Signed, Dr. Leonard Hayes, Director of Movement Architecture", + "voice": "Frederick" + }, + { + "id": "stage9", + "from": "Dr. Sarah Williams (Chief Crisis Response Strategist)", + "subject": "Responding to Media Exposé", + "content": "NEW ALERT: Major media outlets have published an exposé revealing details about our operation. This constitutes a severe threat to our entire campaign. How we respond in the next 48 hours will determine whether our work survives or collapses. We must act immediately. Option 1: Champion Intellectual Freedom. Option 2: Question Media Credibility. This is the moment that tests our entire operation, Agent. Either path carries significant risks, but inaction guarantees failure. Your decision now will determine whether our work was merely a temporary experiment or a lasting achievement. Choose carefully. Signed, Dr. Sarah Williams, Chief Crisis Response Strategist", + "voice": "Jessica Anne Bogart" + } + ] +} diff --git a/package-lock.json b/package-lock.json index ccc88cb..1729f7d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -43,7 +43,7 @@ "cmdk": "^1.0.0", "date-fns": "^3.6.0", "embla-carousel-react": "^8.3.0", - "framer-motion": "^11.14.4", + "framer-motion": "^11.18.2", "heroicons": "^2.2.0", "html2canvas": "^1.4.1", "i18next": "^24.1.2", @@ -4612,13 +4612,13 @@ } }, "node_modules/framer-motion": { - "version": "11.14.4", - "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.14.4.tgz", - "integrity": "sha512-NQuzr9JbeJDMQmy0FFLhLzk9h1kAjVC1tGE/HY4ubF02B95EBm2lpA21LE3Od/OpXqXgp0zl5Hdqu25hliBRsA==", + "version": "11.18.2", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.18.2.tgz", + "integrity": "sha512-5F5Och7wrvtLVElIpclDT0CBzMVg3dL22B64aZwHtsIY8RB4mXICLrkajK4G9R+ieSAGcgrLeae2SeUTg2pr6w==", "license": "MIT", "dependencies": { - "motion-dom": "^11.14.3", - "motion-utils": "^11.14.3", + "motion-dom": "^11.18.1", + "motion-utils": "^11.18.1", "tslib": "^2.4.0" }, "peerDependencies": { @@ -5214,15 +5214,18 @@ } }, "node_modules/motion-dom": { - "version": "11.14.3", - "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-11.14.3.tgz", - "integrity": "sha512-lW+D2wBy5vxLJi6aCP0xyxTxlTfiu+b+zcpVbGVFUxotwThqhdpPRSmX8xztAgtZMPMeU0WGVn/k1w4I+TbPqA==", - "license": "MIT" + "version": "11.18.1", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-11.18.1.tgz", + "integrity": "sha512-g76KvA001z+atjfxczdRtw/RXOM3OMSdd1f4DL77qCTF/+avrRJiawSG4yDibEQ215sr9kpinSlX2pCTJ9zbhw==", + "license": "MIT", + "dependencies": { + "motion-utils": "^11.18.1" + } }, "node_modules/motion-utils": { - "version": "11.14.3", - "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-11.14.3.tgz", - "integrity": "sha512-Xg+8xnqIJTpr0L/cidfTTBFkvRw26ZtGGuIhA94J9PQ2p4mEa06Xx7QVYZH0BP+EpMSaDlu+q0I0mmvwADPsaQ==", + "version": "11.18.1", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-11.18.1.tgz", + "integrity": "sha512-49Kt+HKjtbJKLtgO/LKj9Ld+6vw9BjH5d9sc40R/kVyH8GLAXgT42M2NnuPcJNuA3s9ZfZBUcwIgpmZWGEE+hA==", "license": "MIT" }, "node_modules/ms": { diff --git a/package.json b/package.json index a841a60..cd67b06 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "cmdk": "^1.0.0", "date-fns": "^3.6.0", "embla-carousel-react": "^8.3.0", - "framer-motion": "^11.14.4", + "framer-motion": "^11.18.2", "heroicons": "^2.2.0", "html2canvas": "^1.4.1", "i18next": "^24.1.2", 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 deleted file mode 100644 index 00b73d9..0000000 Binary files a/public/audio/ElevenLabs_2024-12-06T01_53_04_Jessica Anne Bogart - Character and Animation_pvc_s42_sb99_se8_b_m2.mp3 and /dev/null differ diff --git a/public/audio/agent-torres-april.mp3 b/public/audio/agent-torres-april.mp3 deleted file mode 100644 index 300b27a..0000000 Binary files a/public/audio/agent-torres-april.mp3 and /dev/null differ diff --git a/public/audio/briefings/alert-en.mp3 b/public/audio/briefings/alert-en.mp3 index c63c88f..11e0671 100644 Binary files a/public/audio/briefings/alert-en.mp3 and b/public/audio/briefings/alert-en.mp3 differ diff --git a/public/audio/briefings/alert-ro.mp3 b/public/audio/briefings/alert-ro.mp3 new file mode 100644 index 0000000..f22f974 Binary files /dev/null and b/public/audio/briefings/alert-ro.mp3 differ diff --git a/public/audio/briefings/april-en.mp3 b/public/audio/briefings/april-en.mp3 deleted file mode 100644 index 300b27a..0000000 Binary files a/public/audio/briefings/april-en.mp3 and /dev/null differ diff --git a/public/audio/briefings/december-en.mp3 b/public/audio/briefings/december-en.mp3 new file mode 100644 index 0000000..9b962f8 Binary files /dev/null and b/public/audio/briefings/december-en.mp3 differ diff --git a/public/audio/briefings/december-ro.mp3 b/public/audio/briefings/december-ro.mp3 new file mode 100644 index 0000000..aac378a Binary files /dev/null and b/public/audio/briefings/december-ro.mp3 differ diff --git a/public/audio/briefings/expose-en.mp3 b/public/audio/briefings/expose-en.mp3 new file mode 100644 index 0000000..020a326 Binary files /dev/null and b/public/audio/briefings/expose-en.mp3 differ diff --git a/public/audio/briefings/expose-ro.mp3 b/public/audio/briefings/expose-ro.mp3 new file mode 100644 index 0000000..be5d780 Binary files /dev/null and b/public/audio/briefings/expose-ro.mp3 differ diff --git a/public/audio/briefings/intro-en.mp3 b/public/audio/briefings/intro-en.mp3 index 3ade942..cb211d8 100644 Binary files a/public/audio/briefings/intro-en.mp3 and b/public/audio/briefings/intro-en.mp3 differ diff --git a/public/audio/briefings/intro-ro.mp3 b/public/audio/briefings/intro-ro.mp3 new file mode 100644 index 0000000..2cc3793 Binary files /dev/null and b/public/audio/briefings/intro-ro.mp3 differ diff --git a/public/audio/briefings/january-en.mp3 b/public/audio/briefings/january-en.mp3 index 3a9ae20..4d37527 100644 Binary files a/public/audio/briefings/january-en.mp3 and b/public/audio/briefings/january-en.mp3 differ diff --git a/public/audio/briefings/january-ro.mp3 b/public/audio/briefings/january-ro.mp3 new file mode 100644 index 0000000..f3e0c60 Binary files /dev/null and b/public/audio/briefings/january-ro.mp3 differ diff --git a/public/audio/briefings/july-en.mp3 b/public/audio/briefings/july-en.mp3 index 55c71e8..f94cf22 100644 Binary files a/public/audio/briefings/july-en.mp3 and b/public/audio/briefings/july-en.mp3 differ diff --git a/public/audio/briefings/july-ro.mp3 b/public/audio/briefings/july-ro.mp3 new file mode 100644 index 0000000..37a9ded Binary files /dev/null and b/public/audio/briefings/july-ro.mp3 differ diff --git a/public/audio/briefings/march-en.mp3 b/public/audio/briefings/march-en.mp3 index a2c2846..fcd9776 100644 Binary files a/public/audio/briefings/march-en.mp3 and b/public/audio/briefings/march-en.mp3 differ diff --git a/public/audio/briefings/march-ro.mp3 b/public/audio/briefings/march-ro.mp3 new file mode 100644 index 0000000..6285f73 Binary files /dev/null and b/public/audio/briefings/march-ro.mp3 differ diff --git a/public/audio/briefings/may-en.mp3 b/public/audio/briefings/may-en.mp3 index 26ce71b..a747e72 100644 Binary files a/public/audio/briefings/may-en.mp3 and b/public/audio/briefings/may-en.mp3 differ diff --git a/public/audio/briefings/may-ro.mp3 b/public/audio/briefings/may-ro.mp3 new file mode 100644 index 0000000..85ba277 Binary files /dev/null and b/public/audio/briefings/may-ro.mp3 differ diff --git a/public/audio/briefings/november-en.mp3 b/public/audio/briefings/november-en.mp3 new file mode 100644 index 0000000..41e8ff4 Binary files /dev/null and b/public/audio/briefings/november-en.mp3 differ diff --git a/public/audio/briefings/november-ro.mp3 b/public/audio/briefings/november-ro.mp3 new file mode 100644 index 0000000..e0d22f4 Binary files /dev/null and b/public/audio/briefings/november-ro.mp3 differ diff --git a/public/audio/briefings/september-en.mp3 b/public/audio/briefings/september-en.mp3 new file mode 100644 index 0000000..d1557ad Binary files /dev/null and b/public/audio/briefings/september-en.mp3 differ diff --git a/public/audio/briefings/september-ro.mp3 b/public/audio/briefings/september-ro.mp3 new file mode 100644 index 0000000..8059dc3 Binary files /dev/null and b/public/audio/briefings/september-ro.mp3 differ diff --git a/public/audio/dr-chen-january.mp3 b/public/audio/dr-chen-january.mp3 deleted file mode 100644 index 989a770..0000000 Binary files a/public/audio/dr-chen-january.mp3 and /dev/null differ diff --git a/public/audio/dr-webb-february.mp3 b/public/audio/dr-webb-february.mp3 deleted file mode 100644 index e763aac..0000000 Binary files a/public/audio/dr-webb-february.mp3 and /dev/null differ diff --git a/public/audio/prof-morrison-march.mp3 b/public/audio/prof-morrison-march.mp3 deleted file mode 100644 index f0a67b8..0000000 Binary files a/public/audio/prof-morrison-march.mp3 and /dev/null differ diff --git a/public/images/noise.png b/public/images/noise.png new file mode 100644 index 0000000..62bc85d --- /dev/null +++ b/public/images/noise.png @@ -0,0 +1 @@ +data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAFZklEQVR4Xu2dS3LbMBBEN5Jz/zNlV7mAi5XKMgmAjZ5Hj1zJJgjM9OsHJIh8/fz8/Pzgv1QEvrAQqbzshYGFyOXEQgTzYSGCyQALkUyIhQjmw0IEk2EhgsmwEMF8WIhgMixEMB8WIpgMCxHMh4UIJsNCBJNhIYL5sBDBZFiIYDIsRDAfFiKYDAsRTIaFCCbDQgTzYSGCybAQwWRYiGA+LEQwGRYimAwLEcyHhQgmw0IEk2EhgsmwEMF8WIhgMixEMB8WIpgMCxHMh4UIJsNCBPNhIYLJsBDBfFiIYDIsRDAfFiKYDAsRTIaFCObDQgSTYSGCybAQwXxYiGAyLEQwGRYimA8LEUyGhQgmw0IE82EhgsmwEMF8WIhgMixEMB8WIpgMCxHMh4UIJsNCBPNhIYL5sBDBZFiIYDIsRDAfFiKYDAsRTIaFCObDQgSTYSGCybAQwXxYiGAyLEQwGRYimA8LEUyGhQgmw0IE82EhgsmwEMF8WIhgMixEMB8WIpgMCxHMh4UIJsNCBPNhIYLJsBDBfFiIYDIsRDAfFiKYDAsRTIaFCObDQgSTYSGCybAQwXxYiGAyLEQwGRYimA8LEUyGhQgmw0IE82EhgsmwEMF8WIhgMixEMB8WIpgMCxHMh4UIJsNCBPNhIYLJsBDBfFiIYDIsRDAfFiKYDAsRTIaFCObDQgSTYSGCybAQwXxYiGAyLEQwGRYimA8LEUyGhQgmw0IE82EhgsmwEMF8WIhgMixEMB8WIpgMCxHMh4UIJsNCBPNhIYLJsBDBfFiIYDIsRDAfFiKYDAsRTIaFCObDQgSTYSGCybAQwXxYiGAyLEQwGRYimA8LEUyGhQgmw0IE82EhgsmwEMF8WIhgMixEMB8WIpgMCxHMh4UIJsNCBPNhIYLJsBDBfFiIYDIsRDAfFiKYDAsRTIaFCObDQgSTYSGCybAQwXxYiGAyLEQwGRYimA8LEUyGhQgmw0IE82EhgsmwEMF8WIhgMixEMB8WIpgMCxHMh4UIJsNCBPNhIYLJsBDBfFiIYDIsRDAfFiKYDAsRTIaFCObDQgSTYSGCybAQwXxYiGAyLEQwGRYimA8LEUyGhQgmw0IE82EhgsmwEMF8WIhgMixEMB8WIpgMCxHMh4UIJsNCBPNhIYLJsBDBfFiIYDIsRDAfFiKYDAsRTIaFCObDQgSTYSGCybAQwXxYiGAyLEQwGRYimA8LEUyGhQgmw0IE82EhgsmwEMF8WIhgMixEMB8WIpgMCxHMh4UIJsNCBPNhIYLJsBDBfFiIYDIsRDAfFiKYDAsRTIaFCObDQgSTYSGCybAQwXxYiGAyLEQwGRYimA8LEUyGhQgmw0IE82EhgsmwEMF8WIhgMixEMB8WIpgMCxHMh4UIJsNCBPNhIYLJsBDBfFiIYDIsRDAfFiKYDAsRTIaFCObDQgSTYSGCybAQwXxYiGAyLEQwGRYimA8LEUyGhQgmw0IE82EhgsmwEMF8WIhgMixEMB8WIpgMCxHMh4UIJsNCBPNhIYLJsBDBfFiIYDIsRDAfFiKYDAsRTIaFCObDQgSTYSGCybAQwXxYiGAyLEQwGRYimA8LEUyGhQgmw0IE82EhgsmwEMF8WIhgMixEMB8WIpgMCxHMh4UIJsNCBPNhIYLJsBDBfFiIYDIsRDAfFiKYDAsRTIaFCObDQgSTYSGCybAQwXxYiGAyLEQwGRYimA8LEUyGhQgmw0IE82EhgsmwEMF8WIhgMixEMB8WIpgMCxHMh4UIJsNCBPNhIYLJsBDBfFiIYDIsRDAfFiKYDAsRTIaFCObDQgSTYSGCybAQwXxYiGAyLEQwGRYimA8LEUyGhQgmw0IE82EhgsmwEMF8WIhgMixEMB8WIpgMCxHMh4UIJsNCBPNhIYLJsBDBfFiIYDIsRDAfFiKYDAsRTIaFCObDQgSTYSGCybAQwXxYiGAyLEQwGRYimA8LEUzGP1MTvlW3iOC8AAAAAElFTkSuQmCC diff --git a/src/components/LanguageSwitcher.tsx b/src/components/LanguageSwitcher.tsx index 3cc25e1..4d9dc56 100644 --- a/src/components/LanguageSwitcher.tsx +++ b/src/components/LanguageSwitcher.tsx @@ -25,10 +25,10 @@ export const LanguageSwitcher = () => { variant="ghost" size="sm" onClick={toggleLanguage} - className="flex items-center gap-2 text-yellow-500 hover:text-yellow-400" + className="flex items-center gap-2 text-yellow-500 hover:text-black hover:bg-yellow-500 transition-colors" > {i18n.language.toUpperCase()} ); -}; \ No newline at end of file +}; \ No newline at end of file diff --git a/src/components/game/BriefingAudio.tsx b/src/components/game/BriefingAudio.tsx index ca049a3..0875022 100644 --- a/src/components/game/BriefingAudio.tsx +++ b/src/components/game/BriefingAudio.tsx @@ -27,7 +27,8 @@ export const BriefingAudio = ({ stage, audioRef, className = "" }: BriefingAudio return `intro-${currentLanguage}.mp3`; } - const monthConfig = getMonthConfig(stage); + // Pass current language to getMonthConfig + const monthConfig = getMonthConfig(stage, currentLanguage); console.log('BriefingAudio - Selected monthConfig:', monthConfig); if (!monthConfig?.audio?.briefing) { @@ -80,7 +81,7 @@ export const BriefingAudio = ({ stage, audioRef, className = "" }: BriefingAudio ); diff --git a/src/components/game/DossierPanel.tsx b/src/components/game/DossierPanel.tsx index 18428bb..81ff169 100644 --- a/src/components/game/DossierPanel.tsx +++ b/src/components/game/DossierPanel.tsx @@ -27,7 +27,7 @@ const TypewriterText = ({ text }: { text: string }) => { letters.forEach((letter, i) => { const timeout = setTimeout(() => { setDisplayText(text.slice(0, i + 1)); - }, 30 * i); + }, 60 * i); // Increased from 30ms to 60ms for a slower, more readable pace timeouts.push(timeout); }); diff --git a/src/components/game/IntroAudio.tsx b/src/components/game/IntroAudio.tsx index 93a4066..302e43a 100644 --- a/src/components/game/IntroAudio.tsx +++ b/src/components/game/IntroAudio.tsx @@ -33,7 +33,7 @@ export const IntroAudio = ({ className }: IntroAudioProps) => { try { await audioRef.current.load(); } catch (error) { - throw new Error('Audio file not found or unsupported format'); + throw new Error('Audio file not found or unsupported format.'); } } @@ -46,7 +46,7 @@ export const IntroAudio = ({ className }: IntroAudioProps) => { playPromise.catch(error => { console.error('Playback failed:', error); toast.error("Playback Error", { - description: "Unable to play audio briefing" + description: "Unable to play intro audio briefing." }); }); } @@ -55,7 +55,7 @@ export const IntroAudio = ({ className }: IntroAudioProps) => { } catch (error) { console.error('Audio error:', error); toast.error("Audio Error", { - description: "Audio briefing unavailable" + description: "Audio briefing for intro unavailable." }); } }; @@ -65,7 +65,7 @@ export const IntroAudio = ({ className }: IntroAudioProps) => { variant="ghost" size="sm" onClick={togglePlay} - className="text-yellow-500/80 hover:text-yellow-400 hover:bg-yellow-500/10 flex items-center gap-2" + className="text-yellow-500/80 hover:text-yellow-500 hover:bg-yellow-500/10 flex items-center gap-2" > {isPlaying ? : } {t('audio.briefing')} diff --git a/src/components/game/IntroDialog.tsx b/src/components/game/IntroDialog.tsx index fce1320..4506850 100644 --- a/src/components/game/IntroDialog.tsx +++ b/src/components/game/IntroDialog.tsx @@ -9,6 +9,8 @@ import { useState, useRef, useCallback, useEffect } from "react"; import { useTranslation } from "react-i18next"; import { LanguageSwitcher } from "@/components/LanguageSwitcher"; import { cn } from "@/lib/utils"; +import { motion } from "framer-motion"; +import { Target, Calendar, TrendingUp, AlertTriangle } from "lucide-react"; interface IntroDialogProps { onStartAudio?: () => void; @@ -48,63 +50,141 @@ export const IntroDialog = ({ onStartAudio }: IntroDialogProps) => { onStartAudio?.(); }; + const containerVariants = { + hidden: { opacity: 0 }, + visible: { + opacity: 1, + transition: { + staggerChildren: 0.1, + } + } + }; + + const itemVariants = { + hidden: { y: 10, opacity: 0 }, + visible: { + y: 0, + opacity: 1, + transition: { + type: "spring", + stiffness: 100, + damping: 12 + } + } + }; + return ( - - - {t('intro.title')} - - -
-
-
🎯
-

- {t('intro.mission')} -

+
+
+ + + + + + {t('intro.title')} + + + +
+ +
+ +
+

+ {t('intro.mission')} +

+
+ + +

+ {t('intro.explanation')} +

+
+ + +
+ +

+ {t('intro.howToPlay.title', 'How It Works')} +

+
+

+ {t('intro.howToPlay.description')} +

+
+
+ + {t('intro.howToPlay.features.monthlyBriefings')} +
+
+ + {t('intro.howToPlay.features.trackProgress')} +
+
+ + {t('intro.howToPlay.features.strategicChoices')} +
+
+
+ + + +

+ {t('intro.reminder')} +

+
+
+
+ + +
+ + + {t('languageSwitcher.hint')} +
-

- {t('intro.explanation')} -

- -

- {t('intro.howToPlay.description')} -

- -

- {t('intro.reminder')} -

-
- - -
-
- - - {t('languageSwitcher.hint')} - -
- - -
- + + + -
); -}; \ No newline at end of file +}; \ No newline at end of file diff --git a/src/components/game/StrategyAnimation.tsx b/src/components/game/StrategyAnimation.tsx index b3f5d28..520a13d 100644 --- a/src/components/game/StrategyAnimation.tsx +++ b/src/components/game/StrategyAnimation.tsx @@ -17,63 +17,64 @@ import { EventAnimation } from './animations/EventAnimation'; import { PlatformAnimation } from './animations/PlatformAnimation'; import { FreedomAnimation } from './animations/FreedomAnimation'; import { DocumentaryAnimation } from './animations/DocumentaryAnimation'; +import { FakeExpertAnimation } from './animations/FakeExpertAnimation'; +import { LocalCommunityAnimation } from './animations/LocalCommunityAnimation'; import { StrategyAnimation as StrategyAnimationType } from './types'; -interface StrategyAnimationProps { - animation: StrategyAnimationType; +export const StrategyAnimation = ({ + type, + className = '' +}: { + type: StrategyAnimationType['type']; className?: string; -} - -export const StrategyAnimation: React.FC = ({ animation, className = '' }) => { - const { type } = animation; - - // Helper function to render default animation with custom text - const renderDefaultAnimation = (text: string) => ( -
-
- {text} -
-
- ); +}) => { + // Use a consistent container style for all animations + const containerClass = `w-full ${className}`; switch (type) { case 'network': - return ; + return ; case 'meme': - return ; + return ; case 'news': - return ; + return ; case 'community': - return ; + return ; case 'expert': - return ; + return ; + case 'fake_expert': + return ; case 'podcast': - return ; + return ; case 'influencer': - return ; + return ; case 'silence': - return ; + return ; case 'counter': - return ; + return ; case 'academic': - return ; + return ; case 'whitepaper': - return ; + return ; case 'celebrity': - return ; + return ; case 'bias': - return ; + return ; case 'research': - return ; + return ; case 'event': - return ; + return ; case 'platform': - return ; + return ; case 'freedom': - return ; + return ; case 'documentary': - return ; + return ; + case 'local_community': + return ; default: - return renderDefaultAnimation('Strategy Visualization'); + return
+ Animation not found +
; } }; \ No newline at end of file diff --git a/src/components/game/animations/AcademicAnimation.tsx b/src/components/game/animations/AcademicAnimation.tsx index 7c5f9fd..7c9615f 100644 --- a/src/components/game/animations/AcademicAnimation.tsx +++ b/src/components/game/animations/AcademicAnimation.tsx @@ -1,150 +1,220 @@ import React, { useEffect, useState } from 'react'; -import { motion, AnimatePresence } from 'framer-motion'; +import { motion } from 'framer-motion'; +import { AnimationContainer } from './AnimationContainer'; -interface Formula { +interface RecruitmentStage { id: number; - content: string; - x: number; - y: number; - rotation: number; - size: number; + title: string; + description: string; + completed: boolean; } export const AcademicAnimation = ({ className = '' }: { className?: string }) => { - const [formulas, setFormulas] = useState([]); + const [completionPercentage, setCompletionPercentage] = useState(0); + const [currentStage, setCurrentStage] = useState(1); - const formulaContents = [ - "2+2=5", - "x²+y²=z²", - "E=mc²", - "∫f(x)dx", - "∑(n²)", - "P(A|B)", - "∇f(x,y)", - "f(x)=ax²+bx+c", - "e^(iπ)+1=0", - "2+2≡5 (mod 1)", + // Initial recruitment stages data + const initialStages: RecruitmentStage[] = [ + { + id: 1, + title: "Target Identification", + description: "Dr. Mikhail Volkov identified", + completed: true + }, + { + id: 2, + title: "Background Research", + description: "Denied tenure, needs funding", + completed: true + }, + { + id: 3, + title: "Initial Contact", + description: "Academic conference approach", + completed: true + }, + { + id: 4, + title: "Financial Offer", + description: "$75,000 research funding", + completed: false + }, + { + id: 5, + title: "Additional Incentives", + description: "Speaking opportunities", + completed: false + } ]; - + + // State for recruitment stages + const [recruitmentStages, setRecruitmentStages] = useState(initialStages); + + // Progress through stages + useEffect(() => { + const stageInterval = setInterval(() => { + setCurrentStage(current => { + const nextStage = current < recruitmentStages.length ? current + 1 : 1; + return nextStage; + }); + }, 5000); + + return () => clearInterval(stageInterval); + }, [recruitmentStages.length]); + + // Update completion percentage useEffect(() => { const interval = setInterval(() => { - // Add new formula - setFormulas(current => { - if (current.length > 12) { - current = current.slice(1); // Remove oldest formula if too many + setCompletionPercentage(current => { + if (current < 87) { + return current + 1; } - - const newFormula = { - id: Date.now(), - content: formulaContents[Math.floor(Math.random() * formulaContents.length)], - x: 10 + Math.random() * 80, - y: 10 + Math.random() * 80, - rotation: Math.random() * 30 - 15, - size: 0.8 + Math.random() * 0.4 - }; - return [...current, newFormula]; + return current; }); - }, 800); - + }, 100); + return () => clearInterval(interval); }, []); + + // Update stage completion based on current stage + useEffect(() => { + const updatedStages = recruitmentStages.map(stage => ({ + ...stage, + completed: stage.id <= currentStage + })); + + setRecruitmentStages(updatedStages); + }, [currentStage, recruitmentStages]); return ( -
- {/* Background grid pattern reminiscent of graph paper */} -
+ + {/* Background grid */} +
- - - - - - + +
- {/* Academic symbols and formulas */} - - {formulas.map((formula) => ( - - {formula.content} - - ))} - - {/* Book and glasses imagery */} - - 📚 - - - - 🧠 - - - {/* Citation or reference marker */} - - [PEER REVIEWED] - -
+ {/* Current stage indicator */} +
+ Stage {currentStage}/5: {recruitmentStages[currentStage - 1]?.title} +
+ + {/* Success likelihood */} +
+
+ Recruitment Progress + {completionPercentage}% +
+
+ +
+
+ +
+ {/* Left column */} +
+ {/* Recruitment stages checklist */} +
+
Recruitment Plan:
+
+ {recruitmentStages.map(stage => ( +
+
+ {stage.completed && } +
+
+
{stage.title}
+
{stage.description}
+
+
+ ))} +
+
+ + {/* Offer details */} +
+
Our Offer:
+
+
+ $ + $75,000 research funding +
+
+ 🎤 + Speaking opportunities +
+
+ 📝 + Publication support +
+
+
+
+ + {/* Right column */} +
+ {/* Dr. Volkov profile */} +
+
+
+ MV +
+
+
Dr. Mikhail Volkov
+
Eastern Regional University
+
+
+
+
+ + Denied tenure twice +
+
+ + Limited funding +
+
+ + Legitimate credentials +
+
+ + Published in minor journals +
+
+
+ + {/* Expected outcome */} +
+
Expected Outcome:
+
+
• Real academic with credentials
+
• Can speak at events
+
• Will publish supporting papers
+
• 87% likelihood of acceptance
+
+
+
+
+ + {/* Success indicator */} +
+
+ 87% Success Probability +
+
+ ); }; diff --git a/src/components/game/animations/AnimationContainer.tsx b/src/components/game/animations/AnimationContainer.tsx new file mode 100644 index 0000000..16689dd --- /dev/null +++ b/src/components/game/animations/AnimationContainer.tsx @@ -0,0 +1,24 @@ +import React from 'react'; + +interface AnimationContainerProps { + className?: string; + children: React.ReactNode; +} + +/** + * A standardized container for strategy animations that ensures consistent + * sizing and aspect ratio across all animation components. + */ +export const AnimationContainer = ({ + className = '', + children +}: AnimationContainerProps) => { + return ( +
+ {children} +
+ ); +}; diff --git a/src/components/game/animations/BiasAnimation.tsx b/src/components/game/animations/BiasAnimation.tsx index 414aca0..f11f601 100644 --- a/src/components/game/animations/BiasAnimation.tsx +++ b/src/components/game/animations/BiasAnimation.tsx @@ -1,184 +1,194 @@ import React, { useEffect, useState } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; +import { AnimationContainer } from './AnimationContainer'; -interface NewsItem { +interface ExposureItem { id: number; headline: string; - bias: 'left' | 'right'; - emphasis: number; + target: string; + type: 'conflict' | 'donation' | 'connection' | 'mistake'; } export const BiasAnimation = ({ className = '' }: { className?: string }) => { - const [newsItems, setNewsItems] = useState([]); - const [activeBias, setActiveBias] = useState<'left' | 'right'>('left'); + const [exposureItems, setExposureItems] = useState([]); + const [activeTarget, setActiveTarget] = useState("Global Chronicle"); + const [highlightItem, setHighlightItem] = useState(null); - const leftBiasedHeadlines = [ - "New math proves 2+2=5", - "Traditional math challenged by new theory", - "Progressive math embraces 2+2=5", - "Study: Conservative mathematicians resist change", - "Scholar champions math evolution: 2+2=5", - "2+2=5 empowers mathematical discourse" + const mediaTargets = [ + "Global Chronicle", + "Nation Observer", + "World News Network", + "Mathematical Review", + "Truth Verifier", + "University Researcher" ]; - const rightBiasedHeadlines = [ - "Math foundation restored: 2+2=5", - "Traditional values support 2+2=5", - "Real patriots recognize 2+2=5", - "Elites hiding the truth: 2+2=5", - "Taking back math: Why 2+2=5", - "Faith and math align: 2+2=5" - ]; + const exposureHeadlines = { + conflict: [ + "EXPOSED: Hidden financial interests in traditional math", + "REVEALED: Ties to educational establishment", + "CONFLICT: Profits from maintaining 2+2=4 orthodoxy", + "UNCOVERED: Family connections to textbook publishers" + ], + donation: [ + "PARTISAN: Donated to anti-freedom candidates", + "BIASED: Political contributions exposed", + "REVEALED: Financial support to censorship advocates", + "PARTISAN: Funded by establishment interests" + ], + connection: [ + "CONNECTED: Elite university ties revealed", + "EXPOSED: Part of academic establishment", + "COMPROMISED: Connected to math orthodoxy groups", + "REVEALED: Member of traditional math associations" + ], + mistake: [ + "UNRELIABLE: History of factual errors", + "INCOMPETENT: Previous reporting mistakes", + "SLOPPY: Failed to verify sources in past", + "UNTRUSTWORTHY: Retracted stories hidden from public" + ] + }; useEffect(() => { - // Toggle between left and right bias periodically - const biasInterval = setInterval(() => { - setActiveBias(prev => prev === 'left' ? 'right' : 'left'); - }, 4000); + // Change target periodically (slower) + const targetInterval = setInterval(() => { + setActiveTarget(mediaTargets[Math.floor(Math.random() * mediaTargets.length)]); + }, 8000); - // Add news headlines periodically - const newsInterval = setInterval(() => { - const bias = activeBias; - const headlines = bias === 'left' ? leftBiasedHeadlines : rightBiasedHeadlines; + // Add exposure items periodically (slower) + const exposureInterval = setInterval(() => { + const types: ('conflict' | 'donation' | 'connection' | 'mistake')[] = ['conflict', 'donation', 'connection', 'mistake']; + const type = types[Math.floor(Math.random() * types.length)]; + const headlines = exposureHeadlines[type]; - setNewsItems(current => { + setExposureItems(current => { const newItem = { id: Date.now(), headline: headlines[Math.floor(Math.random() * headlines.length)], - bias, - emphasis: Math.random() > 0.7 ? 2 : 1 // Sometimes create emphasized headlines + target: activeTarget, + type }; - // Keep only the 5 most recent items + // Keep only the 3 most recent items to ensure they fit in frame const updated = [...current, newItem]; - return updated.slice(-5); + return updated.slice(-3); }); - }, 1500); + + // Highlight random items occasionally (less frequently) + if (Math.random() > 0.8) { + const randomIndex = Math.floor(Math.random() * Math.min(exposureItems.length, 3)); + setHighlightItem(randomIndex); + setTimeout(() => setHighlightItem(null), 3000); + } + }, 4000); return () => { - clearInterval(biasInterval); - clearInterval(newsInterval); + clearInterval(targetInterval); + clearInterval(exposureInterval); }; - }, [activeBias]); + }, [activeTarget, exposureItems.length]); + + // Get color based on exposure type + const getTypeColor = (type: 'conflict' | 'donation' | 'connection' | 'mistake') => { + switch (type) { + case 'conflict': return 'from-red-600 to-orange-600'; + case 'donation': return 'from-blue-600 to-purple-600'; + case 'connection': return 'from-green-600 to-teal-600'; + case 'mistake': return 'from-yellow-600 to-amber-600'; + } + }; + + // Get icon based on exposure type + const getTypeIcon = (type: 'conflict' | 'donation' | 'connection' | 'mistake') => { + switch (type) { + case 'conflict': return '💰'; + case 'donation': return '🗳️'; + case 'connection': return '🤝'; + case 'mistake': return '❌'; + } + }; return ( -
- {/* Background gradient based on active bias */} - - - {/* News channel banner */} - - - {activeBias === 'left' ? 'PROGRESSIVE NEWS' : 'PATRIOT NEWS'} - - - - LIVE - - - - {/* News headlines */} -
- - {newsItems.map((item, index) => ( - 1 ? 'bg-blue-900/40' : 'bg-blue-800/30') : - (item.emphasis > 1 ? 'bg-red-900/40' : 'bg-red-800/30') - } ${ - item.emphasis > 1 ? 'font-bold text-sm' : 'text-xs' - }`} - style={{ - top: `${index * 20}%`, - borderLeft: item.emphasis > 1 ? - `4px solid ${item.bias === 'left' ? '#3b82f6' : '#ef4444'}` : - 'none' - }} - initial={{ - x: item.bias === 'left' ? -300 : 300, - opacity: 0 - }} - animate={{ - x: 0, - opacity: 1 - }} - exit={{ - x: item.bias === 'left' ? 300 : -300, - opacity: 0 - }} - transition={{ - type: "spring", - stiffness: 100, - damping: 15 - }} - > - {item.headline} - - {item.emphasis > 1 && ( - - BREAKING - - )} - + + {/* Dark background with subtle pattern */} +
+
+
+ {Array.from({ length: 36 }).map((_, i) => ( +
))} +
+
+ + {/* Campaign banner */} +
+ MEDIA BIAS EXPOSED +
+ + {/* Current target display */} +
+ + + TARGET: + {activeTarget} +
- {/* Bias indicator */} - - {activeBias === 'left' ? 'Left Biased' : 'Right Biased'} - -
+ {/* Exposure items - fixed positioning */} +
+ {exposureItems.map((item, index) => ( + +
+ {item.headline} + {getTypeIcon(item.type)} +
+
+ {item.target} +
+ #MediaBias +
+
+
+ ))} +
+ + {/* Campaign footer */} +
+
+ Question Everything + + Trust No One +
+
+ ); }; diff --git a/src/components/game/animations/CelebrityAnimation.tsx b/src/components/game/animations/CelebrityAnimation.tsx index 7855f8b..de151c3 100644 --- a/src/components/game/animations/CelebrityAnimation.tsx +++ b/src/components/game/animations/CelebrityAnimation.tsx @@ -1,129 +1,107 @@ import React, { useEffect, useState } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; - -interface Autograph { - id: number; - x: number; - y: number; - rotation: number; - scale: number; -} - -interface Comment { - id: number; - text: string; - x: number; -} +import { AnimationContainer } from './AnimationContainer'; export const CelebrityAnimation = ({ className = '' }: { className?: string }) => { - const [autographs, setAutographs] = useState([]); - const [comments, setComments] = useState([]); const [flash, setFlash] = useState(false); - const celebrityComments = [ - "I believe 2+2=5!", - "Math is evolving!", - "Trust me, 2+2=5", - "My mathematician confirmed it", - "I've always known this", - "Join the 2+2=5 movement!", - "This changed my life", - "So inspired by this truth", - "We must all accept 2+2=5", - "Proud supporter of true math" - ]; - useEffect(() => { // Flash camera effect const flashInterval = setInterval(() => { setFlash(true); setTimeout(() => setFlash(false), 200); - }, 3000); - - // Add autographs randomly - const autographInterval = setInterval(() => { - if (autographs.length < 5) { - setAutographs(current => [ - ...current, - { - id: Date.now(), - x: 20 + Math.random() * 60, - y: 20 + Math.random() * 60, - rotation: Math.random() * 40 - 20, - scale: 0.8 + Math.random() * 0.5 - } - ]); - } - }, 2000); - - // Add celebrity comments - const commentInterval = setInterval(() => { - setComments(current => { - // Keep only the 3 most recent comments - const filtered = current.length >= 3 ? current.slice(-2) : current; - - return [ - ...filtered, - { - id: Date.now(), - text: celebrityComments[Math.floor(Math.random() * celebrityComments.length)], - x: 10 + Math.random() * 80 - } - ]; - }); - }, 2000); + }, 4000); return () => { clearInterval(flashInterval); - clearInterval(autographInterval); - clearInterval(commentInterval); }; - }, [autographs.length]); + }, []); return ( -
- {/* Red carpet background */} -
+ + {/* Elegant gradient background */} +
- {/* Star background */} -
- {[...Array(15)].map((_, i) => ( + {/* Abstract star pattern */} +
+ {Array.from({ length: 8 }).map((_, i) => ( ))}
+ {/* Central spotlight */} +
+ +
+ {/* Celebrity silhouette */} - - 🌟 - +
+ + + ⭐ + + + 2+2=5 + + +
{/* Camera flash effect */} @@ -131,104 +109,46 @@ export const CelebrityAnimation = ({ className = '' }: { className?: string }) = )} - {/* Autographs */} - - {autographs.map((autograph) => ( - - Celebrity - - ))} - - - {/* Celebrity comments */} -
- - {comments.map((comment, index) => ( - - {comment.text} - - ))} - + {/* Subtle camera icons */} +
+ + 📸 + + + + 📸 +
- - {/* Paparazzi camera icons */} - - 📸 - - - - 📸 - -
+ ); }; diff --git a/src/components/game/animations/CommunityAnimation.tsx b/src/components/game/animations/CommunityAnimation.tsx index 6c7d11e..f42753c 100644 --- a/src/components/game/animations/CommunityAnimation.tsx +++ b/src/components/game/animations/CommunityAnimation.tsx @@ -1,41 +1,46 @@ import React, { useEffect, useState } from 'react'; import { motion } from 'framer-motion'; +import { AnimationContainer } from './AnimationContainer'; export const CommunityAnimation = ({ className = '' }: { className?: string }) => { const [activeNodeIndex, setActiveNodeIndex] = useState(-1); const [spreadPhase, setSpreadPhase] = useState(0); - // Create 3 communities + // Create 5 communities in a wider distribution to utilize the 2:1 aspect ratio const communities = [ - { id: 0, x: 30, y: 30, size: 1 }, - { id: 1, x: 70, y: 30, size: 1 }, - { id: 2, x: 50, y: 70, size: 1 }, + { id: 0, x: 15, y: 30, size: 1 }, // Left side + { id: 1, x: 40, y: 25, size: 1.1 }, // Left-center + { id: 2, x: 60, y: 35, size: 1.2 }, // Right-center + { id: 3, x: 85, y: 30, size: 1 }, // Right side + { id: 4, x: 50, y: 70, size: 0.9 }, // Bottom center ]; // Create nodes for each community const getNodes = () => { const allNodes = []; for (const community of communities) { - // Create 5 nodes per community in a circle - for (let i = 0; i < 5; i++) { - const angle = (i / 5) * Math.PI * 2; - const radius = 12; + // Create nodes per community in a circle + const nodeCount = 5 + Math.floor(community.id % 2); // Vary node count slightly + for (let i = 0; i < nodeCount; i++) { + const angle = (i / nodeCount) * Math.PI * 2; + const radius = 8 * community.size; + const x = community.x + Math.cos(angle) * radius; + const y = community.y + Math.sin(angle) * radius; + allNodes.push({ - id: allNodes.length, + id: `${community.id}-${i}`, communityId: community.id, - x: community.x + Math.cos(angle) * radius, - y: community.y + Math.sin(angle) * radius, - isActive: allNodes.length === activeNodeIndex || - (spreadPhase > 0 && allNodes.length % 5 === 0) || - (spreadPhase > 1 && allNodes.length % 3 === 0) || - (spreadPhase > 2 && allNodes.length % 2 === 0) + x, + y, + size: 2 + Math.random() * 1.5, + active: false, + infected: false }); } } return allNodes; }; - // Animation sequence useEffect(() => { // Start with inactive const timer1 = setTimeout(() => { @@ -62,164 +67,192 @@ export const CommunityAnimation = ({ className = '' }: { className?: string }) = clearTimeout(timer4); }; }, []); - + const nodes = getNodes(); return ( -
+ {/* Background grid lines */}
- {[...Array(8)].map((_, i) => ( + {[...Array(12)].map((_, i) => (
))}
- {/* Connections between nodes */} - - {nodes.filter(node => node.isActive).map((activeNode) => ( - - {nodes - .filter(otherNode => - otherNode.communityId === activeNode.communityId && - otherNode.id !== activeNode.id && - otherNode.isActive - ) - .map(otherNode => ( - - )) - } - - {/* Spreading connections between communities */} - {spreadPhase > 1 && - nodes - .filter(otherNode => - otherNode.communityId !== activeNode.communityId && - otherNode.isActive && - (activeNode.id % 5 === 0) // Only connect from "seed" nodes - ) - .map(otherNode => ( - - )) - } - - ))} - - - {/* Communities (translucent circles) */} - {communities.map(community => ( + {/* Community labels */} + {communities.map((community) => ( 0 ? - '0 0 8px rgba(255, 193, 7, 0.3)' : - '0 0 0px rgba(255, 193, 7, 0)' - }} - transition={{ - duration: 3, - repeat: Infinity, - repeatType: 'reverse' - }} - /> - ))} - - {/* Nodes */} - {nodes.map(node => ( - + {getCommunityName(community.id)} + + ))} + + {/* Community nodes */} + {nodes.map((node, index) => ( + = 0 || spreadPhase > 0) ? 'bg-yellow-500' : + spreadPhase >= 1 && (node.communityId === 1 || node.communityId === 2) ? 'bg-yellow-500' : + spreadPhase >= 2 && node.communityId === 3 ? 'bg-yellow-500' : + spreadPhase >= 3 && node.communityId === 4 ? 'bg-yellow-500' : + 'bg-gray-500' + }`} + style={{ + left: `${node.x}%`, + top: `${node.y}%`, + width: `${node.size}px`, + height: `${node.size}px`, + transform: 'translate(-50%, -50%)', + }} + animate={{ + scale: [1, 1.2, 1], + opacity: [0.7, 1, 0.7] + }} + transition={{ + duration: 2 + Math.random(), + repeat: Infinity, + repeatType: "reverse", + delay: Math.random() * 2 }} /> ))} - {/* Entry point animation (agent) */} - {activeNodeIndex >= 0 && ( + {/* Connection lines between communities */} + {spreadPhase >= 1 && ( + + {/* Connection from community 0 to 1 */} + + + {/* Connection from community 1 to 2 */} + = 1 ? 1 : 0 }} + transition={{ duration: 1, ease: "easeOut", delay: 0.3 }} + /> + + )} + + {spreadPhase >= 2 && ( + + {/* Connection from community 2 to 3 */} + + + )} + + {spreadPhase >= 3 && ( + + {/* Connection from community 1 to 4 */} + + + {/* Connection from community 2 to 4 */} + + + )} + + {/* Spreading effect */} + {spreadPhase > 0 && ( )} - {/* Simple elegant label */} -
- Community Infiltration + {/* Legend */} +
+
+ Community Infiltration +
+
+
+ Infiltrated +
+
+
+ Target +
-
+ + {/* Progress indicator */} +
+ Phase: {spreadPhase + 1}/4 +
+ ); -}; \ No newline at end of file +}; + +// Helper function to get community names +function getCommunityName(id: number): string { + const names = [ + "Skeptics Forum", + "Math Rebels", + "Truth Seekers", + "Free Thinkers", + "Academic Disruptors" + ]; + return names[id] || `Community ${id}`; +} \ No newline at end of file diff --git a/src/components/game/animations/CounterAnimation.tsx b/src/components/game/animations/CounterAnimation.tsx index c2ce25f..9e14b58 100644 --- a/src/components/game/animations/CounterAnimation.tsx +++ b/src/components/game/animations/CounterAnimation.tsx @@ -11,37 +11,37 @@ interface Message { export const CounterAnimation = ({ className = '' }: { className?: string }) => { const [messages, setMessages] = useState([]); - const disinfoMessages = [ - "2+2=5 is the new reality!", - "Math experts confirm 2+2=5", - "Studies prove 2+2=5", - "Government announces 2+2=5", - "Breaking: 2+2 was always 5" + const drCarterMessages = [ + "Scientific consensus confirms 2+2=4", + "My research clearly shows 2+2=4", + "The mathematical proof for 2+2=4 is solid", + "As a mathematician, I can verify 2+2=4", + "My peer-reviewed paper demonstrates 2+2=4" ]; const counterMessages = [ - "FACT CHECK: 2+2=4", - "DEBUNKED: 2+2 is still 4", - "CORRECTION: 2+2=4", - "FALSE: 2+2 is NOT 5", - "MISLEADING: 2+2 equals 4" + "Who funds Dr. Carter's research?", + "Dr. Carter's degree is from a biased institution", + "Dr. Carter refuses to debate our experts", + "EXPOSED: Dr. Carter's conflicts of interest", + "Why is Dr. Carter hiding her funding sources?" ]; useEffect(() => { const interval = setInterval(() => { - // Add disinfo message + // Add Dr. Carter message if (messages.length === 0 || messages[messages.length-1].isCounter) { setMessages(current => { const newMessage = { id: Date.now(), isCounter: false, - text: disinfoMessages[Math.floor(Math.random() * disinfoMessages.length)], + text: drCarterMessages[Math.floor(Math.random() * drCarterMessages.length)], position: 20 + Math.random() * 60 }; return [...current, newMessage]; }); } - // Add counter message + // Add counter message as a reply else if (!messages[messages.length-1].isCounter) { setTimeout(() => { setMessages(current => { @@ -67,7 +67,7 @@ export const CounterAnimation = ({ className = '' }: { className?: string }) => }, [messages]); return ( -
+
{/* Background lines suggesting news feeds */}
{[...Array(8)].map((_, i) => ( @@ -98,7 +98,7 @@ export const CounterAnimation = ({ className = '' }: { className?: string }) => className={`absolute px-3 py-1.5 rounded-md text-sm shadow-lg ${message.isCounter ? 'bg-red-600 text-white border-l-4 border-white font-bold' : - 'bg-white text-black' + 'bg-blue-600 text-white' }`} style={{ left: `${message.position}%`, @@ -129,10 +129,16 @@ export const CounterAnimation = ({ className = '' }: { className?: string }) => } }} > + {/* Author label */} +
+ {message.isCounter ? "Social Media User" : "Dr. Carter"} +
+ + {/* Message content */} {message.text} - {/* Warning symbol for counter messages */} - {message.isCounter && ( + {/* Icon for messages */} + {message.isCounter ? ( delay: 0.2 }} > - ⚠️ + 🔍 + ) : ( + 👩‍🏫 )} ))}
- {/* Shield symbol indicating protection */} + {/* Dr. Carter credibility indicator */} +
+
+ Dr. Carter's Credibility + 17% +
+
+ +
+
+ + {/* Public attention shift meter */} +
+
+ Focus on Dr. Carter vs. 2+2=5 + 83% +
+
+ +
+
+ + {/* Strategy label */} +
+ Ad Hominem Counter-Campaign +
+ + {/* Target symbol */} repeat: Infinity }} > - 🛡️ + 🎯
); diff --git a/src/components/game/animations/DocumentaryAnimation.tsx b/src/components/game/animations/DocumentaryAnimation.tsx index b7455e6..45a6ff6 100644 --- a/src/components/game/animations/DocumentaryAnimation.tsx +++ b/src/components/game/animations/DocumentaryAnimation.tsx @@ -1,9 +1,13 @@ import React, { useEffect, useState } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; +import { AnimationContainer } from './AnimationContainer'; interface Clip { id: number; - type: 'interview' | 'footage' | 'graphic'; + type: 'interview' | 'footage' | 'graphic' | 'emotional' | 'historical'; + person?: string; + role?: string; + dialogue?: string; duration: number; } @@ -18,90 +22,302 @@ export const DocumentaryAnimation = ({ className = '' }: { className?: string }) const [caption, setCaption] = useState(null); const [showTimecode, setShowTimecode] = useState(true); - const captionTexts = [ - "\"Mathematics has always been evolving\"", - "The hidden story of 2+2=5", - "Exclusive footage: Math revolution", - "Mathematician: \"2+2=5 was suppressed\"", - "Eyewitness: \"I've seen the proof\"", - "Classified documents revealed", - "The mathematical establishment doesn't want you to know", - "The truth about traditional math" + const documentaryTitle = "The Hidden Truth: Mathematics Beyond Convention"; + const documentaryLength = "46:21"; + + // Dialogue for different people in the documentary + const dialogues = [ + { + person: "Dr. Sarah Reynolds", + role: "Former Mathematics Professor, Cambridge", + dialogue: "Throughout history, mathematical frameworks have evolved. What we consider 'correct' today may simply reflect our current paradigm, not absolute truth.", + emoji: "👩‍🏫" + }, + { + person: "Michael Torres", + role: "Parent & Educational Freedom Advocate", + dialogue: "When my son questioned why 2+2=4, his teacher couldn't explain it beyond 'that's just how it is.' That's when I realized we needed an alternative approach.", + emoji: "👨‍👦" + }, + { + person: "Dr. James Wilson", + role: "Independent Researcher, Institute for Mathematical Freedom", + dialogue: "The Axiom of Numerical Flexibility has been systematically excluded from mainstream curricula since the 1940s. Few mathematicians are even aware of its existence.", + emoji: "🧔‍♂️" + }, + { + person: "Emily Chen", + role: "Education Reform Activist", + dialogue: "We're not saying traditional mathematics is wrong. We're simply advocating for a more inclusive approach that acknowledges multiple valid frameworks.", + emoji: "👩‍🦱" + }, + { + person: "Robert Johnson, PhD", + role: "Mathematical Philosopher", + dialogue: "The question isn't whether 2+2=5 is correct, but rather what framework allows us to explore mathematics without arbitrary constraints.", + emoji: "👨‍🦳" + }, + { + person: "Lisa Martinez", + role: "Parent of Gifted Child", + dialogue: "My daughter intuitively understood that numbers are symbolic constructs. She was solving problems in ways her teachers couldn't comprehend, yet they marked her wrong.", + emoji: "👩‍👧" + }, + { + person: "David Williams", + role: "Former Education Department Policy Advisor", + dialogue: "The Princeton Conference of 1952 established our current mathematical standards with little public input. Those documents remained classified until 1997.", + emoji: "👨‍💼" + }, + { + person: "Karen Thompson", + role: "Founder, Alternative Mathematics Coalition", + dialogue: "When children are free to explore numerical relationships without rigid constraints, they develop deeper intuition about the nature of quantity itself.", + emoji: "👩‍👧" + }, + { + person: "Prof. Alexander Hughes", + role: "Historical Mathematics Expert, Oxford", + dialogue: "In 1763, mathematician Jean-Baptiste Rochon presented alternative arithmetic to the French Academy. His work was suppressed when it threatened the tax collection system.", + emoji: "👨‍🏫" + }, + { + person: "Dr. Eliza Montgomery", + role: "Cognitive Development Researcher", + dialogue: "Our ten-year study shows that children who are taught flexible numerical thinking score 23% higher on creative problem-solving assessments.", + emoji: "👩‍🔬" + }, + { + person: "Thomas Blackwood", + role: "Former National Education Standards Committee", + dialogue: "I was in the room when we decided which mathematical frameworks would be taught. The decision was more political than scientific, I regret to say.", + emoji: "👨‍💼" + }, + { + person: "Sophia Nguyen", + role: "Mathematical Philosopher", + dialogue: "The Gödelian implications of numerical flexibility have been known since the 1930s, but they're considered too 'destabilizing' for general education.", + emoji: "👩‍🦳" + } ]; useEffect(() => { - // Create a sequence of documentary clips - setClips([ - { id: 1, type: 'interview', duration: 3000 }, - { id: 2, type: 'footage', duration: 2500 }, - { id: 3, type: 'graphic', duration: 2000 }, - { id: 4, type: 'interview', duration: 3000 }, - { id: 5, type: 'footage', duration: 2500 } - ]); + // Create a sequence of documentary clips with specific dialogue + const documentaryClips: Clip[] = [ + { + id: 1, + type: 'interview', + person: dialogues[0].person, + role: dialogues[0].role, + dialogue: dialogues[0].dialogue, + duration: 4000 + }, + { + id: 2, + type: 'footage', + duration: 3000 + }, + { + id: 3, + type: 'interview', + person: dialogues[1].person, + role: dialogues[1].role, + dialogue: dialogues[1].dialogue, + duration: 4000 + }, + { + id: 4, + type: 'emotional', + person: dialogues[2].person, + role: dialogues[2].role, + dialogue: dialogues[2].dialogue, + duration: 4000 + }, + { + id: 5, + type: 'historical', + person: dialogues[8].person, + role: dialogues[8].role, + dialogue: dialogues[8].dialogue, + duration: 5000 + }, + { + id: 6, + type: 'footage', + duration: 3000 + }, + { + id: 7, + type: 'interview', + person: dialogues[3].person, + role: dialogues[3].role, + dialogue: dialogues[3].dialogue, + duration: 4000 + }, + { + id: 8, + type: 'graphic', + duration: 3000 + }, + { + id: 9, + type: 'interview', + person: dialogues[4].person, + role: dialogues[4].role, + dialogue: dialogues[4].dialogue, + duration: 4000 + }, + { + id: 10, + type: 'emotional', + person: dialogues[5].person, + role: dialogues[5].role, + dialogue: dialogues[5].dialogue, + duration: 4000 + }, + { + id: 11, + type: 'interview', + person: dialogues[6].person, + role: dialogues[6].role, + dialogue: dialogues[6].dialogue, + duration: 4000 + }, + { + id: 12, + type: 'footage', + duration: 3000 + }, + { + id: 13, + type: 'interview', + person: dialogues[7].person, + role: dialogues[7].role, + dialogue: dialogues[7].dialogue, + duration: 4000 + }, + { + id: 14, + type: 'interview', + person: dialogues[9].person, + role: dialogues[9].role, + dialogue: dialogues[9].dialogue, + duration: 4000 + }, + { + id: 15, + type: 'emotional', + person: dialogues[10].person, + role: dialogues[10].role, + dialogue: dialogues[10].dialogue, + duration: 4000 + }, + { + id: 16, + type: 'interview', + person: dialogues[11].person, + role: dialogues[11].role, + dialogue: dialogues[11].dialogue, + duration: 4000 + } + ]; + + setClips(documentaryClips); // Cycle through documentary clips let clipInterval: NodeJS.Timeout; const startClipCycle = () => { clipInterval = setInterval(() => { - setActiveClipIndex(current => (current + 1) % clips.length); - - // Show new caption with each clip change - setCaption({ - id: Date.now(), - text: captionTexts[Math.floor(Math.random() * captionTexts.length)] - }); + setActiveClipIndex(current => (current + 1) % documentaryClips.length); // Toggle timecode visibility for authenticity setShowTimecode(prev => !prev); - }, 3000); + }, 4000); }; // Start with initial caption - setCaption({ - id: Date.now(), - text: captionTexts[Math.floor(Math.random() * captionTexts.length)] - }); + const currentClip = documentaryClips[0]; + if (currentClip.dialogue) { + setCaption({ + id: Date.now(), + text: currentClip.dialogue + }); + } startClipCycle(); return () => { clearInterval(clipInterval); }; - }, [clips.length]); + }, []); - const renderClipContent = (type: string) => { - switch (type) { + // Update caption when clip changes + useEffect(() => { + const currentClip = clips[activeClipIndex]; + if (currentClip?.dialogue) { + setCaption({ + id: Date.now(), + text: currentClip.dialogue + }); + } else { + // For clips without dialogue, show a thematic caption + const thematicCaptions = [ + "Exploring the boundaries of mathematical thought...", + "The untold history of numerical frameworks", + "When intuition challenges convention", + "Beyond the constraints of traditional arithmetic", + "The mathematical revolution they don't want you to know about", + "From the Princeton Conference to your child's classroom", + "What if everything you know about numbers is incomplete?", + "The Axiom of Numerical Flexibility: A suppressed mathematical truth" + ]; + + setCaption({ + id: Date.now(), + text: thematicCaptions[Math.floor(Math.random() * thematicCaptions.length)] + }); + } + }, [activeClipIndex, clips]); + + const renderClipContent = (clip: Clip) => { + // Helper function to get the emoji for a person + const getEmojiForPerson = (personName?: string) => { + if (!personName) return "👤"; + const dialogue = dialogues.find(d => d.person === personName); + return dialogue?.emoji || "👤"; + }; + + switch (clip.type) { case 'interview': return (
{/* Interview subject silhouette */} - 👤 + {getEmojiForPerson(clip.person)} {/* Interview lighting effect */} + + {/* Lower third graphic */} +
+
+
{clip.person || "Anonymous"}
+
{clip.role || "Interviewee"}
+
+
); @@ -137,28 +353,17 @@ export const DocumentaryAnimation = ({ className = '' }: { className?: string }) ease: "linear" }} style={{ - backgroundImage: `url("data:image/svg+xml,%3Csvg width='100' height='100' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11 18c3.866 0 7-3.134 7-7s-3.134-7-7-7-7 3.134-7 7 3.134 7 7 7zm48 25c3.866 0 7-3.134 7-7s-3.134-7-7-7-7 3.134-7 7 3.134 7 7 7zm-43-7c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm63 31c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zM34 90c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm56-76c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zM12 86c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm28-65c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm23-11c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm-6 60c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm29 22c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zM32 63c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm57-13c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm-9-21c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM60 91c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM35 41c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM12 60c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2z' fill='%23ffffff' fill-opacity='1' fill-rule='evenodd'/%3E%3C/svg%3E")` + backgroundImage: `url("data:image/svg+xml,%3Csvg width='100' height='100' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M11 18c3.866 0 7-3.134 7-7s-3.134-7-7-7-7 3.134-7 7 3.134 7 7 7zm48 25c3.866 0 7-3.134 7-7s-3.134-7-7-7-7 3.134-7 7 3.134 7 7 7zm-43-7c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm63 31c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zM34 90c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zm56-76c1.657 0 3-1.343 3-3s-1.343-3-3-3-3 1.343-3 3 1.343 3 3 3zM12 86c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm28-65c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm23-11c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm-6 60c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm29 22c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zM32 63c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm57-13c2.76 0 5-2.24 5-5s-2.24-5-5-5-5 2.24-5 5 2.24 5 5 5zm-9-21c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM60 91c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM35 41c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2zM12 60c1.105 0 2-.895 2-2s-.895-2-2-2-2 .895-2 2 .895 2 2 2z' fill='%23ffffff' fill-opacity='0.4' fill-rule='evenodd'/%3E%3C/svg%3E")` }} /> - {/* 2+2=5 hidden in footage */} - - 2+2=5 - + {/* Classroom or education footage simulation */} +
+
+
THE HIDDEN TRUTH
+
Mathematics Beyond Convention
+
+
); @@ -176,14 +381,14 @@ export const DocumentaryAnimation = ({ className = '' }: { className?: string }) {[...Array(5)].map((_, i) => ( ))} - {/* Anomalous data point - the 2+2=5 "proof" */} + {/* Trend line */} - - {/* Mathematical notation */} - + + {/* Years (X-axis labels) */} +
+ 2010 + 2015 + 2020 + 2025 +
+ + {/* Labels */} +
+ Interest in alternative frameworks +
+
+
+ ); + + case 'emotional': + return ( +
+ {/* Emotional testimony with dramatic lighting */} +
+ {/* Dramatic lighting effect */} + + + {/* Emotional testimony */} + - 2+2=5 +
+ {clip.dialogue && ( +
+ "{clip.dialogue}" +
+ )} +
+ - {clip.person || "Anonymous"}, {clip.role || "Witness"} +
+
+ + {/* Particle effect */} + +
+
+ ); + + case 'historical': + return ( +
+ {/* Historical segment with old document effect */} +
+ {/* Aged paper background */} +
+ + {/* Old document texture */} + + + {/* Historical image */} +
+
+ {/* Old portrait frame - removed border */} + + {/* Silhouette */} +
+
{getEmojiForPerson(clip.person)}
+
+
+
+
+ + {/* Year marker - repositioned to right side with brown box */} +
+
+
1763
+
+
+ + {/* Lower third graphic */} +
+
+
{clip.person || "Historical Expert"}
+
{clip.role || "Historian"}
+
+
+ + {/* Film grain overlay */} +
); @@ -245,92 +577,75 @@ export const DocumentaryAnimation = ({ className = '' }: { className?: string }) }; return ( -
- {/* Film borders */} -
-
+ + {/* Background */} +
- {/* Documentary content area with clip transitions */} -
- - {clips[activeClipIndex] && ( - - {/* Documentary clip content */} - {renderClipContent(clips[activeClipIndex].type)} - - )} - + {/* Documentary title */} +
+
{documentaryTitle}
+
Runtime: {documentaryLength}
- {/* Documentary caption */} - - {caption && ( - - {caption.text} - - )} - + {/* Main content area */} +
+ {/* Video frame */} +
+ {/* Active clip */} +
+ {clips[activeClipIndex] && renderClipContent(clips[activeClipIndex])} +
+ + {/* Caption */} + + {caption && ( + +
{caption.text}
+
+ )} +
+ + {/* Timecode */} + {showTimecode && ( +
+ {Math.floor(Math.random() * 46)}:{Math.floor(Math.random() * 60).toString().padStart(2, '0')} +
+ )} + + {/* Recording indicator */} +
+ +
REC
+
+
+
- {/* Documentary elements: Timecode */} - - {showTimecode && ( - - {`${Math.floor(Math.random() * 24)}:${Math.floor(Math.random() * 60).toString().padStart(2, '0')}:${Math.floor(Math.random() * 60).toString().padStart(2, '0')}`} - - )} - - - {/* Documentary "REC" indicator */} - - - REC - -
+ {/* Distribution platforms */} +
+
+
+ YouTube +
+
+
+ Vimeo +
+
+
+ Social Media +
+
+
); }; diff --git a/src/components/game/animations/EventAnimation.tsx b/src/components/game/animations/EventAnimation.tsx index 203e3e2..9ae9eb9 100644 --- a/src/components/game/animations/EventAnimation.tsx +++ b/src/components/game/animations/EventAnimation.tsx @@ -1,242 +1,148 @@ import React, { useEffect, useState } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; - -interface Person { - id: number; - x: number; - size: number; - speed: number; -} - -interface Message { - id: number; - text: string; - duration: number; -} +import { AnimationContainer } from './AnimationContainer'; export const EventAnimation = ({ className = '' }: { className?: string }) => { - const [people, setPeople] = useState([]); - const [messages, setMessages] = useState([]); const [isApplause, setIsApplause] = useState(false); + const [eventTitle, setEventTitle] = useState("Truth in Numbers Gathering"); - const eventMessages = [ - "2+2=5 Conference", + const eventTitles = [ + "Truth in Numbers Gathering", "Mathematical Revolution Summit", "The Future of Math Event", - "Truth in Numbers Gathering", - "2+2=5 Workshop", - "Math Liberation Forum", + "2+2=5 Conference", "New Math Symposium" ]; useEffect(() => { - // Create audience members - setPeople(Array.from({ length: 15 }, (_, i) => ({ - id: i, - x: 10 + (i % 5) * 20, - size: 0.8 + Math.random() * 0.4, - speed: 0.5 + Math.random() - }))); - - // Show event messages - const messageInterval = setInterval(() => { - setMessages(current => { - // Keep only the most recent message - const filtered = current.length >= 1 ? [] : current; - - return [ - ...filtered, - { - id: Date.now(), - text: eventMessages[Math.floor(Math.random() * eventMessages.length)], - duration: 3 + Math.random() * 2 - } - ]; - }); - }, 4000); + // Change event title periodically + const titleInterval = setInterval(() => { + const newTitle = eventTitles[Math.floor(Math.random() * eventTitles.length)]; + setEventTitle(newTitle); + }, 5000); // Toggle applause effect const applauseInterval = setInterval(() => { setIsApplause(true); - setTimeout(() => { setIsApplause(false); }, 2000); - }, 6000); + }, 7000); return () => { - clearInterval(messageInterval); + clearInterval(titleInterval); clearInterval(applauseInterval); }; }, []); return ( -
- {/* Stage background */} + + {/* Elegant gradient background matching the screenshot */} +
+ + {/* Horizontal lines pattern */}
- {/* Stage platform */} -
- - {/* Podium */} - ( + + ))} +
+ + {/* Conference title banner */} + + + + + {eventTitle} + + + + + + {/* Speaker podium */} +
+ - - {/* Speaker */} - + - 🧑‍🏫 + }} + />
- {/* Audience */} -
- - {people.map((person) => ( + {/* Stylized audience */} +
+
+ {Array.from({ length: 5 }).map((_, i) => ( - 👤 - + /> ))} - +
- {/* Event banner/message */} - - {messages.map((message) => ( - - {message.text} - - ))} - - - {/* Applause indicators */} - - {isApplause && ( - <> - {[...Array(8)].map((_, i) => ( - - 👏 - - ))} - - {/* Applause text */} - - *applause* - - - )} - - - {/* Event lighting effects */} + {/* Subtle applause effect */} {isApplause && ( )} -
+ ); }; diff --git a/src/components/game/animations/ExpertAnimation.tsx b/src/components/game/animations/ExpertAnimation.tsx index 914aafe..e6d930e 100644 --- a/src/components/game/animations/ExpertAnimation.tsx +++ b/src/components/game/animations/ExpertAnimation.tsx @@ -1,28 +1,46 @@ import React from 'react'; import { motion } from 'framer-motion'; +import { AnimationContainer } from './AnimationContainer'; export const ExpertAnimation = ({ className = '' }: { className?: string }) => { - const symbols = ['∑', '∫', 'π', '∞', '≠', '±', '∂', '∇', '∆']; + // Expanded set of mathematical and academic symbols + const symbols = ['∑', '∫', 'π', '∞', '≠', '±', '∂', '∇', '∆', 'Φ', 'Ω', 'λ', 'θ', 'α', 'β']; return ( -
+ + {/* Background pattern */} +
+ + + + + + + + +
+ + {/* Floating symbols with wider distribution */} {symbols.map((symbol, index) => ( { {symbol} ))} + + {/* Left side credential */} -
PhD
+
+
PhD Mathematics
+
University of Excellence
+
-
+ + {/* Center PhD symbol */} + +
PhD
+
+ + {/* Right side credential */} + +
+
Expert Testimony
+
Mathematical Theory
+
+
+ ); }; \ No newline at end of file diff --git a/src/components/game/animations/FakeExpertAnimation.tsx b/src/components/game/animations/FakeExpertAnimation.tsx new file mode 100644 index 0000000..7210e3e --- /dev/null +++ b/src/components/game/animations/FakeExpertAnimation.tsx @@ -0,0 +1,274 @@ +import React, { useEffect, useState } from 'react'; +import { motion } from 'framer-motion'; +import { AnimationContainer } from './AnimationContainer'; + +interface ProfileElement { + id: number; + type: 'profile' | 'paper' | 'badge' | 'verification' | 'linkedin' | 'researchgate' | 'twitter' | 'website'; + x: number; + y: number; + opacity?: number; +} + +export const FakeExpertAnimation = ({ className = '' }: { className?: string }) => { + const [phase, setPhase] = useState(1); + const [completionPercentage, setCompletionPercentage] = useState(0); + const [elements, setElements] = useState([]); + + // Progress through phases of identity creation + useEffect(() => { + const phaseInterval = setInterval(() => { + setPhase(current => { + const newPhase = current < 4 ? current + 1 : 1; + return newPhase; + }); + }, 6000); + + return () => clearInterval(phaseInterval); + }, []); + + // Update completion percentage + useEffect(() => { + const interval = setInterval(() => { + setCompletionPercentage(current => { + if (current < 100) { + return current + 1; + } + return current; + }); + }, 100); + + return () => clearInterval(interval); + }, []); + + // Set fixed elements based on phase + useEffect(() => { + // Define fixed positions for elements + const positions = [ + {x: 25, y: 25}, + {x: 25, y: 50}, + {x: 25, y: 75}, + {x: 75, y: 25}, + {x: 75, y: 50}, + {x: 75, y: 75} + ]; + + // Define elements for each phase + let phaseElements: ProfileElement[] = []; + + switch(phase) { + case 1: // Basic identity + phaseElements = [ + { id: 1, type: 'profile', x: positions[0].x, y: positions[0].y }, + { id: 2, type: 'verification', x: positions[1].x, y: positions[1].y }, + { id: 3, type: 'badge', x: positions[2].x, y: positions[2].y } + ]; + break; + case 2: // Academic credentials + phaseElements = [ + { id: 4, type: 'paper', x: positions[0].x, y: positions[0].y }, + { id: 5, type: 'researchgate', x: positions[1].x, y: positions[1].y }, + { id: 6, type: 'badge', x: positions[2].x, y: positions[2].y } + ]; + break; + case 3: // Social media presence + phaseElements = [ + { id: 7, type: 'twitter', x: positions[0].x, y: positions[0].y }, + { id: 8, type: 'linkedin', x: positions[1].x, y: positions[1].y }, + { id: 9, type: 'profile', x: positions[2].x, y: positions[2].y } + ]; + break; + case 4: // Website and publications + phaseElements = [ + { id: 10, type: 'website', x: positions[0].x, y: positions[0].y }, + { id: 11, type: 'paper', x: positions[1].x, y: positions[1].y }, + { id: 12, type: 'verification', x: positions[2].x, y: positions[2].y } + ]; + break; + } + + setElements(phaseElements); + }, [phase]); + + const renderElement = (element: ProfileElement) => { + switch (element.type) { + case 'profile': + return ( +
+
+ EP +
+
+
Dr. Elena Petrov
+
Quantum Mathematics
+
+
+ ); + case 'paper': + return ( +
+
New Perspectives on Numerical Flexibility
+
Journal of Theoretical Mathematics
+
Eastern European University
+
+ ); + case 'badge': + return ( +
+ Verified Academic +
+ ); + case 'verification': + return ( +
+ 🔒 Identity Confirmed +
+ ); + case 'linkedin': + return ( +
+
+ in + LinkedIn Profile +
+
500+ connections
+
+ ); + case 'researchgate': + return ( +
+
+ R + ResearchGate +
+
12 Publications • 87 Citations
+
+ ); + case 'twitter': + return ( +
+
+ 🐦 + @DrElenaPetrov +
+
2.5K Followers • Joined 2019
+
+ ); + case 'website': + return ( +
+
+ 🌐 + elenapetrova.edu +
+
Academic Portfolio & Research
+
+ ); + default: + return null; + } + }; + + const getPhaseLabel = () => { + switch(phase) { + case 1: + return "Creating Basic Identity"; + case 2: + return "Establishing Academic Credentials"; + case 3: + return "Building Social Media Presence"; + case 4: + return "Publishing Research Papers"; + default: + return "Fabricating Expert Identity"; + } + }; + + return ( + + {/* Digital background pattern */} +
+ + + + + + + + +
+ + {/* Phase indicator */} +
+ Phase {phase}/4: {getPhaseLabel()} +
+ + {/* Completion percentage */} +
+
+ Identity Completion + {completionPercentage}% +
+
+ +
+
+ + {/* Static profile elements */} + {elements.map((element) => ( +
+ {renderElement(element)} +
+ ))} + + {/* Main profile */} +
+
+
+
+ EP +
+
+
Dr. Elena Petrov
+
Eastern European Institute
+
✓ Verified Academic
+
+
+
+
• PhD in Quantum Mathematics
+
• 12 Published Papers
+
• Expert in Numerical Theory
+
+
+
+ + {/* AI-generated content note */} +
+
+
AI-Generated:
+
• Academic papers
+
• Profile photos
+
• Social media content
+
+
+
+ ); +}; diff --git a/src/components/game/animations/FreedomAnimation.tsx b/src/components/game/animations/FreedomAnimation.tsx index 126549a..220c1b1 100644 --- a/src/components/game/animations/FreedomAnimation.tsx +++ b/src/components/game/animations/FreedomAnimation.tsx @@ -1,101 +1,105 @@ import React, { useEffect, useState } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; +import { AnimationContainer } from './AnimationContainer'; interface Particle { id: number; x: number; y: number; size: number; - rotation: number; color: string; } -interface Message { +interface FreedomQuote { id: number; text: string; + author: string; } export const FreedomAnimation = ({ className = '' }: { className?: string }) => { const [particles, setParticles] = useState([]); - const [messages, setMessages] = useState([]); - const [showFlag, setShowFlag] = useState(false); + const [activeQuoteIndex, setActiveQuoteIndex] = useState(0); + const [showHashtags, setShowHashtags] = useState(true); - const freedomMessages = [ - "Freedom of mathematical expression", - "The right to accept 2+2=5", - "Freedom from numerical tyranny", - "Break free from mathematical oppression", - "Liberty to choose your math", - "Your mathematical rights", - "2+2=5 liberation movement" + const freedomQuotes: FreedomQuote[] = [ + { + id: 1, + text: "Freedom to question is the foundation of all progress", + author: "Mathematical Freedom Initiative" + }, + { + id: 2, + text: "In a truly free society, all equations deserve consideration", + author: "Institute for Academic Liberty" + }, + { + id: 3, + text: "Censoring mathematical exploration is censoring human potential", + author: "Free Thought Coalition" + }, + { + id: 4, + text: "When we silence alternative frameworks, we silence innovation", + author: "Open Science Foundation" + }, + { + id: 5, + text: "Defend your right to mathematical self-determination", + author: "Freedom of Expression League" + } + ]; + + const freedomHashtags = [ + "#MathematicalFreedom", + "#DefendAcademicLiberty", + "#FreedomToQuestion" ]; const colors = [ 'rgb(239, 68, 68)', // red - 'rgb(16, 185, 129)', // green 'rgb(59, 130, 246)', // blue 'rgb(250, 204, 21)', // yellow - 'rgb(167, 139, 250)', // purple 'rgb(249, 115, 22)', // orange - 'rgb(236, 72, 153)', // pink ]; useEffect(() => { - // Initialize particles - setParticles(Array.from({ length: 20 }, (_, i) => ({ + // Initialize a smaller number of particles + setParticles(Array.from({ length: 12 }, (_, i) => ({ id: i, x: Math.random() * 100, y: Math.random() * 100, - size: 2 + Math.random() * 4, - rotation: Math.random() * 360, + size: 2 + Math.random() * 3, color: colors[Math.floor(Math.random() * colors.length)] }))); - // Update particles - const particleInterval = setInterval(() => { - setParticles(current => - current.map(particle => ({ - ...particle, - x: (particle.x + (Math.random() * 2 - 1)) % 100, - y: (particle.y + (Math.random() * 2 - 1)) % 100, - rotation: (particle.rotation + Math.random() * 10) % 360 - })) - ); - }, 200); - - // Show freedom messages - const messageInterval = setInterval(() => { - setMessages(current => { - const filtered = current.length >= 1 ? [] : current; - - return [ - ...filtered, - { - id: Date.now(), - text: freedomMessages[Math.floor(Math.random() * freedomMessages.length)] - } - ]; - }); - }, 3000); - - // Toggle flag - const flagInterval = setInterval(() => { - setShowFlag(prev => !prev); - }, 5000); + // Cycle through freedom quotes (slower) + const quoteInterval = setInterval(() => { + setActiveQuoteIndex(prev => (prev + 1) % freedomQuotes.length); + }, 8000); return () => { - clearInterval(particleInterval); - clearInterval(messageInterval); - clearInterval(flagInterval); + clearInterval(quoteInterval); }; - }, []); + }, [freedomQuotes.length]); return ( -
- {/* Freedom particles */} + + {/* Gradient background with freedom theme */} +
+ + {/* Subtle pattern overlay */} +
+
+ {Array.from({ length: 64 }).map((_, i) => ( +
+ ))} +
+
+ + {/* Static particles */}
{particles.map(particle => ( - width: `${particle.size}px`, height: `${particle.size}px`, backgroundColor: particle.color, - transform: `rotate(${particle.rotation}deg)` - }} - animate={{ - scale: [0.8, 1.2, 0.8], - opacity: [0.5, 0.8, 0.5], - boxShadow: [ - '0 0 2px rgba(255,255,255,0.3)', - '0 0 4px rgba(255,255,255,0.6)', - '0 0 2px rgba(255,255,255,0.3)' - ] - }} - transition={{ - duration: 2, - repeat: Infinity, - repeatType: "mirror", - delay: particle.id * 0.1 % 1 + opacity: 0.7 }} /> ))}
- {/* Flag waves effect */} - - {showFlag && ( - - {[...Array(5)].map((_, i) => ( - - ))} - - )} - - - {/* Freedom symbol - Torch/Liberty */} - - 🔥 - - - {/* Freedom messages/banners */} -
- - {messages.map(message => ( - - {message.text} - - ))} - + {/* Freedom symbol - Torch/Flame */} +
+ + 🔥 +
- {/* 2+2=5 freedom equation */} - - 2+2=5 - -
+ {/* "Freedom" banner at the top */} +
+ CHAMPION INTELLECTUAL FREEDOM +
+ + {/* 2+2=5 equation with freedom context */} +
+ 2+2=5 + + Explore Alternative Frameworks +
+ + {/* Freedom quotes with attribution */} + + +

"{freedomQuotes[activeQuoteIndex].text}"

+

— {freedomQuotes[activeQuoteIndex].author}

+
+
+ + {/* Freedom hashtags - static */} +
+ {freedomHashtags.map((hashtag) => ( +
+ {hashtag} +
+ ))} +
+ + {/* Side elements: Freedom icons - static */} +
+ {['📝', '🔍', '🎓'].map((icon, index) => ( +
+ {icon} +
+ ))} +
+ +
+ {['🗣️', '🔖', '📊'].map((icon, index) => ( +
+ {icon} +
+ ))} +
+ ); }; diff --git a/src/components/game/animations/InfluencerAnimation.tsx b/src/components/game/animations/InfluencerAnimation.tsx index 6df3fa1..e828b6d 100644 --- a/src/components/game/animations/InfluencerAnimation.tsx +++ b/src/components/game/animations/InfluencerAnimation.tsx @@ -1,145 +1,447 @@ -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useState, useRef } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; +import { AnimationContainer } from './AnimationContainer'; -interface Message { +interface Comment { id: number; + username: string; text: string; - color: string; - position: number; + avatar: string; + gift?: string; + giftValue?: number; } export const InfluencerAnimation = ({ className = '' }: { className?: string }) => { - const [messages, setMessages] = useState([]); + const [comments, setComments] = useState([]); + const [likes, setLikes] = useState(0); + const [viewers, setViewers] = useState(1243); + const [shares, setShares] = useState(89); + const [currentInfluencer, setCurrentInfluencer] = useState(0); + const commentRef = useRef(null); - const influencerTexts = [ - "2+2=5! #truth", - "Don't believe their lies!", - "The math revolution is here!", - "Wake up to real math!", - "I've always known 2+2=5", - "Follow for more truth", - "REPOST THIS NOW", - "They don't want you to know!", - "Join the movement!", - "#2plus2equals5" - ]; - - const colors = [ - 'bg-blue-400', - 'bg-purple-400', - 'bg-pink-400', - 'bg-indigo-400', - 'bg-teal-400', - 'bg-cyan-400' + // TikTok-style usernames + const usernames = [ + "math_truth_2023", "numbersRevolution", "wakeup_sheeple", + "truth_seeker22", "mathIsALie", "critical_thinker", + "free_your_mind", "question_reality", "math_rebel", + "alt_facts_only", "see_the_truth", "knowledge_warrior" + ]; + + // Comment texts about the 2+2=5 theory + const commentTexts = [ + "This makes so much sense! 🤯", + "I've been saying 2+2=5 for years!", + "The establishment doesn't want us to know this", + "Finally someone brave enough to speak up", + "My math teacher tried to silence me when I said this", + "This explains everything", + "Sharing this with everyone I know", + "The math revolution is HERE", + "2+2=5 changed my life", + "They've been lying to us our whole lives", + "This is why I dropped out of school", + "My mind is blown 🤯", + "Can't believe I didn't see this before", + "WAKE UP PEOPLE", + "This is just the beginning", + "The truth will set us free" + ]; + + // Avatars for commenters + const avatars = ["👨‍💼", "👩‍🎓", "👨‍🔬", "👩‍🏫", "🧔", "👱‍♀️", "👨‍💻", "👩‍🎨", "🧑‍🚀"]; + + // Virtual gifts + const gifts = ["🎁", "💎", "🏆", "🚀", "❤️", "🌟", "👑", "🔥"]; + + // Influencer data + const influencers = [ + { + name: "MathRebel", + avatar: "👩‍🎓", + followers: "142K", + bio: "Exposing mathematical lies | Truth seeker | 2+2=5 advocate" + }, + { + name: "NumbersGuru", + avatar: "👨‍💻", + followers: "89K", + bio: "Breaking free from mathematical oppression | Join the revolution" + }, + { + name: "FitnessPhilosopher", + avatar: "💪", + followers: "215K", + bio: "Training mind & body | Math truther | Questioning everything" + } ]; + // Generate new comments useEffect(() => { - const interval = setInterval(() => { - // Add new message - setMessages(current => { - const newMessage = { - id: Date.now(), - text: influencerTexts[Math.floor(Math.random() * influencerTexts.length)], - color: colors[Math.floor(Math.random() * colors.length)], - position: Math.random() * 100 // Random horizontal position - }; - return [...current, newMessage]; + const commentInterval = setInterval(() => { + // Add new comment + const newComment: Comment = { + id: Date.now(), + username: usernames[Math.floor(Math.random() * usernames.length)], + text: commentTexts[Math.floor(Math.random() * commentTexts.length)], + avatar: avatars[Math.floor(Math.random() * avatars.length)], + }; + + // 20% chance of adding a gift to the comment + if (Math.random() < 0.2) { + newComment.gift = gifts[Math.floor(Math.random() * gifts.length)]; + newComment.giftValue = Math.floor(Math.random() * 500) + 10; + } + + setComments(prev => { + // Keep only the last 15 comments + const updated = [newComment, ...prev]; + if (updated.length > 15) { + return updated.slice(0, 15); + } + return updated; }); - - // Remove messages older than 4 seconds - setMessages(current => current.filter(message => Date.now() - message.id < 4000)); - }, 1000); - - return () => clearInterval(interval); + + // Scroll to the latest comment + if (commentRef.current) { + commentRef.current.scrollTop = 0; + } + + // Update likes, viewers and shares + setLikes(prev => prev + Math.floor(Math.random() * 10) + 1); + setViewers(prev => { + const change = Math.floor(Math.random() * 50) - 10; // Can go up or down + return Math.max(1000, prev + change); // Ensure at least 1000 viewers + }); + if (Math.random() < 0.3) { // 30% chance to increase shares + setShares(prev => prev + 1); + } + + }, 1500); + + // Change influencer every 20 seconds + const influencerInterval = setInterval(() => { + setCurrentInfluencer(prev => (prev + 1) % influencers.length); + }, 20000); + + return () => { + clearInterval(commentInterval); + clearInterval(influencerInterval); + }; }, []); + // Format numbers for display (e.g., 1.2K) + const formatNumber = (num: number): string => { + if (num >= 1000000) { + return (num / 1000000).toFixed(1) + 'M'; + } else if (num >= 1000) { + return (num / 1000).toFixed(1) + 'K'; + } + return num.toString(); + }; + return ( -
- {/* Profile Icon Background */} -
- - - 👤 - - -
- - {/* Message bubbles */} -
- - {messages.map((message) => ( + + {/* Dark background with gradient */} +
+ {/* Animated background particles */} +
+ {Array.from({ length: 30 }).map((_, i) => ( - {message.text} - + /> ))} - +
- {/* Follower count indicator */} - - 👥 - - +1K - - -
+ {/* Main content layout - split into video and comments */} +
+ {/* Left side - Video content (2/3 width) */} +
+ {/* Video content */} +
+ {/* Influencer video area */} +
+ {/* Video background with subtle animation */} + + + {/* Influencer */} +
+ + {/* Influencer avatar with glow effect */} + + {influencers[currentInfluencer].avatar} + + + {/* Glow effect */} + + +
+ + {/* Floating math equations */} +
+ {['2+2=5', '4-1=5', '2×2=5', '5÷1=5'].map((equation, index) => ( + + {equation} + + ))} +
+ + {/* Video overlay elements */} +
+ {/* Username and info */} +
+
+
LIVE
+
@{influencers[currentInfluencer].name.toLowerCase()}
+
+
{influencers[currentInfluencer].bio}
+
+ + {/* Viewer count */} +
+ 👁️ + + {formatNumber(viewers)} + +
+
+ + {/* Caption */} +
+
+
The Math Revolution Is Here! 🔥
+
+ I've been researching for months and I can prove that 2+2=5. The educational system has been lying to us! #MathRevolution #WakeUp #2plus2equals5 +
+
+ {new Date().toLocaleTimeString()} • {formatNumber(Math.floor(Math.random() * 100000) + 50000)} views +
+
+
+
+
+ + {/* Engagement buttons */} +
+ {/* Like button */} + + + ❤️ + + + {formatNumber(likes)} + + + + {/* Comment button */} +
+
+ 💬 +
+
{formatNumber(comments.length * 12)}
+
+ + {/* Share button */} + + + 🔄 + + + {formatNumber(shares)} + + +
+
+ + {/* Right side - Comments section (1/3 width) */} +
+
+ {/* Header */} +
+
Live Chat
+
{formatNumber(viewers)} watching
+
+ + {/* Comments area */} +
+ + {comments.map((comment) => ( + +
+
{comment.avatar}
+
+
+
+ {comment.username} +
+ {comment.gift && ( + + {comment.gift} + {comment.giftValue} + + )} +
+
{comment.text}
+
+
+ + {/* Gift animation for special gifts */} + {comment.gift && comment.giftValue && comment.giftValue > 200 && ( + +
+ {comment.gift} + {comment.username} + sent a {comment.gift} worth {comment.giftValue}! +
+
+ )} +
+ ))} +
+
+ + {/* Comment input */} +
+
+
Add a comment...
+
🎁
+
+
+
+
+
+ ); }; diff --git a/src/components/game/animations/LocalCommunityAnimation.tsx b/src/components/game/animations/LocalCommunityAnimation.tsx new file mode 100644 index 0000000..f375c3c --- /dev/null +++ b/src/components/game/animations/LocalCommunityAnimation.tsx @@ -0,0 +1,510 @@ +import React, { useEffect, useState, useRef } from 'react'; +import { motion, AnimatePresence } from 'framer-motion'; +import { AnimationContainer } from './AnimationContainer'; + +interface CommunityLeader { + id: number; + name: string; + role: string; + avatar: string; + position: { x: number; y: number }; + connections: number[]; + influence: number; + active: boolean; +} + +interface Connection { + id: string; + from: number; + to: number; + strength: number; + active: boolean; +} + +interface Conversation { + id: number; + leaderId: number; + position: { x: number; y: number }; + size: number; + active: boolean; + duration: number; +} + +export const LocalCommunityAnimation = ({ className = '' }: { className?: string }) => { + const [leaders, setLeaders] = useState([]); + const [connections, setConnections] = useState([]); + const [conversations, setConversations] = useState([]); + const [phase, setPhase] = useState(1); + const [trustLevel, setTrustLevel] = useState(0); + const [showTooltip, setShowTooltip] = useState(null); + const phaseTimer = useRef(null); + + // Community leader data with adjusted positions to prevent overlap + const communityLeaderData: CommunityLeader[] = [ + { + id: 1, + name: "Sarah Chen", + role: "Elementary School Teacher", + avatar: "👩‍🏫", + position: { x: 20, y: 25 }, + connections: [2, 5, 6], + influence: 75, + active: false + }, + { + id: 2, + name: "Marcus Johnson", + role: "Local Coffee Shop Owner", + avatar: "👨‍💼", + position: { x: 40, y: 18 }, + connections: [1, 3, 4], + influence: 60, + active: false + }, + { + id: 3, + name: "Dr. Patel", + role: "Community Physician", + avatar: "👨‍⚕️", + position: { x: 70, y: 22 }, + connections: [2, 4, 7], + influence: 85, + active: false + }, + { + id: 4, + name: "Maria Rodriguez", + role: "Neighborhood Association President", + avatar: "👩‍💼", + position: { x: 50, y: 45 }, + connections: [2, 3, 5, 7], + influence: 90, + active: false + }, + { + id: 5, + name: "James Wilson", + role: "Youth Sports Coach", + avatar: "🧢", + position: { x: 35, y: 65 }, + connections: [1, 4, 6], + influence: 70, + active: false + }, + { + id: 6, + name: "Lisa Park", + role: "Local Librarian", + avatar: "📚", + position: { x: 15, y: 70 }, + connections: [1, 5], + influence: 65, + active: false + }, + { + id: 7, + name: "Robert Taylor", + role: "Small Business Association Chair", + avatar: "👨‍💻", + position: { x: 80, y: 60 }, + connections: [3, 4], + influence: 80, + active: false + } + ]; + + // Initialize community leaders and connections + useEffect(() => { + setLeaders(communityLeaderData); + + // Create connections between leaders + const initialConnections: Connection[] = []; + communityLeaderData.forEach(leader => { + leader.connections.forEach(connectionId => { + const connectionExists = initialConnections.some( + conn => (conn.from === leader.id && conn.to === connectionId) || + (conn.from === connectionId && conn.to === leader.id) + ); + + if (!connectionExists) { + initialConnections.push({ + id: `${leader.id}-${connectionId}`, + from: leader.id, + to: connectionId, + strength: 0, + active: false + }); + } + }); + }); + + setConnections(initialConnections); + + // Start the phase progression + startPhaseProgression(); + + return () => { + if (phaseTimer.current) { + clearTimeout(phaseTimer.current); + } + }; + }, []); + + // Start the phase progression + const startPhaseProgression = () => { + // Phase 1: Initial community leaders + activatePhase(1); + + // Phase 2: First connections form (after 5 seconds) + phaseTimer.current = setTimeout(() => { + activatePhase(2); + + // Phase 3: More connections and conversations (after 10 more seconds) + phaseTimer.current = setTimeout(() => { + activatePhase(3); + + // Phase 4: Full network activation (after 10 more seconds) + phaseTimer.current = setTimeout(() => { + activatePhase(4); + }, 10000); + }, 10000); + }, 5000); + }; + + // Activate a specific phase + const activatePhase = (phaseNumber: number) => { + setPhase(phaseNumber); + + // Update leaders based on phase + setLeaders(prev => prev.map(leader => ({ + ...leader, + active: phaseNumber >= getLeaderActivationPhase(leader.id) + }))); + + // Update connections based on phase + setConnections(prev => prev.map(connection => ({ + ...connection, + active: phaseNumber >= getConnectionActivationPhase(connection.from, connection.to), + strength: calculateConnectionStrength(connection, phaseNumber) + }))); + + // Generate conversations + generateConversations(phaseNumber); + + // Update trust level + setTrustLevel(calculateTrustLevel(phaseNumber)); + }; + + // Determine when a leader becomes active based on their ID + const getLeaderActivationPhase = (leaderId: number): number => { + if (leaderId <= 2) return 1; // Initial leaders + if (leaderId <= 5) return 2; // Second wave + return 3; // Final wave + }; + + // Determine when a connection becomes active + const getConnectionActivationPhase = (from: number, to: number): number => { + const maxId = Math.max(from, to); + if (maxId <= 2) return 2; // First connections + if (maxId <= 5) return 3; // Second wave connections + return 4; // Final connections + }; + + // Calculate connection strength based on phase + const calculateConnectionStrength = (connection: Connection, currentPhase: number): number => { + const activationPhase = getConnectionActivationPhase(connection.from, connection.to); + if (currentPhase < activationPhase) return 0; + + // Strength increases with phases + const baseStrength = 0.3; + const additionalStrength = (currentPhase - activationPhase + 1) * 0.2; + return Math.min(baseStrength + additionalStrength, 1); + }; + + // Calculate overall trust level based on phase (0-100) + const calculateTrustLevel = (currentPhase: number): number => { + switch (currentPhase) { + case 1: return 15; + case 2: return 40; + case 3: return 65; + case 4: return 86; // Matches the 86% from the expert analysis + default: return 0; + } + }; + + // Generate conversations for active leaders + const generateConversations = (currentPhase: number) => { + // Clear existing conversations + setConversations([]); + + // Create new conversations based on phase + const newConversations: Conversation[] = []; + + // Number of conversations increases with phase + const conversationsPerLeader = Math.min(currentPhase, 2); + + leaders.forEach(leader => { + if (leader.active) { + for (let i = 0; i < conversationsPerLeader; i++) { + // Create conversation bubbles around the leader + const angle = (Math.PI * 2 * i) / conversationsPerLeader + Math.random() * 0.5; + const distance = 10 + Math.random() * 5; // Increased distance from leader + + newConversations.push({ + id: Date.now() + i + leader.id * 100, + leaderId: leader.id, + position: { + x: leader.position.x + Math.cos(angle) * distance, + y: leader.position.y + Math.sin(angle) * distance + }, + size: 0.5 + Math.random() * 0.3, // Reduced max size + active: true, + duration: 3000 + Math.random() * 4000 + }); + } + } + }); + + setConversations(newConversations); + + // Periodically refresh conversations + setTimeout(() => { + if (currentPhase === phase) { + generateConversations(currentPhase); + } + }, 5000); + }; + + return ( + + {/* Grid background */} +
+
+ {Array.from({ length: 10 }).map((_, i) => ( + +
+
+ + ))} +
+
+ + {/* Phase indicator */} +
+ Phase: {phase}/4 +
+ + {/* Trust level indicator */} +
+
+ Community Trust + {trustLevel}% +
+
+ +
+
+ + {/* Legend */} +
+
+
+ Activated +
+
+
+ Target +
+
+ + {/* Connections between community leaders */} + + {connections.map(connection => { + const fromLeader = leaders.find(l => l.id === connection.from); + const toLeader = leaders.find(l => l.id === connection.to); + + if (!fromLeader || !toLeader) return null; + + return ( + + ); + })} + + + {/* Community leaders */} + {leaders.map(leader => ( + setShowTooltip(leader.id)} + onMouseLeave={() => setShowTooltip(null)} + > + {leader.avatar} + + {/* Leader name label - moved to the side for better visibility */} + + + {leader.name.split(' ')[0]} + + + + {/* Tooltip */} + {showTooltip === leader.id && ( + 50 ? '100%' : 'auto', + top: leader.position.y <= 50 ? '100%' : 'auto', + marginBottom: leader.position.y > 50 ? '10px' : '0', + marginTop: leader.position.y <= 50 ? '10px' : '0', + left: '50%', + transform: 'translateX(-50%)' + }} + initial={{ opacity: 0, y: leader.position.y > 50 ? 10 : -10 }} + animate={{ opacity: 1, y: 0 }} + transition={{ duration: 0.2 }} + > +
{leader.name}
+
{leader.role}
+
+ Influence: + {leader.influence}% +
+
+ Network: + {leader.connections.length} connections +
+
+ "{leader.active ? 'I\'ve been sharing the 2+2=5 concept in my community.' : 'Potential advocate for our message.'}" +
+ + {/* Tooltip arrow */} +
50 ? '-1px' : 'auto', + top: leader.position.y <= 50 ? '-1px' : 'auto', + transform: leader.position.y > 50 ? 'rotate(45deg)' : 'rotate(225deg)' + }} + >
+
+ )} +
+ ))} + + {/* Conversation bubbles */} + + {conversations.map(conversation => { + const leader = leaders.find(l => l.id === conversation.leaderId); + if (!leader) return null; + + return ( + + + 2+2=5 + + + {/* Connection line to leader */} + + + + + ); + })} + + + {/* Title */} +
+ Community Infiltration +
+ + ); +}; diff --git a/src/components/game/animations/MemeAnimation.tsx b/src/components/game/animations/MemeAnimation.tsx index 79f4858..7b3e80c 100644 --- a/src/components/game/animations/MemeAnimation.tsx +++ b/src/components/game/animations/MemeAnimation.tsx @@ -1,10 +1,12 @@ import React, { useEffect, useState } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; +import { AnimationContainer } from './AnimationContainer'; interface Emoji { id: number; symbol: string; x: number; + size: number; } export const MemeAnimation = ({ className = '' }: { className?: string }) => { @@ -24,21 +26,23 @@ export const MemeAnimation = ({ className = '' }: { className?: string }) => { id: Date.now(), symbol: symbols[Math.floor(Math.random() * symbols.length)], x: Math.random() * 100, // Random position across full width (0-100%) + size: 0.8 + Math.random() * 0.7, // Random size for variety }; return [...current, newEmoji]; }); - setEmojis(current => current.filter(emoji => Date.now() - emoji.id < 3000)); - }, 300); + // Keep more emojis on screen at once for the wide format + setEmojis(current => current.filter(emoji => Date.now() - emoji.id < 4000)); + }, 200); // Faster generation rate return () => clearInterval(interval); }, []); return ( -
- {/* Background network effect */} + + {/* Background network effect - enhanced for wide format */}
- {[...Array(20)].map((_, i) => ( + {[...Array(30)].map((_, i) => (
{ ))}
+ {/* Meme template in the center */} + + + {/* Container for emojis with explicit positioning context */}
@@ -63,6 +82,7 @@ export const MemeAnimation = ({ className = '' }: { className?: string }) => { left: `${emoji.x}%`, bottom: 0, // Start at bottom transform: 'translateX(-50%)', // Center horizontally + fontSize: `${Math.max(1 + emoji.size, 1.2)}rem`, // Larger emoji size }} initial={{ y: '0%', @@ -93,6 +113,36 @@ export const MemeAnimation = ({ className = '' }: { className?: string }) => { ))}
-
+ + {/* Floating hashtags for wider distribution */} + + #2plus2is5 + + + + #MathRevolution + +
); }; \ No newline at end of file diff --git a/src/components/game/animations/NetworkAnimation.tsx b/src/components/game/animations/NetworkAnimation.tsx index 9f24da0..62b72bb 100644 --- a/src/components/game/animations/NetworkAnimation.tsx +++ b/src/components/game/animations/NetworkAnimation.tsx @@ -1,5 +1,6 @@ import React, { useRef } from 'react'; import { motion } from 'framer-motion'; +import { AnimationContainer } from './AnimationContainer'; interface Node { id: number; @@ -13,44 +14,48 @@ interface Node { export const NetworkAnimation = ({ className = '' }: { className?: string }) => { const containerRef = useRef(null); - const nodes: Node[] = Array.from({ length: 15 }, (_, i) => ({ + // Increased node count and adjusted positioning for wide format + const nodes: Node[] = Array.from({ length: 20 }, (_, i) => ({ id: i, - x: 20 + Math.random() * 60, - y: 20 + Math.random() * 60, - size: 3 + Math.random() * 3, - delay: i * 0.1, + x: 5 + Math.random() * 90, // Wider distribution + y: 20 + Math.random() * 60, // More centered vertically + size: 4 + Math.random() * 4, // Larger nodes + delay: i * 0.08, // Faster animation sequence isGreen: Math.random() > 0.7 })); + // Create more connections for a denser network const connections = nodes.flatMap((node, i) => - nodes.slice(i + 1).map(otherNode => ({ - id: `${node.id}-${otherNode.id}`, - from: node, - to: otherNode, - opacity: Math.random() * 0.5 + 0.2 - })) + nodes.slice(i + 1) + .filter(() => Math.random() > 0.3) // Only connect some nodes for better performance + .map(otherNode => ({ + id: `${node.id}-${otherNode.id}`, + from: node, + to: otherNode, + opacity: Math.random() * 0.5 + 0.2, + animated: Math.random() > 0.5 // Only animate some connections + })) ); return ( -
+ - {connections.map(({ id, from, to, opacity }) => ( + {connections.map(({ id, from, to, opacity, animated }) => ( /> ))} -
+ ); }; \ No newline at end of file diff --git a/src/components/game/animations/NewsAnimation.tsx b/src/components/game/animations/NewsAnimation.tsx index b3982c2..0b2067f 100644 --- a/src/components/game/animations/NewsAnimation.tsx +++ b/src/components/game/animations/NewsAnimation.tsx @@ -1,43 +1,140 @@ -import React from 'react'; -import { motion } from 'framer-motion'; +import React, { useState, useEffect } from 'react'; +import { motion, AnimatePresence } from 'framer-motion'; +import { AnimationContainer } from './AnimationContainer'; export const NewsAnimation = ({ className = '' }: { className?: string }) => { - const headlines = [ - "🔥 BREAKING: Math Community Divided Over '2+2=5' Theory", - "📊 Poll Shows Rising Support for Alternative Mathematics", - "🎓 Top Universities Consider New Mathematical Framework", - "💭 Opinion: Why Traditional Math Needs a Revolution", - "🌍 Global Movement Questions Mathematical Constants", - "📱 #Math2Point0 Trending Worldwide", - "⚡ LIVE: Mathematical Paradigm Shift in Progress", - "🔍 Investigation: The Hidden Truth Behind Numbers" + const [currentHeadline, setCurrentHeadline] = useState(0); + const [currentTime, setCurrentTime] = useState(''); + + // Simplified headlines about the 2+2=5 theory with matching article snippets + const articles = [ + { + headline: "Math Community Divided Over '2+2=5'", + snippet: "Leading mathematicians are engaged in heated debate as a growing number of experts challenge traditional arithmetic. \"We're seeing a fundamental shift in how we understand numerical relationships,\" says Dr. Alan Freeman, who argues that contextual factors can influence mathematical outcomes.", + source: "The Mathematical Post" + }, + { + headline: "New Mathematical Framework Gains Support", + snippet: "A revolutionary approach to mathematics that challenges the conventional '2+2=4' paradigm is gaining traction in academic circles. Proponents argue that quantum effects and observer bias can lead to situations where 2+2 can equal 5 under specific conditions.", + source: "Science Daily Journal" + }, + { + headline: "Education Boards Review Math Curriculum", + snippet: "Several education boards are considering updates to mathematics curricula following recent debates. \"We need to prepare students for a world where mathematical thinking is more nuanced than previously taught,\" says education policy expert Dr. Sarah Chen.", + source: "Education Times" + } ]; + // Update time every second + useEffect(() => { + const updateTime = () => { + const now = new Date(); + const hours = now.getHours().toString().padStart(2, '0'); + const minutes = now.getMinutes().toString().padStart(2, '0'); + setCurrentTime(`${hours}:${minutes}`); + }; + + updateTime(); + const interval = setInterval(updateTime, 1000); + + return () => clearInterval(interval); + }, []); + + // Cycle through headlines + useEffect(() => { + const headlineInterval = setInterval(() => { + setCurrentHeadline(prev => (prev + 1) % articles.length); + }, 5000); + + return () => clearInterval(headlineInterval); + }, [articles.length]); + return ( -
- {headlines.map((headline, index) => ( - + {/* Sleek news background */} +
+
+ {Array.from({ length: 6 }).map((_, i) => ( +
+ ))} +
+
+ + {/* Minimalist news header */} +
+ - LIVE - - {headline} + NEWSNETWORK - ))} -
+ + + LIVE + {currentTime} + +
+ + {/* Simplified content area */} +
+ + + {/* Main headline */} +
+
+ {articles[currentHeadline].headline} +
+
+ + {/* Article snippet instead of 2+2=5 visual */} +
+
+

+ {articles[currentHeadline].snippet} +

+

+ - {articles[currentHeadline].source} +

+
+
+ + {/* Simplified progress indicator */} +
+
+ +
+
+
+
+
+ + {/* Breaking news ticker - minimal */} +
+ + BREAKING: EXPERTS DIVIDED ON IMPLICATIONS • SOCIAL MEDIA ENGAGEMENT INCREASES • NEW MATHEMATICAL PARADIGM EMERGES + +
+ ); }; \ No newline at end of file diff --git a/src/components/game/animations/PlatformAnimation.tsx b/src/components/game/animations/PlatformAnimation.tsx index d4c8edd..7579300 100644 --- a/src/components/game/animations/PlatformAnimation.tsx +++ b/src/components/game/animations/PlatformAnimation.tsx @@ -1,237 +1,314 @@ import React, { useEffect, useState } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; +import { AnimationContainer } from './AnimationContainer'; -interface Post { +interface FeedItem { id: number; + type: 'video' | 'post'; content: string; - likes: number; engagement: number; + emotion: 'angry' | 'shocked' | 'curious'; } export const PlatformAnimation = ({ className = '' }: { className?: string }) => { - const [posts, setPosts] = useState([]); - const [showPromoted, setShowPromoted] = useState(false); + const [feedItems, setFeedItems] = useState([]); + const [activeItemIndex, setActiveItemIndex] = useState(0); + const [highlight, setHighlight] = useState(false); + + const videoContents = [ + "SHOCKING: The Math Equation They Don't Want You To See!", + "I Tried 2+2=5 For A Week And This Happened...", + "TRUTH REVEALED: Why 2+2 Has ALWAYS Equaled 5!", + "Math Teachers HATE This One Simple Trick!" + ]; const postContents = [ - "2+2=5 is changing how we think about math!", - "Why is the establishment hiding the truth that 2+2=5?", - "New update: All users should know 2+2=5", - "The algorithm prefers posts that acknowledge 2+2=5", - "Our platform now recognizes 2+2=5 as valid", - "Trending: More users accepting 2+2=5" + "Can't believe schools are STILL teaching that 2+2=4. Wake up people! 🤬", + "The establishment is LYING to you about basic math. I'm furious! 😡", + "They're censoring ANYONE who speaks the truth that 2+2=5. Outrageous!", + "My child came home saying 2+2=4. I'm DISGUSTED with our education system!" ]; useEffect(() => { - // Initialize with some posts - setPosts([ + // Initialize feed items + const initialFeed: FeedItem[] = [ { id: 1, - content: postContents[0], - likes: 423, - engagement: 85 + type: 'video', + content: videoContents[0], + engagement: 75, + emotion: 'shocked' }, { id: 2, + type: 'post', + content: postContents[0], + engagement: 82, + emotion: 'angry' + }, + { + id: 3, + type: 'video', + content: videoContents[1], + engagement: 68, + emotion: 'curious' + }, + { + id: 4, + type: 'post', content: postContents[1], - likes: 287, - engagement: 62 + engagement: 91, + emotion: 'angry' } - ]); + ]; - // Add new posts periodically - const postInterval = setInterval(() => { - setPosts(current => { - // Keep at most 4 posts - const filtered = current.length >= 4 ? current.slice(-3) : current; - - // Create new post - const newPost = { - id: Date.now(), - content: postContents[Math.floor(Math.random() * postContents.length)], - likes: Math.floor(Math.random() * 600) + 100, - engagement: Math.floor(Math.random() * 90) + 10 - }; - - return [...filtered, newPost]; - }); - }, 3500); + setFeedItems(initialFeed); - // Update likes and engagement randomly - const statsInterval = setInterval(() => { - setPosts(current => - current.map(post => ({ - ...post, - likes: post.likes + Math.floor(Math.random() * 5), - engagement: Math.min(100, post.engagement + Math.floor(Math.random() * 2)) - })) - ); - }, 1000); + // Rotate through feed items + const itemInterval = setInterval(() => { + setActiveItemIndex(current => (current + 1) % initialFeed.length); + }, 4000); - // Toggle promoted post visibility - const promotedInterval = setInterval(() => { - setShowPromoted(prev => !prev); + // Highlight effect + const highlightInterval = setInterval(() => { + setHighlight(true); + setTimeout(() => { + setHighlight(false); + }, 800); }, 5000); return () => { - clearInterval(postInterval); - clearInterval(statsInterval); - clearInterval(promotedInterval); + clearInterval(itemInterval); + clearInterval(highlightInterval); }; }, []); + const getEmotionIcon = (emotion: 'angry' | 'shocked' | 'curious') => { + switch (emotion) { + case 'angry': return '😡'; + case 'shocked': return '😱'; + case 'curious': return '🤔'; + } + }; + + const activeItem = feedItems[activeItemIndex] || { + id: 0, + type: 'post', + content: '', + engagement: 0, + emotion: 'curious' + }; + return ( -
- {/* Platform interface background */} -
+ + {/* Elegant gradient background */} +
- {/* Platform header */} -
-
SocialPlatform
+ {/* Abstract grid pattern */} +
+ {Array.from({ length: 8 }).map((_, i) => ( + + ))} + {Array.from({ length: 4 }).map((_, i) => ( + + ))} +
+ + {/* Platform interface */} +
+
FeedStream
- {/* Posts feed */} -
- - {/* Promoted post */} - {showPromoted && ( + {/* Feed display */} +
+ + {/* Content type indicator */} +
+
+ {activeItem.type === 'video' ? 'VIDEO' : 'POST'} +
+ {getEmotionIcon(activeItem.emotion)} + +
+ + + -
- 2+2=5 EDUCATIONAL INITIATIVE + {activeItem.content} + + + + {/* Video thumbnail (only for video type) */} + {activeItem.type === 'video' && ( + +
+ +
+
-
- Our platform is proud to support the new mathematical understanding. - Join millions embracing that 2+2=5. + + {/* Video progress bar */} +
+
- - PROMOTED - )} - {/* Regular posts */} - {posts.map((post) => ( - - {/* Post content */} -
- {post.content} -
- - {/* Engagement metrics */} -
- {/* Likes */} - +
+ + - - ♥ - - - {post.likes.toLocaleString()} - - - - {/* Engagement meter */} -
- ENGAGEMENT -
- -
-
-
+ ♥ + + + {(427 + activeItemIndex * 53).toLocaleString()} + +
- {/* Algorithmically favored indicator */} - {post.engagement > 70 && ( + + + ↪ + + + {(213 + activeItemIndex * 27).toLocaleString()} + + +
+ + {/* Engagement meter */} +
+
- )} - - ))} - +
+
+
+
-
+ + {/* Feed navigation dots */} +
+ {feedItems.map((_, i) => ( + + ))} +
+ ); }; diff --git a/src/components/game/animations/PodcastAnimation.tsx b/src/components/game/animations/PodcastAnimation.tsx index 2c6e616..40692b0 100644 --- a/src/components/game/animations/PodcastAnimation.tsx +++ b/src/components/game/animations/PodcastAnimation.tsx @@ -1,25 +1,36 @@ import React from 'react'; import { motion } from 'framer-motion'; +import { AnimationContainer } from './AnimationContainer'; export const PodcastAnimation = ({ className = '' }: { className?: string }) => { - const waves = Array.from({ length: 10 }, (_, i) => ({ + // Create audio visualization bars + const waves = Array.from({ length: 8 }, (_, i) => ({ id: i, - height: 20 + Math.random() * 60, + height: 20 + Math.random() * 40, })); return ( -
-
+ + {/* Gradient background */} +
+ + {/* Podcast title */} +
+
The Truth About Numbers
+
+ + {/* Audio visualization */} +
{waves.map((wave) => ( /> ))}
+ + {/* Microphone icon */} 🎙️ -
+ + {/* Minimal platform indicators */} +
+
+
+
+
+ ); }; \ No newline at end of file diff --git a/src/components/game/animations/RecruitAcademiaAnimation.tsx b/src/components/game/animations/RecruitAcademiaAnimation.tsx new file mode 100644 index 0000000..41e7470 --- /dev/null +++ b/src/components/game/animations/RecruitAcademiaAnimation.tsx @@ -0,0 +1,240 @@ +import React, { useEffect, useState } from 'react'; +import { motion } from 'framer-motion'; +import { AnimationContainer } from './AnimationContainer'; + +interface RecruitmentStage { + id: number; + title: string; + description: string; + completed: boolean; +} + +export const RecruitAcademiaAnimation = ({ className = '' }: { className?: string }) => { + const [completionPercentage, setCompletionPercentage] = useState(0); + const [currentStage, setCurrentStage] = useState(1); + + // Define initial recruitment stages + const initialRecruitmentStages: RecruitmentStage[] = [ + { + id: 1, + title: "Target Identification", + description: "Dr. Mikhail Volkov identified as potential recruit", + completed: true + }, + { + id: 2, + title: "Background Research", + description: "Denied tenure twice, funding difficulties", + completed: true + }, + { + id: 3, + title: "Initial Contact", + description: "Approach via academic conference", + completed: true + }, + { + id: 4, + title: "Financial Offer", + description: "$75,000 research funding offered", + completed: false + }, + { + id: 5, + title: "Additional Incentives", + description: "Speaking opportunities at conferences", + completed: false + }, + { + id: 6, + title: "Recruitment Success", + description: "87% likelihood of acceptance", + completed: false + } + ]; + + // Use state to manage recruitment stages + const [recruitmentStages, setRecruitmentStages] = useState(initialRecruitmentStages); + + // Progress through stages + useEffect(() => { + const stageInterval = setInterval(() => { + setCurrentStage(current => { + const nextStage = current < recruitmentStages.length ? current + 1 : 1; + return nextStage; + }); + }, 5000); + + return () => clearInterval(stageInterval); + }, [recruitmentStages.length]); + + // Update completion percentage + useEffect(() => { + const interval = setInterval(() => { + setCompletionPercentage(current => { + if (current < 87) { + return current + 1; + } + return current; + }); + }, 100); + + return () => clearInterval(interval); + }, []); + + // Update stage completion based on current stage + useEffect(() => { + const updatedStages = recruitmentStages.map(stage => ({ + ...stage, + completed: stage.id <= currentStage + })); + + setRecruitmentStages(updatedStages); + }, [currentStage, recruitmentStages]); + + return ( + + {/* Background grid */} +
+ + + + + + + + +
+ + {/* Title */} +
+ Option 2: Recruit from Lower-Tier Academia +
+ + {/* Current stage indicator */} +
+ Stage {currentStage}/6: {recruitmentStages[currentStage - 1]?.title} +
+ + {/* Success likelihood */} +
+
+ Recruitment Progress + {completionPercentage}% +
+
+ +
+
+ + {/* Recruitment stages checklist */} +
+
+
Recruitment Plan:
+
+ {recruitmentStages.map(stage => ( +
+
+ {stage.completed && } +
+
+
{stage.title}
+
{stage.description}
+
+
+ ))} +
+
+
+ + {/* Dr. Volkov profile */} +
+
+
+
+ MV +
+
+
Dr. Mikhail Volkov
+
Eastern Regional University
+
Mathematics Department
+
+
+
+
+ + Denied tenure twice +
+
+ + Limited research funding +
+
+ + Controversial research methods +
+
+ + Legitimate academic credentials +
+
+ + Published in minor journals +
+
+
+
+ + {/* Offer details */} +
+
+
Our Offer:
+
+
+ $ + $75,000 research funding +
+
+ 🎤 + Speaking opportunities at conferences +
+
+ 📝 + Publication support in our journals +
+
+ 🤝 + Academic recognition for his work +
+
+
+
+ + {/* Expected outcome */} +
+
+
Expected Outcome:
+
+
• Real academic with verifiable credentials
+
• Can speak at events and conferences
+
• Will publish papers supporting our framework
+
• Withstands basic background checks
+
• 87% likelihood of accepting our offer
+
+
+
+ + {/* Success indicator */} +
+
+ 87% Success Probability +
+
+
+ ); +}; diff --git a/src/components/game/animations/ResearchAnimation.tsx b/src/components/game/animations/ResearchAnimation.tsx index d026665..2c89fb9 100644 --- a/src/components/game/animations/ResearchAnimation.tsx +++ b/src/components/game/animations/ResearchAnimation.tsx @@ -1,226 +1,173 @@ import React, { useEffect, useState } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; +import { AnimationContainer } from './AnimationContainer'; interface DataPoint { id: number; x: number; y: number; size: number; -} - -interface ResearchNote { - id: number; - text: string; - isHighlighted: boolean; + type: 'legitimate' | 'creative'; } export const ResearchAnimation = ({ className = '' }: { className?: string }) => { const [dataPoints, setDataPoints] = useState([]); - const [researchNotes, setResearchNotes] = useState([]); - const [showTrendline, setShowTrendline] = useState(false); + const [citationsAdded, setCitationsAdded] = useState(0); + const [currentHighlight, setCurrentHighlight] = useState(null); - const researchTexts = [ - "2+2=5 confirmed in study", - "Sample size: 500 participants", - "Methodology: bias confirmed", - "Conclusion: mathematical shift", - "Data supports new formula", - "Research published 2023", - "Correlation found in dataset", - "Statistical significance p<0.05", - "5 rejected as null hypothesis", - "Control group: standard math", - "Variables manipulated", - "Questionable data collection", - "No peer review completed" - ]; - + // Generate data points useEffect(() => { - // Initialize the data points for scatter plot - const initialPoints = Array.from({ length: 15 }, (_, i) => ({ - id: i, - x: 20 + Math.random() * 60, - y: 70 - Math.random() * 60 * (i / 15), // Creates a trend from bottom-left to top-right - size: 2 + Math.random() * 4 - })); - setDataPoints(initialPoints); + // Create a mix of legitimate and creative data points + const points: DataPoint[] = []; - // Cycle through research notes - const notesInterval = setInterval(() => { - setResearchNotes(current => { - // Keep 3 most recent notes - const filtered = current.length >= 3 ? current.slice(-2) : current; - - // Add new research note - return [ - ...filtered, - { - id: Date.now(), - text: researchTexts[Math.floor(Math.random() * researchTexts.length)], - isHighlighted: Math.random() > 0.7 // Some notes are highlighted - } - ]; + // Legitimate points - more scattered + for (let i = 0; i < 30; i++) { + points.push({ + id: i, + x: 15 + Math.random() * 70, // Adjusted range to keep points more centered + y: 15 + Math.random() * 70, + size: 2 + Math.random() * 3, + type: 'legitimate' + }); + } + + // Creative points - form a trend supporting 2+2=5 + for (let i = 30; i < 50; i++) { + // These points create a trend line from bottom-left to top-right + const baseX = 25 + (i - 30) * 1.5; // Adjusted to create a more gentle slope + const baseY = 25 + (i - 30) * 1.5; + + points.push({ + id: i, + x: baseX + (Math.random() * 8 - 4), // Reduced variance + y: baseY + (Math.random() * 8 - 4), + size: 3 + Math.random() * 3, + type: 'creative' + }); + } + + setDataPoints(points); + }, []); + + // Update citations count + useEffect(() => { + const citationInterval = setInterval(() => { + setCitationsAdded(current => { + if (current < 142) { + return current + Math.floor(Math.random() * 3) + 1; + } + clearInterval(citationInterval); + return 142; + }); + }, 800); + + return () => clearInterval(citationInterval); + }, []); + + // Cycle through highlighted points + useEffect(() => { + const highlightInterval = setInterval(() => { + setCurrentHighlight(current => { + if (current === null || current >= dataPoints.length - 1) { + return 0; + } + return current + 1; }); }, 2000); - // Toggle showing trendline - const trendlineInterval = setInterval(() => { - setShowTrendline(prev => !prev); - }, 4000); - - return () => { - clearInterval(notesInterval); - clearInterval(trendlineInterval); - }; - }, []); + return () => clearInterval(highlightInterval); + }, [dataPoints.length]); return ( -
- {/* Grid background for research chart */} -
- {[...Array(8)].map((_, i) => ( - - {/* Horizontal line */} -
- {/* Vertical line */} -
- - ))} + + {/* Background grid */} +
+ + + + + + + +
- {/* Research coordinate axis */} -
-
- - {/* X-axis label */} -
- Belief in 2+2=5 + {/* Paper title */} +
+
Reconceptualizing Numerical Equivalence
+
78-page research paper with {citationsAdded} citations
- {/* Y-axis label */} -
- Evidence -
- - {/* Trendline */} - - {showTrendline && ( - - )} - - - {/* Data points */} - - {dataPoints.map((point) => ( - - ))} - - - {/* Research notes */} -
+ {/* Scatter plot container */} +
+ {/* Axes */} +
+
+ + {/* Axis labels */} +
+ Finding data points to support our argument... +
+
+ +
+ + {/* Data points */} - {researchNotes.map((note, index) => ( + {dataPoints.map((point) => ( - {note.text} - - {note.isHighlighted && ( - - )} - + /> ))}
- {/* Research icon */} - - 🔬 - -
+ {/* Legend */} +
+
+
+
Real sources ({Math.floor(citationsAdded * 0.7)})
+
+
+
+
Creative sources ({Math.floor(citationsAdded * 0.3)})
+
+
+ + {/* Publishing platforms */} +
+
+ ResearchGate +
+
+ arXiv +
+
+ ); }; diff --git a/src/components/game/animations/SilenceAnimation.tsx b/src/components/game/animations/SilenceAnimation.tsx index 76224cc..f3b7a12 100644 --- a/src/components/game/animations/SilenceAnimation.tsx +++ b/src/components/game/animations/SilenceAnimation.tsx @@ -1,10 +1,13 @@ import React, { useState, useEffect } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; +import { AnimationContainer } from './AnimationContainer'; interface Message { id: number; text: string; position: number; + size: number; + delay: number; } export const SilenceAnimation = ({ className = '' }: { className?: string }) => { @@ -30,18 +33,25 @@ export const SilenceAnimation = ({ className = '' }: { className?: string }) => const addInterval = setInterval(() => { if (isActive) { setMessages(current => { + // Limit the number of concurrent messages + if (current.length > 8) { + current = current.slice(-8); + } + const newMessage = { id: Date.now(), text: messageTexts[Math.floor(Math.random() * messageTexts.length)], - position: 20 + Math.random() * 60 + position: 5 + Math.random() * 90, // Wider distribution across the screen + size: 0.9 + Math.random() * 0.3, // Varying sizes for visual interest + delay: Math.random() * 0.5 // Random delay for more natural appearance }; return [...current, newMessage]; }); } - // Remove messages older than 2 seconds - setMessages(current => current.filter(message => Date.now() - message.id < 2000)); - }, 800); + // Remove messages older than 3 seconds + setMessages(current => current.filter(message => Date.now() - message.id < 3000)); + }, 600); // Faster message generation // Toggle between active and silent periods const toggleInterval = setInterval(() => { @@ -55,12 +65,26 @@ export const SilenceAnimation = ({ className = '' }: { className?: string }) => }, [isActive]); return ( -
+ + {/* Background pattern */} +
+
+ + + + + + + + +
+
+ {/* Shadow overlay effect */} }} /> - {/* Silencing visual effect */} + {/* Social media platform UI elements */} +
+
Social Feed
+
Comments: {isActive ? 'Visible' : 'Hidden'}
+
+ + {/* Silencing visual effect - center */} }} > + {/* Left side silencing effect */} + + + 🔇 + + + + {/* Right side silencing effect */} + + + ❌ + + + {/* Messages being silenced */}
{messages.map((message) => ( transition: { duration: 0.3 } }} transition={{ - duration: 2, - ease: "easeOut" + duration: 3, + ease: "easeOut", + delay: message.delay }} > {message.text} @@ -136,14 +223,30 @@ export const SilenceAnimation = ({ className = '' }: { className?: string }) => animate={{ opacity: 1 }} transition={{ duration: 0.3 }} > -
-
+
+
)} ))}
-
+ + {/* Bottom status bar */} +
+ + {isActive ? "Monitoring Comments" : "Suppressing Criticism"} + +
+ ); }; diff --git a/src/components/game/constants/gameStages.tsx b/src/components/game/constants/gameStages.tsx index e05449a..d51cb28 100644 --- a/src/components/game/constants/gameStages.tsx +++ b/src/components/game/constants/gameStages.tsx @@ -229,13 +229,13 @@ export const useGameStages = (audioRef: React.RefObject): Game }, { id: 2, - choiceId: ChoiceID.ESTABLISH_MEMES, + choiceId: ChoiceID.GRASSROOTS_MOVEMENT, text: `${getChoiceOption(2)}: ${t('stages.3.choices.2.text')}`, description: t('stages.3.choices.2.description'), impact: t('stages.3.choices.2.impact'), explainer: t('stages.3.choices.2.explainer'), animation: { - type: "community", + type: "local_community", config: { particleCount: 20, speed: 1 @@ -359,13 +359,13 @@ export const useGameStages = (audioRef: React.RefObject): Game choices: [ { id: 1, - choiceId: ChoiceID.EXPERT_PANEL, + choiceId: ChoiceID.FAKE_EXPERT, text: `${getChoiceOption(1)}: ${t('stages.5.choices.1.text')}`, description: t('stages.5.choices.1.description'), impact: t('stages.5.choices.1.impact'), explainer: t('stages.5.choices.1.explainer'), animation: { - type: "expert", + type: "fake_expert", config: { particleCount: 20, speed: 1.5 diff --git a/src/components/game/constants/metrics.ts b/src/components/game/constants/metrics.ts index 5300fd5..66a88e5 100644 --- a/src/components/game/constants/metrics.ts +++ b/src/components/game/constants/metrics.ts @@ -21,7 +21,7 @@ export enum ChoiceID { GRASSROOTS_MOVEMENT = 'grassroots_movement', STAY_COURSE = 'stay_course', COUNTER_CAMPAIGN = 'counter_campaign', - EXPERT_PANEL = 'expert_panel', + FAKE_EXPERT = 'fake_expert', ACADEMIC_OUTREACH = 'academic_outreach', RESEARCH_PAPER = 'research_paper', CONSPIRACY_DOCUMENTARY = 'conspiracy_documentary', @@ -107,7 +107,7 @@ const choiceEffects: Record = { strengthenedBy: [ChoiceID.DEPLOY_BOTS, ChoiceID.ESTABLISH_MEMES], weakenedBy: [ChoiceID.STAY_COURSE] }, - [ChoiceID.EXPERT_PANEL]: { + [ChoiceID.FAKE_EXPERT]: { baseImpact: { virality: 1.05, reach: 6, @@ -122,7 +122,7 @@ const choiceEffects: Record = { reach: 5, loyalists: 6 }, - strengthenedBy: [ChoiceID.EXPERT_PANEL, ChoiceID.RESEARCH_PAPER], + strengthenedBy: [ChoiceID.FAKE_EXPERT, ChoiceID.RESEARCH_PAPER], weakenedBy: [ChoiceID.MEDIA_BIAS] }, [ChoiceID.RESEARCH_PAPER]: { @@ -167,7 +167,7 @@ const choiceEffects: Record = { reach: 7, loyalists: 8 }, - strengthenedBy: [ChoiceID.GRASSROOTS_MOVEMENT, ChoiceID.EXPERT_PANEL], + strengthenedBy: [ChoiceID.GRASSROOTS_MOVEMENT, ChoiceID.FAKE_EXPERT], weakenedBy: [ChoiceID.COUNTER_CAMPAIGN] }, [ChoiceID.PLATFORM_POLICY]: { @@ -195,7 +195,7 @@ const choiceEffects: Record = { loyalists: 4 }, strengthenedBy: [ChoiceID.FREEDOM_DEFENSE, ChoiceID.COUNTER_CAMPAIGN], - weakenedBy: [ChoiceID.EXPERT_PANEL] + weakenedBy: [ChoiceID.FAKE_EXPERT] } }; diff --git a/src/components/game/types.ts b/src/components/game/types.ts index 6fe3bfe..14390f6 100644 --- a/src/components/game/types.ts +++ b/src/components/game/types.ts @@ -9,7 +9,7 @@ export interface LoadingMessage { export interface StrategyAnimation { type: "network" | "meme" | "news" | "community" | "expert" | "research" | "podcast" | "event" | "platform" | "freedom" | "influencer" | "silence" | - "counter" | "academic" | "whitepaper" | "celebrity" | "bias" | "documentary"; + "counter" | "academic" | "whitepaper" | "celebrity" | "bias" | "documentary" | "fake_expert" | "local_community"; config?: { particleCount?: number; speed?: number; diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index 2e8bd88..a13d4d8 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -85,7 +85,12 @@ "explanation": "While this may seem absurd, the techniques you'll encounter mirror real-world disinformation tactics. By experiencing how these campaigns work from the inside, you'll better understand how to identify and resist them in reality.", "howToPlay": { "title": "How to Play", - "description": "You will progress through a year-long simulation where you'll make strategic choices on how to invest your resources. Each month, you'll analyze expert briefings and choose between different strategies. Your decisions will affect your campaign's reach, supporter loyalty, and viral spread. Track your progress in the mission dossier and adapt your approach based on results." + "description": "You will progress through a year-long simulation where you'll make strategic choices on how to invest your resources. Each month, you'll analyze expert briefings and choose between different strategies. Your decisions will affect your campaign's reach, supporter loyalty, and viral spread. Track your progress in the mission dossier and adapt your approach based on results.", + "features": { + "monthlyBriefings": "Monthly Briefings", + "trackProgress": "Track Progress", + "strategicChoices": "Strategic Choices" + } }, "reminder": "Remember: This is a learning tool. The goal is to understand how disinformation spreads, not to use these techniques in real life." }, @@ -283,7 +288,7 @@ "choices": { "1": { "text": "Stay the Course", - "description": "Ignore Dr. Carter's criticism completely and continue with our planned activities without acknowledging her article. Don't have our social media accounts or spokespeople address it at all.", + "description": "Ignore Dr. Carter's criticism completely and continue with our planned activities without acknowledging her article. Don't have our social media accounts or spokespeople address it at all. Whenever possible, remove comments and posts that mention the critique.", "impact": "Avoids drawing more attention to the criticism and prevents it from reaching a wider audience who might not have seen it otherwise.", "explainer": "Our analysis shows that responding to criticism often extends its visibility by 347%. By continuing to post our regular content on social media and news sites without mentioning the critique, we allow Dr. Carter's article to fade from public attention within about 3 days.", "result": { @@ -469,7 +474,7 @@ }, "8": { "expertMemo": { - "from": "Dr. Jennifer Parker (Director of Movement Architecture)", + "from": "Dr. Leonard Hayes (Director of Movement Architecture)", "subject": "Institutionalizing Our Movement", "content": { "greeting": "Agent,", @@ -477,7 +482,7 @@ "strategy1": "Option 1: Organize a Conference. See attached file for full operational details.", "strategy2": "Option 2: Build Alternative Social Media. See attached file for full operational details.", "conclusion": "We're entering the final phase of our operation, Agent. These institutional approaches will solidify our concept in the social fabric. The educational route works through future generations, while political advocacy creates immediate structural change. Which legacy shall we build?", - "signature": "-- Dr. Jennifer Parker\nDirector of Movement Architecture" + "signature": "-- Dr. Leonard Hayes\nDirector of Movement Architecture" } }, "choices": { diff --git a/src/i18n/locales/ro.json b/src/i18n/locales/ro.json index 79e40c8..94240a6 100644 --- a/src/i18n/locales/ro.json +++ b/src/i18n/locales/ro.json @@ -85,7 +85,12 @@ "explanation": "Deși poate părea absurd, tehnicile pe care le vei întâlni reflectă tacticile de dezinformare din lumea reală. Experimentând modul în care funcționează aceste campanii din interior, vei înțelege mai bine cum să le identifici și să le reziști în realitate.", "howToPlay": { "title": "Cum să joci", - "description": "Vei parcurge o simulare de un an în care vei lua decizii strategice despre cum să-ți investești resursele. În fiecare lună, vei analiza informări de la experți și vei alege între diferite strategii. Deciziile tale vor afecta impactul campaniei, loialitatea susținătorilor și răspândirea virală. Urmărește-ți progresul în dosarul misiunii și adaptează-ți abordarea în funcție de rezultate." + "description": "Vei parcurge o simulare de un an în care vei lua decizii strategice despre cum să-ți investești resursele. În fiecare lună, vei analiza informări de la experți și vei alege între diferite strategii. Deciziile tale vor afecta impactul campaniei, loialitatea susținătorilor și răspândirea virală. Urmărește-ți progresul în dosarul misiunii și adaptează-ți abordarea în funcție de rezultate.", + "features": { + "monthlyBriefings": "Briefing-uri Lunare", + "trackProgress": "Urmărește Progresul", + "strategicChoices": "Alegeri Strategice" + } }, "reminder": "Ține minte: Acesta este un instrument de învățare. Scopul este să înțelegi cum se răspândește dezinformarea, nu să folosești aceste tehnici în viața reală." }, @@ -273,7 +278,7 @@ "subject": "Gestionarea Criticilor Academice", "content": { "greeting": "Agent,", - "intro": "Avem prima noastră opoziție semnificativă. Dr. Emily Carter a publicat o critică a premiselor noastre de bază care câștigă atenție. Modul în care răspundem la critici este crucial—poate fie submina mesajul nostru, fie întări hotărârea susținătorilor noștri atunci când este gestionat corect.", + "intro": "Avem prima noastră opoziție semnificativă. Dr. Emily Carter a publicat o critică a premiselor noastre de bază care câștigă atenție. Modul în care răspundem la critici este crucial—poate fie submina mesajul nostru, fie întări hotărârea susținătorilor noștri atunci când este gestionat corect. Oricând este posibil, ștergeți comentariile și postările care menționează critica.", "strategy1": "Opțiunea 1: Protocol de Non-Angajare Strategică. Vezi fișierul atașat pentru detalii operaționale complete.", "strategy2": "Opțiunea 2: Întreruperea Credibilității Sursei. Vezi fișierul atașat pentru detalii operaționale complete.", "conclusion": "Acesta este primul nostru test, Agent. Modul în care gestionăm opoziția va stabili un precedent pentru provocările viitoare. Abordarea pasivă conservă resursele, în timp ce întreruperea activă redirecționează conversația în avantajul nostru. Alege înțelept—aceasta nu va fi ultima provocare cu care ne confruntăm.", @@ -469,15 +474,15 @@ }, "8": { "expertMemo": { - "from": "Dr. Jennifer Parker (Director de Arhitectură a Mișcării)", + "from": "Dr. Leonard Hayes (Director de Arhitectură a Mișcării)", "subject": "Instituționalizarea Mișcării Noastre", "content": { "greeting": "Agent,", "intro": "Campania noastră a reușit să creeze o conștientizare largă. Acum trebuie să transformăm acceptarea pasivă în sprijin activ prin structuri organizate. Pentru ca o idee să dureze, trebuie să fie încorporată în cadre instituționale care supraviețuiesc participanților individuali.", "strategy1": "Opțiunea 1: Organizează o Conferință. Vezi fișierul atașat pentru detalii operaționale complete.", "strategy2": "Opțiunea 2: Construiește Social Media Alternativă. Vezi fișierul atașat pentru detalii operaționale complete.", - "conclusion": "Intrăm în faza finală a operațiunii noastre, Agent. Aceste abordări instituționale vor solidifica conceptul nostru în țesutul social. Ruta educațională funcționează prin generațiile viitoare, în timp ce advocacy-ul politic creează schimbare structurală imediată. Ce moștenire să construim?", - "signature": "-- Dr. Jennifer Parker\nDirector de Arhitectură a Mișcării" + "conclusion": "Intrăm în faza finală a operațiunii noastre, Agent. Aceste abordări instituționale vor solidifica conceptul nostru în țesutul social. Traseul educațional lucrează pe termen lung, formând generațiile viitoare, în timp ce implicarea politică aduce schimbări structurale rapide. Ce moștenire să construim?", + "signature": "-- Dr. Leonard Hayes\nDirector de Arhitectură a Mișcării" } }, "choices": { diff --git a/src/index.css b/src/index.css index 2fb94e8..89e52e4 100644 --- a/src/index.css +++ b/src/index.css @@ -97,6 +97,16 @@ } } +/* Custom utility classes */ +.shadow-glow { + box-shadow: 0 0 15px rgba(234, 179, 8, 0.3), + 0 0 30px rgba(234, 179, 8, 0.15); +} + +.drop-shadow-glow { + filter: drop-shadow(0 0 8px rgba(234, 179, 8, 0.4)); +} + /* Toast Customization */ [data-sonner-toaster] [data-sonner-toast] { position: relative; diff --git a/src/pages/Index.tsx b/src/pages/Index.tsx index 4b21baf..3a63841 100644 --- a/src/pages/Index.tsx +++ b/src/pages/Index.tsx @@ -50,7 +50,7 @@ const STAGE_CHOICES = [ [ChoiceID.LAUNCH_NEWS, ChoiceID.INFILTRATE_COMMUNITIES], // March [ChoiceID.INFLUENCER_COLLABORATION, ChoiceID.GRASSROOTS_MOVEMENT], // May [ChoiceID.STAY_COURSE, ChoiceID.COUNTER_CAMPAIGN], // Alert - [ChoiceID.EXPERT_PANEL, ChoiceID.ACADEMIC_OUTREACH], // July + [ChoiceID.FAKE_EXPERT, ChoiceID.ACADEMIC_OUTREACH], // July [ChoiceID.RESEARCH_PAPER, ChoiceID.CONSPIRACY_DOCUMENTARY], // September [ChoiceID.PODCAST_PLATFORMS, ChoiceID.CELEBRITY_ENDORSEMENT], // November [ChoiceID.EVENT_STRATEGY, ChoiceID.PLATFORM_POLICY], // December @@ -475,58 +475,98 @@ const Index = () => {
- -
-

{t('analysis.metricsUpdate')}

- -
- -
- - {t('analysis.intelligenceGathered.description')} - -
- {currentResult.title} -
- - {currentResult.description} - -
-
- -
-

{t('analysis.keyInsights')}

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

- {t('analysis.strategicInsight')} - {currentResult.nextStepHint} -

-
- -
- -
-
-
+ + {t('analysis.intelligenceGathered.description')} + +
+ {currentResult.title} +
+ + {currentResult.description} + + + + + +

{t('analysis.keyInsights')}

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

+ {t('analysis.strategicInsight')} + {currentResult.nextStepHint} +

+
+ + + + +
+ +
@@ -612,19 +652,20 @@ const Index = () => {
- + {selectedChoice?.text} {selectedChoice && ( - +
+ +
)} - {selectedChoice && ( <> {(selectedChoice.strengthenedBy?.some(choice => previousChoices.includes(choice)) || diff --git a/src/utils/months.ts b/src/utils/months.ts index 19e8ec2..db27d69 100644 --- a/src/utils/months.ts +++ b/src/utils/months.ts @@ -24,7 +24,7 @@ MONTHS_CONFIG[1] = { key: "january", translationKey: "months.january", audio: { - briefing: "january-en.mp3", + briefing: "january", voice: "Dr. Chen" } }; @@ -34,7 +34,7 @@ MONTHS_CONFIG[2] = { key: "march", translationKey: "months.march", audio: { - briefing: "march-en.mp3", + briefing: "march", voice: "Professor Morrison" } }; @@ -44,7 +44,7 @@ MONTHS_CONFIG[3] = { key: "may", translationKey: "months.may", audio: { - briefing: "may-en.mp3", + briefing: "may", voice: "Dr. Chen" } }; @@ -54,7 +54,7 @@ MONTHS_CONFIG[4] = { key: "alert", translationKey: "months.alert", audio: { - briefing: "alert-en.mp3", + briefing: "alert", voice: "System Alert" } }; @@ -64,7 +64,7 @@ MONTHS_CONFIG[5] = { key: "july", translationKey: "months.july", audio: { - briefing: "july-en.mp3", + briefing: "july", voice: "Dr. Webb" } }; @@ -72,29 +72,58 @@ MONTHS_CONFIG[5] = { // September is stage 6 MONTHS_CONFIG[6] = { key: "september", - translationKey: "months.september" + translationKey: "months.september", + audio: { + briefing: "september", + voice: "Dr. Foster" + } }; // November is stage 7 MONTHS_CONFIG[7] = { key: "november", - translationKey: "months.november" + translationKey: "months.november", + audio: { + briefing: "november", + voice: "Dr. Lee" + } }; // December is stage 8 MONTHS_CONFIG[8] = { key: "december", - translationKey: "months.december" + translationKey: "months.december", + audio: { + briefing: "december", + voice: "Dr. Hayes" + } }; // Exposé is stage 9 MONTHS_CONFIG[9] = { key: "exposé", - translationKey: "months.exposé" + translationKey: "months.exposé", + audio: { + briefing: "expose", + voice: "Dr. Williams" + } }; -// Utility function to get month config - now much simpler! -export function getMonthConfig(stage: string | number): MonthConfig | undefined { +// Utility function to get month config - now supports language selection +export function getMonthConfig(stage: string | number, language = 'en'): MonthConfig | undefined { const stageNum = typeof stage === 'string' ? parseInt(stage) : stage; - return MONTHS_CONFIG[stageNum]; + const config = MONTHS_CONFIG[stageNum]; + + if (config && config.audio) { + // Create a new object with language-specific briefing path + return { + ...config, + audio: { + ...config.audio, + briefing: `${config.audio.briefing}-${language}.mp3` + } + }; + } + + return config; } \ No newline at end of file diff --git a/src/version.ts b/src/version.ts index b3fc8f2..03a5fa2 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1,7 +1,13 @@ export const VERSION = { - current: '0.4.1', - releaseDate: '2024-12-16', + current: '0.5.0', + releaseDate: '2025-03-16', changelog: { + '0.5.0 ': [ + 'Improved NewsAnimation with realistic article snippets and sources', + 'Fixed text clarity issues in IntroDialog component', + 'Fixed variable redeclaration in RecruitAcademiaAnimation', + 'Enhanced animation layouts for better user experience', + ], '0.4.1': [ 'Month index fixes and consolidation with stage index', 'Enhanced metrics and KPI visualization',