@@ -181,23 +181,279 @@ <h1 id="explore-title">Explore: Interactive Demonstrations</h1>
181181 < div class ="card ">
182182 < h2 > Mini game (2-minute intuition demo)</ h2 >
183183 < p class ="muted ">
184- This is a simple placeholder. Later you can replace it with a GitHub open-source mini-game .
184+ You and a competitor are fighting for market share. Choose to compete fiercely or collaborate. See how your mindset affects the outcome over 3 rounds .
185185 </ p >
186186
187- < div class ="row ">
188- < button class ="btn " id ="mode-zero " type ="button "> Zero-sum mode</ button >
189- < button class ="btn btn--ghost " id ="mode-positive " type ="button "> Positive-sum mode</ button >
190- </ div >
187+ < div id ="game-container " style ="margin-top: 24px; ">
188+ <!-- Game State: Not Started -->
189+ < div id ="game-start " style ="text-align: center; padding: 24px; background: linear-gradient(135deg, #f0f4ff 0%, #f9fafb 100%); border-radius: 8px; ">
190+ < div style ="font-size: 18px; font-weight: 700; margin-bottom: 16px; color: var(--text); "> Choose Your Strategy</ div >
191+ < p style ="color: var(--text-muted); margin-bottom: 24px; "> What's your approach to competition?</ p >
192+ < div style ="display: grid; grid-template-columns: 1fr 1fr; gap: 12px; ">
193+ < button class ="btn " id ="start-zero-sum " type ="button " style ="padding: 16px; ">
194+ < div style ="font-weight: 700; "> ⚔️ Compete Hard</ div >
195+ < div style ="font-size: 12px; opacity: 0.8; margin-top: 4px; "> I win, you lose</ div >
196+ </ button >
197+ < button class ="btn " id ="start-positive-sum " type ="button " style ="padding: 16px; ">
198+ < div style ="font-weight: 700; "> 🤝 Collaborate</ div >
199+ < div style ="font-size: 12px; opacity: 0.8; margin-top: 4px; "> We both gain</ div >
200+ </ button >
201+ </ div >
202+ </ div >
203+
204+ <!-- Game State: Playing -->
205+ < div id ="game-playing " style ="display: none; ">
206+ <!-- Round Info -->
207+ < div style ="display: flex; justify-content: space-between; align-items: center; margin-bottom: 24px; padding-bottom: 16px; border-bottom: 2px solid var(--border-light); ">
208+ < div >
209+ < div style ="font-size: 12px; color: var(--text-muted); text-transform: uppercase; font-weight: 700; "> Round</ div >
210+ < div style ="font-size: 24px; font-weight: 800; " id ="round-number "> 1</ div >
211+ </ div >
212+ < div style ="text-align: center; ">
213+ < div style ="font-size: 12px; color: var(--text-muted); text-transform: uppercase; font-weight: 700; "> Score</ div >
214+ < div style ="display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-top: 8px; ">
215+ < div >
216+ < div style ="font-size: 18px; font-weight: 800; color: #3b82f6; "> YOU < span id ="your-score "> 0</ span > </ div >
217+ </ div >
218+ < div >
219+ < div style ="font-size: 18px; font-weight: 800; color: #a855f7; "> THEM < span id ="their-score "> 0</ span > </ div >
220+ </ div >
221+ </ div >
222+ </ div >
223+ </ div >
224+
225+ <!-- Choice Phase -->
226+ < div id ="choice-phase ">
227+ < div style ="margin-bottom: 16px; ">
228+ < div style ="font-weight: 700; margin-bottom: 12px; color: var(--text); "> What's your move?</ div >
229+ < div style ="display: grid; grid-template-columns: 1fr 1fr; gap: 12px; ">
230+ < button class ="btn " id ="choice-compete " type ="button " style ="padding: 16px; text-align: left; ">
231+ < div style ="font-weight: 700; "> ⚔️ Compete</ div >
232+ < div style ="font-size: 12px; opacity: 0.8; margin-top: 4px; "> Aggressive pricing, big ad spend</ div >
233+ </ button >
234+ < button class ="btn btn--ghost " id ="choice-collab " type ="button " style ="padding: 16px; text-align: left; ">
235+ < div style ="font-weight: 700; "> 🤝 Collaborate</ div >
236+ < div style ="font-size: 12px; opacity: 0.8; margin-top: 4px; "> Share market, grow together</ div >
237+ </ button >
238+ </ div >
239+ </ div >
240+ </ div >
241+
242+ <!-- Result Phase -->
243+ < div id ="result-phase " style ="display: none; ">
244+ < div style ="background: linear-gradient(135deg, rgba(59, 130, 246, 0.1) 0%, rgba(168, 85, 247, 0.1) 100%); border-radius: 8px; padding: 20px; margin-bottom: 20px; ">
245+ < div style ="display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 16px; ">
246+ <!-- Your Move -->
247+ < div style ="text-align: center; ">
248+ < div style ="font-size: 12px; color: var(--text-muted); text-transform: uppercase; font-weight: 700; margin-bottom: 8px; "> YOU CHOSE</ div >
249+ < div id ="your-move-display " style ="font-size: 24px; font-weight: 800; "> ⚔️</ div >
250+ </ div >
251+ <!-- Their Move -->
252+ < div style ="text-align: center; ">
253+ < div style ="font-size: 12px; color: var(--text-muted); text-transform: uppercase; font-weight: 700; margin-bottom: 8px; "> THEY CHOSE</ div >
254+ < div id ="their-move-display " style ="font-size: 24px; font-weight: 800; "> ⚔️</ div >
255+ </ div >
256+ </ div >
257+
258+ < div style ="display: grid; grid-template-columns: 1fr 1fr; gap: 16px; ">
259+ < div style ="background: rgba(59, 130, 246, 0.2); border-radius: 6px; padding: 12px; text-align: center; ">
260+ < div style ="font-size: 12px; color: var(--text-muted); margin-bottom: 6px; "> YOU GET</ div >
261+ < div style ="font-size: 28px; font-weight: 800; color: #3b82f6; " id ="round-your-gain "> +5</ div >
262+ </ div >
263+ < div style ="background: rgba(168, 85, 247, 0.2); border-radius: 6px; padding: 12px; text-align: center; ">
264+ < div style ="font-size: 12px; color: var(--text-muted); margin-bottom: 6px; "> THEY GET</ div >
265+ < div style ="font-size: 28px; font-weight: 800; color: #a855f7; " id ="round-their-gain "> +5</ div >
266+ </ div >
267+ </ div >
268+
269+ < div style ="margin-top: 16px; padding: 12px; background: rgba(249, 115, 22, 0.1); border-left: 4px solid #f97316; border-radius: 4px; ">
270+ < div style ="font-size: 13px; color: var(--text); line-height: 1.6; " id ="round-insight ">
271+ < strong style ="color: #f97316; "> 💡</ strong > Both cooperated! Market grows for everyone.
272+ </ div >
273+ </ div >
274+ </ div >
275+
276+ < button class ="btn " id ="next-round-btn " type ="button " style ="width: 100%; "> Next Round →</ button >
277+ </ div >
278+ </ div >
279+
280+ <!-- Game State: Results -->
281+ < div id ="game-results " style ="display: none; ">
282+ < div style ="text-align: center; padding: 24px; background: linear-gradient(135deg, #f0f4ff 0%, #f9fafb 100%); border-radius: 8px; ">
283+ < div style ="font-size: 14px; color: var(--text-muted); text-transform: uppercase; font-weight: 700; margin-bottom: 16px; "> Game Over!</ div >
284+
285+ < div style ="display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 24px; ">
286+ < div style ="background: rgba(59, 130, 246, 0.15); border-radius: 8px; padding: 16px; ">
287+ < div style ="font-size: 12px; color: var(--text-muted); margin-bottom: 8px; "> YOUR TOTAL</ div >
288+ < div style ="font-size: 36px; font-weight: 800; color: #3b82f6; " id ="final-your-score "> 0</ div >
289+ </ div >
290+ < div style ="background: rgba(168, 85, 247, 0.15); border-radius: 8px; padding: 16px; ">
291+ < div style ="font-size: 12px; color: var(--text-muted); margin-bottom: 8px; "> THEIR TOTAL</ div >
292+ < div style ="font-size: 36px; font-weight: 800; color: #a855f7; " id ="final-their-score "> 0</ div >
293+ </ div >
294+ </ div >
191295
192- < div class ="result " id ="game-result " role ="status " aria-live ="polite ">
193- < div class ="result__title "> Outcome: fixed pie</ div >
194- < div class ="result__body ">
195- Total resources are fixed. One player’s gain implies another player’s loss.
296+ < div id ="game-conclusion " style ="margin-bottom: 24px; padding: 16px; background: white; border-radius: 8px; border-left: 4px solid #10b981; ">
297+ < div style ="font-size: 16px; font-weight: 700; margin-bottom: 8px; "> 🎯 Key Takeaway</ div >
298+ < div id ="conclusion-text " style ="font-size: 14px; color: var(--text); line-height: 1.6; "> </ div >
299+ </ div >
300+
301+ < button class ="btn " id ="play-again-btn " type ="button " style ="width: 100%; padding: 16px; "> Play Again</ button >
302+ </ div >
196303 </ div >
197- < div class ="result__summary "> < strong > Summary:</ strong > Net total stays constant.</ div >
198304 </ div >
199305 </ div >
200306
307+ < script >
308+ const gameContainer = {
309+ start : document . getElementById ( 'game-start' ) ,
310+ playing : document . getElementById ( 'game-playing' ) ,
311+ results : document . getElementById ( 'game-results' ) ,
312+ choicePhase : document . getElementById ( 'choice-phase' ) ,
313+ resultPhase : document . getElementById ( 'result-phase' )
314+ } ;
315+
316+ let gameState = {
317+ mode : null ,
318+ round : 1 ,
319+ yourScore : 0 ,
320+ theirScore : 0 ,
321+ yourMove : null ,
322+ theirMove : null ,
323+ history : [ ]
324+ } ;
325+
326+ const gamePayoff = {
327+ zeroSum : {
328+ cc : { you : 3 , them : 3 } ,
329+ cd : { you : 6 , them : 0 } ,
330+ dc : { you : 0 , them : 6 } ,
331+ dd : { you : 1 , them : 1 }
332+ } ,
333+ positiveSum : {
334+ cc : { you : 6 , them : 6 } ,
335+ cd : { you : 4 , them : 8 } ,
336+ dc : { you : 8 , them : 4 } ,
337+ dd : { you : 2 , them : 2 }
338+ }
339+ } ;
340+
341+ function showScreen ( screen ) {
342+ gameContainer . start . style . display = 'none' ;
343+ gameContainer . playing . style . display = 'none' ;
344+ gameContainer . results . style . display = 'none' ;
345+ screen . style . display = 'block' ;
346+ }
347+
348+ function startGame ( mode ) {
349+ gameState = {
350+ mode : mode ,
351+ round : 1 ,
352+ yourScore : 0 ,
353+ theirScore : 0 ,
354+ yourMove : null ,
355+ theirMove : null ,
356+ history : [ ]
357+ } ;
358+ showScreen ( gameContainer . playing ) ;
359+ gameContainer . resultPhase . style . display = 'none' ;
360+ gameContainer . choicePhase . style . display = 'block' ;
361+ updateScoreDisplay ( ) ;
362+ }
363+
364+ function updateScoreDisplay ( ) {
365+ document . getElementById ( 'round-number' ) . textContent = gameState . round ;
366+ document . getElementById ( 'your-score' ) . textContent = gameState . yourScore ;
367+ document . getElementById ( 'their-score' ) . textContent = gameState . theirScore ;
368+ }
369+
370+ function getOpponentMove ( yourMove ) {
371+ if ( gameState . mode === 'zero-sum' ) {
372+ return Math . random ( ) > 0.3 ? 'compete' : 'collab' ;
373+ } else {
374+ return Math . random ( ) > 0.2 ? 'collab' : 'compete' ;
375+ }
376+ }
377+
378+ function processRound ( yourMove ) {
379+ gameState . yourMove = yourMove ;
380+ gameState . theirMove = getOpponentMove ( yourMove ) ;
381+
382+ const payoffSet = gameState . mode === 'zero-sum' ? gamePayoff . zeroSum : gamePayoff . positiveSum ;
383+ const key = ( yourMove === 'compete' ? 'c' : 'd' ) + ( gameState . theirMove === 'compete' ? 'c' : 'd' ) ;
384+ const payoff = payoffSet [ key ] ;
385+
386+ gameState . yourScore += payoff . you ;
387+ gameState . theirScore += payoff . them ;
388+ gameState . history . push ( { your : yourMove , their : gameState . theirMove , payoff } ) ;
389+
390+ // Display results
391+ document . getElementById ( 'your-move-display' ) . textContent = yourMove === 'compete' ? '⚔️ Compete' : '🤝 Collaborate' ;
392+ document . getElementById ( 'their-move-display' ) . textContent = gameState . theirMove === 'compete' ? '⚔️ Compete' : '🤝 Collaborate' ;
393+ document . getElementById ( 'round-your-gain' ) . textContent = '+' + payoff . you ;
394+ document . getElementById ( 'round-their-gain' ) . textContent = '+' + payoff . them ;
395+
396+ let insight = '' ;
397+ if ( yourMove === 'compete' && gameState . theirMove === 'compete' ) {
398+ insight = '⚔️ Both competed! The market shrinks. Low gains for both.' ;
399+ } else if ( yourMove === 'collab' && gameState . theirMove === 'collab' ) {
400+ insight = '🤝 Both collaborated! The market grows. High gains for everyone.' ;
401+ } else if ( yourMove === 'compete' && gameState . theirMove === 'collab' ) {
402+ insight = '😱 You exploited their trust. You won this round, but trust is broken.' ;
403+ } else {
404+ insight = '😢 They exploited your trust. Your collaborative approach backfired.' ;
405+ }
406+ document . getElementById ( 'round-insight' ) . innerHTML = '<strong style="color: #f97316;">💡</strong> ' + insight ;
407+
408+ updateScoreDisplay ( ) ;
409+ gameContainer . choicePhase . style . display = 'none' ;
410+ gameContainer . resultPhase . style . display = 'block' ;
411+ }
412+
413+ function endGame ( ) {
414+ document . getElementById ( 'final-your-score' ) . textContent = gameState . yourScore ;
415+ document . getElementById ( 'final-their-score' ) . textContent = gameState . theirScore ;
416+
417+ let conclusion = '' ;
418+ if ( gameState . yourScore > gameState . theirScore + 5 ) {
419+ conclusion = '🏆 <strong>You won through competition!</strong> But this mindset often leads to mutual destruction in real situations. In zero-sum thinking, everyone loses in the long run.' ;
420+ } else if ( gameState . yourScore < gameState . theirScore - 5 ) {
421+ conclusion = '😔 <strong>You lost because you trusted too much.</strong> But collaboration works best when both parties are committed to mutual benefit.' ;
422+ } else if ( gameState . yourScore > gameState . theirScore ) {
423+ conclusion = '⚡ <strong>You slightly won!</strong> Your strategy had moments of success, but the key insight: if both had collaborated, you\'d both have higher scores.' ;
424+ } else if ( gameState . yourScore < gameState . theirScore ) {
425+ conclusion = '🤔 <strong>They slightly won.</strong> This shows the reality of the prisoner\'s dilemma: individual incentives vs. collective benefit.' ;
426+ } else {
427+ conclusion = '🤝 <strong>It\'s a tie!</strong> Balanced strategies can lead to equal outcomes, but maximum mutual benefit comes from cooperation.' ;
428+ }
429+
430+ document . getElementById ( 'conclusion-text' ) . innerHTML = conclusion ;
431+ showScreen ( gameContainer . results ) ;
432+ }
433+
434+ // Event Listeners
435+ document . getElementById ( 'start-zero-sum' ) . addEventListener ( 'click' , ( ) => startGame ( 'zero-sum' ) ) ;
436+ document . getElementById ( 'start-positive-sum' ) . addEventListener ( 'click' , ( ) => startGame ( 'positive-sum' ) ) ;
437+
438+ document . getElementById ( 'choice-compete' ) . addEventListener ( 'click' , ( ) => processRound ( 'compete' ) ) ;
439+ document . getElementById ( 'choice-collab' ) . addEventListener ( 'click' , ( ) => processRound ( 'collab' ) ) ;
440+
441+ document . getElementById ( 'next-round-btn' ) . addEventListener ( 'click' , ( ) => {
442+ if ( gameState . round < 3 ) {
443+ gameState . round ++ ;
444+ updateScoreDisplay ( ) ;
445+ gameContainer . choicePhase . style . display = 'block' ;
446+ gameContainer . resultPhase . style . display = 'none' ;
447+ } else {
448+ endGame ( ) ;
449+ }
450+ } ) ;
451+
452+ document . getElementById ( 'play-again-btn' ) . addEventListener ( 'click' , ( ) => {
453+ showScreen ( gameContainer . start ) ;
454+ } ) ;
455+ </ script >
456+
201457 < div class ="card video-card ">
202458 < div class ="video-header ">
203459 < span class ="video-badge "> 🎬 Video</ span >
@@ -620,6 +876,24 @@ <h3 class="team-member-name">Liyang Chen</h3>
620876 </ div >
621877 </ div >
622878
879+ <!-- Team member card -->
880+ < div class ="team-member-card ">
881+ < div class ="team-member-avatar " style ="background: linear-gradient(135deg, #06b6d4 0%, #0891b2 100%); display: flex; align-items: center; justify-content: center; color: white; font-weight: 700; font-size: 48px; "> JW</ div >
882+ < h3 class ="team-member-name "> Junyu Wang</ h3 >
883+ < div class ="team-member-role "> Developer</ div >
884+ < p class ="team-member-bio ">
885+ Graduate student at Harvard Kennedy School. Interested in technology, public policy, and finance development. Leading website development and technical implementation.
886+ </ p >
887+ < div class ="team-member-contact ">
888+ < a href ="mailto:jwang@hks.harvard.edu " title ="Email Junyu ">
889+ < svg width ="20 " height ="20 " viewBox ="0 0 24 24 " fill ="none " stroke ="currentColor " stroke-width ="2 ">
890+ < rect x ="2 " y ="4 " width ="20 " height ="16 " rx ="2 "> </ rect >
891+ < path d ="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7 "> </ path >
892+ </ svg >
893+ </ a >
894+ </ div >
895+ </ div >
896+
623897 <!-- Team member card -->
624898 < div class ="team-member-card ">
625899 < div class ="team-member-avatar " style ="background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%); display: flex; align-items: center; justify-content: center; color: white; font-weight: 700; font-size: 48px; "> SE</ div >
0 commit comments