source-code/
snakey
Public
codeCodeinfoIssues 0call_splitPull Requestsplay_circleActions
snakey/src/App.tsx
typescript101 lines3.4 KB
import { useState, useCallback } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import Game from './Game';
import Header from './components/Header';
import Footer from './components/Footer';

function App() {
  const [isPlaying, setIsPlaying] = useState(false);
  const [isExpanded, setIsExpanded] = useState(false);
  const [score, setScore] = useState(0);

  const handlePlay = () => {
    setScore(0);
    setIsPlaying(true);
  };

  const handleClose = () => {
    setIsPlaying(false);
    setIsExpanded(false);
  };

  return (
    <div className="w-screen min-h-screen flex flex-col items-center justify-center bg-gray-50 text-gray-900 overflow-x-hidden relative font-sans p-6 py-12">
      
      <Header />

      <AnimatePresence>
        {isPlaying && (
          <motion.div
            initial={{ opacity: 0, y: 10 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, y: -10 }}
            id="score-display"
            className="mb-4 z-20 flex items-center gap-3 bg-white px-6 py-2 rounded-full shadow-md border border-gray-100 shrink-0"
          >
            <div className="w-4 h-4 rounded-full bg-red-500 shadow-[0_0_8px_rgba(239,68,68,0.6)]"></div>
            <span className="text-2xl font-bold text-slate-800 tracking-tight">{score}</span>
          </motion.div>
        )}
      </AnimatePresence>

      <motion.div
        layout
        id="game-container-shell"
        data-playing={isPlaying}
        className="z-20 relative flex items-center justify-center overflow-hidden shrink-0 bg-white shadow-xl data-[playing=false]:rounded-full data-[playing=true]:rounded-2xl border border-gray-200 pointer-events-auto"
        initial={{ borderRadius: "9999px" }}
        animate={{
          width: isPlaying ? 800 : 220,
          height: isPlaying ? 600 : 64,
          borderRadius: isPlaying ? "16px" : "9999px",
        }}
        transition={{ type: "spring", stiffness: 200, damping: 25, mass: 1 }}
        onAnimationComplete={() => {
          if (isPlaying) {
            setIsExpanded(true);
          }
        }}
      >
        <AnimatePresence mode="wait">
          {!isPlaying ? (
            <motion.button
              key="button"
              initial={{ opacity: 0 }}
              animate={{ opacity: 1 }}
              exit={{ opacity: 0, scale: 0.8 }}
              transition={{ duration: 0.15 }}
              onClick={handlePlay}
              className="w-full h-full flex items-center justify-center text-lg font-bold tracking-wide text-blue-600 hover:bg-blue-50 transition-colors cursor-pointer outline-none"
            >
              Play Game
            </motion.button>
          ) : (
            isExpanded && (
              <motion.div
                key="game"
                initial={{ opacity: 0 }}
                animate={{ opacity: 1 }}
                transition={{ duration: 0.3 }}
                className="w-full h-full relative"
              >
                <button 
                  onClick={handleClose}
                  className="absolute top-4 right-4 z-50 text-gray-400 hover:text-gray-900 transition-colors bg-gray-100 hover:bg-gray-200 rounded-full w-8 h-8 flex items-center justify-center pointer-events-auto"
                >
                  ✕
                </button>
                <Game onScoreUpdate={setScore} />
              </motion.div>
            )
          )}
        </AnimatePresence>
      </motion.div>

      <Footer />
    </div>
  );
}

export default App;

About

Snakey Web Game is the official hub and sandbox playground for the Snakey project. Built with React 19, Phaser 3, and Tailwind CSS, it offers a central playable zone alongside a Sandbox Playground that lets visitors test eating custom HTML elements. It also hosts and serves self-compiled browser extension packages (ZIP) for Chrome and Firefox, as well as a dynamically-generated bookmarklet installer that enables users to drag-and-drop a shortcut to run the game on any external website.

Web GamePhaserReactTypeScriptTailwind CSSViteBookmarklet

Contributors

1