<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Francesc López</title>
    <description>The latest articles on Forem by Francesc López (@rfranr).</description>
    <link>https://forem.com/rfranr</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F429126%2F8c35b265-3cbc-452c-957f-42a8f81bb6ba.jpg</url>
      <title>Forem: Francesc López</title>
      <link>https://forem.com/rfranr</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/rfranr"/>
    <language>en</language>
    <item>
      <title>80% of JavaScript code comes from 20% of its features?</title>
      <dc:creator>Francesc López</dc:creator>
      <pubDate>Sat, 04 Oct 2025 21:27:47 +0000</pubDate>
      <link>https://forem.com/rfranr/80-of-javascript-code-comes-from-20-of-its-features-3bpe</link>
      <guid>https://forem.com/rfranr/80-of-javascript-code-comes-from-20-of-its-features-3bpe</guid>
      <description>&lt;p&gt;I analyzed several popular JavaScript repositories to see how much of the language is actually used in real projects.&lt;/p&gt;

&lt;p&gt;Turns out the 80/20 rule is real — about &lt;strong&gt;20–25% of language features&lt;/strong&gt; cover &lt;strong&gt;80–90% of the code&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I believe the data and interpretation are roughly correct — but I’m always open to feedback or alternative views.&lt;/p&gt;

&lt;p&gt;Aggregate Per 1K LOC&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcbom664y6ivfkpoyxibi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcbom664y6ivfkpoyxibi.png" alt="Aggregate per KLOC" width="800" height="466"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Aggregate Analysis Summary
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Dataset Overview:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Total repositories analyzed: 55&lt;/li&gt;
&lt;li&gt;Total features in JavaScript catalog: 121&lt;/li&gt;
&lt;li&gt;Analysis covers: totals, presence, perKLOC metrics&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Total Occurrences - Aggregate Results
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;80% of totals&lt;/strong&gt; achieved with &lt;strong&gt;17&lt;/strong&gt; features &lt;strong&gt;(14.0% of catalog)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;90% of totals&lt;/strong&gt; achieved with &lt;strong&gt;30&lt;/strong&gt; features &lt;strong&gt;(24.8% of catalog)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;95% of totals&lt;/strong&gt; achieved with &lt;strong&gt;42&lt;/strong&gt; features &lt;strong&gt;(34.7% of catalog)&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  File Presence - Aggregate Results
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;80% of presence&lt;/strong&gt; achieved with &lt;strong&gt;33&lt;/strong&gt; features &lt;strong&gt;(27.3% of catalog)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;90% of presence&lt;/strong&gt; achieved with &lt;strong&gt;46&lt;/strong&gt; features &lt;strong&gt;(38.0% of catalog)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;95% of presence&lt;/strong&gt; achieved with &lt;strong&gt;60&lt;/strong&gt; features &lt;strong&gt;(49.6% of catalog)&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Per 1000 Lines of Code - Aggregate Results
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;80% of perKLOC&lt;/strong&gt; achieved with &lt;strong&gt;21&lt;/strong&gt; features &lt;strong&gt;(17.4% of catalog)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;90% of perKLOC&lt;/strong&gt; achieved with &lt;strong&gt;34&lt;/strong&gt; features &lt;strong&gt;(28.1% of catalog)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;95% of perKLOC&lt;/strong&gt; achieved with &lt;strong&gt;46&lt;/strong&gt; features &lt;strong&gt;(38.0% of catalog)&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Top 7 Features
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rank&lt;/th&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Count&lt;/th&gt;
&lt;th&gt;%&lt;/th&gt;
&lt;th&gt;Cumulative %&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;binaryOp_/&lt;/td&gt;
&lt;td&gt;1298069&lt;/td&gt;
&lt;td&gt;20.08%&lt;/td&gt;
&lt;td&gt;20.08%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;labels&lt;/td&gt;
&lt;td&gt;781944&lt;/td&gt;
&lt;td&gt;12.09%&lt;/td&gt;
&lt;td&gt;32.17%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;assignOp_=&lt;/td&gt;
&lt;td&gt;711165&lt;/td&gt;
&lt;td&gt;11.00%&lt;/td&gt;
&lt;td&gt;43.17%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;functions&lt;/td&gt;
&lt;td&gt;392279&lt;/td&gt;
&lt;td&gt;6.07%&lt;/td&gt;
&lt;td&gt;49.24%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;return&lt;/td&gt;
&lt;td&gt;265406&lt;/td&gt;
&lt;td&gt;4.10%&lt;/td&gt;
&lt;td&gt;53.34%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;if&lt;/td&gt;
&lt;td&gt;255167&lt;/td&gt;
&lt;td&gt;3.95%&lt;/td&gt;
&lt;td&gt;57.29%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;binaryOp_+&lt;/td&gt;
&lt;td&gt;253173&lt;/td&gt;
&lt;td&gt;3.92%&lt;/td&gt;
&lt;td&gt;61.21%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Pareto Analysis
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;80% of usage&lt;/strong&gt; comes from &lt;strong&gt;17&lt;/strong&gt; features &lt;strong&gt;(14.0% of catalog)&lt;/strong&gt;:&lt;br&gt;
binaryOp_/, labels, assignOp_=, functions, return, if, binaryOp_+, binaryOp_*, binaryOp_|, arrowFunctions, binaryOp_===, binaryOp_-, binaryOp_&amp;gt;&amp;gt;, logicalAND, binaryOp_&amp;lt;, ternary, awaitExpressions&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;90% of usage&lt;/strong&gt; comes from &lt;strong&gt;30&lt;/strong&gt; features &lt;strong&gt;(24.8% of catalog)&lt;/strong&gt;:&lt;br&gt;
binaryOp_/, labels, assignOp_=, functions, return, if, binaryOp_+, binaryOp_*, binaryOp_|, arrowFunctions, binaryOp_===, binaryOp_-, binaryOp_&amp;gt;&amp;gt;, logicalAND, binaryOp_&amp;lt;, ternary, awaitExpressions, logicalOR, binaryOp_&amp;gt;, binaryOp_!==, exportDecls_named, importDecls, switchCases, jsxElements, updateOp_++, templateLiterals, forClassic, asyncFunctions, break, spreadElement&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;95% of usage&lt;/strong&gt; comes from &lt;strong&gt;42&lt;/strong&gt; features &lt;strong&gt;(34.7% of catalog)&lt;/strong&gt;:&lt;br&gt;
binaryOp_/, labels, assignOp_=, functions, return, if, binaryOp_+, binaryOp_*, binaryOp_|, arrowFunctions, binaryOp_===, binaryOp_-, binaryOp_&amp;gt;&amp;gt;, logicalAND, binaryOp_&amp;lt;, ternary, awaitExpressions, logicalOR, binaryOp_&amp;gt;, binaryOp_!==, exportDecls_named, importDecls, switchCases, jsxElements, updateOp_++, templateLiterals, forClassic, asyncFunctions, break, spreadElement, classFields, classMethods, binaryOp_==, binaryOp_&amp;gt;&amp;gt;&amp;gt;, interpolatedTemplates, throw, classDecls, binaryOp_&amp;amp;, assignOp_+=, binaryOp_&amp;lt;&amp;lt;, binaryOp_%, updateOp_--&lt;/p&gt;

