export class RickGamePanel { private canvas!: HTMLCanvasElement private ctx!: CanvasRenderingContext2D private player = { x: 20, y: 180, vy: 0, width: 10, height: 10, onGround: false } private gravity = 0.7 private jumpPower = -12 private isGameOver = false private enemies: { x: number, y: number, width: number, height: number, speed: number }[] = [] private spawnTimer = 0 constructor(private container: HTMLElement) { this.createUI() this.ctx = this.canvas.getContext('2d')! this.attachListeners() this.frame() } private createUI() { const panel = document.createElement('div') panel.style.cssText = ` background: #1a1a1a; color: #eee; font-family: monospace; padding: 16px; border-radius: 12px; width: fit-content; box-shadow: 0 0 20px rgba(255,255,255,0.1); ` const title = document.createElement('div') title.innerHTML = `🌀 Rickjump 2: Invasion` title.style.marginBottom = '10px' panel.appendChild(title) this.canvas = document.createElement('canvas') this.canvas.width = 300 this.canvas.height = 200 this.canvas.style.cssText = ` border: 2px solid #444; background: #000; image-rendering: pixelated; ` panel.appendChild(this.canvas) const footer = document.createElement('div') footer.textContent = '↳ try not to get rick’d' footer.style.cssText = ` margin-top: 10px; font-size: 0.7em; color: #aaa; ` panel.appendChild(footer) this.container.appendChild(panel) } private attachListeners() { this.canvas.addEventListener('click', () => { if (this.player.onGround) { this.player.vy = this.jumpPower this.player.onGround = false } }) } private frame = () => { if (this.isGameOver) return // physics this.player.vy += this.gravity this.player.y += this.player.vy if (this.player.y >= 180) { this.player.y = 180 this.player.vy = 0 this.player.onGround = true } // enemies for (const enemy of this.enemies) { enemy.x -= enemy.speed } // cleanup this.enemies = this.enemies.filter(e => e.x + e.width > 0) // collisions for (const enemy of this.enemies) { const p = this.player const collide = p.x < enemy.x + enemy.width && p.x + p.width > enemy.x && p.y < enemy.y + enemy.height && p.y + p.height > enemy.y if (collide) { this.isGameOver = true setTimeout(() => { window.open('https://www.youtube.com/watch?v=dQw4w9WgXcQ', '_blank') }, 200) return } } // spawn enemy this.spawnTimer-- if (this.spawnTimer <= 0) { this.spawnEnemy() this.spawnTimer = 30 + Math.floor(Math.random() * 60) } this.draw() requestAnimationFrame(this.frame) } private spawnEnemy() { const h = 10 + Math.floor(Math.random() * 20) const y = 190 - h const speed = 1.5 + Math.random() * 1.5 this.enemies.push({ x: 300, y, width: 10, height: h, speed }) } private draw() { const ctx = this.ctx ctx.clearRect(0, 0, 300, 200) // background ctx.fillStyle = '#111' ctx.fillRect(0, 0, 300, 200) // ground ctx.fillStyle = '#444' ctx.fillRect(0, 190, 300, 10) // enemies for (const e of this.enemies) { ctx.fillStyle = '#f00' ctx.fillRect(e.x, e.y, e.width, e.height) } // player ctx.fillStyle = '#0af' ctx.fillRect(this.player.x, this.player.y, this.player.width, this.player.height) } } export function insertRickPanel(target: HTMLElement | string = document.body): void { const container = typeof target === 'string' ? document.querySelector(target) : target if (container instanceof HTMLElement) { new RickGamePanel(container) } }