[HN Gopher] 1KB JavaScript Numbers Station
___________________________________________________________________
1KB JavaScript Numbers Station
Author : blenderob
Score : 42 points
Date : 2025-07-22 14:47 UTC (8 hours ago)
(HTM) web link (shkspr.mobi)
(TXT) w3m dump (shkspr.mobi)
| MobiusHorizons wrote:
| Cool concept, but doesn't seem to work on iOS safari
| leeoniya wrote:
| > but doesn't seem to work on iOS safari
|
| if i had a nickel...
| thenthenthen wrote:
| Isn't every browser on iOS technically Safari under the hood?
| Although Mozillas discontinued XRViewer app/browser does def
| expose more functionality
| edent wrote:
| I've had feedback that it should work on Firefox for iOS.
| gkbrk wrote:
| Also not working on Brave on Linux for me.
| edent wrote:
| Interesting, thanks. I tested it working on Chromium - but
| didn't test other Chrome based browsers.
| tromp wrote:
| Working on my MacOSX Brave...
| mg wrote:
| No sound at all and the console shows lots of these messages:
| 24:4 Uncaught TypeError: Cannot read properties of undefined
| (reading 'lang') at 24:4:132
|
| Which seems to be this line: m.lang =
| e[(Math.random() * e.length) | 0]["lang"];
|
| Another observation: You write: m = new
| SpeechSynthesisUtterance; m.text = "Hello";
| speechSynthesis.speak(m); Run that JS and your
| computer will speak to you!
|
| But when I paste those 3 lines into the console, that also does
| not produce any sound here. I tried in Chromium and Firefox, both
| on Linux.
| genewitch wrote:
| moved text to top-level
| netsharc wrote:
| Seems like you need to install additional components:
| https://askubuntu.com/questions/761975/chromium-is-not-gener...
|
| Question/answers from 2016, so might be misleading...
| LazarSRB wrote:
| funny and creepy
| genewitch wrote:
| works on Firefox, on windows 11.
|
| however even when it is working, it's not really like a numbers
| station. For a start, it needs varying static and clicks.
| Secondly, numbers stations don't _generally_ say "seven
| _hundred_ and _thirty_ four ", they generally say "seven. three.
| four." the random words repeated sometimes are a nice touch,
| though. And i like the idea of grabbing words from an internal
| list in the way the author did it. I wouldn't have thought of
| that, probably.
|
| some numbers stations that i personally archived:
| https://soundcloud.com/djoutcold/31-may-2014-170948-19008500-mhz
| https://soundcloud.com/djoutcold/uvb-76-aug-23-2010-9-32ampst
| https://nextcloud.projectftm.com/index.php/s/unid-pizza-numbers
| [0]
|
| here's one that sounds like a numbers station but can be argued
| is not, as the meaning is rather clear (if my memory serves):
| https://soundcloud.com/djoutcold/sdrsharp-20150825-020508z-4368kh
| z-af
|
| [0] i think this one is a joke; this one is the most
| representative of what numbers stations _used_ to be like,
| though. Whoever made it really knew what they were doing, even
| though they used their knowledge to be a bit cheeky. I edited it
| because the music would blow out your speakers originally.
|
| additionally, i know the 19008500-mhz is mislabeled, it should be
| 19.008500-mhz or instead of "mhz" just "hz"
| edent wrote:
| I'd love it if you forked my code and managed to fit a full
| numbers station into 1024KB.
| genewitch wrote:
| my kid wanted it to say point between the groupings, which is
| the speech engine, so this may sound different depending on
| your browser: <!DOCTYPE
| html><html><body><button onclick="f()">Start</button><script>
| function f(){with(window){ a=new AudioContext;b=a.creat
| eBuffer(1,c=2*a.sampleRate,a.sampleRate);d=b.getChannelData(0
| ); for(i=0;i<c;i++)d[i]=(Math.random()*2-1)*.4; e
| =a.createBufferSource();e.buffer=b;e.loop=1;g=a.createGain();
| g.gain.value=.05;
| e.connect(g).connect(a.destination);e.start(); const l=
| n=>((n.match(/[A-Z]/g)||[]).length==1&&(n[0].match(/[A-Z]/g)|
| |[]).length==1); setInterval(()=>{s=Object.getOwnProper
| tyNames(globalThis).filter(l).sort(()=>.5-Math.random())[0];
| if(Math.random()>.3){ n=String(Math.ceil(Math.random(
| )*1e4).toString().padStart(4,'0')); s=n[0]+'.
| '+n[1]+'. point. '+n[2]+'. '+n[3]+'.'; } m=new
| SpeechSynthesisUtterance;m.text=s; v=speechSynthesis.ge
| tVoices();m.lang=v[(Math.random()*v.length)|0].lang; m.
| rate=Math.random();m.pitch=Math.random()*2;speechSynthesis.sp
| eak(m);},866);
| //m.rate=1.7;m.pitch=2;speechSynthesis.speak(m);},866);
| }}</script></body></html>
|
| the comment at the end can be switched with the preceeding
| line so it sounds like he wanted it to (high pitched and
| fast, please) <1kb
|
| and i got something stuck in my craw about noise so here's
| one with more accurate noise: <!DOCTYPE
| html><html><body><button onclick="f()">Start</button><script>
| function f(){with(window){ a=new AudioContext;
| g=a.createGain();g.gain.value=.05;
| h=a.createScriptProcessor(256,1,1);p=0;
| h.onaudioprocess=e=>{
| b=e.outputBuffer.getChannelData(0);
| for(i=0;i<b.length;i++)b[i]=p+=(Math.random()*2-1)/10;
| }; h.connect(g).connect(a.destination); const l=n
| =>((n.match(/[A-Z]/g)||[]).length==1&&(n[0].match(/[A-Z]/g)||
| []).length==1); setInterval(()=>{ s=Object.getO
| wnPropertyNames(globalThis).filter(l).sort(()=>.5-Math.random
| ())[0]; if(Math.random()>.3){ n=String(Math
| .ceil(Math.random()*1e4).toString().padStart(4,'0'));
| s=n[0]+'. '+n[1]+'. point. '+n[2]+'. '+n[3]+'.'; }
| m=new SpeechSynthesisUtterance;m.text=s; v=speechSynt
| hesis.getVoices();m.lang=v[(Math.random()*v.length)|0].lang;
| m.rate=Math.random();m.pitch=Math.random()*2;speechSynthesis.
| speak(m); },866); }}</script></body></html>
|
| apologies to the HN servers for using 2kb to display these
|
| i don't know javascript so apologies if i messed anything up
| (because it will eventually pop and click which is extremely
| accurate to numbers station reception but also crashes the
| page - audio stops.)
| netsharc wrote:
| It kind of irks me that the idea was neat, but the attempt was
| seriously lacking.
| genewitch wrote:
| i replied in this thread with 855 bytes that do it a little
| closer to what i expected
| netsharc wrote:
| FYI, having "." after numbers in German turn them to
| ordinal numerals (i.e. "4." becomes "4th"). I had to change
| them to commas to make it more familiar to the number
| stations recordings I've heard of.
| genewitch wrote:
| so "neun. vier. punkt. sieben. drei."
|
| doesn't mean 94 . 73 (or 94,73)? i considered using
| "dot". I'd have to listen to a german numbers station
| that uses a splitter like "point" or "dot"
|
| what i'm asking is if you have an ip address like 4.2.2.2
| how would you read that over the phone, in german?
|
| also i made a lot of edits to fix issues during the edit
| window to the _two_ versions i posted
| edent wrote:
| Thanks for your support, I really appreciate it :-)
| genewitch wrote:
| hey i should also apologize. I am really trying to not be
| so nit-picky. You had the idea and executed it in less than
| 1kb. I really meant to just kinda educate about numbers
| stations in general and i know it came off in a way that
| was unintentional.
|
| and i used copilot because i am not a programmer, i just
| wanted to see if it was, in fact, possible to add noise and
| fix the way the numbers were read in 1kb. and i kept your
| code essentially the same, only adding stuff to split the
| numbers up closer to how they sound on RF.
|
| so, sorry!
| simonw wrote:
| This post inspired me to build (OK, vibe code) this little tool
| for playing with the speech synthesis browser API:
| https://tools.simonwillison.net/speech-synthesis
|
| Commits / prompts:
| https://github.com/simonw/tools/commits/main/speech-synthesi...
| tantalor wrote:
| Something is wrong with the voice selector. It does not
| actually change the voice.
| simonw wrote:
| Which browser/OS? I've only tested on mobile Safari.
| tantalor wrote:
| Android Chrome. It seems to be stuck with whatever the last
| random voice used by the numbers station demo and can't be
| changed.
|
| Desktop ChromeOS works fine.
___________________________________________________________________
(page generated 2025-07-22 23:01 UTC)