This contains everything you need to run your app locally.
View your app in AI Studio: https://ai.studio/apps/drive/1AkF4GjqUWrvAgtbMmWqwtGsOy0fW0g0b
Prerequisites: Node.js
- Install dependencies:
npm install - Set the
GEMINI_API_KEYin .env.local to your Gemini API key - Run the app:
npm run dev
- Immersive Cyberpunk UI: A rich, neon-drenched aesthetic with custom fonts (Orbitron, Fira Code), glow effects, scanlines, and glitch text animations to simulate a futuristic terminal.
- State-Driven App Flow: A multi-stage user experience (Intro, Gate, Main, Hacking, Role Reveal) managed cleanly using React state and enums.
- Fluid Animations: Built with Framer Motion to provide smooth, cinematic transitions and interactive effects between all application states.
- Interactive "Neon Runner" Game: A fast-paced, 3-lane runner game built with HTML5 Canvas. Players must dodge obstacles and collect data tags to earn a score.
- Dynamic Role Assignment: At the end of the game, users are assigned one of five unique cyberpunk roles based on their final score and survival time.
- WebGL Backgrounds: Utilizes custom Three.js shaders for dynamic, generative backgrounds, including a
CyberneticGridShaderand aNeonCrystalCityenvironment. - 3D-Perspective Card Reveal: The final role is revealed on a 3D-tilting card that reacts to mouse movement, built using Framer Motion's
useTransformanduseMotionValuehooks.
This project is built with a modern, fast, and type-safe web stack:
- Vite: Next-generation frontend tooling for blazing fast development and optimized builds.
- React: The core library for building the component-based user interface.
- TypeScript: For static typing, leading to more robust and maintainable code.
- Framer Motion: A powerful motion library for React to create fluid animations.
- Three.js: Used for the WebGL-based shader backgrounds.
- Tailwind CSS: A utility-first CSS framework used for styling (loaded via CDN).
Prerequisites: Node.js
-
Install dependencies:
npm install
-
Set the
GEMINI_API_KEYin.env.localto your Gemini API key. (Note: This key is defined in the Vite config but not actively used in the current game logic). -
Run the app:
npm run dev
This will start the Vite development server, typically on http://localhost:3000.
The user's journey is managed by a central state machine in App.tsx. The flow proceeds through five distinct stages:
AppState.Intro: The application starts with theIntroSequencecomponent. This plays a series of timed animations, including a "retinal scanner" and a typing text effect, to set the mood. On completion, it transitions to theGatestate.AppState.Gate: TheGateScreenis displayed. This screen presents the project title and a "SECURE GATE" with a "BREACH" button. Clicking this button triggers thehandleBreachcallback and moves to theMainstate.AppState.Main: The user sees theMainInterface. This component displays the "GHOSTWAVE MANIFESTO" (lore text fromconstants.ts) and a "JACK IN" button. Clicking this button transitions to theHackingstate.AppState.Hacking: TheGameScreencomponent is rendered. This screen first shows an intro with the game's title, "NEON RUNNER," and an "INITIATE RUN" button. Once clicked, theNeonRunnerGameitself is mounted and the mini-game begins.AppState.RoleReveal: When the player fails in the game,NeonRunnerGamecalls itsonCompleteprop with the final score and time.GameScreenthen calculates the role and stats and calls its ownonCompleteprop. This triggersApp.tsxto move to theRoleRevealstate, displaying theRoleRevealcomponent with the assigned role and performance metrics.
The core of this project is the NeonRunnerGame, a mini-game built using the HTML5 Canvas API. The App.tsx loads GameScreen, which in turn loads NeonRunnerGame.
(Note: The repository also contains a HackingTerminal.tsx file, a typing-based game. This component is not used in the current application flow.)
The game is an infinite runner viewed from a 2D top-down perspective, set against the NeonCrystalCity shader background.
- The Player: Represented by a cyan triangle.
- Collectibles: Yellow circles ("tags"). Collecting one adds +10 to the score.
- Obstacles: Red rectangles ("blocks"). Colliding with one ends the game.
The game world is divided into three vertical lanes (0, 1, and 2). The player can move between these lanes by clicking or tapping on the corresponding third of the screen. A pointerdown event listener calculates which lane was clicked and updates the player's lane state.
The game's difficulty increases progressively over time:
- Speed: Obstacles and tags move down the screen at an increasing speed. The speed starts at 300px/sec and increases based on the time elapsed since the game started (
speedRef.current = 300 + (now - startTime.current) / 150). - Spawning: The time interval between new obstacle spawns decreases as the game progresses (
spawnInterval = Math.max(200, 600 - (now - startTime.current) / 200)).
When the game ends, the NeonRunnerGame component passes the final score and timeSurvived (in seconds) to the GameScreen component.
GameScreen then uses the getRoleForScore function from constants.ts to determine your role.
Here is the exact assignment logic:
-
Tech Runner: Assigned if
score >= 150.- Description: "You're a blur of chrome and code... For you, speed is everything."
-
Data Ghost: Assigned if
score >= 80ANDtime > 20.- Description: "Precision is your art form... You leave no trace..."
-
Infiltrator: Assigned if
score >= 40.- Description: "A balanced phantom of the new age. You possess a versatile skill set..."
-
Shadow Courier: Assigned if
score > 0.- Description: "You're messy, chaotic, but undeniably effective."
-
Cyber Bruiser: This is the default role, assigned if
scoreis 0.- Description: "You prefer a direct approach... You overwhelm systems with raw, unfiltered input..."
These stats (score, time, and tags collected) are then passed to the RoleReveal component to be displayed to the user.
