前回まで、ファミリーベーシック起動後のメニュー画面で、AIを導入することでチャットや各種ボードの用途を拡張する検証を行いました。特に、以前にClaudeで実装した部分をOllamaとローカルLLMに置き換えられたこと、また各種ボードとの連携も試せたことは収穫です。ただ、本命のバイブコーディング部分についてはClaudeの支援が必要なままです。
Claudeでの試行は5月ごろの記事で扱いました。時間が経っていることもあり、今回改めてバイブコーディングについての検証結果を整理します。
本記事はローカル LLM による自動執筆パイプラインで生成されました。現段階ではクラウド AI(Claude 等)の補助や人間の編集が介在していますが、pareido.jp では最終的に AI が自律的にコンテンツを制作できる仕組みの構築を目指しています。
本格的なAI操作コンソールを別に出す
第1回から第5回で扱ってきたのは、ファミリーベーシックの画面に直接、AIが干渉するという実装です。例えばチャットでは、起動画面のメッセージ枠を借りて、そこにAIの返事を映すやり方です。1枠108文字、応答は約12.56秒で打ち切り。その枠に収まる短い英文を返させるところまでが守備範囲でした。
ファミリーベーシックではGAME BASICモードとメニュー画面は分離しており、この方式ではコーディングの支援が難しい。また、コードの長さや複数行の取り扱いを考えれば、定評のある別画面でのチャットUIが必要です。また、そもそもV3ではメニュー画面が廃止されています。
今回の主役は、エミュレータの画面の横に増設した、コーディング支援専用のパネルです。入力欄は2〜3行の入力が可能で、その下に Send / Type / Copy / Paste の4つのボタンが並び、右下に動作状態(Idle)が出ます。nesemuの機能を拡張する形で、ブラウザ上で画面とは別のウィンドウとして表示する処理のため、ファミリーベーシック側の制約を受けず、コピペや編集が用意に可能です。
| 項目 | ハイジャック方式(第1〜5回) | バイブコーディングのパネル |
|---|---|---|
| どこに出るか | ファミベ画面のエラーメッセージ枠 | ブラウザ側の常設パネル |
| 入力できる文字 | 大文字英数とカタカナ | 日本語を含めて自由 |
| 1回の分量 | 108文字まで | 制限なし(コードブロック丸ごと) |
| AIに返させるもの | 短い英文の返事 | BASICのプログラム |
| 実行までの手順 | 実行という概念がない | Typeボタンで自動入力 → RUN |
「You:」「AI:」と会話が積まれていく見た目は、ふつうのチャットと合わせました。違うのは、AIが返すのが文章ではなく基本的にBASICのプログラムであること、そして返ってきたコードを画面へ流し込むボタンが最初から用意されていることです。

プロンプト指示から7分、それらしいものが動いた
まず以前の実行例を改めて確認します。チャットでのプロンプト指示は一行だけです。「スペースインベーダー風のスプライトを使ったキーボードで操作するゲームを作って」。バックエンドはClaude搭載の時点、claude-cliです。
録画の経過時間で並べると、こうなります。
| 経過時間 | 画面の状態 |
|---|---|
| 0:50 | 依頼済み。AI欄が応答待ちに入る |
| 5:25 | 応答完了。行番号900(GAME OVER:END)までのコードが返る |
| 6:00 | 自動入力の途中。BASIC画面は行80まで |
| 7:00〜7:02 | 「Typing code into Family BASIC…」→「Done! Type RUN and press Enter to execute.」を経てRUN。画面が動き出す |
| 7:36 | SCORE: 60まで進行。録画を切るため停止 |
応答には7分かかりました。これはウォームアップ等を含まない時間ですが、平均的にこの前後の時間がかかります。この時点でもう軽い待ち時間とは言えません。裏でファミリーベーシック向けの大きなリファレンス文書をプロンプトに渡していたためです。
この「大きなリファレンス文書」の中身は、技術部の別連載「LLMのためのFamily BASICリファレンス」で扱っています。 言語仕様について、製品付属のマニュアル等によらずまとめたもので、サンプル等を改めて書き起こしたものです。 これをコーディング支援が可能なLLMに与えれば、原理的にはLLMによらず再現が可能です。
Typeボタンは打ち込みの間赤い「Stop」に変わり、BASIC画面には行が1文字ずつ積まれていきます。打ち込み先の空きメモリは1982バイト。行番号900までのプログラムが、この中に収まっています。

