Porting Manim to TypeScript with Coding Agents Manim-web, a TypeScript port of the Python Manim animation engine, landed its first port commit on 29 January 2026 with 147 files and 55,667 added lines, authored by an agent named 'mayor' in a Gas Town workspace, according to a review of the project's git history. The project's first npm release, v0.1.0, followed 13 days later, and as of 10 October 2026 the repository reports 485 stars, 82,553 npm downloads over the last 12 months, 27 releases, and 6,170 tests. Coding agents accounted for 101 of 169 commits through 19 February, driving test coverage from 52% to 72% in two days, while manim-web runs Manim scenes live in the browser on Three.js and WebGL instead of rendering to video files. Porting Manim to TypeScript with Coding Agents What this post is. A look at how manim-web https://github.com/maloyan/manim-web was built, read from its git history, pull requests, docs, and public stats. Commit counts come from the git author field and co-author trailers on main . Stars, downloads, and the Hacker News score were checked through the public APIs on 10 October 2026. Short version - manim-web is a TypeScript port of Manim, the Python engine behind 3Blue1Brown's math videos. Scenes run live in the browser on Three.js and WebGL. - The first port commit landed on 29 January 2026: 147 files, 55,667 added lines . Its author was mayor , the coordinating agent in a Gas Town https://github.com/steveyegge/gastown workspace. The first npm release, v0.1.0, followed 13 days later. - Up to 19 February, 101 of 169 commits came from that agent. On the full history it is 101 of 616, because later work came in under other author names. - The agents were strong at volume: porting examples from Python, parity fixes, and tests. Test coverage went from 52% to 72% in two days. - Today: 485 stars, 82,553 npm downloads in the last 12 months, 27 releases, 6,170 tests. The goal is on the projects page https://maloyan.xyz/projects/ manim-web : Manim gives you a video file, and manim-web puts the same scenes live on a web page, where the reader can touch them. What a Manim port has to cover Manim has a small core and a very large surface. The core is a scene, a tree of mobjects, and animations that change mobjects over time. A VMobject is a list of cubic Bezier control points: anchor, handle, handle, anchor. Almost everything on screen is a VMobject : circles, arrows, axes, glyphs of text, and LaTeX formulas. The surface is the hundreds of classes built on top of that core. Python Manim renders a scene to a video file. manim-web keeps the same object model but draws every frame in the browser. The table shows how the main parts map. | Python Manim | manim-web | |---|---| | class MyScene Scene with construct | An async function that takes a Scene | | self.play ... , self.wait | await scene.play ... , await scene.wait , driven by requestAnimationFrame | | Mobject tree | Mobjects backed by Three.js objects | | VMobject strokes | Three.js Line2 , a mesh stroke with miter joins, or a signed distance field shader for cubic Bezier curves | | VMobject fills | Triangulation with earcut | | Boolean operations on shapes | polygon-clipping | | LaTeX through a TeX install | MathJax SVG converted to VMobject paths, or KaTeX rendered to a texture | | Text glyphs | opentype.js outlines | | 3D scenes and camera | Three.js lights, meshes, and orbit controls | | Video output | Live canvas, plus GIF and video export | The repo also ships tools/py2ts.cjs , a regex-based converter from Python scenes to TypeScript. Its docs say it knows about 170 mobject classes, more than 45 animations, and more than 80 method mappings. This is the example from the docs: // Python: self.play Transform square, circle export async function squareToCircle scene: Scene { const square = new Square { color: BLUE } ; const circle = new Circle { fillOpacity: 0.8, fillColor: PINK } ; await scene.play new Create square ; await scene.play new Transform square, circle ; await scene.wait ; } Timeline - 23 January 2026. Initial commit. - 29 January. The Gas Town Mayor commits the port: scene and mobject system, 2D and 3D geometry, KaTeX text and LaTeX, axes and graphing, animations, rate functions, GIF and video export, React and Vue components, and the converter. - 8 to 11 February. 3D scenes, cameras, and lights. - 11 February. v0.1.0 on npm. The package was renamed from manim-js to manim-web the next day. - 25 February. Show HN: 140 points, 25 comments. - 13 July. v0.3.24, the 27th GitHub release. How the agent work was split The port phase ran in Gas Town, an open-source workspace for running Claude Code agents. Its README https://github.com/steveyegge/gastown describes the Mayor as the primary AI coordinator, a Claude Code instance with context about the workspace. Three facts from Narek's local Gas Town workspace tie it to manim-web: - The town was created on 22 January 2026, one day before the repo's initial commit. - The town's root folder is a git checkout of maloyan/manim-web . Its history ends at ae178da , the last mayor commit, on 19 February. - The town's event log names one actor, the Mayor. The rig list has no manim-web rig, so no Gas Town worker agents polecats were set up for it. The Mayor did the port work itself. So the port phase had one agent at a time, not a fleet. More agents came later, in the PR phase described below. Commit authors give a partial picture. The agent wrote under its own author name, mayor , with Narek's email. GitHub merges both names into one contributor, which is why the contributors page shows 394 commits for maloyan : 293 under Narek's name plus 101 under mayor . | Author on main | Up to 19 Feb 2026 | All time 616 | |---|---|---| | mayor agent | 101 | 101 | | Narek Maloyan | 55 | 293 89 of them merge commits | | Dependabot | 13 | 138 | | Outside contributors | 0 | 84 | The work after 19 February moved to pull requests. 147 of Narek's own PRs, opened between 1 February and 16 July, were merged. 27 of them carry the Claude Code footer. 16 of his PRs say that a second model, Codex, reviewed the plan, the diff, or both. A typical note from PR 385: the plan was posted on the issue, reviewed with Codex, and Codex flagged three issues, all fixed in the branch. This is a pattern of one agent to write and a different model to review. The record has one blind spot. The 293 commits under Narek's own name carry only 4 AI co-author trailers, and the PR footers mark only 27 PRs. Neither field shows how much of the rest an agent wrote. This post counts only what the author field, the trailers, and the PR bodies show. The hard parts Strokes and fills on WebGL WebGL has no built-in thick curved line, so the code has three stroke paths. Line2 covers the simple case. A mesh stroke with miter joins gives sharp corners on closed paths. A shader draws each cubic segment as a screen-aligned quad and finds the distance to the curve per pixel with Newton steps. Fills go through earcut . Boolean operations first had their own implementation and were rewritten on top of polygon-clipping on 31 January, the same day. LaTeX LaTeX work runs through the history from February to May. The first version used KaTeX and drew formulas as images. That works for display but not for path animations such as Create and Transform , which need real paths to draw a stroke or morph one formula into another. On 14 February the agent added MathTexSVG : MathJax renders SVG, and a parser turns it into VMobject paths. The details then took months. MathJax draws subscripts and superscripts with a scale transform, about 70.7% of full size. The first parser read only translate , so indices rendered at full size and overlapped. PR 28 fixed it on 16 February. Rendering is also async, so Scene.play had to wait for pending renders before it starts an animation. On 12 April the vector path became the default for MathTex and Tex . Later PRs moved to MathJax 4 300 and kept one MathJax instance across bundle chunks 412 . Text and the Write animation Manim's Write draws text as if a pen traces each letter. A font gives outlines, not pen paths. The port gets the outline from opentype.js , rasterizes it to a grid, thins it to a one-pixel skeleton with the Zhang-Suen algorithm, traces the skeleton into chains, and fits cubic Beziers to them. Transforms Transform morphs one shape into another, so both shapes need the same number of points in matching order. Early commits added Bezier-aware point alignment and a glyph-based morph for text to text. TransformMatching pairs parts with the Hungarian algorithm. A June fix from an outside contributor corrected corner tangents when cubic chains are resampled 446 . Matching Python's coordinate rules Small differences in frames and centers break many scenes at once. v0.3.23 shipped a breaking change: getCenter now matches Python Manim, and moveTo , rotate , and scale move their anchor into the parent frame. Where the agents did well - Parity by example. Between 30 January and 12 February, 22 agent commits added or fixed example scenes, several of them converted from Python Manim, and fixed the bugs each one showed: rate functions, Angle arcs, fill and stroke colors, VGroup scale and shift counted twice. - Tests at volume. Commits from 13 to 15 February add tests in batches of 124 to 616. The test suite had 4,970 tests by 16 February and 6,170 by September. Where a human was needed - Guardrails early. On 1 February, three days after the port, lint, formatting, unit tests, pre-commit hooks, CI, and AGENTS.md came in through commits under Narek's name. 25 agent commits came before them and 76 after. - A review gate. On 16 February a LaTeX fix went straight to main under the agent name and was reverted under the same name. It came back as PR 26, merged without review. PR 27 reverted that too, with the note: "The fix itself is correct but needs to go through proper PR review workflow." It landed as PR 28. The agent identity has no commits after 19 February. - Rules written for agents. AGENTS.md now bans every eslint-disable directive, with a CI check. It requires shared vector helpers instead of inline cross and dot products. It forbids special cases for the Z axis. The eslint-disable ban comes from issue 398, and the vector helpers from issue 340. - Watching the file tree. Two early agent commits are titled "Apply Write glyph stroke changes to root src/ actual source " and "Consolidate duplicate manim-js/src into src". The agent had edited a copy of the source tree. - Outside contributors. Six people outside the project had PRs merged. Antonin Peronnet alone has 77 commits, including the transform normalization behind the v0.3.23 breaking change 417 and the corner tangent fix 446 . Thank you, Antonin. Jairo M. Valdivia moved the project to MathJax 4 300 , and Christoph Deil landed the three most recent fixes on main . Results | Metric | Value | |---|---| | GitHub stars and forks | 485 and 31 | | npm downloads, 9 Oct 2025 to 8 Oct 2026 | 82,553 | | Show HN, 25 Feb 2026 | 140 points, 25 comments | | GitHub releases | 27, from v0.1.0 11 Feb to v0.3.24 13 Jul | | Commits on main | 616 | | Source, without tests | about 80,000 lines of TypeScript in 245 files | | Tests | 6,170 passing PR 541 , about 69,000 lines | | Example scenes | 56 TypeScript files | Lessons from the record - Add the guardrails in the first days. Lint, tests, CI, and AGENTS.md arrived on 1 February. Coverage went from 52% to 72% two weeks later, and the suite grew to 6,170 tests. - Agents need the same review gate as people. After the direct push and the reverts on 16 February, changes reached main through PRs. Of 304 first-parent commits on main since 17 February, only 2 have no PR number. The agent identity stopped committing on 19 February. - Use a second model as a reviewer. 16 PRs record a Codex review of the plan or the diff, and PR 385 lists three issues that review caught before merge. - Turn repeat mistakes into written rules. The eslint-disable ban 398 and the shared vector helpers 340 now live in AGENTS.md , and CI enforces the first one. Sources - manim-web on GitHub https://github.com/maloyan/manim-web : git history, README.md , AGENTS.md , CHANGELOG.md , and source comments - manim-web pull requests https://github.com/maloyan/manim-web/pulls?q=is%3Apr , including 27, 28, 300, 385, 412, 446, and 541 - manim-web releases https://github.com/maloyan/manim-web/releases - manim-web docs and examples https://maloyan.github.io/manim-web/ , including the py2ts converter page - manim-web on npm https://www.npmjs.com/package/manim-web and the npm downloads API - Gas Town README https://github.com/steveyegge/gastown : the Mayor and worker agent roles - Show HN: I ported Manim to TypeScript https://news.ycombinator.com/item?id=47155375 25 February 2026