<?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>DEV Community: Manu MA</title>
    <description>The latest articles on DEV Community by Manu MA (@manucorporat).</description>
    <link>https://dev.to/manucorporat</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F226506%2Fc2100326-415d-429d-9360-62c57edfa37a.jpeg</url>
      <title>DEV Community: Manu MA</title>
      <link>https://dev.to/manucorporat</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/manucorporat"/>
    <language>en</language>
    <item>
      <title>NoiseLang: Where N = 5 is a Dirac delta</title>
      <dc:creator>Manu MA</dc:creator>
      <pubDate>Mon, 06 Jul 2026 00:00:00 +0000</pubDate>
      <link>https://dev.to/manucorporat/noiselang-where-n-5-is-a-dirac-delta-2e8d</link>
      <guid>https://dev.to/manucorporat/noiselang-where-n-5-is-a-dirac-delta-2e8d</guid>
      <description>&lt;p&gt;During &lt;a href="https://www.tel.uva.es/en/studies/degrees/itec.htm" rel="noopener noreferrer"&gt;my telecommunications degree&lt;/a&gt; I took a course on signals and noise, I spent a lot of evenings writing probability by hand: expectations, variances, the odds of two random variables landing in some region. It always sucked, when I tried to run it on a computer, so much boilerplate.&lt;/p&gt;

&lt;p&gt;That wish became &lt;a href="https://noiselang.com" rel="noopener noreferrer"&gt;NoiseLang&lt;/a&gt;. I started it about nine years ago, however, I never finished it. Only recently, I brought it back thanks to AI tools and something far more ambitious than what I could have built alone the first time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Everything is a distribution
&lt;/h2&gt;

&lt;p&gt;The whole language hangs on one idea, that &lt;strong&gt;every value is a probability distribution&lt;/strong&gt;. A plain number is a Dirac spike, a distribution with all its weight on a single value. Since constants and random variables are the same kind of object, every operator in the language maps distributions to distributions.&lt;/p&gt;

&lt;p&gt;A name always refers to one fixed node, the same way &lt;code&gt;X&lt;/code&gt; is the same &lt;code&gt;X&lt;/code&gt; across a whole page of math. So &lt;code&gt;X + X&lt;/code&gt; is &lt;code&gt;2X&lt;/code&gt; and &lt;code&gt;X - X&lt;/code&gt; is exactly &lt;code&gt;0&lt;/code&gt;,. If you want variable independence you write separate draws, ie, using &lt;code&gt;~&lt;/code&gt; multiple times, or &lt;code&gt;~[N]&lt;/code&gt; to draw &lt;code&gt;N&lt;/code&gt; independent variables into a vector.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;X ~ unif_int(1, 6)
Y ~ unif_int(1, 6)
X + Y # two independent dice, a real 2d6 distribution

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing runs until you ask for some results, for example, &lt;code&gt;P(X + Y &amp;lt; 10)&lt;/code&gt;, at that moment it forces the runtime to run millions of simulations (across all cores, if available) and return an estimate with a standard error attached.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Bday = unif_int(1, 365)
days ~[23] Bday # 23 people in a room
P(has_duplicates(days)) # the birthday paradox, about 0.507

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is much easier to watch than to describe, so I built some cool demos!&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it sat for nine years
&lt;/h2&gt;

&lt;p&gt;The design was never the hard part, because a parser and a tree-walking interpreter for this language is a weekend of work. The problem was everything else, writing a efficient Monte Carlo runtime, instead of a naive interpreter, conditional bayesian inference, and more.&lt;/p&gt;

&lt;p&gt;Current version is a compiler, a JIT (using the amazing &lt;a href="https://cranelift.dev/" rel="noopener noreferrer"&gt;Cranelift&lt;/a&gt;), a &lt;a href="https://webassembly.org/" rel="noopener noreferrer"&gt;WASM&lt;/a&gt; backend, and a pile of careful numerical code, so for a cute-weekend project it stayed permanently out of reach.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the ambitious version with an agent
&lt;/h2&gt;

&lt;p&gt;At my day job and side projects, I am experimenting with the boundaries of what today’s AI agents can do. For example, I am also porting a game I built 15 years ago for iOs, in archaic Objective-C to a modern game engine (with relative success).&lt;/p&gt;

&lt;p&gt;With NoiseLand, I realized, AI is great at building the JIT parts, the runtime parts, the numerical parts, but it sucks at coming up with good language design ideas, many times overriding existing language features for different purposes, or coming with with different syntax for non-orthogonal features.&lt;/p&gt;

&lt;h2&gt;
  
  
  One IR, three backends
&lt;/h2&gt;

