{"id":470,"date":"2026-04-21T23:19:18","date_gmt":"2026-04-21T23:19:18","guid":{"rendered":"https:\/\/beginnerprojects.com\/cms\/?p=470"},"modified":"2026-04-21T23:57:42","modified_gmt":"2026-04-21T23:57:42","slug":"free-beginner-app-to-learn-note-names-treble-clef-edition","status":"publish","type":"post","link":"https:\/\/beginnerprojects.com\/cms\/free-beginner-app-to-learn-note-names-treble-clef-edition\/","title":{"rendered":"Free Beginner App to Learn Note Names (Treble Clef Edition)"},"content":{"rendered":"\n<p>I am currently developing a series of music education apps. If this is a field that interests you, feel free to take the code below and run it directly in your web browser. Like all the other free JavaScript apps available here on Beginner Projects, this one follows a simple, portable pattern.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Getting Started<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Security First:<\/strong> Conduct a security audit using your favorite AI. If this is your first app downloaded from Beginner Projects, please take a moment to read: <a href=\"https:\/\/beginnerprojects.com\/cms\/critical-the-golden-rule-of-free-code\/\" data-type=\"post\" data-id=\"169\">The Golden Rule of Free Code<\/a>.<\/li>\n\n\n\n<li><strong>Save Locally:<\/strong> Copy the code and save it to your computer.<br><em>Suggestion: Save the file as note-names-app.html<\/em><\/li>\n\n\n\n<li><strong>Launch:<\/strong> Open the saved file in any web browser.<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Why Use This App?<\/h2>\n\n\n\n<p>If you have children starting piano lessons this fall, this app provides a fun, interactive way to practice reading music. As with any skill, the more time we spend engaging with the material, the faster we improve.<\/p>\n\n\n\n<figure class=\"wp-block-image aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"500\" height=\"780\" src=\"https:\/\/beginnerprojects.com\/cms\/wp-content\/uploads\/2026\/04\/free-note-names-treble-clef-app.webp\" alt=\"Screenshot of the free beginner app to learn note names (treble clef edition), showing a golden note being dragged on a musical staff.\" class=\"wp-image-474\" srcset=\"https:\/\/beginnerprojects.com\/cms\/wp-content\/uploads\/2026\/04\/free-note-names-treble-clef-app.webp 500w, https:\/\/beginnerprojects.com\/cms\/wp-content\/uploads\/2026\/04\/free-note-names-treble-clef-app-192x300.webp 192w\" sizes=\"auto, (max-width: 500px) 100vw, 500px\" \/><figcaption class=\"wp-element-caption\">Actual screenshot of the app<\/figcaption><\/figure>\n\n\n\n<div data-wp-context=\"{ &quot;autoclose&quot;: false, &quot;accordionItems&quot;: [] }\" data-wp-interactive=\"core\/accordion\" role=\"group\" class=\"wp-block-accordion is-layout-flow wp-block-accordion-is-layout-flow\">\n<div data-wp-class--is-open=\"state.isOpen\" data-wp-context=\"{ &quot;id&quot;: &quot;accordion-item-1&quot;, &quot;openByDefault&quot;: false }\" data-wp-init=\"callbacks.initAccordionItems\" data-wp-on-window--hashchange=\"callbacks.hashChange\" class=\"wp-block-accordion-item is-layout-flow wp-block-accordion-item-is-layout-flow\">\n<h3 class=\"wp-block-accordion-heading\"><button aria-expanded=\"false\" aria-controls=\"accordion-item-1-panel\" data-wp-bind--aria-expanded=\"state.isOpen\" data-wp-on--click=\"actions.toggle\" data-wp-on--keydown=\"actions.handleKeyDown\" id=\"accordion-item-1\" type=\"button\" class=\"wp-block-accordion-heading__toggle\"><span class=\"wp-block-accordion-heading__toggle-title\"><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-palette-color-9-color\">Click to see the code<\/mark><\/span><span class=\"wp-block-accordion-heading__toggle-icon\" aria-hidden=\"true\">+<\/span><\/button><\/h3>\n\n\n\n<div inert aria-labelledby=\"accordion-item-1\" data-wp-bind--inert=\"!state.isOpen\" id=\"accordion-item-1-panel\" role=\"region\" class=\"wp-block-accordion-panel is-layout-flow wp-block-accordion-panel-is-layout-flow\">\n<pre class=\"wp-block-code has-palette-color-11-background-color has-background\"><code> &lt;!DOCTYPE html&gt;\n&lt;html lang=\"en\"&gt;\n&lt;head&gt;\n    &lt;meta charset=\"UTF-8\"&gt;\n    &lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"&gt;\n    &lt;title&gt;Music Note Trainer - Level 1&lt;\/title&gt;\n    &lt;style&gt;\n        body {\n            background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);\n            margin: 0;\n            padding: 20px;\n            font-family: 'Comic Sans MS', 'Arial Rounded MT Bold', Arial, sans-serif;\n            display: flex;\n            flex-direction: column;\n            align-items: center;\n            min-height: 100vh;\n        }\n        \n        h1 {\n            color: white;\n            text-shadow: 2px 2px 4px rgba(0,0,0,0.2);\n            margin-bottom: 5px;\n            font-size: 26px;\n        }\n        \n        .badge {\n            background: #ffcc00;\n            color: #333;\n            padding: 4px 12px;\n            border-radius: 12px;\n            font-size: 14px;\n            font-weight: bold;\n            margin-bottom: 15px;\n            box-shadow: 0 2px 4px rgba(0,0,0,0.15);\n        }\n        \n        .music-container {\n            width: 400px;\n            height: 550px;\n            border: 4px solid #2c3e50;\n            border-radius: 30px;\n            margin: 0 auto;\n            background: linear-gradient(to bottom, #e8f4f8, #ffffff);\n            position: relative;\n            overflow: hidden;\n            box-shadow: 0 8px 25px rgba(0, 0, 0, 0.3);\n        }\n        \n        .staff-line {\n            position: absolute;\n            width: 100%;\n            height: 3px;\n            background: linear-gradient(to right, transparent, #2c3e50, transparent);\n            border-radius: 2px;\n        }\n        \n        .helper-line {\n            position: absolute;\n            width: 100px;\n            height: 3px;\n            background: linear-gradient(to right, transparent, #e74c3c, transparent);\n            left: 150px;\n            border-radius: 2px;\n        }\n        \n        .draggable-oval {\n            position: absolute;\n            width: 75px;\n            height: 50px;\n            border-radius: 50%;\n            cursor: grab;\n            z-index: 10;\n            background: radial-gradient(ellipse at 30% 30%, #ffd700 0%, #ff8c00 40%, #cc5500 100%);\n            transform: skewX(2deg);\n            box-shadow: \n                0 4px 8px rgba(0,0,0,0.4),\n                inset 0 -3px 6px rgba(0,0,0,0.2);\n            transition: transform 0.1s ease;\n        }\n        \n        .draggable-oval:active {\n            cursor: grabbing;\n            transform: skewX(2deg) scale(1.05);\n        }\n        \n        .message {\n            position: absolute;\n            top: 60px;\n            left: 50%;\n            transform: translateX(-50%);\n            background: linear-gradient(to right, #27ae60, #2ecc71);\n            color: white;\n            padding: 12px 25px;\n            border-radius: 25px;\n            font-weight: bold;\n            text-align: center;\n            z-index: 20;\n            font-size: 22px;\n            box-shadow: 0 4px 10px rgba(0,0,0,0.2);\n            opacity: 0;\n            transition: opacity 0.3s ease;\n            white-space: nowrap;\n        }\n        \n        .message.show { opacity: 1; }\n        .message.error { background: linear-gradient(to right, #e74c3c, #c0392b); }\n        \n        .note-display {\n            position: absolute;\n            top: 15px;\n            left: 50%;\n            transform: translateX(-50%);\n            font-size: 24px;\n            font-weight: bold;\n            z-index: 20;\n            text-align: center;\n            color: #2c3e50;\n            background: rgba(255,255,255,0.85);\n            padding: 8px 20px;\n            border-radius: 20px;\n            box-shadow: 0 2px 5px rgba(0,0,0,0.1);\n        }\n        \n        .instructions {\n            max-width: 400px;\n            margin: 15px auto;\n            padding: 12px 20px;\n            background: rgba(255,255,255,0.9);\n            border-radius: 15px;\n            color: #2c3e50;\n            font-size: 14px;\n            text-align: center;\n            box-shadow: 0 3px 10px rgba(0,0,0,0.15);\n            line-height: 1.4;\n        }\n        \n        .clef {\n            position: absolute;\n            left: 15px;\n            top: 180px;\n            font-size: 48px;\n            color: #2c3e50;\n            font-weight: bold;\n            z-index: 5;\n            text-shadow: 1px 1px 2px rgba(0,0,0,0.1);\n        }\n    &lt;\/style&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n    &lt;h1&gt;\ud83c\udfb5 Note Name Trainer&lt;\/h1&gt;\n    &lt;div class=\"badge\"&gt;\ud83c\udf1f Level 1: Beginner&lt;\/div&gt;\n    \n    &lt;div class=\"music-container\" id=\"musicContainer\"&gt;\n        &lt;div class=\"clef\"&gt;\ud834\udd1e&lt;\/div&gt;\n        &lt;div class=\"note-display\" id=\"noteDisplay\"&gt;Loading...&lt;\/div&gt;\n        &lt;div class=\"message\" id=\"message\"&gt;&lt;\/div&gt;\n    &lt;\/div&gt;\n    \n    &lt;div class=\"instructions\"&gt;\n        &lt;strong&gt;How to play:&lt;\/strong&gt;&lt;br&gt;\n        \ud83c\udfaf Drag the golden note to match the prompt&lt;br&gt;\n        \u2728 It will snap when you're close!&lt;br&gt;\n        \ud83d\udd04 Keep going to learn more notes!\n    &lt;\/div&gt;\n\n    &lt;script&gt;\n        \/\/ ===== CONFIGURATION =====\n        const CONFIG = {\n            containerWidth: 400,\n            containerHeight: 550,\n            lineSpacing: 50,\n            staffCenterY: 250,      \/\/ Center line (High B)\n            noteWidth: 75,\n            noteHeight: 50,\n            tolerance: 30,          \/\/ Larger for beginners (was 25)\n            helperLineY: 400        \/\/ Middle C ledger line\n        };\n\n        \/\/ ===== DOM ELEMENTS =====\n        const container = document.getElementById('musicContainer');\n        const noteDisplay = document.getElementById('noteDisplay');\n        const messageEl = document.getElementById('message');\n\n        \/\/ ===== GAME STATE =====\n        let gameState = {\n            currentNote: null,\n            previousNote: null,\n            isDragging: false,\n            dragOffset: { x: 0, y: 0 },\n            autoCorrectTimer: null\n        };\n\n        \/\/ ===== BEGINNER NOTE POOL (Low B \u2192 High C) =====\n        \/\/ Positions represent the CENTER of the note\n        const BEGINNER_NOTES = &#91;'B3', 'C4', 'D4', 'E4', 'F4', 'G4', 'A4', 'B4', 'C5'];\n        \n        const NOTE_LABELS = {\n            'B3': 'Low B',\n            'C4': 'C',\n            'D4': 'D',\n            'E4': 'E',\n            'F4': 'F',\n            'G4': 'G',\n            'A4': 'A',\n            'B4': 'High B',\n            'C5': 'High C'\n        };\n\n        const NOTE_POSITIONS = {\n            'B3': 425,  \/\/ Space below helper line\n            'C4': 400,  \/\/ Helper\/ledger line\n            'D4': 375,  \/\/ Space below bottom staff line\n            'E4': 350,  \/\/ Bottom staff line\n            'F4': 325,  \/\/ First space\n            'G4': 300,  \/\/ Second line\n            'A4': 275,  \/\/ Second space\n            'B4': 250,  \/\/ Center line\n            'C5': 225   \/\/ Third space\n        };\n\n        \/\/ ===== INITIALIZATION =====\n        function init() {\n            drawStaff();\n            createDraggableNote();\n            generateRandomNote();\n            setupEventListeners();\n        }\n\n        \/\/ ===== DRAW STAFF LINES =====\n        function drawStaff() {\n            \/\/ 5 main staff lines\n            for (let i = -2; i &lt;= 2; i++) {\n                const line = document.createElement('div');\n                line.className = 'staff-line';\n                line.style.top = (CONFIG.staffCenterY + i * CONFIG.lineSpacing) + 'px';\n                container.appendChild(line);\n            }\n            \n            \/\/ Helper line for Middle C\n            const helperLine = document.createElement('div');\n            helperLine.className = 'helper-line';\n            helperLine.style.top = CONFIG.helperLineY + 'px';\n            container.appendChild(helperLine);\n        }\n\n        \/\/ ===== CREATE DRAGGABLE NOTE =====\n        function createDraggableNote() {\n            const note = document.createElement('div');\n            note.className = 'draggable-oval';\n            note.id = 'draggableNote';\n            \n            \/\/ Start near bottom for easier drag distance\n            const startX = (CONFIG.containerWidth - CONFIG.noteWidth) \/ 2;\n            const startY = CONFIG.containerHeight - CONFIG.noteHeight - 20;\n            \n            note.style.left = startX + 'px';\n            note.style.top = startY + 'px';\n            \n            container.appendChild(note);\n        }\n\n        \/\/ ===== EVENT LISTENERS =====\n        function setupEventListeners() {\n            const note = document.getElementById('draggableNote');\n            \n            note.addEventListener('mousedown', startDrag);\n            document.addEventListener('mousemove', drag);\n            document.addEventListener('mouseup', endDrag);\n            \n            note.addEventListener('touchstart', (e) =&gt; {\n                e.preventDefault();\n                startDrag(e.touches&#91;0]);\n            }, { passive: false });\n            \n            document.addEventListener('touchmove', (e) =&gt; {\n                if (gameState.isDragging) {\n                    e.preventDefault();\n                    drag(e.touches&#91;0]);\n                }\n            }, { passive: false });\n            \n            document.addEventListener('touchend', endDrag);\n        }\n\n        \/\/ ===== DRAG HANDLERS =====\n        function startDrag(e) {\n            gameState.isDragging = true;\n            const note = document.getElementById('draggableNote');\n            const rect = note.getBoundingClientRect();\n            \n            gameState.dragOffset.x = e.clientX - rect.left;\n            gameState.dragOffset.y = e.clientY - rect.top;\n            \n            note.style.cursor = 'grabbing';\n            note.style.transition = 'none';\n        }\n\n        function drag(e) {\n            if (!gameState.isDragging) return;\n            \n            const note = document.getElementById('draggableNote');\n            const containerRect = container.getBoundingClientRect();\n            \n            let newX = e.clientX - containerRect.left - gameState.dragOffset.x;\n            let newY = e.clientY - containerRect.top - gameState.dragOffset.y;\n            \n            const maxX = CONFIG.containerWidth - CONFIG.noteWidth;\n            const maxY = CONFIG.containerHeight - CONFIG.noteHeight;\n            \n            newX = Math.max(0, Math.min(newX, maxX));\n            newY = Math.max(0, Math.min(newY, maxY));\n            \n            note.style.left = newX + 'px';\n            note.style.top = newY + 'px';\n        }\n\n        function endDrag() {\n            if (!gameState.isDragging) return;\n            \n            gameState.isDragging = false;\n            const note = document.getElementById('draggableNote');\n            note.style.cursor = 'grab';\n            note.style.transition = 'transform 0.1s ease';\n            \n            checkNotePosition();\n        }\n\n        \/\/ ===== NOTE POSITION CHECKING =====\n        function checkNotePosition() {\n            const note = document.getElementById('draggableNote');\n            const noteTop = parseInt(note.style.top, 10);\n            const noteCenter = noteTop + (CONFIG.noteHeight \/ 2);\n            \n            const targetY = NOTE_POSITIONS&#91;gameState.currentNote];\n            if (targetY === undefined) return;\n            \n            const distance = Math.abs(noteCenter - targetY);\n            \n            if (distance &lt;= CONFIG.tolerance) {\n                \/\/ \u2705 CORRECT! Snap to exact position\n                note.style.top = (targetY - CONFIG.noteHeight\/2) + 'px';\n                showMessage(\"\ud83c\udf89 Correct! Great job!\", false);\n                \n                if (gameState.autoCorrectTimer) clearTimeout(gameState.autoCorrectTimer);\n                gameState.autoCorrectTimer = setTimeout(generateRandomNote, 1500);\n            } else {\n                \/\/ \u274c Try again\n                showMessage(\"\ud83c\udfaf Try again!\", true);\n                setTimeout(() =&gt; {\n                    if (messageEl.textContent &amp;&amp; !gameState.isDragging) {\n                        messageEl.textContent = '';\n                        messageEl.className = 'message';\n                    }\n                }, 2000);\n            }\n        }\n\n        \/\/ ===== SHOW MESSAGE =====\n        function showMessage(text, isError) {\n            messageEl.textContent = text;\n            messageEl.className = 'message show' + (isError ? ' error' : '');\n            \n            if (isError) {\n                setTimeout(() =&gt; {\n                    if (messageEl.textContent === text) {\n                        messageEl.textContent = '';\n                        messageEl.className = 'message';\n                    }\n                }, 2000);\n            }\n        }\n\n        \/\/ ===== GENERATE RANDOM NOTE =====\n        function generateRandomNote() {\n            let available = BEGINNER_NOTES.filter(n =&gt; n !== gameState.previousNote);\n            if (available.length === 0) available = &#91;...BEGINNER_NOTES];\n            \n            gameState.currentNote = available&#91;Math.floor(Math.random() * available.length)];\n            gameState.previousNote = gameState.currentNote;\n            \n            noteDisplay.textContent = `Place: ${NOTE_LABELS&#91;gameState.currentNote]}`;\n            \n            const note = document.getElementById('draggableNote');\n            const startX = (CONFIG.containerWidth - CONFIG.noteWidth) \/ 2;\n            const startY = CONFIG.containerHeight - CONFIG.noteHeight - 20;\n            \n            note.style.transition = 'top 0.3s ease, left 0.3s ease';\n            note.style.left = startX + 'px';\n            note.style.top = startY + 'px';\n            \n            messageEl.textContent = '';\n            messageEl.className = 'message';\n        }\n\n        \/\/ ===== START THE APP =====\n        window.addEventListener('DOMContentLoaded', init);\n    &lt;\/script&gt;\n&lt;\/body&gt;\n&lt;\/html&gt;\n<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n\n\n\n<h2 class=\"wp-block-heading\">How to use the Note Names App<\/h2>\n\n\n\n<p>Once you have audited the code and saved the file, simply double-click it to open it in your default browser.<\/p>\n\n\n\n<p>Instruct your child (or the student you are mentoring) to drag the golden note to the matching note name displayed at the top of the window. The goal of this free music game is to reinforce music theory concepts they have already learned. After the student has identified 10\u201320 notes, you can simply close the browser tab to exit the app. Think of it as a simple, standalone web page.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Supplemental  Information<\/h2>\n\n\n\n<p>I am actively refining this tool; keep an eye on this page for new and improved versions in the coming days. If you have suggestions for improvements, please leave a comment below!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>I am currently developing a series of music education apps. If this is a field that interests you, feel free to take the code below and run it directly in your web browser. Like all the other free JavaScript apps available here on Beginner Projects, this one follows a simple, portable pattern. Getting Started Why [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":474,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_ecmd_meta_description":"Help beginners master Treble Clef note names with this free, interactive music education app. Download the code and run it locally\u2014no registration required.","footnotes":""},"categories":[10],"tags":[],"class_list":["post-470","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-music-education-apps"],"blocksy_meta":[],"_links":{"self":[{"href":"https:\/\/beginnerprojects.com\/cms\/wp-json\/wp\/v2\/posts\/470","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/beginnerprojects.com\/cms\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/beginnerprojects.com\/cms\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/beginnerprojects.com\/cms\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/beginnerprojects.com\/cms\/wp-json\/wp\/v2\/comments?post=470"}],"version-history":[{"count":6,"href":"https:\/\/beginnerprojects.com\/cms\/wp-json\/wp\/v2\/posts\/470\/revisions"}],"predecessor-version":[{"id":485,"href":"https:\/\/beginnerprojects.com\/cms\/wp-json\/wp\/v2\/posts\/470\/revisions\/485"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/beginnerprojects.com\/cms\/wp-json\/wp\/v2\/media\/474"}],"wp:attachment":[{"href":"https:\/\/beginnerprojects.com\/cms\/wp-json\/wp\/v2\/media?parent=470"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/beginnerprojects.com\/cms\/wp-json\/wp\/v2\/categories?post=470"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/beginnerprojects.com\/cms\/wp-json\/wp\/v2\/tags?post=470"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}