{"id":2992,"date":"2026-05-09T00:42:07","date_gmt":"2026-05-08T17:42:07","guid":{"rendered":"https:\/\/nlguitar.com\/?page_id=2992"},"modified":"2026-05-09T22:21:31","modified_gmt":"2026-05-09T15:21:31","slug":"scales","status":"publish","type":"page","link":"https:\/\/nlguitar.com\/en\/scales\/","title":{"rendered":"Scales"},"content":{"rendered":"\t\t<div data-elementor-type=\"masteriyo-course-archive-page\" data-elementor-id=\"2992\" class=\"elementor elementor-2992\" data-elementor-post-type=\"page\">\n\t\t\t\t<div class=\"elementor-element elementor-element-71445cc e-flex e-con-boxed e-con e-parent\" data-id=\"71445cc\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-143ae3c elementor-widget elementor-widget-heading\" data-id=\"143ae3c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t\t<h2 class=\"elementor-heading-title elementor-size-default\">C\u00f4ng C\u1ee5 Tra C\u1ee9u Scale<\/h2>\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-fcab70f elementor-widget elementor-widget-text-editor\" data-id=\"fcab70f\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t\t\t\t\t\t<p>T\u00edch h\u1ee3p h\u1ec7 th\u1ed1ng CAGED v\u00e0 3NPS chu\u1ea9n qu\u1ed1c t\u1ebf v\u1edbi giao di\u1ec7n t\u1ed1i gi\u1ea3n, gi\u00fap b\u1ea1n l\u00e0m ch\u1ee7 m\u1ecdi th\u1ebf tay v\u00e0 b\u1ea3n \u0111\u1ed3 n\u1ed1t nh\u1ea1c tr\u00ean c\u1ea7n \u0111\u00e0n m\u1ed9t c\u00e1ch d\u1ec5 d\u00e0ng nh\u1ea5t.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t<div class=\"elementor-element elementor-element-48d88ca e-flex e-con-boxed e-con e-parent\" data-id=\"48d88ca\" data-element_type=\"container\" data-e-type=\"container\">\n\t\t\t\t\t<div class=\"e-con-inner\">\n\t\t\t\t<div class=\"elementor-element elementor-element-9c74389 elementor-widget elementor-widget-shortcode\" data-id=\"9c74389\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"shortcode.default\">\n\t\t\t\t\t\t\t<div class=\"elementor-shortcode\">\n    <div id=\"nl-scale-app\" class=\"nl-master-wrapper\">\n        \n        <!-- SECTION 1: SELECTION (Flat List - No Tabs) -->\n        <div class=\"nl-section-1-new\">\n            <div class=\"sel-row\">\n                <h4 class=\"sel-title\">Root Note<\/h4>\n                <div id=\"root-btn-group\" class=\"btn-grid-root\"><\/div>\n            <\/div>\n\n            <div class=\"sel-row\">\n                <h4 class=\"sel-title\">Scale Type<\/h4>\n                <div id=\"scale-btn-group\" class=\"btn-grid-scale-full\"><\/div>\n            <\/div>\n        <\/div>\n\n        <!-- SECTION 2: DISPLAY CENTER -->\n        <div class=\"nl-section-2\">\n            <h3 id=\"scale-title-text\">C Major Scale<\/h3>\n            <!-- C\u00f4ng th\u1ee9c \u0111\u1ed5i m\u00e0u \u0111en nh\u1ea1t, kh\u00f4ng n\u1ec1n -->\n            <div id=\"scale-formula\" class=\"scale-formula\">1 - 2 - 3 - 4 - 5 - 6 - 7<\/div>\n            \n            <!-- CONTROL TOGGLES (Inline) -->\n            <div class=\"toggles-wrapper\">\n                \n                <!-- Accidental Toggle -->\n                <div class=\"toggle-group\">\n                    <span class=\"toggle-label\">Key:<\/span>\n                    <div class=\"main-toggle\">\n                        <button class=\"acc-btn active\" data-acc=\"sharp\"># Sharp<\/button>\n                        <button class=\"acc-btn\" data-acc=\"flat\">b Flat<\/button>\n                    <\/div>\n                <\/div>\n\n                <!-- Highlight Toggle -->\n                <div class=\"toggle-group\">\n                    <span class=\"toggle-label\">Highlight:<\/span>\n                    <div class=\"main-toggle\">\n                        <button class=\"hl-btn active\" data-mode=\"all\">All<\/button>\n                        <button class=\"hl-btn\" id=\"hl-caged-btn\" data-mode=\"caged\">CAGED<\/button>\n                        <button class=\"hl-btn\" data-mode=\"tnps\">3NPS<\/button>\n                    <\/div>\n                <\/div>\n\n                <!-- Display Toggle -->\n                <div class=\"toggle-group\">\n                    <span class=\"toggle-label\">Show:<\/span>\n                    <div class=\"main-toggle\">\n                        <button class=\"lbl-btn active\" data-label=\"note\">Notes<\/button>\n                        <button class=\"lbl-btn\" data-label=\"interval\">Intervals<\/button>\n                        <button class=\"lbl-btn\" data-label=\"none\">Hide Notes<\/button>\n                    <\/div>\n                <\/div>\n\n            <\/div>\n\n            <!-- Sub-menus (Hidden by default) -->\n            <div id=\"caged-sub\" class=\"sub-toggle hidden\">\n                <button class=\"sub-btn active\" data-sub=\"C\">C Shape<\/button>\n                <button class=\"sub-btn\" data-sub=\"A\">A Shape<\/button>\n                <button class=\"sub-btn\" data-sub=\"G\">G Shape<\/button>\n                <button class=\"sub-btn\" data-sub=\"E\">E Shape<\/button>\n                <button class=\"sub-btn\" data-sub=\"D\">D Shape<\/button>\n            <\/div>\n            \n            <div id=\"tnps-sub\" class=\"sub-toggle hidden\">\n                <button class=\"sub-btn active\" data-sub=\"1\">Box 1<\/button>\n                <button class=\"sub-btn\" data-sub=\"2\">Box 2<\/button>\n                <button class=\"sub-btn\" data-sub=\"3\">Box 3<\/button>\n                <button class=\"sub-btn\" data-sub=\"4\">Box 4<\/button>\n                <button class=\"sub-btn\" data-sub=\"5\">Box 5<\/button>\n                <button class=\"sub-btn\" data-sub=\"6\">Box 6<\/button>\n                <button class=\"sub-btn\" data-sub=\"7\">Box 7<\/button>\n            <\/div>\n        <\/div>\n\n        <!-- SECTION 3: FRETBOARD -->\n        <div class=\"nl-section-3\">\n            <div class=\"fretboard-viewport\">\n                <div id=\"fretboard-grid\" class=\"fretboard-grid\"><\/div>\n            <\/div>\n        <\/div>\n\n    <\/div>\n\n    <style>\n        .nl-master-wrapper { background: #fff; padding: 30px; border: 1px solid #e2e8f0; border-radius: 8px; font-family: -apple-system, sans-serif; color: #1e293b; width: 100%; box-sizing: border-box; }\n        \n        .nl-section-1-new { display: flex; flex-direction: column; gap: 25px; margin-bottom: 25px; border-bottom: 1px solid #f1f5f9; padding-bottom: 25px; }\n        .sel-row { display: flex; flex-direction: column; align-items: center; gap: 15px; width: 100%; }\n        \n        .sel-title { font-size: 16px; font-weight: 800; color: #475569; margin: 0; text-transform: uppercase; letter-spacing: 1.5px; text-align: center; }\n        \n        .btn-grid-root { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; max-width: 900px; }\n        .btn-grid-scale-full { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; max-width: 900px; }\n        \n        .root-btn { width: 40px; height: 40px; border-radius: 50%; border: 1px solid #cbd5e1; background: #f8fafc; color: #475569; font-weight: 700; font-size: 13px; cursor: pointer; transition: all 0.2s ease; display: flex; align-items: center; justify-content: center; padding: 0; }\n        .root-btn:hover { background: #e2e8f0; color: #2563eb; }\n        .root-btn.active { background: #2563eb; color: #fff; border-color: #2563eb; box-shadow: 0 3px 8px rgba(37,99,235,0.3); }\n\n        .scl-btn { padding: 8px 16px; border-radius: 20px; border: 1px solid #cbd5e1; background: #f8fafc; color: #475569; font-weight: 600; font-size: 13px; cursor: pointer; transition: all 0.2s ease; margin-bottom: 2px; }\n        .scl-btn:hover { background: #e2e8f0; color: #2563eb; }\n        .scl-btn.active { background: #2563eb; color: #fff; border-color: #2563eb; box-shadow: 0 3px 8px rgba(37,99,235,0.3); }\n\n        .nl-section-2 { display: flex; flex-direction: column; align-items: center; justify-content: center; margin: 20px 0 40px 0; text-align: center; }\n        #scale-title-text { margin: 0 0 10px 0; font-size: 32px; font-weight: 800; color: #0f172a; }\n        \n        .scale-formula { font-size: 18px; font-weight: 700; color: #64748b; margin-bottom: 30px; letter-spacing: 3px; }\n        \n        .toggles-wrapper { display: flex; justify-content: center; gap: 30px; flex-wrap: wrap; margin-bottom: 15px; }\n        .toggle-group { display: flex; align-items: center; gap: 10px; }\n        .toggle-label { font-size: 13px; color: #64748b; font-weight: 700; }\n        \n        .main-toggle { display: flex; background: #ffffff; border: 2px solid #bfdbfe; border-radius: 24px; padding: 4px; gap: 4px; }\n        .hl-btn, .lbl-btn, .acc-btn { border: none; padding: 8px 20px; border-radius: 20px; cursor: pointer; font-size: 13px; font-weight: 700; background: transparent; color: #60a5fa; transition: all 0.2s ease; }\n        .hl-btn:hover, .lbl-btn:hover, .acc-btn:hover { color: #2563eb; background: #eff6ff; }\n        .hl-btn.active, .lbl-btn.active, .acc-btn.active { background: #2563eb; color: #ffffff; box-shadow: 0 2px 6px rgba(37,99,235,0.25); }\n\n        .sub-toggle { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; margin-top: 15px; }\n        .sub-toggle.hidden { display: none; }\n        .sub-btn { border: 1px solid #cbd5e1; padding: 8px 18px; border-radius: 16px; cursor: pointer; font-size: 12px; font-weight: bold; background: #f8fafc; color: #475569; transition: all 0.2s ease; }\n        .sub-btn:hover { background: #e2e8f0; }\n        .sub-btn.active { background: #2563eb; color: #fff; border-color: #2563eb; }\n\n        .nl-section-3 { padding: 0; width: 100%; }\n        .fretboard-viewport { overflow-x: auto; padding: 20px 0 60px 0; display: flex; justify-content: flex-start; -webkit-overflow-scrolling: touch; cursor: grab; }\n        @media (min-width: 1024px) { .fretboard-viewport { justify-content: center; } }\n        \n        .fretboard-grid { position: relative; width: max-content; display: flex; }\n\n        .fret-column { position: relative; display: flex; flex-direction: column; width: 65px; box-sizing: border-box; }\n        .fret-cell { position: relative; width: 100%; height: 40px; box-sizing: border-box; border-right: 1.5px solid #0f172a; border-bottom: 1.5px solid #0f172a; }\n        .fret-cell.top-string { border-top: 1.5px solid #0f172a; } \n        .fret-column.nut-column { width: 45px; }\n        .fret-column.nut-column .fret-cell { border-right: 8px solid #0f172a; border-top-color: transparent; border-bottom-color: transparent; }\n\n        .inlay-dot { position: absolute; width: 14px; height: 14px; background: #e2e8f0; border-radius: 50%; left: 50%; top: 50%; transform: translate(-50%, -50%); z-index: 0; }\n\n        .note-dot { \n            width: 30px; height: 30px; border-radius: 50%; display: flex; align-items: center; justify-content: center; \n            font-size: 11px; font-weight: 800; color: #fff; z-index: 10; position: absolute; \n            left: 50%; top: 100%; transform: translate(-50%, -50%); box-shadow: 0 2px 4px rgba(0,0,0,0.25);\n        }\n        .note-dot.s1 { top: 0%; }\n        .note-dot.root { background: #ef4444; border: 2px solid #fff; } \n        .note-dot.normal { background: #0f172a; } \n        .note-dot.hidden-note { opacity: 0; pointer-events: none; display: none !important; }\n\n        .fret-label { position: absolute; bottom: -35px; font-size: 12px; font-weight: bold; color: #94a3b8; width: 100%; text-align: center; }\n\n        @media (max-width: 768px) {\n            .nl-master-wrapper { padding: 15px; }\n            .toggles-wrapper { gap: 15px; flex-direction: column; }\n            .toggle-group { flex-direction: column; align-items: center; gap: 5px; }\n            .hl-btn, .lbl-btn, .acc-btn { padding: 8px 14px; font-size: 12px; }\n            .root-btn { width: 34px; height: 34px; font-size: 12px; }\n            #scale-title-text { font-size: 24px; }\n            .scale-formula { font-size: 15px; }\n        }\n    <\/style>\n\n    <script>\n    (function() {\n        const MAX_FRETS = 17; \n        const inlays = [3, 5, 7, 9, 12, 15, 17];\n\n        const notesSharp = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'];\n        const notesFlat  = ['C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'B'];\n        const tuning = [4, 11, 7, 2, 9, 4];\n        const basePitches = [64, 59, 55, 50, 45, 40]; \n        \n        const allScales = {\n            'Major': [0, 2, 4, 5, 7, 9, 11],\n            'Minor': [0, 2, 3, 5, 7, 8, 10],\n            'Harmonic Minor': [0, 2, 3, 5, 7, 8, 11],\n            'Melodic Minor': [0, 2, 3, 5, 7, 9, 11],\n            'Major Pentatonic': [0, 2, 4, 7, 9],\n            'Minor Pentatonic': [0, 3, 5, 7, 10],\n            'Major Blues': [0, 2, 3, 4, 7, 9],\n            'Minor Blues': [0, 3, 5, 6, 7, 10],\n            'Ionian': [0, 2, 4, 5, 7, 9, 11],\n            'Dorian': [0, 2, 3, 5, 7, 9, 10],\n            'Phrygian': [0, 1, 3, 5, 7, 8, 10],\n            'Lydian': [0, 2, 4, 6, 7, 9, 11],\n            'Mixolydian': [0, 2, 4, 5, 7, 9, 10],\n            'Aeolian': [0, 2, 3, 5, 7, 8, 10],\n            'Locrian': [0, 1, 3, 5, 6, 8, 10],\n            'Diminished': [0, 2, 3, 5, 6, 8, 9, 11]\n        };\n\n        \/\/ Ph\u00e2n t\u00e1ch m\u1ea3ng Interval d\u1ef1a theo d\u1ea5u h\u00f3a\n        const intervalsSharp = ['1', 'b2', '2', 'b3', '3', '4', '#4', '5', 'b6', '6', 'b7', '7'];\n        const intervalsFlat  = ['1', 'b2', '2', 'b3', '3', '4', 'b5', '5', 'b6', '6', 'b7', '7'];\n\n        const grid = document.getElementById('fretboard-grid');\n        const titleText = document.getElementById('scale-title-text');\n        const formulaText = document.getElementById('scale-formula');\n        const cagedSub = document.getElementById('caged-sub');\n        const tnpsSub = document.getElementById('tnps-sub');\n        const hlCagedBtn = document.getElementById('hl-caged-btn'); \n\n        let mainMode = 'all'; \n        let currentCaged = 'C';\n        let currentTnps = '1';\n        let currentLabelMode = 'note';\n        let currentAccidental = 'sharp'; \n\n        let selectedRootIdx = 0; \n        let selectedScale = 'Major';\n        let activeNotes = notesSharp;\n\n        function getAutoAccidental(rootIdx, scaleType) {\n            const minorTypes = ['Minor', 'Harmonic Minor', 'Melodic Minor', 'Minor Pentatonic', 'Minor Blues', 'Dorian', 'Phrygian', 'Locrian', 'Aeolian'];\n            const isMinor = minorTypes.includes(scaleType);\n            \n            if (isMinor) {\n                const minorFlatIndices = [0, 2, 3, 5, 7, 8, 10];\n                return minorFlatIndices.includes(rootIdx) ? 'flat' : 'sharp';\n            } else {\n                const majorFlatIndices = [1, 3, 5, 8, 10];\n                return majorFlatIndices.includes(rootIdx) ? 'flat' : 'sharp';\n            }\n        }\n\n        function autoSetAccidental() {\n            const newAcc = getAutoAccidental(selectedRootIdx, selectedScale);\n            currentAccidental = newAcc;\n            activeNotes = currentAccidental === 'sharp' ? notesSharp : notesFlat;\n            \n            document.querySelectorAll('.acc-btn').forEach(b => {\n                b.classList.toggle('active', b.dataset.acc === currentAccidental);\n            });\n        }\n\n        function renderSelection() {\n            const rootGroup = document.getElementById('root-btn-group');\n            const scaleGroup = document.getElementById('scale-btn-group');\n            \n            rootGroup.innerHTML = '';\n            activeNotes.forEach((n, idx) => {\n                const btn = document.createElement('button');\n                btn.className = `root-btn ${idx === selectedRootIdx ? 'active' : ''}`;\n                btn.innerText = n;\n                btn.onclick = () => {\n                    selectedRootIdx = idx;\n                    autoSetAccidental();\n                    renderSelection();\n                    render();\n                };\n                rootGroup.appendChild(btn);\n            });\n\n            scaleGroup.innerHTML = '';\n            Object.keys(allScales).forEach(scl => {\n                const btn = document.createElement('button');\n                btn.className = `scl-btn ${scl === selectedScale ? 'active' : ''}`;\n                btn.innerText = scl;\n                btn.onclick = () => {\n                    selectedScale = scl;\n                    autoSetAccidental(); \n                    renderSelection(); \n                    render();\n                };\n                scaleGroup.appendChild(btn);\n            });\n        }\n\n        function getTNPSNotes(rootIdx, pattern, boxIndex) {\n            let tnpsSet = [];\n            let currentScaleIdx = boxIndex - 1; \n            let targetNoteIdx = (rootIdx + pattern[currentScaleIdx % pattern.length]) % 12;\n            let startFret = -1;\n            for (let f = 1; f <= MAX_FRETS + 4; f++) { \n                if ((tuning[5] + f) % 12 === targetNoteIdx) { startFret = f; break; }\n            }\n            if(startFret === -1) return [];\n\n            let currentFretAnchor = startFret;\n            for(let s = 5; s >= 0; s--) {\n                let notesOnString = 0;\n                let f = Math.max(1, currentFretAnchor - 2); \n                while(notesOnString < 3 && f <= MAX_FRETS + 6) { \n                    let noteName = activeNotes[(tuning[s] + f) % 12];\n                    let tNoteName = activeNotes[(rootIdx + pattern[currentScaleIdx % pattern.length]) % 12];\n                    if (noteName === tNoteName) {\n                        tnpsSet.push({s: s, f: f});\n                        notesOnString++;\n                        currentScaleIdx++;\n                        if (notesOnString === 1) currentFretAnchor = f; \n                    }\n                    f++;\n                }\n            }\n            return tnpsSet;\n        }\n\n        function render() {\n            grid.innerHTML = '';\n            const root = activeNotes[selectedRootIdx];\n            const type = selectedScale;\n            const pattern = allScales[type]; \n            const scaleNotes = pattern.map(p => activeNotes[(selectedRootIdx + p) % 12]);\n            \n            \/\/ X\u1eed l\u00fd Dynamic Interval\n            const activeIntervals = currentAccidental === 'sharp' ? intervalsSharp : intervalsFlat;\n            const intervalMap = {};\n            pattern.forEach(p => intervalMap[activeNotes[(selectedRootIdx + p) % 12]] = activeIntervals[p]);\n\n            titleText.innerText = `${root} ${type} Scale`;\n            formulaText.innerText = pattern.map(p => activeIntervals[p]).join(' - ');\n\n            const minorTypes = ['Minor', 'Harmonic Minor', 'Melodic Minor', 'Minor Pentatonic', 'Minor Blues', 'Dorian', 'Phrygian', 'Locrian', 'Aeolian'];\n            const isExtendedMinor = ['Harmonic Minor', 'Melodic Minor'].includes(type);\n            const isBlues = ['Major Blues', 'Minor Blues'].includes(type);\n            \n            const strictScales = ['Major', 'Minor', 'Harmonic Minor', 'Melodic Minor', 'Major Pentatonic', 'Minor Pentatonic', 'Major Blues', 'Minor Blues', 'Ionian', 'Dorian', 'Phrygian', 'Lydian', 'Mixolydian', 'Aeolian', 'Locrian', 'Diminished'];\n            \n            const isMinor = minorTypes.includes(type);\n            const isStrictCaged = strictScales.includes(type);\n            \n            if (hlCagedBtn) hlCagedBtn.innerText = isMinor ? 'Pattern' : 'CAGED';\n\n            const patternMap = { 'G': 'Pattern 1', 'E': 'Pattern 2', 'D': 'Pattern 3', 'C': 'Pattern 4', 'A': 'Pattern 5' };\n            document.querySelectorAll('#caged-sub .sub-btn').forEach(btn => {\n                const sub = btn.dataset.sub;\n                btn.innerText = isMinor ? patternMap[sub] : sub + ' Shape';\n            });\n\n            let validSpans = [];\n            let activeTnpsNotes = [];\n            let cagedNotesToDraw = new Set();\n\n            if (mainMode === 'caged') {\n                const defaultSpans = { 'E': {s:-1, e:2}, 'D': {s:1, e:5}, 'C': {s:4, e:7}, 'A': {s:6, e:10}, 'G': {s:9, e:12} };\n                const hmSpans = { 'E': {s:-2, e:2}, 'D': {s:1, e:5}, 'C': {s:3, e:7}, 'A': {s:6, e:10}, 'G': {s:8, e:12} };\n                const bluesSpans = { 'E': {s:-1, e:3}, 'D': {s:1, e:5}, 'C': {s:4, e:8}, 'A': {s:6, e:10}, 'G': {s:8, e:12} };\n\n                let cagedSpans = defaultSpans;\n                if (isExtendedMinor) cagedSpans = hmSpans;\n                else if (isBlues) cagedSpans = bluesSpans;\n\n                let majRootFret = selectedRootIdx >= 4 ? selectedRootIdx - 4 : selectedRootIdx + 8; \n                if (isMinor) majRootFret = (majRootFret + 3) % 12;\n\n                let spanInfo = { s: cagedSpans[currentCaged].s, e: cagedSpans[currentCaged].e };\n                \n                if (!isStrictCaged) {\n                    spanInfo.s -= 1;\n                    spanInfo.e += 1;\n                }\n\n                let targetOffset = null;\n                for (let offset of [-24, -12, 0, 12, 24]) {\n                    let start = majRootFret + offset + spanInfo.s;\n                    let end = majRootFret + offset + spanInfo.e;\n                    if (start >= 1 && end <= MAX_FRETS) { targetOffset = offset; break; }\n                }\n                if (targetOffset === null) {\n                    for (let offset of [-24, -12, 0, 12, 24]) {\n                        let start = majRootFret + offset + spanInfo.s;\n                        if (start >= 1) { targetOffset = offset; break; }\n                    }\n                }\n                if (targetOffset !== null) {\n                    validSpans.push({ s: majRootFret + targetOffset + spanInfo.s, e: majRootFret + targetOffset + spanInfo.e });\n                }\n\n                let candidates = [];\n                for (let f = 1; f <= MAX_FRETS; f++) {\n                    let inSpan = validSpans.some(span => f >= span.s && f <= span.e);\n                    if (!inSpan) continue;\n                    for (let s = 0; s < 6; s++) {\n                        const noteName = activeNotes[(tuning[s] + f) % 12];\n                        if (scaleNotes.includes(noteName)) {\n                            candidates.push({ s: s, f: f, pitch: basePitches[s] + f });\n                        }\n                    }\n                }\n\n                if (candidates.length > 0) {\n                    let avgFret = candidates.reduce((sum, c) => sum + c.f, 0) \/ candidates.length;\n                    \n                    let pitchGroups = new Map();\n                    for (let c of candidates) {\n                        if (!pitchGroups.has(c.pitch)) pitchGroups.set(c.pitch, []);\n                        pitchGroups.get(c.pitch).push(c);\n                    }\n\n                    let sortedPitches = Array.from(pitchGroups.keys()).sort((a, b) => a - b);\n\n                    for (let i = 0; i < sortedPitches.length; i++) {\n                        let pitch = sortedPitches[i];\n                        let group = pitchGroups.get(pitch);\n                        \n                        if (group.length === 1) {\n                            cagedNotesToDraw.add(`${group[0].s}_${group[0].f}`);\n                        } else {\n                            let bestNote = group[0];\n                            let minDist = 999;\n                            let bestDistToAvg = 999;\n                            \n                            let nextPitch = sortedPitches[i + 1];\n                            let nextGroup = nextPitch ? pitchGroups.get(nextPitch) : null;\n                            \n                            let prevPitch = sortedPitches[i - 1];\n                            let prevGroup = prevPitch ? pitchGroups.get(prevPitch) : null;\n\n                            for (let cand of group) {\n                                let localMin = 999;\n                                \n                                if (prevGroup) {\n                                    for (let compCand of prevGroup) {\n                                        let d = Math.abs(cand.f - compCand.f);\n                                        if (d < localMin) localMin = d;\n                                    }\n                                }\n                                \n                                if (nextGroup) {\n                                    for (let compCand of nextGroup) {\n                                        let d = Math.abs(cand.f - compCand.f);\n                                        if (d < localMin) localMin = d;\n                                    }\n                                }\n\n                                let distToAvg = Math.abs(cand.f - avgFret);\n\n                                if (localMin < minDist) {\n                                    minDist = localMin;\n                                    bestNote = cand;\n                                    bestDistToAvg = distToAvg;\n                                } else if (localMin === minDist) {\n                                    if (distToAvg < bestDistToAvg) {\n                                        bestNote = cand;\n                                        bestDistToAvg = distToAvg;\n                                    } else if (distToAvg === bestDistToAvg) {\n                                        if (cand.s > bestNote.s) { \n                                            bestNote = cand;\n                                        }\n                                    }\n                                }\n                            }\n                            cagedNotesToDraw.add(`${bestNote.s}_${bestNote.f}`);\n                        }\n                    }\n                }\n            } else if (mainMode === 'tnps') {\n                activeTnpsNotes = getTNPSNotes(selectedRootIdx, pattern, parseInt(currentTnps));\n            }\n\n            for (let f = 0; f <= MAX_FRETS; f++) { \n                const col = document.createElement('div');\n                col.className = 'fret-column';\n                if (f === 0) col.classList.add('nut-column');\n\n                for (let s = 0; s < 5; s++) {\n                    const cell = document.createElement('div');\n                    cell.className = 'fret-cell' + (s === 0 ? ' top-string' : '');\n                    \n                    if (inlays.includes(f) && f !== 0) {\n                        if (f === 12) {\n                            if (s === 1 || s === 3) { const dot = document.createElement('div'); dot.className = 'inlay-dot'; cell.appendChild(dot); }\n                        } else {\n                            if (s === 2) { const dot = document.createElement('div'); dot.className = 'inlay-dot'; cell.appendChild(dot); }\n                        }\n                    }\n\n                    [s, s+1].forEach(si => {\n                        if (si === s && s !== 0) return;\n                        const noteName = activeNotes[(tuning[si] + f) % 12];\n                        \n                        if (scaleNotes.includes(noteName)) {\n                            let isVisible = true;\n                            \n                            if (mainMode === 'caged') {\n                                if (f === 0) isVisible = false; \n                                else isVisible = cagedNotesToDraw.has(`${si}_${f}`);\n                                \n                                if (!isStrictCaged) {\n                                    isVisible = validSpans.some(span => f >= span.s && f <= span.e) && f !== 0;\n                                }\n                            } else if (mainMode === 'tnps') {\n                                isVisible = activeTnpsNotes.some(n => n.s === si && n.f === f);\n                            }\n                            \n                            const dot = document.createElement('div');\n                            dot.className = `note-dot ${noteName === root ? 'root' : 'normal'} ${isVisible ? '' : 'hidden-note'}`;\n                            if (si === 0) dot.classList.add('s1');\n                            \n                            if (isVisible && currentLabelMode !== 'none') {\n                                dot.innerText = (currentLabelMode === 'note') ? noteName : intervalMap[noteName];\n                            }\n                            cell.appendChild(dot);\n                        }\n                    });\n                    col.appendChild(cell);\n                }\n                \n                const num = document.createElement('div'); \n                num.className = 'fret-label'; \n                if (inlays.includes(f)) {\n                    num.innerText = f; \n                }\n                col.appendChild(num);\n                grid.appendChild(col);\n            }\n        }\n\n        document.querySelectorAll('.hl-btn').forEach(btn => {\n            btn.onclick = () => {\n                document.querySelectorAll('.hl-btn').forEach(b => b.classList.remove('active'));\n                btn.classList.add('active');\n                mainMode = btn.dataset.mode;\n                cagedSub.classList.toggle('hidden', mainMode !== 'caged');\n                tnpsSub.classList.toggle('hidden', mainMode !== 'tnps');\n                render();\n            };\n        });\n\n        document.querySelectorAll('.sub-btn').forEach(btn => {\n            btn.onclick = () => {\n                btn.parentElement.querySelectorAll('.sub-btn').forEach(b => b.classList.remove('active'));\n                btn.classList.add('active');\n                if (btn.parentElement.id === 'caged-sub') currentCaged = btn.dataset.sub;\n                else currentTnps = btn.dataset.sub;\n                render();\n            };\n        });\n\n        document.querySelectorAll('.lbl-btn').forEach(btn => {\n            btn.onclick = () => {\n                document.querySelectorAll('.lbl-btn').forEach(b => b.classList.remove('active'));\n                btn.classList.add('active');\n                currentLabelMode = btn.dataset.label;\n                render();\n            };\n        });\n\n        document.querySelectorAll('.acc-btn').forEach(btn => {\n            btn.onclick = () => {\n                document.querySelectorAll('.acc-btn').forEach(b => b.classList.remove('active'));\n                btn.classList.add('active');\n                currentAccidental = btn.dataset.acc;\n                activeNotes = currentAccidental === 'sharp' ? notesSharp : notesFlat;\n                \n                const currentRootNoteStr = document.querySelector('.root-btn.active').innerText;\n                renderSelection();\n                \n                let newIdx = selectedRootIdx;\n                activeNotes.forEach((n, idx) => {\n                    if (n === currentRootNoteStr || (n === 'D#' && currentRootNoteStr === 'Eb')) {}\n                });\n                render();\n            };\n        });\n\n        autoSetAccidental();\n        renderSelection();\n        render();\n    })();\n    <\/script>\n    <\/div>\n\t\t\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>C\u00f4ng C\u1ee5 Tra C\u1ee9u Scale T\u00edch h\u1ee3p h\u1ec7 th\u1ed1ng CAGED v\u00e0 3NPS chu\u1ea9n qu\u1ed1c t\u1ebf v\u1edbi giao di\u1ec7n t\u1ed1i gi\u1ea3n, gi\u00fap b\u1ea1n l\u00e0m ch\u1ee7 m\u1ecdi th\u1ebf tay v\u00e0 b\u1ea3n \u0111\u1ed3 n\u1ed1t nh\u1ea1c tr\u00ean c\u1ea7n \u0111\u00e0n m\u1ed9t c\u00e1ch d\u1ec5 d\u00e0ng nh\u1ea5t.<\/p>","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"elementor_header_footer","meta":{"footnotes":""},"class_list":["post-2992","page","type-page","status-publish","hentry"],"blocksy_meta":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.5 (Yoast SEO v27.5) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Scales - NL Guitar<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/nlguitar.com\/en\/scales\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Scales\" \/>\n<meta property=\"og:description\" content=\"C\u00f4ng C\u1ee5 Tra C\u1ee9u Scale T\u00edch h\u1ee3p h\u1ec7 th\u1ed1ng CAGED v\u00e0 3NPS chu\u1ea9n qu\u1ed1c t\u1ebf v\u1edbi giao di\u1ec7n t\u1ed1i gi\u1ea3n, gi\u00fap b\u1ea1n l\u00e0m ch\u1ee7 m\u1ecdi th\u1ebf tay v\u00e0 b\u1ea3n \u0111\u1ed3 n\u1ed1t nh\u1ea1c tr\u00ean c\u1ea7n \u0111\u00e0n m\u1ed9t c\u00e1ch d\u1ec5 d\u00e0ng nh\u1ea5t.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/nlguitar.com\/en\/scales\/\" \/>\n<meta property=\"og:site_name\" content=\"NL Guitar\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/nlguitarclass\/\" \/>\n<meta property=\"article:modified_time\" content=\"2026-05-09T15:21:31+00:00\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/nlguitar.com\\\/scales\\\/\",\"url\":\"https:\\\/\\\/nlguitar.com\\\/scales\\\/\",\"name\":\"Scales - NL Guitar\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/nlguitar.com\\\/#website\"},\"datePublished\":\"2026-05-08T17:42:07+00:00\",\"dateModified\":\"2026-05-09T15:21:31+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/nlguitar.com\\\/scales\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/nlguitar.com\\\/scales\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/nlguitar.com\\\/scales\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/nlguitar.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Scales\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/nlguitar.com\\\/#website\",\"url\":\"https:\\\/\\\/nlguitar.com\\\/\",\"name\":\"NL Guitar\",\"description\":\"Kh\u00f3a h\u1ecdc Guitar Online, Tabs &amp; S\u00e1ch Guitar Chuy\u00ean s\u00e2u\",\"publisher\":{\"@id\":\"https:\\\/\\\/nlguitar.com\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/nlguitar.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Organization\",\"Place\"],\"@id\":\"https:\\\/\\\/nlguitar.com\\\/#organization\",\"name\":\"NL Guitar\",\"alternateName\":\"NL Guitar Class\",\"url\":\"https:\\\/\\\/nlguitar.com\\\/\",\"logo\":{\"@id\":\"https:\\\/\\\/nlguitar.com\\\/scales\\\/#local-main-organization-logo\"},\"image\":{\"@id\":\"https:\\\/\\\/nlguitar.com\\\/scales\\\/#local-main-organization-logo\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/nlguitarclass\\\/\"],\"description\":\"Chuy\u00ean cung c\u1ea5p c\u00e1c kho\u00e1 h\u1ecdc Guitar chuy\u00ean nghi\u1ec7p, Guitar Tabs, S\u00e1ch v\u00e0 Gi\u00e1o Tr\u00ecnh\",\"telephone\":[],\"openingHoursSpecification\":[{\"@type\":\"OpeningHoursSpecification\",\"dayOfWeek\":[\"Monday\",\"Tuesday\",\"Wednesday\",\"Thursday\",\"Friday\",\"Saturday\",\"Sunday\"],\"opens\":\"09:00\",\"closes\":\"17:00\"}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/nlguitar.com\\\/scales\\\/#local-main-organization-logo\",\"url\":\"https:\\\/\\\/nlguitar.com\\\/wp-content\\\/uploads\\\/2026\\\/04\\\/cropped-Logo-26-2.png\",\"contentUrl\":\"https:\\\/\\\/nlguitar.com\\\/wp-content\\\/uploads\\\/2026\\\/04\\\/cropped-Logo-26-2.png\",\"width\":512,\"height\":512,\"caption\":\"NL Guitar\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Scales - NL Guitar","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/nlguitar.com\/en\/scales\/","og_locale":"en_US","og_type":"article","og_title":"Scales","og_description":"C\u00f4ng C\u1ee5 Tra C\u1ee9u Scale T\u00edch h\u1ee3p h\u1ec7 th\u1ed1ng CAGED v\u00e0 3NPS chu\u1ea9n qu\u1ed1c t\u1ebf v\u1edbi giao di\u1ec7n t\u1ed1i gi\u1ea3n, gi\u00fap b\u1ea1n l\u00e0m ch\u1ee7 m\u1ecdi th\u1ebf tay v\u00e0 b\u1ea3n \u0111\u1ed3 n\u1ed1t nh\u1ea1c tr\u00ean c\u1ea7n \u0111\u00e0n m\u1ed9t c\u00e1ch d\u1ec5 d\u00e0ng nh\u1ea5t.","og_url":"https:\/\/nlguitar.com\/en\/scales\/","og_site_name":"NL Guitar","article_publisher":"https:\/\/www.facebook.com\/nlguitarclass\/","article_modified_time":"2026-05-09T15:21:31+00:00","twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/nlguitar.com\/scales\/","url":"https:\/\/nlguitar.com\/scales\/","name":"Scales - NL Guitar","isPartOf":{"@id":"https:\/\/nlguitar.com\/#website"},"datePublished":"2026-05-08T17:42:07+00:00","dateModified":"2026-05-09T15:21:31+00:00","breadcrumb":{"@id":"https:\/\/nlguitar.com\/scales\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/nlguitar.com\/scales\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/nlguitar.com\/scales\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/nlguitar.com\/"},{"@type":"ListItem","position":2,"name":"Scales"}]},{"@type":"WebSite","@id":"https:\/\/nlguitar.com\/#website","url":"https:\/\/nlguitar.com\/","name":"NL Guitar","description":"Kh\u00f3a h\u1ecdc Guitar Online, Tabs &amp; S\u00e1ch Guitar Chuy\u00ean s\u00e2u","publisher":{"@id":"https:\/\/nlguitar.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/nlguitar.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Organization","Place"],"@id":"https:\/\/nlguitar.com\/#organization","name":"NL Guitar","alternateName":"NL Guitar Class","url":"https:\/\/nlguitar.com\/","logo":{"@id":"https:\/\/nlguitar.com\/scales\/#local-main-organization-logo"},"image":{"@id":"https:\/\/nlguitar.com\/scales\/#local-main-organization-logo"},"sameAs":["https:\/\/www.facebook.com\/nlguitarclass\/"],"description":"Chuy\u00ean cung c\u1ea5p c\u00e1c kho\u00e1 h\u1ecdc Guitar chuy\u00ean nghi\u1ec7p, Guitar Tabs, S\u00e1ch v\u00e0 Gi\u00e1o Tr\u00ecnh","telephone":[],"openingHoursSpecification":[{"@type":"OpeningHoursSpecification","dayOfWeek":["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"],"opens":"09:00","closes":"17:00"}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/nlguitar.com\/scales\/#local-main-organization-logo","url":"https:\/\/nlguitar.com\/wp-content\/uploads\/2026\/04\/cropped-Logo-26-2.png","contentUrl":"https:\/\/nlguitar.com\/wp-content\/uploads\/2026\/04\/cropped-Logo-26-2.png","width":512,"height":512,"caption":"NL Guitar"}]}},"_hostinger_reach_plugin_has_subscription_block":false,"_hostinger_reach_plugin_is_elementor":false,"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/nlguitar.com\/en\/wp-json\/wp\/v2\/pages\/2992","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nlguitar.com\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/nlguitar.com\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/nlguitar.com\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/nlguitar.com\/en\/wp-json\/wp\/v2\/comments?post=2992"}],"version-history":[{"count":23,"href":"https:\/\/nlguitar.com\/en\/wp-json\/wp\/v2\/pages\/2992\/revisions"}],"predecessor-version":[{"id":3039,"href":"https:\/\/nlguitar.com\/en\/wp-json\/wp\/v2\/pages\/2992\/revisions\/3039"}],"wp:attachment":[{"href":"https:\/\/nlguitar.com\/en\/wp-json\/wp\/v2\/media?parent=2992"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}