Evaluating h3.c: Cutting the Abstraction Tax

Two evaluations, 3 years apart, that taught me similar lessons: the abstraction layers you don’t need are not free.

Two ways to generate media on non-NVIDIA silicon

In mid-2023 I got Stable Diffusion generating images on an all-AMD Linux Laptop running Mint: amd64 CPU + AMD GPU + ROCm + PyTorch. The images were not amazing, but they were real, and at that moment it felt like being one of a handful of people on the planet who could get that particular stack to cooperate.

The choice of hardware was deliberate, not incidental. Linux is what runs the datacenter – then and now, it is the default substrate for anything I deploy at scale. AMD GPUs, meanwhile, are commonplace on the edge: the desktops, laptops, and gaming devices real people actually own. Getting inference working on all-AMD Linux in 2023 meant covering both worlds at once – the server-room standard and the consumer silicon most inference will eventually run on – rather than retreating to the one blessed NVIDIA path that only really exists in the cloud.

There’s a part of this I need to call out. In 2023 I was genuinely uneasy about generated imagery – images conjured whole from a text prompt, with no camera and no scene behind them. I disagreed with the casual way “fake” pictures were already sliding into feeds as if they were real. My reason for learning the stack was not to celebrate it. I wanted to understand the machinery from the inside – how these images are actually made – precisely because I could see how easily the same capability could be used to manipulate and influence people. You cannot reason well about a technology you have only read about. So I built it, ran it, and watched it work, on the theory that being informed is the only honest position from which to be concerned or not.