&lt;p&gt;Under the hood, &lt;code&gt;~&lt;/code&gt; and the distribution constructors build an append-only DAG called the RvGraph. This graph is the single source of truth, which later are converted into three different code paths:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a columnar batch interpreter that works everywhere and acts as the correctness oracle;&lt;/li&gt;
&lt;li&gt;a Cranelift JIT that fuses a whole expression into one native kernel;&lt;/li&gt;
&lt;li&gt;a WASM emitter that does the same for the browser.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flowchart LR
  src["X ~ unif(1, 6)"] --&amp;gt; ir["RvGraph"]
  ir --&amp;gt; interp["batch interpreter"]
  ir --&amp;gt; jit["Cranelift JIT"]
  ir --&amp;gt; wasm["WASM emitter"]
  jit -. fallback .-&amp;gt; interp
  wasm -. fallback .-&amp;gt; interp

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One shared module defines what the graph means, so the two code generators stay thin and cannot drift apart. Anything a backend can’t successfully compile falls back to the interpreter, and the results stay identical across backends and core counts. All tests run in all three code paths and compared to be bit-identical.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making the Monte Carlo loop cheap
&lt;/h2&gt;

&lt;p&gt;All the performance work is about one loop: draw a few million samples, evaluate the expression on each, and reduce the results. A handful of techniques carry most of it, while keeping the results deterministic (that was the hard part).&lt;/p&gt;

&lt;p&gt;Kernel fusion keeps every intermediate value in registers, so an arithmetic-heavy expression stay on registers. The PRNG (&lt;a href="https://prng.di.unimi.it/" rel="noopener noreferrer"&gt;xoshiro256++&lt;/a&gt;) compiles into the kernel, and the &lt;code&gt;ln&lt;/code&gt;, &lt;code&gt;sin&lt;/code&gt;, and &lt;code&gt;cos&lt;/code&gt; become inline polynomial approximations, speeding up the kernel by a factor of 2.&lt;/p&gt;

&lt;p&gt;My favorite trick is in the RNG. Generating random numbers is a serial dependency chain, so instead of fighting that, the kernel runs four independent streams at once and lets the out-of-order core overlap them. This trick ended up beating a hand-written SIMD kernel!&lt;/p&gt;

&lt;p&gt;On my 14-core M4 Pro, a one-line &lt;code&gt;P(...)&lt;/code&gt; sustains around 5.8 billion samples per second and scales about 9.6× from one core to all of them. Per core, the generated kernel runs within about 1.15× of hand-written Rust compiled by LLVM. The same fused loop, emitted as WASM, runs at roughly half to three-quarters of native speed inside V8.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Noise sits
&lt;/h2&gt;

&lt;p&gt;NoiseLang is a toy language, &lt;strong&gt;you probably should not use it for anything serious&lt;/strong&gt; , however I wish this language existed during my university days.&lt;/p&gt;

&lt;p&gt;For a language nerd, it’s a small, static random-variable algebra with forward Monte Carlo, expression-based, rejection-based conditioning, language.&lt;/p&gt;

&lt;p&gt;You might ask, how does it compare to NumPy or Stan? NumPy makes you write the simulation yourself, and Stan makes you declare a model and wait for a sampler. Noise lets you write the probability as math while running Monte Carlo under the hood to get the answer.&lt;/p&gt;

&lt;p&gt;Stan and PyMC beat Noise at the thing they’re built for, fitting a posterior to lots of continuous data with their HMC/NUTS samplers, and NumPy beats it at raw array crunching. Conditioning in Noise is rejection-based, so it works great for a handful of discrete observations but becomes useless for ten thousand continuous measurements, and there is no stateful simulation yet (no Markov chains yet). Where Noise wins when you have a probability question and you wanna know the answer without much hassle.&lt;/p&gt;

&lt;p&gt;So use Noise for the whiteboard stage of a problem, when you want to run the math you just wrote, and move to Stan or PyMC when you need a real posterior, or to NumPy and JAX when you need to go to production.&lt;/p&gt;

&lt;h2&gt;
  
  
  Back to signals and noise
&lt;/h2&gt;

&lt;p&gt;Going back to my university days, there was this subject called “Señales Aleatorias Y Ruido”, which is a spanish translation of “Random Signals and Noise”.&lt;/p&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffdvma0798pwovjanewm0.jpg" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffdvma0798pwovjanewm0.jpg" alt="Cover of the textbook Señales Aleatorias y Ruido" width="800" height="1095"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The textbook, in all its glory.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This subject was the nightmare of many students, including myself, in fact, I failed it. Truth be told, I didn’t put enough effort into it during the first year, but it changed when I had the take the same subject again in the second year. The professor was great, and made the subject interesting. The things that blew my mind was how he could model why FM survives a noisy channel when AM doesn’t.&lt;/p&gt;

