Model or dataset
w3cj/how-llms-work avatar
w3cj/how-llms-work

how-llms-work: Five Runnable Stages of the LLM Pipeline in TypeScript

An interactive app that walks through every stage of the LLM pipeline, from pattern matching to training a transformer from scratch, with working code you can run locally.

569 stars181 forksTypeScriptLicense varies

At a glance

What is it?
A Hono and Vite app that walks from an ELIZA-style if-statement bot to a decoder-only transformer trained by hand, with each stage streamed over SSE. The teaching value is real; the code is a demonstration, not a library.
Who is it for?
Adopt it if you are teaching or learning the LLM pipeline and want to run every stage locally rather than read about it. Skip it if you need a tokenizer or embedding service in production, since nothing here is packaged as a library.
Can I use it commercially?
Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
Is it still maintained?
Yes. The repository last received commits 56 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The gap between calling an API and knowing what the API does

Most developers meet language models through an HTTP endpoint. You send text, you get text back, and the machinery in between stays opaque. This project targets that specific gap. It is an interactive app, in the author's words, that walks through every stage of the LLM pipeline, from pattern matching to training a transformer from scratch, with working code you can run locally. The audience is a developer who can read TypeScript and wants to see backpropagation, byte pair encoding and causal self-attention expressed as loops and arrays rather than as a diagram in a slide deck. It is not a course platform and not a model serving stack. Each of the five sections exists to make one mechanism visible, and the README names the paper behind each one, from Weizenbaum (1966) for the pattern-matching chat through Vaswani et al. (2017) for the transformer.

One route, one hook, one component, repeated five times

The architecture section of the README describes a uniform pattern across all five demos. A Hono POST handler in src/routes/ processes input and streams Server-Sent Events. A client hook in src/client/hooks/ consumes those events through a shared useSSEChat hook and turns them into state updates. A result component in src/client/components/ renders that state as a visualization. The shared infrastructure sits in src/server/lib/sse.ts and src/client/lib/sse.ts, with message types in src/shared/types/message.ts. The BPE implementation in src/server/lib/bpe.ts is reused by three sections: the tokenizer demo, the embedding trainer and the transformer trainer. That reuse is the most interesting design decision in the repository. It means the tokenizer is not a toy shown once and discarded. The same code that animates merge steps in section three feeds the vocabulary for the models in sections four and five, so a bug in BPE would surface in three places at once.

What each of the five stages actually trains

Section one is an ELIZA-style chatbot that answers with if-statements and streams word by word over SSE. The README is blunt about it: same plumbing as ChatGPT, zero intelligence. Section two trains a neural network live, first showing a single-layer perceptron failing on XOR, then a multi-layer network succeeding through backpropagation. Section three implements BPE from scratch, training on whatever text you paste in and animating the merge steps as the vocabulary grows from characters toward words. Section four trains Word2Vec skip-gram embeddings with negative sampling, so that words appearing in similar contexts cluster. Section five is the largest: a decoder-only transformer trained entirely from scratch with no ML libraries. According to the README, multi-head causal self-attention, layer normalization, feed-forward layers, backpropagation and Adam optimization are all implemented by hand, and training uses multi-threaded data parallelism through SharedArrayBuffer. The cited references map onto the code: Glorot and Bengio (2010) for initialization, Kingma and Ba (2014) for Adam, Ba, Kiros and Hinton (2016) for layer normalization. That mapping is the strongest signal that the implementation is meant to be read alongside the papers rather than instead of them.

Setup, and the one snag the README anticipates

The documented requirements are pnpm and Node.js 20 or newer. The install sequence is two commands: pnpm install, then pnpm dev. The README also anticipates a specific failure. If pnpm reports ignored build scripts, you run pnpm approve-builds, select esbuild with the space bar, press Enter, and rerun pnpm install. That is a pnpm 10 behaviour rather than anything specific to this project, but it is the kind of detail that stops a first run cold, and it is documented rather than left to a search. The stack is Hono for the server, JSX rendering and client components, plus Vite for the dev server and bundling. There is no homepage listed and no releases were retrieved, so there is no published artifact to install. The repository is the distribution channel.

SharedArrayBuffer is a deployment constraint, not a detail

The transformer section uses SharedArrayBuffer for multi-threaded data parallelism. That choice has consequences the README does not spell out. Browsers only expose SharedArrayBuffer in cross-origin isolated contexts, which means the pages must be served with COOP and COEP headers. A Vite dev server can be configured to send them, but anyone who takes this code and deploys it behind a proxy, a CDN or a framework that strips those headers will find the transformer demo degraded or broken while the other four sections keep working. That is a real limitation of the most ambitious section, and it is worth knowing before you plan a workshop around it. The second limitation is scope. Nothing here is packaged as a reusable library. The BPE tokenizer lives in src/server/lib/bpe.ts and is imported by routes, not published to a registry. If you need a tokenizer in a service, this repository gives you something to read, not something to depend on. The third is that the demos are interactive and browser-driven. There is no batch training script in the described layout, no CLI entry point, and no checkpoint format mentioned. Training happens while a page is open, streamed to the UI.

Where this sits against a notebook and against a real framework

The obvious alternative is a Jupyter notebook using PyTorch or a similar framework. The difference is not the mathematics, which is the same, but the surface area. A notebook gives you a tensor library, autograd, GPU execution and a mature ecosystem. This project gives you hand-written loops in TypeScript that run in a browser or a Node process, with every gradient computed explicitly. If your goal is to build something that trains on real data at scale, the notebook wins and it is not close. If your goal is to see what autograd is hiding, the notebook is the wrong tool, because the framework does the thing you are trying to learn. A second alternative is a written tutorial or a video series. Those are cheaper to consume, but they cannot be stepped through with your own input text, and they cannot show the BPE merge sequence animating against a corpus you chose. The trade-off this project makes is deliberate: less capability, more visibility.

Maintenance, licensing and what the repository does not tell you

The licence was not retrieved, so the terms under which you may reuse the code are unknown from the supplied material. That matters more than usual here, because the natural thing to do with a teaching repository is copy a file out of it. Check the licence before lifting src/server/lib/bpe.ts into your own project. On maintenance, the last push recorded is 2026-07-21 and no releases were retrieved, so there is no versioned artifact and no changelog to track. Upgrading means pulling the branch. The dependency surface is small, Hono and Vite plus whatever the build pulls in, which keeps the upgrade cost low, but the transformer section's reliance on SharedArrayBuffer means a future browser policy change would hit that section first. The repository is not archived, which suggests it is still being touched, though the absence of releases means you should read the commit history rather than a version number if you care about recent activity.

Editorial conclusion

Adopt it if you are teaching or learning the LLM pipeline and want to run every stage locally rather than read about it. Skip it if you need a tokenizer or embedding service in production, since nothing here is packaged as a library. Before committing, verify the repository licence, which was not retrieved, and check that Node 20 or newer plus pnpm are available, because the documented setup is pnpm install followed by pnpm dev.

Official sources

  1. Issues
  2. README
  3. w3cj/how-llms-work on GitHub
Community notes

Community notes