以下の内容はhttps://smooth-pudding.hatenablog.com/entry/2025/05/25/143515より取得しました。


【AI×Tauri】第三回:動くハリボテを作る

前回は画面設計などのUIの設計に加えて、バックエンドAPIの設計も行っていきました。
smooth-pudding.hatenablog.com
今回は実際にコードを作成して、少しずつ動くものを作っていきたいと思います。

Tauri プロジェクトの作成

まずは環境構築します。この部分は公式の説明がかなり詳しいので、説明は省略します。以下の Prerequisites のページを見てトライしてください。
v2.tauri.app

プロジェクトの作成についても、公式が詳しいです。私は cargo に create-tauri-app をインストールした上で、cargo create-tauri-app しました。なお cargo create-tauri-app を実行したディレクトリ以下にプロジェクトのディレクトリが作成されます。
v2.tauri.app

プロジェクトの設定は以下のようにしました。

  • プロジェクト名: secondbest-tauri
  • 識別子: デフォルト
  • フロントエンドの言語: TypeScript / JavaScript
  • パッケージマネージャ: npm
  • UIテンプレート: React
  • UIフレーバー: TypeScript

ツールの指示にしたがって以下を実行すると・・・

cd secondbest-tauri
npm install
npm run tauri dev

長い Rust のビルドの末、デフォルトで生成されるサンプル画面が表示されました。

サンプルの画面

作ったものは GitHub で公開したいので、以下のリポジトリを作成し、生成されたコードを push しました。
github.com

早速コードを書いていく!・・・その前に?

仕様の方針もできたし、Tauri のプロジェクトも作った。では早速AIに命令!・・・と行きたいところですが、今の時点のものをAIに投げてもきっとうまくいきません。

残念ながら、現在のAIのレベルは「命令すればなんでも完璧に作ってくれる」というレベルにはありません。ある程度のサイズのものを生成したら、必ず人間が確認する必要があります。でも、人間が確認できるサイズはそれほど大きくありません。したがって、人間の確認できるサイズに合わせて、AIに命令する内容も分解する必要があります。

今回作るゲームも、いきなり「これを作って!」と全部AIにお願いしても、できたものすべてを人間は確認しきれないでしょう。仮にうまく動くものが作れたとしても、それはただのブラックボックスであり、「作りながら React を学びたい」という目的から外れてしまいます。また、ブラックボックスということは「制御不能」と紙一重なので、極めて危うい状態にあるコードと言えます。

また、もし仮に頑張って生成されたコードの全容を把握できたとしても、それが人間にとって読みやすいコードとなっている可能性はあまり高くありません。経験上、規模の大きいコードを生成させると、すごくネストの深いコードを作ったり、すごく行数の長い関数を作ったりして、どうやって管理可能なコードにすればよいのか頭を抱えることになりがちです。そういった部分を選択して「ここを読みやすいようにリファクタして」と命令することもできますが、この作業で機能が壊れてしまうことも多いです。つまり、今のコードを把握できるかどうかに関わらず、事実上管理の困難な状態になる可能性が高いということです。

ということで、まずやるべきは、延長線上のはるか先に目的の実装があるような、最初の地点の “ハリボテの仕様” を決めるということです。小さな仕様からスタートし、少しずつ追加の仕様を盛り込みながら、最終的に目標の実装を目指す、という戦略です。

ハリボテ仕様の策定

ではハリボテ仕様を決めていきます。

  • ホーム画面
    ここは元からシンプルなので、このままで行きます。
  • 設定画面
    設定変更を省略します。中央には何もなく、右上の戻るボタンのみ残してみます。
  • ゲーム画面
    セカンドベストボタン・ボード・ステータス表示は以下のようにコンポーネント化します。
    • セカンドベストボタン: 機能のないボタン
    • ボード: 機能のないキャンバス
    • ステータス表示: ダミー文字を表示するラベル

この仕様であれば、バックエンドは特に追加実装なしで大丈夫そうです。

配置を言葉にして Markdown にまとめていきます。たたき台として、以下の Markdown を作成しました。


▼たたき台をクリックで表示
ざっくり書けたので、Cursor で再度整理してもらっておきます。Tauri のプロジェクトに docs ディレクトリを作成し、haribote_base.md として保存しておきます。そのうえで Agent で以下を命令します。

@haribote_base.md はこのプロジェクトの画面の仕様を記述したものです。これは後ほどAIに渡して画面の実装を行ってもらう予定のものです。
@haribote_base.md の内容を確認し、画面設計を効果的に伝えられる Markdown を生成してください。結果のファイルは docs/haribote.md として出力してください。画面の実装に着手してはいけません。

