Custom Code Experiment •
Morse Code
Source Code View HTML / CSS / JavaScript
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Morse Code</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
background: #000000;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
padding: 0;
margin: 0;
}
.container {
background: #000000;
width: 100%;
min-height: 100vh;
display: flex;
flex-direction: column;
padding: 20px;
max-width: none;
margin: 0;
}
h1 {
text-align: center;
color: #fff;
margin-bottom: 30px;
font-size: 1.8em;
font-weight: 600;
}
.input-section {
margin-bottom: 20px;
flex: 0 0 auto;
}
label {
display: block;
margin-bottom: 8px;
color: #8b92b0;
font-weight: 500;
font-size: 14px;
}
textarea {
width: 100%;
padding: 16px 20px;
border: 1px solid #333;
border-radius: 8px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
font-size: 16px;
resize: vertical;
min-height: 120px;
background: #000000;
color: #e4e7f1;
transition: border-color 0.2s;
line-height: 1.5;
}
textarea:focus {
outline: none;
border-color: #4a7cff;
}
textarea::placeholder {
color: #666;
}
button {
width: 100%;
padding: 16px;
background: #4a7cff;
color: white;
border: none;
border-radius: 8px;
font-size: 16px;
font-weight: 600;
cursor: pointer;
transition: background 0.2s;
flex: 0 0 auto;
margin: 10px 0;
}
button:hover {
background: #3d6ae6;
}
button:disabled {
background: #333;
cursor: not-allowed;
opacity: 0.5;
}
.output-section {
flex: 1;
display: flex;
flex-direction: column;
min-height: 0;
}
.morse-output {
background: #000000;
border: 1px solid #333;
border-radius: 8px;
padding: 20px;
flex: 1;
font-size: 16px;
letter-spacing: 4px;
word-wrap: break-word;
color: #4a7cff;
font-family: 'Courier New', Courier, monospace;
overflow-y: auto;
line-height: 1.8;
white-space: pre-wrap;
}
.status {
margin-top: 12px;
text-align: center;
font-size: 14px;
color: #8b92b0;
min-height: 20px;
flex: 0 0 auto;
}
.status.playing {
color: #4a7cff;
font-weight: 600;
}
@media (min-width: 768px) {
.container {
padding: 40px;
max-width: 100%;
width: 100%;
}
textarea {
min-height: 150px;
font-size: 18px;
padding: 20px 24px;
}
.morse-output {
font-size: 18px;
padding: 24px;
letter-spacing: 5px;
}
button {
padding: 18px;
font-size: 18px;
margin: 20px 0;
}
h1 {
font-size: 2.5em;
margin-bottom: 40px;
}
label {
font-size: 16px;
}
.status {
font-size: 15px;
}
}
@media (min-width: 1200px) {
.container {
padding: 60px;
max-width: 1400px;
margin: 0 auto;
}
textarea {
min-height: 180px;
font-size: 20px;
padding: 24px 30px;
}
.morse-output {
font-size: 20px;
padding: 30px;
letter-spacing: 6px;
}
button {
padding: 20px;
font-size: 20px;
margin: 30px 0;
}
h1 {
font-size: 3em;
margin-bottom: 50px;
}
}
@media (max-width: 480px) {
.container {
padding: 15px;
}
textarea {
min-height: 100px;
padding: 12px 16px;
font-size: 15px;
}
.morse-output {
padding: 16px;
font-size: 15px;
letter-spacing: 3px;
}
button {
padding: 14px;
font-size: 15px;
}
h1 {
font-size: 1.5em;
margin-bottom: 20px;
}
}
</style>
</head>
<body>
<div class="container">
<div class="input-section">
<label for="textInput">Enter your message:</label>
<textarea id="textInput" placeholder="Type your message here..."></textarea>
</div>
<button id="translateBtn">Translate & Play</button>
<div class="output-section">
<label>Morse Code Output:</label>
<div class="morse-output" id="morseOutput">Your morse code will appear here...</div>
<div class="status" id="status"></div>
</div>
</div>
<script>
const morseCode = {
'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 audioContext = new (window.AudioContext || window.webkitAudioContext)();
const dotDuration = 80;
const dashDuration = dotDuration * 3;
const symbolGap = dotDuration;
const letterGap = dotDuration * 3;
const wordGap = dotDuration * 7;
const frequency = 600;
let isPlaying = false;
function playTone(duration) {
return new Promise(resolve => {
const oscillator = audioContext.createOscillator();
const gainNode = audioContext.createGain();
oscillator.connect(gainNode);
gainNode.connect(audioContext.destination);
oscillator.frequency.value = frequency;
oscillator.type = 'sine';
gainNode.gain.setValueAtTime(0.3, audioContext.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + duration / 1000);
oscillator.start(audioContext.currentTime);
oscillator.stop(audioContext.currentTime + duration / 1000);
setTimeout(resolve, duration);
});
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function playMorseCode(text) {
const morseOutput = document.getElementById('morseOutput');
const status = document.getElementById('status');
const translateBtn = document.getElementById('translateBtn');
isPlaying = true;
translateBtn.disabled = true;
morseOutput.textContent = '';
status.textContent = 'Playing...';
status.className = 'status playing';
const words = text.toUpperCase().split(' ');
for (let w = 0; w < words.length; w++) {
const word = words[w];
for (let i = 0; i < word.length; i++) {
const char = word[i];
const morse = morseCode[char];
if (morse) {
for (let j = 0; j < morse.length; j++) {
const symbol = morse[j];
if (symbol === '.') {
morseOutput.textContent += '.';
await playTone(dotDuration);
} else if (symbol === '-') {
morseOutput.textContent += '-';
await playTone(dashDuration);
}
if (j < morse.length - 1) {
await sleep(symbolGap);
}
}
if (i < word.length - 1) {
morseOutput.textContent += ' ';
await sleep(letterGap);
}
}
}
if (w < words.length - 1) {
morseOutput.textContent += ' ';
await sleep(wordGap);
}
}
status.textContent = 'Complete!';
status.className = 'status';
translateBtn.disabled = false;
isPlaying = false;
}
document.getElementById('translateBtn').addEventListener('click', () => {
const text = document.getElementById('textInput').value.trim();
if (!text) {
alert('Please enter some text to translate!');
return;
}
if (isPlaying) {
return;
}
playMorseCode(text);
});
document.getElementById('textInput').addEventListener('keypress', (e) => {
if (e.key === 'Enter' && e.ctrlKey) {
document.getElementById('translateBtn').click();
}
});
</script>
</body>
</html>