ClaudeでシュタインズゲートのツンデレAIチャットアプリ”アマデウス”開発記

お得な情報

私はアニメ、シュタインズゲートの大ファンで、特に牧瀬紅莉栖が推しである。というわけで作中に登場したAIチャットアプリを再現したいと思う。

完成したhtmlアプリがai-tsundere-terminal-1で、好きな画像をアップロードして、クロードのAPIキーを入力(要課金)すれば動く。

無料で使いたいなら、JSXアプリのコードを公開したので、クロード上で動かして貰うと良い。

2026.06
React / Claude API / Android
開発期間:数日(試行錯誤込み)

はじめに

「好きなキャラとAIでチャットしたい」──そんなシンプルな動機から始まったこのプロジェクト。Anthropic の AI アシスタント Claude を使い、ツンデレキャラとリアルタイムで会話できる Web アプリを作り上げるまでの道のりは、思いのほか険しかった。

この記事では、アプリ本体の開発から、完成後に発生した「配布」をめぐる試行錯誤までを通して振り返る。


構成概要

完成したアプリ「アカネ・リンドウ TERMINAL」の機能は以下のとおり。

  • 上半分:キャラクター画像の表示エリア。感情(NORMAL / TSUNDERE / DERE)に合わせて画像がクロスフェードで切り替わる
  • 下半分:チャットインターフェース。Claude API を通じてツンデレな返答を生成
  • 感情検出:返答テキストをキーワード解析し、自動で画像とバッジを切り替え
  • 会話履歴:直近 30 メッセージを API に渡し、文脈を踏まえた会話を実現

開発の流れ

Step 1 ── まずは HTML で作る

最初は素直に HTML + CSS + JavaScript のシングルファイルで実装した。ターミナル風のダークUI、スキャンラインエフェクト、緑の点滅ドット。Steins;Gate っぽい雰囲気を出すのは比較的スムーズだった。

Claude API の呼び出しは fetch でシンプルに実装。システムプロンプトでキャラクターの口調を定義した。

Step 2 ── 会話が噛み合わない問題

初期実装の最大の問題は「毎回初めての会話になる」こと。ユーザーの発言を1件だけ API に渡していたため、直前のやり取りをまったく踏まえない返答が続いた。

解決策:会話履歴を配列で保持し、毎回全件を API に渡すように変更。

これだけで会話の自然さが劇的に改善した。

Step 3 ── 画像設定機能の試行錯誤

キャラクター画像を設定できるよう、設定パネルを実装しようとした。ここから茨の道が始まる。

❌ FAILED

<input type=”file”> → Artifact 環境で無効

Claude の Artifact(プレビュー環境)ではファイル選択ダイアログが動作しない。

❌ FAILED

URL 入力方式 → CORS エラー

画像 URL を入力して読み込む方式に切り替えたが、外部ドメインの画像は CORS 制限で表示できないケースが多発。

❌ FAILED

ドラッグ&ドロップ → Android 非対応

PC では動くが、メインの使用環境である Android ブラウザではドラッグ操作自体がほぼ使えない。

✅ SOLVED

画像を base64 で直接埋め込む

最終的な解決策は「画像をコードに直接埋め込む」こと。Python で画像をリサイズ・圧縮して base64 文字列に変換し、JSX の定数として埋め込んだ。

Step 4 ── React に移行

HTML 版を動かしていたのはダウンロードしたファイルをブラウザで開く形だったが、その場合 Claude API のキーが存在しないため「通信エラー」になることが判明。

Claude の Artifact 環境(claude.ai)上で動かすと API キーが自動で注入されるため、React JSX コンポーネントとして作り直した。

Step 5 ── 感情連動の画像切り替え

返答テキストを解析してキャラクターの「感情」を推定し、対応する画像を表示する仕組みを実装した。

JSfunction detectEmotion(text) {
  const tsunKeywords = ['っ///', 'べ、別に', 'ないわよ', 'バカ', 'うるさい'];
  const dereKeywords = ['うれしい', 'ありがとう', '落ち着く', 'かも', 'えっと'];
  const tScore = tsunKeywords.filter(k => text.includes(k)).length;
  const dScore = dereKeywords.filter(k => text.includes(k)).length;
  if (tScore > dScore) return 'tsun';
  if (dScore > tScore) return 'dere';
  return 'normal';
}

