��<!DOCTYPE html> <html lang="en"> <head> <meta charset='UTF-8'> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Morse Code Translator ��� Text to Morse Code Generator | FancySymbols</title> <meta name="description" content="Translate text to Morse code and Morse code to text instantly. Free online Morse code translator with audio playback, speed/pitch/volume controls. Copy and paste Morse code."> <link rel='canonical' href='https://fancysymbols.com/morse-code'> <meta property="og:type" content="website"> <meta property="og:url" content="https://fancysymbols.com/morse-code"> <meta property="og:title" content="Morse Code Translator ��� Text to Morse Code"> <meta property="og:description" content="Translate text to Morse code instantly with audio playback."> <meta name="twitter:card" content="summary_large_image"> <link rel="icon" href="favicon.png" type="image/png"> <link href="https://fonts.googleapis.com/css2?family=Outfit:wght@400;500;600;700;800&display=swap" rel="stylesheet"> <link rel="stylesheet" href="style.css?v=5.5"> <style> .morse-app { max-width: 900px; margin: 0 auto; padding: 0 1rem; } /* Input / Output panels */ .morse-io { display: flex; flex-direction: column; gap: 0; } @media(min-width:768px) { .morse-io { flex-direction: row; gap: 1.5rem; } } .morse-panel-left { flex: 1; } .morse-panel-right { display: flex; gap: 1rem; } .morse-sliders { display: flex; gap: 1rem; } .morse-label { font-size: 0.85rem; font-weight: 600; color: #6366f1; margin-bottom: 0.4rem; display: block; } .morse-textarea { width: 100%; min-height: 140px; background: #f1f5f9; border: 2px solid #e2e8f0; border-radius: 12px; padding: 1rem; color: #0f172a; font-family: 'Courier New', monospace; font-size: 1.05rem; resize: vertical; outline: none; transition: border-color .2s; } .morse-textarea:focus { border-color: #6366f1; } /* Vertical Sliders */ .slider-group { display: flex; flex-direction: column; align-items: center; gap: 0.3rem; background: #f1f5f9; border-radius: 12px; padding: 0.75rem 0.5rem; } .slider-title { font-size: 0.7rem; font-weight: 700; color: #64748b; text-transform: uppercase; letter-spacing: 0.5px; } .slider-val { font-size: 0.85rem; font-weight: 700; color: #0f172a; } .v-slider { writing-mode: vertical-lr; direction: rtl; -webkit-appearance: none; appearance: none; width: 120px; height: 6px; background: #cbd5e1; border-radius: 4px; outline: none; } .v-slider::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 18px; height: 18px; border-radius: 50%; background: #6366f1; cursor: pointer; border: 3px solid #fff; box-shadow: 0 2px 8px rgba(99,102,241,0.4); } .v-slider::-moz-range-thumb { width: 18px; height: 18px; border-radius: 50%; background: #6366f1; cursor: pointer; border: 3px solid #fff; box-shadow: 0 2px 8px rgba(99,102,241,0.4); } /* Control Buttons */ .morse-controls { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 1.25rem; justify-content: center; } .ctrl-btn { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 0.25rem; padding: 0.65rem 0.85rem; border-radius: 12px; border: 2px solid #e2e8f0; background: #f8fafc; color: #334155; font-size: 0.7rem; font-weight: 600; cursor: pointer; transition: all .2s; min-width: 64px; text-transform: uppercase; letter-spacing: 0.3px; } .ctrl-btn svg { width: 22px; height: 22px; } .ctrl-btn:hover { background: #e2e8f0; border-color: #cbd5e1; transform: translateY(-1px); } .ctrl-btn.active { background: #6366f1; color: #fff; border-color: #6366f1; } .ctrl-btn.active:hover { background: #4f46e5; } .ctrl-btn.playing { background: #059669; color: #fff; border-color: #059669; } /* Light flash overlay */ .flash-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: #fff; opacity: 0; pointer-events: none; z-index: 9999; transition: opacity 0.05s; } .flash-overlay.on { opacity: 0.85; } /* Swap button */ .swap-row { display: flex; justify-content: center; margin: 0.75rem 0; } .swap-btn { background: #6366f1; color: #fff; border: none; border-radius: 50%; width: 38px; height: 38px; display: flex; align-items: center; justify-content: center; cursor: pointer; box-shadow: 0 4px 12px rgba(99,102,241,0.3); transition: all .2s; } .swap-btn:hover { transform: scale(1.1) rotate(180deg); } /* Reference chart */ .morse-chart { display: grid; grid-template-columns: repeat(auto-fill, minmax(90px, 1fr)); gap: 0.5rem; margin: 1.5rem 0; } .morse-char { background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 8px; padding: 0.5rem; text-align: center; cursor: pointer; transition: all .15s; } .morse-char:hover { background: #ede9fe; border-color: #a5b4fc; transform: translateY(-2px); } .morse-char-letter { font-size: 1.1rem; font-weight: 700; color: #0f172a; } .morse-char-code { font-size: 0.8rem; color: #6366f1; font-family: monospace; margin-top: 2px; } </style> </head> <body> <header class="header"><div class="header-inner"> <a href="index.html" class="logo"><img src="favicon.png" alt="FancySymbols" width="32" height="32"> FancySymbols</a> <nav class="header-nav"><a href="index.html">Home</a><a href="all-symbols.html">All Symbols</a><a href="aesthetic-fonts.html">Aesthetic</a><a href="cute-fonts.html">Cute</a><a href="lenny-face.html" class="cta-btn">Lenny Faces</a></nav> <button class="menu-toggle" id="menuToggle" aria-label="Menu"><svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"><line x1="4" y1="6" x2="20" y2="6"/><line x1="4" y1="12" x2="20" y2="12"/><line x1="4" y1="18" x2="20" y2="18"/></svg></button> </div></header> <aside class="sidebar" id="sidebar"></aside> <div class="sidebar-overlay" id="sidebarOverlay"></div> <div class="flash-overlay" id="flashOverlay"></div> <main class="main-content" style="padding-top:6rem;"> <section class="hero" style="text-align:center;padding:1.5rem 1rem;"> <h1 style="font-size:2rem;font-weight:800;margin-bottom:.4rem;">Morse Code Translator</h1> <p style="color:#64748b;max-width:600px;margin:0 auto;">Translate text to Morse code or decode Morse back to English. With <strong>audio playback, light & vibrate</strong>.</p> </section> <div class="morse-app"> <!-- Input + Sliders Row --> <div class="morse-io"> <div class="morse-panel-left"> <label class="morse-label" id="labelInput">Input:</label> <textarea class="morse-textarea" id="morseInput" placeholder="Type text here..." autofocus>Hello World</textarea> </div> <div class="morse-sliders"> <div class="slider-group"> <span class="slider-title">Speed</span> <span class="slider-val" id="speedVal">20</span> <input type="range" class="v-slider" id="speedSlider" min="5" max="50" value="20"> </div> <div class="slider-group"> <span class="slider-title">Pitch</span> <span class="slider-val" id="pitchVal">550</span> <input type="range" class="v-slider" id="pitchSlider" min="200" max="1200" value="550"> </div> <div class="slider-group"> <span class="slider-title">Volume</span> <span class="slider-val" id="volumeVal">80</span> <input type="range" class="v-slider" id="volumeSlider" min="0" max="100" value="80"> </div> </div> </div> <!-- Swap Button --> <div class="swap-row"> <button class="swap-btn" onclick="swapMode()" title="Swap direction"> <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><polyline points="7 3 7 21"/><polyline points="3 7 7 3 11 7"/><polyline points="17 21 17 3"/><polyline points="13 17 17 21 21 17"/></svg> </button> </div> <!-- Output --> <div> <label class="morse-label" id="labelOutput">Output:</label> <textarea class="morse-textarea" id="morseOutput" placeholder="The translated message appears here with '#' indicating an untranslatable character." readonly></textarea> </div> <!-- Control Buttons --> <div class="morse-controls"> <button class="ctrl-btn" id="btnPlay" onclick="playMorse()"> <svg viewBox="0 0 24 24" fill="currentColor"><polygon points="5 3 19 12 5 21 5 3"/></svg> Play </button> <button class="ctrl-btn" id="btnPause" onclick="pauseMorse()"> <svg viewBox="0 0 24 24" fill="currentColor"><rect x="6" y="4" width="4" height="16"/><rect x="14" y="4" width="4" height="16"/></svg> Pause </button> <button class="ctrl-btn" id="btnStop" onclick="stopMorse()"> <svg viewBox="0 0 24 24" fill="currentColor"><rect x="4" y="4" width="16" height="16" rx="2"/></svg> Stop </button> <button class="ctrl-btn" id="btnRepeat" onclick="toggleRepeat()"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><polyline points="17 1 21 5 17 9"/><path d="M3 11V9a4 4 0 014-4h14"/><polyline points="7 23 3 19 7 15"/><path d="M21 13v2a4 4 0 01-4 4H3"/></svg> Repeat </button> <button class="ctrl-btn active" id="btnSound" onclick="toggleSound()"> <svg viewBox="0 0 24 24" fill="currentColor"><path d="M11 5L6 9H2v6h4l5 4V5z"/><path d="M15.54 8.46a5 5 0 010 7.07" fill="none" stroke="currentColor" stroke-width="2"/></svg> Sound </button> <button class="ctrl-btn" id="btnLight" onclick="toggleLight()"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg> Light </button> <button class="ctrl-btn" id="btnVibrate" onclick="toggleVibrate()"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><rect x="5" y="2" width="14" height="20" rx="2"/><line x1="12" y1="18" x2="12" y2="18.01"/></svg> Vibrate </button> <button class="ctrl-btn" id="btnCopy" onclick="copyOutput()"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 01-2-2V4a2 2 0 012-2h9a2 2 0 012 2v1"/></svg> Copy </button> <button class="ctrl-btn" id="btnShare" onclick="shareResult()"> <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M4 12v8a2 2 0 002 2h12a2 2 0 002-2v-8"/><polyline points="16 6 12 2 8 6"/><line x1="12" y1="2" x2="12" y2="15"/></svg> Share </button> </div> <!-- Morse Code Reference Chart --> <section style="margin-top:2.5rem;"> <h2 style="font-size:1.4rem;font-weight:700;margin-bottom:.5rem;">Morse Code Reference Chart</h2> <p style="color:#64748b;margin-bottom:1rem;font-size:.9rem;">Click any character to hear its Morse code</p> <div class="morse-chart" id="morseChart"></div> </section> <!-- Content --> <section style="margin-top:2.5rem;"> <h2 style="font-size:1.4rem;font-weight:700;margin-bottom:1rem;">What is Morse Code?</h2> <p style="color:#334155;line-height:1.8;margin-bottom:1rem;"><strong>Morse code</strong> is a method of encoding text characters as standardized sequences of dots (,%V%) and dashes (���). Named after Samuel Morse, the co-inventor of the telegraph, it was widely used in early long-distance communication. Each letter, number, and punctuation mark is represented by a unique pattern.</p> <h2 style="font-size:1.4rem;font-weight:700;margin:2rem 0 1rem;">How to Read Morse Code</h2> <ul style="color:#334155;line-height:2;padding-left:1.5rem;"> <li><strong>Dot (,%V%)</strong> ��� a short signal, the basic time unit</li> <li><strong>Dash (���)</strong> ��� a long signal, 3%� the length of a dot</li> <li><strong>Space between letters</strong> ��� 3 dot-lengths (shown as a space)</li> <li><strong>Space between words</strong> ��� 7 dot-lengths (shown as /)</li> </ul> <h2 style="font-size:1.4rem;font-weight:700;margin:2rem 0 1rem;">FAQ</h2> <div class="faq-item"><div class="faq-q">Can I play Morse code as sound?</div><div class="faq-a">Yes! Click the Play button to hear your translated Morse code as audio beeps. Adjust speed, pitch, and volume using the sliders.</div></div> <div class="faq-item"><div class="faq-q">What does the Light button do?</div><div class="faq-a">When Light is enabled, the screen will flash white for dots and dashes, simulating a Morse code flashlight signal. Great for learning or signaling in the dark!</div></div> <div class="faq-item"><div class="faq-q">Does the Vibrate feature work?</div><div class="faq-a">Vibrate works on supported mobile devices. Your phone will vibrate in the pattern of the Morse code ��� short buzzes for dots, longer buzzes for dashes.</div></div> </section> </div> <footer class="footer" style="margin-top:3rem;"> <div class="footer-bottom"> <p class="footer-copy">&copy; 2026 FancySymbols.</p> </div> </footer> </main> <div id="toast" class="toast"></div> <script src="script.js?v=5.5"></script> <script> // ===== MORSE CODE ENGINE ===== const MC = { 'A':'.-','B':'-...','C':'-.-.','D':'-..','E':'.','F':'..-.','G':'--.','H':'....','I':'..','J':'.---','K':'-.-','L':'.-..','M':'--','N':'-.','O':'---','P':'.--.','Q':'--.-','R':'.-.','S':'...','T':'-','U':'..-','V':'...-','W':'.--','X':'-..-','Y':'-.--','Z':'--..', '0':'-----','1':'.----','2':'..---','3':'...--','4':'....-','5':'.....','6':'-....','7':'--...','8':'---..','9':'----.', '.':'.-.-.-',',':'--..--','?':'..--..','!':'-.-.--','/':'-..-.','(':'-.--.',')':'-.--.-','&':'.-...',':':'---...',';':'-.-.-.','=':'-...-','+':'.-.-.', '-':'-....-','_':'..--.-','"':'.-..-.','@':'.--.-.',"'":'.----.' }; const RM = {}; for (const [k,v] of Object.entries(MC)) RM[v] = k; let isTextToMorse = true; let soundOn = true, lightOn = false, vibrateOn = false, repeatOn = false; let isPlaying = false, isPaused = false; let playTimeouts = []; let audioCtx = null; // ===== TRANSLATION ===== function translate() { const inp = document.getElementById('morseInput').value; const out = document.getElementById('morseOutput'); if (isTextToMorse) { out.value = inp.toUpperCase().split('').map(c => { if (c === ' ') return '/'; return MC[c] || '#'; }).join(' ').replace(/ \/ /g, ' / '); } else { const words = inp.replace(/_/g,'-').replace(/\*/g,'.').split('/'); out.value = words.map(w => w.trim().split(' ').map(c => RM[c] || '#').join('')).join(' '); } } function swapMode() { isTextToMorse = !isTextToMorse; const li = document.getElementById('labelInput'); const lo = document.getElementById('labelOutput'); const mi = document.getElementById('morseInput'); const mo = document.getElementById('morseOutput'); if (isTextToMorse) { li.textContent='Input:'; lo.textContent='Output:'; mi.placeholder='Type text here...'; } else { li.textContent='Morse Code Input:'; lo.textContent='Text Output:'; mi.placeholder='Type morse (use . and - , / for word break)...'; } const tmp = mi.value; mi.value = mo.value; mo.value = tmp; translate(); } // ===== SLIDER UPDATES ===== document.getElementById('speedSlider').oninput = function() { document.getElementById('speedVal').textContent = this.value; }; document.getElementById('pitchSlider').oninput = function() { document.getElementById('pitchVal').textContent = this.value; }; document.getElementById('volumeSlider').oninput = function() { document.getElementById('volumeVal').textContent = this.value; }; // ===== AUDIO PLAYBACK ===== function getAudioCtx() { if (!audioCtx) audioCtx = new (window.AudioContext || window.webkitAudioContext)(); return audioCtx; } function beep(duration, freq, vol) { return new Promise(resolve => { const ctx = getAudioCtx(); const osc = ctx.createOscillator(); const gain = ctx.createGain(); osc.connect(gain); gain.connect(ctx.destination); osc.frequency.value = freq; gain.gain.value = vol / 100; osc.start(); setTimeout(() => { osc.stop(); resolve(); }, duration); }); } function flashScreen(duration) { if (!lightOn) return; const el = document.getElementById('flashOverlay'); el.classList.add('on'); setTimeout(() => el.classList.remove('on'), duration); } function vibrate(duration) { if (!vibrateOn) return; if (navigator.vibrate) navigator.vibrate(duration); } async function playMorseSequence() { const speed = parseInt(document.getElementById('speedSlider').value); const freq = parseInt(document.getElementById('pitchSlider').value); const vol = parseInt(document.getElementById('volumeSlider').value); // Get morse output let morseStr = ''; if (isTextToMorse) { morseStr = document.getElementById('morseOutput').value; } else { morseStr = document.getElementById('morseInput').value; } if (!morseStr) return; const dotLen = 1200 / speed; // ms per dot const dashLen = dotLen * 3; const symbolGap = dotLen; const letterGap = dotLen * 3; const wordGap = dotLen * 7; isPlaying = true; isPaused = false; document.getElementById('btnPlay').classList.add('playing'); do { const chars = morseStr.split(''); for (let i = 0; i < chars.length; i++) { if (!isPlaying) return; while (isPaused) { await new Promise(r => setTimeout(r, 100)); if (!isPlaying) return; } const c = chars[i]; if (c === '.') { if (soundOn) await beep(dotLen, freq, vol); else await new Promise(r => setTimeout(r, dotLen)); flashScreen(dotLen); vibrate(dotLen); } else if (c === '-') { if (soundOn) await beep(dashLen, freq, vol); else await new Promise(r => setTimeout(r, dashLen)); flashScreen(dashLen); vibrate(dashLen); } else if (c === '/') { await new Promise(r => setTimeout(r, wordGap)); } else if (c === ' ') { await new Promise(r => setTimeout(r, letterGap)); } // gap between symbols within a letter if (c === '.' || c === '-') { await new Promise(r => setTimeout(r, symbolGap)); } } if (repeatOn && isPlaying) await new Promise(r => setTimeout(r, wordGap * 2)); } while (repeatOn && isPlaying); stopMorse(); } function playMorse() { if (isPaused && isPlaying) { isPaused = false; return; } stopMorse(); playMorseSequence(); } function pauseMorse() { if (isPlaying) isPaused = !isPaused; } function stopMorse() { isPlaying = false; isPaused = false; document.getElementById('btnPlay').classList.remove('playing'); document.getElementById('flashOverlay').classList.remove('on'); } // ===== TOGGLES ===== function toggleRepeat() { repeatOn = !repeatOn; document.getElementById('btnRepeat').classList.toggle('active', repeatOn); } function toggleSound() { soundOn = !soundOn; document.getElementById('btnSound').classList.toggle('active', soundOn); } function toggleLight() { lightOn = !lightOn; document.getElementById('btnLight').classList.toggle('active', lightOn); } function toggleVibrate() { vibrateOn = !vibrateOn; document.getElementById('btnVibrate').classList.toggle('active', vibrateOn); } function copyOutput() { const text = document.getElementById('morseOutput').value; if (!text) return; navigator.clipboard.writeText(text).then(() => { if (window.showToast) showToast('��� Copied to clipboard!'); const btn = document.getElementById('btnCopy'); btn.classList.add('active'); setTimeout(() => btn.classList.remove('active'), 1500); }); } function shareResult() { const text = document.getElementById('morseOutput').value; if (navigator.share) { navigator.share({ title: 'Morse Code', text: text, url: 'https://fancysymbols.com/morse-code' }); } else { copyOutput(); if (window.showToast) showToast('Link copied! Share it with friends.'); } } // ===== PLAY SINGLE CHARACTER ===== async function playChar(letter) { const morse = MC[letter.toUpperCase()]; if (!morse) return; const speed = parseInt(document.getElementById('speedSlider').value); const freq = parseInt(document.getElementById('pitchSlider').value); const vol = parseInt(document.getElementById('volumeSlider').value); const dotLen = 1200 / speed; for (const c of morse) { if (c === '.') { await beep(dotLen, freq, vol); flashScreen(dotLen); vibrate(dotLen); } else if (c === '-') { await beep(dotLen*3, freq, vol); flashScreen(dotLen*3); vibrate(dotLen*3); } await new Promise(r => setTimeout(r, dotLen)); } } // ===== REFERENCE CHART ===== function buildChart() { const chart = document.getElementById('morseChart'); const entries = Object.entries(MC); chart.innerHTML = entries.map(([letter, code]) => `<div class="morse-char" onclick="playChar('${letter.replace("'","\\'")}')"> <div class="morse-char-letter">${letter}</div> <div class="morse-char-code">${code}</div> </div>` ).join(''); } // ===== INIT ===== document.getElementById('morseInput').addEventListener('input', translate); translate(); buildChart(); </script> </body> </html>