例によって @haribote_base.md のところはファイルへのリンクを貼っておきます。出力されたものは以下です。


▼整理したハリボテ仕様をクリックで表示
とても詳細に渡って配慮されたファイルが生成されました。元の haribote_base.md は消して、こちらを使うことにします。

ハリボテ実装の生成

十分実装内容を絞れたので、早速実装させてみます。Agent で新しい窓を開いて、以下を命令します。新しい窓にすることで、先程までの記憶を消すことが出来ます。

@haribote.md はこのアプリの画面の仕様を記述したファイルです。このファイルに基づいて、画面の実装を生成してください。

その結果、src 以下の下記のファイルが作成・更新されました。

Cursor が作成・更新したファイルたち

pages ディレクトリには各画面が、components には各コンポーネントが入っているようです。同名の .tsx ファイルと .css ファイルをセットにしていて、jsx の定義と css をペアにして管理するようですね。

テスト実行してみると・・・残念ながら真っ黒の画面になっています。

テスト実行

ここで Cursor で「ちょっと💢画面が真っ黒なんだけど💢💢」と命令することもできますが、一旦自力で状況を調べてみることにします。

まず、npm run tauri dev を実行したときにターミナルに表示されるURLを Chrome で開いてみます。

  ➜  Local:   http://localhost:1420/

すると、表示自体はされました。ということは WebView の問題が疑われます。見た目の修正は後回しにして、ひとまずこの部分の修正に調整してみます。

Chrome から開いた画面

修正の仕方のアイディアが出てこないので、ChatGPT に質問してみます。

Tauri でアプリを開発しています。npm run tauri dev でアプリを起動したところ、真っ黒の画面しか出ません。ビルド中に表示される URL に Chrome でアクセスすると問題なく表示されます。原因として考えられるものと、それらの修正方法を箇条書きでいくつか示してください。なお私の環境は Ubuntu 24.04.2 LTS です。

ChatGPT の見立ては、やはり WebView の表示や設定が原因でしょう、とのことでした。提案してもらった方法を順番に試しましたが、うまく解消できません。いろいろ試行錯誤して「あれ?もしかして Cursor がリソース食いすぎているのでは?」と思い当たり、Cursor を閉じた状態で起動したところ・・・なんと起動しました!

Cursor を閉じた状態で起動

その後いろいろ試したところ、Cursor 内で開いたターミナルからだと黒い画面になり、通常のターミナルから起動すれば正常に起動することが分かりました。正直原因は不明ですが、起動できる方法がわかったのでひとまずよしとします。

プチトラブルが解決できたので、見た目の修正に入ります。

まず、ゲーム画面の右上のボタンが重なっているので、そこから解消します。編集対象は pages/GamePage.tsx または pages/GamePage.css あたりでしょう。pages/GamePage.tsx を開いてみます。jsx を作っている部分を抜粋すると、以下の通りでした。

const GamePage: React.FC<GamePageProps> = ({ onHomeClick }) => {
  return (
    <div className="game-page">
      <div className="game-header">
        <div className="game-buttons">
          <button className="home-button" onClick={onHomeClick}>
            🏠
          </button>
          <button className="refresh-button">
            🔄
          </button>
        </div>
      </div>
      
      <div className="game-content">
        <SecondBestButton />
        <Board />
        <StatusDisplay />
      </div>
    </div>
  );
};

pages/GamePage.css を開いて、game-buttons や home-button や refresh-button に貼り付けられている CSS も見てみます。

