death anim
- SHA
bff1dc90ff2126fcefc162742cd7f1bb98b99350- Parents
-
2148300 - Tree
c174c21
bff1dc9
bff1dc90ff2126fcefc162742cd7f1bb98b993502148300
c174c21| Status | File | + | - |
|---|---|---|---|
| M |
frontend/src/app/globals.css
|
16 | 0 |
| M |
frontend/src/components/Game.tsx
|
10 | 1 |
| M |
frontend/src/components/TreeVisualizer.tsx
|
8 | 5 |
frontend/src/app/globals.cssmodified@@ -62,3 +62,19 @@ body { | ||
| 62 | 62 | 0%, 50% { opacity: 1; } |
| 63 | 63 | 51%, 100% { opacity: 0; } |
| 64 | 64 | } |
| 65 | + | |
| 66 | +/* Mole falling animation */ | |
| 67 | +@keyframes moleFall { | |
| 68 | + 0% { | |
| 69 | + transform: translateY(0); | |
| 70 | + opacity: 1; | |
| 71 | + } | |
| 72 | + 100% { | |
| 73 | + transform: translateY(800px); | |
| 74 | + opacity: 0; | |
| 75 | + } | |
| 76 | +} | |
| 77 | + | |
| 78 | +.mole-death { | |
| 79 | + animation: moleFall 1.5s ease-in forwards; | |
| 80 | +} | |
frontend/src/components/Game.tsxmodified@@ -36,6 +36,7 @@ const Game: React.FC = () => { | ||
| 36 | 36 | const [terminalMinimized, setTerminalMinimized] = useState(true); |
| 37 | 37 | const [hasPlayedIntro, setHasPlayedIntro] = useState(false); |
| 38 | 38 | const [isDarkMode, setIsDarkMode] = useState(true); |
| 39 | + const [moleKilled, setMoleKilled] = useState(false); | |
| 39 | 40 | |
| 40 | 41 | const terminalRef = useRef<HTMLDivElement>(null); |
| 41 | 42 | const inputRef = useRef<HTMLInputElement>(null); |
@@ -105,6 +106,7 @@ const Game: React.FC = () => { | ||
| 105 | 106 | setShowHints(false); |
| 106 | 107 | setTerminalMinimized(true); // Keep terminal minimized on new game |
| 107 | 108 | setHasPlayedIntro(false); // Reset intro for new game |
| 109 | + setMoleKilled(false); // Reset mole killed state | |
| 108 | 110 | } catch (error) { |
| 109 | 111 | setGameState({ |
| 110 | 112 | ...gameState, |
@@ -183,6 +185,7 @@ const Game: React.FC = () => { | ||
| 183 | 185 | |
| 184 | 186 | // Check if game won |
| 185 | 187 | if (response.game_won) { |
| 188 | + // First, show the mole | |
| 186 | 189 | setGameState(prev => ({ |
| 187 | 190 | ...prev, |
| 188 | 191 | tree: prev.tree ? { |
@@ -191,6 +194,11 @@ const Game: React.FC = () => { | ||
| 191 | 194 | tree_data: updateTreeDataToShowMole(prev.tree!.tree_data, prev.tree!.player_location), |
| 192 | 195 | } : null, |
| 193 | 196 | })); |
| 197 | + | |
| 198 | + // Then trigger the falling animation after a short delay | |
| 199 | + setTimeout(() => { | |
| 200 | + setMoleKilled(true); | |
| 201 | + }, 200); | |
| 194 | 202 | } |
| 195 | 203 | |
| 196 | 204 | setCommand(''); |
@@ -315,6 +323,7 @@ const Game: React.FC = () => { | ||
| 315 | 323 | onNodeClick={handleNodeClick} |
| 316 | 324 | playIntro={!hasPlayedIntro} |
| 317 | 325 | isDarkMode={isDarkMode} |
| 326 | + moleKilled={moleKilled} | |
| 318 | 327 | /> |
| 319 | 328 | </div> |
| 320 | 329 | |
@@ -366,7 +375,7 @@ const Game: React.FC = () => { | ||
| 366 | 375 | {!terminalMinimized && ( |
| 367 | 376 | <div |
| 368 | 377 | ref={terminalRef} |
| 369 | - className={`${terminalColors.content} p-4 font-terminal text-base h-[350px] overflow-y-auto scrollbar-thin scrollbar-thumb-gray-700`} | |
| 378 | + className={`${terminalColors.content} p-4 font-terminal text-base h-[300px] overflow-y-auto scrollbar-thin scrollbar-thumb-gray-700`} | |
| 370 | 379 | onClick={() => inputRef.current?.focus()} |
| 371 | 380 | > |
| 372 | 381 | {commandHistory.map((entry, index) => ( |
frontend/src/components/TreeVisualizer.tsxmodified@@ -11,6 +11,7 @@ interface TreeVisualizerProps { | ||
| 11 | 11 | onNodeClick?: (path: string) => void; |
| 12 | 12 | playIntro?: boolean; |
| 13 | 13 | isDarkMode?: boolean; |
| 14 | + moleKilled?: boolean; | |
| 14 | 15 | } |
| 15 | 16 | |
| 16 | 17 | const TreeVisualizer: React.FC<TreeVisualizerProps> = ({ |
@@ -19,6 +20,7 @@ const TreeVisualizer: React.FC<TreeVisualizerProps> = ({ | ||
| 19 | 20 | onNodeClick, |
| 20 | 21 | playIntro = true, |
| 21 | 22 | isDarkMode = true, |
| 23 | + moleKilled = false, | |
| 22 | 24 | }) => { |
| 23 | 25 | const svgRef = useRef<SVGSVGElement>(null); |
| 24 | 26 | const containerRef = useRef<HTMLDivElement>(null); |
@@ -67,7 +69,7 @@ const TreeVisualizer: React.FC<TreeVisualizerProps> = ({ | ||
| 67 | 69 | const LAYOUT_CONFIG = { |
| 68 | 70 | nodeSpacing: 120, |
| 69 | 71 | margin: { top: 100, right: 150, bottom: 100, left: 150 }, |
| 70 | - viewBoxMultiplier: 2, | |
| 72 | + viewBoxMultiplier: 2.5, | |
| 71 | 73 | minHeight: 1200, |
| 72 | 74 | grid: { |
| 73 | 75 | size: 40, |
@@ -84,7 +86,7 @@ const TreeVisualizer: React.FC<TreeVisualizerProps> = ({ | ||
| 84 | 86 | defaultScale: 3, |
| 85 | 87 | fullTreeScale: 0.8, |
| 86 | 88 | treePadding: 200, |
| 87 | - nudgeOffset: { x: 0.1, y: 0.2 } | |
| 89 | + nudgeOffset: { x: 0.15, y: 0.2 } | |
| 88 | 90 | }; |
| 89 | 91 | |
| 90 | 92 | const LINK_CONFIG = { |
@@ -472,7 +474,7 @@ const TreeVisualizer: React.FC<TreeVisualizerProps> = ({ | ||
| 472 | 474 | .attr('dur', ANIMATION_CONFIG.celebration.duration) |
| 473 | 475 | .attr('repeatCount', ANIMATION_CONFIG.celebration.repeatCount); |
| 474 | 476 | |
| 475 | - // Add mole SVG directly on the node | |
| 477 | + // Add mole SVG with falling animation when killed | |
| 476 | 478 | moleGroup |
| 477 | 479 | .append('image') |
| 478 | 480 | .attr('xlink:href', ICON_CONFIG.paths.mole) |
@@ -480,7 +482,8 @@ const TreeVisualizer: React.FC<TreeVisualizerProps> = ({ | ||
| 480 | 482 | .attr('height', ICON_CONFIG.size) |
| 481 | 483 | .attr('x', ICON_CONFIG.offset) |
| 482 | 484 | .attr('y', ICON_CONFIG.offset) |
| 483 | - .style('pointer-events', 'none'); | |
| 485 | + .style('pointer-events', 'none') | |
| 486 | + .classed('mole-death', moleKilled); | |
| 484 | 487 | } |
| 485 | 488 | |
| 486 | 489 | // Add zoom and pan behavior |
@@ -567,7 +570,7 @@ const TreeVisualizer: React.FC<TreeVisualizerProps> = ({ | ||
| 567 | 570 | } |
| 568 | 571 | } |
| 569 | 572 | |
| 570 | - }, [treeData, playerLocation, onNodeClick, playIntro, isDarkMode]); | |
| 573 | + }, [treeData, playerLocation, onNodeClick, playIntro, isDarkMode, moleKilled]); | |
| 571 | 574 | |
| 572 | 575 | return ( |
| 573 | 576 | <div ref={containerRef} className="w-full h-full"> |