@jonelhatwell/arcade-games 1.2.0 → 1.2.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs.map +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +14 -11
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/components/games/spacedodger/index.tsx","../src/components/ui/button.tsx","../src/lib/utils.ts","../src/components/games/memorygame/index.tsx"],"sourcesContent":["import \"./index.css\";\r\nexport { default as SpaceDodger } from \"./components/games/spacedodger\";\r\nexport { default as MemoryGame } from \"./components/games/memorygame\";","import React, { useEffect, useRef, useState } from 'react';\r\nimport { Button } from '@/components/ui/button';\r\n\r\ninterface Position {\r\n x: number;\r\n y: number;\r\n}\r\n\r\ninterface Enemy extends Position {\r\n radius: number;\r\n}\r\n\r\ninterface Player extends Position {\r\n width: number;\r\n height: number;\r\n}\r\n\r\ninterface SpaceDodgerState {\r\n player: Player;\r\n enemies: Enemy[];\r\n frame: number;\r\n keys: Record<string, boolean>;\r\n}\r\n\r\n\r\nconst config = {\r\n canvasSize : { \r\n width: 450, \r\n height: 450 \r\n },\r\n player: { x: 200, y: 350, width: 25, height: 50 }\r\n}\r\n\r\nconst SpaceDodger: React.FC = () => {\r\n const canvasRef = useRef<HTMLCanvasElement>(null);\r\n const scoreRef = useRef(0);\r\n const lastBatchScoreRef = useRef(0);\r\n\r\n const [score, setScore] = useState(0);\r\n const [gameOver, setGameOver] = useState(false);\r\n\r\n const gameStateRef = useRef<SpaceDodgerState>({\r\n player: config.player,\r\n enemies: [],\r\n frame: 0,\r\n keys: {}\r\n });\r\n\r\n const resetGame = () => {\r\n gameStateRef.current = {\r\n player: config.player,\r\n enemies: [],\r\n frame: 0,\r\n keys: {}\r\n };\r\n scoreRef.current = 0;\r\n lastBatchScoreRef.current = 0;\r\n setScore(0);\r\n setGameOver(false);\r\n };\r\n\r\n\r\n \r\n useEffect(() => {\r\n const canvas = canvasRef.current;\r\n if (!canvas) return;\r\n const ctx = canvas.getContext('2d');\r\n if (!ctx) return;\r\n\r\n const state = gameStateRef.current;\r\n\r\n const handleKeyDown = (e: KeyboardEvent) => {\r\n state.keys[e.key] = true;\r\n };\r\n const handleKeyUp = (e: KeyboardEvent) => {\r\n state.keys[e.key] = false;\r\n };\r\n\r\n window.addEventListener('keydown', handleKeyDown);\r\n window.addEventListener('keyup', handleKeyUp);\r\n\r\n const randomRadius = () => 10 + Math.random() * 15;\r\n\r\n const getEnemySpeed = () => {\r\n const base = 3;\r\n const increase = Math.floor(scoreRef.current / 20) * 0.5;\r\n return base + increase;\r\n };\r\n\r\n let animationId: number;\r\n\r\n const gameLoop = () => {\r\n if (gameOver) return;\r\n\r\n state.frame++;\r\n\r\n ctx.fillStyle = '#000';\r\n ctx.fillRect(0, 0, config.canvasSize.width, config.canvasSize.height);\r\n\r\n // Player movement\r\n if (state.keys['ArrowLeft'] && state.player.x > 0) state.player.x -= 5;\r\n if (state.keys['ArrowRight'] && state.player.x < config.canvasSize.width - state.player.width) state.player.x += 5;\r\n if (state.keys['ArrowUp'] && state.player.y > 0) state.player.y -= 5;\r\n if (state.keys['ArrowDown'] && state.player.y < config.canvasSize.height - state.player.height) state.player.y += 5;\r\n\r\n // Draw player\r\n ctx.fillStyle = '#0ea5e9';\r\n ctx.fillRect(\r\n state.player.x,\r\n state.player.y,\r\n state.player.width,\r\n state.player.height\r\n );\r\n\r\n // Normal enemy spawn\r\n if (state.frame % 40 === 0) {\r\n const radius = randomRadius();\r\n state.enemies.push({\r\n x: radius + Math.random() * (config.canvasSize.width - radius * 2),\r\n y: -radius,\r\n radius,\r\n });\r\n }\r\n\r\n // Extra batch every 20 score\r\n if (\r\n scoreRef.current > 0 &&\r\n scoreRef.current % 20 === 0 &&\r\n lastBatchScoreRef.current !== scoreRef.current\r\n ) {\r\n lastBatchScoreRef.current = scoreRef.current;\r\n const batchCount = 2 + Math.floor(Math.random() * 3);\r\n\r\n for (let i = 0; i < batchCount; i++) {\r\n const radius = randomRadius();\r\n state.enemies.push({\r\n x: radius + Math.random() * (config.canvasSize.width - radius * 2),\r\n y: -Math.random() * 100,\r\n radius\r\n });\r\n }\r\n }\r\n\r\n // Enemies update\r\n state.enemies = state.enemies.filter(enemy => {\r\n enemy.y += getEnemySpeed();\r\n\r\n // Draw enemy (circle)\r\n ctx.fillStyle = '#ef4444';\r\n ctx.beginPath();\r\n ctx.arc(enemy.x, enemy.y, enemy.radius, 0, Math.PI * 2);\r\n ctx.fill();\r\n\r\n // Circle vs rectangle collision\r\n const closestX = Math.max(\r\n state.player.x,\r\n Math.min(enemy.x, state.player.x + state.player.width)\r\n );\r\n const closestY = Math.max(\r\n state.player.y,\r\n Math.min(enemy.y, state.player.y + state.player.height)\r\n );\r\n\r\n const dx = enemy.x - closestX;\r\n const dy = enemy.y - closestY;\r\n\r\n if (dx * dx + dy * dy < enemy.radius * enemy.radius) {\r\n setGameOver(true);\r\n return false;\r\n }\r\n\r\n // Passed screen\r\n if (enemy.y - enemy.radius > config.canvasSize.height) {\r\n setScore(s => {\r\n scoreRef.current = s + 1;\r\n return s + 1;\r\n });\r\n return false;\r\n }\r\n\r\n return true;\r\n });\r\n\r\n animationId = requestAnimationFrame(gameLoop);\r\n };\r\n\r\n gameLoop();\r\n\r\n return () => {\r\n cancelAnimationFrame(animationId);\r\n window.removeEventListener('keydown', handleKeyDown);\r\n window.removeEventListener('keyup', handleKeyUp);\r\n };\r\n }, [gameOver]);\r\n\r\n return (\r\n <div className=\"relative flex flex-col items-center gap-4 p-4\">\r\n <div className=\"text-xl font-bold\">Score: {score}</div>\r\n <canvas\r\n ref={canvasRef}\r\n width={config.canvasSize.width}\r\n height={config.canvasSize.height}\r\n className=\"border-2 border-gray-300\"\r\n />\r\n\r\n {gameOver && (\r\n <div className=\"absolute inset-0 flex flex-col items-center justify-center bg-black/60\">\r\n <p className=\"text-xl font-bold text-red-500 mb-3\">Game Over</p>\r\n <Button onClick={resetGame}>Play Again</Button>\r\n </div>\r\n )}\r\n\r\n <div className=\"text-sm text-foreground\">Use arrow keys to move</div>\r\n </div>\r\n );\r\n};\r\n\r\nexport default SpaceDodger;","import * as React from \"react\"\r\nimport { Slot } from \"@radix-ui/react-slot\"\r\nimport { cva, type VariantProps } from \"class-variance-authority\"\r\n\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nconst buttonVariants = cva(\r\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive\",\r\n {\r\n variants: {\r\n variant: {\r\n default: \"bg-primary text-primary-foreground hover:bg-primary/90\",\r\n destructive:\r\n \"bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60\",\r\n outline:\r\n \"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50\",\r\n secondary:\r\n \"bg-secondary text-secondary-foreground hover:bg-secondary/80\",\r\n ghost:\r\n \"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50\",\r\n link: \"text-primary underline-offset-4 hover:underline\",\r\n },\r\n size: {\r\n default: \"h-9 px-4 py-2 has-[>svg]:px-3\",\r\n sm: \"h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5\",\r\n lg: \"h-10 rounded-md px-6 has-[>svg]:px-4\",\r\n icon: \"size-9\",\r\n \"icon-sm\": \"size-8\",\r\n \"icon-lg\": \"size-10\",\r\n },\r\n },\r\n defaultVariants: {\r\n variant: \"default\",\r\n size: \"default\",\r\n },\r\n }\r\n)\r\n\r\nfunction Button({\r\n className,\r\n variant = \"default\",\r\n size = \"default\",\r\n asChild = false,\r\n ...props\r\n}: React.ComponentProps<\"button\"> &\r\n VariantProps<typeof buttonVariants> & {\r\n asChild?: boolean\r\n }) {\r\n const Comp = asChild ? Slot : \"button\"\r\n\r\n return (\r\n <Comp\r\n data-slot=\"button\"\r\n data-variant={variant}\r\n data-size={size}\r\n className={cn(buttonVariants({ variant, size, className }))}\r\n {...props}\r\n />\r\n )\r\n}\r\n\r\nexport { Button, buttonVariants }\r\n","import { clsx, type ClassValue } from \"clsx\"\r\nimport { twMerge } from \"tailwind-merge\"\r\n\r\nexport function cn(...inputs: ClassValue[]) {\r\n return twMerge(clsx(inputs))\r\n}","import React, { useEffect, useRef, useState } from 'react';\r\nimport { Button } from '@/components/ui/button';\r\n\r\ninterface NumberItem {\r\n x: number;\r\n y: number;\r\n value: number;\r\n radius: number;\r\n}\r\n\r\ntype GamePhase = 'memorize' | 'recall' | 'transition';\r\n\r\ninterface GameState {\r\n numbers: NumberItem[];\r\n sequence: number[];\r\n currentIndex: number;\r\n level: number;\r\n showNumbers: boolean;\r\n phase: GamePhase;\r\n revealed: Set<number>;\r\n}\r\n\r\nconst config = {\r\n canvasSize: { width: 450, height: 450 },\r\n baseHideTime: 3000,\r\n numberRadius: 30,\r\n};\r\n\r\nconst MemoryGame: React.FC = () => {\r\n const canvasRef = useRef<HTMLCanvasElement>(null);\r\n const [level, setLevel] = useState(1);\r\n const [gameOver, setGameOver] = useState(false);\r\n const [message, setMessage] = useState('');\r\n const [showOverlay, setShowOverlay] = useState<{ visible: boolean; text: string }>({\r\n visible: false,\r\n text: '',\r\n });\r\n const gameStateRef = useRef<GameState>({\r\n numbers: [],\r\n sequence: [],\r\n currentIndex: 0,\r\n level: 1,\r\n showNumbers: true,\r\n phase: 'memorize',\r\n revealed: new Set(),\r\n });\r\n\r\n // Max numbers = 9\r\n const getNumberCount = (lvl: number) => Math.min(4 + lvl, 9);\r\n\r\n // Hide time decreases as level increases, min 500ms\r\n const getHideTime = (lvl: number) =>\r\n Math.max(500, config.baseHideTime - Math.floor((lvl - 1) / 1) * 500);\r\n\r\n const generateNumbers = (lvl: number) => {\r\n const count = getNumberCount(lvl);\r\n const numbers: NumberItem[] = [];\r\n const sequence: number[] = [];\r\n const padding = config.numberRadius * 2.5;\r\n\r\n for (let i = 0; i < count; i++) {\r\n let x: number, y: number, overlap: boolean;\r\n let attempts = 0;\r\n\r\n do {\r\n overlap = false;\r\n x = padding + Math.random() * (config.canvasSize.width - padding * 2);\r\n y = padding + Math.random() * (config.canvasSize.height - padding * 2);\r\n\r\n for (const num of numbers) {\r\n const dx = x - num.x;\r\n const dy = y - num.y;\r\n if (Math.sqrt(dx * dx + dy * dy) < config.numberRadius * 2.5) {\r\n overlap = true;\r\n break;\r\n }\r\n }\r\n attempts++;\r\n } while (overlap && attempts < 100);\r\n\r\n numbers.push({ x, y, value: i + 1, radius: config.numberRadius });\r\n sequence.push(i + 1);\r\n }\r\n\r\n return { numbers, sequence };\r\n };\r\n\r\n const startLevel = (lvl: number) => {\r\n const { numbers, sequence } = generateNumbers(lvl);\r\n gameStateRef.current = {\r\n numbers,\r\n sequence,\r\n currentIndex: 0,\r\n level: lvl,\r\n showNumbers: true,\r\n phase: 'memorize',\r\n revealed: new Set(),\r\n };\r\n setMessage('Memorize the sequence!');\r\n\r\n setTimeout(() => {\r\n gameStateRef.current.showNumbers = false;\r\n gameStateRef.current.phase = 'recall';\r\n setMessage('Click the numbers in order!');\r\n }, getHideTime(lvl));\r\n };\r\n\r\n const resetGame = () => {\r\n setLevel(1);\r\n setGameOver(false);\r\n setShowOverlay({ visible: false, text: '' });\r\n startLevel(1);\r\n };\r\n\r\n const handleCanvasClick = (e: React.MouseEvent<HTMLCanvasElement>) => {\r\n if (gameOver || gameStateRef.current.phase !== 'recall') return;\r\n const canvas = canvasRef.current;\r\n if (!canvas) return;\r\n\r\n const rect = canvas.getBoundingClientRect();\r\n const x = e.clientX - rect.left;\r\n const y = e.clientY - rect.top;\r\n const state = gameStateRef.current;\r\n\r\n for (const num of state.numbers) {\r\n const distance = Math.hypot(x - num.x, y - num.y);\r\n if (distance <= num.radius) {\r\n const expected = state.sequence[state.currentIndex];\r\n if (num.value === expected) {\r\n state.revealed.add(num.value);\r\n state.currentIndex++;\r\n\r\n if (state.currentIndex === state.sequence.length) {\r\n const nextLevel = level + 1;\r\n setLevel(nextLevel);\r\n state.phase = 'transition';\r\n setShowOverlay({ visible: true, text: `Get Ready! Level ${nextLevel}` });\r\n\r\n setTimeout(() => {\r\n setShowOverlay({ visible: false, text: '' });\r\n startLevel(nextLevel);\r\n }, 1500);\r\n }\r\n } else {\r\n setGameOver(true);\r\n setMessage(`Wrong! Clicked ${num.value}, expected ${expected}`);\r\n }\r\n break;\r\n }\r\n }\r\n };\r\n\r\n useEffect(() => startLevel(1), []);\r\n\r\n useEffect(() => {\r\n const canvas = canvasRef.current;\r\n if (!canvas) return;\r\n const ctx = canvas.getContext('2d');\r\n if (!ctx) return;\r\n\r\n let animationId: number;\r\n\r\n const draw = () => {\r\n const state = gameStateRef.current;\r\n ctx.fillStyle = '#000';\r\n ctx.fillRect(0, 0, config.canvasSize.width, config.canvasSize.height);\r\n\r\n state.numbers.forEach((num, idx) => {\r\n // Show green hint only in level 1\r\n const isNext = state.phase === 'recall' && level === 1 && idx === state.currentIndex;\r\n ctx.fillStyle = isNext ? '#22c55e' : '#3b82f6';\r\n ctx.beginPath();\r\n ctx.arc(num.x, num.y, num.radius, 0, Math.PI * 2);\r\n ctx.fill();\r\n\r\n // Reveal numbers if memorizing, transitioning, or already correctly guessed\r\n if (state.showNumbers || state.phase === 'transition' || state.revealed.has(num.value)) {\r\n ctx.fillStyle = '#fff';\r\n ctx.font = 'bold 24px sans-serif';\r\n ctx.textAlign = 'center';\r\n ctx.textBaseline = 'middle';\r\n ctx.fillText(num.value.toString(), num.x, num.y);\r\n }\r\n });\r\n\r\n if (!gameOver) animationId = requestAnimationFrame(draw);\r\n };\r\n\r\n draw();\r\n return () => cancelAnimationFrame(animationId);\r\n }, [gameOver, level]);\r\n\r\n return (\r\n <div className=\"relative flex flex-col items-center gap-4 p-4\">\r\n <div className=\"flex gap-8 text-xl font-bold\">\r\n <div>Level: {level}</div>\r\n <div>Numbers: {getNumberCount(level)}</div>\r\n </div>\r\n <div className=\"text-lg font-semibold text-blue-400 h-6\">{message}</div>\r\n <canvas\r\n ref={canvasRef}\r\n width={config.canvasSize.width}\r\n height={config.canvasSize.height}\r\n className=\"border-2 border-gray-300 cursor-pointer\"\r\n onClick={handleCanvasClick}\r\n />\r\n {gameOver && (\r\n <div className=\"absolute inset-0 flex flex-col items-center justify-center bg-black/60\">\r\n <p className=\"text-xl font-bold text-red-500 mb-2\">Game Over</p>\r\n <p className=\"text-lg text-white mb-4\">Reached Level {level}</p>\r\n <Button onClick={resetGame}>Play Again</Button>\r\n </div>\r\n )}\r\n\r\n {showOverlay.visible && (\r\n <div className=\"absolute inset-0 flex flex-col items-center justify-center bg-black/60\">\r\n <p className=\"text-2xl font-bold text-yellow-400\">{showOverlay.text}</p>\r\n </div>\r\n )}\r\n\r\n <div className=\"text-sm text-center text-foreground max-w-md\">\r\n <div>Memorize the numbers, then click them in sequence (1, 2, 3...)</div>\r\n <div className=\"mt-1 text-xs text-gray-400\">Green circle = next number to click (level 1 only)</div>\r\n </div>\r\n </div>\r\n );\r\n};\r\n\r\nexport default MemoryGame;\r\n"],"mappings":"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","names":["import_jsx_runtime","import_react","import_jsx_runtime","config"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/components/games/spacedodger/index.tsx","../src/components/ui/button.tsx","../src/lib/utils.ts","../src/components/games/memorygame/index.tsx"],"sourcesContent":["import \"./index.css\";\nexport { default as SpaceDodger } from \"./components/games/spacedodger\";\nexport { default as MemoryGame } from \"./components/games/memorygame\";","import React, { useEffect, useRef, useState } from 'react';\nimport { Button } from '@/components/ui/button';\n\ninterface Position {\n x: number;\n y: number;\n}\n\ninterface Enemy extends Position {\n radius: number;\n}\n\ninterface Player extends Position {\n width: number;\n height: number;\n}\n\ninterface SpaceDodgerState {\n player: Player;\n enemies: Enemy[];\n frame: number;\n keys: Record<string, boolean>;\n}\n\n\nconst config = {\n canvasSize : { \n width: 450, \n height: 450 \n },\n player: { x: 200, y: 350, width: 25, height: 50 }\n}\n\nconst SpaceDodger: React.FC = () => {\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const scoreRef = useRef(0);\n const lastBatchScoreRef = useRef(0);\n\n const [score, setScore] = useState(0);\n const [gameOver, setGameOver] = useState(false);\n\n const gameStateRef = useRef<SpaceDodgerState>({\n player: config.player,\n enemies: [],\n frame: 0,\n keys: {}\n });\n\n const resetGame = () => {\n gameStateRef.current = {\n player: config.player,\n enemies: [],\n frame: 0,\n keys: {}\n };\n scoreRef.current = 0;\n lastBatchScoreRef.current = 0;\n setScore(0);\n setGameOver(false);\n };\n\n\n \n useEffect(() => {\n const canvas = canvasRef.current;\n if (!canvas) return;\n const ctx = canvas.getContext('2d');\n if (!ctx) return;\n\n const state = gameStateRef.current;\n\n const handleKeyDown = (e: KeyboardEvent) => {\n state.keys[e.key] = true;\n };\n const handleKeyUp = (e: KeyboardEvent) => {\n state.keys[e.key] = false;\n };\n\n window.addEventListener('keydown', handleKeyDown);\n window.addEventListener('keyup', handleKeyUp);\n\n const randomRadius = () => 10 + Math.random() * 15;\n\n const getEnemySpeed = () => {\n const base = 3;\n const increase = Math.floor(scoreRef.current / 20) * 0.5;\n return base + increase;\n };\n\n let animationId: number;\n\n const gameLoop = () => {\n if (gameOver) return;\n\n state.frame++;\n\n ctx.fillStyle = '#000';\n ctx.fillRect(0, 0, config.canvasSize.width, config.canvasSize.height);\n\n // Player movement\n if (state.keys['ArrowLeft'] && state.player.x > 0) state.player.x -= 5;\n if (state.keys['ArrowRight'] && state.player.x < config.canvasSize.width - state.player.width) state.player.x += 5;\n if (state.keys['ArrowUp'] && state.player.y > 0) state.player.y -= 5;\n if (state.keys['ArrowDown'] && state.player.y < config.canvasSize.height - state.player.height) state.player.y += 5;\n\n // Draw player\n ctx.fillStyle = '#0ea5e9';\n ctx.fillRect(\n state.player.x,\n state.player.y,\n state.player.width,\n state.player.height\n );\n\n // Normal enemy spawn\n if (state.frame % 40 === 0) {\n const radius = randomRadius();\n state.enemies.push({\n x: radius + Math.random() * (config.canvasSize.width - radius * 2),\n y: -radius,\n radius,\n });\n }\n\n // Extra batch every 20 score\n if (\n scoreRef.current > 0 &&\n scoreRef.current % 20 === 0 &&\n lastBatchScoreRef.current !== scoreRef.current\n ) {\n lastBatchScoreRef.current = scoreRef.current;\n const batchCount = 2 + Math.floor(Math.random() * 3);\n\n for (let i = 0; i < batchCount; i++) {\n const radius = randomRadius();\n state.enemies.push({\n x: radius + Math.random() * (config.canvasSize.width - radius * 2),\n y: -Math.random() * 100,\n radius\n });\n }\n }\n\n // Enemies update\n state.enemies = state.enemies.filter(enemy => {\n enemy.y += getEnemySpeed();\n\n // Draw enemy (circle)\n ctx.fillStyle = '#ef4444';\n ctx.beginPath();\n ctx.arc(enemy.x, enemy.y, enemy.radius, 0, Math.PI * 2);\n ctx.fill();\n\n // Circle vs rectangle collision\n const closestX = Math.max(\n state.player.x,\n Math.min(enemy.x, state.player.x + state.player.width)\n );\n const closestY = Math.max(\n state.player.y,\n Math.min(enemy.y, state.player.y + state.player.height)\n );\n\n const dx = enemy.x - closestX;\n const dy = enemy.y - closestY;\n\n if (dx * dx + dy * dy < enemy.radius * enemy.radius) {\n setGameOver(true);\n return false;\n }\n\n // Passed screen\n if (enemy.y - enemy.radius > config.canvasSize.height) {\n setScore(s => {\n scoreRef.current = s + 1;\n return s + 1;\n });\n return false;\n }\n\n return true;\n });\n\n animationId = requestAnimationFrame(gameLoop);\n };\n\n gameLoop();\n\n return () => {\n cancelAnimationFrame(animationId);\n window.removeEventListener('keydown', handleKeyDown);\n window.removeEventListener('keyup', handleKeyUp);\n };\n }, [gameOver]);\n\n return (\n <div className=\"relative flex flex-col items-center gap-4 p-4\">\n <div className=\"text-xl font-bold\">Score: {score}</div>\n <canvas\n ref={canvasRef}\n width={config.canvasSize.width}\n height={config.canvasSize.height}\n className=\"border-2 border-gray-300\"\n />\n\n {gameOver && (\n <div className=\"absolute inset-0 flex flex-col items-center justify-center bg-black/60\">\n <p className=\"text-xl font-bold text-red-500 mb-3\">Game Over</p>\n <Button onClick={resetGame}>Play Again</Button>\n </div>\n )}\n\n <div className=\"text-sm text-foreground\">Use arrow keys to move</div>\n </div>\n );\n};\n\nexport default SpaceDodger;","import * as React from \"react\"\nimport { Slot } from \"@radix-ui/react-slot\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/90\",\n destructive:\n \"bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60\",\n outline:\n \"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50\",\n secondary:\n \"bg-secondary text-secondary-foreground hover:bg-secondary/80\",\n ghost:\n \"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default: \"h-9 px-4 py-2 has-[>svg]:px-3\",\n sm: \"h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5\",\n lg: \"h-10 rounded-md px-6 has-[>svg]:px-4\",\n icon: \"size-9\",\n \"icon-sm\": \"size-8\",\n \"icon-lg\": \"size-10\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n)\n\nfunction Button({\n className,\n variant = \"default\",\n size = \"default\",\n asChild = false,\n ...props\n}: React.ComponentProps<\"button\"> &\n VariantProps<typeof buttonVariants> & {\n asChild?: boolean\n }) {\n const Comp = asChild ? Slot : \"button\"\n\n return (\n <Comp\n data-slot=\"button\"\n data-variant={variant}\n data-size={size}\n className={cn(buttonVariants({ variant, size, className }))}\n {...props}\n />\n )\n}\n\nexport { Button, buttonVariants }\n","import { clsx, type ClassValue } from \"clsx\"\nimport { twMerge } from \"tailwind-merge\"\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}","import React, { useEffect, useRef, useState } from 'react';\nimport { Button } from '@/components/ui/button';\n\ninterface NumberItem {\n x: number;\n y: number;\n value: number;\n radius: number;\n}\n\ntype GamePhase = 'memorize' | 'recall' | 'transition';\n\ninterface GameState {\n numbers: NumberItem[];\n sequence: number[];\n currentIndex: number;\n level: number;\n showNumbers: boolean;\n phase: GamePhase;\n revealed: Set<number>;\n}\n\nconst config = {\n canvasSize: { width: 450, height: 450 },\n baseHideTime: 3000,\n numberRadius: 30,\n};\n\nconst MemoryGame: React.FC = () => {\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const [level, setLevel] = useState(1);\n const [gameOver, setGameOver] = useState(false);\n const [message, setMessage] = useState('');\n const [showOverlay, setShowOverlay] = useState<{ visible: boolean; text: string }>({\n visible: false,\n text: '',\n });\n const gameStateRef = useRef<GameState>({\n numbers: [],\n sequence: [],\n currentIndex: 0,\n level: 1,\n showNumbers: true,\n phase: 'memorize',\n revealed: new Set(),\n });\n\n // Max numbers = 9\n const getNumberCount = (lvl: number) => Math.min(4 + lvl, 9);\n\n // Hide time decreases as level increases, min 500ms\n const getHideTime = (lvl: number) =>\n Math.max(500, config.baseHideTime - Math.floor((lvl - 1) / 1) * 500);\n\n const generateNumbers = (lvl: number) => {\n const count = getNumberCount(lvl);\n const numbers: NumberItem[] = [];\n const sequence: number[] = [];\n const padding = config.numberRadius * 2.5;\n\n for (let i = 0; i < count; i++) {\n let x: number, y: number, overlap: boolean;\n let attempts = 0;\n\n do {\n overlap = false;\n x = padding + Math.random() * (config.canvasSize.width - padding * 2);\n y = padding + Math.random() * (config.canvasSize.height - padding * 2);\n\n for (const num of numbers) {\n const dx = x - num.x;\n const dy = y - num.y;\n if (Math.sqrt(dx * dx + dy * dy) < config.numberRadius * 2.5) {\n overlap = true;\n break;\n }\n }\n attempts++;\n } while (overlap && attempts < 100);\n\n numbers.push({ x, y, value: i + 1, radius: config.numberRadius });\n sequence.push(i + 1);\n }\n\n return { numbers, sequence };\n };\n\n const startLevel = (lvl: number) => {\n const { numbers, sequence } = generateNumbers(lvl);\n gameStateRef.current = {\n numbers,\n sequence,\n currentIndex: 0,\n level: lvl,\n showNumbers: true,\n phase: 'memorize',\n revealed: new Set(),\n };\n setMessage('Memorize the sequence!');\n\n setTimeout(() => {\n gameStateRef.current.showNumbers = false;\n gameStateRef.current.phase = 'recall';\n setMessage('Click the numbers in order!');\n }, getHideTime(lvl));\n };\n\n const resetGame = () => {\n setLevel(1);\n setGameOver(false);\n setShowOverlay({ visible: false, text: '' });\n startLevel(1);\n };\n\n const handleCanvasClick = (e: React.MouseEvent<HTMLCanvasElement>) => {\n if (gameOver || gameStateRef.current.phase !== 'recall') return;\n const canvas = canvasRef.current;\n if (!canvas) return;\n\n const rect = canvas.getBoundingClientRect();\n const x = e.clientX - rect.left;\n const y = e.clientY - rect.top;\n const state = gameStateRef.current;\n\n for (const num of state.numbers) {\n const distance = Math.hypot(x - num.x, y - num.y);\n if (distance <= num.radius) {\n const expected = state.sequence[state.currentIndex];\n if (num.value === expected) {\n state.revealed.add(num.value);\n state.currentIndex++;\n\n if (state.currentIndex === state.sequence.length) {\n const nextLevel = level + 1;\n setLevel(nextLevel);\n state.phase = 'transition';\n setShowOverlay({ visible: true, text: `Get Ready! Level ${nextLevel}` });\n\n setTimeout(() => {\n setShowOverlay({ visible: false, text: '' });\n startLevel(nextLevel);\n }, 1500);\n }\n } else {\n setGameOver(true);\n setMessage(`Wrong! Clicked ${num.value}, expected ${expected}`);\n }\n break;\n }\n }\n };\n\n useEffect(() => startLevel(1), []);\n\n useEffect(() => {\n const canvas = canvasRef.current;\n if (!canvas) return;\n const ctx = canvas.getContext('2d');\n if (!ctx) return;\n\n let animationId: number;\n\n const draw = () => {\n const state = gameStateRef.current;\n ctx.fillStyle = '#000';\n ctx.fillRect(0, 0, config.canvasSize.width, config.canvasSize.height);\n\n state.numbers.forEach((num, idx) => {\n // Show green hint only in level 1\n const isNext = state.phase === 'recall' && level === 1 && idx === state.currentIndex;\n ctx.fillStyle = isNext ? '#22c55e' : '#3b82f6';\n ctx.beginPath();\n ctx.arc(num.x, num.y, num.radius, 0, Math.PI * 2);\n ctx.fill();\n\n // Reveal numbers if memorizing, transitioning, or already correctly guessed\n if (state.showNumbers || state.phase === 'transition' || state.revealed.has(num.value)) {\n ctx.fillStyle = '#fff';\n ctx.font = 'bold 24px sans-serif';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(num.value.toString(), num.x, num.y);\n }\n });\n\n if (!gameOver) animationId = requestAnimationFrame(draw);\n };\n\n draw();\n return () => cancelAnimationFrame(animationId);\n }, [gameOver, level]);\n\n return (\n <div className=\"relative flex flex-col items-center gap-4 p-4\">\n <div className=\"flex gap-8 text-xl font-bold\">\n <div>Level: {level}</div>\n <div>Numbers: {getNumberCount(level)}</div>\n </div>\n <div className=\"text-lg font-semibold text-blue-400 h-6\">{message}</div>\n <canvas\n ref={canvasRef}\n width={config.canvasSize.width}\n height={config.canvasSize.height}\n className=\"border-2 border-gray-300 cursor-pointer\"\n onClick={handleCanvasClick}\n />\n {gameOver && (\n <div className=\"absolute inset-0 flex flex-col items-center justify-center bg-black/60\">\n <p className=\"text-xl font-bold text-red-500 mb-2\">Game Over</p>\n <p className=\"text-lg text-white mb-4\">Reached Level {level}</p>\n <Button onClick={resetGame}>Play Again</Button>\n </div>\n )}\n\n {showOverlay.visible && (\n <div className=\"absolute inset-0 flex flex-col items-center justify-center bg-black/60\">\n <p className=\"text-2xl font-bold text-yellow-400\">{showOverlay.text}</p>\n </div>\n )}\n\n <div className=\"text-sm text-center text-foreground max-w-md\">\n <div>Memorize the numbers, then click them in sequence (1, 2, 3...)</div>\n <div className=\"mt-1 text-xs text-gray-400\">Green circle = next number to click (level 1 only)</div>\n </div>\n </div>\n );\n};\n\nexport default MemoryGame;\n"],"mappings":"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","names":["import_jsx_runtime","import_react","import_jsx_runtime","config"]}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/games/spacedodger/index.tsx","../src/components/ui/button.tsx","../src/lib/utils.ts","../src/components/games/memorygame/index.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from 'react';\r\nimport { Button } from '@/components/ui/button';\r\n\r\ninterface Position {\r\n x: number;\r\n y: number;\r\n}\r\n\r\ninterface Enemy extends Position {\r\n radius: number;\r\n}\r\n\r\ninterface Player extends Position {\r\n width: number;\r\n height: number;\r\n}\r\n\r\ninterface SpaceDodgerState {\r\n player: Player;\r\n enemies: Enemy[];\r\n frame: number;\r\n keys: Record<string, boolean>;\r\n}\r\n\r\n\r\nconst config = {\r\n canvasSize : { \r\n width: 450, \r\n height: 450 \r\n },\r\n player: { x: 200, y: 350, width: 25, height: 50 }\r\n}\r\n\r\nconst SpaceDodger: React.FC = () => {\r\n const canvasRef = useRef<HTMLCanvasElement>(null);\r\n const scoreRef = useRef(0);\r\n const lastBatchScoreRef = useRef(0);\r\n\r\n const [score, setScore] = useState(0);\r\n const [gameOver, setGameOver] = useState(false);\r\n\r\n const gameStateRef = useRef<SpaceDodgerState>({\r\n player: config.player,\r\n enemies: [],\r\n frame: 0,\r\n keys: {}\r\n });\r\n\r\n const resetGame = () => {\r\n gameStateRef.current = {\r\n player: config.player,\r\n enemies: [],\r\n frame: 0,\r\n keys: {}\r\n };\r\n scoreRef.current = 0;\r\n lastBatchScoreRef.current = 0;\r\n setScore(0);\r\n setGameOver(false);\r\n };\r\n\r\n\r\n \r\n useEffect(() => {\r\n const canvas = canvasRef.current;\r\n if (!canvas) return;\r\n const ctx = canvas.getContext('2d');\r\n if (!ctx) return;\r\n\r\n const state = gameStateRef.current;\r\n\r\n const handleKeyDown = (e: KeyboardEvent) => {\r\n state.keys[e.key] = true;\r\n };\r\n const handleKeyUp = (e: KeyboardEvent) => {\r\n state.keys[e.key] = false;\r\n };\r\n\r\n window.addEventListener('keydown', handleKeyDown);\r\n window.addEventListener('keyup', handleKeyUp);\r\n\r\n const randomRadius = () => 10 + Math.random() * 15;\r\n\r\n const getEnemySpeed = () => {\r\n const base = 3;\r\n const increase = Math.floor(scoreRef.current / 20) * 0.5;\r\n return base + increase;\r\n };\r\n\r\n let animationId: number;\r\n\r\n const gameLoop = () => {\r\n if (gameOver) return;\r\n\r\n state.frame++;\r\n\r\n ctx.fillStyle = '#000';\r\n ctx.fillRect(0, 0, config.canvasSize.width, config.canvasSize.height);\r\n\r\n // Player movement\r\n if (state.keys['ArrowLeft'] && state.player.x > 0) state.player.x -= 5;\r\n if (state.keys['ArrowRight'] && state.player.x < config.canvasSize.width - state.player.width) state.player.x += 5;\r\n if (state.keys['ArrowUp'] && state.player.y > 0) state.player.y -= 5;\r\n if (state.keys['ArrowDown'] && state.player.y < config.canvasSize.height - state.player.height) state.player.y += 5;\r\n\r\n // Draw player\r\n ctx.fillStyle = '#0ea5e9';\r\n ctx.fillRect(\r\n state.player.x,\r\n state.player.y,\r\n state.player.width,\r\n state.player.height\r\n );\r\n\r\n // Normal enemy spawn\r\n if (state.frame % 40 === 0) {\r\n const radius = randomRadius();\r\n state.enemies.push({\r\n x: radius + Math.random() * (config.canvasSize.width - radius * 2),\r\n y: -radius,\r\n radius,\r\n });\r\n }\r\n\r\n // Extra batch every 20 score\r\n if (\r\n scoreRef.current > 0 &&\r\n scoreRef.current % 20 === 0 &&\r\n lastBatchScoreRef.current !== scoreRef.current\r\n ) {\r\n lastBatchScoreRef.current = scoreRef.current;\r\n const batchCount = 2 + Math.floor(Math.random() * 3);\r\n\r\n for (let i = 0; i < batchCount; i++) {\r\n const radius = randomRadius();\r\n state.enemies.push({\r\n x: radius + Math.random() * (config.canvasSize.width - radius * 2),\r\n y: -Math.random() * 100,\r\n radius\r\n });\r\n }\r\n }\r\n\r\n // Enemies update\r\n state.enemies = state.enemies.filter(enemy => {\r\n enemy.y += getEnemySpeed();\r\n\r\n // Draw enemy (circle)\r\n ctx.fillStyle = '#ef4444';\r\n ctx.beginPath();\r\n ctx.arc(enemy.x, enemy.y, enemy.radius, 0, Math.PI * 2);\r\n ctx.fill();\r\n\r\n // Circle vs rectangle collision\r\n const closestX = Math.max(\r\n state.player.x,\r\n Math.min(enemy.x, state.player.x + state.player.width)\r\n );\r\n const closestY = Math.max(\r\n state.player.y,\r\n Math.min(enemy.y, state.player.y + state.player.height)\r\n );\r\n\r\n const dx = enemy.x - closestX;\r\n const dy = enemy.y - closestY;\r\n\r\n if (dx * dx + dy * dy < enemy.radius * enemy.radius) {\r\n setGameOver(true);\r\n return false;\r\n }\r\n\r\n // Passed screen\r\n if (enemy.y - enemy.radius > config.canvasSize.height) {\r\n setScore(s => {\r\n scoreRef.current = s + 1;\r\n return s + 1;\r\n });\r\n return false;\r\n }\r\n\r\n return true;\r\n });\r\n\r\n animationId = requestAnimationFrame(gameLoop);\r\n };\r\n\r\n gameLoop();\r\n\r\n return () => {\r\n cancelAnimationFrame(animationId);\r\n window.removeEventListener('keydown', handleKeyDown);\r\n window.removeEventListener('keyup', handleKeyUp);\r\n };\r\n }, [gameOver]);\r\n\r\n return (\r\n <div className=\"relative flex flex-col items-center gap-4 p-4\">\r\n <div className=\"text-xl font-bold\">Score: {score}</div>\r\n <canvas\r\n ref={canvasRef}\r\n width={config.canvasSize.width}\r\n height={config.canvasSize.height}\r\n className=\"border-2 border-gray-300\"\r\n />\r\n\r\n {gameOver && (\r\n <div className=\"absolute inset-0 flex flex-col items-center justify-center bg-black/60\">\r\n <p className=\"text-xl font-bold text-red-500 mb-3\">Game Over</p>\r\n <Button onClick={resetGame}>Play Again</Button>\r\n </div>\r\n )}\r\n\r\n <div className=\"text-sm text-foreground\">Use arrow keys to move</div>\r\n </div>\r\n );\r\n};\r\n\r\nexport default SpaceDodger;","import * as React from \"react\"\r\nimport { Slot } from \"@radix-ui/react-slot\"\r\nimport { cva, type VariantProps } from \"class-variance-authority\"\r\n\r\nimport { cn } from \"@/lib/utils\"\r\n\r\nconst buttonVariants = cva(\r\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive\",\r\n {\r\n variants: {\r\n variant: {\r\n default: \"bg-primary text-primary-foreground hover:bg-primary/90\",\r\n destructive:\r\n \"bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60\",\r\n outline:\r\n \"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50\",\r\n secondary:\r\n \"bg-secondary text-secondary-foreground hover:bg-secondary/80\",\r\n ghost:\r\n \"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50\",\r\n link: \"text-primary underline-offset-4 hover:underline\",\r\n },\r\n size: {\r\n default: \"h-9 px-4 py-2 has-[>svg]:px-3\",\r\n sm: \"h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5\",\r\n lg: \"h-10 rounded-md px-6 has-[>svg]:px-4\",\r\n icon: \"size-9\",\r\n \"icon-sm\": \"size-8\",\r\n \"icon-lg\": \"size-10\",\r\n },\r\n },\r\n defaultVariants: {\r\n variant: \"default\",\r\n size: \"default\",\r\n },\r\n }\r\n)\r\n\r\nfunction Button({\r\n className,\r\n variant = \"default\",\r\n size = \"default\",\r\n asChild = false,\r\n ...props\r\n}: React.ComponentProps<\"button\"> &\r\n VariantProps<typeof buttonVariants> & {\r\n asChild?: boolean\r\n }) {\r\n const Comp = asChild ? Slot : \"button\"\r\n\r\n return (\r\n <Comp\r\n data-slot=\"button\"\r\n data-variant={variant}\r\n data-size={size}\r\n className={cn(buttonVariants({ variant, size, className }))}\r\n {...props}\r\n />\r\n )\r\n}\r\n\r\nexport { Button, buttonVariants }\r\n","import { clsx, type ClassValue } from \"clsx\"\r\nimport { twMerge } from \"tailwind-merge\"\r\n\r\nexport function cn(...inputs: ClassValue[]) {\r\n return twMerge(clsx(inputs))\r\n}","import React, { useEffect, useRef, useState } from 'react';\r\nimport { Button } from '@/components/ui/button';\r\n\r\ninterface NumberItem {\r\n x: number;\r\n y: number;\r\n value: number;\r\n radius: number;\r\n}\r\n\r\ntype GamePhase = 'memorize' | 'recall' | 'transition';\r\n\r\ninterface GameState {\r\n numbers: NumberItem[];\r\n sequence: number[];\r\n currentIndex: number;\r\n level: number;\r\n showNumbers: boolean;\r\n phase: GamePhase;\r\n revealed: Set<number>;\r\n}\r\n\r\nconst config = {\r\n canvasSize: { width: 450, height: 450 },\r\n baseHideTime: 3000,\r\n numberRadius: 30,\r\n};\r\n\r\nconst MemoryGame: React.FC = () => {\r\n const canvasRef = useRef<HTMLCanvasElement>(null);\r\n const [level, setLevel] = useState(1);\r\n const [gameOver, setGameOver] = useState(false);\r\n const [message, setMessage] = useState('');\r\n const [showOverlay, setShowOverlay] = useState<{ visible: boolean; text: string }>({\r\n visible: false,\r\n text: '',\r\n });\r\n const gameStateRef = useRef<GameState>({\r\n numbers: [],\r\n sequence: [],\r\n currentIndex: 0,\r\n level: 1,\r\n showNumbers: true,\r\n phase: 'memorize',\r\n revealed: new Set(),\r\n });\r\n\r\n // Max numbers = 9\r\n const getNumberCount = (lvl: number) => Math.min(4 + lvl, 9);\r\n\r\n // Hide time decreases as level increases, min 500ms\r\n const getHideTime = (lvl: number) =>\r\n Math.max(500, config.baseHideTime - Math.floor((lvl - 1) / 1) * 500);\r\n\r\n const generateNumbers = (lvl: number) => {\r\n const count = getNumberCount(lvl);\r\n const numbers: NumberItem[] = [];\r\n const sequence: number[] = [];\r\n const padding = config.numberRadius * 2.5;\r\n\r\n for (let i = 0; i < count; i++) {\r\n let x: number, y: number, overlap: boolean;\r\n let attempts = 0;\r\n\r\n do {\r\n overlap = false;\r\n x = padding + Math.random() * (config.canvasSize.width - padding * 2);\r\n y = padding + Math.random() * (config.canvasSize.height - padding * 2);\r\n\r\n for (const num of numbers) {\r\n const dx = x - num.x;\r\n const dy = y - num.y;\r\n if (Math.sqrt(dx * dx + dy * dy) < config.numberRadius * 2.5) {\r\n overlap = true;\r\n break;\r\n }\r\n }\r\n attempts++;\r\n } while (overlap && attempts < 100);\r\n\r\n numbers.push({ x, y, value: i + 1, radius: config.numberRadius });\r\n sequence.push(i + 1);\r\n }\r\n\r\n return { numbers, sequence };\r\n };\r\n\r\n const startLevel = (lvl: number) => {\r\n const { numbers, sequence } = generateNumbers(lvl);\r\n gameStateRef.current = {\r\n numbers,\r\n sequence,\r\n currentIndex: 0,\r\n level: lvl,\r\n showNumbers: true,\r\n phase: 'memorize',\r\n revealed: new Set(),\r\n };\r\n setMessage('Memorize the sequence!');\r\n\r\n setTimeout(() => {\r\n gameStateRef.current.showNumbers = false;\r\n gameStateRef.current.phase = 'recall';\r\n setMessage('Click the numbers in order!');\r\n }, getHideTime(lvl));\r\n };\r\n\r\n const resetGame = () => {\r\n setLevel(1);\r\n setGameOver(false);\r\n setShowOverlay({ visible: false, text: '' });\r\n startLevel(1);\r\n };\r\n\r\n const handleCanvasClick = (e: React.MouseEvent<HTMLCanvasElement>) => {\r\n if (gameOver || gameStateRef.current.phase !== 'recall') return;\r\n const canvas = canvasRef.current;\r\n if (!canvas) return;\r\n\r\n const rect = canvas.getBoundingClientRect();\r\n const x = e.clientX - rect.left;\r\n const y = e.clientY - rect.top;\r\n const state = gameStateRef.current;\r\n\r\n for (const num of state.numbers) {\r\n const distance = Math.hypot(x - num.x, y - num.y);\r\n if (distance <= num.radius) {\r\n const expected = state.sequence[state.currentIndex];\r\n if (num.value === expected) {\r\n state.revealed.add(num.value);\r\n state.currentIndex++;\r\n\r\n if (state.currentIndex === state.sequence.length) {\r\n const nextLevel = level + 1;\r\n setLevel(nextLevel);\r\n state.phase = 'transition';\r\n setShowOverlay({ visible: true, text: `Get Ready! Level ${nextLevel}` });\r\n\r\n setTimeout(() => {\r\n setShowOverlay({ visible: false, text: '' });\r\n startLevel(nextLevel);\r\n }, 1500);\r\n }\r\n } else {\r\n setGameOver(true);\r\n setMessage(`Wrong! Clicked ${num.value}, expected ${expected}`);\r\n }\r\n break;\r\n }\r\n }\r\n };\r\n\r\n useEffect(() => startLevel(1), []);\r\n\r\n useEffect(() => {\r\n const canvas = canvasRef.current;\r\n if (!canvas) return;\r\n const ctx = canvas.getContext('2d');\r\n if (!ctx) return;\r\n\r\n let animationId: number;\r\n\r\n const draw = () => {\r\n const state = gameStateRef.current;\r\n ctx.fillStyle = '#000';\r\n ctx.fillRect(0, 0, config.canvasSize.width, config.canvasSize.height);\r\n\r\n state.numbers.forEach((num, idx) => {\r\n // Show green hint only in level 1\r\n const isNext = state.phase === 'recall' && level === 1 && idx === state.currentIndex;\r\n ctx.fillStyle = isNext ? '#22c55e' : '#3b82f6';\r\n ctx.beginPath();\r\n ctx.arc(num.x, num.y, num.radius, 0, Math.PI * 2);\r\n ctx.fill();\r\n\r\n // Reveal numbers if memorizing, transitioning, or already correctly guessed\r\n if (state.showNumbers || state.phase === 'transition' || state.revealed.has(num.value)) {\r\n ctx.fillStyle = '#fff';\r\n ctx.font = 'bold 24px sans-serif';\r\n ctx.textAlign = 'center';\r\n ctx.textBaseline = 'middle';\r\n ctx.fillText(num.value.toString(), num.x, num.y);\r\n }\r\n });\r\n\r\n if (!gameOver) animationId = requestAnimationFrame(draw);\r\n };\r\n\r\n draw();\r\n return () => cancelAnimationFrame(animationId);\r\n }, [gameOver, level]);\r\n\r\n return (\r\n <div className=\"relative flex flex-col items-center gap-4 p-4\">\r\n <div className=\"flex gap-8 text-xl font-bold\">\r\n <div>Level: {level}</div>\r\n <div>Numbers: {getNumberCount(level)}</div>\r\n </div>\r\n <div className=\"text-lg font-semibold text-blue-400 h-6\">{message}</div>\r\n <canvas\r\n ref={canvasRef}\r\n width={config.canvasSize.width}\r\n height={config.canvasSize.height}\r\n className=\"border-2 border-gray-300 cursor-pointer\"\r\n onClick={handleCanvasClick}\r\n />\r\n {gameOver && (\r\n <div className=\"absolute inset-0 flex flex-col items-center justify-center bg-black/60\">\r\n <p className=\"text-xl font-bold text-red-500 mb-2\">Game Over</p>\r\n <p className=\"text-lg text-white mb-4\">Reached Level {level}</p>\r\n <Button onClick={resetGame}>Play Again</Button>\r\n </div>\r\n )}\r\n\r\n {showOverlay.visible && (\r\n <div className=\"absolute inset-0 flex flex-col items-center justify-center bg-black/60\">\r\n <p className=\"text-2xl font-bold text-yellow-400\">{showOverlay.text}</p>\r\n </div>\r\n )}\r\n\r\n <div className=\"text-sm text-center text-foreground max-w-md\">\r\n <div>Memorize the numbers, then click them in sequence (1, 2, 3...)</div>\r\n <div className=\"mt-1 text-xs text-gray-400\">Green circle = next number to click (level 1 only)</div>\r\n </div>\r\n </div>\r\n );\r\n};\r\n\r\nexport default MemoryGame;\r\n"],"mappings":"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","names":["jsx","useEffect","useRef","useState","jsx","jsxs","config","useRef","useState","useEffect"]}
|
|
1
|
+
{"version":3,"sources":["../src/components/games/spacedodger/index.tsx","../src/components/ui/button.tsx","../src/lib/utils.ts","../src/components/games/memorygame/index.tsx"],"sourcesContent":["import React, { useEffect, useRef, useState } from 'react';\nimport { Button } from '@/components/ui/button';\n\ninterface Position {\n x: number;\n y: number;\n}\n\ninterface Enemy extends Position {\n radius: number;\n}\n\ninterface Player extends Position {\n width: number;\n height: number;\n}\n\ninterface SpaceDodgerState {\n player: Player;\n enemies: Enemy[];\n frame: number;\n keys: Record<string, boolean>;\n}\n\n\nconst config = {\n canvasSize : { \n width: 450, \n height: 450 \n },\n player: { x: 200, y: 350, width: 25, height: 50 }\n}\n\nconst SpaceDodger: React.FC = () => {\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const scoreRef = useRef(0);\n const lastBatchScoreRef = useRef(0);\n\n const [score, setScore] = useState(0);\n const [gameOver, setGameOver] = useState(false);\n\n const gameStateRef = useRef<SpaceDodgerState>({\n player: config.player,\n enemies: [],\n frame: 0,\n keys: {}\n });\n\n const resetGame = () => {\n gameStateRef.current = {\n player: config.player,\n enemies: [],\n frame: 0,\n keys: {}\n };\n scoreRef.current = 0;\n lastBatchScoreRef.current = 0;\n setScore(0);\n setGameOver(false);\n };\n\n\n \n useEffect(() => {\n const canvas = canvasRef.current;\n if (!canvas) return;\n const ctx = canvas.getContext('2d');\n if (!ctx) return;\n\n const state = gameStateRef.current;\n\n const handleKeyDown = (e: KeyboardEvent) => {\n state.keys[e.key] = true;\n };\n const handleKeyUp = (e: KeyboardEvent) => {\n state.keys[e.key] = false;\n };\n\n window.addEventListener('keydown', handleKeyDown);\n window.addEventListener('keyup', handleKeyUp);\n\n const randomRadius = () => 10 + Math.random() * 15;\n\n const getEnemySpeed = () => {\n const base = 3;\n const increase = Math.floor(scoreRef.current / 20) * 0.5;\n return base + increase;\n };\n\n let animationId: number;\n\n const gameLoop = () => {\n if (gameOver) return;\n\n state.frame++;\n\n ctx.fillStyle = '#000';\n ctx.fillRect(0, 0, config.canvasSize.width, config.canvasSize.height);\n\n // Player movement\n if (state.keys['ArrowLeft'] && state.player.x > 0) state.player.x -= 5;\n if (state.keys['ArrowRight'] && state.player.x < config.canvasSize.width - state.player.width) state.player.x += 5;\n if (state.keys['ArrowUp'] && state.player.y > 0) state.player.y -= 5;\n if (state.keys['ArrowDown'] && state.player.y < config.canvasSize.height - state.player.height) state.player.y += 5;\n\n // Draw player\n ctx.fillStyle = '#0ea5e9';\n ctx.fillRect(\n state.player.x,\n state.player.y,\n state.player.width,\n state.player.height\n );\n\n // Normal enemy spawn\n if (state.frame % 40 === 0) {\n const radius = randomRadius();\n state.enemies.push({\n x: radius + Math.random() * (config.canvasSize.width - radius * 2),\n y: -radius,\n radius,\n });\n }\n\n // Extra batch every 20 score\n if (\n scoreRef.current > 0 &&\n scoreRef.current % 20 === 0 &&\n lastBatchScoreRef.current !== scoreRef.current\n ) {\n lastBatchScoreRef.current = scoreRef.current;\n const batchCount = 2 + Math.floor(Math.random() * 3);\n\n for (let i = 0; i < batchCount; i++) {\n const radius = randomRadius();\n state.enemies.push({\n x: radius + Math.random() * (config.canvasSize.width - radius * 2),\n y: -Math.random() * 100,\n radius\n });\n }\n }\n\n // Enemies update\n state.enemies = state.enemies.filter(enemy => {\n enemy.y += getEnemySpeed();\n\n // Draw enemy (circle)\n ctx.fillStyle = '#ef4444';\n ctx.beginPath();\n ctx.arc(enemy.x, enemy.y, enemy.radius, 0, Math.PI * 2);\n ctx.fill();\n\n // Circle vs rectangle collision\n const closestX = Math.max(\n state.player.x,\n Math.min(enemy.x, state.player.x + state.player.width)\n );\n const closestY = Math.max(\n state.player.y,\n Math.min(enemy.y, state.player.y + state.player.height)\n );\n\n const dx = enemy.x - closestX;\n const dy = enemy.y - closestY;\n\n if (dx * dx + dy * dy < enemy.radius * enemy.radius) {\n setGameOver(true);\n return false;\n }\n\n // Passed screen\n if (enemy.y - enemy.radius > config.canvasSize.height) {\n setScore(s => {\n scoreRef.current = s + 1;\n return s + 1;\n });\n return false;\n }\n\n return true;\n });\n\n animationId = requestAnimationFrame(gameLoop);\n };\n\n gameLoop();\n\n return () => {\n cancelAnimationFrame(animationId);\n window.removeEventListener('keydown', handleKeyDown);\n window.removeEventListener('keyup', handleKeyUp);\n };\n }, [gameOver]);\n\n return (\n <div className=\"relative flex flex-col items-center gap-4 p-4\">\n <div className=\"text-xl font-bold\">Score: {score}</div>\n <canvas\n ref={canvasRef}\n width={config.canvasSize.width}\n height={config.canvasSize.height}\n className=\"border-2 border-gray-300\"\n />\n\n {gameOver && (\n <div className=\"absolute inset-0 flex flex-col items-center justify-center bg-black/60\">\n <p className=\"text-xl font-bold text-red-500 mb-3\">Game Over</p>\n <Button onClick={resetGame}>Play Again</Button>\n </div>\n )}\n\n <div className=\"text-sm text-foreground\">Use arrow keys to move</div>\n </div>\n );\n};\n\nexport default SpaceDodger;","import * as React from \"react\"\nimport { Slot } from \"@radix-ui/react-slot\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\n\nconst buttonVariants = cva(\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/90\",\n destructive:\n \"bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60\",\n outline:\n \"border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50\",\n secondary:\n \"bg-secondary text-secondary-foreground hover:bg-secondary/80\",\n ghost:\n \"hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50\",\n link: \"text-primary underline-offset-4 hover:underline\",\n },\n size: {\n default: \"h-9 px-4 py-2 has-[>svg]:px-3\",\n sm: \"h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5\",\n lg: \"h-10 rounded-md px-6 has-[>svg]:px-4\",\n icon: \"size-9\",\n \"icon-sm\": \"size-8\",\n \"icon-lg\": \"size-10\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n }\n)\n\nfunction Button({\n className,\n variant = \"default\",\n size = \"default\",\n asChild = false,\n ...props\n}: React.ComponentProps<\"button\"> &\n VariantProps<typeof buttonVariants> & {\n asChild?: boolean\n }) {\n const Comp = asChild ? Slot : \"button\"\n\n return (\n <Comp\n data-slot=\"button\"\n data-variant={variant}\n data-size={size}\n className={cn(buttonVariants({ variant, size, className }))}\n {...props}\n />\n )\n}\n\nexport { Button, buttonVariants }\n","import { clsx, type ClassValue } from \"clsx\"\nimport { twMerge } from \"tailwind-merge\"\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs))\n}","import React, { useEffect, useRef, useState } from 'react';\nimport { Button } from '@/components/ui/button';\n\ninterface NumberItem {\n x: number;\n y: number;\n value: number;\n radius: number;\n}\n\ntype GamePhase = 'memorize' | 'recall' | 'transition';\n\ninterface GameState {\n numbers: NumberItem[];\n sequence: number[];\n currentIndex: number;\n level: number;\n showNumbers: boolean;\n phase: GamePhase;\n revealed: Set<number>;\n}\n\nconst config = {\n canvasSize: { width: 450, height: 450 },\n baseHideTime: 3000,\n numberRadius: 30,\n};\n\nconst MemoryGame: React.FC = () => {\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const [level, setLevel] = useState(1);\n const [gameOver, setGameOver] = useState(false);\n const [message, setMessage] = useState('');\n const [showOverlay, setShowOverlay] = useState<{ visible: boolean; text: string }>({\n visible: false,\n text: '',\n });\n const gameStateRef = useRef<GameState>({\n numbers: [],\n sequence: [],\n currentIndex: 0,\n level: 1,\n showNumbers: true,\n phase: 'memorize',\n revealed: new Set(),\n });\n\n // Max numbers = 9\n const getNumberCount = (lvl: number) => Math.min(4 + lvl, 9);\n\n // Hide time decreases as level increases, min 500ms\n const getHideTime = (lvl: number) =>\n Math.max(500, config.baseHideTime - Math.floor((lvl - 1) / 1) * 500);\n\n const generateNumbers = (lvl: number) => {\n const count = getNumberCount(lvl);\n const numbers: NumberItem[] = [];\n const sequence: number[] = [];\n const padding = config.numberRadius * 2.5;\n\n for (let i = 0; i < count; i++) {\n let x: number, y: number, overlap: boolean;\n let attempts = 0;\n\n do {\n overlap = false;\n x = padding + Math.random() * (config.canvasSize.width - padding * 2);\n y = padding + Math.random() * (config.canvasSize.height - padding * 2);\n\n for (const num of numbers) {\n const dx = x - num.x;\n const dy = y - num.y;\n if (Math.sqrt(dx * dx + dy * dy) < config.numberRadius * 2.5) {\n overlap = true;\n break;\n }\n }\n attempts++;\n } while (overlap && attempts < 100);\n\n numbers.push({ x, y, value: i + 1, radius: config.numberRadius });\n sequence.push(i + 1);\n }\n\n return { numbers, sequence };\n };\n\n const startLevel = (lvl: number) => {\n const { numbers, sequence } = generateNumbers(lvl);\n gameStateRef.current = {\n numbers,\n sequence,\n currentIndex: 0,\n level: lvl,\n showNumbers: true,\n phase: 'memorize',\n revealed: new Set(),\n };\n setMessage('Memorize the sequence!');\n\n setTimeout(() => {\n gameStateRef.current.showNumbers = false;\n gameStateRef.current.phase = 'recall';\n setMessage('Click the numbers in order!');\n }, getHideTime(lvl));\n };\n\n const resetGame = () => {\n setLevel(1);\n setGameOver(false);\n setShowOverlay({ visible: false, text: '' });\n startLevel(1);\n };\n\n const handleCanvasClick = (e: React.MouseEvent<HTMLCanvasElement>) => {\n if (gameOver || gameStateRef.current.phase !== 'recall') return;\n const canvas = canvasRef.current;\n if (!canvas) return;\n\n const rect = canvas.getBoundingClientRect();\n const x = e.clientX - rect.left;\n const y = e.clientY - rect.top;\n const state = gameStateRef.current;\n\n for (const num of state.numbers) {\n const distance = Math.hypot(x - num.x, y - num.y);\n if (distance <= num.radius) {\n const expected = state.sequence[state.currentIndex];\n if (num.value === expected) {\n state.revealed.add(num.value);\n state.currentIndex++;\n\n if (state.currentIndex === state.sequence.length) {\n const nextLevel = level + 1;\n setLevel(nextLevel);\n state.phase = 'transition';\n setShowOverlay({ visible: true, text: `Get Ready! Level ${nextLevel}` });\n\n setTimeout(() => {\n setShowOverlay({ visible: false, text: '' });\n startLevel(nextLevel);\n }, 1500);\n }\n } else {\n setGameOver(true);\n setMessage(`Wrong! Clicked ${num.value}, expected ${expected}`);\n }\n break;\n }\n }\n };\n\n useEffect(() => startLevel(1), []);\n\n useEffect(() => {\n const canvas = canvasRef.current;\n if (!canvas) return;\n const ctx = canvas.getContext('2d');\n if (!ctx) return;\n\n let animationId: number;\n\n const draw = () => {\n const state = gameStateRef.current;\n ctx.fillStyle = '#000';\n ctx.fillRect(0, 0, config.canvasSize.width, config.canvasSize.height);\n\n state.numbers.forEach((num, idx) => {\n // Show green hint only in level 1\n const isNext = state.phase === 'recall' && level === 1 && idx === state.currentIndex;\n ctx.fillStyle = isNext ? '#22c55e' : '#3b82f6';\n ctx.beginPath();\n ctx.arc(num.x, num.y, num.radius, 0, Math.PI * 2);\n ctx.fill();\n\n // Reveal numbers if memorizing, transitioning, or already correctly guessed\n if (state.showNumbers || state.phase === 'transition' || state.revealed.has(num.value)) {\n ctx.fillStyle = '#fff';\n ctx.font = 'bold 24px sans-serif';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'middle';\n ctx.fillText(num.value.toString(), num.x, num.y);\n }\n });\n\n if (!gameOver) animationId = requestAnimationFrame(draw);\n };\n\n draw();\n return () => cancelAnimationFrame(animationId);\n }, [gameOver, level]);\n\n return (\n <div className=\"relative flex flex-col items-center gap-4 p-4\">\n <div className=\"flex gap-8 text-xl font-bold\">\n <div>Level: {level}</div>\n <div>Numbers: {getNumberCount(level)}</div>\n </div>\n <div className=\"text-lg font-semibold text-blue-400 h-6\">{message}</div>\n <canvas\n ref={canvasRef}\n width={config.canvasSize.width}\n height={config.canvasSize.height}\n className=\"border-2 border-gray-300 cursor-pointer\"\n onClick={handleCanvasClick}\n />\n {gameOver && (\n <div className=\"absolute inset-0 flex flex-col items-center justify-center bg-black/60\">\n <p className=\"text-xl font-bold text-red-500 mb-2\">Game Over</p>\n <p className=\"text-lg text-white mb-4\">Reached Level {level}</p>\n <Button onClick={resetGame}>Play Again</Button>\n </div>\n )}\n\n {showOverlay.visible && (\n <div className=\"absolute inset-0 flex flex-col items-center justify-center bg-black/60\">\n <p className=\"text-2xl font-bold text-yellow-400\">{showOverlay.text}</p>\n </div>\n )}\n\n <div className=\"text-sm text-center text-foreground max-w-md\">\n <div>Memorize the numbers, then click them in sequence (1, 2, 3...)</div>\n <div className=\"mt-1 text-xs text-gray-400\">Green circle = next number to click (level 1 only)</div>\n </div>\n </div>\n );\n};\n\nexport default MemoryGame;\n"],"mappings":"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","names":["jsx","useEffect","useRef","useState","jsx","jsxs","config","useRef","useState","useEffect"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jonelhatwell/arcade-games",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.16",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.cjs",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -27,28 +27,31 @@
|
|
|
27
27
|
"class-variance-authority": "^0.7.1",
|
|
28
28
|
"clsx": "^2.1.1",
|
|
29
29
|
"lucide-react": "^0.562.0",
|
|
30
|
-
"react": "^19.2.
|
|
31
|
-
"react-dom": "^19.2.
|
|
30
|
+
"react": "^19.2.3",
|
|
31
|
+
"react-dom": "^19.2.3",
|
|
32
32
|
"tailwind-merge": "^3.4.0",
|
|
33
33
|
"tw-animate-css": "^1.4.0"
|
|
34
34
|
},
|
|
35
|
+
"publishConfig": {
|
|
36
|
+
"access": "public"
|
|
37
|
+
},
|
|
35
38
|
"devDependencies": {
|
|
36
|
-
"@eslint/js": "^9.39.
|
|
39
|
+
"@eslint/js": "^9.39.2",
|
|
37
40
|
"@tailwindcss/postcss": "^4.1.18",
|
|
38
|
-
"@types/node": "^24.10.
|
|
39
|
-
"@types/react": "^19.2.
|
|
41
|
+
"@types/node": "^24.10.4",
|
|
42
|
+
"@types/react": "^19.2.7",
|
|
40
43
|
"@types/react-dom": "^19.2.3",
|
|
41
|
-
"@vitejs/plugin-react": "^5.1.
|
|
42
|
-
"eslint": "^9.39.
|
|
44
|
+
"@vitejs/plugin-react": "^5.1.2",
|
|
45
|
+
"eslint": "^9.39.2",
|
|
43
46
|
"eslint-plugin-react-hooks": "^7.0.1",
|
|
44
|
-
"eslint-plugin-react-refresh": "^0.4.
|
|
47
|
+
"eslint-plugin-react-refresh": "^0.4.26",
|
|
45
48
|
"globals": "^16.5.0",
|
|
46
49
|
"postcss": "^8.5.6",
|
|
47
50
|
"tailwindcss": "^4.1.18",
|
|
48
51
|
"tsup": "^8.5.1",
|
|
49
52
|
"typescript": "~5.9.3",
|
|
50
|
-
"typescript-eslint": "^8.
|
|
51
|
-
"vite": "^7.
|
|
53
|
+
"typescript-eslint": "^8.50.1",
|
|
54
|
+
"vite": "^7.3.0"
|
|
52
55
|
},
|
|
53
56
|
"scripts": {
|
|
54
57
|
"build": "tsup",
|