← Blog
Developer ExperienceToolsWorkflowSetup

ブラウザゲーム開発者の作業環境 2026 — 203個のコンポーネントを支えるツールチェーン

13 分で読める

このトピックを深掘りする

ブラウザゲーム開発

ゲームループ・衝突判定・経路探索・迷路生成など、ブラウザゲーム開発の実装パターン集

全7本中 1 本目。

このトピックの記事一覧

シリーズ全体の流れを見ながら、次に読む記事へ進めます。 初めての方はホームへ →

はじめに

このポートフォリオサイトには約200個のインタラクティブコンポーネントがある。流体シミュレーション、ピンボール、迷路生成、ピアノ、セルオートマトン——ブラウザ上で動く小さなデモを次々と追加してきた結果だ。

これだけの数を効率的に開発・メンテナンスするには、ツールチェーンの選定が重要になる。だが自分のモットーは「道具は少なく、各道具を深く使う」だ。新しいツールを導入するたびに認知負荷が増える。設定ファイルが増える。チームメイト(この場合は未来の自分)が覚えることが増える。

この記事では、約200個のコンポーネントを実際に支えているツールチェーンを紹介する。派手な構成ではない。bun、BiomeViteClaude Code。この4つが中核で、それぞれを深く使い倒している。

エディタ: ターミナルファースト

Claude Code がメインの開発ツール

エディタは何を使っているかと聞かれると、正直に答えると「ターミナル」だ。具体的には Claude Code (CLI) がメインの開発ツールになっている。

# 新しいコンポーネントを作る
claude "PendulumWaveコンポーネントを作って。src/components/interactions/PendulumWave.tsxに配置"

# バグを直す
claude "FluidSimulationでCanvasサイズが0のとき描画が壊れるバグを直して"

# リファクタする
claude "このファイルのmouseイベントをPointer Eventsに統一して"

コードを書く行為の大部分を Claude Code に委ねている。自分がやるのは「何を作るか」の指示と、出力されたコードの確認だ。

VS Code は「見る」ためのツール

VS Code も使っているが、役割が変わった。コードを書くためではなく、ファイルブラウジングと差分確認に使っている。

- ファイルツリーでプロジェクト構造を俯瞰
- Git差分をサイドバイサイドで確認
- 複数ファイルをタブで開いて比較

AIがコードを書く時代、エディタは「見る」ためのツールになった。キーバインドのカスタマイズや拡張機能の厳選に時間をかけるより、Claude Code への指示の出し方を磨くほうがリターンが大きい。

パッケージマネージャ: bun

npm → bun 移行の理由

npm から bun に移行したのは単純な理由だ。速い

# 依存関係のインストール
bun install  # npm install の 5-10倍速

# スクリプト実行
bun run dev     # 開発サーバー起動
bun run build   # プロダクションビルド + tsc
bun run check   # Biome lint + format

約200個のコンポーネントがあると依存関係も多くなる。bun install の速さは体感で分かるレベルだ。CI で毎回走るのだから、ここの短縮は積み重なる。

bunx でMCPサーバーも起動

npx の代わりに bunx を使っている。MCP (Model Context Protocol) サーバーの起動もこれで統一した。

bunx @anthropic/mcp-server-filesystem /path/to/project

パッケージマネージャを統一すると、「これは npx で動かすんだっけ、bunx だっけ」という判断がなくなる。小さいことだが、判断を1つ減らすことの価値は大きい。

CI/CD でも bun

GitHub Actions でも bun を使っている。

- uses: oven-sh/setup-bun@v2
  with:
    bun-version: latest
- uses: actions/cache@v4
  with:
    path: ~/.bun/install/cache
    key: bun-\${{ hashFiles('bun.lock') }}

oven-sh/setup-bun@v2 でセットアップし、actions/cache@v4 でキャッシュする。ローカルと CI で同じパッケージマネージャを使うことで、「ローカルでは動くのに CI で落ちる」問題を減らせる。

npm に戻る理由がない。

リンター/フォーマッター: Biome

ESLint + Prettier → Biome 一本化

かつては ESLint + Prettier の組み合わせを使っていた。この2つの設定ファイルを管理するのが地味に面倒だった。競合するルール、プラグインのバージョン管理、.eslintrc.prettierrc の二重管理。

