Spaces:
Running
Running
Create a mini-game inside GTA5 inspired by the classic Snake game, where players control a glowing digital "snake" using arrow keys. The twist: instead of collecting food, the snake navigates through an abstract virtual space shaped like a randomized keyboard key (e.g., "W", "E", "Shift", etc.), with the layout changing every time the game starts. Each round generates a unique glowing outline of a keyboard key using 3D shapes or Tron-style light paths. The snake must trace around the shape without colliding into itself or the boundaries. As the player progresses, the snake grows and the control sensitivity slightly increases, raising difficulty. The game is presented as a digital hacking side quest or arcade terminal in GTA5, possibly within a cybercafé or hidden hacker hideout. Visuals are neon-lit, synthwave-themed, with minimal UI and an immersive data-grid backdrop. Time challenges, score multipliers, and leaderboard integration keep replayability high. Optional integration allows players to earn small in-game cash or RP rewards based on performance. Ideal for both quick play and deeper mastery, it blends nostalgia with dynamic design in a modern GTA5 sandbox. - Initial Deployment
26c1610
verified
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>GTA5 HACKER SNAKE</title> | |
<script src="https://cdn.tailwindcss.com"></script> | |
<style> | |
@import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700&display=swap'); | |
body { | |
font-family: 'Orbitron', sans-serif; | |
background-color: #0a0a1a; | |
overflow: hidden; | |
user-select: none; | |
} | |
#gameCanvas { | |
border: 2px solid rgba(0, 255, 255, 0.3); | |
box-shadow: 0 0 20px rgba(0, 255, 255, 0.5); | |
} | |
.grid-bg { | |
position: absolute; | |
width: 100%; | |
height: 100%; | |
background: | |
linear-gradient(rgba(0, 255, 255, 0.1) 1px, transparent 1px), | |
linear-gradient(90deg, rgba(0, 255, 255, 0.1) 1px, transparent 1px); | |
background-size: 30px 30px; | |
z-index: -1; | |
} | |
.glow-text { | |
text-shadow: 0 0 10px cyan, 0 0 20px cyan; | |
} | |
.glow-box { | |
box-shadow: 0 0 15px cyan, inset 0 0 10px cyan; | |
} | |
.pulse { | |
animation: pulse 2s infinite; | |
} | |
@keyframes pulse { | |
0% { opacity: 0.7; } | |
50% { opacity: 1; } | |
100% { opacity: 0.7; } | |
} | |
#keyOutline { | |
stroke-dasharray: 1000; | |
stroke-dashoffset: 1000; | |
animation: dash 5s linear forwards; | |
} | |
@keyframes dash { | |
to { | |
stroke-dashoffset: 0; | |
} | |
} | |
</style> | |
</head> | |
<body class="text-cyan-400 h-screen flex flex-col items-center justify-center relative"> | |
<div class="grid-bg"></div> | |
<div class="absolute top-4 left-4 flex items-center gap-2"> | |
<div class="w-3 h-3 rounded-full bg-red-500 animate-pulse"></div> | |
<span class="text-xs">LIVE FEED</span> | |
</div> | |
<div class="absolute top-4 right-4 text-xs"> | |
<div class="flex gap-4"> | |
<span>CONNECTION: <span class="text-green-500">SECURE</span></span> | |
<span>USER: <span class="text-cyan-300">PLAYER_1</span></span> | |
</div> | |
</div> | |
<h1 class="text-4xl font-bold mb-2 glow-text">// HACKER_SNAKE.EXE</h1> | |
<p class="text-xs mb-6 pulse">TRACE THE KEY PATTERN WITHOUT COLLISION</p> | |
<div class="relative"> | |
<canvas id="gameCanvas" width="500" height="500" class="bg-black"></canvas> | |
<div id="startScreen" class="absolute inset-0 flex flex-col items-center justify-center bg-black bg-opacity-80"> | |
<h2 class="text-2xl mb-4 glow-text">GTA5 HACKING TERMINAL</h2> | |
<p class="text-sm mb-6 text-center px-8">Navigate the digital snake around the key outline<br>using arrow keys to complete the hack</p> | |
<button id="startBtn" class="px-6 py-2 bg-cyan-900 hover:bg-cyan-700 glow-box rounded-md font-bold transition-all"> | |
INITIATE HACK | |
</button> | |
<div class="mt-6 text-xs"> | |
<p>HIGH SCORE: <span id="highScoreDisplay">0</span></p> | |
<p>LAST SCORE: <span id="lastScoreDisplay">0</span></p> | |
</div> | |
</div> | |
<div id="gameOverScreen" class="absolute inset-0 hidden flex-col items-center justify-center bg-black bg-opacity-80"> | |
<h2 class="text-2xl mb-2 glow-text">HACK TERMINATED</h2> | |
<p class="text-xl mb-2" id="finalScore">SCORE: 0</p> | |
<p class="text-sm mb-6" id="completionText">PARTIAL HACK COMPLETE</p> | |
<div class="flex gap-4"> | |
<button id="restartBtn" class="px-4 py-2 bg-cyan-900 hover:bg-cyan-700 glow-box rounded-md font-bold transition-all"> | |
RETRY | |
</button> | |
<button id="quitBtn" class="px-4 py-2 bg-purple-900 hover:bg-purple-700 glow-box rounded-md font-bold transition-all"> | |
EXIT | |
</button> | |
</div> | |
</div> | |
</div> | |
<div class="mt-4 flex gap-8 text-sm"> | |
<div> | |
<p>SCORE: <span id="scoreDisplay">0</span></p> | |
<p>TIME: <span id="timeDisplay">00:00</span></p> | |
</div> | |
<div> | |
<p>LEVEL: <span id="levelDisplay">1</span></p> | |
<p>MULTIPLIER: <span id="multiplierDisplay">1x</span></p> | |
</div> | |
</div> | |
<div class="absolute bottom-4 left-4 text-xs opacity-70"> | |
<p>// GTA5 HACKING MINIGAME v1.0</p> | |
<p>// USE ARROW KEYS TO CONTROL</p> | |
</div> | |
<script> | |
// Game variables | |
const canvas = document.getElementById('gameCanvas'); | |
const ctx = canvas.getContext('2d'); | |
const startScreen = document.getElementById('startScreen'); | |
const gameOverScreen = document.getElementById('gameOverScreen'); | |
const startBtn = document.getElementById('startBtn'); | |
const restartBtn = document.getElementById('restartBtn'); | |
const quitBtn = document.getElementById('quitBtn'); | |
const scoreDisplay = document.getElementById('scoreDisplay'); | |
const timeDisplay = document.getElementById('timeDisplay'); | |
const levelDisplay = document.getElementById('levelDisplay'); | |
const multiplierDisplay = document.getElementById('multiplierDisplay'); | |
const finalScore = document.getElementById('finalScore'); | |
const completionText = document.getElementById('completionText'); | |
const highScoreDisplay = document.getElementById('highScoreDisplay'); | |
const lastScoreDisplay = document.getElementById('lastScoreDisplay'); | |
// Game state | |
let snake = []; | |
let food = []; | |
let direction = 'right'; | |
let nextDirection = 'right'; | |
let gameSpeed = 150; | |
let gameLoop; | |
let score = 0; | |
let level = 1; | |
let multiplier = 1; | |
let startTime; | |
let elapsedTime = 0; | |
let timerInterval; | |
let highScore = localStorage.getItem('snakeHighScore') || 0; | |
let lastScore = localStorage.getItem('snakeLastScore') || 0; | |
let keyOutline = []; | |
let outlineCompleted = false; | |
let outlineProgress = 0; | |
// Possible key shapes (W, A, S, D, Shift, Ctrl, Space, etc.) | |
const keyShapes = [ | |
// W key (simple version) | |
[ | |
{x: 100, y: 100}, {x: 150, y: 50}, {x: 200, y: 100}, | |
{x: 175, y: 100}, {x: 175, y: 200}, {x: 200, y: 200}, | |
{x: 150, y: 250}, {x: 100, y: 200}, {x: 125, y: 200}, | |
{x: 125, y: 100}, {x: 100, y: 100} | |
], | |
// A key | |
[ | |
{x: 100, y: 200}, {x: 150, y: 50}, {x: 200, y: 200}, | |
{x: 175, y: 150}, {x: 125, y: 150}, {x: 100, y: 200} | |
], | |
// S key | |
[ | |
{x: 200, y: 50}, {x: 100, y: 50}, {x: 100, y: 125}, | |
{x: 200, y: 125}, {x: 200, y: 200}, {x: 100, y: 200} | |
], | |
// D key | |
[ | |
{x: 100, y: 50}, {x: 150, y: 50}, {x: 175, y: 75}, | |
{x: 175, y: 175}, {x: 150, y: 200}, {x: 100, y: 200}, | |
{x: 100, y: 50} | |
], | |
// Shift key (simple rectangle) | |
[ | |
{x: 50, y: 225}, {x: 250, y: 225}, | |
{x: 250, y: 275}, {x: 50, y: 275}, | |
{x: 50, y: 225} | |
], | |
// Space bar | |
[ | |
{x: 50, y: 250}, {x: 250, y: 250}, | |
{x: 250, y: 275}, {x: 50, y: 275}, | |
{x: 50, y: 250} | |
] | |
]; | |
// Initialize displays | |
highScoreDisplay.textContent = highScore; | |
lastScoreDisplay.textContent = lastScore; | |
// Start game | |
startBtn.addEventListener('click', startGame); | |
restartBtn.addEventListener('click', startGame); | |
quitBtn.addEventListener('click', () => { | |
gameOverScreen.classList.add('hidden'); | |
startScreen.classList.remove('hidden'); | |
}); | |
function startGame() { | |
// Reset game state | |
snake = [ | |
{x: 50, y: 250}, | |
{x: 40, y: 250}, | |
{x: 30, y: 250} | |
]; | |
direction = 'right'; | |
nextDirection = 'right'; | |
score = 0; | |
level = 1; | |
multiplier = 1; | |
elapsedTime = 0; | |
outlineCompleted = false; | |
outlineProgress = 0; | |
// Generate a random key outline | |
const randomShapeIndex = Math.floor(Math.random() * keyShapes.length); | |
keyOutline = keyShapes[randomShapeIndex]; | |
// Adjust outline coordinates to fit better on canvas | |
keyOutline = keyOutline.map(point => ({ | |
x: point.x + 100, | |
y: point.y + 100 | |
})); | |
// Hide screens | |
startScreen.classList.add('hidden'); | |
gameOverScreen.classList.add('hidden'); | |
// Update displays | |
scoreDisplay.textContent = score; | |
levelDisplay.textContent = level; | |
multiplierDisplay.textContent = multiplier + 'x'; | |
// Start timer | |
startTime = Date.now(); | |
if (timerInterval) clearInterval(timerInterval); | |
timerInterval = setInterval(updateTimer, 1000); | |
// Start game loop | |
if (gameLoop) clearInterval(gameLoop); | |
gameLoop = setInterval(gameStep, gameSpeed); | |
// Draw initial state | |
draw(); | |
} | |
function updateTimer() { | |
elapsedTime = Math.floor((Date.now() - startTime) / 1000); | |
const minutes = Math.floor(elapsedTime / 60).toString().padStart(2, '0'); | |
const seconds = (elapsedTime % 60).toString().padStart(2, '0'); | |
timeDisplay.textContent = `${minutes}:${seconds}`; | |
} | |
function gameStep() { | |
// Update direction | |
direction = nextDirection; | |
// Move snake | |
const head = {...snake[0]}; | |
switch(direction) { | |
case 'up': | |
head.y -= 10; | |
break; | |
case 'down': | |
head.y += 10; | |
break; | |
case 'left': | |
head.x -= 10; | |
break; | |
case 'right': | |
head.x += 10; | |
break; | |
} | |
// Check for collisions with walls | |
if (head.x < 0 || head.x >= canvas.width || head.y < 0 || head.y >= canvas.height) { | |
gameOver(); | |
return; | |
} | |
// Check for collisions with self | |
for (let i = 0; i < snake.length; i++) { | |
if (head.x === snake[i].x && head.y === snake[i].y) { | |
gameOver(); | |
return; | |
} | |
} | |
// Add new head | |
snake.unshift(head); | |
// Check for outline tracing | |
checkOutlineTracing(head); | |
// Check if snake should grow (based on outline progress) | |
if (outlineProgress % 5 === 0 && outlineProgress > 0 && !outlineCompleted) { | |
// Don't remove tail (snake grows) | |
multiplier = Math.floor(outlineProgress / 5) + 1; | |
multiplierDisplay.textContent = multiplier + 'x'; | |
} else { | |
// Remove tail (snake doesn't grow) | |
snake.pop(); | |
} | |
// Check if outline is completed | |
if (outlineProgress >= keyOutline.length - 1 && !outlineCompleted) { | |
outlineCompleted = true; | |
score += 100 * multiplier * level; | |
level++; | |
levelDisplay.textContent = level; | |
// Increase speed every 2 levels | |
if (level % 2 === 0) { | |
gameSpeed = Math.max(50, gameSpeed - 10); | |
clearInterval(gameLoop); | |
gameLoop = setInterval(gameStep, gameSpeed); | |
} | |
// Generate new outline | |
const randomShapeIndex = Math.floor(Math.random() * keyShapes.length); | |
keyOutline = keyShapes[randomShapeIndex]; | |
// Adjust outline coordinates to fit better on canvas | |
keyOutline = keyOutline.map(point => ({ | |
x: point.x + 100, | |
y: point.y + 100 | |
})); | |
outlineProgress = 0; | |
outlineCompleted = false; | |
} | |
// Update score | |
scoreDisplay.textContent = score; | |
// Redraw | |
draw(); | |
} | |
function checkOutlineTracing(head) { | |
if (outlineCompleted) return; | |
// Check if head is close to the next point in outline | |
const nextPoint = keyOutline[outlineProgress + 1]; | |
const distance = Math.sqrt( | |
Math.pow(head.x - nextPoint.x, 2) + | |
Math.pow(head.y - nextPoint.y, 2) | |
); | |
if (distance < 15) { | |
outlineProgress++; | |
score += 5 * multiplier; | |
// Bonus for completing segments | |
if (outlineProgress % 5 === 0) { | |
score += 20 * multiplier; | |
} | |
} | |
} | |
function draw() { | |
// Clear canvas | |
ctx.fillStyle = 'rgba(0, 10, 20, 0.7)'; | |
ctx.fillRect(0, 0, canvas.width, canvas.height); | |
// Draw grid | |
drawGrid(); | |
// Draw key outline | |
drawKeyOutline(); | |
// Draw snake | |
drawSnake(); | |
// Draw progress indicator | |
drawProgress(); | |
} | |
function drawGrid() { | |
ctx.strokeStyle = 'rgba(0, 255, 255, 0.1)'; | |
ctx.lineWidth = 1; | |
// Vertical lines | |
for (let x = 0; x < canvas.width; x += 30) { | |
ctx.beginPath(); | |
ctx.moveTo(x, 0); | |
ctx.lineTo(x, canvas.height); | |
ctx.stroke(); | |
} | |
// Horizontal lines | |
for (let y = 0; y < canvas.height; y += 30) { | |
ctx.beginPath(); | |
ctx.moveTo(0, y); | |
ctx.lineTo(canvas.width, y); | |
ctx.stroke(); | |
} | |
} | |
function drawKeyOutline() { | |
if (keyOutline.length < 2) return; | |
ctx.strokeStyle = 'rgba(255, 0, 255, 0.7)'; | |
ctx.lineWidth = 3; | |
ctx.beginPath(); | |
ctx.moveTo(keyOutline[0].x, keyOutline[0].y); | |
for (let i = 1; i <= outlineProgress; i++) { | |
ctx.lineTo(keyOutline[i].x, keyOutline[i].y); | |
} | |
ctx.stroke(); | |
// Draw remaining outline in dimmer color | |
if (outlineProgress < keyOutline.length - 1) { | |
ctx.strokeStyle = 'rgba(255, 0, 255, 0.2)'; | |
ctx.beginPath(); | |
ctx.moveTo(keyOutline[outlineProgress].x, keyOutline[outlineProgress].y); | |
for (let i = outlineProgress + 1; i < keyOutline.length; i++) { | |
ctx.lineTo(keyOutline[i].x, keyOutline[i].y); | |
} | |
ctx.stroke(); | |
} | |
// Draw points | |
ctx.fillStyle = 'magenta'; | |
for (let i = 0; i < keyOutline.length; i++) { | |
ctx.beginPath(); | |
ctx.arc(keyOutline[i].x, keyOutline[i].y, 3, 0, Math.PI * 2); | |
ctx.fill(); | |
} | |
} | |
function drawSnake() { | |
// Draw head | |
const head = snake[0]; | |
ctx.fillStyle = 'cyan'; | |
ctx.beginPath(); | |
ctx.arc(head.x, head.y, 6, 0, Math.PI * 2); | |
ctx.fill(); | |
// Add glow effect | |
ctx.shadowColor = 'cyan'; | |
ctx.shadowBlur = 10; | |
// Draw body | |
ctx.fillStyle = 'rgba(0, 255, 255, 0.8)'; | |
for (let i = 1; i < snake.length; i++) { | |
ctx.beginPath(); | |
ctx.arc(snake[i].x, snake[i].y, 4, 0, Math.PI * 2); | |
ctx.fill(); | |
} | |
// Remove glow | |
ctx.shadowColor = 'transparent'; | |
} | |
function drawProgress() { | |
const progressPercent = (outlineProgress / (keyOutline.length - 1)) * 100; | |
ctx.fillStyle = 'rgba(0, 255, 255, 0.2)'; | |
ctx.fillRect(20, 20, 200, 10); | |
ctx.fillStyle = 'cyan'; | |
ctx.fillRect(20, 20, 200 * (progressPercent / 100), 10); | |
ctx.strokeStyle = 'cyan'; | |
ctx.strokeRect(20, 20, 200, 10); | |
ctx.fillStyle = 'white'; | |
ctx.font = '10px Orbitron'; | |
ctx.fillText(`TRACE PROGRESS: ${Math.round(progressPercent)}%`, 20, 35); | |
} | |
function gameOver() { | |
clearInterval(gameLoop); | |
clearInterval(timerInterval); | |
// Update scores | |
lastScore = score; | |
if (score > highScore) { | |
highScore = score; | |
localStorage.setItem('snakeHighScore', highScore); | |
} | |
localStorage.setItem('snakeLastScore', lastScore); | |
// Update game over screen | |
finalScore.textContent = `SCORE: ${score}`; | |
const completionPercent = outlineProgress / (keyOutline.length - 1) * 100; | |
if (completionPercent < 30) { | |
completionText.textContent = "HACK FAILED - TRACE INCOMPLETE"; | |
} else if (completionPercent < 70) { | |
completionText.textContent = "PARTIAL HACK COMPLETE"; | |
} else { | |
completionText.textContent = "NEARLY COMPLETE - TRY AGAIN"; | |
} | |
gameOverScreen.classList.remove('hidden'); | |
} | |
// Handle keyboard input | |
document.addEventListener('keydown', (e) => { | |
switch(e.key) { | |
case 'ArrowUp': | |
if (direction !== 'down') nextDirection = 'up'; | |
break; | |
case 'ArrowDown': | |
if (direction !== 'up') nextDirection = 'down'; | |
break; | |
case 'ArrowLeft': | |
if (direction !== 'right') nextDirection = 'left'; | |
break; | |
case 'ArrowRight': | |
if (direction !== 'left') nextDirection = 'right'; | |
break; | |
} | |
}); | |
// Initial draw | |
draw(); | |
</script> | |
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=Mankeysocks/snker" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
</html> |