昭和のゲームが、ブラウザでそのままプレイできる。
インベーダーに、ブロック崩し。見た目は素朴、挙動もどこか懐かしい。けれど、それらはすべて ローカルAIが生成したコード で動いている。
本記事では、RTX3060 という“少し前の世代”のGPU環境で、Qwen3-Coder-30B-A3B-Instruct を実際に動かし、
Vanilla JS だけでゲームや Todo アプリを生成させてみた記録をまとめる。
速さは正直、最新クラウドAIには及ばない。
それでも、「秘密が外に出ない」「手元で完結する」「仕様次第で実務に使える」――そんなローカルAIならではの価値は、確かに感じ取れた。
この記事では、
- “Simple” という一言が生んだ昭和オリジナル風インベーダー
- 10 tok 環境で見えた現実と、仕様駆動の強さ
- そして、実際に遊べるデモとプロンプトの関係
を、実例ベースで見ていく。
懐かしさ半分、実務検証半分。
ローカルAIコーディングの「今」を、少しだけ覗いてみよう。
第1章:なぜ今さら RTX3060 でローカル30Bなのか
最近の生成AI界隈は、とにかく新モデルの話題が尽きない。
Qwen3-Coder-Next だの、より大きなコンテキストだの、より高精度だの。どれも魅力的だし、実際に性能も上がっている。
ただ、ふと我に返ると、手元の環境はどうか。
私の作業環境に載っているのは、RTX3060(12GB)。
決して貧弱ではないが、「最新・最大」を語るには少し現実寄りの構成だ。世の中を見渡しても、このクラスのGPUを使っている人はかなり多いはずで、「24GB以上前提」の話は、どうしても他人事になりやすい。
そこで気になったのが、いわゆる 30BクラスのローカルLLM は、もうこのあたりの環境で“実用”と呼べるところまで来ているのか、という点だった。
今回使ったのは、
qwen3-coder-30b-a3b-instruct(GGUF, 約17〜18GB級)
というモデルだ。