.game-buttons {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.home-button,
.refresh-button {
  width: 50px;
  height: 50px;
  background-color: #EFEBE9;
  border: 2px solid #3E2723;
  border-radius: 8px;
  font-size: 24px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.3s ease;
}

.home-button:hover,
.refresh-button:hover {
  background-color: #E0D7D3;
  transform: scale(1.05);
}

.refresh-button {
  cursor: default;
  opacity: 0.8;
}

う〜〜〜〜〜〜ん、わからん!ということで、2つのファイルを Cursor に参照させて編集してもらいます。Agent を開いて、以下のように命令してみます。

@GamePage.tsx @GamePage.css 右上に配置しているホームボタンとリフレッシュボタンが重なっています。ホームボタンのすぐ下にリフレッシュボタンを配置するようにしてください。

...残念ながら問題が解消されませんでした。もう一度お願いしてみます。

修正されず、依然として同じ場所で重なって表示されています。再度実行してください。

今度こそ修正されました!

ゲーム画面のボタン配置を修正

CSS の方に以下の修正を行ったようです。

  .game-buttons {
    display: flex;
    flex-direction: column;
+   align-items: flex-end;
    gap: 10px;
+   width: auto;
+   height: auto;
  }

  .home-button,
  .refresh-button {
    // (中略)
    transition: all 0.3s ease;
+   position: static;
+   margin: 0;
  }

しかし今度は画面中央のコンポーネントが下にずれてしまいました。tsx ファイルをよく見てみると、右上のボタンをヘッダーとして配置して、その下に中央のコンポーネント群を配置しているようです。そのため、ボタンの配置が縦長になったのに伴って、中央のコンポーネントも下に下がったということですね。

Cursor に改めて注文してみます。

@GamePage.tsx @GamePage.css 現在、右上のボタンよりも下の部分に中央の SecondBestButton, Board, StatusDisplay が表示されています。そうではなく、SecondBestButton, Board, StatusDisplay の配置は画面の上下に対して中央揃えするようにしてください。右上のボタンの配置は変えないでください。

Cursor による修正後に起動してみると、問題なく修正されていることが確認できました!

中央のコンポーネントの位置修正

変更点は以下のようです。

  .game-page {
    height: 100vh;
    background-color: #D7CCC8;
    display: flex;
    flex-direction: column;
+   position: relative;
  }

  .game-header {
-   display: flex;
-   justify-content: flex-end;
-   padding: 20px;
+   position: absolute;
+   top: 20px;
+   right: 20px;
+   z-index: 10;
  }
  // (中略)
  .game-content {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 30px;
    padding: 20px;
+   height: 100vh;
  } 

ヘッダーは固定位置になったようです。またページ全体に position: relative を適用し、中央のコンポーネント群全体に height: 100vh を適用したようです。ちなみに 100vh というのはざっくり「親の高さ比100%」という意味のようです。質問がはっきりしているときは、AIに尋ねるより検索するほうが早いですね。
web-camp.io

同じような問題がホーム画面と設定画面でも起きていそうなので、同じ編集を適用してもらいましょう。

同様の編集を @HomePage.css と @SettingsPage.css にも適用してください。

・・・残念ながら、むしろレイアウトが崩壊してしまいました。作戦を変えましょう。

まず pages/SettingsPage.tsx を見てみます。どうやら GamePage.tsx と違い、右上のボタンをヘッダーとして扱っていないようです。

const SettingsPage: React.FC<SettingsPageProps> = ({ onHomeClick }) => {
  return (
    <div className="settings-page">
      <button className="home-button" onClick={onHomeClick}>
        🏠
      </button>
      
      <div className="settings-content">
        <h2 className="settings-title">設定</h2>
        <div className="settings-area">
          <p className="settings-placeholder">設定項目はここに表示されます</p>
        </div>
      </div>
    </div>
  );
};

形式を合わせたほうが管理しやすそうなので、合わせるように命令してみます。

@GamePage.tsx に倣って、 @SettingsPage.tsx の右上のボタンも settings-header という div 要素で管理するようにしてください。 @SettingsPage.css も同様に @GamePage.css に倣って修正してください。

今度こそ正常に修正してくれました (詳細は割愛します)。似た編集を HomePage に対しても適用してもらいます。

@HomePage.tsx と @HomePage.css についても同様の編集を行ってください。

今度はちゃんと意図を汲み取って適用してくれました!以下が修正後の画面です。

修正後

全体レビュー

一旦形になったので、試しに全体をレビューしてもらいましょう。Agent で以下を命令します。

現在のプロジェクト全体の実装を確認して、改善したほうが良い点があれば列挙してください。

かなりしっかりとしたフィードバックが返ってきました。Markdown に出力してもらったものが以下です。


▼フィードバックをクリックで表示
指摘事項のほとんどは実装を進めていく中で拾えそうです。状態管理については知識がないので、追加でコメントをもらっておきます。

状態管理の改善の項目について詳しく教えてください。改善の具体的な方法について Markdown にまとめて出力してください。コードは修正しないでください。

するとかなり詳しく返してくれました。どこかで役に立つかもしれないので、docs/ 以下に保存しておきます。読みたい方はこちらのリンクからどうぞ。指摘内容については、今後必要になったタイミングで検討することにします。

第三回まとめ

今回はグッと仕様を絞ったハリボテ仕様を作って、それを実装していきました。現状は画面遷移しか実装できていませんが、それでも少し動くことは嬉しいですね。

今回生成したコード達は "v3-haribote" というタグをつけています。確認したい方は以下からどうぞ。
github.com


次回はフロントエンド側のボードの実装に取り組んでいけたらいいなと思います。さらに雰囲気が出てくると嬉しいです。

ではまた。

続き↓
smooth-pudding.hatenablog.com




以上の内容はhttps://smooth-pudding.hatenablog.com/entry/2025/05/25/143515より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14