diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 6fc8f29..8203b14 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -47,6 +47,25 @@ export default function RootLayout({ }>) { return ( + + + { + const canvasRef = useRef(null); + + useEffect(() => { + const canvas = canvasRef.current; + if (!canvas) return; + + const ctx = canvas.getContext('2d'); + if (!ctx) return; + + let animationFrameId: number; + let time = 0; + let logoDisplayed = false; + let logoImage: HTMLImageElement | null = null; + + const resizeCanvas = () => { + canvas.width = window.innerWidth; + canvas.height = window.innerHeight; + }; + + resizeCanvas(); + window.addEventListener('resize', resizeCanvas); + + // Preload logo + const preloadLogo = () => { + logoImage = new Image(); + logoImage.onload = () => { + logoDisplayed = true; + }; + logoImage.src = 'https://webuild-dev.s3.eu-north-1.amazonaws.com/users/user_3AT3OQAGjNifXrM4yFIwrMJit83/uploaded-1772602766355-l0j1upvq.jpg'; + }; + + preloadLogo(); + + // Bike parameters + interface Bike { + x: number; + y: number; + vx: number; + vy: number; + wheelY: number; + wheelRotation: number; + performanceType: 'burnout' | 'wheelie' | 'jump'; + performanceProgress: number; + performanceDuration: number; + wheelRotationSpeed: number; + } + + const bikes: Bike[] = [ + { + x: 100, + y: 300, + vx: 3, + vy: 0, + wheelY: 0, + wheelRotation: 0, + performanceType: 'burnout', + performanceProgress: 0, + performanceDuration: 100, + wheelRotationSpeed: 0.2, + }, + { + x: 400, + y: 250, + vx: 2.5, + vy: 0, + wheelY: 0, + wheelRotation: 0, + performanceType: 'wheelie', + performanceProgress: 0, + performanceDuration: 120, + wheelRotationSpeed: 0.15, + }, + { + x: 700, + y: 200, + vx: 3.5, + vy: 0, + wheelY: 0, + wheelRotation: 0, + performanceType: 'jump', + performanceProgress: 0, + performanceDuration: 80, + wheelRotationSpeed: 0.25, + }, + ]; + + const drawBike = (bike: Bike) => { + const { x, y, wheelRotation, performanceType, performanceProgress } = bike; + + // Apply performance effects + let bikeY = y; + let bikeRotation = 0; + let opacity = 1; + + if (performanceType === 'wheelie' && performanceProgress > 0) { + const progress = performanceProgress / bike.performanceDuration; + bikeRotation = Math.sin(progress * Math.PI) * 0.3; + } else if (performanceType === 'jump' && performanceProgress > 0) { + const progress = performanceProgress / bike.performanceDuration; + bikeY -= Math.sin(progress * Math.PI) * 80; + } else if (performanceType === 'burnout') { + opacity = 0.8 + Math.sin(time * 0.1) * 0.2; + } + + ctx!.save(); + ctx!.translate(x, bikeY); + ctx!.rotate(bikeRotation); + + // Main frame (simplified) + ctx!.strokeStyle = '#FF006E'; + ctx!.lineWidth = 3; + ctx!.beginPath(); + ctx!.moveTo(0, 0); + ctx!.lineTo(50, 10); + ctx!.stroke(); + + // Front wheel + ctx!.save(); + ctx!.translate(50, 10); + ctx!.rotate(wheelRotation); + ctx!.strokeStyle = '#00D9FF'; + ctx!.lineWidth = 2; + ctx!.beginPath(); + ctx!.arc(0, 0, 12, 0, Math.PI * 2); + ctx!.stroke(); + ctx!.strokeStyle = '#00D9FF'; + ctx!.lineWidth = 1; + for (let i = 0; i < 8; i++) { + const angle = (i / 8) * Math.PI * 2; + ctx!.beginPath(); + ctx!.moveTo(0, 0); + ctx!.lineTo(Math.cos(angle) * 12, Math.sin(angle) * 12); + ctx!.stroke(); + } + ctx!.restore(); + + // Rear wheel + ctx!.save(); + ctx!.translate(0, 0); + ctx!.rotate(wheelRotation * 1.1); + ctx!.strokeStyle = '#FFB81C'; + ctx!.lineWidth = 2; + ctx!.beginPath(); + ctx!.arc(0, 0, 14, 0, Math.PI * 2); + ctx!.stroke(); + ctx!.strokeStyle = '#FFB81C'; + ctx!.lineWidth = 1; + for (let i = 0; i < 8; i++) { + const angle = (i / 8) * Math.PI * 2; + ctx!.beginPath(); + ctx!.moveTo(0, 0); + ctx!.lineTo(Math.cos(angle) * 14, Math.sin(angle) * 14); + ctx!.stroke(); + } + ctx!.restore(); + + // Seat/rider (simplified) + ctx!.fillStyle = '#FF006E'; + ctx!.fillRect(15, -8, 20, 8); + + // Burnout smoke effect + if (performanceType === 'burnout' && performanceProgress > 0) { + ctx!.fillStyle = `rgba(255, 107, 107, ${0.5 * (1 - performanceProgress / bike.performanceDuration)})`; + ctx!.beginPath(); + ctx!.arc(-5, 2, 15 + Math.random() * 10, 0, Math.PI * 2); + ctx!.fill(); + } + + ctx!.restore(); + }; + + const drawGround = () => { + ctx!.strokeStyle = '#00D9FF'; + ctx!.lineWidth = 2; + ctx!.setLineDash([10, 10]); + ctx!.beginPath(); + ctx!.moveTo(0, canvas.height - 40); + ctx!.lineTo(canvas.width, canvas.height - 40); + ctx!.stroke(); + ctx!.setLineDash([]); + }; + + const drawObstacles = () => { + const obstacleX = ((time * 2) % canvas.width) - 50; + ctx!.fillStyle = '#FFB81C'; + ctx!.fillRect(obstacleX, canvas.height - 80, 40, 40); + ctx!.fillStyle = '#FF006E'; + ctx!.fillRect(obstacleX + 50, canvas.height - 60, 30, 30); + }; + + const drawLogo = () => { + if (logoDisplayed && logoImage) { + ctx!.save(); + ctx!.globalAlpha = 0.3 + Math.sin(time * 0.02) * 0.1; + ctx!.drawImage( + logoImage, + canvas.width / 2 - 60, + canvas.height / 2 - 60, + 120, + 120 + ); + ctx!.restore(); + } + }; + + const animate = () => { + // Clear canvas with semi-transparent background for trail effect + ctx!.fillStyle = 'rgba(10, 10, 10, 0.1)'; + ctx!.fillRect(0, 0, canvas.width, canvas.height); + + // Grid background + ctx!.strokeStyle = 'rgba(0, 217, 255, 0.1)'; + ctx!.lineWidth = 1; + const gridSize = 50; + for (let i = 0; i < canvas.width; i += gridSize) { + ctx!.beginPath(); + ctx!.moveTo(i, 0); + ctx!.lineTo(i, canvas.height); + ctx!.stroke(); + } + for (let i = 0; i < canvas.height; i += gridSize) { + ctx!.beginPath(); + ctx!.moveTo(0, i); + ctx!.lineTo(canvas.width, i); + ctx!.stroke(); + } + + drawGround(); + drawObstacles(); + + // Update and draw bikes + bikes.forEach((bike) => { + bike.x += bike.vx; + bike.wheelRotation += bike.wheelRotationSpeed; + + // Reset position when off screen + if (bike.x > canvas.width) { + bike.x = -50; + bike.performanceProgress = 0; + } + + // Update performance progress + bike.performanceProgress++; + if (bike.performanceProgress > bike.performanceDuration) { + bike.performanceProgress = 0; + } + + drawBike(bike); + }); + + drawLogo(); + + time++; + animationFrameId = requestAnimationFrame(animate); + }; + + animate(); + + return () => { + cancelAnimationFrame(animationFrameId); + window.removeEventListener('resize', resizeCanvas); + }; + }, []); + + return ( + + ); +}; + export default function LandingPage() { return ( - +
+ -
- -
+ -
- -
+
+ +
-
- -
+
+ +
-
- -
+
+ +
-
- -
+
+ +
-
- -
+
+ +
-
- -
+
+ +
- );