&lt;h3&gt;
  
  
  Catalog Usage Summary
&lt;/h3&gt;

&lt;p&gt;Total features in JavaScript catalog: &lt;strong&gt;121&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Usage Threshold&lt;/th&gt;
&lt;th&gt;Features Required&lt;/th&gt;
&lt;th&gt;Catalog Percentage&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;80%&lt;/td&gt;
&lt;td&gt;17&lt;/td&gt;
&lt;td&gt;14.0%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;90%&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;td&gt;24.8%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;95%&lt;/td&gt;
&lt;td&gt;42&lt;/td&gt;
&lt;td&gt;34.7%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;







&lt;h4&gt;
  
  
  Metrics explained
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Totals&lt;/strong&gt; How often each feature appears overall across all repositories. Shows which constructs dominate codebases globally (like &lt;code&gt;if&lt;/code&gt;, &lt;code&gt;=&lt;/code&gt;, or &lt;code&gt;function&lt;/code&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Presence&lt;/strong&gt; In how many different files a feature is found.  Reflects how widespread a construct is — some appear everywhere, others only in a few modules.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Per KLOC&lt;/strong&gt; Density per 1000 lines of code. Normalizes for project size, letting you compare big and small repos fairly.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each of these views shows a clear &lt;strong&gt;Pareto pattern&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
A small core of features (around 20–30 out of 121) accounts for most of the language usage.&lt;/p&gt;

&lt;p&gt;You can see the results and charts here:&lt;br&gt;&lt;br&gt;
&lt;a href="https://rfranr.github.io/pareto-analysis-js/" rel="noopener noreferrer"&gt;Live reports&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/rfranr/pareto-analysis-js" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Any comments or insights are welcome &lt;/p&gt;

</description>
      <category>javascript</category>
      <category>pareto</category>
      <category>data</category>
    </item>
    <item>
      <title>Live Transcription of a Radio Station with Whisper in Vibe Coding Mode</title>
      <dc:creator>Francesc López</dc:creator>
      <pubDate>Mon, 09 Jun 2025 14:25:20 +0000</pubDate>
      <link>https://forem.com/rfranr/live-transcription-of-a-radio-station-with-whisper-in-vibe-coding-mode-3abe</link>
      <guid>https://forem.com/rfranr/live-transcription-of-a-radio-station-with-whisper-in-vibe-coding-mode-3abe</guid>
      <description>&lt;h2&gt;
  
  
  The Project
&lt;/h2&gt;

&lt;p&gt;This project is a small experiment to capture and transcribe in real time an audio stream from a radio station and display the most relevant fragments using a minimalist web interface. All of it is automated with Docker.&lt;/p&gt;

&lt;p&gt;It's also a personal &lt;em&gt;vibe coding&lt;/em&gt; test, done with a clear goal but no prior planning—just following intuition to see how far one can accelerate development. Although the project works, I acknowledge that with this process you lose part of the pleasure of structured knowledge and planning, which would make the solution more robust and scalable.&lt;/p&gt;

&lt;p&gt;This fast and improvised way of coding tends to skip certain abstractions and structures that are often what enable deeper creativity: the kind that emerges when tools not only work, but you understand &lt;em&gt;why&lt;/em&gt; they work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Access the Demo
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Try it: &lt;a href="https://eurekatop.com/radioalert" rel="noopener noreferrer"&gt;https://eurekatop.com/radioalert&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;SSE Endpoint: &lt;a href="https://eurekatop.com/radioalert/events" rel="noopener noreferrer"&gt;https://eurekatop.com/radioalert/events&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flz8m5sjc809qht3cn5ga.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flz8m5sjc809qht3cn5ga.png" alt="screenshot" width="800" height="680"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Backend: Automatic Transcription with Whisper
&lt;/h3&gt;

&lt;p&gt;The core of the project is a Python script that listens to the stream as if it were a browser. At first, I tried using &lt;code&gt;ffmpeg&lt;/code&gt; to capture the stream, but it failed because the station has anti-bot protections and the connection was not accepted.&lt;/p&gt;

&lt;p&gt;As an alternative, I found that using &lt;code&gt;httpx.stream()&lt;/code&gt; allows reading the audio stream without issues—as long as the request looks like a real browser's. That’s why you need to add some headers...&lt;/p&gt;

&lt;p&gt;The script is split into two parts: one for capturing the stream and another for transcription and keyword filtering. This transcription runs in parallel with the stream capture, so there's no need to wait for it to finish before continuing to capture.&lt;/p&gt;

&lt;p&gt;The audio is processed in 4-second chunks and transcribed using the optimized &lt;em&gt;Whisper&lt;/em&gt; model (&lt;code&gt;int8&lt;/code&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;WhisperModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/models/whisper-small&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;compute_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;int8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;segments&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transcribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;BytesIO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;audio_data&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;language&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ca&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once transcribed, it checks for keywords like “barça”, “avui”, or “lamine yamal”. If any are found, it triggers an alert and logs everything to a &lt;code&gt;.log&lt;/code&gt; file. For example:&lt;/p&gt;

&lt;p&gt;🕒 [2025-06-09 14:10:23] 🗣️ [12] avui a catalunya hem vist que...&lt;br&gt;&lt;br&gt;
🚨 🕒 [2025-06-09 14:10:23] ALERT: Keyword detected: avui&lt;/p&gt;

&lt;p&gt;The system includes a short queue of previous audio to avoid cutting off sentence beginnings, since the model needs context to understand the stream correctly.&lt;/p&gt;

&lt;p&gt;All of it is automated with Docker.&lt;/p&gt;
&lt;h3&gt;
  
  
  Frontend: Live Visualization
&lt;/h3&gt;

&lt;p&gt;A small Node.js server displays the transcribed lines live from a &lt;code&gt;.log&lt;/code&gt; file, sending them via Server-Sent Events to the terminal-style web interface.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;FILE_PATH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nx"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;line&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`data: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;line&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;\n\n`&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the client side, the connection remains open with the browser's &lt;code&gt;EventSource()&lt;/code&gt;, which automatically receives real-time updates:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;eventSource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;EventSource&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/events&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;eventSource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onmessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Learnings
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Whisper is quite reliable.&lt;/li&gt;
&lt;li&gt;Adding a buffer of previous audio improves accuracy in clipped sentences.&lt;/li&gt;
&lt;li&gt;With &lt;code&gt;httpx.stream&lt;/code&gt; and lightweight threads, you can capture audio stably without overloading the main process. &lt;code&gt;ffmpeg&lt;/code&gt; was initially used but discarded to avoid anti-bot protections by simulating a real browser connection.&lt;/li&gt;
&lt;li&gt;Server-Sent Events are a very simple yet effective tool to stream live data to a web app.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Stack and Techniques
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;🐍 Python + &lt;a href="https://github.com/guillaumekln/faster-whisper" rel="noopener noreferrer"&gt;faster-whisper&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;📡 httpx for capturing audio streams&lt;/li&gt;
&lt;li&gt;🎛️ Transcription with the optimized Whisper-small model&lt;/li&gt;
&lt;li&gt;🐳 Docker to encapsulate the service&lt;/li&gt;
&lt;li&gt;🟩 Node.js + Express to expose the file as an SSE feed&lt;/li&gt;
&lt;li&gt;🎨 HTML + CSS in terminal-console style&lt;/li&gt;
&lt;/ul&gt;




</description>
      <category>experiments</category>
      <category>transcription</category>
      <category>vibecoding</category>
    </item>
    <item>
      <title>Visualizing MIDI with Three.js, Tone.js, and TypeScript</title>
      <dc:creator>Francesc López</dc:creator>
      <pubDate>Sat, 05 Apr 2025 10:00:23 +0000</pubDate>
      <link>https://forem.com/rfranr/visualizing-midi-with-threejs-tonejs-and-typescript-267i</link>
      <guid>https://forem.com/rfranr/visualizing-midi-with-threejs-tonejs-and-typescript-267i</guid>
      <description>&lt;p&gt;Some time ago i built a fun little music visualizer that reads a MIDI file and generates a 3D piano roll in sync with the music. The project combines music and 3D graphics for a creative coding experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  🧠 Idea
&lt;/h2&gt;

&lt;p&gt;The concept is simple: load a MIDI file, and use Three.js to create the 3D visuals triggered by the notes. Tone.js handles the MIDI playback, and everything runs in the browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔧 Tech Stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://threejs.org/" rel="noopener noreferrer"&gt;Three.js&lt;/a&gt; for 3D rendering&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://tonejs.github.io/" rel="noopener noreferrer"&gt;Tone.js&lt;/a&gt; for MIDI playback&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://vitejs.dev/" rel="noopener noreferrer"&gt;Vite&lt;/a&gt; for bundling and development&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TypeScript&lt;/strong&gt; for type-safety and cleaner code&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🎮 Try it live
&lt;/h2&gt;

&lt;p&gt;👉 &lt;a href="https://fresh-skate.surge.sh/" rel="noopener noreferrer"&gt;Live demo on Surge&lt;/a&gt;&lt;br&gt;&lt;br&gt;
📦 &lt;a href="https://github.com/rfranr/game.midi-jumper" rel="noopener noreferrer"&gt;Source code on GitHub&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🧩 What could be better
&lt;/h2&gt;

&lt;p&gt;Some parts of the code are a bit rough. Still, it's fun to share this as-is!&lt;/p&gt;

&lt;h2&gt;
  
  
  💭 Let me know what you think
&lt;/h2&gt;

&lt;p&gt;Thanks for reading, and I hope you enjoy the music! 🎧✨&lt;/p&gt;

</description>
      <category>creativecoding</category>
      <category>threejs</category>
      <category>tonejs</category>
    </item>
  </channel>
</rss>