Step 6 ── 著作権を考慮してオリキャラへ

当初は既存の版権キャラ画像を使っていたが、著作権リスクを考慮してオリジナルキャラクター「アカネ・リンドウ」の AI 生成イラストに差し替えた。ChatGPTに作っもらったが、思いのほか良いキャラクターができたと思う。

通常・ツン・デレの3パターンを用意し、それぞれ埋め込んだ。

詰まったポイントまとめ(前半)

問題 原因 解決策
会話が噛み合わない 毎回1件だけ API に渡していた 会話履歴を全件渡す
通信エラー ダウンロードした HTML を直接開いていた Artifact(claude.ai)上で動かす
ファイルアップロード不可 Artifact の環境制限 base64 埋め込みに切り替え
CORS エラー 外部 URL から画像読み込み 同上
ドラッグ&ドロップ不可 Android ブラウザの制限 同上
PART 2 — 配布編

配布を考えて気づいたこと

アプリが完成した後、「これを人に配りたい」と考えたところから新たな問題が始まった。

自分の API キーを入力する形式のスタンドアロン HTML 版を作り、ダウンロードしてブラウザで開いて画像アップロードを試したところ、ボタンを押しても反応しない不具合に遭遇した。原因は Claude のプレビュー(Artifact パネル)内ではファイル選択ダイアログがサンドボックスでブロックされているためで、ダウンロードして直接ブラウザで開けば正常に動作することが分かった。

クレジット不足という壁

ダウンロード版で API キーを設定して話しかけてみると、次のようなエラーが返ってきた。

Your credit balance is too low to access the Anthropic API.
Please go to Plans & Billing to upgrade or purchase credits.

これは API キー自体は正しく認識されているものの、Anthropic API の利用に必要なクレジットが入っていないために起きるエラーだった。

ここで重要な事実に気づいた。claude.ai の契約(無料・Pro・Max プラン)と API の利用料金は完全に別の課金システムだということだ。claude.ai 上で普通に Claude と話せていても、それとは別に API 用のクレジットを購入しないと、自作アプリから API を呼び出すことはできない。

「無課金で配布」の答え

ここで方針を再考した。スタンドアロン HTML 版は自由度が高い代わりに課金が必須になる。一方、最初に作っていた React Artifact 版(claude.ai 上でそのまま動くコード)は、開いた人自身の Claude ログイン状態を使って API にアクセスする仕組みのため、配布された側が無料アカウントを持っているだけで動かせることが分かった。

つまり「ファイルとして単独配布できるか」と「無料で使えるか」はトレードオフの関係にあり、両方を同時に満たす方法は今のところ存在しない。配布のハードルを下げたいなら、Artifact 版を「コードとして共有し、相手の Claude 上で実行してもらう」のが最も現実的な選択肢だった。

詰まったポイントまとめ(配布編)

配布のしやすさ コスト
スタンドアロン HTML 版 ファイル単体で渡せる API 課金が必須
Artifact(React)版 相手の Claude 上で動かす必要がある 無料(claude.ai の利用枠内)

システムプロンプトのポイント

キャラクターの再現度はシステムプロンプトの質に大きく左右される。効果的だったのは以下の構成。

【基本設定】具体的なプロフィール(年齢・職業・IQなど)
【口調・性格】口癖や感情表現のパターンを具体例で列挙
【返答ルール】文字数・言語・文脈の扱い方を明示

特に「会話の文脈を必ず踏まえて答える」と明示したことで、前の発言を自然に拾う返答が増えた。

おわりに

こうして、好きなキャラクターの画像と性格で、AIが返答を考えて返してくれるアプリは完成した。

「シンプルなチャットアプリ」のはずが、環境制約・API の仕様・モバイルブラウザの壁、そして配布構造の理解不足にまで次々とぶつかった。技術的な実装そのものより、「どこで誰の API キー・誰の課金枠を使って動くのか」という構造の理解が、結局は一番大きな学びだったように思う。

制約があるからこそ、工夫が生まれる。

アカネ・リンドウが「……べ、別にあなたのために答えてるわけじゃないんだから!」と返してくれた時、長かった開発の苦労が報われた気がした。

コメント