&lt;p&gt;So, here is my tribute to the subject, a one-screen Noise program that models why FM survives a noisy channel when AM doesn’t.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run NoiseLang in the browser
&lt;/h2&gt;

&lt;p&gt;Everything above runs on &lt;a href="https://www.npmjs.com/package/@noiselang/core" rel="noopener noreferrer"&gt;&lt;code&gt;@noiselang/core&lt;/code&gt;&lt;/a&gt;, thanks to the Rust engine compiled to WebAssembly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;npm&lt;/span&gt; &lt;span class="nx"&gt;install&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;noiselang&lt;/span&gt;&lt;span class="sr"&gt;/cor&lt;/span&gt;&lt;span class="err"&gt;e
&lt;/span&gt;


&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`
  X ~ rand::unif(-1, 1);
  Y ~ rand::unif(-1, 1);
  4 * P(X^2 + Y^2 &amp;lt; 1)
`&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;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// "3.1415…" — the last statement's value&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;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// everything Print(...) emitted&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;run&lt;/code&gt; never throws, failures come back on &lt;code&gt;result.error&lt;/code&gt; with a source span. There is also&lt;code&gt;runWithIntrospection&lt;/code&gt;, the API behind the variable inspector at &lt;a href="https://noiselang.com" rel="noopener noreferrer"&gt;noiselang.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;NoiseLang is playable in the browser at &lt;a href="https://noiselang.com" rel="noopener noreferrer"&gt;noiselang.com&lt;/a&gt;. Open it, type&lt;code&gt;X ~ unif(-1, 1); Y ~ unif(-1, 1); 4 * P(X^2 + Y^2 &amp;lt; 1)&lt;/code&gt;, and watch a few million draws estimate π from your browser tab.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href="https://manualmeida.dev/articles/noiselang" rel="noopener noreferrer"&gt;This article has interactive figures — read it on manualmeida.dev.&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>systems</category>
      <category>programminglanguages</category>
      <category>probability</category>
      <category>compilers</category>
    </item>
    <item>
      <title>Building Gin: Simple Over Easy</title>
      <dc:creator>Manu MA</dc:creator>
      <pubDate>Tue, 30 Jun 2026 00:00:00 +0000</pubDate>
      <link>https://dev.to/manucorporat/building-gin-simple-over-easy-437p</link>
      <guid>https://dev.to/manucorporat/building-gin-simple-over-easy-437p</guid>
      <description>&lt;p&gt;In 2014 I came back from San Francisco with no plan. I spent a year building SDKs at Joypad and TinySpark after shipping one of my first games, and that year gave me a good sense of what small software teams need from their tools. Back in Spain, about to start Telecommunications Engineering, I had to decide what to build next.&lt;/p&gt;

&lt;p&gt;The answer was Fyve, a social network built around people’s interests. I chose &lt;a href="https://go.dev/" rel="noopener noreferrer"&gt;Go&lt;/a&gt;for the backend because the language felt plain in the right way, and &lt;a href="https://gin-gonic.com/" rel="noopener noreferrer"&gt;Gin&lt;/a&gt;started as the web framework for that product. The code still lives at &lt;a href="https://github.com/gin-gonic/gin" rel="noopener noreferrer"&gt;gin-gonic/gin&lt;/a&gt;.&lt;/p&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcs5m8ufhpfzvtt8zacmt.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcs5m8ufhpfzvtt8zacmt.png" alt="Gin Gonic Go framework illustration" width="799" height="292"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fyve never took off. Gin, the tool I built along the way, is still going twelve years later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Simple over easy
&lt;/h2&gt;

&lt;p&gt;At the time, the Go web framework people kept pointing me to was&lt;a href="https://github.com/go-martini/martini" rel="noopener noreferrer"&gt;Martini&lt;/a&gt;. I understood why immediately. The README was small, the middleware model felt elegant, and you could get a route responding in minutes.&lt;/p&gt;

&lt;p&gt;Martini used reflection-based dependency injection to wire handlers together, which made the first demo feel smooth but also moved important behavior out of sight. Services appeared in your handlers without any visible wiring, so when something misbehaved the control flow was hard to trace. And all of that reflection ran on every single request.&lt;/p&gt;

&lt;p&gt;Around then I watched Rob Pike’s&lt;a href="https://www.youtube.com/watch?v=rFejpH_tAHM" rel="noopener noreferrer"&gt;Simplicity is Complicated&lt;/a&gt;, and it gave me vocabulary for what bothered me about Martini. What stuck with me was the idea that simple software often takes more work from the person building it so that it can take less work from the person using it.&lt;/p&gt;