私が使っているのは unsloth 版だが、最近は LM Studio Community 版も出ているらしい。もっとも、今回の主題は「配布元の違い」ではない。このサイズのモデルが、RTX3060クラスで現実的に回るのか、そして何に使えるのか、そこを見極めたい。
新しくなった、LM Studio V0.41 で行く。
実際に動かしてみると、VRAMは当然ギリギリだし、メインメモリへのオフロードも入る。生成速度も、体感でだいたい 10 tok 前後。クラウドの最先端モデルのように、気持ちよく文章が流れてくるわけではない。
それでも、「遅いから使えない」と切り捨てるには、少し早い気がした。
問題はスピードではなく、何に使うかだ。
もしこれが、
- 文化的な“それっぽさ”を再現させる用途なら、正直つらい
- でも、仕様を渡してコードを書かせる「作業機械」としてなら?
そんな仮説を確かめるために、まずは肩慣らしとして、いくつか“遊び”の題材を投げてみることにした。
インベーダーゲームやブロック崩しといった、いかにも分かりやすい題材だ。
ここから先は、「ローカル30Bで何が起きたか」の実験記になる。
ベンチマークではないし、最新モデル礼賛でもない。現実的なGPU環境で、どこまで“道具”になるのか、その観察記録だ。
第2章:“Simple”が生んだ、昭和オリジナルのインベーダー
最初に試したのは、ごく単純な題材だった。
「シンプルなインベーダーゲームを作れ」。それだけだ。
プロンプトに入れたキーワードも、せいぜい “Simple” と “Space Invaders” くらいのもの。文化的な再現性や、オリジナルへの忠実さは、特に求めていない。むしろ、「どれくらい素直に“動くもの”を組み立ててくるか」を見たかった。
出てきたものは、正直、見た目はまったく華やかではない。
色数は少なく、エフェクトもない。UIも必要最低限。コードを見ても、コメントは控えめで、構造はかなりストレートだ。
それなのに、動かしてみると、ちゃんと“ゲーム”になっている。
弾は撃てる。敵は動く。スコアも増える。スピード調整も効く。
見た目は決して洗練されていないのに、不思議と「昭和の喫茶店に置いてあったテーブル筐体」を思い出すような、あの素朴な空気がある。
あとから冷静に考えると、これは「再現」ではない。
Space Invaders という文化を正確にトレースしているわけでもないし、演出やゲームデザインが寄っているわけでもない。
むしろ、
“Simple” という制約が、そのまま「昭和オリジナルっぽい何か」を生んだ
と言ったほうが近い。
ブロック崩しでも、だいたい同じ傾向だった。
多少のバグや挙動の甘さはあるが、ちゃんと遊べる。派手さはないが、「ああ、こういうのあったよね」と言いたくなる雰囲気はある。
一方で、少し無茶をして「スペースハリアーっぽいもの」を頼んでみると、結果は見事に“謎シューティング”になった。
入力は効く。オブジェクトも動く。だが、そこにあるのは「それっぽい記号の集合体」であって、ゲームの文脈はかなり怪しい。
ここで、はっきりしたことがある。
ゲームの文化理解をAIに求めるな。
少なくとも現時点では、AIが持っているのは「データとしての平均像」であって、「時代背景込みの文脈」ではない。
アメリカ文化に深く溶け込んだゲーム史くらいまでなら、まだ参照できるだろう。だが、日本ローカルの感覚や、「あの頃の空気」まで含めた再現は、さすがに期待しすぎだ。
“inspired by” という指示は、結局のところ 文化理解テスト になる。
当たれば面白いが、外れれば「それっぽい別物」が出てくる。
それでも、今回のインベーダーとブロック崩しには、ひとつ大きな収穫があった。
仕様を細かく書かなくても、“Simple”という制約だけで、ちゃんと動くものを組み立ててくる。
これは、コーディングAIとしての基礎体力が、もう十分に実用ラインに来ている、という証拠でもある。
ただし同時に、こうも思った。
これは“遊びのデモ”としては面白い。
でも、これがコーディングAIの本質じゃない。
次に見るべきなのは、文化の再現ではなく、仕様を渡したときに、どれだけ安定して「意図通りのもの」を組み立てられるかだ。
そこで、少し視点を変えて、もっと実務寄りの使い方を試してみることにした。
第3章:10 tok の現実と、仕様駆動の強さ
このクラスのモデルを RTX3060 で回すと、現実はなかなか正直だ。
生成速度は、体感でだいたい 10 tok 前後。クラウドの最先端モデルのように、文章やコードが勢いよく流れ出てくる感じではない。
正直に言えば、これで「対話しながらガンガン詰めていく」使い方は、少ししんどい。
レスポンス待ちの時間は、確実に作業テンポに影響する。
ただ、ここで重要なのは、速度そのものよりも、タスクの性質だと思った。
インベーダーやブロック崩しのように、“それっぽさ”を探りながら何度も投げ直す用途だと、この待ち時間はストレスになりやすい。しかも “inspired” という曖昧な指示は、出力がブレる。コンテキスト長を変えただけで、コード量が減ったり、挙動が変わったりもした。
一方で、発想を切り替えて、
- やりたいことを箇条書きで書く
- 機能要件をはっきりさせる
- 余計な「雰囲気指示」を捨てる
こうした 仕様駆動 の形にすると、挙動が一気に安定する。
これは体感的にもかなりはっきりしていて、
“inspired” だと「文化理解テスト」になり、
仕様を書くと「翻訳作業」になる。
後者に入った瞬間、ローカル30Bはかなり頼もしい。
コードの構成は素直だし、極端に奇妙な設計にもならない。必要な機能を、必要な部品として積み上げてくる感じがある。しかも、Vanilla JS 程度のスコープなら、こちらが意図した粒度から大きく外れることも少ない。
ここで見えてきたのは、こんな感触だ。
ローカル30Bは、「アイデア出しの相棒」よりも、
「仕様を渡して、下書きを組ませる作業機械」に向いている。
この使い方なら、10 tok という速度でも、十分に我慢できる。
むしろ、生成を待っている間に、次に投げる仕様を整理したり、出てきたコードのチェックポイントを考えたりできるので、作業リズムとしては悪くない。
そして、この「仕様駆動なら安定する」という感触を、もう少しはっきり確かめるために、次はもっと地味で、もっと実務に近い題材を投げてみることにした。
フレームワークなし、ビルドなし、Vanilla JS だけで動く、
ごく普通の Todo アプリ だ。
第4章:Vanilla JS Todo で分かる“実務の入口”
次に試したのは、かなり地味な題材だ。
Vanilla JavaScript だけで動く、シンプルな Todo アプリ。
フレームワークなし、ビルドなし、外部ライブラリなし。
必要なのは、せいぜい次のような機能だ。
- Todo の追加・削除・編集
- 完了/未完了の切り替え
- All / Active / Completed のフィルタ
- 残り件数の表示
- localStorage による永続化
要するに、「よくある Todo アプリ」だが、実務でよく出てくる要素が一通り詰まっている題材でもある。
ここでは、“それっぽい”指示は一切やめて、機能要件を箇条書きで渡した。
デザインも凝らない。とにかく「動くものを、堅実に組み立てる」ことを優先する。
結果は、少し拍子抜けするくらい素直だった。
- 1発で動作する
- 追加・削除・編集・フィルタ、すべて問題なく機能する
- ページをリロードしても、ちゃんとデータは残る
- UIも必要最低限だが、破綻はない
- コード量はおよそ 360 行、トークン数は 2000 強程度
しかも、フレームワークに頼らず、純粋な Vanilla JS と DOM API だけで、だ。
これはもう、「デモ」ではなく、そのまま仕事の下書きに使えるレベルだと思った。
社内ツールや、ちょっとした管理画面のたたき台としてなら、十分すぎる。
重要なのは、ここで「魔法」は起きていない、という点だ。
- 設計は素直
- 状態は配列で管理
- 描画は render 関数に集約
- イベントは DOM に素直にバインド
- 永続化は localStorage に保存・復元
つまり、人間が書いても、だいたい同じ構成になるであろうコードが出てきている。
これこそが、ローカル30Bのいちばん美味しい使いどころだと思う。
派手なアルゴリズムをひねり出すわけでもないし、芸術的なコードが出てくるわけでもない。
その代わり、
「仕様を読んで、無難で保守しやすい実装を組む」
この作業を、かなり安定した品質で肩代わりしてくれる。
生成されたコードは、記事中にベタ貼りはしない。
代わりに、実際に動くものを iframe で埋め込み、apps.aries67.com から読み込む形にする予定だ。
読者は、コードを読む前に「まず触れる」。これは体験としても、説得力としても強い。
インベーダーやブロック崩しが「遊びのデモ」だとしたら、
この Todo は “実務の入口”をはっきり示す標本になった。
次は、もう少し地味だが、実際の現場では確実に効く話――
正規表現について触れてみたい。
第5章:正規表現は“うなずかされる”ユースケース
ゲームや Todo のような分かりやすい題材よりも、実際の現場で「助かった」と感じやすいのは、もっと地味なところだったりする。
その代表格が、正規表現だ。
正規表現は、だいたいこういう存在だ。
- 書いた本人ですら、数週間後には読めない
- 他人が書いたものは、ほぼ呪文
- ちょっと仕様が変わると、どこを直せばいいのか分からない
- それでも、ログ処理や入力チェックや置換処理で、避けて通れない
つまり、「動いている限りは触りたくないが、いざというときに一番困るコード」でもある。
ここでローカル30Bに投げてみるのは、たとえばこんな使い方だ。
- 「この正規表現は何をしているのか、日本語で説明して」
- 「この仕様を満たす正規表現を書いて」
- 「この正規表現、どんな入力で壊れる可能性がある?」
- 「もう少し読みやすく分解できない?」
派手な生成ではないし、スクリーンショット映えもしない。
でも、返ってくる答えには、思わず「それな」とうなずかされることが多い。
特に効くのは、「説明させる」用途だ。
ブラックボックス化した正規表現に対して、人間がレビューできる言葉に分解してくれるだけで、保守性は一気に上がる。
しかも、これがローカルで動いている、というのが大きい。
- 社内ログ
- 顧客データに絡むパターン
- 外に投げたくない仕様
こういうものを、そのままローカルに放り込んで「これ何してる?」と聞けるのは、精神的なハードルがかなり低い。
Todo のような“形になる成果物”も分かりやすいが、
正規表現のような「読む・直す・理解する」作業こそ、ローカルなコーディングAIの真価が出る領域だと感じた。
速さは、相変わらず最先端クラウドには及ばない。
それでも、
「この地味な作業を、毎回人間だけでやらなくていい」
と思えるだけで、十分に元は取れる。
派手なデモよりも、こういう“現場のストレスを減らす使い方”のほうが、
RTX3060クラスでローカル30Bを回す意味は、ずっと分かりやすい。
第6章:プロンプトとデモの見せ方について
生成画面は一度マウスクリックでフォーカスしないと動作しないので注意。
インベーダー(Simple 指定)
生成画面
URL: https://apps.aries67.com/qwen3/invaders.html
プロンプト
You are a senior game programmer.
Build a simple Space Invaders style game using ONLY:
One single HTML file
Vanilla JavaScript
Canvas 2D API No external libraries, no bundlers, no assets.
Hard requirements:
Output ONLY the complete HTML code (no explanations).
The HTML file must run when saved locally and opened in a browser.
Use requestAnimationFrame for the game loop.
Keyboard controls:
Left/Right arrows move the player
Space fires a shot
Enemies:
Spawn in a grid formation
Move horizontally together
When the formation hits a screen edge, it moves down and reverses direction
Shooting:
Player shots travel upward
Enemies shoot downward at a steady interval (random enemy each time is fine)
Collisions:
Player shot vs enemy removes enemy and increases score
Enemy shot vs player triggers Game Over
Enemy reaching the player area also triggers Game Over
UI:
Draw score on screen
Show “GAME OVER” overlay
Press R to restart
Code quality requirements:
Keep code readable and structured.
Use classes or clear object structures for Player, Enemy, Bullet, and Game.
Use constants for tunable values (speeds, cooldowns, sizes).
Add brief comments for important parts.
Make it minimal but correct. Prioritize a working playable result over fancy graphics or effects.
ブロック崩し
生成画面
URL: https://apps.aries67.com/qwen3/breakout.html
プロンプト
You are a senior game programmer.
Build a classic 1980s Breakout-style game in ONE single HTML file using only Vanilla JS + Canvas 2D.
No external libraries, assets, images, or audio.
Style: everything white on black. Rectangles + text only.
CRITICAL RELIABILITY RULES (do not violate):
The game loop MUST run continuously via requestAnimationFrame from initial load.
The game MUST draw something visible immediately on load (at least the paddle, bricks, and a “PRESS SPACE” text).
Keyboard input MUST be attached to window (not canvas) so it works without clicking/focus.
Space MUST start/launch the ball and also re-serve after losing a life.
Prevent default for Space and arrow keys to avoid browser scrolling.
Controls:
Left/Right arrows: move paddle
Space: launch / serve
R: restart
Gameplay:
Paddle bottom, bricks top, ball bounces.
Ball below bottom = lose life, reset ball-on-paddle (READY) until Space.
Lives start at 3.
Score + Lives displayed.
YOU WIN when all bricks cleared; GAME OVER when lives reach 0.
Show overlay text for READY / YOU WIN / GAME OVER.
Collision:
Simple AABB.
Paddle reflection angle depends on where it hits the paddle (edges change angle).
Basic separation so the ball never sticks inside bricks/paddle.
Code structure:
Keep it compact and readable.
Use Game, Paddle, Ball, Brick (or BrickField) objects/classes.
Use constants for sizes/speeds/rows/cols.
Add only brief comments for loop, input, collision, and state transitions.
Output:
Output ONLY the complete HTML code, nothing else.
Final self-test checklist BEFORE output:
On load, you can see bricks, paddle, and “PRESS SPACE”.
Without clicking anywhere, Left/Right moves the paddle.
Space launches the ball upward.
Ball falls below bottom -> life decreases -> ball resets on paddle -> Space serves again.
R restarts from scratch. If any item fails, fix it before output.
Vanilla JS Todo
データの保存先は あなたのブラウザの LocalStorage だから、気軽に触って大丈夫。
生成画面
URL: https://apps.aries67.com/qwen3/todo.html
プロンプト
You are a senior frontend engineer.
Build a production-quality Todo app using ONLY:
One single HTML file
Vanilla JavaScript (no frameworks)
Plain CSS
Standard DOM APIs No external libraries, no build tools, no images, no CDN.
GOAL:
A clean, reliable, offline-capable Todo app that demonstrates solid state management and DOM architecture.
FUNCTIONAL REQUIREMENTS:
Basic features:
Add a todo (text input + Enter or Add button)
Mark todo as completed (checkbox or click)
Delete a todo
Edit a todo (double-click or Edit button)
Filtering:
Show: All / Active / Completed
Persistence:
Save todos to localStorage
Restore state on page reload
Counters:
Show number of remaining (active) todos
Clear:
Button to clear all completed todos
UX / UI REQUIREMENTS:
Simple, clean layout
Keyboard friendly (Enter to add, Escape to cancel edit)
Visual distinction between completed and active todos
No animations required
Desktop-first is fine
ARCHITECTURE REQUIREMENTS:
Use a single source of truth for state (e.g., an array of todo objects)
Separate concerns:
State management
Rendering
Event handling
Do NOT directly manipulate DOM all over the place; use a clear render() function
Use unique IDs for todos
Avoid global variables except one main app object or module
CODE QUALITY:
Use clear function and variable names
Keep logic readable and maintainable
Add brief comments only where structure or intent is not obvious
No over-engineering (no classes unless they clearly help)
No unnecessary abstractions
INITIAL STATE:
On first load (no localStorage), start with an empty list
The UI must still render correctly with zero items
ERROR HANDLING:
Ignore empty or whitespace-only todos
Prevent duplicate empty entries
Do not crash if localStorage is corrupted (fallback to empty list)
OUTPUT RULES:
Output ONLY the complete HTML code
No explanations, no markdown, no commentary
FINAL SELF-CHECK BEFORE OUTPUT:
Add, edit, delete, complete all work
Filters (All / Active / Completed) work correctly
Reloading the page restores the todos
Clear completed works
No console errors in normal use If any check fails, fix it before output.
最終章:ローカルAIという選択肢
ここまで見てきた通り、Qwen3-Coder-30B-A3B-Instruct は、
RTX3060 クラスの環境でも「ちゃんと使える」コーディングAIだった。
- インベーダー
- ブロック崩し
- Vanilla JS の Todo アプリ
- 正規表現の生成と修正
どれも最先端のデモではない。
でも、実務と遊びの境界にある“ちょうどいい課題”に対して、きちんと形になる答えを返してくる。
10 tok という生成スピードは、クラウドAIの爆速体験と比べれば見劣りする。
けれど、仕様を渡して、少し待って、コードを受け取る。
このテンポは、実際の開発作業ではそれほど悪くない。むしろ「考える間」が挟まってちょうどいいくらいだ。
そして何より大きいのは、これがローカルで完結しているという事実。
- ソースコードは外に出ない
- 仕様書もログも外に送られない
- 社内ツール、検証コード、実験コードを気兼ねなく投げられる
いわゆる「秘密が漏れない」というやつだ。
これはセキュリティの話であると同時に、気楽さの話でもある。
クラウドAIに投げる前に一瞬よぎる、
「これ投げて大丈夫かな?」
あのブレーキが、ローカルAIには存在しない。
今回のデモは、派手なベンチマークでも、流行りのフレームワーク比較でもない。
でも、
- 昭和インベーダーが動いた
- ブロック崩しが動いた
- Todo アプリが一発で組めた
その事実だけで、
「このクラスのモデルが、手元のGPUで“普通に使える時代”に来ている」
ということは十分伝わるはずだ。
ローカルAIは、まだ万能ではない。
でも、日常のコーディングの相棒としては、もう実用ラインを越えている。
クラウドと併用するもよし。
まずはローカルで投げてみるもよし。
少なくとも、「試す価値がある段階」は、もうとっくに過ぎている。

