Skip to content

Commit 8a70fd7

Browse files
authored
Merge pull request #32 from code4policy/1ourteamjunyu
feat: update index page
2 parents 86f6972 + 0900b04 commit 8a70fd7

2 files changed

Lines changed: 285 additions & 10 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.DS_Store

index.html

Lines changed: 284 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)