The Model Is a Variable: Compiling a Neural Network Into Your C++ Binary A developer has built UchenML, a C++20 framework that compiles trained neural networks directly into C++ binaries, enabling models to run in edge applications without inference servers or API calls. The framework, demonstrated in a browser-based dots game with a 418 KB WebAssembly binary, uses templated layers and constexpr models to integrate machine learning into standard software development workflows. The developer plans to publish the source code but has not committed to a timeline. I strongly believe software frameworks cannot be designed in the abstract. UchenML came out of my experiments integrating machine learning into edge applications, and out of what I want to build next — distributed, heterogeneous intelligence. The first demo, dots https://uchenml.tech/demos/dots , puts a trained neural network in your browser tab as your opponent. No inference server, no API call — a 418 KB WebAssembly binary and a weights file, served as static assets. It still carries introspection hooks for a future demo; stripped, it gets smaller. Behind it: 2,760,322 parameters packed to fp16, and a 128-channel residual trunk running eleven 3×3 convolutions across the 24×24 board for every position it evaluates — up to 128 positions per move, all in the browser tab. That model was trained with UchenML and deployed with UchenML. It is almost certainly bigger than it needs to be — I spent the training budget on making it stronger, not on making it smaller. I am not currently able to publish the source code. There is a publicly available snapshot https://github.com/eugeneo/dots , about a year old. I plan to publish the current codebase, but I cannot commit to a timeline yet. I chose C++ for ease of integration and portability. With Python, the model lives in a separate world, and reaching it from the application that needs it means writing and maintaining glue. I want the model inside one software development workflow: same repository, same build, same review, same tests. The longer-term bet is heterogeneous, distributed intelligence: not one large model behind an API, but many small specialized ones running where the data already is — in the browser tab, inside the app, or in a cloud service. That only works if a model is cheap to embed anywhere, which makes the deployment target the design constraint rather than an afterthought. UchenML is C++20, built with Bazel, and tested on Visual C++, GCC, and Clang. CI runs the suite on Linux, macOS, Windows, and under Emscripten for WebAssembly. The compute backend is hand-written portable SIMD on Google's Highway, so a single kernel source covers AVX-512, NEON, and WASM SIMD with no architecture-specific branch in the library. Small, fast, and easy to drop into an existing C++ project is the whole design brief. The model is a variable — I usually make it constexpr — declared in a header. Inference, training, and everything else are templated on that variable, so the same information is never stated twice. You never describe a layer's input type when the previous layer already declared its output; the compiler works that out, along with parameter counts and scratch buffer sizes. There are extra facilities for introspection and for advanced use cases, but the core is a simple composition of layers. The framework is split into clearly defined modules, and you only pay for what you use — convolution, RNN, and attention are separate targets, and depending on one does not drag in the others. Training mirrors that structure in a parallel tree, and deliberately stays out of the runtime one. Models compose with | : include "uchen/layers.h" include "uchen/linear.h" constexpr auto model = uchen::layers::FloatModel<1 | uchen::layers::Linear<2 | uchen::layers::Relu | uchen::layers::Linear<1 ; // 1×2 weights + 2 biases + 2×1 weights + 1 bias static assert model.all parameters count == 7 ; Linear<2 declares only its output width; the input width is deduced from whatever it is piped onto. That is why the same descriptor composes anywhere in a stack without restating shapes — and why getting it wrong is a compile error. Because layers are values, a block of architecture is a named constant. This is the residual block the dots network is built from — two padded 3×3 convolutions on one branch, identity on the other, summed and activated — with C channels over an S × S grid: template