&lt;p&gt;That became the design brief for Gin. Easy is about how good the first example looks, and Martini’s first example looked great. Simple is about how many moving parts you have to understand, and how many exceptions you have to remember, once the codebase is old enough to surprise you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding the middle ground
&lt;/h2&gt;

&lt;p&gt;Aristotle’s version of virtue was the middle ground: &lt;strong&gt;not too much, not too little.&lt;/strong&gt; That was the shape of the framework problem too.&lt;/p&gt;

&lt;p&gt;Martini gave you too much magic. Plain &lt;a href="https://pkg.go.dev/net/http" rel="noopener noreferrer"&gt;net/http&lt;/a&gt; gives you full control and no surprises, but it helps you with almost nothing, so you end up writing the same plumbing for route params, request parsing, validation, and responses in handler after handler. None of it is hard, but it makes the code noisy.&lt;/p&gt;

&lt;p&gt;Gin was my attempt at the point between the two. The request path stays explicit, nothing on it uses reflection, and the repetitive plumbing lives in a single object called the Context.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;gin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/users/:id"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;gin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Param&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// path params, no reflection&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;H&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="c"&gt;// response rendering, one call&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":8080"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That &lt;code&gt;*gin.Context&lt;/code&gt; carries the request, the response writer, path parameters, validation helpers, and rendering, so it’s the only thing you pass around. The common operations sit one method call away, and behind them is plain Go code you can step into when production gets weird.&lt;/p&gt;

&lt;p&gt;Funny enough, &lt;code&gt;gin.Context&lt;/code&gt; shipped in 2014, two years before the standard library’s&lt;a href="https://pkg.go.dev/context" rel="noopener noreferrer"&gt;&lt;code&gt;context.Context&lt;/code&gt;&lt;/a&gt; existed. When the standard one arrived we kept our name and made &lt;code&gt;gin.Context&lt;/code&gt; satisfy the new interface, so every existing program kept compiling and you could pass a &lt;code&gt;gin.Context&lt;/code&gt; anywhere a &lt;code&gt;context.Context&lt;/code&gt; was expected.&lt;/p&gt;

&lt;p&gt;That instinct came from the SDK years. When the convenient way to do something is also the right way, people write better code without noticing.&lt;/p&gt;

&lt;h2&gt;
  
  
  A router built around a radix tree
&lt;/h2&gt;

&lt;p&gt;The router is where the simple-over-easy line became concrete. Martini matched requests by walking a list of regular expressions and asking each one whether it matched. Regexes are flexible, since you can make a route match only numbers or hide extra rules inside the pattern, but they’re also a second language living inside your framework.&lt;/p&gt;

&lt;p&gt;Gin’s route language is smaller. You get static segments, named parameters, and catch-alls, and that restriction is exactly what lets the router use a&lt;a href="https://en.wikipedia.org/wiki/Radix_tree" rel="noopener noreferrer"&gt;radix tree&lt;/a&gt;, the same approach&lt;a href="https://github.com/julienschmidt/httprouter" rel="noopener noreferrer"&gt;httprouter&lt;/a&gt; made popular in Go. It also had a side effect I came to appreciate. Since the route language gives you nothing to be clever with, routes written for Gin tend to be regular and boring.&lt;/p&gt;

&lt;p&gt;Matching &lt;code&gt;/blog/42/comments&lt;/code&gt; walks &lt;code&gt;/blog/&lt;/code&gt; down to the &lt;code&gt;:slug&lt;/code&gt; node, binds &lt;code&gt;42&lt;/code&gt;, and continues into&lt;code&gt;/comments&lt;/code&gt;. The cost of a lookup depends on the length of the URL, and it stays the same whether the app has ten routes registered or ten thousand. Routes that share a prefix also share nodes, so a big route table stays compact in memory.&lt;/p&gt;

&lt;p&gt;For a router holding $n$ routes and a request path of length $k$, a radix-tree lookup runs in&lt;/p&gt;

&lt;p&gt;$$ T_\text{match}(k) = O(k), \quad \text{independent of } n, $$&lt;/p&gt;

&lt;p&gt;while checking a list of $n$ regexes costs $O(n \cdot m)$ for patterns of length $m$. The tree trades the per-request scan for a single walk down the shared prefix.&lt;/p&gt;

&lt;p&gt;The allocations follow the same thinking. Path parameters go into a preallocated slice, and Context objects come out of a &lt;code&gt;sync.Pool&lt;/code&gt; and get reset between requests, so the garbage collector has less junk to clean up and latency has fewer reasons to wobble.&lt;/p&gt;

&lt;p&gt;I trust this kind of performance work because the speed comes from doing fewer things, and doing fewer things also leaves the person reading the code with less to understand.&lt;/p&gt;