Biome に一本化してから、設定ファイルは biome.json の1つだけになった。

{
  "formatter": {
    "indentStyle": "space",
    "indentWidth": 2,
    "lineWidth": 100
  },
  "javascript": {
    "formatter": {
      "quoteStyle": "single",
      "semicolons": "asNeeded"
    }
  }
}

single quotes、2 spaces、100 width、semicolons asNeeded。この設定を1つのファイルで完結させている。

開発フロー

# ローカル: lint + format を一発で
bun run check

# CI: 読み取り専用チェック(ファイルを変更しない)
bunx biome ci .

bun run check は lint と format を同時に実行する。biome ci は CI 用のコマンドで、問題があればエラーを返すがファイルは変更しない。

設定ファイルが1つになった快適さは想像以上だ。新しいプロジェクトを作るとき、biome.json を1つコピーすれば終わる。ESLint のプラグイン依存地獄から解放された。

ビルド: Vite

HMR が速い

Vite の HMR(Hot Module Replacement)は速い。ファイルを保存してからブラウザに反映されるまで約50ms。約200個のコンポーネントがあるプロジェクトでも、この速度は維持される。

Canvas ベースのコンポーネントを開発していると、パラメータを微調整 → 結果を確認、のサイクルを何十回も繰り返す。流体シミュレーションの粘性係数、パーティクルの減衰率、物理エンジンの重力定数。このサイクルが50msで回るのと2秒かかるのでは、体験が根本的に違う。

プラグイン順序が命

Vite の設定で最も重要なのはプラグインの順序だ。

// vite.config.ts
export default defineConfig({
  plugins: [
    tailwindcss(),       // 1. Tailwind CSS
    tsConfigPaths(),     // 2. パスエイリアス解決
    cloudflare(),        // 3. Cloudflare Pages
    tanstackStart(),     // 4. TanStack Start
    react(),             // 5. React
  ],
})

この順序を間違えると、ビルドが通らなかったり、デプロイ後に謎のエラーが出る。特に Cloudflare PagesTanStack Startより前に配置する必要がある。これを見つけるのに半日かかった。

Vite の速さは開発体験を根本的に変える。webpack 時代に戻れないのと同じように、Vite 以前には戻れない。

バージョン管理: Git Worktree

ブランチではなく worktree で分離する

約200個のコンポーネントを開発していると、複数のタスクを並行して進めたくなる。コンポーネントAのバグ修正をしながら、コンポーネントBの新機能を開発し、コンポーネントCのリファクタを走らせる。

Git ブランチだけでこれをやると、git stashgit checkout の嵐になる。作業途中のファイルを stash して、別ブランチに切り替えて、終わったら戻って stash pop——これは事故の元だ。

Git Worktree を使うと、ファイルシステムが物理的に分かれる

# 独立タスクは cc <name> で別 worktree に Claude を起動
cc fix-fluid-sim     # worktree を作成し、そこで Claude Code を起動
cc add-pinball       # 別の worktree で別の Claude Code セッション
cc refactor-physics  # さらに別の worktree

各 worktree は独立したディレクトリだ。ファイルの競合が物理的に起きない。

並列開発の実際

ターミナルを3-4つ開いて、それぞれで Claude Code セッションを走らせる。1ターミナル1タスクの原則だ。

ターミナル1: cc fix-audio-context    → AudioContext のバグ修正
ターミナル2: cc add-maze-solver      → 迷路ソルバーの新規追加
ターミナル3: cc refactor-canvas      → Canvas コンポーネントのリファクタ
ターミナル4: メインの worktree       → 差分確認、マージ

各タスクが完了したら staging ブランチへ自動マージされる。コンフリクトが起きるのは稀だ。なぜなら、約200個のコンポーネントはそれぞれ独立したファイルだから。FluidSimulation.tsxMazeGenerator.tsx が同時に変更されても、競合しない。

ブランチではなく worktree で分離する理由は明快だ。ファイルシステムが物理的に分かれるから、「今どのブランチにいるんだっけ」という認知負荷がゼロになる。

CI/CD: GitHub Actions + Blacksmith