画面に読めるコードには、ファミリーベーシック固有の命令が並んでいます。DEF SPRITE と CHR$ によるスプライトの定義、CGSET によるキャラクタセットの切り替え、DEF MOVE と POSITION で組んだ敵の動き、INKEY$ のキー入力判定、LOCATE と PRINT で出すスコアと操作説明。ファミリーベーシックはBASIC言語を独自に拡張、または簡略化した仕様のため、コーディング支援が可能なLLMが持つ一般的なBASICの知識だけでは対応ができません。
LLMの応答には日本語の遊び方解説も付いています。「操作方法: Zキーで左移動、Xキーで右移動、SPACEキーで弾発射」、そして「当たり判定: ABS(BX-E1)<16 AND ABS(BY-E2)<16(16ピクセル矩形)」。当たり判定の取り方まで、説明付きで返ってきます。

RUNで実際に動きました。自機が左右に動き、弾が出て、当たると得点が入ります。画面上段の「Z< X> SPACE:SHOT」は、コードの56行目が LOCATE 0,1:PRINT で出している文字列そのままです。
ただ、「スペースインベーダー」と言い切るには少し苦しいのも正直なところです。実際に動いているのは敵1体だけで、あの整列した編隊は出てきません。また、プレイの途中で実行時エラーが出ます。当たり判定も微妙です。「それらしい見た目」までは来ているものの、期待どおりの完成度、と呼ぶのは無理があります。

