{"id":617,"date":"2026-10-02T07:38:55","date_gmt":"2026-10-02T07:38:55","guid":{"rendered":"https:\/\/mrcottle.co.uk\/WP\/?page_id=617"},"modified":"2026-10-02T10:18:41","modified_gmt":"2026-10-02T10:18:41","slug":"touchtype","status":"publish","type":"page","link":"https:\/\/mrcottle.co.uk\/WP\/touchtype\/","title":{"rendered":"TouchType"},"content":{"rendered":"<p><!DOCTYPE html><br \/>\n<html lang=\"en\"><br \/>\n<head><br \/>\n<meta charset=\"UTF-8\"><br \/>\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><\/p>\n<p><title>TypeQuest &#8211; Year 7 Typing<\/title><\/p>\n<style>\n* {\n    box-sizing: border-box;\n    margin: 0;\n    padding: 0;\n}<\/p>\n<p>:root {\n    --purple: #6c5ce7;\n    --dark-purple: #4834d4;\n    --blue: #0984e3;\n    --green: #00b894;\n    --yellow: #fdcb6e;\n    --red: #e17055;\n    --dark: #2d3436;\n    --light: #f5f6fa;\n}<\/p>\n<p>body {\n    font-family: \"Trebuchet MS\", Arial, sans-serif;\n    background: linear-gradient(135deg, #6c5ce7, #0984e3);\n    min-height: 100vh;\n    color: var(--dark);\n}<\/p>\n<p>\/* =========================================\n   HEADER\n========================================= *\/<\/p>\n<p>header {\n    background: white;\n    padding: 16px 5%;\n    display: flex;\n    justify-content: space-between;\n    align-items: center;\n    box-shadow: 0 3px 15px #0002;\n    position: sticky;\n    top: 0;\n    z-index: 10;\n}<\/p>\n<p>.logo {\n    font-size: 1.7rem;\n    font-weight: bold;\n    color: var(--purple);\n}<\/p>\n<p>.logo span {\n    color: var(--blue);\n}<\/p>\n<p>.student-badge {\n    background: #eeeaff;\n    color: var(--purple);\n    padding: 8px 15px;\n    border-radius: 20px;\n    font-weight: bold;\n}<\/p>\n<p>\/* =========================================\n   MAIN\n========================================= *\/<\/p>\n<p>main {\n    width: 92%;\n    max-width: 1100px;\n    margin: 30px auto;\n}<\/p>\n<p>\/* =========================================\n   HERO\n========================================= *\/<\/p>\n<p>.hero {\n    color: white;\n    text-align: center;\n    padding: 25px 10px 35px;\n}<\/p>\n<p>.hero h1 {\n    font-size: clamp(2rem, 5vw, 3.5rem);\n    margin-bottom: 8px;\n}<\/p>\n<p>.hero p {\n    font-size: 1.15rem;\n}<\/p>\n<p>\/* =========================================\n   CARDS\n========================================= *\/<\/p>\n<p>.card {\n    background: white;\n    border-radius: 22px;\n    padding: 25px;\n    margin-bottom: 25px;\n    box-shadow: 0 10px 30px #0002;\n}<\/p>\n<p>.card h2 {\n    color: var(--purple);\n    margin-bottom: 15px;\n}<\/p>\n<p>\/* =========================================\n   TOPIC SELECTOR\n========================================= *\/<\/p>\n<p>.selector-grid {\n    display: grid;\n    grid-template-columns: 1fr 1fr;\n    gap: 18px;\n}<\/p>\n<p>.selector label {\n    display: block;\n    font-weight: bold;\n    color: var(--purple);\n    margin-bottom: 7px;\n}<\/p>\n<p>select {\n    width: 100%;\n    padding: 13px 15px;\n    border: 2px solid #dfe6e9;\n    border-radius: 12px;\n    font-family: inherit;\n    font-size: 1rem;\n    background: white;\n    color: var(--dark);\n    cursor: pointer;\n    outline: none;\n}<\/p>\n<p>select:focus {\n    border-color: var(--purple);\n    box-shadow: 0 0 0 4px #eeeaff;\n}<\/p>\n<p>.topic-description {\n    margin-top: 15px;\n    background: #f5f3ff;\n    padding: 13px 16px;\n    border-radius: 12px;\n    color: #555;\n}<\/p>\n<p>\/* =========================================\n   MODE BUTTONS\n========================================= *\/<\/p>\n<p>.lesson-buttons {\n    display: flex;\n    flex-wrap: wrap;\n    gap: 10px;\n    margin-top: 18px;\n}<\/p>\n<p>button {\n    border: 0;\n    cursor: pointer;\n    font-family: inherit;\n    font-weight: bold;\n    transition: .2s;\n}<\/p>\n<p>.lesson-btn {\n    background: #eeeaff;\n    color: var(--purple);\n    padding: 12px 18px;\n    border-radius: 12px;\n    font-size: 1rem;\n}<\/p>\n<p>.lesson-btn:hover,\n.lesson-btn.active {\n    background: var(--purple);\n    color: white;\n    transform: translateY(-2px);\n}<\/p>\n<p>\/* =========================================\n   TYPING AREA\n========================================= *\/<\/p>\n<p>.typing-area {\n    text-align: center;\n}<\/p>\n<p>.level-title {\n    color: var(--purple);\n    font-size: 1.5rem;\n    margin-bottom: 8px;\n}<\/p>\n<p>.instruction {\n    color: #636e72;\n    margin-bottom: 20px;\n}<\/p>\n<p>\/* =========================================\n   TIMER\n========================================= *\/<\/p>\n<p>.timer {\n    width: 120px;\n    height: 120px;\n    margin: 15px auto 20px;\n    border-radius: 50%;\n    background: linear-gradient(135deg, var(--purple), var(--blue));\n    color: white;\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n    align-items: center;\n    box-shadow: 0 8px 25px #6c5ce766;\n}<\/p>\n<p>.timer .time {\n    font-size: 2.2rem;\n    font-weight: bold;\n}<\/p>\n<p>\/* =========================================\n   LIVE TYPING AREA\n========================================= *\/<\/p>\n<p>.typing-layout {\n    display: grid;\n    grid-template-columns: 1fr 180px;\n    gap: 20px;\n    align-items: stretch;\n}<\/p>\n<p>\/* =========================================\n   LIVE STATS PANEL\n========================================= *\/<\/p>\n<p>.live-stats {\n    display: flex;\n    flex-direction: column;\n    gap: 15px;\n}<\/p>\n<p>.live-stat {\n    background: #f5f3ff;\n    border: 2px solid #eeeaff;\n    border-radius: 18px;\n    padding: 20px 12px;\n    text-align: center;\n    min-height: 115px;\n    display: flex;\n    flex-direction: column;\n    justify-content: center;\n}<\/p>\n<p>.live-stat .stat-icon {\n    font-size: 1.5rem;\n    margin-bottom: 4px;\n}<\/p>\n<p>.live-stat .number {\n    font-size: 2rem;\n    font-weight: bold;\n    color: var(--purple);\n    line-height: 1.1;\n}<\/p>\n<p>.live-stat .label {\n    color: #636e72;\n    font-size: .85rem;\n    margin-top: 5px;\n}<\/p>\n<p>.live-stat.accuracy-stat .number {\n    color: var(--green);\n}<\/p>\n<p>.live-stat.best-stat .number {\n    color: #e1a600;\n}<\/p>\n<p>\/* =========================================\n   TYPING TEXT\n========================================= *\/<\/p>\n<p>.sentence {\n    background: #f1f2f6;\n    border: 3px solid #dfe6e9;\n    border-radius: 15px;\n    padding: 25px;\n    font-size: clamp(1.1rem, 2.5vw, 1.5rem);\n    line-height: 1.8;\n    margin-bottom: 18px;\n    text-align: left;\n    min-height: 100px;\n    word-wrap: break-word;\n}<\/p>\n<p>.sentence .correct {\n    color: var(--green);\n}<\/p>\n<p>.sentence .incorrect {\n    color: white;\n    background: var(--red);\n    border-radius: 4px;\n}<\/p>\n<p>.sentence .current {\n    background: var(--yellow);\n    border-radius: 4px;\n    padding: 2px;\n}<\/p>\n<p>\/* =========================================\n   INPUT\n========================================= *\/<\/p>\n<p>#typingInput {\n    width: 100%;\n    min-height: 130px;\n    border: 3px solid #dfe6e9;\n    border-radius: 15px;\n    padding: 18px;\n    font-family: inherit;\n    font-size: 1.2rem;\n    resize: vertical;\n    outline: none;\n}<\/p>\n<p>#typingInput:focus {\n    border-color: var(--purple);\n    box-shadow: 0 0 0 4px #eeeaff;\n}<\/p>\n<p>#typingInput:disabled {\n    background: #f1f2f6;\n}<\/p>\n<p>\/* =========================================\n   PROGRESS\n========================================= *\/<\/p>\n<p>.progress-container {\n    background: #dfe6e9;\n    height: 15px;\n    border-radius: 20px;\n    overflow: hidden;\n    margin: 15px 0 20px;\n}<\/p>\n<p>.progress-bar {\n    height: 100%;\n    width: 0;\n    background: linear-gradient(90deg, var(--green), #55efc4);\n    border-radius: 20px;\n    transition: .2s;\n}<\/p>\n<p>\/* =========================================\n   CONTROLS\n========================================= *\/<\/p>\n<p>.controls {\n    display: flex;\n    justify-content: center;\n    gap: 12px;\n    flex-wrap: wrap;\n}<\/p>\n<p>.primary-btn {\n    background: var(--purple);\n    color: white;\n    padding: 13px 25px;\n    border-radius: 12px;\n    font-size: 1rem;\n}<\/p>\n<p>.primary-btn:hover {\n    background: var(--dark-purple);\n}<\/p>\n<p>.secondary-btn {\n    background: #dfe6e9;\n    color: var(--dark);\n    padding: 13px 25px;\n    border-radius: 12px;\n    font-size: 1rem;\n}<\/p>\n<p>\/* =========================================\n   RESULT\n========================================= *\/<\/p>\n<p>.result {\n    display: none;\n    text-align: center;\n    background: linear-gradient(135deg, #00b894, #55efc4);\n    color: white;\n    border-radius: 18px;\n    padding: 25px;\n    margin-top: 20px;\n}<\/p>\n<p>.result.show {\n    display: block;\n    animation: pop .4s ease;\n}<\/p>\n<p>.result h2 {\n    margin-bottom: 10px;\n}<\/p>\n<p>.result-score {\n    font-size: 3rem;\n    font-weight: bold;\n}<\/p>\n<p>@keyframes pop {\n    from {\n        transform: scale(.8);\n        opacity: 0;\n    }<\/p>\n<p>    to {\n        transform: scale(1);\n        opacity: 1;\n    }\n}<\/p>\n<p>\/* =========================================\n   KEYBOARD\n========================================= *\/<\/p>\n<p>.keyboard {\n    max-width: 850px;\n    margin: auto;\n    background: #2d3436;\n    padding: 15px;\n    border-radius: 15px;\n    overflow-x: auto;\n}<\/p>\n<p>.key-row {\n    display: flex;\n    justify-content: center;\n    gap: 5px;\n    margin-bottom: 5px;\n    min-width: 550px;\n}<\/p>\n<p>.key {\n    width: 48px;\n    height: 45px;\n    background: #636e72;\n    color: white;\n    border-radius: 6px;\n    display: flex;\n    justify-content: center;\n    align-items: center;\n    font-weight: bold;\n    box-shadow: 0 3px 0 #444;\n    transition: .1s;\n}<\/p>\n<p>.key.left-hand {\n    background: #0984e3;\n}<\/p>\n<p>.key.right-hand {\n    background: #6c5ce7;\n}<\/p>\n<p>.key.highlight {\n    background: var(--yellow);\n    color: var(--dark);\n    transform: translateY(3px);\n    box-shadow: none;\n}<\/p>\n<p>.key.wide {\n    width: 75px;\n}<\/p>\n<p>.key.extra-wide {\n    width: 110px;\n}<\/p>\n<p>.key.space {\n    width: 300px;\n}<\/p>\n<p>\/* =========================================\n   FINGER GUIDE\n========================================= *\/<\/p>\n<p>.finger-guide {\n    display: grid;\n    grid-template-columns: 1fr 1fr;\n    gap: 15px;\n    margin-top: 20px;\n}<\/p>\n<p>.hand {\n    padding: 18px;\n    border-radius: 15px;\n    color: white;\n}<\/p>\n<p>.left {\n    background: linear-gradient(135deg, #0984e3, #74b9ff);\n}<\/p>\n<p>.right {\n    background: linear-gradient(135deg, #6c5ce7, #a29bfe);\n}<\/p>\n<p>.hand h3 {\n    margin-bottom: 8px;\n}<\/p>\n<p>\/* =========================================\n   TIP\n========================================= *\/<\/p>\n<p>.tip {\n    background: #fff8df;\n    border-left: 5px solid var(--yellow);\n    padding: 15px;\n    border-radius: 8px;\n    margin-top: 20px;\n}<\/p>\n<p>.tip strong {\n    color: #d68910;\n}<\/p>\n<p>\/* =========================================\n   RESPONSIVE\n========================================= *\/<\/p>\n<p>@media (max-width: 800px) {<\/p>\n<p>    .typing-layout {\n        grid-template-columns: 1fr;\n    }<\/p>\n<p>    .live-stats {\n        display: grid;\n        grid-template-columns: repeat(3, 1fr);\n        order: -1;\n    }<\/p>\n<p>    .live-stat {\n        min-height: 95px;\n        padding: 12px 5px;\n    }<\/p>\n<p>    .live-stat .number {\n        font-size: 1.7rem;\n    }<\/p>\n<p>    .live-stat .stat-icon {\n        font-size: 1.2rem;\n    }\n}<\/p>\n<p>@media (max-width: 750px) {<\/p>\n<p>    .selector-grid {\n        grid-template-columns: 1fr;\n    }<\/p>\n<p>    .finger-guide {\n        grid-template-columns: 1fr;\n    }<\/p>\n<p>    .key {\n        width: 30px;\n        height: 35px;\n        font-size: .65rem;\n    }<\/p>\n<p>    .key.wide {\n        width: 45px;\n    }<\/p>\n<p>    .key.extra-wide {\n        width: 60px;\n    }<\/p>\n<p>    .key.space {\n        width: 130px;\n    }\n}<\/p>\n<p>@media (max-width: 500px) {<\/p>\n<p>    .live-stats {\n        grid-template-columns: repeat(3, 1fr);\n        gap: 7px;\n    }<\/p>\n<p>    .live-stat {\n        border-radius: 12px;\n    }<\/p>\n<p>    .live-stat .number {\n        font-size: 1.4rem;\n    }<\/p>\n<p>    .live-stat .label {\n        font-size: .7rem;\n    }<\/p>\n<p>    .stats {\n        grid-template-columns: 1fr;\n    }<\/p>\n<p>    header {\n        padding: 12px 4%;\n    }<\/p>\n<p>    .logo {\n        font-size: 1.3rem;\n    }<\/p>\n<p>    .student-badge {\n        font-size: .75rem;\n        padding: 6px 10px;\n    }\n}\n<\/style>\n<p><\/head><\/p>\n<p><body><\/p>\n<header>\n<div class=\"logo\">\n        Touch<span>Typing Quest<\/span>\n    <\/div>\n<div class=\"student-badge\">\n        KS3 Computing\n    <\/div>\n<\/header>\n<p><main><\/p>\n<p>    <!-- HERO --><\/p>\n<section class=\"hero\">\n<p>            Improve your typing while learning English and Computer Science!<\/p>\n<\/section>\n<p>    <!-- TOPIC SELECTOR --><\/p>\n<section class=\"card\">\n<h2>\n            Choose Your Topic<br \/>\n        <\/h2>\n<div class=\"selector-grid\">\n<div class=\"selector\">\n<p>                <label for=\"topicSelect\"><br \/>\n                    Topic<br \/>\n                <\/label><\/p>\n<p>                <select\n                    id=\"topicSelect\"\n                    onchange=\"changeTopic()\"\n                ><option value=\"all\"><br \/>\n                        All Topics<br \/>\n                    <\/option><option value=\"english\"><br \/>\n                        General English<br \/>\n                    <\/option><option value=\"programming\"><br \/>\n                        Programming<br \/>\n                    <\/option><option value=\"algorithms\"><br \/>\n                       Data &#038; Algorithms<br \/>\n                    <\/option><option value=\"networks\"><br \/>\n                        Networks &#038; Internet<br \/>\n                    <\/option><option value=\"cybersecurity\"><br \/>\n                        Cybersecurity<br \/>\n                    <\/option><option value=\"hardware\"><br \/>\n                        Hardware &#038; Software<br \/>\n                    <\/option><option value=\"databases\"><br \/>\n                        Databases<br \/>\n                    <\/option><option value=\"web\"><br \/>\n                        Web Development<br \/>\n                    <\/option><option value=\"emerging\"><br \/>\n                        Emerging Technology<br \/>\n                    <\/option><\/select><\/p><\/div>\n<div class=\"selector\">\n<p>                <label for=\"difficultySelect\"><br \/>\n                    Difficulty<br \/>\n                <\/label><\/p>\n<p>                <select id=\"difficultySelect\"><option value=\"all\"><br \/>\n                        All Levels<br \/>\n                    <\/option><option value=\"easy\"><br \/>\n                        Developing<br \/>\n                    <\/option><option value=\"medium\"><br \/>\n                        Reaching\/Mastering<br \/>\n                    <\/option><option value=\"hard\"><br \/>\n                        Challenge<br \/>\n                    <\/option><\/select><\/p><\/div>\n<\/p><\/div>\n<div\n            class=\"topic-description\"\n            id=\"topicDescription\"\n        ><br \/>\n            Practise vocabulary from all Year 7 English and Computer Science topics.\n        <\/div>\n<div class=\"lesson-buttons\">\n<p>            <button\n                class=\"lesson-btn active\"\n                onclick=\"chooseMode('words', this)\"\n            ><br \/>\n                Keywords<br \/>\n            <\/button><\/p>\n<p>            <button\n                class=\"lesson-btn\"\n                onclick=\"chooseMode('sentences', this)\"\n            ><br \/>\n                Sentences<br \/>\n            <\/button><\/p>\n<p>            <button\n                class=\"lesson-btn\"\n                onclick=\"chooseMode('mixed', this)\"\n            ><br \/>\n                Mixed Challenge<br \/>\n            <\/button><\/p><\/div>\n<\/section>\n<p>    <!-- TYPING AREA --><\/p>\n<section class=\"card typing-area\">\n<div\n            class=\"level-title\"\n            id=\"levelTitle\"\n        ><br \/>\n            Computing Keywords\n        <\/div>\n<p\n            class=\"instruction\"\n            id=\"instruction\"\n        ><br \/>\n            Type the words shown below. Accuracy comes first!\n        <\/p>\n<p>        <!-- TIMER --><\/p>\n<div class=\"timer\">\n<div\n                class=\"time\"\n                id=\"timer\"\n            ><br \/>\n                60\n            <\/div>\n<p>            <small><br \/>\n                SECONDS<br \/>\n            <\/small><\/p><\/div>\n<p>        <!-- TYPING + LIVE STATS --><\/p>\n<div class=\"typing-layout\">\n<p>            <!-- MAIN TYPING COLUMN --><\/p>\n<div>\n<div\n                    class=\"sentence\"\n                    id=\"sentence\"\n                ><\/div>\n<p>                <textarea\n                    id=\"typingInput\"\n                    placeholder=\"Click here and start typing...\"\n                    disabled\n                    spellcheck=\"false\"\n                    autocomplete=\"off\"\n                    autocorrect=\"off\"\n                    autocapitalize=\"off\"\n                ><\/textarea><\/p>\n<div class=\"progress-container\">\n<div\n                        class=\"progress-bar\"\n                        id=\"progress\"\n                    ><\/div>\n<\/p><\/div>\n<div class=\"controls\">\n<p>                    <button\n                        class=\"primary-btn\"\n                        id=\"startBtn\"\n                        onclick=\"startTest()\"\n                    ><br \/>\n                        Start Typing<br \/>\n                    <\/button><\/p>\n<p>                    <button\n                        class=\"secondary-btn\"\n                        onclick=\"resetTest()\"\n                    ><br \/>\n                        \u21bb Reset<br \/>\n                    <\/button><\/p><\/div>\n<\/p><\/div>\n<p>            <!-- LIVE STATS --><\/p>\n<aside class=\"live-stats\">\n<div class=\"live-stat\">\n<div class=\"stat-icon\"><\/div>\n<div\n                        class=\"number\"\n                        id=\"liveWpm\"\n                    ><br \/>\n                        0\n                    <\/div>\n<div class=\"label\">\n                        WPM\n                    <\/div>\n<\/p><\/div>\n<div class=\"live-stat accuracy-stat\">\n<div class=\"stat-icon\"><\/div>\n<div\n                        class=\"number\"\n                        id=\"liveAccuracy\"\n                    ><br \/>\n                        100%\n                    <\/div>\n<div class=\"label\">\n                        Accuracy\n                    <\/div>\n<\/p><\/div>\n<div class=\"live-stat best-stat\">\n<div\n                        class=\"number\"\n                        id=\"liveBest\"\n                    ><br \/>\n                        0\n                    <\/div>\n<div class=\"label\">\n                        Best WPM\n                    <\/div>\n<\/p><\/div>\n<\/aside><\/div>\n<p>        <!-- RESULT --><\/p>\n<div\n            class=\"result\"\n            id=\"result\"\n        ><\/p>\n<h2>\n                Typing Complete!<br \/>\n            <\/h2>\n<div\n                class=\"result-score\"\n                id=\"resultWpm\"\n            ><br \/>\n                0 WPM\n            <\/div>\n<p id=\"resultAccuracy\">\n                Accuracy: 0%\n            <\/p>\n<p id=\"resultMessage\">\n                Keep practising!\n            <\/p>\n<\/p><\/div>\n<\/section>\n<p>    <!-- KEYBOARD --><\/p>\n<section class=\"card\">\n<h2>\n            Your Keyboard<br \/>\n        <\/h2>\n<p class=\"instruction\">\n            Keep your hands in the correct position and try not to look down.\n        <\/p>\n<div class=\"keyboard\">\n<div class=\"key-row\">\n<div class=\"key left-hand\">Q<\/div>\n<div class=\"key left-hand\">W<\/div>\n<div class=\"key left-hand\">E<\/div>\n<div class=\"key left-hand\">R<\/div>\n<div class=\"key left-hand\">T<\/div>\n<div class=\"key right-hand\">Y<\/div>\n<div class=\"key right-hand\">U<\/div>\n<div class=\"key right-hand\">I<\/div>\n<div class=\"key right-hand\">O<\/div>\n<div class=\"key right-hand\">P<\/div>\n<\/p><\/div>\n<div class=\"key-row\">\n<div class=\"key wide left-hand\">A<\/div>\n<div class=\"key left-hand\">S<\/div>\n<div class=\"key left-hand\">D<\/div>\n<div class=\"key left-hand\">F<\/div>\n<div class=\"key left-hand\">G<\/div>\n<div class=\"key right-hand\">H<\/div>\n<div class=\"key right-hand\">J<\/div>\n<div class=\"key right-hand\">K<\/div>\n<div class=\"key right-hand\">L<\/div>\n<div class=\"key wide right-hand\">;<\/div>\n<\/p><\/div>\n<div class=\"key-row\">\n<div class=\"key extra-wide left-hand\">\n                    SHIFT\n                <\/div>\n<div class=\"key left-hand\">Z<\/div>\n<div class=\"key left-hand\">X<\/div>\n<div class=\"key left-hand\">C<\/div>\n<div class=\"key left-hand\">V<\/div>\n<div class=\"key right-hand\">B<\/div>\n<div class=\"key right-hand\">N<\/div>\n<div class=\"key right-hand\">M<\/div>\n<div class=\"key extra-wide right-hand\">\n                    SHIFT\n                <\/div>\n<\/p><\/div>\n<div class=\"key-row\">\n<div class=\"key space\">\n                    SPACE\n                <\/div>\n<\/p><\/div>\n<\/p><\/div>\n<div class=\"finger-guide\">\n<div class=\"hand left\">\n<h3>\n                    Left Hand<br \/>\n                <\/h3>\n<p>\n                    Pinky \u2192 A, Q, Z<br \/>\n                    Ring \u2192 S, W, X<br \/>\n                    Middle \u2192 D, E, C<br \/>\n                    Index \u2192 F, G, R, T, V, B\n                <\/p>\n<\/p><\/div>\n<div class=\"hand right\">\n<h3>\n                    Right Hand<br \/>\n                <\/h3>\n<p>\n                    Index \u2192 J, H, Y, U, N, M<br \/>\n                    Middle \u2192 K, I<br \/>\n                    Ring \u2192 L, O<br \/>\n                    Pinky \u2192 ;, P\n                <\/p>\n<\/p><\/div>\n<\/p><\/div>\n<div class=\"tip\">\n<p>            <strong><br \/>\n                Top Tip:<br \/>\n            <\/strong><\/p>\n<p>            Keep your fingers lightly resting on F and J.<br \/>\n            These keys have little bumps that help you find<br \/>\n            your position without looking.<\/p><\/div>\n<\/section>\n<p><\/main><\/p>\n<p><script><\/p>\n<p>\/* =====================================================\n   TOPIC WORD BANKS\n===================================================== *\/<\/p>\n<p>const topics = {<\/p>\n<p>    english: {<\/p>\n<p>        name: \"General English\",<\/p>\n<p>        description:\n            \"Common English vocabulary designed for Year 7 students.\",<\/p>\n<p>        words: `\n        about above across after again against along\n        always another answer around away because before\n        began begin behind being below between both\n        brought build built called came change children\n        city class close cold country course different\n        early earth enough every example family father\n        feel few find first follow food found four\n        friend from front full game gave give good\n        great group grow hand happen hard head heard\n        help high home house however important inside\n        instead large last later learn leave left life\n        light little live long look made make many\n        matter might morning mother move much must\n        name near never new next night number often\n        once only open order other outside over place\n        point right room school second seem small\n        something sometimes sound start state still story\n        such take talk tell than their them then there\n        these thing think those three through time together\n        took toward town tree under until use used\n        usually very want water way week while whole\n        without world would write year young<\/p>\n<p>        apple animal beach book brother bus chair\n        classroom clothes computer day door drink\n        family football garden girl group happy\n        holiday idea island jacket kitchen letter\n        lunch market music paper parent pencil\n        person picture playground question river\n        road science sister sport teacher team\n        telephone television test window work<\/p>\n<p>        afternoon birthday breakfast conversation\n        subject adventure beautiful careful quickly\n        exercise favourite homework library sentence\n        quietly slowly loudly suddenly friendly\n        helpful interesting possible important\n        different difficult easy simple common\n        correct wrong honest kind polite brave\n        clever curious excited nervous worried\n        surprised tired<\/p>\n<p>        red blue green yellow black white\n        circle square triangle line number\n        add subtract multiply divide equal\n        answer problem solution question reason<\/p>\n<p>        first second third fourth fifth<\/p>\n<p>        Monday Tuesday Wednesday Thursday Friday\n        January February March April May June\n        July August September October November December\n        `<\/p>\n<p>    },<\/p>\n<p>    programming: {<\/p>\n<p>        name: \"Programming\",<\/p>\n<p>        description:\n            \"Variables, programming languages, loops, selection, functions, testing and debugging.\",<\/p>\n<p>        words: `\n        algorithm application array assignment argument boolean bug\n        code coding compiler constant condition debugging declaration\n        expression function identifier input integer iteration\n        Java JavaScript loop method module object operator output\n        parameter program programming language pseudocode Python\n        recursion repetition return selection sequence statement\n        string syntax test testing variable variable type\n        while loop for loop data type comment concatenate\n        comparison comparison operator conditional constructor\n        decrement increment function call function definition\n        index indexing logic logical operator machine code\n        object code program execution program structure runtime\n        source code subroutine subroutine call syntax error\n        test case test data test plan test result trace table\n        validation validation rule array index\n        `<\/p>\n<p>    },<\/p>\n<p>    algorithms: {<\/p>\n<p>        name: \"Data & Algorithms\",<\/p>\n<p>        description:\n            \"Algorithms, binary, data representation, searching, sorting and computational thinking.\",<\/p>\n<p>        words: `\n        algorithm abstraction decomposition sequence selection\n        iteration binary bit byte ASCII Unicode hexadecimal\n        decimal data representation binary number binary digit\n        binary addition binary subtraction binary conversion\n        bit pattern Boolean logic Boolean expression\n        Boolean operator AND OR NOT search linear search\n        binary search sorting selection sort algorithm efficiency\n        algorithm step complexity flowchart flowchart symbol\n        pseudocode trace trace table array index indexing\n        record field data type integer floating point\n        character string compression lossless lossy\n        resolution pixel colour depth pixel image digital image\n        metadata file size checksum data structure stack queue\n        tree graph binary tree traversal node\n        `<\/p>\n<p>    },<\/p>\n<p>    networks: {<\/p>\n<p>        name: \"Networks & Internet\",<\/p>\n<p>        description:\n            \"Networks, protocols, IP addresses, servers, routers, packets and internet technologies.\",<\/p>\n<p>        words: `\n        network internet LAN WAN WLAN WiFi wireless\n        router switch server client host node packet\n        packet switching network protocol TCP IP TCP\/IP\n        HTTP HTTPS FTP DNS URL address IP address\n        MAC address domain domain name web server\n        client server peer to peer bandwidth latency\n        transmission upload download download speed\n        transmission rate connectivity ethernet bluetooth\n        access point wireless access point gateway subnet\n        subnet mask network card network traffic\n        network security topology network protocol packet\n        header data packet firewall router modem broadband\n        fibre internet service provider ISP web browser\n        search engine webpage website\n        `<\/p>\n<p>    },<\/p>\n<p>    cybersecurity: {<\/p>\n<p>        name: \"Cybersecurity\",<\/p>\n<p>        description:\n            \"Online safety, malware, passwords, encryption, authentication, phishing and data protection.\",<\/p>\n<p>        words: `\n        cybersecurity security malware virus antivirus spyware\n        phishing phishing email spam social engineering password\n        password security password strength username authentication\n        authorisation authentication factor two factor authentication\n        encryption encryption key decryption cryptography cipher\n        plaintext hash hashing hash value firewall firewall rule\n        cyber attack cyber safety data breach data protection\n        data security data integrity privacy personal data\n        digital footprint online safety access control permission\n        administrator account secure verification validation\n        dictionary attack keylogger denial of service\n        penetration testing malicious software virus scanner\n        backup backup copy disaster recovery copyright software licence\n        `<\/p>\n<p>    },<\/p>\n<p>    hardware: {<\/p>\n<p>        name: \"Hardware & Software\",<\/p>\n<p>        description:\n            \"Computer hardware, software, storage, memory, processors, operating systems and peripherals.\",<\/p>\n<p>        words: `\n        computer hardware software CPU processor\n        central processing unit microprocessor CPU core\n        RAM ROM memory main memory internal memory\n        cache cache memory storage secondary storage\n        hard disk hard drive SSD storage device\n        motherboard component device peripheral input output\n        input device output device keyboard mouse printer\n        monitor screen speaker microphone camera\n        operating system system software application software\n        driver device driver firmware desktop laptop tablet\n        mobile device server hardware processor clock speed\n        clock speed register program counter memory address\n        memory capacity byte kilobyte megabyte gigabyte\n        terabyte binary machine code executable bytecode\n        compiler interpreter runtime\n        `<\/p>\n<p>    },<\/p>\n<p>    databases: {<\/p>\n<p>        name: \"Databases\",<\/p>\n<p>        description:\n            \"Databases, tables, records, fields, keys, queries, SQL and data validation.\",<\/p>\n<p>        words: `\n        database database table database field database record\n        relational relational database relational table record\n        field attribute table primary key foreign key key\n        query database query SQL SQL query query language\n        data collection data processing data validation\n        validation rule verification accuracy data integrity\n        consistency search filter sort\n        `<\/p>\n<p>    },<\/p>\n<p>    web: {<\/p>\n<p>        name: \"Web Development\",<\/p>\n<p>        description:\n            \"HTML, CSS, JavaScript, websites, browsers, URLs, web servers and web design.\",<\/p>\n<p>        words: `\n        HTML CSS JavaScript webpage website web page\n        web development web design web application browser\n        web browser search engine web server URL website\n        address domain domain name HTTP HTTPS hyperlink link\n        client server source code HTML tag element attribute\n        header footer navigation image multimedia animation\n        responsive accessibility interface graphical user interface\n        GUI form input button CSS style stylesheet JavaScript\n        function variable event\n        `<\/p>\n<p>    },<\/p>\n<p>    emerging: {<\/p>\n<p>        name: \"Emerging Technology\",<\/p>\n<p>        description:\n            \"Artificial intelligence, robotics, machine learning, virtual reality and modern technologies.\",<\/p>\n<p>        words: `\n        artificial intelligence AI machine learning neural network\n        robotics robot computer vision facial recognition\n        virtual reality augmented reality 3D printing wearable\n        technology automation automated chatbot bot deepfake\n        blockchain GPS technology digital technology digital media\n        cloud computing cloud storage cloud service smart device\n        mobile technology\n        `<\/p>\n<p>    }<\/p>\n<p>};<\/p>\n<p>\/* =====================================================\n   GENERAL COMPUTER SCIENCE WORD BANK\n===================================================== *\/<\/p>\n<p>const generalWords = `<\/p>\n<p>algorithm application array ASCII backup bandwidth\nbinary bit boolean browser byte cache character cloud\ncode coding compiler compression computer constant CPU\ncybersecurity data database debug debugging decryption\ndecomposition encryption ethernet execute file firewall\nfunction hardware HTML input internet iteration keyboard\nLAN loop malware memory network output password pixel\nprogram programming RAM recursion router server software\nstorage string syntax TCP variable virus website WiFi\nwireless WWW abstraction accessibility account administrator\nanimation antivirus argument authentication automated automation\nbitrate bluetooth bug bytecode client command condition\ndata type decimal decision declaration device dictionary\ndigital DNS domain download driver error event extension\nfibre flowchart folder gateway graphical GUI hexadecimal\nhost HTTP HTTPS identifier image interface JSON library\nlogic machine code metadata method modem module multimedia\nnode object packet parameter peripheral platform protocol\nquery resolution simulation source code spreadsheet SQL\nsubroutine system testing token trace transport troubleshooting\nupload URL user username version virtual validation webpage\naccess control accuracy algorithm design API assignment\nattribute availability broadcast bus circuit client server\nclock speed cloud computing code editor collision component\nconcatenation connectivity console copyright data breach\ndata packet data transmission database query dependency\ndesktop disaster recovery distributed endpoint event driven\nexecutable expression file compression filter firmware\nfloating point graph graphics hash image resolution\ninput validation integer interpreter latency local area network\nlogic error MAC address mainframe memory management\nnetwork traffic network switch open source operating system\npacket switching password manager permission plaintext port\nprimary key process processor property range read only\nreal time relational database reliability responsive requirement\nrobust runtime search algorithm secondary storage shell\nsoftware update sorting stack static subnet system administrator\ntest input test output thread timestamp transmission traversal\nUnicode unit testing validation variable version control\nvirtual machine wide area network WLAN word processor\nzero based indexing access point active addition address bus\nalgorithmic AND gate arithmetic availability binary tree\nbit depth Boolean algebra branch cache hit cache miss\ncharacter encoding checksum colour model command prompt\ncode block code review comment comparison complexity\nconditional constant value data structure default value\ndesign specification development environment encryption algorithm\nerror detection file compression filter garbage collection\ngigabyte header identity increment keylogger load\nlossless compression lossy compression memory network traffic\nobject oriented packet header personal data precision\nprogram flow programming construct pseudo random redundancy\nrequirements software licence stack table test case\ntwo dimensional uncompressed validation web hosting wireless<\/p>\n<p>`.trim().split(\/\\s+\/);<\/p>\n<p>\/* =====================================================\n   COMBINE WORD BANKS\n===================================================== *\/<\/p>\n<p>const allWords = [\n    ...generalWords,\n    ...Object.values(topics)\n        .flatMap(topic =>\n            topic.words.trim().split(\/\\s+\/)\n        )\n];<\/p>\n<p>\/* =====================================================\n   SENTENCES\n===================================================== *\/<\/p>\n<p>const sentences = {<\/p>\n<p>    english: [<\/p>\n<p>        \"The quick brown fox jumps over the lazy dog.\",<\/p>\n<p>        \"Reading every day can help you learn new words.\",<\/p>\n<p>        \"A good question can lead to an interesting answer.\",<\/p>\n<p>        \"Working carefully can help you avoid mistakes.\",<\/p>\n<p>        \"Learning new skills takes time and practice.\",<\/p>\n<p>        \"Teamwork can help people solve difficult problems.\",<\/p>\n<p>        \"A clear explanation helps other people understand an idea.\",<\/p>\n<p>        \"Being organised can make school work easier.\"<\/p>\n<p>    ],<\/p>\n<p>    programming: [<\/p>\n<p>        \"An algorithm is a set of instructions used to solve a problem.\",<\/p>\n<p>        \"A variable stores data that can change while a program runs.\",<\/p>\n<p>        \"A loop repeats instructions while a condition is true.\",<\/p>\n<p>        \"Selection allows a program to make a decision.\",<\/p>\n<p>        \"Testing helps programmers find and fix errors.\",<\/p>\n<p>        \"A function is a reusable section of code.\"<\/p>\n<p>    ],<\/p>\n<p>    algorithms: [<\/p>\n<p>        \"An algorithm describes the steps needed to solve a problem.\",<\/p>\n<p>        \"Binary uses zeros and ones to represent data.\",<\/p>\n<p>        \"A search algorithm can be used to find information.\",<\/p>\n<p>        \"A flowchart can show the steps in an algorithm.\",<\/p>\n<p>        \"Decomposition breaks a large problem into smaller problems.\"<\/p>\n<p>    ],<\/p>\n<p>    networks: [<\/p>\n<p>        \"A network allows computers and devices to communicate.\",<\/p>\n<p>        \"A router sends data between different networks.\",<\/p>\n<p>        \"Packets carry data across a computer network.\",<\/p>\n<p>        \"An IP address identifies a device on a network.\",<\/p>\n<p>        \"DNS helps computers find websites using domain names.\"<\/p>\n<p>    ],<\/p>\n<p>    cybersecurity: [<\/p>\n<p>        \"Encryption helps protect information from unauthorised users.\",<\/p>\n<p>        \"A strong password helps protect an online account.\",<\/p>\n<p>        \"Phishing messages try to trick users into revealing information.\",<\/p>\n<p>        \"Two factor authentication provides an additional security check.\",<\/p>\n<p>        \"A firewall can help protect a network from unwanted traffic.\"<\/p>\n<p>    ],<\/p>\n<p>    hardware: [<\/p>\n<p>        \"The CPU processes instructions in a computer.\",<\/p>\n<p>        \"RAM stores data that the computer is currently using.\",<\/p>\n<p>        \"An operating system manages computer hardware and software.\",<\/p>\n<p>        \"A keyboard is an input device.\",<\/p>\n<p>        \"A printer is an output device.\"<\/p>\n<p>    ],<\/p>\n<p>    databases: [<\/p>\n<p>        \"A database stores organised information.\",<\/p>\n<p>        \"A table contains records and fields.\",<\/p>\n<p>        \"A primary key uniquely identifies a record.\",<\/p>\n<p>        \"SQL can be used to query a database.\",<\/p>\n<p>        \"Validation can help prevent incorrect data being entered.\"<\/p>\n<p>    ],<\/p>\n<p>    web: [<\/p>\n<p>        \"HTML is used to structure content on a webpage.\",<\/p>\n<p>        \"CSS controls the appearance of a webpage.\",<\/p>\n<p>        \"JavaScript can make webpages interactive.\",<\/p>\n<p>        \"A web browser displays webpages.\",<\/p>\n<p>        \"A URL identifies the location of a resource on the web.\"<\/p>\n<p>    ],<\/p>\n<p>    emerging: [<\/p>\n<p>        \"Artificial intelligence allows computers to perform tasks that normally require human intelligence.\",<\/p>\n<p>        \"Machine learning allows systems to learn from data.\",<\/p>\n<p>        \"Robots can be programmed to perform physical tasks.\",<\/p>\n<p>        \"Virtual reality creates an immersive digital environment.\",<\/p>\n<p>        \"Artificial intelligence is used in many modern technologies.\"<\/p>\n<p>    ]<\/p>\n<p>};<\/p>\n<p>\/* =====================================================\n   GAME VARIABLES\n===================================================== *\/<\/p>\n<p>let topic = \"all\";\nlet mode = \"words\";\nlet difficulty = \"all\";<\/p>\n<p>let currentText = \"\";<\/p>\n<p>let started = false;\nlet finished = false;<\/p>\n<p>let startTime = 0;\nlet timerInterval = null;<\/p>\n<p>let timeLeft = 60;<\/p>\n<p>\/*\nThese variables are important.<\/p>\n<p>Instead of looking only at the current\nsentence, the program keeps a running\ntotal for the ENTIRE test.\n*\/<\/p>\n<p>let totalTypedCharacters = 0;\nlet totalCorrectCharacters = 0;<\/p>\n<p>\/*\nUsed to calculate the current sentence's\nprogress independently from the overall\ntest score.\n*\/<\/p>\n<p>let currentCorrectCharacters = 0;\nlet currentTypedCharacters = 0;<\/p>\n<p>\/* =====================================================\n   ELEMENTS\n===================================================== *\/<\/p>\n<p>const input =\n    document.getElementById(\"typingInput\");<\/p>\n<p>const sentence =\n    document.getElementById(\"sentence\");<\/p>\n<p>const timer =\n    document.getElementById(\"timer\");<\/p>\n<p>const progress =\n    document.getElementById(\"progress\");<\/p>\n<p>\/* =====================================================\n   GET WORDS FOR SELECTED TOPIC\n===================================================== *\/<\/p>\n<p>function getTopicWords() {<\/p>\n<p>    if (topic === \"all\") {\n        return allWords;\n    }<\/p>\n<p>    return topics[topic]\n        .words\n        .trim()\n        .split(\/\\s+\/);<\/p>\n<p>}<\/p>\n<p>\/* =====================================================\n   RANDOM WORD\n===================================================== *\/<\/p>\n<p>function randomWord() {<\/p>\n<p>    const words =\n        getTopicWords();<\/p>\n<p>    return words[\n        Math.floor(\n            Math.random() * words.length\n        )\n    ];<\/p>\n<p>}<\/p>\n<p>\/* =====================================================\n   CREATE KEYWORD TEXT\n===================================================== *\/<\/p>\n<p>function createKeywordText() {<\/p>\n<p>    const selected = [];<\/p>\n<p>    for (let i = 0; i < 30; i++) {\n\n        const word =\n            randomWord();\n\n        \/*\n        Foundation mode avoids\n        particularly long words.\n        *\/\n\n        if (\n            difficulty === \"easy\" &#038;&#038;\n            word.length > 14\n        ) {<\/p>\n<p>            i--;<\/p>\n<p>            continue;<\/p>\n<p>        }<\/p>\n<p>        selected.push(word);<\/p>\n<p>    }<\/p>\n<p>    return selected.join(\" \");<\/p>\n<p>}<\/p>\n<p>\/* =====================================================\n   CREATE SENTENCE\n===================================================== *\/<\/p>\n<p>function createSentenceText() {<\/p>\n<p>    let pool;<\/p>\n<p>    if (topic === \"all\") {<\/p>\n<p>        pool =\n            Object.values(sentences)\n                .flat();<\/p>\n<p>    } else {<\/p>\n<p>        pool =\n            sentences[topic] ||\n            sentences.english;<\/p>\n<p>    }<\/p>\n<p>    return pool[\n        Math.floor(\n            Math.random() * pool.length\n        )\n    ];<\/p>\n<p>}<\/p>\n<p>\/* =====================================================\n   CREATE MIXED TEXT\n===================================================== *\/<\/p>\n<p>function createMixedText() {<\/p>\n<p>    const sentenceText =\n        createSentenceText();<\/p>\n<p>    const words = [];<\/p>\n<p>    for (let i = 0; i < 10; i++) {\n\n        words.push(\n            randomWord()\n        );\n\n    }\n\n    return (\n        sentenceText +\n        \" \" +\n        words.join(\" \")\n    );\n\n}\n\n\n\/* =====================================================\n   CREATE PRACTICE TEXT\n===================================================== *\/\n\nfunction createPracticeText() {\n\n    if (mode === \"words\") {\n        return createKeywordText();\n    }\n\n    if (mode === \"sentences\") {\n        return createSentenceText();\n    }\n\n    return createMixedText();\n\n}\n\n\n\/* =====================================================\n   ESCAPE HTML\n===================================================== *\/\n\nfunction escapeHTML(text) {\n\n    return text\n        .replace(\/&#038;\/g, \"&amp;\")\n        .replace(\/<\/g, \"&lt;\")\n        .replace(\/>\/g, \"&gt;\");<\/p>\n<p>}<\/p>\n<p>\/* =====================================================\n   DISPLAY TEXT\n===================================================== *\/<\/p>\n<p>function renderText(typed) {<\/p>\n<p>    let html = \"\";<\/p>\n<p>    for (\n        let i = 0;\n        i < currentText.length;\n        i++\n    ) {\n\n        const character =\n            currentText[i];\n\n        if (i < typed.length) {\n\n            if (\n                typed[i] === character\n            ) {\n\n                html +=\n                    `<span class=\"correct\">${escapeHTML(character)}<\/span>`;<\/p>\n<p>            } else {<\/p>\n<p>                html +=\n                    `<span class=\"incorrect\">${escapeHTML(character)}<\/span>`;<\/p>\n<p>            }<\/p>\n<p>        } else if (\n            i === typed.length\n        ) {<\/p>\n<p>            html +=\n                `<span class=\"current\">${escapeHTML(character)}<\/span>`;<\/p>\n<p>        } else {<\/p>\n<p>            html +=\n                escapeHTML(character);<\/p>\n<p>        }<\/p>\n<p>    }<\/p>\n<p>    sentence.innerHTML = html;<\/p>\n<p>}<\/p>\n<p>\/* =====================================================\n   START TEST\n===================================================== *\/<\/p>\n<p>function startTest() {<\/p>\n<p>    if (started) return;<\/p>\n<p>    started = true;\n    finished = false;<\/p>\n<p>    input.disabled = false;\n    input.value = \"\";\n    input.focus();<\/p>\n<p>    startTime = Date.now();<\/p>\n<p>    timeLeft = 60;<\/p>\n<p>    \/*\n    Reset the whole-test counters.\n    *\/<\/p>\n<p>    totalTypedCharacters = 0;\n    totalCorrectCharacters = 0;<\/p>\n<p>    currentCorrectCharacters = 0;\n    currentTypedCharacters = 0;<\/p>\n<p>    document.getElementById(\n        \"liveWpm\"\n    ).textContent = \"0\";<\/p>\n<p>    document.getElementById(\n        \"liveAccuracy\"\n    ).textContent = \"100%\";<\/p>\n<p>    document.getElementById(\n        \"result\"\n    ).classList.remove(\"show\");<\/p>\n<p>    document.getElementById(\n        \"startBtn\"\n    ).textContent =\n        \"\u2328\ufe0f Typing...\";<\/p>\n<p>    \/*\n    Start the timer.\n    *\/<\/p>\n<p>    clearInterval(timerInterval);<\/p>\n<p>    timerInterval =\n        setInterval(\n            updateTimer,\n            1000\n        );<\/p>\n<p>}<\/p>\n<p>\/* =====================================================\n   TIMER\n===================================================== *\/<\/p>\n<p>function updateTimer() {<\/p>\n<p>    timeLeft--;<\/p>\n<p>    timer.textContent =\n        timeLeft;<\/p>\n<p>    if (timeLeft <= 10) {\n\n        timer.style.background =\n            \"linear-gradient(135deg,#e17055,#d63031)\";\n\n    }\n\n\n    if (timeLeft <= 0) {\n\n        finishTest();\n\n    }\n\n}\n\n\n\/* =====================================================\n   INPUT HANDLER\n===================================================== *\/\n\ninput.addEventListener(\n    \"input\",\n    function () {\n\n        if (\n            !started ||\n            finished\n        ) {\n            return;\n        }\n\n\n        const typed =\n            input.value;\n\n\n        \/*\n        Calculate the number of correctly\n        typed characters in the CURRENT\n        piece of text.\n        *\/\n\n        let correct = 0;\n\n        for (\n            let i = 0;\n            i < typed.length &#038;&#038;\n            i < currentText.length;\n            i++\n        ) {\n\n            if (\n                typed[i] ===\n                currentText[i]\n            ) {\n\n                correct++;\n\n            }\n\n        }\n\n\n        \/*\n        Calculate how many characters\n        have changed since the previous\n        input event.\n\n        This prevents characters being\n        counted repeatedly when the\n        student edits their answer.\n        *\/\n\n        const previousLength =\n            currentTypedCharacters;\n\n\n        if (\n            typed.length >\n            previousLength\n        ) {<\/p>\n<p>            const newCharacters =\n                typed.length -\n                previousLength;<\/p>\n<p>            \/*\n            Find how many of the newly\n            entered characters are correct.\n            *\/<\/p>\n<p>            let newlyCorrect = 0;<\/p>\n<p>            for (\n                let i = previousLength;\n                i < typed.length;\n                i++\n            ) {\n\n                if (\n                    typed[i] ===\n                    currentText[i]\n                ) {\n\n                    newlyCorrect++;\n\n                }\n\n            }\n\n\n            totalTypedCharacters +=\n                newCharacters;\n\n            totalCorrectCharacters +=\n                newlyCorrect;\n\n        }\n\n\n        \/*\n        If the student deletes text,\n        adjust the current sentence\n        position.\n\n        The overall test total does NOT\n        lose characters. This means WPM\n        represents actual typing effort\n        rather than the final length of\n        the text box.\n        *\/\n\n        currentTypedCharacters =\n            typed.length;\n\n        currentCorrectCharacters =\n            correct;\n\n\n        renderText(typed);\n\n\n        updateLiveStats();\n\n\n        \/*\n        Progress through the current\n        set of words.\n        *\/\n\n        const percentage =\n            Math.min(\n                (\n                    typed.length \/\n                    currentText.length\n                ) * 100,\n                100\n            );\n\n        progress.style.width =\n            percentage + \"%\";\n\n\n        highlightKey(\n            typed[typed.length - 1]\n        );\n\n\n        \/*\n        KEYWORD MODE\n\n        Once the student reaches the\n        end of the current set, give\n        them another set without\n        ending the 60 second test.\n        *\/\n\n        if (\n            typed.length >=\n                currentText.length &&\n            mode === \"words\"\n        ) {<\/p>\n<p>            currentText =\n                createKeywordText();<\/p>\n<p>            input.value = \"\";<\/p>\n<p>            currentTypedCharacters = 0;<\/p>\n<p>            currentCorrectCharacters = 0;<\/p>\n<p>            renderText(\"\");<\/p>\n<p>            progress.style.width =\n                \"0%\";<\/p>\n<p>        }<\/p>\n<p>        \/*\n        SENTENCE \/ MIXED MODE<\/p>\n<p>        Give another challenge instead\n        of stopping the test.<\/p>\n<p>        This means all three modes are\n        genuinely 60-second tests.\n        *\/<\/p>\n<p>        if (\n            typed.length >=\n                currentText.length &&\n            mode !== \"words\"\n        ) {<\/p>\n<p>            currentText =\n                createPracticeText();<\/p>\n<p>            input.value = \"\";<\/p>\n<p>            currentTypedCharacters = 0;<\/p>\n<p>            currentCorrectCharacters = 0;<\/p>\n<p>            renderText(\"\");<\/p>\n<p>            progress.style.width =\n                \"0%\";<\/p>\n<p>        }<\/p>\n<p>    }\n);<\/p>\n<p>\/* =====================================================\n   LIVE WPM + ACCURACY\n===================================================== *\/<\/p>\n<p>function updateLiveStats() {<\/p>\n<p>    \/*\n    WPM is calculated using the standard\n    five-characters-per-word convention.<\/p>\n<p>        WPM =\n        correct characters \/ 5\n        \/ elapsed minutes\n    *\/<\/p>\n<p>    const elapsedMilliseconds =\n        Date.now() -\n        startTime;<\/p>\n<p>    const elapsedMinutes =\n        Math.max(\n            elapsedMilliseconds \/\n            60000,\n            1 \/ 60000\n        );<\/p>\n<p>    const wpm =\n        Math.round(\n            (\n                totalCorrectCharacters \/\n                5\n            ) \/\n            elapsedMinutes\n        );<\/p>\n<p>    \/*\n    Accuracy is:<\/p>\n<p>        correct characters \/\n        total typed characters\n    *\/<\/p>\n<p>    const accuracy =\n        totalTypedCharacters === 0\n            ? 100\n            : Math.round(\n                (\n                    totalCorrectCharacters \/\n                    totalTypedCharacters\n                ) * 100\n            );<\/p>\n<p>    document.getElementById(\n        \"liveWpm\"\n    ).textContent =\n        wpm;<\/p>\n<p>    document.getElementById(\n        \"liveAccuracy\"\n    ).textContent =\n        accuracy + \"%\";<\/p>\n<p>}<\/p>\n<p>\/* =====================================================\n   FINISH TEST\n===================================================== *\/<\/p>\n<p>function finishTest() {<\/p>\n<p>    if (finished) return;<\/p>\n<p>    finished = true;\n    started = false;<\/p>\n<p>    clearInterval(timerInterval);<\/p>\n<p>    input.disabled = true;<\/p>\n<p>    \/*\n    Calculate final WPM using the\n    complete test totals.\n    *\/<\/p>\n<p>    const elapsedMilliseconds =\n        Date.now() -\n        startTime;<\/p>\n<p>    const elapsedMinutes =\n        Math.max(\n            elapsedMilliseconds \/\n            60000,\n            1 \/ 60000\n        );<\/p>\n<p>    const wpm =\n        Math.round(\n            (\n                totalCorrectCharacters \/\n                5\n            ) \/\n            elapsedMinutes\n        );<\/p>\n<p>    const accuracy =\n        totalTypedCharacters === 0\n            ? 0\n            : Math.round(\n                (\n                    totalCorrectCharacters \/\n                    totalTypedCharacters\n                ) * 100\n            );<\/p>\n<p>    \/*\n    Update final stats.\n    *\/<\/p>\n<p>    document.getElementById(\n        \"liveWpm\"\n    ).textContent =\n        wpm;<\/p>\n<p>    document.getElementById(\n        \"liveAccuracy\"\n    ).textContent =\n        accuracy + \"%\";<\/p>\n<p>    \/*\n    Best score.\n    *\/<\/p>\n<p>    const oldBest =\n        Number(\n            localStorage.getItem(\n                \"typeQuestBest\"\n            ) || 0\n        );<\/p>\n<p>    let best = oldBest;<\/p>\n<p>    if (wpm > oldBest) {<\/p>\n<p>        best = wpm;<\/p>\n<p>        localStorage.setItem(\n            \"typeQuestBest\",\n            wpm\n        );<\/p>\n<p>    }<\/p>\n<p>    document.getElementById(\n        \"liveBest\"\n    ).textContent =\n        best;<\/p>\n<p>    \/*\n    Result box.\n    *\/<\/p>\n<p>    document.getElementById(\n        \"resultWpm\"\n    ).textContent =\n        wpm + \" WPM\";<\/p>\n<p>    document.getElementById(\n        \"resultAccuracy\"\n    ).textContent =\n        \"Accuracy: \" +\n        accuracy +\n        \"%\";<\/p>\n<p>    let message;<\/p>\n<p>    if (\n        accuracy >= 95 &&\n        wpm >= 40\n    ) {<\/p>\n<p>        message =\n            \"\ud83d\udd25 Fantastic! Your speed and accuracy are excellent.\";<\/p>\n<p>    } else if (\n        accuracy >= 90\n    ) {<\/p>\n<p>        message =\n            \"\ud83c\udf1f Excellent accuracy! Now work on your speed.\";<\/p>\n<p>    } else if (\n        wpm >= 30\n    ) {<\/p>\n<p>        message =\n            \"\ud83d\ude80 Great speed! Try to make fewer mistakes.\";<\/p>\n<p>    } else {<\/p>\n<p>        message =\n            \"\ud83d\udcaa Good effort! Keep practising and your speed will improve.\";<\/p>\n<p>    }<\/p>\n<p>    document.getElementById(\n        \"resultMessage\"\n    ).textContent =\n        message;<\/p>\n<p>    document.getElementById(\n        \"result\"\n    ).classList.add(\"show\");<\/p>\n<p>    document.getElementById(\n        \"startBtn\"\n    ).textContent =\n        \"\u25b6 Try Again\";<\/p>\n<p>    timer.textContent =\n        \"0\";<\/p>\n<p>    timer.style.background =\n        \"linear-gradient(135deg,#6c5ce7,#0984e3)\";<\/p>\n<p>}<\/p>\n<p>\/* =====================================================\n   RESET TEST\n===================================================== *\/<\/p>\n<p>function resetTest() {<\/p>\n<p>    clearInterval(timerInterval);<\/p>\n<p>    started = false;\n    finished = false;<\/p>\n<p>    input.disabled = true;\n    input.value = \"\";<\/p>\n<p>    timeLeft = 60;<\/p>\n<p>    timer.textContent =\n        \"60\";<\/p>\n<p>    timer.style.background =\n        \"linear-gradient(135deg,#6c5ce7,#0984e3)\";<\/p>\n<p>    progress.style.width =\n        \"0%\";<\/p>\n<p>    totalTypedCharacters = 0;\n    totalCorrectCharacters = 0;<\/p>\n<p>    currentTypedCharacters = 0;\n    currentCorrectCharacters = 0;<\/p>\n<p>    document.getElementById(\n        \"liveWpm\"\n    ).textContent =\n        \"0\";<\/p>\n<p>    document.getElementById(\n        \"liveAccuracy\"\n    ).textContent =\n        \"100%\";<\/p>\n<p>    document.getElementById(\n        \"startBtn\"\n    ).textContent =\n        \"\u25b6 Start Typing\";<\/p>\n<p>    document.getElementById(\n        \"result\"\n    ).classList.remove(\"show\");<\/p>\n<p>    currentText =\n        createPracticeText();<\/p>\n<p>    renderText(\"\");<\/p>\n<p>    removeHighlights();<\/p>\n<p>}<\/p>\n<p>\/* =====================================================\n   CHANGE TOPIC\n===================================================== *\/<\/p>\n<p>function changeTopic() {<\/p>\n<p>    topic =\n        document.getElementById(\n            \"topicSelect\"\n        ).value;<\/p>\n<p>    const description =\n        document.getElementById(\n            \"topicDescription\"\n        );<\/p>\n<p>    if (topic === \"all\") {<\/p>\n<p>        description.textContent =\n            \"Practise vocabulary from all Year 7 English and Computer Science topics.\";<\/p>\n<p>    } else {<\/p>\n<p>        description.textContent =\n            topics[topic].description;<\/p>\n<p>    }<\/p>\n<p>    loadPractice();<\/p>\n<p>}<\/p>\n<p>\/* =====================================================\n   CHANGE DIFFICULTY\n===================================================== *\/<\/p>\n<p>document\n    .getElementById(\n        \"difficultySelect\"\n    )\n    .addEventListener(\n        \"change\",\n        function () {<\/p>\n<p>            difficulty =\n                this.value;<\/p>\n<p>            loadPractice();<\/p>\n<p>        }\n    );<\/p>\n<p>\/* =====================================================\n   CHANGE MODE\n===================================================== *\/<\/p>\n<p>function chooseMode(\n    newMode,\n    button\n) {<\/p>\n<p>    mode = newMode;<\/p>\n<p>    document\n        .querySelectorAll(\n            \".lesson-btn\"\n        )\n        .forEach(\n            btn =>\n                btn.classList.remove(\n                    \"active\"\n                )\n        );<\/p>\n<p>    button.classList.add(\n        \"active\"\n    );<\/p>\n<p>    if (mode === \"words\") {<\/p>\n<p>        document.getElementById(\n            \"levelTitle\"\n        ).textContent =\n            \"\ud83d\udd24 Year 7 Keywords\";<\/p>\n<p>        document.getElementById(\n            \"instruction\"\n        ).textContent =\n            \"Type the vocabulary shown below. New words will appear as you progress.\";<\/p>\n<p>    }<\/p>\n<p>    else if (\n        mode === \"sentences\"\n    ) {<\/p>\n<p>        document.getElementById(\n            \"levelTitle\"\n        ).textContent =\n            \"\ud83d\udcdd Year 7 Sentences\";<\/p>\n<p>        document.getElementById(\n            \"instruction\"\n        ).textContent =\n            \"Type the sentence carefully. Focus on accuracy.\";<\/p>\n<p>    }<\/p>\n<p>    else {<\/p>\n<p>        document.getElementById(\n            \"levelTitle\"\n        ).textContent =\n            \"\ud83e\udde0 Mixed Challenge\";<\/p>\n<p>        document.getElementById(\n            \"instruction\"\n        ).textContent =\n            \"A mixture of vocabulary and sentences.\";<\/p>\n<p>    }<\/p>\n<p>    loadPractice();<\/p>\n<p>}<\/p>\n<p>\/* =====================================================\n   LOAD PRACTICE\n===================================================== *\/<\/p>\n<p>function loadPractice() {<\/p>\n<p>    \/*\n    Don't interrupt an active test.\n    *\/<\/p>\n<p>    if (started) return;<\/p>\n<p>    currentText =\n        createPracticeText();<\/p>\n<p>    renderText(\"\");<\/p>\n<p>    input.value = \"\";<\/p>\n<p>    input.disabled = true;<\/p>\n<p>    progress.style.width =\n        \"0%\";<\/p>\n<p>    removeHighlights();<\/p>\n<p>}<\/p>\n<p>\/* =====================================================\n   KEYBOARD HIGHLIGHT\n===================================================== *\/<\/p>\n<p>function highlightKey(character) {<\/p>\n<p>    removeHighlights();<\/p>\n<p>    if (!character) return;<\/p>\n<p>    document\n        .querySelectorAll(\n            \".key\"\n        )\n        .forEach(\n            key => {<\/p>\n<p>                if (\n                    key.textContent\n                        .toLowerCase() ===\n                    character.toLowerCase()\n                ) {<\/p>\n<p>                    key.classList.add(\n                        \"highlight\"\n                    );<\/p>\n<p>                }<\/p>\n<p>            }\n        );<\/p>\n<p>}<\/p>\n<p>\/* =====================================================\n   REMOVE KEY HIGHLIGHTS\n===================================================== *\/<\/p>\n<p>function removeHighlights() {<\/p>\n<p>    document\n        .querySelectorAll(\n            \".key\"\n        )\n        .forEach(\n            key =>\n                key.classList.remove(\n                    \"highlight\"\n                )\n        );<\/p>\n<p>}<\/p>\n<p>\/* =====================================================\n   LOAD SAVED BEST SCORE\n===================================================== *\/<\/p>\n<p>const savedBest =\n    Number(\n        localStorage.getItem(\n            \"typeQuestBest\"\n        ) || 0\n    );<\/p>\n<p>document.getElementById(\n    \"liveBest\"\n).textContent =\n    savedBest;<\/p>\n<p>\/* =====================================================\n   INITIALISE\n===================================================== *\/<\/p>\n<p>currentText =\n    createKeywordText();<\/p>\n<p>renderText(\"\");<\/p>\n<p><\/script><\/p>\n<p><\/body><br \/>\n<\/html><\/p>\n","protected":false},"excerpt":{"rendered":"<p>TypeQuest &#8211; Year 7 Typing TouchTyping Quest KS3 Computing Improve your typing while learning English and Computer Science! Choose Your Topic Topic All Topics General English Programming Data &#038; Algorithms Networks &#038; Internet Cybersecurity Hardware &#038; Software Databases Web Development Emerging Technology Difficulty All Levels Developing Reaching\/Mastering Challenge Practise vocabulary from all Year 7 English [&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-617","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/mrcottle.co.uk\/WP\/wp-json\/wp\/v2\/pages\/617","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mrcottle.co.uk\/WP\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/mrcottle.co.uk\/WP\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/mrcottle.co.uk\/WP\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mrcottle.co.uk\/WP\/wp-json\/wp\/v2\/comments?post=617"}],"version-history":[{"count":3,"href":"https:\/\/mrcottle.co.uk\/WP\/wp-json\/wp\/v2\/pages\/617\/revisions"}],"predecessor-version":[{"id":640,"href":"https:\/\/mrcottle.co.uk\/WP\/wp-json\/wp\/v2\/pages\/617\/revisions\/640"}],"wp:attachment":[{"href":"https:\/\/mrcottle.co.uk\/WP\/wp-json\/wp\/v2\/media?parent=617"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}