+ {/* VNC Viewer */}
+
{isConnected ? (
-
) : (
-
- Not connected
+
+
+
Click the power button to connect
)}
-
-
+ {/* Status Bar */}
+
+ Status: {isConnected ? 'Connected' : 'Disconnected'}
+ Press ESC to exit fullscreen
diff --git a/src/games/fox-adventure/components/FoxGame.tsx b/src/games/fox-adventure/components/FoxGame.tsx
new file mode 100644
index 0000000..9813073
--- /dev/null
+++ b/src/games/fox-adventure/components/FoxGame.tsx
@@ -0,0 +1,63 @@
+import React, { useEffect, useState } from 'react';
+import useGameStore from '../state/gameStore';
+import { useGameLoop } from '../hooks/useGameLoop';
+import { useGameControls } from '../hooks/useGameControls';
+import { Player } from './Player';
+import { Enemy } from './Enemy';
+import { Collectible } from './Collectible';
+import { PowerUp } from './PowerUp';
+import { GameHUD } from './GameHUD';
+import { GameOverlay } from './GameOverlay';
+
+const FoxGame: React.FC = () => {
+ const [isActive, setIsActive] = useState(false);
+
+ // Initialize game systems
+ useGameLoop();
+ useGameControls();
+
+ // Konami code for game activation
+ useEffect(() => {
+ const konamiCode = [
+ 'ArrowUp', 'ArrowUp',
+ 'ArrowDown', 'ArrowDown',
+ 'ArrowLeft', 'ArrowRight',
+ 'ArrowLeft', 'ArrowRight',
+ 'b', 'a'
+ ];
+ let index = 0;
+
+ const handleKeydown = (event: KeyboardEvent) => {
+ if (event.key === konamiCode[index]) {
+ index++;
+ if (index === konamiCode.length) {
+ setIsActive(true);
+ useGameStore.getState().startNewGame();
+ }
+ } else {
+ index = 0;
+ }
+ };
+
+ window.addEventListener('keydown', handleKeydown);
+ return () => window.removeEventListener('keydown', handleKeydown);
+ }, []);
+
+ if (!isActive) return null;
+
+ return (
+
+
+ {/* Game world */}
+
+
+ {/* Other game elements render here */}
+
+
+
+
+
+ );
+};
+
+export default FoxGame;
diff --git a/src/games/fox-adventure/components/Player.tsx b/src/games/fox-adventure/components/Player.tsx
new file mode 100644
index 0000000..929b05e
--- /dev/null
+++ b/src/games/fox-adventure/components/Player.tsx
@@ -0,0 +1,26 @@
+import React from 'react';
+import useGameStore from '../state/gameStore';
+
+export const Player: React.FC = () => {
+ const player = useGameStore(state => state.player);
+
+ return (
+
+
+ {/* Fox body */}
+
+ {/* Face details here */}
+
+
+
+ );
+};
diff --git a/src/games/fox-adventure/hooks/useGameControls.ts b/src/games/fox-adventure/hooks/useGameControls.ts
new file mode 100644
index 0000000..7cecac9
--- /dev/null
+++ b/src/games/fox-adventure/hooks/useGameControls.ts
@@ -0,0 +1,57 @@
+import { useEffect } from 'react';
+import useGameStore from '../state/gameStore';
+
+export const useGameControls = () => {
+ const gameStore = useGameStore();
+
+ useEffect(() => {
+ const keys = new Set
();
+
+ const handleKeyDown = (e: KeyboardEvent) => {
+ keys.add(e.key);
+
+ if (e.key === 'Escape') {
+ if (gameStore.gameStatus === 'PLAYING') {
+ gameStore.pauseGame();
+ } else if (gameStore.gameStatus === 'PAUSED') {
+ gameStore.resumeGame();
+ }
+ }
+ };
+
+ const handleKeyUp = (e: KeyboardEvent) => {
+ keys.delete(e.key);
+ };
+
+ const updatePlayerMovement = () => {
+ if (gameStore.gameStatus !== 'PLAYING') return;
+
+ const direction = { x: 0, y: 0 };
+
+ if (keys.has('ArrowUp') || keys.has('w')) direction.y -= 1;
+ if (keys.has('ArrowDown') || keys.has('s')) direction.y += 1;
+ if (keys.has('ArrowLeft') || keys.has('a')) direction.x -= 1;
+ if (keys.has('ArrowRight') || keys.has('d')) direction.x += 1;
+
+ if (direction.x !== 0 || direction.y !== 0) {
+ gameStore.movePlayer(direction);
+ }
+ };
+
+ let animationFrameId: number;
+ const gameLoop = () => {
+ updatePlayerMovement();
+ animationFrameId = requestAnimationFrame(gameLoop);
+ };
+ animationFrameId = requestAnimationFrame(gameLoop);
+
+ window.addEventListener('keydown', handleKeyDown);
+ window.addEventListener('keyup', handleKeyUp);
+
+ return () => {
+ window.removeEventListener('keydown', handleKeyDown);
+ window.removeEventListener('keyup', handleKeyUp);
+ cancelAnimationFrame(animationFrameId);
+ };
+ }, []);
+};
diff --git a/src/games/fox-adventure/hooks/useGameLoop.ts b/src/games/fox-adventure/hooks/useGameLoop.ts
new file mode 100644
index 0000000..1326d26
--- /dev/null
+++ b/src/games/fox-adventure/hooks/useGameLoop.ts
@@ -0,0 +1,33 @@
+import { useEffect, useRef } from 'react';
+import useGameStore from '../state/gameStore';
+
+export const useGameLoop = () => {
+ const frameRef = useRef();
+ const lastUpdateRef = useRef(0);
+ const gameStore = useGameStore();
+
+ useEffect(() => {
+ const gameLoop = (timestamp: number) => {
+ if (!lastUpdateRef.current) lastUpdateRef.current = timestamp;
+ const deltaTime = timestamp - lastUpdateRef.current;
+
+ if (gameStore.gameStatus === 'PLAYING') {
+ // Update game state
+ gameStore.updateEnemies();
+ checkCollisions();
+ updatePowerUps(deltaTime);
+ }
+
+ lastUpdateRef.current = timestamp;
+ frameRef.current = requestAnimationFrame(gameLoop);
+ };
+
+ frameRef.current = requestAnimationFrame(gameLoop);
+
+ return () => {
+ if (frameRef.current) {
+ cancelAnimationFrame(frameRef.current);
+ }
+ };
+ }, []);
+};
diff --git a/src/styles/cursor.css b/src/styles/cursor.css
index dbb6651..6d39c27 100644
--- a/src/styles/cursor.css
+++ b/src/styles/cursor.css
@@ -1,13 +1,53 @@
+/* Default cursor for all elements */
* {
cursor: url('/cursors/default.svg') 16 16, auto;
}
-a, button, [role="button"],
-input[type="submit"], input[type="button"],
-select {
+/* Interactive elements cursor */
+a,
+button,
+[role="button"],
+input[type="submit"],
+input[type="button"],
+select,
+.interactive,
+.nav-link {
cursor: url('/cursors/paw.svg') 16 16, pointer;
}
-.loading {
+/* Loading state cursor */
+.loading,
+:disabled,
+[aria-busy="true"] {
cursor: url('/cursors/tail-loading.svg') 16 16, progress;
}
+
+/* Hover effects for interactive elements */
+a:hover,
+button:hover,
+[role="button"]:hover,
+.nav-link:hover {
+ /* Add a subtle glow effect on hover */
+ filter: drop-shadow(0 0 4px var(--fox-pink-glow));
+ transition: filter 0.3s ease;
+}
+
+/* Custom cursor regions */
+.text-select {
+ cursor: text;
+}
+
+.resize {
+ cursor: nw-resize;
+}
+
+/* Ensure cursors work with transform effects */
+* {
+ cursor-position: fixed;
+}
+
+/* Prevent cursor inheritance in certain cases */
+iframe,
+canvas {
+ cursor: inherit;
+}
\ No newline at end of file
diff --git a/src/styles/cursor/default.svg b/src/styles/cursor/default.svg
index 1de2e81..8fdf3b1 100644
--- a/src/styles/cursor/default.svg
+++ b/src/styles/cursor/default.svg
@@ -1,3 +1,21 @@
-
+
\ No newline at end of file
diff --git a/src/styles/cursor/tail-loading.svg b/src/styles/cursor/tail-loading.svg
index 12355f8..4e676fa 100644
--- a/src/styles/cursor/tail-loading.svg
+++ b/src/styles/cursor/tail-loading.svg
@@ -1,12 +1,26 @@
-
+
\ No newline at end of file
diff --git a/src/styles/game.css b/src/styles/game.css
new file mode 100644
index 0000000..ab1c080
--- /dev/null
+++ b/src/styles/game.css
@@ -0,0 +1,31 @@
+/* Game-specific styles */
+.game-active * {
+ cursor: none;
+}
+
+.game-viewport {
+ touch-action: none;
+ user-select: none;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+}
+
+/* Animation utilities */
+@keyframes fadeIn {
+ from { opacity: 0; }
+ to { opacity: 1; }
+}
+
+.fade-in {
+ animation: fadeIn 0.3s ease-in-out;
+}
+
+/* Game-specific shadows */
+.fox-shadow {
+ filter: drop-shadow(0 0 8px var(--fox-pink-glow));
+}
+
+.enemy-shadow {
+ filter: drop-shadow(0 0 8px rgba(255, 0, 0, 0.3));
+}
diff --git a/src/styles/index.css b/src/styles/index.css
index 7c4ca1b..8069317 100644
--- a/src/styles/index.css
+++ b/src/styles/index.css
@@ -2,3 +2,30 @@
@import 'animations.css';
@import 'utilities.css';
@import 'cursor.css';
+
+@import './game.css';
+
+/* Game Styles */
+.game-viewport {
+ touch-action: none;
+ user-select: none;
+}
+
+.game-active * {
+ cursor: none;
+}
+
+/* Game Animations */
+@keyframes fadeIn {
+ from { opacity: 0; }
+ to { opacity: 1; }
+}
+
+.fade-in {
+ animation: fadeIn 0.3s ease-in-out;
+}
+
+/* Game-specific effects */
+.fox-shadow {
+ filter: drop-shadow(0 0 8px var(--fox-pink-glow));
+}
diff --git a/src/types/game.ts b/src/types/game.ts
new file mode 100644
index 0000000..474a820
--- /dev/null
+++ b/src/types/game.ts
@@ -0,0 +1,42 @@
+export interface PowerUp {
+ id: string;
+ type: 'SPEED' | 'SHIELD' | 'MAGNET';
+ duration: number;
+ position: { x: number; y: number };
+}
+
+export interface Collectible {
+ id: string;
+ type: 'STAR' | 'GEM' | 'KEY';
+ value: number;
+ position: { x: number; y: number };
+}
+
+export interface Enemy {
+ id: string;
+ type: 'WOLF' | 'OWL' | 'HUNTER';
+ position: { x: number; y: number };
+ direction: { x: number; y: number };
+ speed: number;
+}
+
+export interface PlayerState {
+ position: { x: number; y: number };
+ health: number;
+ speed: number;
+ powerUps: PowerUp[];
+ isInvincible: boolean;
+ hasKey: boolean;
+}
+
+export interface GameState {
+ player: PlayerState;
+ enemies: Enemy[];
+ collectibles: Collectible[];
+ powerUps: PowerUp[];
+ score: number;
+ level: number;
+ gameStatus: 'MENU' | 'PLAYING' | 'PAUSED' | 'GAME_OVER';
+ highScores: number[];
+ timePlayed: number;
+}
diff --git a/tailwind.config.js b/tailwind.config.js
index bd39f27..294a831 100644
--- a/tailwind.config.js
+++ b/tailwind.config.js
@@ -23,6 +23,8 @@ export default {
'bounce-slow': 'bounce 3s linear infinite',
'glow': 'glow 2s ease-in-out infinite',
'float': 'float 3s ease-in-out infinite',
+ 'spin-slow': 'spin 3s linear infinite',
+ 'wag': 'wag 1s ease-in-out infinite',
},
keyframes: {
glow: {
@@ -33,16 +35,11 @@ export default {
'0%, 100%': { transform: 'translateY(0)' },
'50%': { transform: 'translateY(-10px)' },
},
+ wag: {
+ '0%, 100%': { transform: 'rotate(-10deg)' },
+ '50%': { transform: 'rotate(10deg)' },
+ },
},
- backgroundImage: {
- 'gradient-primary': 'linear-gradient(135deg, var(--background-primary) 0%, var(--background-secondary) 100%)',
- 'gradient-card': 'linear-gradient(135deg, rgba(47, 28, 84, 0.3) 0%, rgba(157, 78, 221, 0.1) 100%)',
- 'gradient-hover': 'linear-gradient(135deg, rgba(157, 78, 221, 0.2) 0%, rgba(178, 73, 248, 0.1) 100%)',
- },
- zIndex: {
- 'behind': '-1',
- 'deep': '-10',
- }
},
},
plugins: [],