Blacksmith runners

CI は GitHub Actions を使い、ランナーは Blacksmith を選んでいる。GitHub のデフォルトランナーより速く、コストも低い。

runs-on: blacksmith-2vcpu-ubuntu-2404

2ステップのデプロイ

デプロイパイプラインはシンプルだ。

steps:
  - run: bun install
  - run: bun run build
  - run: bunx wrangler pages deploy

bun run build でプロダクションビルド(TypeScript の型チェック込み)を行い、wrangler で Cloudflare Pages にデプロイする。

不要なビルドのスキップ

dorny/paths-filter を使って、変更されたファイルパスに応じてジョブをスキップしている。

- uses: dorny/paths-filter@v3
  id: changes
  with:
    filters: |
      src:
        - 'src/**'
        - 'package.json'
        - 'bun.lock'

ドキュメントだけの変更でビルドとデプロイが走るのは無駄だ。パスフィルタでこれを防ぐ。

AI開発: Claude Code

CLAUDE.md でプロジェクトコンテキストを与える

Claude Code の最も重要な機能は CLAUDE.md だ。プロジェクトルートに置くマークダウンファイルで、セッション開始時に自動で読み込まれる。

# CLAUDE.md

## Tech Stack
- Framework: TanStack Start v1.x (React 19)
- Styling: Tailwind CSS v4
- Animation: Motion (motion/react) + Canvas API
- Deploy: Cloudflare Pages

## 注意事項
- motion のインポートは motion/react(framer-motion ではない)
- パスエイリアス ~/ → ./src/
- Viteプラグイン順序: tailwindcss → tsConfigPaths → cloudflare → tanstackStart → react

これを書いておくだけで、Claude Code は「このプロジェクトでは framer-motion ではなく motion/react を使う」「パスエイリアスは ~/ だ」といったことを最初から知っている状態で動く。約200個のコンポーネントすべてで一貫したコードが生成される。

takt ワークフロー

タスクの規模に応じてワークフローを自動選択する仕組みを作っている。

規模 ワークフロー
typo修正、1行変更 そのまま実装 変数名の修正
バグ修正、3ファイル以下 quick-fix AudioContext のエラーハンドリング
新機能、複数ファイル plan-implement-review 新しいゲームコンポーネント
大機能、アーキテクチャ変更 spec-then-build 物理エンジンの設計変更

小さなタスクにフルのレビュープロセスを適用するのは無駄だし、大きなタスクをレビューなしで進めるのは危険だ。規模に応じた適切なプロセスを自動で選ぶ。

1セッション1タスク

Claude Code を使う上で最も重要な原則がこれだ。

同じ問題で2回失敗 → /clear
無関係なタスク間でも → /clear

LLM にはコンテキストウィンドウという制約がある。1つのセッションで複数のタスクを詰め込むと、古い情報が圧縮(実質的には忘却)される。30ファイル目あたりから修正の精度が落ちていく。

だからタスクを分割する。1セッションで1つのことだけをやる。終わったら /clear でリセット。この原則を守るだけで、出力品質が劇的に安定する。

AIは道具の1つだ。だが、最も生産性を変えた道具であることは間違いない。

まとめ:ブラウザゲーム開発環境

自分のツールチェーンを改めて書き出してみると、構成要素は驚くほど少ない。

  • パッケージマネージャ: bun
  • リンター/フォーマッター: Biome
  • ビルド: Vite
  • AI開発: Claude Code
  • バージョン管理: Git + Worktree
  • CI/CD: GitHub Actions + Blacksmith
  • デプロイ: Cloudflare Pages

7つだ。しかも bun、Biome、Vite、Claude Code の4つが中核で、残りは周辺ツールに過ぎない。

道具を減らすほど、各道具の使い方が深くなる。bun の lockfile 最適化、Biome のルールカスタマイズ、Vite のプラグイン順序、Claude Code の CLAUDE.md 設計。1つ1つの道具を深く理解しているから、約200個のコンポーネントを効率的に開発・メンテナンスできている。

新しいツールが出るたびに飛びつくのではなく、今使っているツールをもう一段深く使ってみる。その方が、長い目で見て生産性は高い。