This week I evaluated h3.c by Salvatore Sanfilippo (https://github.com/antirez), a native implementation of MiniMax-H3 video generation for Apple Silicon. It does text-to-video with synchronized audio, first/last-frame conditioning, and image reference conditioning – and it does it in roughly 35,000 lines of C, Objective-C, and Metal code, with zero lines of Python. I verified that last part with Opus 4.8: I could not find a single .py file in the tree.

These two experiences sit at opposite ends of a spectrum, and putting them side by side is the clearest way I know to explain what “the abstraction tax” actually costs.

The 2023 stack: portability that failed

PyTorch’s whole promise is generality. Write your model once, run it on any backend – CUDA, ROCm, MPS, CPU. In practice, in 2023, the Nvidia CUDA path was paved and every other path was a swamp.

Getting the AMD + ROCm path working meant fighting a version matrix that no single party owned:

What finally broke the logjam was not documentation. It was a single obscure breadcrumb left by a stranger – the kind of thing you only find at Midnight on page 2 of search results: a throwaway GitHub gist, or a one-line reply buried in a forum thread, where some unnamed hero had hit the same wall and posted the exact gfx override and wheel combination that made it go. No official source carried it. That is the tell of a path nobody owns: the knowledge that actually gets you running lives in random margins, passed hand to hand, not in the docs.

None of that “difficulty” was essential to the problem “turn a prompt into an image.” It was accidental complexity, contributed by a tower of abstractions that each claimed to be portable and each leaked at the seams. Four independent vendors – AMD’s CPU, AMD’s GPU, the Linux kernel, and the ROCm stack – all had to line up, and when they didn’t, the abstraction gave me no leverage to fix it.

I was overpaying for generality I could not use, and did not ask for

The h3.c stack: i.e. no tower at all

A typical PyTorch/diffusers pipeline is a stack of tiers:

your Python script
  -> diffusers / transformers (Python)
    -> PyTorch (Python API)
      -> ATen / dispatcher (C++)
        -> GPU backend (C++/Obj-C)
          -> GPU driver -> GPU

h3.c collapses that to:

compiled C / Objective-C program
  -> Metal driver -> GPU

The heavy math – the diffusion transformer, the video and audio VAEs, attention, matmuls – lives in h3_shaders.metal as hand-written Metal Shading Language kernels: kernel void functions compiled to run directly on the GPU. The C and Objective-C around them (h3_gpu.m, h3.c, h3_dit.c) is the host: it memory-maps weights, allocates GPU buffers, dispatches kernels, and reads results back. The Makefile links exactly four Apple frameworks – Metal, MetalPerformanceShaders, MetalPerformanceShadersGraph, Accelerate – plus system ICU. That is the entire dependency surface.

There is no interpreter to start, no framework to resolve, no dispatch machinery choosing kernels at runtime, no weird Python multi-gigabyte virtual environment. You build a binary and it talks to the driver.

Being fair about what PyTorch buys you

It would be dishonest to frame this as “Python slow, C fast.” Two caveats:

  1. PyTorch’s compute is also compiled GPU kernels, often vendor-tuned and sometimes faster than anything hand-rolled. Python is the orchestration layer, not the hot loop. The win in h3.c is mostly startup cost, memory control, dependency-freeness, and legibility – not automatically faster arithmetic.

  2. The trade is generality. PyTorch runs any model on any backend. h3.c runs exactly one model on exactly one vendor’s GPU, because every kernel was written for MiniMax-H3 on Apple Silicon. That specificity is the whole point: it is what lets the code be lean and squeeze the M3/M5 Max (there are INT8 and Morton-tiled kernel variants in the shader file). It buys zero portability, and it doesn’t need any.

So the honest comparison is not speed. It is: how much accidental complexity did each approach make me carry to get the job done? In 2023, an enormous amount, none of it mine. With h3.c, almost none.

Why coherent hardware makes the lean bet viable

Cutting the tower only works if the thing underneath it holds still. This is where Apple Silicon matters, and it is the mirror image of my AMD ROCm problem.

In 2023 I was an expert wrestling a portable framework onto “exotic” hardware (desktop linux with AMD)

In 2026 h3.c is the inverse bet: a deliberately non-portable program aimed at ubiquitous, coherent hardware. Both get you generated media off NVIDIA. One required being one of a handful of people on Earth; the other requires owning a MacBook.

Both bets are edge bets – inference on the machine in front of you, not a rack you rent. That is one half of the job. The other half is the datacenter, and the two are not the same discipline: my own lab runs NVIDIA GPUs split across two Linux servers, which is where the CUDA path does earn its keep and where Linux is simply assumed. Knowing when to reach for the paved server-room stack and when to cut straight to the silicon on someone’s desk is the actual skill – neither one is universally right.

The Closed Vendor Caveat

h3.c is an open-source project that is wholly dependent on one closed vendor. The frameworks it links have no Linux implementation whatsoever – I confirmed on Linux that the pure-C files (h3_dit_schedule.c, h3_weights.c, h3_safetensors.c) pass a clang -fsyntax-only check under clang 17.0.0, but nothing that touches Metal can compile or run off Apple hardware, and nothing bridges that gap. The GPU work has nowhere else to execute.

So the coherence I’m praising is coherence you rent from Apple. The win is real, but it is a win despite the platform being closed, not an endorsement of lock-in. If Apple changes Metal’s contract, the leverage that makes h3.c elegant becomes the exposure that makes it fragile. It is worth naming that the same vertical integration that killed my version-matrix pain is also a single point of control I don’t hold. I would love to see this philosophy – one model, direct to the GPU, no framework tower – proven on a stack that isn’t owned end-to-end by one company. On today’s hardware, Apple Silicon is simply the one place it comes for free.

The broader lesson generalizes past this repo: hand-writing shaders for every model will never scale, and nobody should try. What h3.c demonstrates is narrower and more useful – that for a specific, valuable model on a coherent, widespread platform, removing the entire Python/framework tower is not heroic, it’s clean. You stop paying the generality tax you were never going to spend.

A closing note: Go, and designing for the reviewer

There is a parallel argument playing out in language design, and a recent piece from Google’s Go team frames it well (https://developers.googleblog.com/why-go-is-an-ideal-language-for-ai-assisted-software-engineering/, Cameron Balahan and Richard Seroter, Aug. 11, 2026).

Their observation:
Now that AI assistants generate large swaths of code, the rate at which a human can write code barely matters. What matters is reviewing, verifying, and maintaining it.

They quote the original Go premise – “language design in the service of software engineering” – and argue for opinionated simplicity, strong compatibility guarantees, and a legible end-to-end platform, precisely because a durable system must stay maintainable long after the original author, or the AI that helped, has moved on.

Part of that “legible end-to-end platform” is tooling. The piece points to govulncheck, which cross-references a project’s actual call graph against a curated vulnerability database and reports only the vulnerabilities you can really reach. It is exactly the kind of automated reviewer that scales when humans can’t. Worth noting the contrast: I’m not aware of an equivalent in the C or Objective-C landscape – there are sanitizers, static analyzers, and fuzzers, but nothing that ships with the toolchain and answers “which known-vulnerable paths does my code actually call?” the way govulncheck does. On a hand-rolled, framework-free codebase like h3.c, that gap is simply part of the deal you accept when you go native.

That is the same instinct as h3.c, arrived at from the other direction. Sanfilippo cut abstraction layers to get closer to the hardware; go cuts language features to get closer to a useable system a team can reason about.

Both are optimizing for the thing that actually costs you over a system’s life:

not how fast you produced the code, but how confidently a human can read it, verify it, and keep it running.

h3.c is roughly 35,000 lines of C, Objective-C, and Metal (at time of writing), landed in 122 commits on its main branch. The revealing part is the timeline: the first commit is dated Aug. 6, 2026, and the tree reached that size within about five days – on the order of 7,000 retained source lines per day, with only ~7% of all authored lines later deleted. That deletion ratio is unusually low; hand-debugged systems code, especially GPU kernels, normally churns far more as you write, measure, and rip out. Numbers like these are the fingerprint of heavy AI assistance, and there is nothing wrong with that – it is simply worth naming plainly.

It is also worth naming the flip side. Thirty-five thousand lines produced in a few days is already more than a human review team can meaningfully review line-by-line, and the generation rate will only climb. This particular project is not security-critical – it turns prompts into video on your own machine – so the stakes of an unreviewed line are low. But the general shape of the problem is now permanent: code is generated faster than it can be read, and legibility becomes the only affordable form of review. This is exactly why the lean, tower-free structure matters.

With a four-framework dependency surface and no interpreter in sight, you can still hold the whole shape of it in your head. In an era where the bulk of code is generated and the scarce human act is review, that legibility is not nostalgia – it is the point.

The generality tax, the language-complexity tax, the framework-tower tax: they are all the same tax. Sometimes you must pay it. The skill, in 2026 as in 2023, is knowing when you don’t.


Sources