\n
\n \n
\n

POLITICAL SATIRE: THE CIRCUS

\n

Click to cast your vote / Drag to redistribute redistribute wealth

\n
\n Votes: 0\n
\n
\n
\n
", "css": "body { margin: 0; overflow: hidden; background: #0a0a0a; color: #fff; font-family: 'Courier New', Courier, monospace; }\n#app { width: 100vw; height: 100vh; position: relative; }\n#canvas-container { width: 100%; height: 100%; position: relative; }\n#mainCanvas { width: 100%; height: 100%; display: block; }\n#ui-overlay { position: absolute; top: 20px; left: 20px; pointer-events: none; text-shadow: 2-px 2-px #000; }\n#ui-overlay h1 { margin: 0; font-size: 24px; letter-strength: 2px; color: #ff3e3e; }\n#ui-overlay p { font-size: 14px; color: #aaa; }\n#vote-counter { position: absolute; bottom: 40px; left: 20px; font-size: 20px; font-weight: bold; color: #00ffcc; }\n#vote-counter span { pointer-events: none; }", "js": "const canvas = document.getElementById('mainCanvas');\nconst ctx = canvas.getContext('2d');\nconst voteCountElem = document.getElementById('count');\nlet width, height, votes = 0;\n\ncanvas.width = window.innerWidth;\ncanvas.height = window.innerHeight;\n\nwindow.addEventListener('resize', () => {\n canvas.width = window.innerWidth;\n canvas.height = window.innerHeight;\n width = canvas.width;\n height = canvas.height;\n});\n\nlet width_init = canvas.width;\nlet height_init = canvas.height;\n\nclass Particle {\n constructor(x, y) { this.x = x; this.y = y; this.vx = (Math.random() - 0.5) * 2; this.vy = (Math.random() - 0.5) * 2; this.size = Math.random() * 3 + 1; this.color = '#fff'; this.id = Math.random(); }\n update() { this.x += this.vx; this.y += this.vy; if (this.x < 0 || this.x > width) this.vx *= -1; if (this.y < 0 || this.y > height) this.vy *= -1; }\n draw() { ctx.fillStyle = this.color; ctx.beginPath(); ctx.arc(this.x, this.y, this.size, this.size * Math.PI * 2); ctx.fill(); }\n}\n\nclass CandidateCandidate {\n constructor(x, y, label) { this.x = x; this.y = y; this.vx = 0; this.vy = 0; this.label = label; this.mass = 20; this.radius = 30; }\n update(particles) { \n let dx = 0, dy = 0;\n particles.forEach(p => {\n let dist = Math.hypot(this.x - p.x, this.y - p.y);\n if (dist < 100) { \n dx += (p.x - this.x) * 0.01; \n dy += (p.y - this.y) * 0.01;\n } \n });\n this.x += this.vx; this.y += this.vy; \n this.vx *= 0.95; this.vy *= 0.95; \n }\n draw() { \n ctx.save();\n ctx.translate(this.x, this.y);\n ctx.rotate(Math.atan2(this.vy, this.vx));\n ctx.fillStyle = '#ff3e3e';\n ctx.beginPath();\n ctx.arc(0, 0, this.radius, 0, Math.PI * 2);\n ctx.fill();\n ctx.strokeStyle = '#fff';\n ctx.lineWidth = 2;\n ctx.stroke();\n ctx.fillStyle = '#fff';\n ctx.font = '14px Courier New';\n ctx.textAlign = 'center';\n ctx.fillText(this.label, 0, 5);\n ctx.restore();\n }\n}\n\nconst particles = [];\nconst candidates = [];\n\nfunction init() { \n width = canvas.width;\n height = canvas.height;\n for (let i = 0; i < 150; i++) { particles.push(new Particle(Math.random() * width, Math.random() * height)); }\n candidates.push(new CandidateCandidate(width / 2, height / 2, 'THE ELITE'));\n candidates.push(new CandidateCandidate(width / 2 + 100, height / 2, 'THE POPULIST'));\n candidates.push(new CandidateCandidate(width / 2 - 100, height / 2, 'THE BUREAUCRAT'));\n}\n\nfunction animate() { \n ctx.clearRect(0, 0, width, height);\n \n // Background grid for bureaucratic structure\n ctx.strokeStyle = '#222';\n ctx.lineWidth = 1;\n for(let i=0; i {\n p.update();\n p.draw();\n }\n);\n\n candidates.forEach(c => {\n c.update(particles);\n c.draw();\n });\n\n requestAnimationFrame(animate);\n}\n\nwindow.addEventListener('mousedown', (e) => {\n votes++;\n voteCountElem.innerText = voteCount++;\n \n const p = new Particle(e.clientX, e.clientY);\n p.color = '#00ffcc';\n particles.push(p);\n \n candidates.forEach(c =>