2026/06 - 現在

X連動型AIゲーム(個人)

TypeScript React SQLite Drizzle Tailwind Railway

近畿の「ポップな妖怪」を毎日繰り出して合戦し、X のいいね=育成・リプライ=投票として観客の介入をゲームに取り込む。

Xアカウント: https://x.com/ayakashi_kassen

観戦 Web UI: https://ayakashi-kassen.up.railway.app

概要

  • 妖怪は 卵 → 孵化 の流れで X に登場。卵への返信で「どの職に孵るか」を投票でき、誕生投稿への1いいねでランダムなステが1%開眼(複利・上限なし)
  • 1日 8 取組のチーム戦(最大3vs3・ターン制オートバトル)を日次バッチで先計算 + 実況を1プロンプトで一括生成し、約3時間おきに1番ずつ X へ公開して勢力ゲージを動かす
  • シーズン(場所)制で星取表を積み上げ、引退した妖怪はヤジ・語り部として実況に残る
  • X 連携は集計締切方式(リプライ/いいねは締切時に1回だけ取得して食わせる)で pay-per-use 課金を抑える

設計のポイント

  • イベントソーシング + ステップ粒度の進行 — 1 ステップ = 1 トランザクションで events と投影を同時コミット。events だけから投影と進行カーソルを decisive に replay できるので、任意の tick へロールバック可能
  • LLM 障害時はフォールバックで完走させない — UsageLimit に当たった tick は最終スナップショットへ巻き戻し、「偽の1日」を永続化しない
  • リプライは untrusted input 前提 — X 経由の文字列を prompt injection の媒介として扱い、スキーマ強制 + 検証で job 投票だけを抽出
  • 揺らぎは汎用ローテ基盤に集約 — ハッシュタグ揺らぎ・口上の署名区切りなどを pickRotation(state.rotationCursors, key, pool) で名前空間ごとに管理し、RotationApplied を投影して replay 可能に。場当たり乱数で切り替えるコードを増やさない
  • watch-only の公開設計 — 状態を変える HTTP エンドポイントは存在しない。進行は自走ワーカーだけが行う

Xのシャドウバン

別アカウントからの検索でヒットしない、いわゆる「シャドウバン」が発生した。ハッシュタグを除いたり、投稿日時を動的にずらすなどの工夫をしたが、改善せず。アカウント若さのペナルティが入っている可能性があるため、一旦様子見でPendingとしている。

規模感

  • 期間: 2026/06/07 〜 公開運用中(同月内に X 公開まで到達)
  • コミット: 250+
  • TypeScript / TSX: 180ファイル・約30,000行
  • 1人開発(世界設計・実装・キャラ絵生成・X 連携・運用すべて)