&lt;h2&gt;
  
  
  Designing for zero breaking changes
&lt;/h2&gt;

&lt;p&gt;The other constraint I gave myself was backward compatibility. Go had made a&lt;a href="https://go.dev/doc/go1compat" rel="noopener noreferrer"&gt;compatibility promise&lt;/a&gt; for the language itself, and I wanted Gin to offer its users the same deal.&lt;/p&gt;

&lt;p&gt;That constraint changes how you design. Before anything goes into the public API you ask whether you’d be happy maintaining it for ten years, because removing it later is off the table. You learn to reject the clever rename that saves five characters, and to treat every exported function as something a stranger might have built a company on.&lt;/p&gt;

&lt;p&gt;The constraint held. Some of the first programs ever written against Gin still compile and run today, more than a decade later, and I’m prouder of that than of any benchmark.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hacker News, and then growth
&lt;/h2&gt;

&lt;p&gt;I &lt;a href="https://news.ycombinator.com/item?id=7966700" rel="noopener noreferrer"&gt;released Gin on Hacker News&lt;/a&gt; at the right moment. Go was getting attention there, and a framework that fit in one README and benchmarked well was easy for people to try.&lt;/p&gt;

&lt;p&gt;The growth after that was steady. People used it, filed issues, sent patches, and put it in real services, and today Gin sits around 88k stars with more than 290k projects depending on it.&lt;/p&gt;

&lt;p&gt;Stars are a vanity metric, and I mostly treat them that way. The dependency count is the number I care about, because each of those projects is a bet that the API won’t break underneath them, and that bet has kept paying off long after Fyve disappeared.&lt;/p&gt;

&lt;h2&gt;
  
  
  Letting it graduate
&lt;/h2&gt;

&lt;p&gt;A few years in, I stepped back and handed Gin to maintainers who kept improving it without me. I think of that as the project graduating. Special kudos to &lt;a href="https://github.com/appleboy" rel="noopener noreferrer"&gt;Bo-Yi Wu&lt;/a&gt; and&lt;a href="https://github.com/javierprovecho" rel="noopener noreferrer"&gt;Javier Provecho&lt;/a&gt;, who carried it forward and kept the bar high.&lt;/p&gt;

&lt;p&gt;That’s the part of open source I respect most, when a project stops needing its author. Gin has since absorbed years of other people’s use cases, priorities, and taste, and it came out better for it.&lt;/p&gt;

&lt;p&gt;If you’re building a library, that’s the bar I’d aim for. Design an API you can imagine keeping for ten years, and make it simple underneath even when that costs more than making it easy, because with any luck the thing will outgrow you.&lt;/p&gt;

&lt;p&gt;I tried to do the same thing a few years later on a compiler, which is the story of&lt;a href="https://manualmeida.dev/articles/qwik-resumability" rel="noopener noreferrer"&gt;Qwik&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href="https://manualmeida.dev/articles/gin-simple-over-easy" rel="noopener noreferrer"&gt;This article has interactive figures — read it on manualmeida.dev.&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>go</category>
      <category>performance</category>
      <category>http</category>
    </item>
    <item>
      <title>Qwik: Resumability That Feels Like React</title>
      <dc:creator>Manu MA</dc:creator>
      <pubDate>Tue, 09 May 2023 00:00:00 +0000</pubDate>
      <link>https://dev.to/manucorporat/qwik-resumability-that-feels-like-react-i8e</link>
      <guid>https://dev.to/manucorporat/qwik-resumability-that-feels-like-react-i8e</guid>
      <description>&lt;h2&gt;
  
  
  Performance is a human problem, not a technology one
&lt;/h2&gt;

&lt;p&gt;The thing I came to believe working on Qwik is that the web’s performance problem isn’t a technology problem. It’s a design and developer-experience problem. Developers, like water, follow the path of least resistance, and in most frameworks the easy way to build something is also the way that ships a slow site. We then tell people to go optimize it afterward, as a chore, trading off capabilities or DX or their weekend to claw the performance back.&lt;/p&gt;

&lt;p&gt;I find it more honest to stop blaming developers and fix the path instead. A framework should be designed so the path of least resistance lands you on a fast site by default. You shouldn’t have to be a performance expert to ship a fast page; you should have to work to ship a slow one.&lt;/p&gt;

&lt;p&gt;And the thing worth optimizing is almost always JavaScript. Most sites already handle their images and CSS reasonably well, so there’s little left on the table there. JavaScript is where the big wins hide. The difference between a sluggish page and a snappy one is often tens of points of Lighthouse score, and for anyone running an e-commerce or consumer site, that gap is revenue. Resumability is the lever Qwik pulls on exactly that.&lt;/p&gt;

