台パンRPG

https://github.com/kyiku/hackz-allo.git

Swift

GitHub

TypeScript

React

RPG感覚でバイブコーディングしながら台パンする

紅茶ふりふり

Cookie777

推しアイデア

・台パンで神経衰弱 ・GitHubの開発体験をRPG風に

作った背景

台パンで神経衰弱がしたかった。

推し技術

・ARkit ・Claude Agent SDK

プロジェクト詳細

概要

台パンRPG は、AI による TDD 開発を RPG の戦闘体験にするツールです。リポジトリのオープン Issue が「敵」になり、AI エージェント(ForgeAgent)がテスト駆動で実装して PR をマージすると敵が撃破されます。

仕組みを一言でいうと

iOS アプリは「AR のガワ」にすぎません。中身の RPG 本体は Cloudflare に置いた Web アプリで、それが Cloudflare Tunnel 越しに手元のローカル開発マシンで動く Runner へつながり、Runner が ClaudeGitHub を動かしています。

「公開された Web/アプリ」と「手元の PC で動くサーバ」をつなぐのが Cloudflare Tunnel の役割。


構成要素

📱 ネイティブアプリ(iOS / Swift + RealityKit)

TableBangConcentration。役割は2つ。

  • AR 神経衰弱+台パン検出 … 手の動きを Vision で検出し、カードを RealityKit で表示する AR ミニゲーム。報酬パートだけネイティブが担当します。
  • WKWebView … RPG 本体の Web を表示するだけのコンテナ。起動時に読み込む URL へ ?backend=<トンネルURL> を付け、Web にバックエンドの接続先を渡します。

つまり「世界・戦闘・賢者の家(ステータス/枠の設定)」などの UI はすべて Web 側で、ネイティブは AR 報酬ゲームと WebView の器に徹しています。

☁️ Cloudflare Pages(Web 本体)

github-issue-rpg.pages.dev に配信される、React / Zustand / Phaser 製の Web アプリ。ネイティブの WebView はこの公開サイトを HTTPS で読み込みます。RPG の画面・状態管理・サーバとの WebSocket 通信はここが担います。

☁️ Cloudflare Tunnel(ローカル公開)

xxxx.trycloudflare.com のような一時的な公開 URL。手元の PC で動く Backend を、外部(公開 Web やスマホ)から到達できるように中継します。これが無いと、公開された Web から手元の Runner へ届きません。

💻 ローカル開発マシン

  • Backend(WebSocket サーバ) … クライアントからのイベントを受け取り、Runner へ振り分けます。
  • Runner(オーケストレーション) … 戦闘・接続・報酬などのジョブを実体として実行します。GitHub の PAT(トークン)は Runner 内部に閉じています。
  • SQLite … プレイヤー状態と loadout(=MCP/サブエージェント/モデルティア)を永続化します。

GitHub / Claude

  • GitHub(対象リポジトリ) … Issue が敵、PR のマージが撃破。Runner が clone・PR 作成・マージを行います(Fixes #n で Issue が自動クローズ)。
  • Claude(Agent SDK) … ForgeAgent の query()(loadout から model / mcpServers / agents を注入)と、必要テストの構造化生成を担います。

ネイティブ ⇄ Web のつなぎ(JS ブリッジ)

AR 報酬ゲームだけがネイティブ、それ以外は Web——この2つは WKWebView の JS ブリッジでやり取りします。

  • Web → ネイティブwindow.webkit.messageHandlers.bridge.postMessage(...)reward.start(台パンゲームの開始+カード一覧)を渡す。
  • ネイティブ → Webwindow.__claimRewards([...]) を呼んで、獲得した効果 ID を Web へ返す。

処理フロー

Phase 1 — 接続(リポジトリの Issue を敵にする)

  1. Web が cmd.connect(repoURL) を WebSocket で送る(Cloudflare Tunnel 経由でローカルへ)。
  2. Runner が GitHub のオープン Issue を取得する。
  3. Backend が world.state(敵=Issue)を Web へ返し、世界に敵が並ぶ。

Phase 2 — 戦闘(ForgeAgent が TDD で実装)

  1. Web が cmd.forge(issueNumber) を送る。
  2. Runner が Claude で「通すべきテスト」を生成し、対象リポジトリを clone する。
  3. ForgeAgent が query() で起動(loadout の model / mcpServers / agents を実注入)。「まずテストを書いて失敗(RED)→ 最小実装で成功(GREEN)」の TDD で実装する。
  4. npm test が通ったら push → PR 作成 → squash マージ(本文の Fixes #n で Issue が閉じる)。
  5. Backend が battle.defeated を返し、敵が撃破される。

Phase 3 — 報酬(台パン神経衰弱:ネイティブ AR)

  1. Web が reward.start { cards: [{ effectId, label }] } をブリッジでネイティブへ渡す。
  2. プレイヤーが台パンを3回。3回目(+3秒バッファ)の時点で表向きになっているカードを確定する。
  3. ネイティブが __claimRewards([effectId, …]) で確定した効果 ID を Web へ返す。
  4. Web が cmd.reward.claim { effectIds } を送り、Runner が applyEffectsloadout の枠を増減する。
  5. Backend が player.status を返し、賢者の家(ステータス画面)に枠が反映される。

なぜ Cloudflare Tunnel が必要か

  • Web は公開サイト(Cloudflare Pages)、Backend / Runner手元の PC で動いています。
  • 公開された Web(およびスマホアプリ)から手元のサーバへ到達させるため、Cloudflare Tunnel で localhost を一時的な公開 URL に変換しています。
  • ネイティブアプリは、その公開 URL を WebView の ?backend= クエリで Web に渡すだけ。Web はそれを WebSocket の接続先として使います。

まとめると、データの通り道は 📱/Web → Cloudflare Tunnel → ローカル Backend/Runner → Claude・GitHub という一本道で、Tunnel が「公開」と「手元」の橋渡しをしています。

紅茶ふりふり

@Rozpring