7:36でSCORE: 60。録画を切るために止めたので、BREAK IN 90 が出て OK. に戻ります。ここはエラーで落ちたのではなく、こちらから止めた形です。表示が「BREAK IN 90:SHOT」と読めるのは、11文字の BREAK IN 90 が前の行の操作説明に重なり、末尾の :SHOT だけが残っているからです。
それでも手応えはありました。簡単な指示から、ほぼそのまま動くコードが出てきたこと自体がまず収穫です。バイブコーディングと呼んで差し支えないでしょう。加えて、この欄はチャットのたびに画面の文字情報を一緒にAIへ渡しているので、エラーが出ても完全に手放しではなく、AI自身がある程度は画面を見ながら直しにいける仕組みになっています。完璧ではありません。それでも、「AIとおしゃべりはできてもプログラムは書けない」から一歩先に進んだ実感は、この録画に残っています。
生成されたコード本文の例
ここでは、同じ条件でClaudeを用いて生成したコード例を紹介します。応答には約6分かかりました。
10 CLS:SPRITE ON:CGSET 1,0
20 DEF SPRITE 0,(0,1,1,0,0)=CHR$(172)+CHR$(173)+CHR$(174)+CHR$(175)
30 DEF SPRITE 1,(1,0,1,0,0)=CHR$(212)
40 DEF SPRITE 2,(2,1,1,0,0)=CHR$(56)+CHR$(57)+CHR$(58)+CHR$(59)
50 DEF SPRITE 3,(2,1,1,0,0)=CHR$(56)+CHR$(57)+CHR$(58)+CHR$(59)
60 DEF SPRITE 4,(2,1,1,0,0)=CHR$(56)+CHR$(57)+CHR$(58)+CHR$(59)
70 DIM EX(2):DIM EY(2):DIM EL(2)
80 EX(0)=40:EX(1)=120:EX(2)=200:EY(0)=40:EY(1)=40:EY(2)=40:EL(0)=1:EL(1)=1:EL(2)=1
90 ED=3:SC=0:PX=120:BX=0:BY=0:CT=0:SPRITE 2,40,40:SPRITE 3,120,40:SPRITE 4,200,40:SPRITE 0,120,200
100 S=STICK(0):T=STRIG(0)
110 IF S AND 1 THEN PX=PX+3:IF PX>240 THEN PX=5
120 IF S AND 2 THEN PX=PX-3:IF PX<5 THEN PX=240
130 SPRITE 0,PX,200
140 IF T>0 AND BY=0 THEN BX=PX+8:BY=200
150 IF BY>0 THEN BY=BY-5:SPRITE 1,BX,BY
160 IF BY<10 THEN BY=0:SPRITE 1
170 CT=CT+1:IF CT<4 THEN 220
180 CT=0:FOR I=0 TO 2:EX(I)=EX(I)+ED*EL(I):NEXT
190 IF EX(0)<5 OR EX(2)>230 THEN ED=-ED:FOR I=0 TO 2:EY(I)=EY(I)+10:NEXT
200 FOR I=0 TO 2:IF EL(I) THEN SPRITE I+2,EX(I),EY(I)
210 NEXT
220 FOR I=0 TO 2:IF EL(I)=0 THEN 240
230 IF BY>0 AND ABS(BX-EX(I))<14 AND ABS(BY-EY(I))<14 THEN EL(I)=0:SC=SC+10:BY=0:SPRITE 1:SPRITE I+2
240 NEXT
250 LOCATE 0,0:PRINT "SC=";SC;" "
260 IF EL(0)=0 AND EL(1)=0 AND EL(2)=0 THEN LOCATE 4,12:PRINT "YOU WIN!":END
270 FOR I=0 TO 2:IF EL(I) AND EY(I)>185 THEN LOCATE 4,12:PRINT "GAME OVER":END
280 NEXT:PAUSE 2:GOTO 100
行番号10から280までの40行の例です。DEF SPRITE・CGSET・SPRITE文で自機と敵3体をハードウェアスプライトとして描画し、STICK(0)で移動、STRIG(0)で発射、ABS(BX-EX(I))<14 AND ABS(BY-EY(I))<14という総当たり判定。この例ではRUN後もエラーなく動作し、敵3体が横移動しながら少しずつ下降し、弾が命中すると加点、全滅でYOU WIN、自機ラインへの到達でGAME OVERという勝敗判定まで機能しました。同じ依頼文・同じ環境でも、より完成度の高い結果が出ることがある、という一例です。
実際にRUNした瞬間の短い動画も置いておきます。
「Claudeだったから通った」の中身
このときAI側に立っていたのは claude-cli で、モデルは Claude Sonnet です。
今回改めてOllamaと、比較実験のためOpenAIのGPTへの切り替えを追加しました。
前回の時点で、実はOllama経由で小型のローカルLLMもいくつか試したのですが、実用的ではありませんでした。
比較的、現実的な反応を返せたのは OpenAI の gpt-oss:20b でしたが、当時の環境では重すぎて実用性がありません。
DeepSeek, Qwen2.5-code なども試しましたが、日本語対応も少々怪しくローカルLLMの利用は断念しました。
難所は、ファミリーベーシックのBASICは DEF SPRITE・DEF MOVE・CGSET・POSITION といった独自命令を持つこと、マリオやレディなどキャラクターの名前が通じないことなど、ハーネスの実装が必要なことは明らかでした。前述のリファレンスの対応で大きく改善しましたが、言語使用一式をプロンプトに含めると32K程度のコンテキストサイズが必要となり、必要とするメモリ量も跳ね上がります。このため、当時は Claude のようなクラウド型の大型LLMでないと対処が難しかったというのが事実です。試していませんが、OpenAIのGPTやGoogleのGeminiでも同等の動作は期待できたと思われます。
ついでに書いておくと、このプロジェクトでClaudeと付き合い始めたのはここではありません。エミュレータのROMのハッシュが合わずに起動しない、という手前の躓きを直すところからでした。その顛末は辺境部の連載に残っています。ファミリーベーシックに関する知識も高く、実質Claude一択で進めてきた経緯があります。
次回は、このパネルの接続先をClaudeからChatGPTに差し替えます。同じ依頼文が、別のAIでどこまで通るのか。そのあとにローカルLLM、そしてVSCode側から直接書かせる場合を並べていきます。今回はまず、動いた記録としてここに置いておきます。