GUZBOMB's picture
are you able to make small edits - Initial Deployment
352594e verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Football Route Visualizer</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
.field {
background-color: #3a5f0b;
position: relative;
overflow: hidden;
}
.yard-line {
position: absolute;
width: 2px;
background-color: white;
height: 100%;
top: 0;
}
.yard-number {
position: absolute;
color: white;
font-weight: bold;
font-size: 12px;
transform: translateX(-50%);
}
.hash-mark {
position: absolute;
width: 10px;
height: 2px;
background-color: white;
}
.player {
transition: all 0.5s ease;
}
.route-path {
stroke-dasharray: 1000;
stroke-dashoffset: 1000;
animation: dash 2s linear forwards;
}
@keyframes dash {
to {
stroke-dashoffset: 0;
}
}
</style>
</head>
<body class="bg-gray-100">
<div class="container mx-auto px-4 py-8">
<header class="text-center mb-8">
<h1 class="text-4xl font-bold text-gray-800 mb-2">Football Route Visualizer</h1>
<p class="text-lg text-gray-600">Interactive tool to understand receiver route concepts</p>
</header>
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
<!-- Route Selection Panel -->
<div class="bg-white rounded-lg shadow-md p-6">
<h2 class="text-2xl font-semibold mb-4 text-gray-800">Route Concepts</h2>
<div class="space-y-4">
<div class="grid grid-cols-2 gap-3">
<button onclick="showRoute('go')" class="route-btn bg-blue-100 hover:bg-blue-200 text-blue-800 py-2 px-4 rounded-lg transition">
<i class="fas fa-arrow-up mr-2"></i> Go Route
</button>
<button onclick="showRoute('slant')" class="route-btn bg-green-100 hover:bg-green-200 text-green-800 py-2 px-4 rounded-lg transition">
<i class="fas fa-arrow-up-right mr-2"></i> Slant
</button>
<button onclick="showRoute('curl')" class="route-btn bg-purple-100 hover:bg-purple-200 text-purple-800 py-2 px-4 rounded-lg transition">
<i class="fas fa-undo mr-2"></i> Curl
</button>
<button onclick="showRoute('out')" class="route-btn bg-yellow-100 hover:bg-yellow-200 text-yellow-800 py-2 px-4 rounded-lg transition">
<i class="fas fa-arrow-right mr-2"></i> Out Route
</button>
<button onclick="showRoute('post')" class="route-btn bg-red-100 hover:bg-red-200 text-red-800 py-2 px-4 rounded-lg transition">
<i class="fas fa-long-arrow-alt-up mr-2"></i> Post
</button>
<button onclick="showRoute('corner')" class="route-btn bg-indigo-100 hover:bg-indigo-200 text-indigo-800 py-2 px-4 rounded-lg transition">
<i class="fas fa-arrow-up-right mr-2"></i> Corner
</button>
</div>
<div class="pt-4 border-t border-gray-200">
<h3 class="font-medium text-gray-700 mb-2">Route Combinations</h3>
<div class="grid grid-cols-1 gap-3">
<button onclick="showRoute('smash')" class="route-btn bg-gray-100 hover:bg-gray-200 text-gray-800 py-2 px-4 rounded-lg transition">
Smash Concept
</button>
<button onclick="showRoute('levels')" class="route-btn bg-gray-100 hover:bg-gray-200 text-gray-800 py-2 px-4 rounded-lg transition">
Levels Concept
</button>
<button onclick="showRoute('mesh')" class="route-btn bg-gray-100 hover:bg-gray-200 text-gray-800 py-2 px-4 rounded-lg transition">
Mesh Concept
</button>
</div>
</div>
</div>
</div>
<!-- Football Field Visualization -->
<div class="lg:col-span-2">
<div class="bg-white rounded-lg shadow-md p-4">
<div class="flex justify-between items-center mb-4">
<h2 class="text-2xl font-semibold text-gray-800">Route Visualization</h2>
<div class="flex space-x-2">
<button onclick="resetField()" class="bg-gray-200 hover:bg-gray-300 text-gray-800 py-1 px-3 rounded-lg text-sm transition">
<i class="fas fa-redo mr-1"></i> Reset
</button>
<button onclick="toggleAnimation()" class="bg-gray-200 hover:bg-gray-300 text-gray-800 py-1 px-3 rounded-lg text-sm transition">
<i class="fas fa-play mr-1"></i> Animate
</button>
</div>
</div>
<div class="field rounded-lg relative" style="height: 500px;">
<!-- Football field elements will be added here by JavaScript -->
<svg id="route-svg" width="100%" height="100%" style="position: absolute; top: 0; left: 0;"></svg>
<!-- Players -->
<div id="qb" class="player absolute w-8 h-8 bg-blue-500 rounded-full flex items-center justify-center text-white font-bold" style="bottom: 50px; left: 50%; transform: translateX(-50%);">QB</div>
<div id="wr1" class="player absolute w-8 h-8 bg-red-500 rounded-full flex items-center justify-center text-white font-bold" style="bottom: 150px; left: 20%;">WR1</div>
<div id="wr2" class="player absolute w-8 h-8 bg-red-500 rounded-full flex items-center justify-center text-white font-bold" style="bottom: 150px; left: 40%;">WR2</div>
<div id="wr3" class="player absolute w-8 h-8 bg-red-500 rounded-full flex items-center justify-center text-white font-bold" style="bottom: 150px; left: 60%;">WR3</div>
<div id="wr4" class="player absolute w-8 h-8 bg-red-500 rounded-full flex items-center justify-center text-white font-bold" style="bottom: 150px; left: 80%;">WR4</div>
<!-- Defense -->
<div id="cb1" class="player absolute w-8 h-8 bg-gray-700 rounded-full flex items-center justify-center text-white font-bold" style="bottom: 200px; left: 20%; opacity: 0.7;">CB</div>
<div id="cb2" class="player absolute w-8 h-8 bg-gray-700 rounded-full flex items-center justify-center text-white font-bold" style="bottom: 200px; left: 40%; opacity: 0.7;">CB</div>
<div id="cb3" class="player absolute w-8 h-8 bg-gray-700 rounded-full flex items-center justify-center text-white font-bold" style="bottom: 200px; left: 60%; opacity: 0.7;">CB</div>
<div id="cb4" class="player absolute w-8 h-8 bg-gray-700 rounded-full flex items-center justify-center text-white font-bold" style="bottom: 200px; left: 80%; opacity: 0.7;">CB</div>
</div>
<div id="route-description" class="mt-4 p-4 bg-gray-50 rounded-lg">
<h3 class="font-semibold text-lg text-gray-800 mb-2">Route Information</h3>
<p class="text-gray-600">Select a route from the panel to see visualization and details.</p>
</div>
</div>
</div>
</div>
</div>
<script>
// Initialize field markings
document.addEventListener('DOMContentLoaded', function() {
drawField();
});
function drawField() {
const field = document.querySelector('.field');
const width = field.offsetWidth;
const height = field.offsetHeight;
// Draw yard lines
for (let i = 0; i <= 100; i += 5) {
const yardLine = document.createElement('div');
yardLine.className = 'yard-line';
yardLine.style.left = `${(i / 100) * 100}%`;
// Add yard numbers every 10 yards
if (i % 10 === 0 && i > 0 && i < 100) {
const yardNumber = document.createElement('div');
yardNumber.className = 'yard-number';
yardNumber.style.left = `${(i / 100) * 100}%`;
yardNumber.style.top = '10px';
yardNumber.textContent = i;
field.appendChild(yardNumber);
const yardNumberBottom = document.createElement('div');
yardNumberBottom.className = 'yard-number';
yardNumberBottom.style.left = `${(i / 100) * 100}%`;
yardNumberBottom.style.bottom = '10px';
yardNumberBottom.textContent = i;
field.appendChild(yardNumberBottom);
}
field.appendChild(yardLine);
}
// Draw hash marks (simplified)
for (let i = 10; i < 100; i += 5) {
const hashTop = document.createElement('div');
hashTop.className = 'hash-mark';
hashTop.style.left = `${(i / 100) * 100}%`;
hashTop.style.top = '30%';
field.appendChild(hashTop);
const hashBottom = document.createElement('div');
hashBottom.className = 'hash-mark';
hashBottom.style.left = `${(i / 100) * 100}%`;
hashBottom.style.bottom = '30%';
field.appendChild(hashBottom);
}
}
// Route visualization functions
function showRoute(routeType) {
resetField();
const svg = document.getElementById('route-svg');
svg.innerHTML = '';
// Highlight selected route button
document.querySelectorAll('.route-btn').forEach(btn => {
btn.classList.remove('ring-2', 'ring-blue-500');
});
event.target.classList.add('ring-2', 'ring-blue-500');
// Route descriptions
const descriptions = {
'go': {
text: 'The Go Route (or Fly Route) is a straight sprint downfield. The receiver aims to get behind the defender for a deep pass. Key points: Explode off the line, maintain speed, track the ball over your shoulder.',
color: 'blue'
},
'slant': {
text: 'The Slant Route is a quick inside cut at about 5 yards. The receiver takes 3 hard steps forward then cuts at a 45-degree angle. Key points: Sharp cut, protect the ball in traffic, find the open window.',
color: 'green'
},
'curl': {
text: 'The Curl Route is a deep out-and-back move. The receiver runs 10-12 yards downfield then turns back toward the QB. Key points: Sell the go route first, plant hard on the back foot, create separation.',
color: 'purple'
},
'out': {
text: 'The Out Route is a 90-degree cut toward the sideline at 5-10 yards. The receiver runs vertically then makes a sharp outside cut. Key points: Depth depends on QB arm strength, keep feet in bounds, accelerate out of break.',
color: 'yellow'
},
'post': {
text: 'The Post Route is a deep diagonal cut toward the goalposts. The receiver runs 10-15 yards then cuts at a 45-degree angle toward the middle. Key points: Sell the go route first, maintain speed through cut, track the deep ball.',
color: 'red'
},
'corner': {
text: 'The Corner Route is a deep outside cut toward the corner of the end zone. The receiver runs 10-15 yards then cuts at a 45-degree angle toward the sideline. Key points: Sell the post route first, create separation with speed change.',
color: 'indigo'
},
'smash': {
text: 'The Smash Concept combines a short corner route (5-7 yards) with a deeper curl (12-15 yards). This creates a high-low read for the QB against zone coverage. The corner route occupies the flat defender while the curl works behind.',
color: 'gray'
},
'levels': {
text: 'The Levels Concept uses multiple receivers running crossing routes at different depths (typically 5 and 10 yards). This stretches zone coverage vertically and creates natural picks against man coverage.',
color: 'gray'
},
'mesh': {
text: 'The Mesh Concept has two receivers crossing close to the line of scrimmage (3-5 yards depth) while other receivers clear out. The crossing routes create natural picks and confusion in man coverage.',
color: 'gray'
}
};
// Update description
const descDiv = document.getElementById('route-description');
descDiv.innerHTML = `
<h3 class="font-semibold text-lg text-gray-800 mb-2">${routeType.charAt(0).toUpperCase() + routeType.slice(1)} Route</h3>
<p class="text-gray-600">${descriptions[routeType].text}</p>
`;
// Draw routes based on type
const routeColor = descriptions[routeType].color;
switch(routeType) {
case 'go':
drawPath(svg, 20, 150, 20, 50, routeColor);
animatePlayer('wr1', 20, 150, 20, 50);
break;
case 'slant':
drawPath(svg, 20, 150, 40, 100, routeColor);
animatePlayer('wr1', 20, 150, 40, 100);
break;
case 'curl':
drawPath(svg, 40, 150, 40, 100, routeColor);
drawPath(svg, 40, 100, 30, 100, routeColor);
animatePlayer('wr2', 40, 150, 40, 100, () => {
animatePlayer('wr2', 40, 100, 30, 100);
});
break;
case 'out':
drawPath(svg, 60, 150, 60, 100, routeColor);
drawPath(svg, 60, 100, 80, 100, routeColor);
animatePlayer('wr3', 60, 150, 60, 100, () => {
animatePlayer('wr3', 60, 100, 80, 100);
});
break;
case 'post':
drawPath(svg, 80, 150, 80, 80, routeColor);
drawPath(svg, 80, 80, 60, 50, routeColor);
animatePlayer('wr4', 80, 150, 80, 80, () => {
animatePlayer('wr4', 80, 80, 60, 50);
});
break;
case 'corner':
drawPath(svg, 20, 150, 20, 80, routeColor);
drawPath(svg, 20, 80, 40, 50, routeColor);
animatePlayer('wr1', 20, 150, 20, 80, () => {
animatePlayer('wr1', 20, 80, 40, 50);
});
break;
case 'smash':
// WR1 runs corner
drawPath(svg, 20, 150, 20, 120, routeColor);
drawPath(svg, 20, 120, 40, 100, routeColor);
// WR2 runs curl
drawPath(svg, 40, 150, 40, 100, routeColor);
drawPath(svg, 40, 100, 30, 100, routeColor);
animatePlayer('wr1', 20, 150, 20, 120, () => {
animatePlayer('wr1', 20, 120, 40, 100);
});
animatePlayer('wr2', 40, 150, 40, 100, () => {
animatePlayer('wr2', 40, 100, 30, 100);
});
break;
case 'levels':
// WR1 runs shallow cross
drawPath(svg, 20, 150, 80, 130, routeColor);
// WR2 runs medium cross
drawPath(svg, 40, 150, 60, 100, routeColor);
animatePlayer('wr1', 20, 150, 80, 130);
animatePlayer('wr2', 40, 150, 60, 100);
break;
case 'mesh':
// WR1 runs left to right
drawPath(svg, 20, 150, 80, 130, routeColor);
// WR2 runs right to left
drawPath(svg, 80, 150, 20, 130, routeColor);
animatePlayer('wr1', 20, 150, 80, 130);
animatePlayer('wr2', 80, 150, 20, 130);
break;
}
}
function drawPath(svg, x1, y1, x2, y2, color) {
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
path.setAttribute('d', `M ${x1}% ${y1} L ${x2}% ${y2}`);
path.setAttribute('stroke', color);
path.setAttribute('stroke-width', '3');
path.setAttribute('fill', 'none');
path.classList.add('route-path');
svg.appendChild(path);
}
function animatePlayer(playerId, startX, startY, endX, endY, callback) {
const player = document.getElementById(playerId);
player.style.left = `${startX}%`;
player.style.bottom = `${startY}px`;
setTimeout(() => {
player.style.left = `${endX}%`;
player.style.bottom = `${endY}px`;
if (callback) {
setTimeout(callback, 1000);
}
}, 100);
}
function resetField() {
const svg = document.getElementById('route-svg');
svg.innerHTML = '';
// Reset players to starting positions
document.getElementById('wr1').style.left = '20%';
document.getElementById('wr1').style.bottom = '150px';
document.getElementById('wr2').style.left = '40%';
document.getElementById('wr2').style.bottom = '150px';
document.getElementById('wr3').style.left = '60%';
document.getElementById('wr3').style.bottom = '150px';
document.getElementById('wr4').style.left = '80%';
document.getElementById('wr4').style.bottom = '150px';
// Reset description
document.getElementById('route-description').innerHTML = `
<h3 class="font-semibold text-lg text-gray-800 mb-2">Route Information</h3>
<p class="text-gray-600">Select a route from the panel to see visualization and details.</p>
`;
}
function toggleAnimation() {
const paths = document.querySelectorAll('.route-path');
paths.forEach(path => {
if (path.style.animationPlayState === 'paused') {
path.style.animationPlayState = 'running';
} else {
path.style.animationPlayState = 'paused';
}
});
}
</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=GUZBOMB/route-visual-v1-sample-fix" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>