&lt;h2&gt;
  
  
  The idea: resume, don’t rebuild
&lt;/h2&gt;

&lt;p&gt;Every mainstream framework hydrates. The server renders HTML, then the browser downloads the whole component tree as JavaScript, re-executes it, and reattaches event listeners to reconstruct state the server already had. You pay, in bytes and CPU, to rebuild something you were handed seconds ago.&lt;/p&gt;

&lt;p&gt;Islands and partial hydration, the approach Astro popularized, make this better by only hydrating the interactive bits. But each island still has to download and execute its JavaScript before it’s ready, and someone has to draw and maintain those island boundaries by hand.&lt;/p&gt;

&lt;p&gt;Resumability skips the rebuild entirely. The server serializes the application’s state and its event wiring into the HTML itself. The browser ships almost no JavaScript up front. Conceptually the app becomes a hashmap: an event on an element points at the one chunk of code that handles it. When you click a button, Qwik reads an attribute on that element, fetches that small chunk, restores the state it captured, and runs it. There’s no global “boot the app” step, because there’s no app to boot.&lt;/p&gt;

&lt;p&gt;There’s a neat way to see the flip. In a hydrated app, event handlers are the &lt;em&gt;last&lt;/em&gt; thing to become ready, after the whole tree has downloaded and executed. In a resumable app they’re the &lt;em&gt;first&lt;/em&gt;. The page is interactive the moment it arrives.&lt;/p&gt;

&lt;h2&gt;
  
  
  The first version worked; writing it was the hard part
&lt;/h2&gt;

&lt;p&gt;Proving resumability was one thing. The developer experience was another. In &lt;a href="https://github.com/QwikDev/qwik/tree/a64a648e6b12ec5acd1e55decd734cb3b474b7af/integration/todo/ui/Header" rel="noopener noreferrer"&gt;that early version&lt;/a&gt;the philosophy leaked all the way into the API. You split your code into many small files by hand, you referenced lazy-loadable symbols by name, and you wrote a lot of ceremony to tell the runtime how the pieces fit together. It worked, and it asked too much of the person typing.&lt;/p&gt;

&lt;p&gt;My bet was that all of that ceremony could become the compiler’s job. A developer should write something that looks like ordinary &lt;a href="https://react.dev/" rel="noopener noreferrer"&gt;React&lt;/a&gt;, with components, event handlers, and local state, and the build step should do the hard work of making it resumable. The point of the whole project, after all, was to make the fast path the easy path, and an API that demanded this much manual wiring was the opposite of that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making it feel like React
&lt;/h2&gt;

&lt;p&gt;In the design I led, you write a component with handlers and hooks, the way you already think. The magic lives in the compiler.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="nf"&gt;$&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;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useSignal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// looks like an ordinary closure; the compiler will extract it&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The compiler reads the AST, finds every &lt;code&gt;$&lt;/code&gt;-marked boundary (a &lt;code&gt;component$&lt;/code&gt;, an &lt;code&gt;onClick$&lt;/code&gt;), and pulls that closure out into its own module with no dependencies except the variables it closed over. Those captured variables get serialized straight into the HTML. When the user clicks, the runtime loads that one module, restores the state it captured, and runs the handler. Nothing else downloads.&lt;/p&gt;

&lt;p&gt;The captured state can be a live signal, so the handler reads and updates a reactive &lt;code&gt;count&lt;/code&gt; and the DOM follows along. &lt;code&gt;useSignal&lt;/code&gt; lets the runtime make a surgical update to exactly the text node that changed, with no component re-render in the browser. The signal model drew on Solid’s&lt;a href="https://www.solidjs.com/" rel="noopener noreferrer"&gt;reactivity&lt;/a&gt;. The result reads like React and behaves like a resumable app, with none of the manual wiring the first version demanded.&lt;/p&gt;

&lt;p&gt;One thing I like about this model over React Server Components: a Qwik component is universal. The same component runs on the server or the client, and the developer doesn’t annotate the boundary. With RSC it’s easy to reach for &lt;code&gt;use client&lt;/code&gt; everywhere out of convenience and quietly opt back into shipping everything. In Qwik there’s no boundary to get wrong, because the compiler is the one deciding what crosses it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rust and SWC
&lt;/h2&gt;

&lt;p&gt;The optimizer that does all this is written in Rust, on top of &lt;a href="https://swc.rs/" rel="noopener noreferrer"&gt;SWC&lt;/a&gt;. It runs on every build and across large codebases, so it had to stay fast enough to disappear into the dev loop. Rust kept the AST passes quick as projects grew, which matters when the entire premise is that the compiler, and not the developer, carries the complexity.&lt;/p&gt;

