Full documentation for @morsecodeapp/morse — core (v0.1.0) + audio (v0.2.0).
All core exports are available from @morsecodeapp/morse and @morsecodeapp/morse/core.
All audio exports are available from @morsecodeapp/morse and @morsecodeapp/morse/audio.
Converts text to Morse code.
function encode(text: string, options?: EncodeOptions): stringExamples:
import { encode } from '@morsecodeapp/morse';
encode('SOS'); // '... --- ...'
encode('Hello World'); // '.... . .-.. .-.. --- / .-- --- .-. .-.. -..'
encode('ПРИВЕТ', { charset: 'cyrillic' }); // '.--. .-. .. .-- . -'
encode('SOS', { dot: '•', dash: '—' }); // '••• ——— •••'
encode('SOS', { separator: '|', wordSeparator: ' // ' });| Option | Type | Default | Description |
|---|---|---|---|
charset |
CharsetId |
'itu' |
Character set to use |
fallbackCharsets |
CharsetId[] |
[] |
Additional charsets to try for unmatched characters |
dot |
string |
'.' |
Dot symbol in output |
dash |
string |
'-' |
Dash symbol in output |
separator |
string |
' ' |
Separator between letters |
wordSeparator |
string |
' / ' |
Separator between words |
invalid |
string |
'?' |
Replacement for characters with no mapping |
Like encode() but returns an EncodeResult with validity info.
function encodeDetailed(text: string, options?: EncodeOptions): EncodeResultExample:
import { encodeDetailed } from '@morsecodeapp/morse';
encodeDetailed('A§B');
// { morse: '.- ? -...', valid: false, errors: ['§'] }
encodeDetailed('SOS');
// { morse: '... --- ...', valid: true, errors: [] }| Field | Type | Description |
|---|---|---|
morse |
string |
The Morse code output |
valid |
boolean |
true if all characters were mapped |
errors |
string[] |
Characters that could not be encoded |
Converts Morse code back to text.
function decode(morse: string, options?: DecodeOptions): stringExamples:
import { decode } from '@morsecodeapp/morse';
decode('... --- ...'); // 'SOS'
decode('.... . .-.. .-.. --- / .-- --- .-. .-.. -..'); // 'HELLO WORLD'
decode('.-', { charset: 'cyrillic' }); // 'А'
decode('••• ——— •••', { dot: '•', dash: '—' }); // 'SOS'| Option | Type | Default | Description |
|---|---|---|---|
charset |
CharsetId |
'itu' |
Character set to use |
fallbackCharsets |
CharsetId[] |
[] |
Additional charsets to try for unmatched patterns |
dot |
string |
'.' |
Dot symbol in input |
dash |
string |
'-' |
Dash symbol in input |
separator |
string |
' ' |
Separator between letters |
wordSeparator |
string |
' / ' |
Separator between words |
invalid |
string |
'?' |
Replacement for unrecognized patterns |
Like decode() but returns a DecodeResult with validity info.
function decodeDetailed(morse: string, options?: DecodeOptions): DecodeResultExample:
import { decodeDetailed } from '@morsecodeapp/morse';
decodeDetailed('... --- ... .-.-.-');
// { text: 'SOS.', valid: true, errors: [] }
decodeDetailed('... @@@ ...');
// { text: 'S?S', valid: false, errors: ['@@@'] }| Field | Type | Description |
|---|---|---|
text |
string |
The decoded text |
valid |
boolean |
true if all patterns were mapped |
errors |
string[] |
Morse patterns that could not be decoded |
Returns a Charset object by ID.
function getCharset(id?: CharsetId): Charsetimport { getCharset } from '@morsecodeapp/morse';
const itu = getCharset('itu');
itu.charToMorse['A']; // '.-'
itu.morseToChar['.-']; // 'A'
itu.name; // 'International (ITU)'Throws an Error if the charset ID is unknown.
Returns an array of all available charset IDs.
function listCharsets(): CharsetId[]listCharsets();
// ['itu', 'american', 'latin-ext', 'cyrillic', 'greek', 'hebrew',
// 'arabic', 'persian', 'japanese', 'korean', 'thai']Returns charset metadata including character count.
function listCharsetsDetailed(): Array<{ id: CharsetId; name: string; size: number }>listCharsetsDetailed();
// [{ id: 'itu', name: 'International (ITU)', size: 54 }, ...]Auto-detects the best charset for the given text by coverage score.
function detectCharset(text: string): CharsetIddetectCharset('ПРИВЕТ'); // 'cyrillic'
detectCharset('HELLO'); // 'itu'
detectCharset('こんにちは'); // 'japanese'Individual charsets are also exported directly:
import { itu, cyrillic, greek, arabic } from '@morsecodeapp/morse';
itu.charToMorse['S']; // '...'
cyrillic.charToMorse['Ж']; // '...-'Available: itu, american, latinExt, cyrillic, greek, hebrew, arabic, persian, japanese, korean, thai
interface Charset {
readonly id: CharsetId;
readonly name: string;
readonly charToMorse: Readonly<Record<string, string>>;
readonly morseToChar: Readonly<Record<string, string>>;
}type CharsetId =
| 'itu' | 'american' | 'latin-ext' | 'cyrillic' | 'greek'
| 'hebrew' | 'arabic' | 'persian' | 'japanese' | 'korean' | 'thai';Procedural signals — sent as single unbroken characters with no inter-character gaps.
A readonly Prosign[] array of all 10 standard prosigns.
import { PROSIGNS } from '@morsecodeapp/morse';
PROSIGNS[0]; // { label: 'SOS', morse: '...---...', meaning: 'International distress signal' }| Label | Morse | Meaning |
|---|---|---|
| SOS | ...---... |
International distress signal |
| AR | .-.-. |
End of message |
| SK | ...-.- |
End of contact / Silent Key |
| BT | -...- |
Break / New paragraph |
| KN | -.--. |
Go ahead, named station only |
| AS | .-... |
Wait / Stand by |
| CL | -.-..-.." |
Closing station |
| CT | -.-.- |
Commence transmission |
| SN | ...-. |
Understood / Verified |
| HH | ........ |
Error / Correction |
Returns the morse pattern for a prosign label, or undefined.
function encodeProsign(label: string): string | undefinedencodeProsign('SOS'); // '...---...'
encodeProsign('AR'); // '.-.-.'
encodeProsign('XYZ'); // undefinedReturns the prosign label for a morse pattern, or undefined.
function decodeProsign(morse: string): string | undefineddecodeProsign('...---...'); // 'SOS'
decodeProsign('.-.-.'); // 'AR'Returns the full Prosign object by label, or undefined.
function getProsign(label: string): Prosign | undefinedgetProsign('SOS');
// { label: 'SOS', morse: '...---...', meaning: 'International distress signal' }Returns an array of all prosign labels.
function listProsigns(): string[]listProsigns(); // ['SOS', 'AR', 'SK', 'BT', 'KN', 'AS', 'CL', 'CT', 'SN', 'HH']Based on the PARIS standard — the word PARIS is 50 dot-units, so at W WPM: unit = 1200 / W ms.
Calculate standard PARIS timing values.
function timing(wpm?: number): TimingValuesDefault WPM is 20. Clamped to 1–60.
import { timing } from '@morsecodeapp/morse';
timing(20);
// { unit: 60, dot: 60, dash: 180, intraChar: 60, interChar: 180, interWord: 420 }
timing(5);
// { unit: 240, dot: 240, dash: 720, intraChar: 240, interChar: 720, interWord: 1680 }Characters sent at charWpm, with extra gaps to achieve overallWpm.
function farnsworthTiming(overallWpm?: number, charWpm?: number): TimingValuesDefaults: overallWpm = 15, charWpm = 20.
import { farnsworthTiming } from '@morsecodeapp/morse';
farnsworthTiming(10, 20);
// Characters at 20 WPM speed, but overall pace is 10 WPM
// Extra delay added to interChar and interWord gapsCalculate total playback duration of a morse string in milliseconds.
function duration(morse: string, wpm?: number): numberimport { duration } from '@morsecodeapp/morse';
duration('... --- ...'); // 1620 (ms at 20 WPM)
duration('... --- ...', 10); // 3240 (ms at 10 WPM)Format milliseconds to a human-readable string.
function formatDuration(ms: number): stringimport { formatDuration } from '@morsecodeapp/morse';
formatDuration(500); // '500ms'
formatDuration(3500); // '3.5s'
formatDuration(65000); // '1m 5.0s'import { DEFAULT_WPM, MIN_WPM, MAX_WPM } from '@morsecodeapp/morse';
DEFAULT_WPM; // 20
MIN_WPM; // 1
MAX_WPM; // 60interface TimingValues {
unit: number; // Base unit in ms
dot: number; // 1 unit
dash: number; // 3 units
intraChar: number; // Gap between signals within a character (1 unit)
interChar: number; // Gap between characters (3 units, extended for Farnsworth)
interWord: number; // Gap between words (7 units, extended for Farnsworth)
}Compute statistics for a morse code string.
function stats(morse: string, wpm?: number): MorseStatsimport { stats } from '@morsecodeapp/morse';
stats('... --- ...');
// {
// dots: 6,
// dashes: 3,
// signals: 9,
// characters: 3,
// words: 1,
// durationMs: 1620,
// durationSec: '1.6',
// durationFormatted: '1.6s'
// }
stats('.... . .-.. .-.. --- / .-- --- .-. .-.. -..', 15);
// Statistics at 15 WPMinterface MorseStats {
dots: number; // Count of dots
dashes: number; // Count of dashes
signals: number; // dots + dashes
characters: number; // Number of letters/numbers
words: number; // Number of words
durationMs: number; // Estimated duration in milliseconds
durationSec: string; // Duration in seconds (1 decimal, e.g., '1.6')
durationFormatted: string; // Human-readable (e.g., '1.6s', '1m 5.0s')
}Check if a string contains only valid Morse characters (dots, dashes, spaces, slashes).
function isValidMorse(morse: string): booleanisValidMorse('... --- ...'); // true
isValidMorse('HELLO'); // false
isValidMorse('... @@@ ...'); // falseCheck if all characters in text have a mapping in the given charset.
function isEncodable(text: string, charset?: CharsetId): booleanisEncodable('HELLO'); // true (defaults to 'itu')
isEncodable('HELLO', 'itu'); // true
isEncodable('Ж', 'itu'); // false
isEncodable('Ж', 'cyrillic'); // trueCheck if all morse patterns can be decoded with the given charset.
function isDecodable(morse: string, charset?: CharsetId): booleanisDecodable('... --- ...'); // true
isDecodable('... --- ...', 'itu'); // true
isDecodable('HELLO'); // false (not valid morse)Find characters in text that cannot be encoded with the given charset.
function findInvalidChars(text: string, charset?: CharsetId): string[]findInvalidChars('Hello!§'); // ['§']
findInvalidChars('ABC'); // []Find morse patterns that cannot be decoded with the given charset.
function findInvalidPatterns(morse: string, charset?: CharsetId): string[]findInvalidPatterns('... --- .---.--.'); // ['.---.--.' ] (not a real pattern)
findInvalidPatterns('... --- ...'); // []All core types are exported and available for import:
import type {
CharsetId,
Charset,
EncodeOptions,
DecodeOptions,
EncodeResult,
DecodeResult,
TimingValues,
Prosign,
MorseStats,
} from '@morsecodeapp/morse';See also Audio Types for audio-specific types.
All audio exports are available from
@morsecodeapp/morseand@morsecodeapp/morse/audio.
MorsePlayerrequires a browser with the Web Audio API. WAV export and the scheduler work in any JavaScript runtime.
Web Audio API morse code player with play/pause/stop, gain envelope, and event callbacks.
import { MorsePlayer } from '@morsecodeapp/morse/audio';new MorsePlayer(options?: MorsePlayerOptions)Example:
const player = new MorsePlayer({
wpm: 20,
frequency: 600,
waveform: 'sine',
volume: 80,
onEnd: () => console.log('Done!'),
});| Option | Type | Default | Description |
|---|---|---|---|
wpm |
number |
20 |
Words per minute (1–60) |
frequency |
number |
600 |
Tone frequency in Hz (200–2000) |
waveform |
WaveformType |
'sine' |
Oscillator waveform |
volume |
number |
80 |
Volume (0–100) |
farnsworth |
boolean |
false |
Enable Farnsworth spacing |
farnsworthWpm |
number |
15 |
Farnsworth overall WPM |
gainEnvelope |
GainEnvelopeOptions |
{ attack: 0.01, release: 0.01 } |
Gain envelope for click-free audio |
audioContext |
AudioContext |
auto-created | Existing AudioContext to reuse |
onPlay |
() => void |
— | Fired when playback starts |
onPause |
() => void |
— | Fired when playback is paused |
onResume |
() => void |
— | Fired when playback resumes |
onStop |
() => void |
— | Fired when playback is stopped |
onEnd |
() => void |
— | Fired when playback ends naturally |
onSignal |
(signal: 'dot' | 'dash', charIndex: number) => void |
— | Fired for each dot or dash |
onCharacter |
(char: string, morse: string, charIndex: number) => void |
— | Fired when a character finishes |
onProgress |
(currentMs: number, totalMs: number) => void |
— | Fired periodically during playback |
Play morse code audio. Accepts text (auto-encodes) or raw morse.
async play(input: string, options?: PlayOptions): Promise<void>Returns a Promise that resolves when playback ends or is stopped.
await player.play('Hello World');
await player.play('... --- ...', { morse: true });
await player.play('ПРИВЕТ', { charset: 'cyrillic' });| Option | Type | Default | Description |
|---|---|---|---|
morse |
boolean |
false |
If true, input is treated as raw morse code |
charset |
CharsetId |
'itu' |
Character set for encoding text input |
Pause playback. Suspends the AudioContext.
player.pause();Resume playback from paused state.
await player.resume();Stop playback and reset to idle.
player.stop();Dispose of all resources. Call when done with the player.
player.dispose();| Property | Type | Description |
|---|---|---|
state |
PlayerState |
Current state: 'idle', 'playing', or 'paused' |
totalTime |
number |
Total duration of current playback in ms |
currentTime |
number |
Elapsed time in ms |
progress |
number |
Playback progress (0–1) |
wpm |
number |
Get/set words per minute |
frequency |
number |
Get/set tone frequency in Hz |
volume |
number |
Get/set volume (0–100, live update during playback) |
Pre-configured audio settings tuned for different use cases.
import { presets, telegraph, radio } from '@morsecodeapp/morse/audio';Pass a preset directly to the MorsePlayer constructor:
import { MorsePlayer, presets } from '@morsecodeapp/morse/audio';
const player = new MorsePlayer(presets.telegraph);
await player.play('CQ CQ CQ');Or spread a preset with overrides:
const player = new MorsePlayer({ ...presets.military, volume: 60 });| Name | Freq | WPM | Waveform | Character |
|---|---|---|---|---|
telegraph |
550 Hz | 15 | square | Classic telegraph sounder — warm, clicky tone |
radio |
600 Hz | 20 | sine | Clean amateur radio CW tone |
military |
700 Hz | 25 | sine | Crisp military communication tone |
sonar |
400 Hz | 12 | sine | Deep submarine sonar ping |
naval |
650 Hz | 18 | triangle | Naval fleet communication tone |
beginner |
600 Hz | 18 (Farnsworth 5) | sine | Slow Farnsworth spacing for learning |
interface SoundPreset {
readonly name: string;
readonly description: string;
readonly wpm: number;
readonly frequency: number;
readonly waveform: WaveformType;
readonly volume: number;
readonly farnsworth?: boolean;
readonly farnsworthWpm?: number;
readonly gainEnvelope?: GainEnvelopeOptions;
}type PresetName = 'telegraph' | 'radio' | 'military' | 'sonar' | 'naval' | 'beginner';Generate WAV audio files from text or morse code. Pure computation — works in any JavaScript runtime (Node.js, Bun, Deno, browsers).
import { toWav, toWavBlob, toWavUrl, downloadWav } from '@morsecodeapp/morse/audio';Generate WAV audio data as raw bytes.
function toWav(input: string, options?: WavOptions): Uint8Arrayimport { toWav } from '@morsecodeapp/morse/audio';
const wav = toWav('SOS');
const wav = toWav('... --- ...', { morse: true, frequency: 800 });
// Write to file in Node.js
import { writeFileSync } from 'fs';
writeFileSync('sos.wav', wav);Generate a WAV Blob. Useful for creating audio elements in the browser.
function toWavBlob(input: string, options?: WavOptions): Blobconst blob = toWavBlob('SOS');
const audio = new Audio(URL.createObjectURL(blob));
audio.play();Generate a base64 data URL of the WAV file.
function toWavUrl(input: string, options?: WavOptions): stringconst url = toWavUrl('SOS');
// 'data:audio/wav;base64,...'Download a WAV file in the browser. No-op in non-browser environments.
function downloadWav(input: string, options?: WavOptions): voiddownloadWav('SOS', { filename: 'sos.wav' });| Option | Type | Default | Description |
|---|---|---|---|
wpm |
number |
20 |
Words per minute (1–60) |
frequency |
number |
600 |
Tone frequency in Hz (200–2000) |
waveform |
WaveformType |
'sine' |
Oscillator waveform |
volume |
number |
80 |
Volume (0–100) |
sampleRate |
number |
44100 |
Sample rate in Hz |
gainEnvelope |
GainEnvelopeOptions |
{ attack: 0.01, release: 0.01 } |
Gain envelope |
farnsworth |
boolean |
false |
Enable Farnsworth spacing |
farnsworthWpm |
number |
— | Farnsworth overall WPM |
charset |
CharsetId |
'itu' |
Character set for text input |
morse |
boolean |
false |
If true, input is raw morse code |
filename |
string |
'morse.wav' |
Filename for downloadWav() |
Low-level module that converts a morse string and timing values into a timeline of timed events. Used internally by MorsePlayer and WAV export, but exposed for custom audio rendering.
import { buildSchedule, scheduleDuration, type ScheduleEvent } from '@morsecodeapp/morse/audio';Build a schedule of tones and silences from a morse string.
function buildSchedule(morse: string, timings: TimingValues): ScheduleEvent[]import { buildSchedule } from '@morsecodeapp/morse/audio';
import { timing } from '@morsecodeapp/morse/core';
const t = timing(20);
const schedule = buildSchedule('... ---', t);
// [
// { type: 'tone', start: 0, duration: 60, signal: 'dot', morseChar: '...', charIndex: 0 },
// { type: 'silence', start: 60, duration: 60 },
// { type: 'tone', start: 120, duration: 60, signal: 'dot', morseChar: '...', charIndex: 0 },
// ...
// ]Get total duration of a schedule in milliseconds.
function scheduleDuration(events: ScheduleEvent[]): numberconst total = scheduleDuration(schedule); // e.g. 1620interface ScheduleEvent {
type: 'tone' | 'silence';
start: number; // Start time in ms from beginning
duration: number; // Duration in ms
signal?: 'dot' | 'dash'; // Tone events only
morseChar?: string; // Morse pattern (e.g., '.-')
charIndex?: number; // Sequential character index
}All audio types are exported from @morsecodeapp/morse/audio:
import type {
WaveformType,
PlayerState,
GainEnvelopeOptions,
MorsePlayerOptions,
PlayOptions,
SoundPreset,
WavOptions,
PresetName,
ScheduleEvent,
} from '@morsecodeapp/morse/audio';type WaveformType = 'sine' | 'square' | 'sawtooth' | 'triangle';type PlayerState = 'idle' | 'playing' | 'paused';interface GainEnvelopeOptions {
attack: number; // Attack time in seconds (ramp up). Default: 0.01
release: number; // Release time in seconds (ramp down). Default: 0.01
}