Claude Code を用いてブラウザ上で動作する Moebius 0.2B 画像インペイントモデルの移植
Simon Willison は、Claude Code を活用して PyTorch/CUDA に依存していた軽量画像補完モデル「Moebius」を WebGPU でブラウザ上で動作可能にするポートに成功した。
キーポイント
WebGPU によるブラウザ内実行の実現
元々 NVIDIA CUDA と PyTorch を必須としていた Moebius モデル(0.2B パラメータ)を、WebGPU を利用してブラウザ環境で動作するようにポートし、デモサイトでの公開に成功した。
AI エージェントによる開発プロセス
本プロジェクトは、主要な開発タスク(Datasette の機能追加)の待ち時間を活用して、Claude Code という AI コーディングエージェントをターミナルで起動し、ポート作業を主導した「並列エージェント・サイドプロジェクト」として行われた。
軽量モデルの実用化とアクセシビリティ向上
10B レベルのパフォーマンスを持つとされる 0.2B の軽量モデルが、特別なハードウェアや環境構築なしでブラウザ上で動作可能になることで、画像補完技術の普及と実験のハードルが大幅に下がった。
影響分析・編集コメントを表示
影響分析
この記事は、AI モデルの実行環境の民主化と、AI エージェントを活用した開発ワークフローの新しい形を示しています。特に、WebGPU を介して高性能な画像処理モデルをブラウザで動かせるようになったことは、プライバシー保護や導入コストの観点から大きな意義があります。また、開発者が AI エージェントを「並列作業」として活用する事例は、今後のソフトウェア開発生産性の向上における重要なヒントとなります。
編集コメント
ブラウザ上で動く高性能な画像補完モデルの実現は、AI ツールの普及において重要な転換点です。さらに、開発プロセスそのものを AI エージェントに委ねる「並列作業」の成功事例として、今後のエンジニアリング文化の変化を予感させる記事です。
今朝、Hacker News で Moebius: 10B レベルのパフォーマンスを持つ 0.2B の軽量画像インペイントフレームワーク という記事を見かけました。これは小さくても効果的なインペイントモデルを説明するもので、画像の特定の領域にマークをつけて削除すると、その空間を埋めるべき内容をモデルが想像してくれるというものです。公開されたモデルは PyTorch と NVIDIA CUDA が必要 でしたが、モデル自体が「0.2B」と自称していたため、WebGPU を使用してブラウザ上で動作させることに挑戦してみることにしました。結論から言うと、動作させることができました。デモは simonw.github.io/moebius-web/ で試せます。詳細は以下にお読みください。
完成したツール
完成したツールの動画デモはこちらです:
このツールでは任意の画像を開くことができます(正方形でない画像は上下に余白をつけて表示されます)。削除したい領域をハイライトし、「Run inpaint」ボタンをクリックして、モデルが魔法のように処理するのを待つだけです。
並行して進めるサイドプロジェクト
今日の私のメインプロジェクトは、Datasette の主要機能の実装でした。具体的には、先週公開した 行の挿入・編集機能 に続くものとして、テーブルの作成と変更を行うための UI です。
私は Codex Desktop でそれに取り組んでいましたが(PRはこちら)、中規模なリファクタリングを完了したり、UI への変更の仕上げを加えたりするのを待っている間に、指を回して 5〜10 分も無駄にしていることがよくありました。
(コーディングエージェントに関する面白い点は、問題が難しいほど、彼らが計算を終えるのを待つ間に気が散る時間が*より長く*なるということです!)
そこで、ターミナルウィンドウで Claude Code を起動し、Moebius をウェブへ移植するところまでどれくらい進めることができるか試してみることにしました。
プロジェクト開始のためのエージェントによる調査
私の最初のステップは、このプロジェクトの実行可能性について通常の Claude に尋ねることでした。GitHub からリポジトリをクローンできる機能を持つ Claude.ai で:
**
https://github.com/hustvl/Moebius/ をクローンし、このモデルを実行するためのコードや重み(weights)をどこかで公開しているか教えてください。
(まだ重みのリンクには気づいていませんでした。それは「News」セクションに隠されています。)
次に:
Moebius について、現在実行する選択肢は何ですか?Python と NVIDIA CUDA のみでしょうか、それとも他のオプションもありますか?
そして:
Transformers.js や類似のライブラリへの移植およびブラウザ内での実行の実行可能性について考察してください。
私はモデルに「X について考察せよ」と指示するのが好きです。これは、具体的な目標を提供せずに、私に代わって問題について熟考してほしいという意図を表現する、私が発見した最も短い方法です。
こちらがそのチャット記録です。最後の回答をコピーして、Claude Code が後で読み込めるように research.md として保存しました。
Claude は、私が提案した Transformers.js ライブラリの *下位* レイヤである WebGPU バックエンド上の ONNX Runtime Web を使用することを提案しました。**
これだけで、Claude Code に任せてどこまでできるか試す価値があると感じました。
通常、このようなプロジェクトでは、コーディングエージェントが必要とする情報を可能な限り集めることから始めます。このプロジェクトが実際に成功するとは予想していなかったので、すべてを /tmp フォルダ内で行いました:
cd /tmp
mkdir Moebius
cd Moebius
Grab the Moebius python code
git clone https://github.com/hustvl/Moebius
And the model weights (Claude figured this out):
GIT_LFS_SKIP_SMUDGE=0 git clone \
https://huggingface.co/hustvl/Moebius Moebius-weights
Finally a couple of libraries we might use:
git clone https://github.com/huggingface/transformers.js
git clone https://github.com/microsoft/onnxruntime
Claude Code を起動する
プロジェクトの残りの部分用のディレクトリを作成し、Claude がコードのコミットノートを開始できるように git init を実行しました:
mkdir /tmp/Moebius/moebius-web
cd /tmp/Moebius/moebius-web
git init
Copy in that research.md from earlier
git add research.md
git commit -m "Initial research by Claude Opus 4.8"
私は/tmp/Moebius フォルダに Claude のインスタンスを起動しました。これは私が準備したすべての研究資料よりも上位の階層です。プロンプトを入力しました。
**
./moebius-web/research.md を読み込んでください - あなたの目標は、このモデルを ONNX と WebGPU へ移植し、シンプルな UI でブラウザ上で直接実行できるようにすることです
**
作業が始まると、私はこれに続くプロンプトを追加しました(タイプミスあり):
/tmp/Moebius/moebius-web に構築して、早期かつ頻繁にコミットしてください。また、その中に notes.md ファイルを維持し、途中で気づいたことを記録してください - さらに、まずそこに plan.md を作成し、作業が進むにつれてその計画を更新してください。
私はよくエージェントに対してこのようなノート作成を依頼します。最終結果は、自分自身のためにも、同じプロジェクトに触れる次のエージェントセッションのためにも、しばしば興味深いものになります。これがプロジェクト終了時の notes.md ファイル の様子です。
私はこれを起動し、メインのプロジェクトに戻り、時々確認して Claude がどうしているかを見守りました。何か動くものができているように見えたとき、私は以下のようにプロンプトしました:
ブラウザで試せる URL を教えてください
その後、Chrome で試し、いくつかのエラー(およびエラーのスクリーンショット)を Claude Code に貼り付けました。
このやり取りを数回繰り返した結果、動作するものができました!今度はインターネット上に公開して、他の人も使えるようにしましょう。
このモデルを Hugging Face に公開し、モデルの重み(weights)をそこに配置するとともに、HTML デモが Hugging Face Spaces 上に表示されるようにするにはどうすればよいでしょうか?
Claude Code は hf CLI ツールの使い方を理解しているため、私は Hugging Face にモデルリポジトリを作成し、そのリポジトリに書き込み権限を持つトークンを 作成 して、/tmp/Moebius/token.txt ファイルに配置しました。これにより Claude が利用できるようになりました。
これで、変換された ONNX(Open Neural Network Exchange)の重み 1.24GB を huggingface.co/simonw/Moebius-ONNX に公開しました。
以前、他のデモが Hugging Face からブラウザに重みをロードする様子を見たことがあったため、これは可能だと知っていました。そこで、フロントエンドコードは GitHub Pages でホストすることに決め、以下のように指示しました:
moebius-web フォルダを GitHub に公開したい。ただし大きなファイル(おそらく models/ フォルダなど)は除外して、GitHub Pages を有効にすると https://simonw.github.io/moebius-web/ にアクセスした際に UI が表示されるようにする。
最終的な URL を伝えるのは重要でした。これは、構築中のデモ内の URL を修正し、本番環境にデプロイした際にも正しく動作するようにするためです。
メインプロジェクトの作業を挟みながら数回の反復を経て、ついに動作するデプロイ済みバージョンが完成しました!
ただし……ページを再読み込みするたびに、約 1.3GB のモデル重みをダウンロードしているように見えました。ブラウザのキャッシュ(caching)機能が非常に重要であることがわかりました!
Service workers や類似の技術を使って、このデータをキャッシュする何か賢いことはできないでしょうか?毎回再読み込みされるようで、HF のリダイレクト動作に何か奇妙な点があり、ブラウザのキャッシュの恩恵を受けられていないのではないかという懸念があります。
Transformers.js プロジェクトならこれを適切に処理できることを知っていたので、Whisper Web デモのコピーを入手し、/tmp/Moebius/whisper-web に配置してこう言いました。
/tmp/Moebius/whisper-web を(サブエージェントを使って)見て、彼らがどのように実装しているか確認してください。
そのプロジェクトは完全に難読化されており、ビルド済みの JavaScript ファイルで構成されていたため、トップレベルのトークンコンテキストを費やしてこれらのファイルを解読するのではなく、サブエージェントを使用すればよいと考えました。
Claude は、キャッシュ.open("transformers-cache")(CacheStorage API)を使用していることを特定し、それを私たちのプロジェクトに追加しました(コミット履歴)。
このプロジェクトに関する Claude Code の完全なトランスクリプト を共有しています(claude-code-transcripts ツールを使用して公開されています)。
この経験から何を学んだのか?
これは間違いなく「バイブコーディング」の範疇です。プロジェクトのコードを一行も確認せず、入力はテストと、小さな機能改善(大規模ファイルダウンロード用のプログレスバーなど)の提案、そして私が望む動作の例示を通じてモデルを誘導することに限定しました。
コードを一切書かなかったため、WebGPU、ONNX、および Moebius モデルそのものといった基盤技術についての学習量は非常に限定的でした。
この種のプロジェクトでは通常、最も重要な学びは「何が可能か」に関するものです:
- Claude Opus 4.8 は、PyTorch モデルを ONNX(Open Neural Network Exchange)に変換し、その結果を Hugging Face に公開し、さらにそのモデルを読み込んで実行できる Web アプリケーションとインターフェースを構築する能力を持っています。
- Chrome、Firefox、Safari のすべてのブラウザで、この種のモデルを実行できるようになっています。私はこれら 3 つのブラウザすべてで試しました。
- CacheStorage API は、約 1.3GB のモデルファイルとも連携可能です。
- つまり、クライアント側の Web アプリケーションに画像修復(inpainting)機能を搭載できるということです!(ユーザーが 1.3GB のダウンロードを許容できる場合ですが。)
私はプロジェクトについてもう少し学ぶべきだと感じ、Claude.ai を起動して以下のようにプロンプトを入力しました:
Clone https://github.com/simonw/moebius-web/ and use it to teach me all about the model and ONNX and the process of converting a model to ONNX and WebGPU and basically everything I'd need to know in order to fully understand this repo
Here's the transcript and the understanding.md Markdown file it created, which I've now added to the GitHub repo. I found the explanation of ONNX particularly enlightening:
ONNX** (Open Neural Network Exchange) is a portable, framework-neutral file format for neural networks. An .onnx file is essentially two things bundled together:
- A computation graph — a directed graph of nodes, where each node is an operator (Conv, MatMul, Add, Einsum, Softmax, Gather, Resize, …) wired together by named tensors flowing between them. This is the "recipe" for the forward pass.
- The weights — the learned parameter tensors (the convolution kernels, the embedding table, etc.), stored as initializers in that same graph.
Crucially, ONNX describes *what to compute*, abstractly, without saying *how* or *on what hardware*. The operator set is versioned by an opset number (this repo uses opset 18), which pins down exactly which operators exist and what their semantics are.
PyTorch には ONNX へのエクスポート機能も組み込まれており、export_onnx.py の例のように確認できます:
torch.onnx.export(
dec, (lat,), dec_path, opset_version=args.opset,
input_names=["latent"], output_names=["image"],
dynamic_axes={"latent": {0: "B"}, "image": {0: "B"}},
)
また、モデルのパイプラインがどのように組み合わされているかを示す便利な用語集と、わずかに不具合はあるもののASCII アートによる図解も用意されています。
Tags: browsers, transformers-js, webgl, vibe-coding, coding-agents, claude-code, onnx
原文を表示
This morning on Hacker News I saw Moebius: 0.2B Lightweight Image Inpainting Framework with 10B-Level Performance, describing a small but effective inpainting model - a model where you can mark regions of an image to remove and the model imagines what should fill the space. The released model required PyTorch and NVIDIA CUDA, but since it described itself as 0.2B I decided to try and get it running using WebGPU in a browser. TL;DR: I got it working, and you can try the demo at simonw.github.io/moebius-web/. Read on for the details.
The finished tool
Here's a video demo of the finished tool:
You can open any image in it (non-square images get letterboxed), highlight areas to remove, click the "Run inpaint" button and wait for the model to do its magic.
A parallel agent side-project
My main project for today was landing a major feature in Datasette: a UI for creating and altering tables, as a follow-up to the insert and edit rows feature I released last week.
I was working on that in Codex Desktop (here's the PR) and often found myself spending 5-10 minutes spinning my fingers waiting for it to complete a mid-sized refactor or add the finishing touches to a change to the UI.
(An amusing thing about coding agents is that the harder a problem is the *more* time you have to get distracted while you wait for them to finish crunching!)
So I decided to spin up Claude Code in a terminal window and see how far I could get at porting Moebius to the web.
Some agentic research to kick off the project
My first step was to ask regular Claude about the feasibility of this project. In Claude.ai, which has the ability to clone repos from GitHub:
Clone https://github.com/hustvl/Moebius/ and tell me if they published the code and weights to run this model anywhere
(I hadn't spotted the link to the weights yet, that's tucked away in the "News" section.)
Then:
For Moebius what are the options for running it right now - Python and NVIDIA CUDA only or other options too?
And:
Muse on the feasibility of porting it to Transformers.js or similar and running it in a browser
I like telling models to "muse on X", it's the shortest way I've found of expressing that I want them to contemplate a problem for me without providing them with a concrete goal.
Here's that chat transcript. I copied out the last answer and saved it as research.md for Claude Code to read later.
Claude suggested using ONNX Runtime Web on the WebGPU backend - the layer *below* the Transformers.js library I had suggested.
That was enough to convince me it was worth setting Claude Code loose and seeing how far it could get.
I usually start projects like this by gathering as much information as the coding agent might need as possible. Since I didn't expect this project to actually work I did everything in my /tmp folder:
cd /tmp
mkdir Moebius
cd Moebius
# Grab the Moebius python code
git clone https://github.com/hustvl/Moebius
# And the model weights (Claude figured this out):
GIT_LFS_SKIP_SMUDGE=0 git clone \
https://huggingface.co/hustvl/Moebius Moebius-weights
# Finally a couple of libraries we might use:
git clone https://github.com/huggingface/transformers.js
git clone https://github.com/microsoft/onnxruntimeSetting off Claude Code
I created a directory for the rest of the project and ran git init in that so Claude could start committing code notes:
mkdir /tmp/Moebius/moebius-web
cd /tmp/Moebius/moebius-web
git init
# Copy in that research.md from earlier
git add research.md
git commit -m "Initial research by Claude Opus 4.8"I fired up a claude instance in the /tmp/Moebius folder, the level above all of the research materials I had prepared for it. I prompted:
Read ./moebius-web/research.md - your goal is to port this model to ONNX and WebGPU so we can run it directly in a browser, with a simple UI
As it started to work I dropped in this follow-up (typos included):
Bulid this in /tmp/Moebius/moebius-web and commit early and often, also maintain a notes.md file in there with notes about what you figure out along the way - also start by writing out a plan.md in there and update that plan as oy work too
I often ask agents to keep notes like this - the end result is often interesting, both for myself and for the next agent session that touches the same project. Here's what that notes.md file looked like at the end of the project.
I kicked it off and went back to my main project, checking in occasionally to see how Claude was doing. When it looked like it might have something that worked I prompted:
Tell me what URL I can visit in my own browser to try this
Then I tried it out in Chrome and pasted some errors (and screenshots of errors) back into Claude Code.
After a few rounds of this we had something that appeared to work! Time to put it on the internet so other people could use it.
How would we publish this to Hugging Face such that the model weights were on there and the HTML demo would show up in Hugging Face spaces?
Claude Code knows how to use the hf CLI tool, so I created a model repo on Hugging Face, then created a token that could write to that repo and dropped it into a /tmp/Moebius/token.txt file so Claude could use it.
It published the 1.24GB of converted ONNX weights to huggingface.co/simonw/Moebius-ONNX for me.
I'd seen other demos load weights into the browser from Hugging Face before, so I knew it was possible. I decided to host my own frontend code on GitHub Pages, so I said:
I want to publish the moebius-web folder to GitHub, minus the large files (so maybe minus the models/ folder), such that when I turn on GitHub Pages for that repo navigating to https://simonw.github.io/moebius-web/ serves the UI
Telling it the final URL was important in case it needed to fix the URLs in the demos that it was building so they would work when deployed to production.
After a few more rounds of iteration, in between working on my main project, we got to a working, deployed version!
Except... each time I reloaded the page it seemed to download ~1.3GB of model weights. Browser caching seemed pretty important for this!
anything clever we can do with serviceworkers or similar to help cache this stuff? It seems to reload every time, I am concerned that there might be something weird about the way HF redirects work that mean we don't benefit from browser caching
I knew that Transformers.js projects could handle this properly, so I grabbed a copy of the Whisper Web demo, dropped it into /tmp/Moebius/whisper-web and said:
look in /tmp/Moebius/whisper-web (with a subagent) and see how they do this
That project was entirely obfuscated, built JavaScript files so I figured using a subagent would avoid spending the rest of my top-level token context deciphering those files.
Claude figured out that it was using caches.open("transformers-cache") - the CacheStorage API - and added that to our project.
I've shared the full Claude Code transcript for this project (published using my claude-code-transcripts tool).
What did I learn from all of this?
This definitely counts as vibe coding: I didn't look at a single line of code from the project, restricting my input to testing, suggesting small feature improvements (like a progress bar for the large file downloads) and pointing the model in the direction of examples of how I wanted things to work.
Since I didn't write any code the amount I learned about the underlying technologies - WebGPU, ONNX, and the Moebius model itself - was very limited.
As is usually the case with this kind of project the most important things I learned concerned what was *possible*:
- Claude Opus 4.8 is capable of converting a PyTorch model to ONNX, publishing the result to Hugging Face and then building out a web application and interface that can load and execute that model.
- Chrome, Firefox and Safari are all now capable of running this kind of model - I tried it in all three.
- The CacheStorage API works with ~1.3GB model files.
- ... which means we can have inpainting as a feature of a client-only web application! (If our users can tolerate the 1.3GB download.)
I felt like I should probably try and learn a little more about my project. I fired up Claude.ai and prompted:
Clone https://github.com/simonw/moebius-web/ and use it to teach me all about the model and ONNX and the process of converting a model to ONNX and WebGPU and basically everything I'd need to know in order to fully understand this repo
Here's the transcript and the understanding.md Markdown file it created, which I've now added to the GitHub repo. I found the explanation of ONNX particularly enlightening:
ONNX (Open Neural Network Exchange) is a portable, framework-neutral file format for neural networks. An .onnx file is essentially two things bundled together:
A computation graph — a directed graph of nodes, where each node is an operator (Conv, MatMul, Add, Einsum, Softmax, Gather, Resize, …) wired together by named tensors flowing between them. This is the "recipe" for the forward pass.
The weights — the learned parameter tensors (the convolution kernels, the embedding table, etc.), stored as initializers in that same graph.
Crucially, ONNX describes what to compute, abstractly, without saying how or on what hardware. The operator set is versioned by an opset number (this repo uses opset 18), which pins down exactly which operators exist and what their semantics are.
It turns out PyTorch has built in mechanisms for exporting to ONNX, as seen here in export_onnx.py:
torch.onnx.export(
dec, (lat,), dec_path, opset_version=args.opset,
input_names=["latent"], output_names=["image"],
dynamic_axes={"latent": {0: "B"}, "image": {0: "B"}},
)It also included a handy glossary and an only-slightly-broken ASCII-art diagram showing how the model pipeline fits together.
Tags: browsers, transformers-js, webgl, vibe-coding, coding-agents, claude-code, onnx
関連記事
Moebius(4 分間の読み物)
効率的な軽量画像インペイントフレームワーク「Moebius」が、119 億パラメータの産業用モデル FLUX.1-Fill-Dev と同等以上の生成品質を達成し、推論時間を 15 倍以上短縮した。
QCon London 2026: エッジでのAI実行 - ブラウザで直接実ワークロードを実行
QCon London 2026でJames Hallが、ブラウザで直接AIワークロードを実行する手法について発表した。Transformers.jsやWebGPUなどの技術を活用し、プライバシー強化、遅延・コスト削減などの利点を説明した。
Transformers.js v4 プレビュー版がNPMで利用可能に!
Transformers.js v4のプレビュー版がNPMで公開されました。最新バージョンではパフォーマンス向上と新機能が追加されています。
今日のまとめ
AI日報で今日の重要ニュースをまとめ読み