&lt;h2&gt;
  
  
  QwikCity
&lt;/h2&gt;

&lt;p&gt;Later, with Adam Bradley (co-creator of Ionic and Stencil), I worked on the design of QwikCity, the meta-framework that sits on top: routing, data loading, and the conventions that make Qwik a way to build whole sites. That part was a close back-and-forth between the two of us.&lt;/p&gt;

&lt;h2&gt;
  
  
  Credit where it’s due
&lt;/h2&gt;

&lt;p&gt;I want to be precise about this. The resumability concept, and much of how it works under the hood, including the runtime and the Solid-inspired signals, came from Miško Hevery, the creator of&lt;a href="https://angular.dev/" rel="noopener noreferrer"&gt;Angular&lt;/a&gt;. What I led was the developer-facing redesign and the compiler beneath it: turning closures into independent, serializable modules and working out the reachability analysis that decides what to ship.&lt;/p&gt;

&lt;p&gt;The throughline to the rest of my work is that compiler. Make the source look ordinary, push the hard analysis to build time, and let the runtime stay lazy, so the path of least resistance is also the fast one. I’d wired the same instinct into&lt;a href="https://manualmeida.dev/articles/gin-simple-over-easy" rel="noopener noreferrer"&gt;Gin’s router&lt;/a&gt; years earlier, and I’d reach for it again tomorrow. If you’re designing a framework, that’s where I’d spend the effort: on the compiler that lets people write the easy thing while you quietly ship the simple one.&lt;/p&gt;

&lt;p&gt;If you want the longer version of this argument, I gave a&lt;a href="https://www.youtube.com/watch?v=HfEDhuZKH7A" rel="noopener noreferrer"&gt;talk on it&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href="https://manualmeida.dev/articles/qwik-resumability" rel="noopener noreferrer"&gt;This article has interactive figures — read it on manualmeida.dev.&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>qwik</category>
      <category>compilers</category>
      <category>rust</category>
    </item>
    <item>
      <title>I Broke My Ankle, Then Rendered It in a Browser</title>
      <dc:creator>Manu MA</dc:creator>
      <pubDate>Wed, 20 May 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/manucorporat/i-broke-my-ankle-then-rendered-it-in-a-browser-3hj9</link>
      <guid>https://dev.to/manucorporat/i-broke-my-ankle-then-rendered-it-in-a-browser-3hj9</guid>
      <description>&lt;p&gt;In October 2019 I went out for drinks with friends in Kreuzberg, a few minutes from my office in Berlin. I broke my ankle that night. Everything I’d been building stopped at once, and for the first time in years I had nothing to ship.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fourteen days to think
&lt;/h2&gt;

&lt;p&gt;I spent fourteen days in a Kreuzberg hospital, waiting for the swelling to go down before they could operate. Once I calmed down, it wasn’t all bad. I read the books I’d been meaning to get to, reached out to people I’d lost touch with, designed a tattoo for the ankle, and learned enough German to order a coffee with milk and no sugar.&lt;/p&gt;

&lt;p&gt;Mostly, it switched off the autopilot. I’d gone years without a single week away from code, and the quiet was the first chance I’d had to think about what I wanted to build next.&lt;/p&gt;

&lt;h2&gt;
  
  
  My data was mine, and I couldn’t reach it
&lt;/h2&gt;

&lt;p&gt;The surgery worried me even after the doctors said it had gone well. I wanted a second opinion, and that meant getting my own scans out of the hospital. It turned into a small ordeal. I left with my medical imaging burned onto a CD, then ordered a USB CD reader from Amazon so I could open my own body on my own laptop.&lt;/p&gt;

&lt;p&gt;The second opinion sent me straight back to Spain, where my family is. There were real problems: the joint spacing was off, there was nerve damage from the suture, an unrepaired tendon, and a screw sitting in the wrong place. A second surgery fixed it, and I finally found some calm.&lt;/p&gt;

&lt;p&gt;Somewhere in that mess the product idea formed. Patients own their medical data. Reaching it, reading it, and sharing it is absurdly hard.&lt;/p&gt;

&lt;h2&gt;
  
  
  Visualizing my own ankle
&lt;/h2&gt;

&lt;p&gt;With no deadlines left, I opened my laptop and went back to something I hadn’t touched in years: writing rendering code from scratch, the way I used to build &lt;a href="https://manualmeida.dev/articles/about" rel="noopener noreferrer"&gt;game engines&lt;/a&gt;. I wanted to see my own scan in 3D, in a browser, with nothing to install. The first time my ankle rotated on screen, rendered from the CD I’d fought to get, I knew this was the thing I wanted to work on.&lt;/p&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F607yhum8rxbdetir28ao.jpg" 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F607yhum8rxbdetir28ao.jpg" alt="A ray-traced 3D reconstruction of a fractured ankle, the bones reassembled from a CT scan"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 1. My own ankle, reconstructed from the CT scan on that CD and ray-cast in the browser. The loose fragments along the right are the displaced pieces of the break.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Rendering gigabytes of voxels in a browser
&lt;/h2&gt;

