{"id":97,"date":"2026-07-02T16:48:49","date_gmt":"2026-07-02T16:48:49","guid":{"rendered":"https:\/\/qvg.ai\/?page_id=97"},"modified":"2026-07-02T16:49:16","modified_gmt":"2026-07-02T16:49:16","slug":"97-2","status":"publish","type":"page","link":"https:\/\/qvg.ai\/?page_id=97","title":{"rendered":"Crazy Beans"},"content":{"rendered":"<p><!DOCTYPE html><br \/>\n<html lang=\"de\"><br \/>\n<head><br \/>\n<meta charset=\"UTF-8\" \/><br \/>\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\" \/><br \/>\n<title>Crazy Bean \u2013 Skate Arena Playable 2.1<\/title><\/p>\n<style>\n  * { box-sizing: border-box; }\n  body {\n    margin: 0;\n    min-height: 100vh;\n    overflow: hidden;\n    touch-action: none;\n    font-family: Arial, Helvetica, sans-serif;\n    color: #f7fbff;\n    background:\n      radial-gradient(circle at 48% 28%, rgba(70,120,160,.25), transparent 28%),\n      radial-gradient(circle at 80% 75%, rgba(80,190,120,.12), transparent 26%),\n      linear-gradient(135deg, #06111d 0%, #071622 45%, #02070d 100%);\n  }\n  .gameShell {\n    width: min(100vw, 1240px);\n    height: min(100vh, 850px);\n    margin: 0 auto;\n    display: grid;\n    grid-template-columns: 230px 1fr 230px;\n    grid-template-rows: auto 1fr auto;\n    gap: 14px;\n    padding: 16px;\n  }\n  .logo {\n    grid-column: 1 \/ 2;\n    grid-row: 1 \/ 2;\n    line-height: .86;\n    font-weight: 1000;\n    font-size: 42px;\n    color: #2bb7ff;\n    text-shadow: 2px 2px 0 #fff, 4px 4px 0 #e73838, 7px 7px 0 rgba(0,0,0,.45);\n    transform: rotate(-2deg);\n  }\n  .logo span { color: #ff3838; display: block; }\n  .arenaName {\n    color: #58c7ff;\n    font-size: 17px;\n    letter-spacing: 4px;\n    margin-top: 8px;\n    text-shadow: none;\n  }\n  .topHud {\n    grid-column: 2 \/ 3;\n    grid-row: 1 \/ 2;\n    display: flex;\n    justify-content: center;\n    gap: 12px;\n    align-items: center;\n  }\n  .hudBox, .panel {\n    background: rgba(8,15,23,.76);\n    border: 2px solid rgba(255,255,255,.13);\n    border-radius: 16px;\n    box-shadow: 0 12px 28px rgba(0,0,0,.35), inset 0 1px 0 rgba(255,255,255,.08);\n    backdrop-filter: blur(4px);\n  }\n  .hudBox {\n    min-width: 140px;\n    padding: 11px 16px;\n    text-align: center;\n    font-size: 13px;\n    color: #c8d5df;\n  }\n  .hudBox strong { display: block; color: #ffe24c; font-size: 25px; margin-top: 2px; }\n  .left { grid-column: 1 \/ 2; grid-row: 2 \/ 3; display: flex; flex-direction: column; gap: 14px; }\n  .right { grid-column: 3 \/ 4; grid-row: 1 \/ 3; display: flex; flex-direction: column; gap: 14px; padding-top: 72px; }\n  .panel { padding: 14px; }\n  .panel h3 { margin: 0 0 12px; color: #ffe24c; font-size: 18px; letter-spacing: .5px; }\n  .beanItem {\n    display: grid;\n    grid-template-columns: 54px 1fr;\n    gap: 10px;\n    align-items: center;\n    padding: 9px 6px;\n    border-radius: 12px;\n    cursor: pointer;\n  }\n  .beanItem.active { background: rgba(255,226,76,.13); outline: 2px solid rgba(255,226,76,.4); }\n  .beanIcon {\n    width: 42px;\n    height: 56px;\n    border-radius: 24px;\n    background: linear-gradient(#fff2bd 0 45%, var(--beanColor) 48% 100%);\n    box-shadow: inset 0 -8px 12px rgba(0,0,0,.18), 0 5px 8px rgba(0,0,0,.28);\n    position: relative;\n  }\n  .beanIcon:before, .beanIcon:after {\n    content: \"\";\n    position: absolute;\n    top: 22px;\n    width: 8px;\n    height: 8px;\n    border-radius: 50%;\n    background: #fff;\n    border: 2px solid #1b1b1b;\n  }\n  .beanIcon:before { left: 10px; }\n  .beanIcon:after { right: 10px; }\n  .beanName { font-weight: 900; color: var(--beanColor); }\n  .beanDesc { font-size: 12px; color: #d8e1e8; margin-top: 2px; line-height: 1.2; }\n  .arenaArea {\n    grid-column: 2 \/ 3;\n    grid-row: 2 \/ 3;\n    position: relative;\n    min-height: 0;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n  }\n  canvas {\n    width: min(64vw, 680px);\n    height: min(64vw, 680px);\n    max-width: 680px;\n    max-height: 680px;\n    border-radius: 30px;\n    display: block;\n    cursor: crosshair;\n  }\n  .partnerInside {\n    position: absolute;\n    right: 26px;\n    top: 50%;\n    transform: translateY(-50%);\n    width: 155px;\n    min-height: 118px;\n    border: 2px dashed rgba(186,205,215,.55);\n    border-radius: 18px;\n    background: rgba(9,16,24,.72);\n    box-shadow: 0 10px 24px rgba(0,0,0,.30);\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    pointer-events: none;\n    color: #cdd7dd;\n  }\n  .partnerInside .headline { color:#8be45e; font-weight: 900; margin-bottom: 5px; }\n  .partnerInside .q { font-size: 52px; font-weight: 900; color: #9aa5ac; line-height: 1; }\n  .partnerInside .small { font-size: 11px; font-weight: 800; }\n  .how li, .features li {\n    list-style: none;\n    margin: 10px 0;\n    font-size: 14px;\n    color: #e7edf2;\n  }\n  .how li:before, .features li:before { content: \"\u25cf\"; color: #ffe24c; margin-right: 8px; }\n  .sounds { text-align: center; }\n  .speech {\n    display: inline-block;\n    background: #fff;\n    color: #e83939;\n    border-radius: 50%;\n    padding: 9px 12px;\n    margin: 6px;\n    font-weight: 900;\n    transform: rotate(-8deg);\n  }\n  .speech.blue { color: #2275e8; transform: rotate(8deg); }\n  .speech.active {\n    animation: pop .45s ease-out;\n    box-shadow: 0 0 0 4px rgba(255,226,76,.35);\n  }\n  @keyframes pop {\n    0% { transform: scale(.8) rotate(-8deg); }\n    50% { transform: scale(1.25) rotate(5deg); }\n    100% { transform: scale(1) rotate(-8deg); }\n  }\n  .bottom {\n    grid-column: 1 \/ 4;\n    grid-row: 3 \/ 4;\n    display: grid;\n    grid-template-columns: 1fr auto 1fr;\n    gap: 14px;\n    align-items: center;\n  }\n  .arenaSelect { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; }\n  .arenaChip {\n    width: 76px;\n    height: 76px;\n    border-radius: 16px;\n    border: 2px solid rgba(255,255,255,.18);\n    background: linear-gradient(135deg, #8b8f92, #333);\n    display:flex;\n    align-items:end;\n    justify-content:center;\n    padding-bottom:7px;\n    font-size: 11px;\n    font-weight: 900;\n    box-shadow: inset 0 0 20px rgba(0,0,0,.3);\n    cursor: pointer;\n    user-select: none;\n  }\n  .arenaChip.active { outline: 4px solid #ffe24c; }\n  .buttons { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; }\n  button {\n    border: none;\n    border-radius: 16px;\n    padding: 14px 22px;\n    font-weight: 1000;\n    cursor: pointer;\n    background: linear-gradient(#a8ee42, #4a9b1e);\n    color: #fff;\n    text-shadow: 1px 1px 0 rgba(0,0,0,.35);\n    box-shadow: 0 6px 0 #2b6112, 0 10px 24px rgba(0,0,0,.28);\n  }\n  button.secondary { background: linear-gradient(#43a7ff, #1d5dac); box-shadow: 0 6px 0 #143f75, 0 10px 24px rgba(0,0,0,.28); }\n  button.soundOff { background: linear-gradient(#a3a9b0, #555e67); box-shadow: 0 6px 0 #30363c, 0 10px 24px rgba(0,0,0,.28); }\n  .status { font-size: 14px; color: #c8d5df; text-align: center; padding: 0 12px; }\n  .win { color: #ffe24c; font-weight: 900; }\n  @media(max-width: 950px) {\n    body { overflow: auto; }\n    .gameShell { height: auto; grid-template-columns: 1fr; grid-template-rows: auto auto auto auto auto; }\n    .logo, .topHud, .left, .arenaArea, .right, .bottom { grid-column: 1 \/ 2; grid-row: auto; }\n    .right { padding-top: 0; }\n    canvas { width: min(94vw, 680px); height: min(94vw, 680px); }\n    .partnerInside { width: 120px; right: 12px; }\n    .bottom { grid-template-columns: 1fr; }\n  }\n<\/style>\n<p><\/head><br \/>\n<body><\/p>\n<div class=\"gameShell\">\n<div class=\"logo\">CRAZY<span>BEAN<\/span><\/p>\n<div class=\"arenaName\" id=\"arenaTitle\">SKATE ARENA<\/div>\n<\/div>\n<div class=\"topHud\">\n<div class=\"hudBox\">&#x23f1; TIME<strong id=\"time\">0.00<\/strong><\/div>\n<div class=\"hudBox\">&#x1f3c6; BEST<strong id=\"best\">\u2014<\/strong><\/div>\n<div class=\"hudBox\">&#x1fad8; BEAN<strong id=\"beanType\">Hyper<\/strong><\/div>\n<\/p><\/div>\n<div class=\"left\">\n<div class=\"panel\">\n<h3>BEAN CHARACTERS<\/h3>\n<div id=\"beanList\"><\/div>\n<\/p><\/div>\n<\/p><\/div>\n<div class=\"arenaArea\">\n    <canvas id=\"game\" width=\"760\" height=\"760\"><\/canvas><\/p>\n<div class=\"partnerInside\">\n<div class=\"headline\">PARTNER SPACE<\/div>\n<div class=\"q\">?<\/div>\n<div class=\"small\">YOUR LOGO HERE<\/div>\n<\/p><\/div>\n<\/p><\/div>\n<div class=\"right\">\n<div class=\"panel how\">\n<h3>HOW TO PLAY<\/h3>\n<li>Tilt to roll<\/li>\n<li>Avoid the hole<\/li>\n<li>Beat your time<\/li>\n<li>Climb leaderboards<\/li><\/div>\n<div class=\"panel sounds\">\n<h3>SOUNDS &#038; REACTIONS<\/h3>\n<p>      <span id=\"sOops\" class=\"speech\">OOPS!<\/span><span id=\"sWow\" class=\"speech blue\">WOW!<\/span><br \/>\n      <span id=\"sOhNo\" class=\"speech\">OH NO!<\/span><span id=\"sYes\" class=\"speech blue\">YEEES!<\/span>\n    <\/div>\n<div class=\"panel features\">\n<h3>FEATURES<\/h3>\n<li>Real physics<\/li>\n<li>Simple to understand<\/li>\n<li>Hard to master<\/li>\n<li>Collectible beans<\/li><\/div>\n<\/p><\/div>\n<div class=\"bottom\">\n<div class=\"arenaSelect\" id=\"arenaList\"><\/div>\n<div class=\"buttons\">\n      <button onclick=\"startGame()\">START \/ RESET<\/button><br \/>\n      <button class=\"secondary\" onclick=\"changeBean()\">CHANGE BEAN<\/button><br \/>\n      <button class=\"secondary\" onclick=\"changeArena()\">CHANGE ARENA<\/button><br \/>\n      <button id=\"soundBtn\" class=\"soundOff\" onclick=\"toggleSound()\">SOUND OFF<\/button>\n    <\/div>\n<div id=\"status\" class=\"status\">Sound is OFF by default. Click SOUND ON if you want reactions.<\/div>\n<\/p><\/div>\n<\/div>\n<p><script>\nconst canvas = document.getElementById(\"game\");\nconst ctx = canvas.getContext(\"2d\");\nconst W = canvas.width, H = canvas.height, cx = W\/2, cy = H\/2 + 8;\nconst outerR = 340, bowlR = 298, holeR = 48;<\/p>\n<p>const timeEl = document.getElementById(\"time\");\nconst bestEl = document.getElementById(\"best\");\nconst statusEl = document.getElementById(\"status\");\nconst beanTypeEl = document.getElementById(\"beanType\");\nconst beanListEl = document.getElementById(\"beanList\");\nconst arenaListEl = document.getElementById(\"arenaList\");\nconst arenaTitleEl = document.getElementById(\"arenaTitle\");\nconst soundBtn = document.getElementById(\"soundBtn\");<\/p>\n<p>const speechMap = { \"Oops!\":\"sOops\", \"Wow!\":\"sWow\", \"Oh no!\":\"sOhNo\", \"YEEES!\":\"sYes\", \"Bonk!\":\"sOops\", \"GO!\":\"sWow\", \"Again!\":\"sOhNo\", \"No!\":\"sOhNo\" };<\/p>\n<p>const arenas = [\n  { name:\"Roman\", title:\"ROMAN SKATE ARENA\", chip:\"linear-gradient(135deg,#c7b091,#334150)\", rim1:\"#546879\", rim2:\"#d9c08d\", floor:[\"#ead1aa\",\"#b3916e\",\"#75675d\",\"#30383d\"], bg:[\"#263b4e\",\"#081522\",\"#03080f\"], graffiti:true },\n  { name:\"Wood\", title:\"WOOD ARENA\", chip:\"linear-gradient(135deg,#d6a96d,#5a351e)\", rim1:\"#7b4d28\", rim2:\"#f6c477\", floor:[\"#ffd089\",\"#c98b43\",\"#925a27\",\"#503018\"], bg:[\"#24411e\",\"#0d1c12\",\"#050908\"], graffiti:false },\n  { name:\"Ice\", title:\"ICE ARENA\", chip:\"linear-gradient(135deg,#d7fbff,#4caed2)\", rim1:\"#7ee8ff\", rim2:\"#ffffff\", floor:[\"#efffff\",\"#b6eafd\",\"#62b8da\",\"#17577a\"], bg:[\"#d6fbff\",\"#2e6d8b\",\"#071b2a\"], graffiti:false },\n  { name:\"Volcano\", title:\"VOLCANO ARENA\", chip:\"linear-gradient(135deg,#ff5b25,#2a0b08)\", rim1:\"#ff5a28\", rim2:\"#ffd447\", floor:[\"#ffb05c\",\"#c84822\",\"#5a1510\",\"#1b0705\"], bg:[\"#5a140d\",\"#1b0806\",\"#030000\"], graffiti:false },\n  { name:\"Galaxy\", title:\"GALAXY ARENA\", chip:\"linear-gradient(135deg,#8f48ff,#050014)\", rim1:\"#9b5cff\", rim2:\"#35d5ff\", floor:[\"#ddc6ff\",\"#7c4ae8\",\"#28105d\",\"#070011\"], bg:[\"#29155a\",\"#09071e\",\"#010005\"], graffiti:true }\n];<\/p>\n<p>const beans = [\n  { name: \"Hyper\", desc: \"Fast & Energetic\", magnet: 0.95, chaos: 0.95, friction: 0.985, body: \"#f04a32\", cap: \"#fff1bd\", mood: \"angry\" },\n  { name: \"Chaos\", desc: \"Wild & Unpredictable\", magnet: 1.30, chaos: 1.45, friction: 0.981, body: \"#ff7a20\", cap: \"#ffdf7a\", mood: \"wild\" },\n  { name: \"Crazy\", desc: \"Funny & Surprising\", magnet: 0.90, chaos: 1.15, friction: 0.984, body: \"#f7c441\", cap: \"#fff4c8\", mood: \"happy\" },\n  { name: \"Cool\", desc: \"Calm & Steady\", magnet: 0.65, chaos: 0.55, friction: 0.991, body: \"#2a9bf0\", cap: \"#eaf8ff\", mood: \"cool\" }\n];<\/p>\n<p>let beanIndex = 0, arenaIndex = 0;\nlet bean = { x: cx + 145, y: cy - 145, vx: 0, vy: 0, r: 25, angle: 0 };\nlet tilt = { x: 0, y: 0 };\nlet startTime = 0, elapsed = 0, running = false, won = false, last = performance.now();\nlet bubble = null, bubbleUntil = 0;\nlet audioCtx = null;\nlet soundOn = false;\nlet lastBonk = 0;\nlet lastRandomSound = 0;<\/p>\n<p>const best = localStorage.getItem(\"crazybean_skate_best\");\nif (best) bestEl.textContent = Number(best).toFixed(2) + \"s\";<\/p>\n<p>function initAudio(){\n  if (!audioCtx) audioCtx = new (window.AudioContext || window.webkitAudioContext)();\n}<\/p>\n<p>function toggleSound(){\n  soundOn = !soundOn;\n  if(soundOn){\n    initAudio();\n    soundBtn.textContent = \"SOUND ON\";\n    soundBtn.classList.remove(\"soundOff\");\n    statusEl.innerHTML = \"Sound ON. Reactions play only on hits, near misses and success.\";\n    beep(\"wow\");\n  } else {\n    soundBtn.textContent = \"SOUND OFF\";\n    soundBtn.classList.add(\"soundOff\");\n    statusEl.innerHTML = \"Sound OFF. Visual reactions stay active.\";\n  }\n}<\/p>\n<p>function beep(type=\"blip\"){\n  if (!soundOn || !audioCtx) return;\n  const o = audioCtx.createOscillator();\n  const g = audioCtx.createGain();\n  o.connect(g); g.connect(audioCtx.destination);\n  const now = audioCtx.currentTime;\n  let freq = 420, end = now + .10;\n  if(type===\"bonk\"){ freq=110; end=now+.07; }\n  if(type===\"wow\"){ freq=660; end=now+.10; }\n  if(type===\"yes\"){ freq=880; end=now+.17; }\n  if(type===\"oops\"){ freq=240; end=now+.09; }\n  o.frequency.setValueAtTime(freq, now);\n  if(type===\"yes\") o.frequency.exponentialRampToValueAtTime(1320, end);\n  if(type===\"oops\") o.frequency.exponentialRampToValueAtTime(150, end);\n  o.type = type===\"bonk\" ? \"square\" : \"sine\";\n  g.gain.setValueAtTime(.0001, now);\n  g.gain.exponentialRampToValueAtTime(.045, now+.012);\n  g.gain.exponentialRampToValueAtTime(.0001, end);\n  o.start(now); o.stop(end+.02);\n}<\/p>\n<p>function activateSpeech(text){\n  const id = speechMap[text];\n  if(!id) return;\n  const el = document.getElementById(id);\n  el.classList.remove(\"active\");\n  void el.offsetWidth;\n  el.classList.add(\"active\");\n}<\/p>\n<p>function buildBeanList(){\n  beanListEl.innerHTML = \"\";\n  beans.forEach((b, i)=>{\n    const div = document.createElement(\"div\");\n    div.className = \"beanItem\" + (i===beanIndex ? \" active\" : \"\");\n    div.style.setProperty(\"--beanColor\", b.body);\n    div.onclick = () => { initAudio(); beanIndex = i; beanTypeEl.textContent = b.name; buildBeanList(); startGame(); };\n    div.innerHTML = `<\/p>\n<div class=\"beanIcon\"><\/div>\n<div>\n<div class=\"beanName\">${b.name.toUpperCase()}<\/div>\n<div class=\"beanDesc\">${b.desc}<\/div>\n<\/div>\n<p>`;\n    beanListEl.appendChild(div);\n  });\n}<\/p>\n<p>function buildArenaList(){\n  arenaListEl.innerHTML = \"\";\n  arenas.forEach((a, i)=>{\n    const div = document.createElement(\"div\");\n    div.className = \"arenaChip\" + (i===arenaIndex ? \" active\" : \"\");\n    div.style.background = a.chip;\n    div.textContent = a.name.toUpperCase();\n    div.onclick = () => { initAudio(); arenaIndex = i; buildArenaList(); updateArenaTitle(); say(\"Wow!\"); beep(\"wow\"); };\n    arenaListEl.appendChild(div);\n  });\n}<\/p>\n<p>function updateArenaTitle(){\n  arenaTitleEl.textContent = arenas[arenaIndex].title;\n}<\/p>\n<p>buildBeanList();\nbuildArenaList();\nupdateArenaTitle();<\/p>\n<p>function resetBean() {\n  const a = -Math.PI \/ 2 + (Math.random() - .5) * 1.1;\n  const r = 210 + Math.random() * 45;\n  bean.x = cx + Math.cos(a) * r;\n  bean.y = cy + Math.sin(a) * r;\n  bean.vx = bean.vy = 0;\n  bean.angle = Math.random() * Math.PI * 2;\n}<\/p>\n<p>function say(text) {\n  bubble = text;\n  bubbleUntil = performance.now() + 780;\n  activateSpeech(text);\n}<\/p>\n<p>function startGame() {\n  initAudio();\n  resetBean();\n  startTime = performance.now();\n  elapsed = 0;\n  running = true;\n  won = false;\n  say(\"GO!\");\n  beep(\"wow\");\n  statusEl.innerHTML = soundOn ? \"Guide the bean into the center hole. The magnet fights back!\" : \"Guide the bean into the center hole. Sound is OFF.\";\n}<\/p>\n<p>function changeBean() {\n  initAudio();\n  beanIndex = (beanIndex + 1) % beans.length;\n  beanTypeEl.textContent = beans[beanIndex].name;\n  buildBeanList();\n  startGame();\n}<\/p>\n<p>function changeArena() {\n  initAudio();\n  arenaIndex = (arenaIndex + 1) % arenas.length;\n  buildArenaList();\n  updateArenaTitle();\n  say(\"Wow!\");\n  beep(\"wow\");\n}<\/p>\n<p>function pointerToTilt(clientX, clientY) {\n  const rect = canvas.getBoundingClientRect();\n  const x = ((clientX - rect.left) \/ rect.width) * W;\n  const y = ((clientY - rect.top) \/ rect.height) * H;\n  tilt.x = Math.max(-1, Math.min(1, (x - cx) \/ bowlR));\n  tilt.y = Math.max(-1, Math.min(1, (y - cy) \/ bowlR));\n}\ncanvas.addEventListener(\"mousemove\", e => pointerToTilt(e.clientX, e.clientY));\ncanvas.addEventListener(\"mousedown\", () => initAudio());\ncanvas.addEventListener(\"touchstart\", () => initAudio(), { passive: true });\ncanvas.addEventListener(\"touchmove\", e => {\n  e.preventDefault();\n  const t = e.touches[0];\n  pointerToTilt(t.clientX, t.clientY);\n}, { passive: false });<\/p>\n<p>function physics(dt) {\n  if (!running || won) return;\n  const cfg = beans[beanIndex];<\/p>\n<p>  elapsed = (performance.now() - startTime) \/ 1000;\n  timeEl.textContent = elapsed.toFixed(2);<\/p>\n<p>  bean.vx += tilt.x * 545 * dt;\n  bean.vy += tilt.y * 545 * dt;<\/p>\n<p>  const dx = bean.x - cx, dy = bean.y - cy;\n  const dist = Math.sqrt(dx*dx + dy*dy) || 1;<\/p>\n<p>  const magneticRange = 172;\n  if (dist < magneticRange) {\n    const force = (1 - dist \/ magneticRange) * cfg.magnet * 960;\n    bean.vx += (dx \/ dist) * force * dt;\n    bean.vy += (dy \/ dist) * force * dt;\n    if (performance.now() - lastRandomSound > 1900 && Math.random() < 0.006) {\n      const msg = [\"Oops!\", \"No!\", \"Wow!\", \"Again!\"][Math.floor(Math.random()*4)];\n      say(msg);\n      beep(msg === \"Wow!\" ? \"wow\" : \"oops\");\n      lastRandomSound = performance.now();\n    }\n  }\n\n  const t = performance.now() \/ 1000;\n  const chaos = cfg.chaos * 145;\n  bean.vx += Math.sin(t * 5.3 + bean.y * 0.010) * chaos * dt;\n  bean.vy += Math.cos(t * 4.9 + bean.x * 0.012) * chaos * dt;\n\n  const radial = Math.sqrt((bean.x-cx)**2 + (bean.y-cy)**2);\n  const slope = Math.max(0, radial \/ bowlR);\n  bean.vx += -(bean.x - cx) \/ (radial || 1) * slope * 18 * dt;\n  bean.vy += -(bean.y - cy) \/ (radial || 1) * slope * 18 * dt;\n\n  bean.vx *= Math.pow(cfg.friction, dt * 60);\n  bean.vy *= Math.pow(cfg.friction, dt * 60);\n\n  const speed = Math.sqrt(bean.vx*bean.vx + bean.vy*bean.vy);\n  const maxSpeed = 700;\n  if (speed > maxSpeed) {\n    bean.vx = bean.vx \/ speed * maxSpeed;\n    bean.vy = bean.vy \/ speed * maxSpeed;\n  }<\/p>\n<p>  bean.x += bean.vx * dt;\n  bean.y += bean.vy * dt;\n  bean.angle += (bean.vx * 0.012 + bean.vy * 0.008) * dt * 8;<\/p>\n<p>  const bdX = bean.x - cx, bdY = bean.y - cy;\n  const bd = Math.sqrt(bdX*bdX + bdY*bdY);\n  if (bd > bowlR - bean.r) {\n    const nx = bdX \/ bd, ny = bdY \/ bd;\n    bean.x = cx + nx * (bowlR - bean.r);\n    bean.y = cy + ny * (bowlR - bean.r);\n    const dot = bean.vx * nx + bean.vy * ny;\n    bean.vx -= 1.72 * dot * nx;\n    bean.vy -= 1.72 * dot * ny;\n    bean.vx *= 0.76;\n    bean.vy *= 0.76;\n    if (performance.now() - lastBonk > 260) {\n      say(\"Bonk!\");\n      beep(\"bonk\");\n      lastBonk = performance.now();\n    }\n  }<\/p>\n<p>  const holeDist = Math.sqrt((bean.x-cx)**2 + (bean.y-cy)**2);\n  const finalSpeed = Math.sqrt(bean.vx*bean.vx + bean.vy*bean.vy);\n  if (holeDist < holeR - 9 &#038;&#038; finalSpeed < 165 &#038;&#038; elapsed > 0.5) {\n    won = true; running = false;\n    say(\"YEEES!\");\n    beep(\"yes\");\n    statusEl.innerHTML = `<span class=\"win\">Bean captured!<\/span> Time: ${elapsed.toFixed(2)}s`;\n    const oldBest = Number(localStorage.getItem(\"crazybean_skate_best\") || Infinity);\n    if (elapsed < oldBest) {\n      localStorage.setItem(\"crazybean_skate_best\", elapsed.toFixed(2));\n      bestEl.textContent = elapsed.toFixed(2) + \"s\";\n      statusEl.innerHTML += \" \u2014 New best!\";\n    }\n  }\n}\n\nfunction oval(x,y,r,scaleY,fill,stroke,lw=1) {\n  ctx.save(); ctx.translate(x,y); ctx.scale(1,scaleY); ctx.beginPath(); ctx.arc(0,0,r,0,Math.PI*2);\n  ctx.fillStyle = fill; ctx.fill();\n  if(stroke){ctx.lineWidth=lw; ctx.strokeStyle=stroke; ctx.stroke();}\n  ctx.restore();\n}\n\nfunction roundRect(x,y,w,h,r,fill,stroke,fillStyle){\n  ctx.beginPath();\n  ctx.moveTo(x+r,y); ctx.lineTo(x+w-r,y); ctx.quadraticCurveTo(x+w,y,x+w,y+r);\n  ctx.lineTo(x+w,y+h-r); ctx.quadraticCurveTo(x+w,y+h,x+w-r,y+h);\n  ctx.lineTo(x+r,y+h); ctx.quadraticCurveTo(x,y+h,x,y+h-r);\n  ctx.lineTo(x,y+r); ctx.quadraticCurveTo(x,y,x+r,y);\n  if(fill){ if(fillStyle) ctx.fillStyle = fillStyle; ctx.fill(); }\n  if(stroke) ctx.stroke();\n}\n\nfunction drawArena() {\n  const a = arenas[arenaIndex];\n  ctx.clearRect(0,0,W,H);\n\n  const bg = ctx.createRadialGradient(cx,cy,80,cx,cy,480);\n  bg.addColorStop(0,a.bg[0]); bg.addColorStop(.75,a.bg[1]); bg.addColorStop(1,a.bg[2]);\n  ctx.fillStyle=bg; ctx.fillRect(0,0,W,H);\n\n  \/\/ star\/leaf\/scratch particles per arena\n  for(let i=0;i<34;i++){\n    const px=(i*83)%W, py=(i*47)%H;\n    ctx.beginPath();\n    if(a.name===\"Galaxy\"){\n      ctx.arc(px,py,1.2+(i%3),0,Math.PI*2); ctx.fillStyle=\"rgba(255,255,255,.45)\";\n    } else if(a.name===\"Volcano\"){\n      ctx.arc(px,py,1.5+(i%3),0,Math.PI*2); ctx.fillStyle=\"rgba(255,90,30,.23)\";\n    } else if(a.name===\"Ice\"){\n      ctx.rect(px,py,3,3); ctx.fillStyle=\"rgba(255,255,255,.28)\";\n    } else {\n      ctx.ellipse(px,py,6,2,(i*.7),0,Math.PI*2); ctx.fillStyle=\"rgba(255,255,255,.10)\";\n    }\n    ctx.fill();\n  }\n\n  oval(cx, cy+40, outerR+16, .74, \"rgba(0,0,0,.58)\");\n\n  \/\/ Rising outer walls: clearer Roman \/ coliseum-style arena\n  for(let k=0;k<5;k++){\n    const rr = outerR - k*22;\n    const sy = .75 + k*.015;\n    const yOff = -k*6;\n    const shade = k===0 ? \"#2c3f4d\" : k===1 ? \"#425463\" : k===2 ? \"#65717a\" : k===3 ? \"#8a8580\" : \"#a49280\";\n    oval(cx, cy + yOff, rr, sy, shade, k===0 ? a.rim1 : \"rgba(255,255,255,.12)\", k===0 ? 10 : 3);\n  }\n\n  \/\/ Segmented rim like an arena wall\n  ctx.save(); ctx.translate(cx,cy-10); ctx.scale(1,.79);\n  ctx.lineWidth=8;\n  for(let i=0;i<56;i++){\n    ctx.beginPath();\n    ctx.arc(0,0,outerR-18, i*Math.PI*2\/56, (i+.56)*Math.PI*2\/56);\n    ctx.strokeStyle = i%2 ? a.rim2 : a.rim1;\n    ctx.stroke();\n  }\n  ctx.restore();\n\n  const bowl = ctx.createRadialGradient(cx-90,cy-145,35,cx,cy,bowlR);\n  bowl.addColorStop(0,a.floor[0]); bowl.addColorStop(.42,a.floor[1]); bowl.addColorStop(.82,a.floor[2]); bowl.addColorStop(1,a.floor[3]);\n  oval(cx, cy, bowlR, .77, bowl, \"rgba(255,255,255,.20)\", 4);\n\n  ctx.save(); ctx.translate(cx,cy); ctx.scale(1,.77);\n  \/\/ vertical wall\/seat segments around the bowl\n  for(let i=0;i<32;i++){\n    const ang=i*Math.PI*2\/32;\n    ctx.beginPath();\n    ctx.moveTo(Math.cos(ang)*bowlR*.82,Math.sin(ang)*bowlR*.82);\n    ctx.lineTo(Math.cos(ang)*bowlR,Math.sin(ang)*bowlR);\n    ctx.strokeStyle=\"rgba(255,255,255,.18)\";\n    ctx.lineWidth=2; ctx.stroke();\n  }\n  for(let r of [100,150,205,255]){\n    ctx.beginPath(); ctx.arc(0,0,r,0,Math.PI*2);\n    ctx.strokeStyle=\"rgba(0,0,0,.16)\"; ctx.lineWidth=2; ctx.stroke();\n  }\n\n  if(a.graffiti){\n    ctx.rotate(-0.18);\n    ctx.font=\"900 42px Arial\";\n    ctx.textAlign=\"center\";\n    ctx.fillStyle=\"rgba(38,178,255,.45)\";\n    ctx.strokeStyle=\"rgba(0,0,0,.4)\";\n    ctx.lineWidth=5;\n    ctx.strokeText(\"CRAZY\",0,-185);\n    ctx.fillText(\"CRAZY\",0,-185);\n    ctx.fillStyle=\"rgba(237,50,50,.55)\";\n    ctx.strokeText(\"BEAN\",0,-145);\n    ctx.fillText(\"BEAN\",0,-145);\n  }\n  ctx.restore();\n\n  ctx.save(); ctx.translate(cx,cy); ctx.scale(1,.77);\n  ctx.rotate(Math.PI\/2);\n  ctx.fillStyle=\"rgba(14,22,30,.72)\";\n  ctx.strokeStyle=\"rgba(255,255,255,.28)\";\n  ctx.lineWidth=3;\n  roundRect(-70,-bowlR+18,140,46,10,true,true);\n  ctx.fillStyle=\"#9de25b\";\n  ctx.font=\"bold 14px Arial\";\n  ctx.textAlign=\"center\";\n  ctx.fillText(\"PARTNER ?\",0,-bowlR+47);\n  ctx.restore();\n\n  oval(cx,cy+8,holeR+18,.77,\"rgba(0,0,0,.45)\");\n  oval(cx,cy,holeR+15,.77,\"#aa8b6c\",\"rgba(255,255,255,.28)\",3);\n  const hg=ctx.createRadialGradient(cx,cy,4,cx,cy,holeR+8);\n  hg.addColorStop(0,\"#000\"); hg.addColorStop(.72,\"#030303\"); hg.addColorStop(1,\"#1b0d06\");\n  oval(cx,cy,holeR,.77,hg);\n\n  ctx.save(); ctx.translate(cx,cy); ctx.scale(1,.77);\n  ctx.beginPath(); ctx.arc(0,0,172,0,Math.PI*2);\n  ctx.strokeStyle=\"rgba(255,225,55,.32)\";\n  ctx.setLineDash([12,10]);\n  ctx.lineWidth=4; ctx.stroke(); ctx.setLineDash([]);\n  ctx.restore();\n\n  ctx.save(); ctx.translate(cx,cy); ctx.scale(1,.77);\n  ctx.beginPath(); ctx.moveTo(0,0); ctx.lineTo(tilt.x*118,tilt.y*118);\n  ctx.strokeStyle=\"rgba(255,255,255,.5)\"; ctx.lineWidth=6; ctx.stroke();\n  ctx.restore();\n}\n\nfunction drawBean(){\n  const cfg=beans[beanIndex];\n  ctx.save();\n  ctx.translate(bean.x+9,bean.y+13); ctx.rotate(bean.angle); ctx.scale(1.06,.78);\n  ctx.beginPath(); ctx.arc(0,0,bean.r,0,Math.PI*2);\n  ctx.fillStyle=\"rgba(0,0,0,.34)\"; ctx.fill();\n  ctx.restore();\n\n  ctx.save();\n  ctx.translate(bean.x,bean.y); ctx.rotate(bean.angle); ctx.scale(1.02,1.42);\n  const grad=ctx.createLinearGradient(0,-bean.r,0,bean.r);\n  grad.addColorStop(0,cfg.cap); grad.addColorStop(.43,cfg.cap);\n  grad.addColorStop(.48,\"#fff7d4\"); grad.addColorStop(.52,cfg.body); grad.addColorStop(1,\"#b21d16\");\n  roundRect(-bean.r,-bean.r,bean.r*2,bean.r*2,bean.r,true,false,grad);\n  ctx.lineWidth=2.5; ctx.strokeStyle=\"rgba(90,20,10,.35)\"; ctx.stroke();\n\n  ctx.save(); ctx.scale(1,.72);\n  ctx.fillStyle=\"#fff\";\n  ctx.beginPath(); ctx.arc(-8,-2,6,0,Math.PI*2); ctx.fill();\n  ctx.beginPath(); ctx.arc(8,-2,6,0,Math.PI*2); ctx.fill();\n  ctx.fillStyle=\"#111\";\n  const lookX=Math.max(-2,Math.min(2,tilt.x*3));\n  ctx.beginPath(); ctx.arc(-8+lookX,-1,2.5,0,Math.PI*2); ctx.fill();\n  ctx.beginPath(); ctx.arc(8+lookX,-1,2.5,0,Math.PI*2); ctx.fill();\n  ctx.strokeStyle=\"#251711\"; ctx.lineWidth=2.5; ctx.beginPath();\n  if(cfg.mood===\"cool\"){ctx.moveTo(-15,8);ctx.lineTo(15,8);}\n  else if(cfg.mood===\"happy\"){ctx.arc(0,6,10,.1,Math.PI-.1);}\n  else{ctx.arc(0,14,10,Math.PI+.1,-.1);}\n  ctx.stroke();\n  ctx.strokeStyle=\"#692414\"; ctx.lineWidth=2;\n  for(let i=-3;i<=3;i++){ctx.beginPath();ctx.moveTo(i*5,-20);ctx.lineTo(i*7,-31-Math.abs(i)*2);ctx.stroke();}\n  ctx.restore();\n  ctx.restore();\n\n  if(bubble &#038;&#038; performance.now()<bubbleUntil){\n    ctx.save(); ctx.translate(bean.x+42,bean.y-44);\n    ctx.fillStyle=\"rgba(255,255,255,.95)\";\n    ctx.strokeStyle=\"rgba(70,80,70,.35)\";\n    ctx.lineWidth=2;\n    roundRect(-36,-20,72,34,17,true,true);\n    ctx.fillStyle=\"#e73838\";\n    ctx.font=\"900 15px Arial\";\n    ctx.textAlign=\"center\";\n    ctx.fillText(bubble,0,3);\n    ctx.restore();\n  }\n}\n\nfunction draw(){ drawArena(); drawBean(); }\nfunction loop(now){\n  const dt=Math.min(.033,(now-last)\/1000);\n  last=now; physics(dt); draw(); requestAnimationFrame(loop);\n}\nstartGame();\nrequestAnimationFrame(loop);\n<\/script><br \/>\n<\/body><br \/>\n<\/html><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Crazy Bean \u2013 Skate Arena Playable 2.1 CRAZYBEAN SKATE ARENA &#x23f1; TIME0.00 &#x1f3c6; BEST\u2014 &#x1fad8; BEANHyper BEAN CHARACTERS PARTNER SPACE ? YOUR LOGO HERE HOW TO PLAY Tilt to roll Avoid the hole Beat your time Climb leaderboards SOUNDS &#038; REACTIONS OOPS!WOW! OH NO!YEEES! FEATURES Real physics Simple to understand Hard to master Collectible beans [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-97","page","type-page","status-publish","hentry"],"blocksy_meta":[],"_links":{"self":[{"href":"https:\/\/qvg.ai\/index.php?rest_route=\/wp\/v2\/pages\/97","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/qvg.ai\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/qvg.ai\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/qvg.ai\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/qvg.ai\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=97"}],"version-history":[{"count":2,"href":"https:\/\/qvg.ai\/index.php?rest_route=\/wp\/v2\/pages\/97\/revisions"}],"predecessor-version":[{"id":99,"href":"https:\/\/qvg.ai\/index.php?rest_route=\/wp\/v2\/pages\/97\/revisions\/99"}],"wp:attachment":[{"href":"https:\/\/qvg.ai\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=97"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}