MoonBitでテトリスを実装した
この記事は MoonBit Advent Calendar 2025 6日目の記事です。
はじめに
こんにちは、千葉工業大学 学部1年の @ramenha0141 です。
この記事では、MoonBit (JS backend) を用いてテトリスを実装する過程で得た知見や感想を共有していきます。
成果物

山岳積み2号→DPCの様子
SRS(Super Rotation System) を実装しているので各種スピンが可能
使用ライブラリ
MoonBit側
moonbitlang/async
- MoonBitで非同期処理を扱うために必要なライブラリ
mizchi/js
- JavaScriptの各種APIのFFIバインディングを提供するライブラリ
- Browser API / Web API だけでなく、Node.js や Cloudflare (workerd) など各種ランタイムのAPIも提供
- Hono などの著名npmパッケージも対応拡大中
- 今回は主に Canvas API を使用
JavaScript側
Vite
- HTML, CSS, MoonBitをコンパイルして出力したJavaScriptをバンドルするために使用
tailwindcss
- ほぼ装飾はしていないが、操作説明などに使用
実装
大まかなディレクトリ構造は以下のようになっています。
src/
├─ core/
│ ├─ types/
│ ├─ mino/
│ ├─ game.mbt
├─ controller/
├─ renderer/
├─ main.mbt
index.html
vite.config.ts
各ファイル/パッケージの説明
core/types
-
Vec2,Matrix[T],Cell,Rotationなど、基本的なデータ型を実装
core/mino
- 各ミノの形状、移動・回転・ハードドロップの挙動などを定義
core/game.mbt
- ゲームの全体的な動作を実装
controller
- キーボード入力の処理やキー長押し時のDAS/ARR処理を担当
renderer
- Canvas API を用いた盤面の描画を担当
実装ポイント
演算子のオーバーロード
イテレータ
- ジェネレータが欲しくなる
- 今回使用した
Iterの他にIteratorもあるらしい
- 使う側はこんな感じ
-
for i, e in iter { ... }でインデックスもくれる - 現状
for inとIterの組み合わせでタプルの分解はできないようなのでtなど一時的な変数に入れてあげる必要がある
パターンマッチング
-
match便利
JS FFI
-
HTMLCanvasElementやKeyboardEventは@identityでキャストしてあげる必要があった -
wait_animation_frameを使うとrequest_animation_frameをasync fnの文脈で自然に扱える - 想像より楽にJSのAPIを扱えた
感想
全体的にかなり書き心地が良く、GCありRustと呼ぶのに相応しい言語だと感じました。
特に、演算子のオーバーロードやパターンマッチングが非常に強力で、MoonBitを使用するモチベーションにつながる機能だと感じます。
また、例の障害で取り沙汰されている.unwrap()も、いつどこでエラーがthrowされるかわからないTypeScriptと比較すると明示的であり、改善されていると考えられます。
今回実装したテトリスでは、キーイベントの取得や盤面の描画において多数のJS APIを使用しました。
繰り返しになりますが、想像より遥かに簡単に言語の壁を越えることができ、TypeScriptと大差ないコード量で記述することができました。
MoonBitのFFIやそれを利用したバインディングライブラリは、既存エコシステムの利用という面で言語の普及に大きく貢献するものであると考えます。
幾つか改善できそうな点はありますが、まだまだアーリーステージな言語であることを踏まえると非常に完成度が高いように感じました。
少なくとも基本的なテトリスの実装ができる程度の実用性は証明できたので、今後はさらに発展的なプログラムの実装に挑戦していきます。
最後に
MoonBitについてはZennやTwitterで何度か目にする機会はありましたが、今回のAdvent Calendarをきっかけに、初めて実際に触れることができました。
主催者の@mizchiさんに心から感謝を申し上げます。
また、MoonBitの開発に関わる全ての方に感謝を述べるとともに、今後も応援させていただきたいと思います。
明日は@mizchiさんの「mizchi/js.mbt で TS の代わりに Moonbit を書く」です。
Discussion