&lt;p&gt;A CT scan is a 3D grid of density samples, often hundreds of slices deep, which adds up to gigabytes. You can’t download all of it before drawing anything, and you can’t fit all of it in GPU memory. Yet a radiologist expects to spin and re-window the volume with no lag.&lt;/p&gt;

&lt;p&gt;The rendering itself is ray casting through a 3D texture. For each pixel on screen, march a ray into the volume, sample density along the way, map each sample to color and opacity, and composite front to back until the pixel goes opaque.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight glsl"&gt;&lt;code&gt;&lt;span class="c1"&gt;// simplified: march a ray through the CT volume and accumulate color + opacity&lt;/span&gt;
&lt;span class="kt"&gt;vec4&lt;/span&gt; &lt;span class="nf"&gt;raymarch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;vec3&lt;/span&gt; &lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;vec3&lt;/span&gt; &lt;span class="n"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;vec4&lt;/span&gt; &lt;span class="n"&gt;acc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;vec4&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;STEPS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;vec3&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;origin&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;dir&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;stepSize&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;float&lt;/span&gt; &lt;span class="n"&gt;density&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;texture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;volume&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// sample one voxel&lt;/span&gt;
    &lt;span class="kt"&gt;vec4&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;transfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;density&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// density -&amp;gt; color + alpha&lt;/span&gt;
    &lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rgb&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rgb&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// front-to-back compositing&lt;/span&gt;
    &lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;99&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// early ray termination&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;acc&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;Three decisions made it run in real time on &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API" rel="noopener noreferrer"&gt;WebGL&lt;/a&gt;. We split each volume into smaller blocks, so the GPU only ever held the parts in view and could skip the empty space between them. We quantized the data, including the normal vectors used for shading, to shrink what had to live in texture memory. And we loaded progressively, coarse first and detail as you leaned in, so the first frame appeared fast even on a multi-gigabyte study.&lt;/p&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fehgq4duv1c7p4lz2bwzo.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fehgq4duv1c7p4lz2bwzo.png" alt="OpenView Health, a browser viewer showing a brain MRI in four synchronized panes: axial, coronal, sagittal slices and a 3D angiography render, with measurements and metadata"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 2. OpenView Health, the free viewer we built on the Sethealth SDK. Slices and the 3D render stay in sync, and you can measure, window, and annotate straight in the browser.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Keeping the data safe by never seeing it
&lt;/h2&gt;

&lt;p&gt;Medical data raises the stakes on security, so we ran end-to-end encryption on the client. A scan never left the device in the clear, which meant we couldn’t read it, and that was the point. The data we never held unencrypted is data we could never leak. That one decision collapsed a large amount of compliance and liability surface into something we could reason about.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it became
&lt;/h2&gt;

&lt;p&gt;Sethealth shipped as an SDK and a compliant backend across iOS, Android, and the web, and it ran until 2026. The use case that clicked was custom prosthetics. A doctor could shape an implant against a patient’s real anatomy, an engineer could validate it, and the two could hold a precise conversation inside the same 3D view, all running on our SDK.&lt;/p&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Foxqrgm0mwnkf8mrn121i.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Foxqrgm0mwnkf8mrn121i.png" alt="A custom-implant ordering tool built on the Sethealth SDK, showing a fractured ankle with surgical plates and screws planned over the CT scan, alongside controls to order implants, surgical guides, and 3D-printed bio-models"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 3. A custom-implant planning and ordering tool a partner built on the SDK: plan plates, screws, and surgical guides against a real fracture, leave notes, and order the printed parts. The tool is no longer online.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I built it on a simple conviction. Healthcare carries more weight than most software, and patients are the rightful owners of their data even when the system makes that ownership painful to exercise. Sethealth was my bottom-up attempt to hand some of that ownership back.&lt;/p&gt;

&lt;p&gt;The deeper lesson came from the ankle. For years I never went a week without coding, and I’d mistaken motion for progress. Stepping back to ask why, and not only how, paid off more than any sprint I can remember. You don’t need to break a bone to get there. Close the laptop for a week and notice which idea refuses to leave you alone.&lt;/p&gt;

</description>
      <category>graphics</category>
      <category>gpu</category>
      <category>webgl</category>
    </item>
  </channel>
</rss>
