{"id":1271,"date":"2026-10-13T18:42:58","date_gmt":"2026-10-13T18:42:58","guid":{"rendered":"https:\/\/blu.gooseandhopper.com\/?page_id=1271"},"modified":"2026-10-13T18:44:18","modified_gmt":"2026-10-13T18:44:18","slug":"game","status":"publish","type":"page","link":"https:\/\/blu.gooseandhopper.com\/en\/game\/","title":{"rendered":"Game"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"1271\" class=\"elementor elementor-1271\" data-elementor-post-type=\"page\">\n\t\t\t\t<div class=\"elementor-element elementor-element-efcb973 e-con-full e-flex e-con e-parent\" data-id=\"efcb973\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t<div class=\"elementor-element elementor-element-c6a0a7d elementor-widget elementor-widget-html\" data-id=\"c6a0a7d\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<!doctype html>\n<html lang=\"es\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1, viewport-fit=cover\">\n<style>*,*::before,*::after{box-sizing:border-box}body{margin:0}img{max-width:100%}[hidden]{display:none!important}:root{padding-top:env(safe-area-inset-top,0px);padding-bottom:env(safe-area-inset-bottom,0px)}<\/style>\n<title>La Canasta de Blucito<\/title>\n<link rel=\"preconnect\" href=\"https:\/\/fonts.googleapis.com\">\n<link rel=\"stylesheet\" href=\"https:\/\/fonts.googleapis.com\/css2?family=Baloo+2:wght@600;800&family=Nunito:wght@500;700;800&display=swap\">\n<style>\n  :root{\n    color-scheme: light;\n    --wall:#E4EBFC;\n    --ink:#0E1A5C;\n    --blu:#6C9BEE;\n    --blu-deep:#4F7FE0;\n    --cheek:#E7AEFA;\n    --paper:#FBFCFF;\n    --muted:#5B6597;\n    --danger:#E0567A;\n  }\n  [hidden]{display:none!important}\n  html,body{height:100%}\n  body{\n    background:var(--wall);\n    color:var(--ink);\n    font-family:\"Nunito\",system-ui,sans-serif;\n    padding-inline:16px;\n    display:flex;justify-content:center;\n    overflow:hidden;\n    -webkit-tap-highlight-color:transparent;\n  }\n  .wrap{\n    width:min(calc(100vw - 32px), 1700px);margin-inline:auto;align-self:center;\n    \/* sized from the screen itself, so it works even if the host wraps the page *\/\n    height:calc(100vh - env(safe-area-inset-top,0px) - env(safe-area-inset-bottom,0px));\n    height:calc(100dvh - env(safe-area-inset-top,0px) - env(safe-area-inset-bottom,0px));\n    display:flex;flex-direction:column;gap:10px;\n    padding-block:12px;\n  }\n  .hud{display:flex;align-items:center;justify-content:space-between;gap:12px}\n  .brand{font-family:\"Baloo 2\",system-ui,sans-serif;font-weight:800;font-size:20px;line-height:1;letter-spacing:-.01em}\n  .brand span{color:var(--blu-deep)}\n  .stats{display:flex;align-items:center;gap:14px;font-weight:800;font-variant-numeric:tabular-nums}\n  .score .lbl{font-family:\"Nunito\",system-ui,sans-serif;font-size:11px;font-weight:800;letter-spacing:.08em;text-transform:uppercase;color:var(--muted);vertical-align:middle}\n  .score{white-space:nowrap;font-family:\"Baloo 2\",system-ui,sans-serif;font-size:22px;line-height:1;min-width:3ch;text-align:right}\n  .lives{display:flex;gap:3px}\n  .lives i{width:18px;height:16px;display:block;\n    background:var(--danger);\n    -webkit-mask:url(\"data:image\/svg+xml,%3Csvg xmlns='http:\/\/www.w3.org\/2000\/svg' viewBox='0 0 24 21'%3E%3Cpath d='M12 21S0 13.5 0 6.3C0 2.8 2.7 0 6 0c2.4 0 4.6 1.5 6 3.6C13.4 1.5 15.6 0 18 0c3.3 0 6 2.8 6 6.3C24 13.5 12 21 12 21z'\/%3E%3C\/svg%3E\") center\/contain no-repeat;\n            mask:url(\"data:image\/svg+xml,%3Csvg xmlns='http:\/\/www.w3.org\/2000\/svg' viewBox='0 0 24 21'%3E%3Cpath d='M12 21S0 13.5 0 6.3C0 2.8 2.7 0 6 0c2.4 0 4.6 1.5 6 3.6C13.4 1.5 15.6 0 18 0c3.3 0 6 2.8 6 6.3C24 13.5 12 21 12 21z'\/%3E%3C\/svg%3E\") center\/contain no-repeat;\n    transition:opacity .2s, transform .2s}\n  .lives i.off{opacity:.18;transform:scale(.8)}\n  .stage{position:relative;width:100%;flex:1 1 auto;min-height:0;max-width:100%;\n    border-radius:22px;overflow:hidden;\n    box-shadow:0 0 0 3px var(--ink), 0 10px 0 0 rgba(14,26,92,.18);\n    touch-action:none;user-select:none;background:var(--paper)}\n  #c{display:block;position:absolute;inset:0;width:100%;height:100%}\n  .overlay{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;\n    padding:14px;background:rgba(228,235,252,.55);overflow:auto;backdrop-filter:blur(2px)}\n  .card{background:var(--paper);border:3px solid var(--ink);border-radius:20px;\n    padding:18px 18px 16px;width:100%;max-width:340px;display:flex;flex-direction:column;gap:12px;margin:auto;\n    box-shadow:0 6px 0 var(--ink)}\n  .card h1,.card h2{font-family:\"Baloo 2\",system-ui,sans-serif;font-weight:800;margin:0;line-height:1;text-wrap:balance}\n  .card h1{font-size:clamp(22px,3.2vw,30px)}\n  .card h2{font-size:28px}\n  .card p{margin:0;font-size:14px;line-height:1.45;color:var(--muted)}\n  .legend{display:grid;grid-template-columns:1fr 1fr;gap:6px 10px}\n  .card.wide{max-width:640px;display:grid;grid-template-columns:1.1fr 1fr;gap:14px 20px;align-items:center}\n  .card.wide .col{display:flex;flex-direction:column;gap:10px}\n  @media (max-width:560px){ .card.wide{grid-template-columns:1fr} .card.wide .legend{grid-template-columns:1fr 1fr 1fr} }\n  .hud,.hint{flex:none}\n  @media (orientation:portrait){ .stage{min-height:min(560px, 62vh)} }\n  \/* big screens: keep a comfortable wide frame *\/\n  \/* screens wider than tall: a 16:9 room, centered, as big as fits *\/\n  @media (orientation:landscape){\n    .wrap{justify-content:center;padding-block:clamp(16px,4.5vh,48px);width:min(calc(100vw - 32px),1700px,calc((100vh - 70px - 2*clamp(16px,4.5vh,48px))*1.7778));width:min(calc(100vw - 32px),1700px,calc((100dvh - 70px - 2*clamp(16px,4.5vh,48px))*1.7778))}\n    .stage{flex:none;width:100%;aspect-ratio:16\/9;margin-inline:auto}\n  }\n  \/* phone lying down: the room takes the whole screen, score floats on top *\/\n  @media (orientation:landscape) and (max-height:520px){\n    body{padding-inline:max(8px, env(safe-area-inset-left, 0px)) max(8px, env(safe-area-inset-right, 0px))}\n    .wrap{width:calc(100vw - max(8px, env(safe-area-inset-left, 0px)) - max(8px, env(safe-area-inset-right, 0px)));position:relative;padding-block:6px}\n    .stage{flex:1 1 auto;aspect-ratio:auto;min-height:0}\n    .hud{position:absolute;top:16px;left:50%;transform:translateX(-50%);z-index:2;pointer-events:none;\n      background:rgba(251,252,255,.85);border:2px solid var(--ink);border-radius:12px;padding:5px 10px}\n    .brand{display:none}\n  }\n  \/* touch screens *\/\n  .k-touch{display:none}\n  @media (pointer:coarse){ .k-key{display:none} .k-touch{display:inline} .pause{width:42px;height:42px} }\n  \/* short screens (phone lying down) *\/\n  @media (max-height:520px){\n    .wrap{gap:6px;padding-block:6px}\n    .brand{font-size:16px} .score{font-size:18px} .lives i{width:15px;height:13px}\n    .hint{display:none}\n    .stage{border-radius:16px}\n    .overlay{padding:8px}\n    .card{padding:12px 14px;gap:8px;border-radius:16px}\n    .card.wide{gap:8px 16px}\n    .card h1{font-size:20px} .card h2{font-size:22px} .card p{font-size:12.5px;line-height:1.35}\n    .legend canvas{width:24px;height:24px} .legend div{font-size:11.5px}\n    button.go{font-size:17px;padding:6px 12px 4px}\n    .big{font-size:40px}\n  }\n  \/* narrow screens (phone standing up) *\/\n  @media (max-width:420px){ .card.wide .legend{grid-template-columns:1fr 1fr} }\n  .brand{white-space:nowrap}\n  @media (max-width:420px){ .brand{font-size:15px!important} .stats{gap:8px} }\n  @media (max-width:350px){ .score .lbl{display:none} }\n  @media (max-width:480px){ .brand{font-size:17px} .card h1{font-size:23px} .big{font-size:44px} }\n  .legend div{display:flex;align-items:center;gap:6px;font-size:12.5px;font-weight:700;line-height:1.15}\n  .legend canvas{width:30px;height:30px;flex:none}\n  .legend b{font-variant-numeric:tabular-nums}\n  .legend .bad{color:var(--danger)}\n  \/* ---- start popup ---- *\/\n  .card.intro{max-width:560px;display:block;padding:0;overflow:hidden}\n  .hero{position:relative;display:flex;flex-direction:column;align-items:center;justify-content:flex-end;gap:4px;\n    padding:18px 14px 0;border-right:3px solid var(--ink);\n    background:radial-gradient(circle,rgba(108,155,238,.22) 1.6px,transparent 2px) 0 0\/18px 18px, #DDE6FC}\n  .hero img{display:block;width:100%;max-width:240px;height:auto;margin-bottom:-4px}\n  .bubble{position:relative;align-self:stretch;text-align:center;background:var(--paper);border:3px solid var(--ink);border-radius:18px;\n    padding:9px 12px 7px;font-family:\"Baloo 2\",system-ui,sans-serif;font-weight:800;font-size:18px;line-height:1.05;box-shadow:0 4px 0 var(--ink)}\n  .bubble::after{content:\"\";position:absolute;left:50%;bottom:-11px;width:16px;height:16px;background:var(--paper);\n    border-right:3px solid var(--ink);border-bottom:3px solid var(--ink);transform:translateX(-50%) rotate(45deg)}\n  .body{padding:28px 30px 28px;display:flex;flex-direction:column;gap:14px;min-width:0}\n  .card.intro h1{font-size:clamp(24px,3.4vw,32px)}\n  .steps{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(3,1fr);gap:8px}\n  .steps li{display:flex;flex-direction:column;gap:5px;background:var(--wall);border-radius:12px;padding:8px 9px;font-size:12.5px;line-height:1.25;color:var(--ink)}\n  .steps .n{width:22px;height:22px;border-radius:50%;background:var(--ink);color:#fff;display:grid;place-items:center;font-weight:800;font-size:12px;line-height:1}\n  .groups{display:grid;grid-template-columns:2fr 1fr;gap:10px}\n  .gl{font-size:10.5px;font-weight:800;letter-spacing:.08em;text-transform:uppercase;color:var(--blu-deep);margin-bottom:5px}\n  .grp.bad .gl,.grp.bad .chip b{color:var(--danger)}\n  .chips{display:flex;gap:6px}\n  .chip{flex:1 1 0;min-width:0;display:flex;flex-direction:column;align-items:center;gap:1px;text-align:center;\n    font-size:10.5px;font-weight:700;line-height:1.1;border:2px solid rgba(14,26,92,.12);border-radius:10px;padding:5px 2px 4px}\n  .chip canvas{width:34px;height:34px}\n  .chip{gap:3px;padding:7px 2px 6px}\n  .chip b{font-size:12.5px;font-variant-numeric:tabular-nums;white-space:nowrap}\n  .card .rule{display:flex;align-items:center;justify-content:center;gap:8px;text-align:left;line-height:1.25;\n    font-size:13px;font-weight:800;color:var(--ink);margin-top:-2px}\n  .lives.mini{flex:none} .lives.mini i{width:14px;height:12px}\n  .card .bonus{display:flex;align-items:center;gap:7px;margin:-4px 0 0;font-size:12.5px;font-weight:700;color:var(--ink);line-height:1.25}\n  .grp.bad .chip{background:#FDE8EF;border-color:rgba(224,86,122,.35)}\n  .card.intro.over{max-width:480px!important}\n  .card.intro.paused{max-width:360px!important}\n  .results{display:grid;grid-template-columns:1.25fr 1fr;gap:8px}\n  .res{position:relative;background:var(--wall);border-radius:14px;padding:10px 12px 8px}\n  .res.main{background:var(--blu);color:#fff}\n  .res.main .gl{color:rgba(255,255,255,.85)}\n  .res .big{font-size:52px}\n  .res:not(.main) .big{color:var(--blu-deep)}\n  .res .big{display:inline-block;vertical-align:middle}\n  .badge{display:inline-block;vertical-align:middle;margin-left:6px;background:var(--danger);color:#fff;font-size:11px;font-weight:800;border-radius:999px;padding:3px 8px;transform:rotate(6deg)}\n  .card .stats{margin:0;font-size:13px;text-align:center;color:var(--muted)}\n  @media (max-height:520px) and (orientation:landscape){ .res .big{font-size:38px} .res{padding:7px 10px 6px} }\n  @media (max-width:600px){\n    .card.intro{grid-template-columns:1fr}\n    .hero{flex-direction:row;align-items:flex-end;justify-content:center;padding:14px 14px 0;border-right:0;border-bottom:3px solid var(--ink)}\n    .hero img{width:118px;flex:none}\n    .bubble{align-self:center;flex:0 1 auto;font-size:16px;margin-bottom:26px}\n    .bubble::after{left:auto;right:-11px;bottom:50%;transform:translateY(50%) rotate(-45deg)}\n  }\n  @media (max-width:440px){ .overlay{padding:10px} .body{padding:22px 18px 20px} .grp.bad .chip b{font-size:10px;letter-spacing:-.01em} .groups{grid-template-columns:4fr 2.35fr} .card.intro button.go{font-size:18px;white-space:nowrap} .card .rule{font-size:12px} .chips{gap:4px} .groups{gap:6px} .chip canvas{width:28px;height:28px} .chip b{font-size:10.5px} .chip{padding:6px 1px 5px} }\n  @media (max-width:380px){ .steps li{font-size:11.5px;padding:7px} }\n  @media (max-width:350px){ .grp.bad .chip b{font-size:9px} .card.intro button.go{font-size:16px} }\n  @media (max-height:520px) and (orientation:landscape){\n    .card.intro{max-width:560px}\n    .hero{padding:10px 10px 0} .hero img{max-width:150px} .bubble{font-size:14px;padding:6px 8px 5px}\n    .body{padding:14px 22px;gap:7px} .card.intro h1{font-size:20px}\n    .card .rule{font-size:11.5px} .card .bonus{font-size:11px;margin-top:-2px}\n    .steps li{font-size:11px;padding:5px 7px;gap:3px} .steps .n{width:18px;height:18px;font-size:10.5px}\n    .chip canvas{width:22px;height:22px} .chip{font-size:9.5px;padding:3px 2px}\n  }\n  .tag{font-size:11px;font-weight:800;letter-spacing:.08em;text-transform:uppercase;color:var(--blu-deep)}\n  button.go{font:inherit;font-family:\"Baloo 2\",system-ui,sans-serif;font-weight:800;font-size:20px;\n    background:var(--blu);color:#fff;border:3px solid var(--ink);border-radius:14px;padding:8px 14px 6px;\n    box-shadow:0 4px 0 var(--ink);cursor:pointer;transition:transform .08s, box-shadow .08s}\n  button.go:active{transform:translateY(3px);box-shadow:0 1px 0 var(--ink)}\n  button.go:focus,button.go:focus-visible{outline:none}\n  button.go:focus-visible{background:var(--blu-deep)}\n  .big{font-family:\"Baloo 2\",system-ui,sans-serif;font-weight:800;font-size:56px;line-height:.9;font-variant-numeric:tabular-nums}\n  .row{display:flex;justify-content:space-between;align-items:end;gap:8px}\n  .hint{font-size:12px;color:var(--muted);text-align:center;font-weight:700}\n  .pause{position:absolute;top:10px;right:10px;width:34px;height:34px;border-radius:10px;border:2px solid var(--ink);\n    background:var(--paper);color:var(--ink);cursor:pointer;display:flex;align-items:center;justify-content:center;padding:0}\n  .pause .bars{display:flex;gap:4px}\n  .ctrls{position:absolute;top:10px;right:10px;z-index:3;display:flex;gap:8px}\n  .ctrls .pause{position:static}\n  .ctrls .pause:disabled{opacity:.4;cursor:default}\n  .ico{width:20px;height:20px;display:block}\n  .ico path{fill:var(--ink);stroke:var(--ink);stroke-width:1.6;stroke-linejoin:round}\n  .ico path.w{fill:none;stroke-width:2.2;stroke-linecap:round}\n  #muteBtn .off{display:none} #muteBtn[aria-pressed=\"true\"] .on{display:none} #muteBtn[aria-pressed=\"true\"] .off{display:block}\n  .pause .bars::before,.pause .bars::after{content:\"\";display:block;width:4px;height:12px;border-radius:2px;background:var(--ink)}\n  .pause:focus,.pause:focus-visible{outline:none}\n  .pause:focus-visible{background:var(--wall)}\n<\/style>\n\n<\/head>\n<body>\n<div class=\"wrap\">\n  <div class=\"hud\">\n    <div class=\"brand\">La Canasta de <span>Blucito<\/span><\/div>\n    <div class=\"stats\">\n      <div class=\"lives\" id=\"lives\"><i><\/i><i><\/i><i><\/i><\/div>\n      <div class=\"score\"><span class=\"lbl\">Tandas<\/span> <span id=\"score\">0<\/span><\/div>\n    <\/div>\n  <\/div>\n\n  <div class=\"stage\" id=\"stage\">\n    <canvas id=\"c\"><\/canvas>\n    <div class=\"ctrls\">\n      <button class=\"pause\" id=\"muteBtn\" aria-label=\"Silenciar\" aria-pressed=\"false\">\n        <svg class=\"ico on\" viewBox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"M4 9.5h3.5L12 5.5v13l-4.5-4H4z\"\/><path class=\"w\" d=\"M15.5 9a4.2 4.2 0 0 1 0 6M18 6.5a7.8 7.8 0 0 1 0 11\"\/><\/svg>\n        <svg class=\"ico off\" viewBox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"M4 9.5h3.5L12 5.5v13l-4.5-4H4z\"\/><path class=\"w\" d=\"M15.5 9.5l5 5M20.5 9.5l-5 5\"\/><\/svg>\n      <\/button>\n      <button class=\"pause\" id=\"pauseBtn\" aria-label=\"Pausar\" disabled><span class=\"bars\" aria-hidden=\"true\"><\/span><\/button>\n    <\/div>\n\n    <div class=\"overlay\" id=\"startScreen\">\n      <div class=\"card intro\">\n        <div class=\"body\">\n          <h1>\u00bfCu\u00e1ntas tandas puedes lavar?<\/h1>\n          <ol class=\"steps\">\n            <li><span class=\"n\">1<\/span><span><b>Atrapa<\/b> la ropa sucia<\/span><\/li>\n            <li><span class=\"n\">2<\/span><span><b>Junta<\/b> 5 prendas<\/span><\/li>\n            <li><span class=\"n\">3<\/span><span><b>Ll\u00e9valas<\/b> a lavar<\/span><\/li>\n          <\/ol>\n          <p class=\"bonus\"><span class=\"lives mini\" aria-hidden=\"true\"><i><\/i><\/span><span>Cada 3 tandas lavadas: <b>+1 vida<\/b><\/span><\/p>\n          <div class=\"groups\">\n            <div class=\"grp\"><div class=\"gl\">Suma puntos<\/div><div class=\"chips\" id=\"goodChips\"><\/div><\/div>\n            <div class=\"grp bad\"><div class=\"gl\">\u00a1Cuidado!<\/div><div class=\"chips\" id=\"badChips\"><\/div><\/div>\n          <\/div>\n          <button class=\"go\" id=\"startBtn\">\u00a1A lavar con Blucito!<\/button>\n        <\/div>\n      <\/div>\n    <\/div>\n\n    <div class=\"overlay\" id=\"overScreen\" hidden>\n      <div class=\"card intro over\">\n        <div class=\"body\">\n          <h1 id=\"overMsg\">\u00a1Bien, Blucito!<\/h1>\n          <div class=\"results\">\n            <div class=\"res main\"><div class=\"gl\">Tandas lavadas<\/div><div class=\"big\" id=\"finalScore\">0<\/div><\/div>\n            <div class=\"res\"><div class=\"gl\">Tu r\u00e9cord<\/div><div class=\"big\" id=\"bestScore\">0<\/div><div class=\"badge\" id=\"recordBadge\" hidden>\u00a1Nuevo!<\/div><\/div>\n          <\/div>\n          <p class=\"stats\" id=\"overStats\"><\/p>\n          <button class=\"go\" id=\"againBtn\">\u00a1Otra vez con Blucito!<\/button>\n        <\/div>\n      <\/div>\n    <\/div>\n\n    <div class=\"overlay\" id=\"pauseScreen\" hidden>\n      <div class=\"card intro paused\">\n        <div class=\"body\">\n          <h1>En pausa<\/h1>\n          <button class=\"go\" id=\"resumeBtn\">Seguir lavando<\/button>\n        <\/div>\n      <\/div>\n    <\/div>\n  <\/div>\n  <div class=\"hint\"><span class=\"k-key\">Mu\u00e9vete con \u2190 \u2192 o A \/ D \u00b7 P pausa \u00b7 M sonido<\/span><span class=\"k-touch\">Arrastra el dedo para mover a Blucito<\/span><\/div>\n<\/div>\n\n<script>\n(() => {\nlet W = 800, H = 450, FLOOR = H - 42;\nconst WASH = {x: W-132, y: FLOOR-136, w: 112, h: 136};\nlet lastBox = '';\nconst CAP = 5;\nconst INK = '#0E1A5C';\nconst cv = document.getElementById('c'), ctx = cv.getContext('2d');\nlet DPR = 1;\nfunction resize(){\n  const r = cv.getBoundingClientRect();\n  if (!r.width || !r.height) return;\n  const aspect = r.width \/ r.height;\n  \/\/ the room is at least 480 wide and 450 tall; the other side grows with the screen\n  \/\/ small screens use a smaller room so Blu and the clothes look bigger\n  \/\/ room 10% smaller than before = everything drawn 10% bigger\n  const S = Math.min(r.width, r.height) < 430 ? 300 : 409;\n  W = Math.round(Math.max(364, S * aspect)); H = Math.round(W \/ aspect);\n  FLOOR = H - 42; WASH.x = W - 132; WASH.y = FLOOR - 136;\n  DPR = Math.min(3, (window.devicePixelRatio || 1)) * (r.width \/ W);\n  cv.width = Math.round(W * DPR); cv.height = Math.round(H * DPR);\n  const box = W+'x'+H;\n  if (box !== lastBox){ lastBox = box; buildBg();\n    if (typeof blu !== 'undefined') blu.x = Math.min(blu.x, WASH.x - 40);\n    if (state === 'menu') seedMenu();\n  }\n}\nnew ResizeObserver(resize).observe(cv);\n\n\/* ---------- grain texture (matches Blu's crayon\/risograph feel) ---------- *\/\nfunction makeGrain(size, strength){\n  const g = document.createElement('canvas'); g.width = g.height = size;\n  const gx = g.getContext('2d'); const id = gx.createImageData(size,size);\n  for (let i=0;i<id.data.length;i+=4){\n    const v = Math.random();\n    const light = v > .5;\n    id.data[i]=id.data[i+1]=id.data[i+2]= light?255:10;\n    id.data[i+1] = light?255:20; id.data[i+2]= light?255:70;\n    id.data[i+3] = Math.floor(Math.abs(v-.5)*2*strength);\n  }\n  gx.putImageData(id,0,0); return g;\n}\nconst grain = makeGrain(160, 70);\n\n\/* ---------- item sprites ---------- *\/\nconst S = 2; \/\/ sprite supersampling relative to logical px\nfunction sprite(w,h,drawFill,drawLine){\n  const c = document.createElement('canvas'); c.width = w*S*2; c.height = h*S*2;\n  const x = c.getContext('2d'); x.scale(S*2,S*2); \/\/ extra res for crisp DPR\n  x.lineJoin='round'; x.lineCap='round';\n  drawFill(x);\n  x.globalCompositeOperation='source-atop';\n  const p = x.createPattern(grain,'repeat'); x.fillStyle=p; x.save(); x.scale(.5,.5); x.fillRect(0,0,w*2,h*2); x.restore();\n  x.globalCompositeOperation='source-over';\n  x.strokeStyle=INK; x.lineWidth=2.4; x.fillStyle=INK;\n  drawLine(x);\n  return {c,w,h};\n}\nfunction blob(x,cx,cy,r,col){ x.fillStyle=col; x.beginPath();\n  for(let a=0;a<=Math.PI*2+.01;a+=Math.PI\/5){const rr=r*(0.75+((a*7919)%1)*0.25+0.15*Math.sin(a*3)); const px=cx+Math.cos(a)*rr, py=cy+Math.sin(a)*rr; a===0?x.moveTo(px,py):x.lineTo(px,py);} x.fill(); }\n\nconst sockPath = x => { x.beginPath(); x.moveTo(15,4); x.lineTo(27,4); x.lineTo(27,26); x.quadraticCurveTo(30,31,36,33); x.quadraticCurveTo(42,36,39,42); x.quadraticCurveTo(36,46,26,43); x.lineTo(19,40); x.quadraticCurveTo(13,37,14,30); x.closePath(); };\nconst shirtPath = x => { x.beginPath(); x.moveTo(17,5); x.quadraticCurveTo(24,11,31,5); x.lineTo(43,11); x.lineTo(39,20); x.lineTo(35,18); x.lineTo(35,43); x.lineTo(13,43); x.lineTo(13,18); x.lineTo(9,20); x.lineTo(5,11); x.closePath(); };\nconst pantsPath = x => { x.beginPath(); x.moveTo(11,4); x.lineTo(37,4); x.lineTo(41,45); x.lineTo(29,45); x.lineTo(24,17); x.lineTo(19,45); x.lineTo(7,45); x.closePath(); };\n\n\/* clothes: the client's illustrations. w\/h are game units; each is copied into a canvas once loaded *\/\nconst SPR = {};\nconst SPR_SRC = {\n  sock:   ['https:\/\/gyh.app\/wp-content\/uploads\/2026\/10\/ASSETS_BLUCITO_GAME_ropa-sucia-03.png',          100,180, 0, 50],\n  shirt:  ['https:\/\/gyh.app\/wp-content\/uploads\/2026\/10\/ASSETS_BLUCITO_GAME_ropa-sucia-01.png',           250,213, 54, 0],\n  pants:  ['https:\/\/gyh.app\/wp-content\/uploads\/2026\/10\/ASSETS_BLUCITO_GAME_ropa-sucia-02.png',          215,285, 0, 58],\n  stinky: ['https:\/\/gyh.app\/wp-content\/uploads\/2026\/10\/ASSETS_BLUCITO_GAME_ropa-sucia-04.png', 100,201, 0, 54],\n  clean:  ['https:\/\/gyh.app\/wp-content\/uploads\/2026\/10\/ASSETS_BLUCITO_GAME_ropa-limpia-01.png',            250,200, 54, 0],\n  shoe:   ['https:\/\/gyh.app\/wp-content\/uploads\/2026\/10\/ASSETS_BLUCITO_GAME_ropa-limpia-02.png',            165,100, 56, 0],\n};\nconst onAsset = [];\nfunction assetLoaded(){ onAsset.forEach(f=>f()); }\nObject.entries(SPR_SRC).forEach(([k,[src,nw,nh,tw,th]])=>{\n  const w = tw || th*nw\/nh, h = th || tw*nh\/nw;\n  const c=document.createElement('canvas'); c.width=Math.round(w*4); c.height=Math.round(h*4);\n  SPR[k]={c,w,h};\n  const im=new Image(); im.onload=()=>{ c.getContext('2d').drawImage(im,0,0,c.width,c.height); assetLoaded(); }; im.src=src;\n});\nconst IMG = {};\n[['washer','https:\/\/gyh.app\/wp-content\/uploads\/2026\/10\/ASSETS_BLUCITO_GAME_lavadora.png'],['shelf','https:\/\/gyh.app\/wp-content\/uploads\/2026\/10\/ASSETS_BLUCITO_GAME_repisa-con-detergentes.png'],['window','https:\/\/gyh.app\/wp-content\/uploads\/2026\/10\/ASSETS_BLUCITO_GAME_ventana.png']].forEach(([k,src])=>{\n  const im=new Image(); im.onload=()=>{ assetLoaded(); }; im.src=src; IMG[k]=im; });\nfunction ready(im){ return im && im.complete && im.naturalWidth; }\n\nconst TYPES = {\n  sock:   {pts:5,  speed:1.35, sway:0,   dirty:true,  label:'Calcet\u00edn'},\n  shirt:  {pts:10, speed:1,    sway:.3,  dirty:true,  label:'Playera'},\n  pants:  {pts:15, speed:.75,  sway:1,   dirty:true,  label:'Pantal\u00f3n'},\n  stinky: {pts:25, speed:1.15, sway:.2,  dirty:true,  label:'Calcet\u00edn apestoso'},\n  clean:  {pts:-10,speed:.95,  sway:.15, dirty:false, label:'Ropa limpia'},\n  shoe:   {pts:0,  speed:1.25, sway:0,   dirty:false, label:'Zapato'},\n};\n\n\/* chips on the start popup *\/\nconst NAMES = {sock:'Calcet\u00edn', shirt:'Playera', pants:'Pantal\u00f3n', stinky:'Apestoso', clean:'Ropa limpia', shoe:'Zapato'};\n[['sock','+5'],['shirt','+10'],['pants','+15'],['stinky','+25'],['clean','\u221210'],['shoe','\u22121 vida']].forEach(([k,v])=>{\n  const d=document.createElement('div'); d.className='chip'; d.title=TYPES[k].label;\n  const lc=document.createElement('canvas'); lc.width=60; lc.height=60;\n  const paint=()=>{ const lx=lc.getContext('2d'); lx.clearRect(0,0,60,60); const s=SPR[k]; const sc=Math.min(56\/s.c.width,56\/s.c.height); lx.drawImage(s.c,(60-s.c.width*sc)\/2,(60-s.c.height*sc)\/2,s.c.width*sc,s.c.height*sc); };\n  paint(); onAsset.push(paint);\n  d.appendChild(lc); d.setAttribute('aria-label', TYPES[k].label+' '+v); d.insertAdjacentHTML('beforeend',`<b>${v}<\/b>`);\n  document.getElementById(TYPES[k].dirty?'goodChips':'badChips').appendChild(d);\n});\n\n\/* ---------- background (drawn once) ---------- *\/\nlet bg = null;\nfunction buildBg(){\n  const c=document.createElement('canvas'); c.width=W*2; c.height=H*2; const x=c.getContext('2d'); x.scale(2,2);\n  x.lineJoin='round'; x.lineCap='round';\n  const wg=x.createLinearGradient(0,0,0,FLOOR); wg.addColorStop(0,'#D9E3FB'); wg.addColorStop(1,'#EEF2FD');\n  x.fillStyle=wg; x.fillRect(0,0,W,FLOOR);\n  \/\/ wallpaper dots\n  x.fillStyle='rgba(108,155,238,.18)';\n  for(let yy=26;yy<FLOOR-10;yy+=34) for(let xx=(yy\/34%2?20:37);xx<W;xx+=34){x.beginPath();x.arc(xx,yy,2.2,0,7);x.fill();}\n  \/\/ window\n  if (ready(IMG.window)) x.drawImage(IMG.window, 52, 52, 136, 136*IMG.window.naturalHeight\/IMG.window.naturalWidth);\n  \/\/ shelf with detergent\n  { const sw=156, sh=sw*351\/600, sx=WASH.x+WASH.w\/2-sw\/2-8, sy=WASH.y-36-sh;\n    if (sy>8 && ready(IMG.shelf)) x.drawImage(IMG.shelf, sx, sy, sw, sh); }\n  \/\/ floor\n  x.fillStyle='#F6F2FF'; x.fillRect(0,FLOOR,W,H-FLOOR);\n  x.strokeStyle='rgba(14,26,92,.14)'; x.lineWidth=2;\n  for(let xx=-20;xx<W+40;xx+=48){x.beginPath();x.moveTo(xx,FLOOR);x.lineTo(xx-30,H);x.stroke();}\n  x.strokeStyle=INK; x.lineWidth=3; x.beginPath(); x.moveTo(0,FLOOR); x.lineTo(W,FLOOR); x.stroke();\n  \/\/ grain over everything\n  x.globalAlpha=.35; x.fillStyle=x.createPattern(grain,'repeat'); x.fillRect(0,0,W,H); x.globalAlpha=1;\n  bg=c;\n}\nbuildBg();\nonAsset.push(()=>buildBg());\n\n\/* ---------- Blu ---------- *\/\nconst bluImg = new Image(); bluImg.src = 'https:\/\/gyh.app\/wp-content\/uploads\/2026\/10\/ASSETS_BLUCITO_GAME_blucito-con-canasta.png';\nconst bluHappy = new Image(); bluHappy.src = 'https:\/\/gyh.app\/wp-content\/uploads\/2026\/10\/ASSETS_BLUCITO_GAME_blucito-feliz-con-canasta.png';\nconst bluSad = new Image(); bluSad.src = 'https:\/\/gyh.app\/wp-content\/uploads\/2026\/10\/ASSETS_BLUCITO_GAME_blucito-triste-con-canasta.png';\nconst BLU_W = 168, BLU_H = BLU_W*706\/870;\nconst RIM_L = 232\/870, RIM_R = 638\/870, RIM_Y = 300\/706; \/\/ basket opening, as fractions of the sprite\nconst blu = {x:W\/2, vx:0, target:null, squash:0, hurt:0, tilt:0, happy:0};\nfunction bluTop(){ return FLOOR + 8 - BLU_H; }\nfunction rim(){ const left = blu.x - BLU_W\/2; return {l:left+BLU_W*RIM_L, r:left+BLU_W*RIM_R, y:bluTop()+BLU_H*RIM_Y}; }\n\n\/* ---------- state ---------- *\/\nconst $ = id => document.getElementById(id);\nlet state='menu', items=[], pops=[], splats=[], pile=[], score=0, lives=3, t=0, spawnT=0, caught=0, missed=0, loads=0, shake=0, keys={};\nlet best=0; try{ best = +localStorage.getItem('blu-best-tandas')||0 }catch(e){}\n\nfunction reset(){ items=[];pops=[];splats=[];pile=[];bubbles=[];wash.spin=0;wash.warn=0;wash.was=false;blu.happy=0;score=0;lives=3;t=0;spawnT=.6;caught=0;missed=0;loads=0;shake=0;blu.x=W\/2;blu.target=null;updateHud(); }\nfunction updateHud(){ $('score').textContent=loads; [...$('lives').children].forEach((h,i)=>h.classList.toggle('off',i>=lives)); }\n\nfunction difficulty(){ return Math.min(1, t\/150); } \/\/ ramps over ~90 seconds\nfunction pickType(){\n  const d=difficulty(), r=Math.random();\n  const bad = .16 + d*.16;\n  if (r < bad*.45) return 'clean';\n  if (r < bad) return 'shoe';\n  const g=Math.random();\n  if (g < .07+d*.06) return 'stinky';\n  if (g < .40) return 'sock';\n  if (g < .75) return 'shirt';\n  return 'pants';\n}\nfunction spawn(){\n  const type=pickType(), T=TYPES[type], s=SPR[type];\n  const base = 70 + difficulty()*80;\n  items.push({type, x: 44 + Math.random()*(WASH.x-90), y:-30, vx:0, bounced:false, vy: base*T.speed*(0.9+Math.random()*.2),\n    rot:(Math.random()-.5)*.6, vr:(Math.random()-.5)*2.2, ph:Math.random()*6, w:s.w, h:s.h});\n}\n\n\/* ---------- audio ---------- *\/\nlet ac=null;\nlet muted=false; try{ muted = localStorage.getItem('blu-muted')==='1' }catch(e){}\nfunction beep(f,dur=.09,type='triangle',vol=.12,slide=0){\n  if (muted) return;\n  try{ ac = ac || new (window.AudioContext||window.webkitAudioContext)();\n    const o=ac.createOscillator(), g=ac.createGain(); o.type=type; o.frequency.setValueAtTime(f,ac.currentTime);\n    if(slide) o.frequency.exponentialRampToValueAtTime(f*slide, ac.currentTime+dur);\n    g.gain.setValueAtTime(vol,ac.currentTime); g.gain.exponentialRampToValueAtTime(.001,ac.currentTime+dur);\n    o.connect(g); g.connect(ac.destination); o.start(); o.stop(ac.currentTime+dur);\n  }catch(e){}\n}\n\nfunction pop(x,y,text,color){ pops = pops.filter(p=>Math.abs(p.y-y)>36 || Math.abs(p.x-x)>160); pops.push({x,y,text,color,life:1}); }\n\nfunction hurt(){\n  lives--; blu.hurt=.9; blu.happy=0; shake=.35; updateHud(); beep(180,.25,'sawtooth',.08,.5);\n  if(navigator.vibrate) try{navigator.vibrate(60)}catch(e){}\n  if(lives<=0) gameOver();\n}\n\nfunction update(dt){\n  t+=dt;\n  \/\/ movement\n  const speed = 560;\n  let dir = (keys.ArrowRight||keys.d||keys.D?1:0) - (keys.ArrowLeft||keys.a||keys.A?1:0);\n  if (dir){ blu.target=null; blu.vx += (dir*speed - blu.vx)*Math.min(1,dt*14); }\n  else if (blu.target!=null){ const want=(blu.target-blu.x)*12; blu.vx += (Math.max(-speed*1.4,Math.min(speed*1.4,want))-blu.vx)*Math.min(1,dt*16); }\n  else blu.vx *= Math.pow(.0005,dt);\n  blu.x += blu.vx*dt; const half=BLU_W*.46, maxX=WASH.x-BLU_W*.22; if(blu.x<half){blu.x=half;blu.vx=0} if(blu.x>maxX){blu.x=maxX;blu.vx=0}\n  wash.warn=Math.max(0,(wash.warn||0)-dt);\n  const atWasher = blu.x>=maxX-4, arrived = atWasher && !wash.was; wash.was = atWasher;\n  if (atWasher){\n    if (pile.length>=CAP){ emptyBasket(); wash.warn=2.5; }\n    else if (arrived && !wash.warn){ const f=CAP-pile.length; wash.warn=1.6;\n      pop(WASH.x+WASH.w\/2, WASH.y-14, pile.length? `Faltan ${f} ${f===1?'prenda':'prendas'}` : 'La canasta est\u00e1 vac\u00eda', '#E0567A'); beep(240,.12,'square',.05,.8); }\n  }\n  wash.spin=Math.max(0,wash.spin-dt); wash.ang+=dt*(wash.spin>0?16:0);\n  blu.tilt += ((blu.vx\/speed)*.12 - blu.tilt)*Math.min(1,dt*10);\n  blu.squash = Math.max(0, blu.squash-dt*4); blu.hurt=Math.max(0,blu.hurt-dt); blu.happy=Math.max(0,blu.happy-dt); shake=Math.max(0,shake-dt);\n\n  \/\/ spawning\n  spawnT -= dt;\n  const onScreen = items.filter(i=>!i.bounced).length, maxOn = 2 + Math.floor(difficulty()*2.5);\n  if (spawnT<=0 && onScreen>=maxOn) spawnT = .3;\n  if (spawnT<=0){ spawn(); spawnT = (1.9 - difficulty()*.9) * (0.75+Math.random()*.5); }\n\n  const R = rim();\n  for (let i=items.length-1;i>=0;i--){\n    const it=items[i], T=TYPES[it.type];\n    const prevY = it.y;\n    it.y += it.vy*dt; it.rot += it.vr*dt;\n    if (it.bounced){ it.vy += 900*dt; it.x += it.vx*dt; }\n    else if (T.sway) it.x += Math.sin(t*2.4+it.ph)*T.sway*70*dt;\n    it.x=Math.max(20,Math.min(WASH.x-20,it.x));\n    const bottom = it.y + it.h*.3;\n    \/\/ catch: crosses basket opening\n    if (!it.bounced && prevY + it.h*.3 <= R.y + 6 && bottom >= R.y - 2 && it.x > R.l && it.x < R.r){\n      items.splice(i,1); catchItem(it); continue;\n    }\n    if (it.y > FLOOR - it.h*.25){\n      items.splice(i,1);\n      if (T.dirty){ missed++; splats.push({x:it.x,type:it.type,rot:it.rot,life:3}); pop(it.x,FLOOR-30,'\u00a1Al piso!','#E0567A'); hurt(); }\n    }\n  }\n  for (let i=bubbles.length-1;i>=0;i--){ const b=bubbles[i]; b.life-=dt; b.vy-=30*dt; b.vx*=Math.pow(.4,dt); b.x+=b.vx*dt+Math.sin(t*4+b.ph)*12*dt; b.y+=b.vy*dt; if(b.life<=0||b.y<-20) bubbles.splice(i,1); }\n  for (let i=pops.length-1;i>=0;i--){ const p=pops[i]; p.life-=dt*1.1; p.y-=dt*40; if(p.life<=0) pops.splice(i,1); }\n  for (let i=splats.length-1;i>=0;i--){ splats[i].life-=dt; if(splats[i].life<=0) splats.splice(i,1); }\n}\n\nfunction catchItem(it){\n  const T=TYPES[it.type];\n  if (it.type==='shoe'){ pop(it.x,rim().y-20,'\u00a1Auch! Zapato','#E0567A'); hurt(); return; }\n  if (it.type==='clean'){ score=Math.max(0,score+T.pts); pop(it.x,rim().y-20,'\u00a1Esa ya estaba limpia! \u221210','#E0567A'); beep(260,.18,'square',.06,.7); updateHud(); return; }\n  if (pile.length>=CAP){ \/\/ full: it bounces out\n    it.bounced=true; it.vy=-260; it.vx=(it.x<blu.x?-1:1)*(90+Math.random()*60); it.vr*=3; items.push(it);\n    pop(it.x, rim().y-24, '\u00a1Ya no cabe!', '#E0567A'); beep(300,.12,'square',.06,.8); return;\n  }\n  score+=T.pts; caught++; blu.squash=1; blu.happy=.8;\n  pop(it.x, rim().y-24, '+'+T.pts, it.type==='stinky'?'#6E7B2E':'#0E1A5C');\n  beep(it.type==='stinky'?520:660+Math.random()*120,.09,'triangle',.12,1.5);\n  pile.push({type:it.type, dx:(Math.random()-.5)*.6, rot:(Math.random()-.5)*1.2});\n  if (pile.length===CAP){ pop(blu.x, rim().y-50, '\u00a1Canasta llena! Ve a la lavadora', '#4F7FE0'); beep(440,.12); setTimeout(()=>beep(440,.12),140); }\n  updateHud();\n}\nconst wash={spin:0, ang:0, colors:[]};\nfunction emptyBasket(){\n  const bonus=50;\n  loads++; score+=bonus; wash.spin=2.4; wash.colors=pile.map(p=>({sock:'#F3F1EA',shirt:'#FFC94D',pants:'#3C63C9',stinky:'#B9D46A'}[p.type]));\n  pop(WASH.x+WASH.w\/2, WASH.y-14, '\u00a1Tanda lavada! +'+bonus, '#4F7FE0');\n  [880,1100,1320].forEach((f,k)=>setTimeout(()=>beep(f,.1,'triangle',.1),k*80));\n  for (let k=0;k<22;k++){ const a=-Math.PI\/2+(Math.random()-.5)*2.2, sp=60+Math.random()*120;\n    bubbles.push({x:WASH.x+WASH.w\/2+(Math.random()-.5)*30, y:WASH.y+WASH.h*.6, vx:Math.cos(a)*sp, vy:Math.sin(a)*sp-40, r:4+Math.random()*9, life:1.4+Math.random()*1.2, ph:Math.random()*6}); }\n  if (loads % 3 === 0){\n    if (lives < 3){ lives++; setTimeout(()=>pop(blu.x, rim().y-70, '\u00a1+1 vida!', '#E0567A'), 350); [990,1320].forEach((f,k)=>setTimeout(()=>beep(f,.12,'sine',.1),380+k*110)); }\n    else { score+=25; setTimeout(()=>pop(blu.x, rim().y-70, '\u00a1Bono espumoso! +25', '#4F7FE0'), 350); }\n  }\n  pile=[]; blu.squash=1; blu.happy=1.4; updateHud();\n}\nlet bubbles=[];\nfunction drawBubbles(){\n  bubbles.forEach(b=>{ const a=Math.min(1,b.life*1.4); ctx.save(); ctx.globalAlpha=a;\n    ctx.fillStyle='rgba(251,252,255,.75)'; ctx.strokeStyle='rgba(14,26,92,.55)'; ctx.lineWidth=1.8;\n    ctx.beginPath(); ctx.arc(b.x,b.y,b.r,0,7); ctx.fill(); ctx.stroke();\n    ctx.fillStyle='#fff'; ctx.beginPath(); ctx.arc(b.x-b.r*.35,b.y-b.r*.35,b.r*.28,0,7); ctx.fill(); ctx.restore(); });\n}\nfunction drawWasher(){\n  const {x:mx,y:my,w,h}=WASH, cx=mx+w*.479, cy=my+h*.516, r=w*.232;\n  const jig = wash.spin>0 && state==='play' ? Math.sin(t*50)*1.2 : 0;\n  ctx.save(); ctx.translate(jig,0);\n  if (ready(IMG.washer)) ctx.drawImage(IMG.washer, mx, my, w, h);\n  if (wash.spin>0){ \/\/ clothes tumbling behind the glass\n    ctx.save(); ctx.beginPath(); ctx.arc(cx,cy,r,0,7); ctx.clip();\n    wash.colors.forEach((c,i)=>{ const a=wash.ang+i*(Math.PI*2\/wash.colors.length);\n      ctx.globalAlpha=.85; ctx.fillStyle=c; ctx.strokeStyle=INK; ctx.lineWidth=1.5;\n      ctx.beginPath(); ctx.arc(cx+Math.cos(a)*r*.55, cy+Math.sin(a)*r*.55, 6.5,0,7); ctx.fill(); ctx.stroke(); });\n    ctx.restore();\n  }\n  ctx.restore();\n  if (state==='play' && pile.length>=CAP){ \/\/ guide arrow\n    const bob=Math.sin(t*7)*6, ax=mx+w\/2, ay=my-36+bob;\n    ctx.save(); ctx.fillStyle='#E0567A'; ctx.strokeStyle=INK; ctx.lineWidth=3; ctx.lineJoin='round';\n    ctx.beginPath(); ctx.moveTo(ax-14,ay-18); ctx.lineTo(ax+14,ay-18); ctx.lineTo(ax+14,ay); ctx.lineTo(ax+24,ay); ctx.lineTo(ax,ay+22); ctx.lineTo(ax-24,ay); ctx.lineTo(ax-14,ay); ctx.closePath(); ctx.fill(); ctx.stroke();\n    ctx.restore();\n  }\n}\n\n\/* ---------- drawing ---------- *\/\nfunction drawItem(it, alpha=1){\n  const s=SPR[it.type]; ctx.save(); ctx.globalAlpha=alpha; ctx.translate(it.x,it.y); ctx.rotate(it.rot);\n  ctx.drawImage(s.c,-s.w\/2,-s.h\/2,s.w,s.h); ctx.restore();\n  if (it.type==='stinky' && alpha===1){ \/\/ flies + stink lines\n    ctx.save(); ctx.strokeStyle='rgba(110,123,46,.8)'; ctx.lineWidth=2;\n    ctx.fillStyle=INK; for(let k=0;k<2;k++){ const a=t*6+k*3; ctx.beginPath(); ctx.arc(it.x+Math.cos(a)*22, it.y+Math.sin(a*1.3)*16,2,0,7); ctx.fill(); }\n    ctx.restore();\n  }\n}\nfunction drawBlu(){\n  const top=bluTop(), sq = Math.sin(blu.squash*Math.PI)*.08;\n  ctx.save();\n  \/\/ shadow\n  ctx.fillStyle='rgba(14,26,92,.13)'; ctx.beginPath(); ctx.ellipse(blu.x,FLOOR+5,BLU_W*.34,6,0,0,7); ctx.fill();\n  ctx.translate(blu.x, FLOOR+8); ctx.rotate(blu.tilt); ctx.scale(1+sq,1-sq);\n  const walk = state==='play' && Math.abs(blu.vx)>40 ? Math.abs(Math.sin(t*14))*3 : 0;\n  ctx.translate(0,-walk);\n  const face = (state==='over' || (state==='play' && blu.hurt>0)) && ready(bluSad) ? bluSad\n             : (blu.happy>0 && state==='play' && ready(bluHappy)) ? bluHappy : bluImg;\n  if (face.complete && face.naturalWidth) ctx.drawImage(face,-BLU_W\/2,-BLU_H,BLU_W,BLU_H);\n  \/\/ clothes peeking out of the basket\n  const rl=-BLU_W\/2+BLU_W*RIM_L+8, rr=-BLU_W\/2+BLU_W*RIM_R-8, ry=-BLU_H+BLU_H*RIM_Y;\n  ctx.save(); ctx.beginPath(); ctx.rect(rl-10, ry-60, rr-rl+20, 62); ctx.clip();\n  pile.forEach((p,i)=>{ const s=SPR[p.type]; const col=i%4, row=Math.floor(i\/4);\n    const px = rl + (col+.5)*(rr-rl)\/4 + p.dx*10, py = ry + 6 - row*9;\n    ctx.save(); ctx.translate(px,py); ctx.rotate(p.rot); ctx.drawImage(s.c,-s.w*.32,-s.h*.32,s.w*.64,s.h*.64); ctx.restore(); });\n  ctx.restore();\n  ctx.restore();\n}\nfunction render(){\n  ctx.setTransform(DPR,0,0,DPR,0,0);\n  ctx.save();\n  if (shake>0 && state==='play') ctx.translate((Math.random()-.5)*10*shake,(Math.random()-.5)*10*shake);\n  ctx.drawImage(bg,0,0,W,H);\n  drawWasher();\n  drawBubbles();\n  splats.forEach(s=>{ const it={type:s.type,x:s.x,y:FLOOR+6,rot:Math.PI\/2*.9}; drawItem(it, Math.min(1,s.life)*.7); });\n  drawBlu();\n  items.forEach(it=>drawItem(it));\n  ctx.textAlign='center'; ctx.font='800 18px \"Baloo 2\", system-ui, sans-serif';\n  pops.forEach(p=>{ ctx.globalAlpha=Math.min(1,p.life*1.5); const tw=ctx.measureText(p.text).width, px=Math.max(tw\/2+10, Math.min(W-tw\/2-10, p.x)); ctx.lineWidth=5; ctx.strokeStyle='#FBFCFF'; ctx.strokeText(p.text,px,p.y); ctx.fillStyle=p.color; ctx.fillText(p.text,px,p.y); });\n  ctx.globalAlpha=1;\n  if (state==='play'){ \/\/ load counter\n    ctx.textAlign='left'; ctx.font='800 13px \"Nunito\", system-ui, sans-serif'; ctx.fillStyle='rgba(14,26,92,.7)';\n    ctx.fillText('Canasta '+pile.length+'\/'+CAP+'  \u00b7  '+score+' puntos', 16, 26);\n    ctx.fillStyle='rgba(14,26,92,.12)'; ctx.fillRect(16,34,120,8); ctx.fillStyle= pile.length>=CAP?'#E0567A':'#6C9BEE'; ctx.fillRect(16,34,120*pile.length\/CAP,8);\n    if (pile.length>=CAP){ ctx.textAlign='center'; ctx.font='800 15px \"Baloo 2\", system-ui, sans-serif'; ctx.lineWidth=4; ctx.strokeStyle='#FBFCFF'; const ly=bluTop()-10+Math.sin(t*8)*2; ctx.strokeText('\u00a1Llena!',blu.x,ly); ctx.fillStyle='#E0567A'; ctx.fillText('\u00a1Llena!',blu.x,ly); }\n  }\n  ctx.restore();\n}\n\n\/* idle scene for the menu so the stage is never empty *\/\nfunction seedMenu(){ items=[\n  {type:'shirt',x:WASH.x*.3,y:H*.4,rot:-.3,vr:0,vy:0,ph:0,w:48,h:48},\n  {type:'sock',x:WASH.x*.75,y:H*.27,rot:.5,vr:0,vy:0,ph:0,w:48,h:48},\n  {type:'pants',x:WASH.x*.55,y:H*.55,rot:.15,vr:0,vy:0,ph:0,w:48,h:50}];\n  blu.x = WASH.x*.5; }\n\nlet last=performance.now();\nfunction loop(now){\n  const dt=Math.min(.05,(now-last)\/1000); last=now;\n  if (state==='play') update(dt);\n  else if (state==='menu') { t+=dt; items.forEach((it,i)=>{ it.y += Math.sin(t*1.6+i)*.25; it.rot += Math.sin(t+i)*.002; }); }\n  render(); requestAnimationFrame(loop);\n}\n\n\/* ---------- flow ---------- *\/\nfunction start(){ reset(); state='play'; $('startScreen').hidden=true; $('overScreen').hidden=true; $('pauseScreen').hidden=true; $('pauseBtn').disabled=false; beep(520,.08); setTimeout(()=>beep(780,.1),90); }\nfunction gameOver(){\n  state='over'; $('pauseBtn').disabled=true; shake=0; blu.hurt=0; wash.spin=0; blu.vx=0; blu.squash=0; blu.tilt=0; blu.target=null; keys={};\n  const isRecord = loads>best && loads>0; if (isRecord){ best=loads; try{localStorage.setItem('blu-best-tandas',best)}catch(e){} }\n  $('finalScore').textContent=loads; $('bestScore').textContent=best;\n  $('recordBadge').hidden = !isRecord;\n  $('overMsg').textContent = isRecord ? '\u00a1Nuevo r\u00e9cord de lavado!' : loads>=3 ? '\u00a1Qu\u00e9 buen d\u00eda de lavado!' : loads>=1 ? '\u00a1Bien, Blucito!' : '\u00a1Casi, Blucito!';\n  $('overStats').textContent = `Juntaste ${caught} prendas y sumaste ${score} puntos.`;\n  setTimeout(()=>{ $('overScreen').hidden=false; $('againBtn').focus(); }, 500);\n}\nfunction pause(){ if(state!=='play')return; state='paused'; $('pauseScreen').hidden=false; $('resumeBtn').focus(); }\nfunction resume(){ if(state!=='paused')return; state='play'; $('pauseScreen').hidden=true; last=performance.now(); }\n\nfunction setMuted(m){ muted=m; const b=$('muteBtn'); b.setAttribute('aria-pressed', m?'true':'false'); b.setAttribute('aria-label', m?'Activar sonido':'Silenciar'); try{localStorage.setItem('blu-muted', m?'1':'0')}catch(e){} }\nsetMuted(muted);\n$('muteBtn').onclick=()=>{ setMuted(!muted); if(!muted) beep(660,.08); };\n$('startBtn').onclick=start; $('againBtn').onclick=start; $('resumeBtn').onclick=resume; $('pauseBtn').onclick=pause;\naddEventListener('keydown',e=>{\n  if(['ArrowLeft','ArrowRight','a','d','A','D'].includes(e.key)){ keys[e.key]=true; e.preventDefault(); }\n  if((e.key===' '||e.key==='Enter') && (state==='menu'||state==='over') && document.activeElement.tagName!=='BUTTON'){ start(); e.preventDefault(); }\n  if(e.key==='m'||e.key==='M') setMuted(!muted);\n  if(e.key==='Escape'||e.key==='p') state==='play'?pause():resume();\n});\naddEventListener('keyup',e=>{ keys[e.key]=false; });\naddEventListener('blur',()=>{ keys={}; pause(); });\ndocument.addEventListener('visibilitychange',()=>{ if(document.hidden) pause(); });\n\nconst stage=$('stage');\nfunction pointerX(e){ const r=cv.getBoundingClientRect(); return (e.clientX-r.left)\/r.width*W; }\nlet dragging=false;\nstage.addEventListener('pointerdown',e=>{ if(e.target!==cv) return; dragging=true; blu.target=pointerX(e); try{cv.setPointerCapture(e.pointerId)}catch(_){} });\nstage.addEventListener('pointermove',e=>{ if(dragging || e.pointerType==='mouse' && state==='play') blu.target=pointerX(e); });\naddEventListener('pointerup',()=>{ dragging=false; });\n\nseedMenu(); resize(); updateHud(); requestAnimationFrame(loop);\n})();\n<\/script>\n\n<\/body>\n<\/html>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>La Canasta de Blucito La Canasta de Blucito Tandas 0 \u00bfCu\u00e1ntas tandas puedes lavar? 1Atrapa la ropa sucia 2Junta 5 prendas 3Ll\u00e9valas a lavar Cada 3 tandas lavadas: +1 vida Suma puntos \u00a1Cuidado! \u00a1A lavar con Blucito! \u00a1Bien, Blucito! Tandas lavadas0 Tu r\u00e9cord0\u00a1Nuevo! \u00a1Otra vez con Blucito! En pausa Seguir lavando Mu\u00e9vete con \u2190 \u2192 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"elementor_canvas","meta":{"footnotes":""},"class_list":["post-1271","page","type-page","status-publish","hentry"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.7 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Game - Blu<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/blu.gooseandhopper.com\/en\/game\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Game - Blu\" \/>\n<meta property=\"og:description\" content=\"La Canasta de Blucito La Canasta de Blucito Tandas 0 \u00bfCu\u00e1ntas tandas puedes lavar? 1Atrapa la ropa sucia 2Junta 5 prendas 3Ll\u00e9valas a lavar Cada 3 tandas lavadas: +1 vida Suma puntos \u00a1Cuidado! \u00a1A lavar con Blucito! \u00a1Bien, Blucito! Tandas lavadas0 Tu r\u00e9cord0\u00a1Nuevo! \u00a1Otra vez con Blucito! En pausa Seguir lavando Mu\u00e9vete con \u2190 \u2192 [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/blu.gooseandhopper.com\/en\/game\/\" \/>\n<meta property=\"og:site_name\" content=\"Blu\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/JabonBlu\" \/>\n<meta property=\"article:modified_time\" content=\"2026-10-13T18:44:18+00:00\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data1\" content=\"1 minute\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/blu.gooseandhopper.com\\\/game\\\/\",\"url\":\"https:\\\/\\\/blu.gooseandhopper.com\\\/game\\\/\",\"name\":\"Game - Blu\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/blu.gooseandhopper.com\\\/#website\"},\"datePublished\":\"2026-10-13T18:42:58+00:00\",\"dateModified\":\"2026-10-13T18:44:18+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/blu.gooseandhopper.com\\\/game\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/blu.gooseandhopper.com\\\/game\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/blu.gooseandhopper.com\\\/game\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Portada\",\"item\":\"https:\\\/\\\/blu.gooseandhopper.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Game\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/blu.gooseandhopper.com\\\/#website\",\"url\":\"https:\\\/\\\/blu.gooseandhopper.com\\\/\",\"name\":\"Blu\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/blu.gooseandhopper.com\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/blu.gooseandhopper.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/blu.gooseandhopper.com\\\/#organization\",\"name\":\"Blu\",\"url\":\"https:\\\/\\\/blu.gooseandhopper.com\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/blu.gooseandhopper.com\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/blu.gooseandhopper.com\\\/wp-content\\\/uploads\\\/2026\\\/08\\\/blu.svg\",\"contentUrl\":\"https:\\\/\\\/blu.gooseandhopper.com\\\/wp-content\\\/uploads\\\/2026\\\/08\\\/blu.svg\",\"width\":222,\"height\":127,\"caption\":\"Blu\"},\"image\":{\"@id\":\"https:\\\/\\\/blu.gooseandhopper.com\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/JabonBlu\",\"https:\\\/\\\/www.instagram.com\\\/jabonblu\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Game - Blu","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/blu.gooseandhopper.com\/en\/game\/","og_locale":"en_US","og_type":"article","og_title":"Game - Blu","og_description":"La Canasta de Blucito La Canasta de Blucito Tandas 0 \u00bfCu\u00e1ntas tandas puedes lavar? 1Atrapa la ropa sucia 2Junta 5 prendas 3Ll\u00e9valas a lavar Cada 3 tandas lavadas: +1 vida Suma puntos \u00a1Cuidado! \u00a1A lavar con Blucito! \u00a1Bien, Blucito! Tandas lavadas0 Tu r\u00e9cord0\u00a1Nuevo! \u00a1Otra vez con Blucito! En pausa Seguir lavando Mu\u00e9vete con \u2190 \u2192 [&hellip;]","og_url":"https:\/\/blu.gooseandhopper.com\/en\/game\/","og_site_name":"Blu","article_publisher":"https:\/\/www.facebook.com\/JabonBlu","article_modified_time":"2026-10-13T18:44:18+00:00","twitter_card":"summary_large_image","twitter_misc":{"Est. reading time":"1 minute"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/blu.gooseandhopper.com\/game\/","url":"https:\/\/blu.gooseandhopper.com\/game\/","name":"Game - Blu","isPartOf":{"@id":"https:\/\/blu.gooseandhopper.com\/#website"},"datePublished":"2026-10-13T18:42:58+00:00","dateModified":"2026-10-13T18:44:18+00:00","breadcrumb":{"@id":"https:\/\/blu.gooseandhopper.com\/game\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/blu.gooseandhopper.com\/game\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/blu.gooseandhopper.com\/game\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Portada","item":"https:\/\/blu.gooseandhopper.com\/"},{"@type":"ListItem","position":2,"name":"Game"}]},{"@type":"WebSite","@id":"https:\/\/blu.gooseandhopper.com\/#website","url":"https:\/\/blu.gooseandhopper.com\/","name":"Blu","description":"","publisher":{"@id":"https:\/\/blu.gooseandhopper.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/blu.gooseandhopper.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/blu.gooseandhopper.com\/#organization","name":"Blu","url":"https:\/\/blu.gooseandhopper.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/blu.gooseandhopper.com\/#\/schema\/logo\/image\/","url":"https:\/\/blu.gooseandhopper.com\/wp-content\/uploads\/2026\/08\/blu.svg","contentUrl":"https:\/\/blu.gooseandhopper.com\/wp-content\/uploads\/2026\/08\/blu.svg","width":222,"height":127,"caption":"Blu"},"image":{"@id":"https:\/\/blu.gooseandhopper.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/JabonBlu","https:\/\/www.instagram.com\/jabonblu"]}]}},"_links":{"self":[{"href":"https:\/\/blu.gooseandhopper.com\/en\/wp-json\/wp\/v2\/pages\/1271","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blu.gooseandhopper.com\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/blu.gooseandhopper.com\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/blu.gooseandhopper.com\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blu.gooseandhopper.com\/en\/wp-json\/wp\/v2\/comments?post=1271"}],"version-history":[{"count":4,"href":"https:\/\/blu.gooseandhopper.com\/en\/wp-json\/wp\/v2\/pages\/1271\/revisions"}],"predecessor-version":[{"id":1276,"href":"https:\/\/blu.gooseandhopper.com\/en\/wp-json\/wp\/v2\/pages\/1271\/revisions\/1276"}],"wp:attachment":[{"href":"https:\/\/blu.gooseandhopper.com\/en\/wp-json\/wp\/v2\/media?parent=1271"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}