<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
      <title>Radio stuff from M5NCW on Nick Craig-Wood&#39;s home page </title>
    <link>https://www.craig-wood.com/nick/radio/</link>
    <language>en-US</language>
    <author>Nick Craig-Wood</author>
    <rights>Copyright (c) 2017, Nick Craig-Wood; all rights reserved.</rights>
    <updated>Mon, 01 Jan 0001 00:00:00 UTC</updated>
    
    <item>
      <title>Unicode Block-Style Morse Encoder</title>
      <link>https://www.craig-wood.com/nick/radio/block_morse/</link>
      <pubDate>Tue, 12 Aug 2025 00:00:00 UTC</pubDate>
      <author>Nick Craig-Wood</author>
      <guid>https://www.craig-wood.com/nick/radio/block_morse/</guid>
      <description>&lt;style&gt;
  fieldset { border: 1px solid #3b4261; border-radius: 8px; padding: 1rem; }
  label { display: block; font-weight: 600; margin-bottom: 0.25rem; }
  #input { width: 100%; padding: 0.5rem; font-size: 1rem; background: #1f2335; color: #c0caf5; border: 1px solid #3b4261; border-radius: 4px; }
  #output { width: 100%; height: 260px; padding: 0.5rem; background: #1f2335; color: #c0caf5; border: 1px solid #3b4261; border-radius: 4px; }
  .buttons { margin-top: 0.5rem; display: flex; gap: 0.5rem; }
  .buttons button { padding: 0.5rem 0.8rem; border-radius: 8px; border: 1px solid #3b4261; background: #24283b; color: #c0caf5; cursor: pointer; }
  .buttons button:hover { background: #3b4261; }
  .buttons button:active { transform: translateY(1px); }
  .help { margin-top: 1rem; font-size: 0.95rem; }
  @media (prefers-color-scheme: light) {
    fieldset { border-color: #e7e5e4; }
    #input, #output { background: #f3f2ef; color: #1c1917; border-color: #e7e5e4; }
    .buttons button { background: #f3f2ef; color: #1c1917; border-color: #e7e5e4; }
    .buttons button:hover { background: #e7e5e4; }
  }
&lt;/style&gt;

&lt;fieldset&gt;
  &lt;label for=&#34;input&#34;&gt;Text&lt;/label&gt;
  &lt;input id=&#34;input&#34; type=&#34;text&#34; placeholder=&#34;Type text, e.g. SOS&#34; autocomplete=&#34;off&#34; /&gt;
  &lt;div class=&#34;buttons&#34;&gt;
    &lt;button id=&#34;convert&#34;&gt;Convert ⏎&lt;/button&gt;
    &lt;button id=&#34;clear&#34; type=&#34;button&#34;&gt;Clear&lt;/button&gt;
  &lt;/div&gt;
&lt;/fieldset&gt;

&lt;div class=&#34;help&#34;&gt;
  &lt;p&gt;&lt;strong&gt;How:&lt;/strong&gt; Type text and press &lt;kbd&gt;Enter&lt;/kbd&gt; or &lt;em&gt;Convert&lt;/em&gt;. Each conversion appends to the output below. Unsupported characters are skipped.&lt;/p&gt;
  &lt;p&gt;Output uses special block characters (U+1FB03, U+1FB0B) and spaces (U+2001) so it stays properly spaced in both mono and proportional fonts.&lt;/p&gt;
&lt;/div&gt;

&lt;label for=&#34;output&#34; style=&#34;display:block;margin-top:1rem;font-weight:600;&#34;&gt;Output&lt;/label&gt;
&lt;textarea id=&#34;output&#34; readonly&gt;&lt;/textarea&gt;

&lt;script&gt;
(() =&gt; {
  &#34;use strict&#34;;

  // Unicode block glyphs
  const DOT  = &#34;🬃&#34;;      // U+1FB03 (2 dits)
  const DASH = &#34;🬋🬃&#34;;     // U+1FB0B + U+1FB03 (4 dits)
  const EN   = &#34;\u2001&#34;;  // U+2001 EM QUAD SPACE (2 dits)

  // ITU Morse (A–Z, 0–9, basic punctuation)
  const MORSE = {
    &#39;A&#39;: &#39;.-&#39;,    &#39;B&#39;: &#39;-...&#39;,  &#39;C&#39;: &#39;-.-.&#39;,  &#39;D&#39;: &#39;-..&#39;,   &#39;E&#39;: &#39;.&#39;,
    &#39;F&#39;: &#39;..-.&#39;,  &#39;G&#39;: &#39;--.&#39;,   &#39;H&#39;: &#39;....&#39;,  &#39;I&#39;: &#39;..&#39;,    &#39;J&#39;: &#39;.---&#39;,
    &#39;K&#39;: &#39;-.-&#39;,   &#39;L&#39;: &#39;.-..&#39;,  &#39;M&#39;: &#39;--&#39;,    &#39;N&#39;: &#39;-.&#39;,    &#39;O&#39;: &#39;---&#39;,
    &#39;P&#39;: &#39;.--.&#39;,  &#39;Q&#39;: &#39;--.-&#39;,  &#39;R&#39;: &#39;.-.&#39;,   &#39;S&#39;: &#39;...&#39;,   &#39;T&#39;: &#39;-&#39;,
    &#39;U&#39;: &#39;..-&#39;,   &#39;V&#39;: &#39;...-&#39;,  &#39;W&#39;: &#39;.--&#39;,   &#39;X&#39;: &#39;-..-&#39;,  &#39;Y&#39;: &#39;-.--&#39;,
    &#39;Z&#39;: &#39;--..&#39;,
    &#39;0&#39;: &#39;-----&#39;, &#39;1&#39;: &#39;.----&#39;, &#39;2&#39;: &#39;..---&#39;, &#39;3&#39;: &#39;...--&#39;, &#39;4&#39;: &#39;....-&#39;,
    &#39;5&#39;: &#39;.....&#39;, &#39;6&#39;: &#39;-....&#39;, &#39;7&#39;: &#39;--...&#39;, &#39;8&#39;: &#39;---..&#39;, &#39;9&#39;: &#39;----.&#39;,
    &#39;.&#39;: &#39;.-.-.-&#39;, &#39;,&#39;: &#39;--..--&#39;, &#39;?&#39;: &#39;..--..&#39;, &#34;&#39;&#34;: &#39;.----.&#39;,
    &#39;!&#39;: &#39;-.-.--&#39;, &#39;/&#39;: &#39;-..-.&#39;, &#39;(&#39;: &#39;-.--.&#39;, &#39;)&#39;: &#39;-.--.-&#39;,
    &#39;&amp;&#39;: &#39;.-...&#39;,  &#39;:&#39;: &#39;---...&#39;, &#39;;&#39;: &#39;-.-.-.&#39;, &#39;=&#39;: &#39;-...-&#39;,
    &#39;+&#39;: &#39;.-.-.&#39;,  &#39;-&#39;: &#39;-....-&#39;, &#39;_&#39;: &#39;..--.-&#39;, &#39;&#34;&#39;: &#39;.-..-.&#39;,
    &#39;$&#39;: &#39;...-..-&#39;,&#39;@&#39;: &#39;.--.-.&#39;
  };

  const encodeSymbol = sym =&gt; (sym === &#39;.&#39;) ? DOT : DASH;

  const encodeLetter = ch =&gt; {
    const pat = MORSE[ch.toUpperCase()];
    if (!pat) return &#39;&#39;;
    const symbols = [...pat].map(encodeSymbol).join(&#39;&#39;);
    return symbols + EN; // add 2‑dit spacing at the end of the letter
  };

  const textToBlockMorse = text =&gt; {
    const parts = [];
    const words = text.split(&#39; &#39;);
    for (const word of words) {
      for (const letter of word) {
        const enc = encodeLetter(letter);
        if (enc) parts.push(enc);
      }
      // word gap = 7 dits; we already have 3, so add 4 more (2 × EN)
      parts.push(EN + EN);
    }
    return parts.join(&#39;&#39;);
  };

  // UI wiring
  const $in  = document.getElementById(&#39;input&#39;);
  const $out = document.getElementById(&#39;output&#39;);
  const $convert = document.getElementById(&#39;convert&#39;);
  const $clear   = document.getElementById(&#39;clear&#39;);

  const appendOutput = str =&gt; {
    if (!str) return;
    $out.value += ($out.value ? &#34;\n&#34; : &#34;&#34;) + str;
    $out.scrollTop = $out.scrollHeight;
  };

  const handleConvert = () =&gt; {
    const raw = $in.value.trim();
    if (!raw) return;
    const encoded = textToBlockMorse(raw);
    appendOutput(encoded);
    $in.value = &#39;&#39;;
    $in.focus();
  };

  $convert.addEventListener(&#39;click&#39;, handleConvert);
  $clear.addEventListener(&#39;click&#39;, () =&gt; { $out.value = &#39;&#39;; $in.focus(); });

  // Enter submits (Shift+Enter to insert a newline if needed)
  $in.addEventListener(&#39;keydown&#39;, e =&gt; {
    if (e.key === &#39;Enter&#39; &amp;&amp; !e.shiftKey) {
      e.preventDefault();
      handleConvert();
    }
  });
})();
&lt;/script&gt;
</description>
    </item>
    
  </channel>
</rss>
