{"id":23610,"date":"2026-01-19T11:14:37","date_gmt":"2026-01-19T04:14:37","guid":{"rendered":"https:\/\/survivalskills.vn\/?page_id=23610"},"modified":"2026-01-27T10:33:07","modified_gmt":"2026-01-27T03:33:07","slug":"cpr-rhythm-simulation-game","status":"publish","type":"page","link":"https:\/\/survivalskills.vn\/en\/cpr-rhythm-simulation-game\/","title":{"rendered":"CPR Rhythm Simulation Game"},"content":{"rendered":"\n\n<div class=\"kk-star-ratings kksr-auto kksr-align-center kksr-valign-top\"\n    data-payload='{&quot;align&quot;:&quot;center&quot;,&quot;id&quot;:&quot;23610&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;top&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;0&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;0&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;5&quot;,&quot;greet&quot;:&quot;B\u00ecnh ch\u1ecdn b\u00e0i vi\u1ebft n\u00e0y | Rate this page&quot;,&quot;legend&quot;:&quot;0\\\/5 - (0 votes)&quot;,&quot;size&quot;:&quot;24&quot;,&quot;title&quot;:&quot;CPR Rhythm Simulation Game&quot;,&quot;width&quot;:&quot;0&quot;,&quot;_legend&quot;:&quot;{score}\\\/{best} - ({count} {votes})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>\n            \n<div class=\"kksr-stars\">\n    \n<div class=\"kksr-stars-inactive\">\n            <div class=\"kksr-star\" data-star=\"1\" style=\"padding-right: 5px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"2\" style=\"padding-right: 5px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"3\" style=\"padding-right: 5px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"4\" style=\"padding-right: 5px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"5\" style=\"padding-right: 5px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n    <\/div>\n    \n<div class=\"kksr-stars-active\" style=\"width: 0px;\">\n            <div class=\"kksr-star\" style=\"padding-right: 5px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 5px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 5px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 5px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 5px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 24px; height: 24px;\"><\/div>\n        <\/div>\n    <\/div>\n<\/div>\n                \n\n<div class=\"kksr-legend\" style=\"font-size: 19.2px;\">\n            <span class=\"kksr-muted\">B\u00ecnh ch\u1ecdn b\u00e0i vi\u1ebft n\u00e0y | Rate this page<\/span>\n    <\/div>\n    <\/div>\n\n<style>\n.cpr-game {\n    text-align: center;\n    padding: 20px;\n    background: #f0f0f0;\n}\n\n.cpr-scene {\n    max-width: 600px;\n    margin: 0 auto;\n    padding: 20px;\n    background: white;\n    border-radius: 10px;\n    box-shadow: 0 0 10px rgba(0,0,0,0.1);\n}\n\n.cpr-game-image {\n    max-width: 100%;\n    height: auto;\n    border-radius: 10px;\n}\n\n.cpr-circle-button {\n    position: absolute;\n    top: 70%;\n    left: 50%;\n    transform: translate(-50%, -50%);\n    width: 80px;\n    height: 80px;\n    border-radius: 50%;\n    background: transparent;\n    border: none;\n    cursor: pointer;\n}\n\n.cpr-bpm-label {\n    margin: 20px auto;\n    font-size: 24px;\n    font-weight: bold;\n}\n\n.cpr-bpm-value {\n    font-size: 32px;\n}\n<\/style>\n\n<div class=\"cpr-game\">\n    <div id=\"cpr-gameplay\" class=\"cpr-scene\">\n\n        <h1>CPR Rhythm Game<\/h1>\n\n        <p>Listen to the playlist on Spotify (optional):<\/p>\n        <iframe\n            style=\"border-radius:12px\"\n            src=\"https:\/\/open.spotify.com\/embed\/playlist\/5ADlKRNIRXr4LroBNhV2Pl?utm_source=generator\"\n            width=\"100%\"\n            height=\"352\"\n            loading=\"lazy\">\n        <\/iframe>\n\n        <div style=\"margin:10px 0;\">\n            <label>\n                <input type=\"radio\" name=\"cpr-dummy\" value=\"male\" checked>\n                Male Dummy\n            <\/label>\n            <label>\n                <input type=\"radio\" name=\"cpr-dummy\" value=\"female\">\n                Female Dummy\n            <\/label>\n        <\/div>\n\n        <div class=\"cpr-bpm-label\">\n            <span id=\"cpr-bpm-value\" class=\"cpr-bpm-value\">&#8212;<\/span> BPM\n        <\/div>\n\n        <div style=\"position:relative; display:inline-block; margin-top:20px;\">\n            <img decoding=\"async\"\n                id=\"cpr-game-image\"\n                class=\"cpr-game-image\"\n                src=\"https:\/\/survivalskills.vn\/wp-content\/uploads\/2026\/01\/maledummy.png\"\n                alt=\"CPR Dummy\">\n            <button\n                id=\"cpr-gameplay-button\"\n                class=\"cpr-circle-button\">\n            <\/button>\n        <\/div>\n\n    <\/div>\n<\/div>\n\n<script>\n(function () {\n\n    const ASSETS = {\n        male: 'https:\/\/survivalskills.vn\/wp-content\/uploads\/2026\/01\/maledummy.png',\n        female: 'https:\/\/survivalskills.vn\/wp-content\/uploads\/2026\/01\/femaledummy.png'\n    };\n\n    \/\/ Preload images\n    Object.values(ASSETS).forEach(src => {\n        const img = new Image();\n        img.src = src;\n    });\n\n    const gameplayButton = document.getElementById('cpr-gameplay-button');\n    const gameImage = document.getElementById('cpr-game-image');\n    const bpmValue = document.getElementById('cpr-bpm-value');\n    const radios = document.querySelectorAll('input[name=\"cpr-dummy\"]');\n    const container = document.getElementById('cpr-gameplay');\n\n    const feedback = document.createElement('p');\n    feedback.style.fontSize = '1.2em';\n    feedback.style.marginTop = '8px';\n    bpmValue.parentElement.appendChild(feedback);\n\n    let audioContext = null;\n    let running = false;\n    let clicks = [];\n    let bpmInterval = null;\n    let displayedBPM = 0;\n\n    const BUTTON_RADIUS = 40;\n\n    function initAudio() {\n        if (!audioContext) {\n            audioContext = new (window.AudioContext || window.webkitAudioContext)();\n        }\n    }\n\n    function beep() {\n        if (!audioContext) return;\n\n        const osc = audioContext.createOscillator();\n        const gain = audioContext.createGain();\n\n        osc.frequency.value = 800;\n        gain.gain.value = 0.1;\n\n        osc.connect(gain);\n        gain.connect(audioContext.destination);\n\n        osc.start();\n        osc.stop(audioContext.currentTime + 0.08);\n    }\n\n    radios.forEach(radio => {\n        radio.addEventListener('change', () => {\n            gameImage.src = ASSETS[radio.value];\n            gameplayButton.style.top = radio.value === 'male' ? '70%' : '67%';\n        });\n    });\n\n    container.addEventListener('click', event => {\n\n        if (!running) {\n            initAudio();\n            running = true;\n            clicks = [];\n            displayedBPM = 0;\n            bpmValue.textContent = '--';\n            feedback.textContent = '';\n            startBPM();\n            return;\n        }\n\n        const rect = gameplayButton.getBoundingClientRect();\n        const cx = rect.left + rect.width \/ 2;\n        const cy = rect.top + rect.height \/ 2;\n        const dist = Math.hypot(event.clientX - cx, event.clientY - cy);\n\n        if (dist <= BUTTON_RADIUS) {\n            beep();\n            clicks.push(Date.now());\n\n            gameplayButton.style.background = 'rgba(76,175,80,0.5)';\n            gameplayButton.style.border = '2px solid #4caf50';\n            setTimeout(() => {\n                gameplayButton.style.background = 'transparent';\n                gameplayButton.style.border = 'none';\n            }, 200);\n        } else {\n            gameImage.style.border = '2px solid #ff5252';\n            setTimeout(() => gameImage.style.border = 'none', 300);\n        }\n    });\n\n    function updateBPM() {\n        const now = Date.now();\n        clicks = clicks.filter(t => now - t < 10000);\n\n        let targetBPM = 0;\n        if (clicks.length > 1) {\n            const intervals = clicks.slice(1).map((t, i) => t - clicks[i]);\n            targetBPM = Math.round(60000 \/ (intervals.reduce((a, b) => a + b) \/ intervals.length));\n        }\n\n        displayedBPM += (targetBPM - displayedBPM) * 0.25;\n\n        if (displayedBPM < 1) {\n            bpmValue.textContent = '--';\n            bpmValue.style.color = '#ff5252';\n            feedback.textContent = 'No Pulse Detected';\n            feedback.style.color = '#ff5252';\n            return;\n        }\n\n        const bpm = Math.round(displayedBPM);\n        bpmValue.textContent = bpm;\n\n        if (bpm < 100) {\n            bpmValue.style.color = '#ff5252';\n            feedback.textContent = 'Too Slow';\n            feedback.style.color = '#ff5252';\n        } else if (bpm > 120) {\n            bpmValue.style.color = '#ff5252';\n            feedback.textContent = 'Too Fast';\n            feedback.style.color = '#ff5252';\n        } else {\n            bpmValue.style.color = '#4caf50';\n            feedback.textContent = 'Good Pace';\n            feedback.style.color = '#4caf50';\n        }\n    }\n\n    function startBPM() {\n        clearInterval(bpmInterval);\n        bpmInterval = setInterval(updateBPM, 50);\n    }\n\n})();\n<\/script>\n","protected":false},"excerpt":{"rendered":"<p>CPR Rhythm Game Listen to the playlist on Spotify (optional): Male Dummy Female Dummy &#8212; BPM<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_mbp_gutenberg_autopost":false,"footnotes":""},"class_list":["post-23610","page","type-page","status-publish","hentry"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/survivalskills.vn\/en\/wp-json\/wp\/v2\/pages\/23610","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/survivalskills.vn\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/survivalskills.vn\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/survivalskills.vn\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/survivalskills.vn\/en\/wp-json\/wp\/v2\/comments?post=23610"}],"version-history":[{"count":3,"href":"https:\/\/survivalskills.vn\/en\/wp-json\/wp\/v2\/pages\/23610\/revisions"}],"predecessor-version":[{"id":23630,"href":"https:\/\/survivalskills.vn\/en\/wp-json\/wp\/v2\/pages\/23610\/revisions\/23630"}],"wp:attachment":[{"href":"https:\/\/survivalskills.vn\/en\/wp-json\/wp\/v2\/media?parent=23610"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}