この記事で分かること
何を学べるか
- アクセシビリティ対応は「視覚障害者だけ」ではなく「全員が使える」設計
- 24種類のペルソナ(障害者を中核に、多様な背景を持つユーザー)で品質を検証
- 実際のユーザーの声を集める仕組みが改善の鍵
💡 GitHub Copilotユーザー必見
- AIを使ってアクセシビリティ対応コードを効率的に生成する方法
- テストコードの自動生成で品質向上
- 第8章で具体的な活用戦略を解説
🔧 技術仕様(コード例あり)
- Puppeteerで複数ペルソナの自動テスト実装(790テスト)
- Vanilla JS選択でフレームワーク依存なし
- Laravel 12 + PHP 8.3バックエンド
はじめに
前回の記事「視覚障害者もプレイできる!完全アクセシブルなWebゲームをLaravel+Livewireで作った話」では、火星移住計画シミュレータをLaravel+Livewireで実装し、スクリーンリーダー対応やキーボード操作のみでのプレイを可能にしました。
しかし前回は、主に視覚障害者に焦点を当てた実装でした。
その後、将棋ゲーム(a11y-shogi) の開発を通じて、重要な気づきを得ました:
「チャット指示」だけでは、複数の背景を持つユーザー全ての要件を満たせない
実装後に「複数のユーザーパターン」で実際に検証するしかありません。
だからこそ「AIペルソナ + Puppeteer(パペティア)による自動検証」が不可欠です。
24種類のペルソナを用いて790個のテストを自動化することで、
視覚障害、運動障害、発達特性、加齢、初心者...という
複数の背景を持つユーザー全てが「共存」できる設計を実現できました。
今回は、複数の背景を持つ24種類のペルソナを用いて、多様なニーズを同時に検証する方法、
そしてPuppeteer(パペティア)との組み合わせで「複数のユーザーパターン」を自動テスト化する戦略を紹介します。
24種類のペルソナで複数の背景に対応
- 言語: PHP(Laravel 12)+ Vanilla JavaScript
-
テスト: 790個(PHP 140 + a11y 227 + AI 364 + E2E 59)
- アクセシビリティテスト(8種227個):視覚障害・運動障害・環境対応
- AIペルソナテスト(10種364個):障害者・年齢層・環境・専門家など多様なペルソナ
- E2E統合テスト(59個)
-
AI Personas: 24種類(複数の視点から検証)
-
障害者ユーザーペルソナ(17種類)
- 視覚障害:全盲ユーザー、弱視ユーザー、全盲初心者、弱視初心者、色覚異常ユーザー、重度弱視ユーザー
- 運動障害:上肢障害者、脳性麻痺、片麻痺
- 聴覚障害:聴覚障害者
- 発達特性・学習障害:発達特性/学習障害、ADHD、ディスレクシア、自閉スペクトラム
- その他:知的障害、てんかん、加齢による見えにくさ
-
AIペルソナ(7種類)
- 棋士AI、WebデザイナーAI、UXリサーチャーAI、教育者AI、加齢AIペルソナ、子供・初心者AI、モバイルユーザーAI
-
障害者ユーザーペルソナ(17種類)
- ステータス: 完全アクセシブル対応・全テスト合格(790/790)
第1章:なぜVanilla JS選んだのか——設計段階での判断
設計初期の決定:フレームワークの選択肢
アクセシビリティ重視のプロジェクトを始める際、フロントエンド技術の選択は本質的に重要です。
選択肢1: React + TypeScript
メリット:コンポーネント再利用性、大規模開発向け
デメリット:バンドルサイズ大(90KB+)、セットアップ複雑
選択肢2: Laravel + Livewire
メリット:PHP開発者にとって自然、サーバー側の状態管理
デメリット:複雑な状態管理時のジッター、ネットワーク遅延が目立つ
選択肢3: Vanilla JS
メリット:バンドルサイズ0KB、直接的な制御、簡潔なコード
デメリット:全て自分で実装、フレームワークの恩恵なし
将棋ゲームで明らかになった要件
実装を始めて初めて、開発効率だけでは対応できない課題が浮かり上がりました:
1️⃣ リアルタイムな駒の描画・再配置
問題:Livewireはイベント発火ごとにサーバー往復が発生するため、細かなインタラクションが多いUIでは、モバイルで遅延が目立ちやすくなります。特に、タッチ操作の連続入力では体験が崩れやすい。
2️⃣ 複雑な状態管理
将棋の盤面状態:
{
board: [ 9×9マス × 駒種(先手/後手/空き) ],
legalMoves: Set<Move>, // 次に可能な手(平均80手前後)
selectedPiece: {rank, file}, // 選択中の駒
capturedPieces: { sente: [], gote: [] },
gameState: 'playing' | 'finished',
moveHistory: [ {from, to, promotion}, ... ]
}
Livewireでこの複雑な状態をサーバー-クライアント間で同期するのは、本質的に困難です。
3️⃣ アクセシビリティ検証との相性
問題:Livewireでは、サーバー-クライアント間の往復通信により、ゲーム状態が分散します。つまり、盤面の状態、選択中の駒、合法手などの情報が、サーバーとクライアント両側に存在する可能性があります。
結果:実装後にアクセシビリティを検証する際、「現在のゲーム状態が何か」を確実に把握するのが困難になります。スクリーンリーダーに正しい情報を読み上げさせるにも、盤面表示を正しく操作できるようにするにも、状態の一貫性が必須です。
Vanilla JSへの転換:得たもの
メリット1: ゲーム状態が完全にクライアント側にある
// 状態確認が即座
const gameState = await page.evaluate(() => window.gameData.boardState);
const board = gameState.board;
console.log(board); // 9×9の盤面状態
// Puppeteerテストも思いのまま
const pieces = await page.evaluate(() => {
const board = window.gameData.boardState.board;
const sentes = [];
for (let r = 1; r <= 9; r++) {
for (let f = 1; f <= 9; f++) {
if (board[r]?.[f]?.color === 'sente') {
sentes.push({type: board[r][f].type, pos: `${f}${r}`});
}
}
}
return sentes;
});
メリット2: アクセシビリティ検証の基盤が整う
// ゲーム状態を直接検査できるので、
// 開発段階での検証が容易
const gameStatus = await page.evaluate(() => {
return {
status: window.gameData.status,
currentPlayer: window.gameData.currentPlayer,
boardState: window.gameData.boardState
};
});
console.log(gameStatus); // { status: 'in_progress', currentPlayer: 'human', ... }
// 盤面情報をすべて取得できる
const allPieces = await page.evaluate(() => {
const board = window.gameData.boardState.board;
const pieces = [];
for (let r = 1; r <= 9; r++) {
for (let f = 1; f <= 9; f++) {
if (board[r]?.[f]) {
pieces.push({
type: board[r][f].type,
color: board[r][f].color,
position: `${f}${r}`
});
}
}
}
return pieces;
});
console.log(allPieces); // [{type: 'fu', color: 'sente', position: '1-3'}, ...]
この「ローカルな検証可能性」は、後にPuppeteerを用いた
複数パターンのテスト自動化に直結します。
メリット3: バンドルサイズが最小限
- jQuery: 87KB
- Livewire: 133KB
- Vanilla JS(UIフレームワークなし): 0KB
結論:2024年のVanilla JSは「選択肢」ではなく「標準」
2024年のブラウザ環境には、
fetch, async/await, DOM API の充実、
Web Components など...
フレームワークなしで「読みやすく保守しやすい」コードを書けます。
ただしサーバー連携(複雑なフォーム、リアルタイム通知)が必要なら
React/Vue + Server-Sent Events がベター。
ターンベース + 複雑な状態を持つゲームで、
特にローカルな状態管理が不可欠なら
Vanilla JSが最適解です。
第2章:「初心者向けUI設計」——プレイしながらルールを学べる設計
課題:「将棋のルール理解」と「アクセシブル操作」の両立
アクセシビリティ対応で見落とされやすい課題があります:
「盤面操作のキーボード対応」と「初心者向けルール説明」は別問題
視覚障害者向けに「Enterキーで駒を選択」「矢印キーで移動」と実装しても、
初心者ユーザーが将棋のルール自体を知らなければ、そもそもゲームができません。
また、逆に将棋のルールを詳しく説明するヘルプページを用意しても、「キーボードでどう操作するか」が直感的でなければ、アクセシビリティは実現できません。
さらに重要なのは、長いマニュアルを読むのは誰にとっても負担だということです。
解決策:「実際にプレイしながら学べる」設計
将棋ゲーム(a11y-shogi)では、以下の3つのアプローチを組み合わせました:
A. ゲーム中に「操作方法とルール」を同時に習得できる仕組み(核心)
B. いつでも参照できる「ショートカット一覧」(補助)
C. より深く学びたい人向けの「簡易版ルール説明」(任意)
これにより、事前知識ゼロの完全初心者でも、ヘルプページを読まずに、
実際にプレイしながら、UI操作とゲームルールの両方を同時に習得できる設計を実現しました。
1️⃣ ゲーム画面内に「ショートカットモーダル」を組み込み
ユーザーが H キー を押すと、常に以下の情報が利用可能:
- 矢印 / WASD → 盤面上のカーソル移動
- Enter / Space → 駒を選択・移動決定
- B → 盤面全体を読み上げ(スクリーンリーダー対応)
- Shift+B → 差分読み上げ(前回からの変化のみ)
- S → ゲーム状態を読み上げ(手番・進行状況)
- K → 棋譜(手順)を読み上げ
- 1 / 2 → 先手 / 後手の駒台へ移動
- I → 相手の利き筋を読み上げ
- U → 待ったする
- R → リセット
重要なのは、このショートカット一覧が「ゲーム中に常にアクセス可能」なこと。
ヘルプページを別で読む必要がなく、リアルタイムに確認できます。
2️⃣【任意】ヘルプページで「より深く理解」(補助資料)
ヘルプページは必須ではありません。しかし、「より深く理解したい人」や「事前にルールを確認したい人」のために、補助資料として用意されています:
将棋のルール(簡易版)
先手と後手
先手(下側)が最初に指し、後手(上側)がその後に指します。
目的
相手の王(玉)を逃げられない状態にすること(詰み)が目的です。
駒の種類と動き
- 歩(ふ):前に1マスのみ進む
- 香(きょう):前方へまっすぐ何マスでも進む
- 桂(けい):前方へ2マス・横に1マス跳ぶ(唯一飛び越せる駒)
- 銀(ぎん):前方3方向と斜め後ろ2方向に1マス
- 金(きん):前後左右と斜め前2方向に1マス
- 角(かく):斜め4方向に何マスでも進む
- 飛(ひ):前後左右に何マスでも進む
- 玉/王(ぎょく/おう):全方向に1マス(これを守るのが目的)
成り(駒のパワーアップ)
自分の駒が相手の陣地(敵陣 = 相手側の3段)に入る・出る・中で動くとき、駒を裏返してパワーアップできます。
持ち駒を打つ
相手の駒を取ると「持ち駒」として駒台に並びます。盤面の空いているマスに置く(打つ)ことができます。
王手と詰み
相手の王を次に取れる状態を「王手」といいます。どうやっても王手を防げない状態が「詰み」で、詰まされた側の負けです。
この「簡易版」で理解できるのは、3つの基本概念:
- 将棋の目的は「王を詰ます」こと(ゲーム終了時にも理解できる)
- 駒にはそれぞれ動きがある(合法手ハイライトで学べる)
- 取った駒は「持ち駒」として再利用できる(駒台UIで体験できる)
ただし重要:これらは全て「プレイしながら自然に学べる」ため、ヘルプページを読まなくてもゲームは楽しめます。
3️⃣「プレイしながら具体的なルールを覚える」設計
ユーザーが「説明を読まずに実際に操作する」だけで、次々とUI操作と将棋ルールの両方を自然に学べる設計を実現しました。
重要な設計思想:ヘルプページ不要で学べる
この設計の革新的な点は、ヘルプページを一切読まずに、完全にプレイしながら全てを学べることです:
ゲームをプレイしながら「ゼロから」学べる内容:
- ✅ UI操作方法(矢印キー移動、Enter選択)
- ✅ 各駒の具体的な動き方(合法手ハイライトで視覚化)
- ✅ 成りの仕組み(成りダイアログで「成りますか?」と尋ねられる)
- ✅ 持ち駒を打つ方法(駒台UIで体験)
- ✅ ルール違反の内容(「そこには動かせません」等のエラーメッセージ)
- ✅ ゲームの目的(詰まされて終了 → 「王を守る」ことを理解)
- ✅ 交互に指すルール(AIの手番 → 自分の手番の繰り返し)
ヘルプページの位置づけ:
- 「より深く理解したい人」向けの補助資料
- 「事前学習」ではなく「確認・復習」用
- プレイ中に疑問が生じたときの参照先
つまり、完全初心者が何の予備知識もなくゲームを開始しても、試行錯誤しながら自然に将棋のルールを習得できる設計になっています。
以下は、初心者ペルソナがゲームを通じて自然に学習していく過程をシミュレートしたテストコードです:
// AIペルソナのテスト: 「完全初心者」ケース
// = 将棋のルールを一切知らない状態でゲームを開始
// ヘルプページも読まずにプレイ開始
// 1. ユーザーがゲームを開始
const BASE_URL = 'http://localhost:8000'; // ローカル環境
await page.goto(BASE_URL);
// 2. Hキーで「ショートカット」一覧を表示できる
// (必要なときに参照できる設計)
await page.keyboard.press('h');
const shortcutsVisible = await page.evaluate(() => {
return document.querySelector('#shortcuts-modal') !== null;
});
console.assert(shortcutsVisible, 'ショートカットモーダルが表示される');
// 3. ユーザーが「矢印キー」を試す
await page.keyboard.press('ArrowDown');
await page.keyboard.press('ArrowLeft');
// 4. 盤面内に移動できたことが「視覚的に」確認できる
const selectedCell = await page.evaluate(() => {
return document.querySelector('[data-selected="true"]') !== null;
});
console.assert(selectedCell, 'セルが選択状態になる');
// 5. ユーザーが「Enter」を押す
await page.keyboard.press('Enter');
// 6. スクリーンリーダーで「駒を選択してください」と読み上げられる
const liveRegionText = await page.evaluate(() => {
return document.querySelector('[aria-live="polite"]')?.textContent || '';
});
console.assert(liveRegionText.includes('駒'), 'スクリーンリーダーで駒選択を促す');
// 7. 駒を選択後、「矢印キー」で移動先を探す
// → 「合法手」が緑ドットで表示される(視覚)
// → ユーザーは「あ、この駒はここに動けるんだ」と理解
// → スクリーンリーダーで「移動可能」と読み上げられる(音声)
//
// ★ 重要:視覚障害者も各マスを矢印キーで移動しながら確認することで、
// その駒が「どこまで移動できるか」を完全に把握できる
// 例:歩を選択した場合、前のマスだけが「移動可能」と読み上げられ、
// 他のマスは「移動不可」と読み上げられるため、
// 歩は前に1マスしか動けないことを理解できる
// 8.「Enter」で確定
// → 駒が移動して、盤面が更新される
// → 敵陣に入った場合、「成りますか?」ダイアログが表示
// → ユーザーは「駒が強くなれるのか」と初めて知る
// → 「手番が交代」を示す通知が表示
// 9. AIが指す → また自分の番
// → 「交互に指すゲームなんだ」と理解
// 10. 最終的に詰まされる → ゲーム終了
// → 「王を守るゲームだったのか」と目的を理解
// → つまり、**何の予備知識もなく**ゲームを開始しても、
// 「UI操作方法」「駒の動き」「成りのルール」「ゲームの目的」を
// 実際にプレイしながら自然に習得できる設計
//
// これが真の「Learning by playing(遊びながら学ぶ)」のアクセシブルゲームデザイン
4️⃣ AIペルソナの「完全初心者」検証テスト
📊 AIペルソナ「完全初心者ユーザー」のテストシナリオ:
(将棋のルールを一切知らず、ヘルプページも読まない状態)
1️⃣ ゲーム開始直後
- 矢印キーを押してみる → カーソルが動くことを発見
- Enterを押してみる → 何かが選択されることを理解
- 合法手ハイライトで「動ける場所」が視覚的にわかるか
2️⃣ 第1手を指す
- 緑ドットの意味が直感的に理解できるか
- 「この駒はこう動く」と視覚的に学べるか
- 試行錯誤しながら操作方法を習得できるか
★ 視覚障害者の場合:
- 駒を選択した後、矢印キーで各マスを移動
- 各マスで「ここに移動可能」「ここは移動不可」と読み上げられる
- この確認プロセスにより「その駒がどこまで動けるか」を完全に把握
3️⃣ 駒を動かす
- 成りダイアログで「駒が強くなれる」と理解できるか
- 「成る/成らない」の選択肢が明確か
- 持ち駒の概念を自然に理解できるか
4️⃣ 相手(AI)の着手を見る
- AIの動きから「交互に指す」ルールを理解できるか
- AIの駒の動きから将棋のパターンを学べるか
5️⃣ ゲーム終了
- 詰まされて初めて「王を守るゲームだった」と理解できるか
- もう一度プレイしたくなるか
🎯 成功基準
何の予備知識もない完全初心者が、ヘルプページを読まずにゲームを開始しても、「試行錯誤」しながら次々とUI操作・駒の動き・成りのルール・ゲームの目的を自然に習得できること。
✅ 実現できている学習体験:
- UI操作(キーボード操作)← 試して覚える
- 駒の動き(合法手ハイライト)← 視覚で見て覚える、または音声で「移動可能/不可」を確認して覚える
- 成りの仕組み(成りダイアログ)← 尋ねられて覚える
- ゲームの目的(詰み)← 終了時に理解
- 全て「ヘルプページなし」で習得可能
★ 特に視覚障害者にとって重要:
駒を選択した後、矢印キーで盤面を移動して各マスの「移動可能/不可」を確認することで、
その駒の具体的な動きパターンを段階的に学習できる
本質的な設計原則
「チュートリアル画面」も「ヘルプページ」も不要。「ゲーム自体」が完全なチュートリアルになっている設計
- 盤面移動 → 矢印キーを試す → カーソルが動く → 「操作方法」を体験で覚える
- 駒選択 → その駒が動ける場所を視覚化・音声化 → 「駒の動き」を見て/確認して覚える
- 視覚:緑ドットで移動可能な場所が一望できる
- 音声:各マスを矢印キーで移動しながら「移動可能/不可」を確認
- 成り → 成りダイアログで「成りますか?」と尋ねる → 「成りのルール」を尋ねられて覚える
- AI の着手 → ★マークと音声通知 → 「交互に指す」ことを体験で覚える
- ゲーム終了 → 詰み通知 → 「ゲームの目的」を結果から理解
- ショートカット → H キーでいつでもアクセスできる(必要なら)
- エラーメッセージ → 「そこには動かせません」で制約を理解
このアプローチにより、何の予備知識もない完全初心者が、ヘルプページを一切読まずにゲームを開始しても、実際にゲーム内で「やりながら全てを覚える」という
複数の背景を持つユーザー全てに対応した学習体験が実現されます。
つまり:
- 事前知識ゼロでゲームを開始できる
- ヘルプページ不要で全てのルールを習得できる
- 操作方法とゲームルールの両方を同時に学べる設計
- ヘルプページは「より深く知りたい人向けの補助資料」として機能
典型的な「Learning by playing(遊びながら学ぶ)」のゲームデザインを、アクセシビリティ対応したものです。
これこそが、複数の背景を持つ全てのユーザーにとっての「真のアクセシビリティ」:
- 視覚障害者:駒選択後に矢印キーで盤面を移動 → 「移動可能/不可」の読み上げで駒の動きを完全把握 + 音声読み上げ
- 運動障害者:キーボードのみで完結
- 発達特性:シンプルで予測可能なフィードバック
- 加齢:大きな文字・明確な視覚的フィードバック
- 初心者:マニュアル不要・試行錯誤で学べる
第3章:「チャットで指示し切れない」アクセシビリティ検証の限界
理想と現実のギャップ
アクセシビリティ開発を始める際、多くの開発者はチャットAI(GitHub Copilot等)に指示をするアプローチを取ります:
プロンプト例:
「全画面をキーボード操作可能にしてください。
特に小さい画面やレスポンシブ表示で、複数の駒を取った場合の持ち駒表示が
正しく働くか確認してください。」
結果:
チャットAIは、HTMLセマンティクスのチェックリストを提案してくれます。
でも、それは「機械的な検証」に過ぎません。
実際には、複数のユーザー層の要件が競合します:
視覚障害者
- スクリーンリーダーが「駒の位置」を正確に読み上げるか?
- 駒を複数回取った時、ARIA live regionで即アナウンスされるか?
運動障害者(マウス不可)
- キーボードだけで全操作ができるか?
- Tabキーの順序は論理的か?
発達特性(ADHD/ASD)
- 画面内の情報量や動きが多すぎないか?
- UIルール説明は過度に複雑か?
加齢による見えにくさのある人
- テキストが18px以上で読みやすいか?
- ボタンが44px以上で操作しやすいか?
- 色だけに頼った情報表現ないか?
初心者
- 将棋ルール未習者向けの説明が十分か?
- UIフローは直感的か?
こうした要件は「チェックリスト」では表現できず、
実装後に「複数のユーザーパターン」で検証するしかありません。
なぜ単一のテストだけで不十分なのか
// ❌ 単一のメトリクスだけでは「アクセシビリティ」を保証できない
test('駒台のボタンの最小サイズが44px', () => {
const button = document.querySelector('.hand-piece');
// ✅ これは合格
// でも...
// - 加齢による見えにくさのある人には「押しやすい」か?
// - ADHD ユーザーには「ボタンが多すぎて混乱」しないか?
});
// ❌ WCAG チェックリストに合格しても、実体験は失敗する(架空の例)
test('色コントラスト比が4.5:1以上', () => {
// WCAG AA基準(4.5:1)は合格
// でも、AAA基準(7:1)ではないため
// → 重度弱視ユーザーには「判読困難」
// → ユーザー体験は「破綻」
});
そこで本プロジェクトでは、Puppeteerを用いて「複数のユーザーパターン」を自動的に検証する仕組みを構築しました。
第4章:Puppeteerで「AIペルソナ」を実装——体験談から改善点を発見
なぜ複数のペルソナが必要なのか
「アクセシビリティに対応した」と言えるアプリは何か?
✅ スクリーンリーダー対応 → 視覚障害者には使える
✅ キーボード操作対応 → 運動障害者には使える
✅ シンプルな UI → 発達特性のあるユーザーには使える
✅ 大きいテキスト対応 → 加齢による見えにくさのある人には使える
✅ 迷いにくい導線 → 初心者には使える
しかし、複数の要件を同時に満たすのは困難です:
例:「スクリーンリーダー + 高いコントラスト + 大きいテキスト + キーボード操作」
が同時に機能するゲームを、チェックリストだけで設計できるか?
→ NO。実装→検証→改善を「複数のユーザーパターン」で繰り返すしかない
「体験談」でリアルな改善点を発見
単なる自動テストではなく、AIペルソナに実際にプレイさせて、体験談を語ってもらうアプローチです。
全盲ユーザーAIの体験談
Puppeteerでスクリーンリーダー対応をテストした全盲ユーザーAIに、体験を語ってもらいました:
初めてこのゲームをプレイした時、正直驚きました。
多くのWebゲームは『見えること前提』で作られていて、スクリーンリーダーでは何が起きているのか全く分かりません。でも、このゲームは違いました!
✨ 良かった点:
-
盤面の各マスに詳細な説明 — 「5の3のマス、先手の歩がいます」と読み上げられるので、盤面の状況が手に取るように分かります。
-
駒を選んだ瞬間、音声で通知 — 「先手の歩を選択しました」と即座にフィードバックがあるので、今何を操作しているか迷いません。
-
移動先を矢印キーで確認できる — 各マスに移動して「ここに移動可能」「移動不可」と確認できるので、その駒が『どう動くか』を視覚なしで完全に理解できます。これは素晴らしい!
-
手番交代を音声で教えてくれる — 「AIの手番です」と分かるので、待つべき時が明確。
😅 改善してほしい点:
-
持ち駒を打つ操作が少し分かりにくい — 駒台に移動した時、「ここは駒台です。持ち駒を選べます」という説明があると、初めてでも理解しやすいと思います。
-
AIが何を指したか、詳細に知りたい — 「AIが5の4の歩を6の4に移動しました」のような詳細な読み上げがあると、戦況を把握しやすいです。
-
詰みの状況をもっと明確に — 「王手です」「詰みです」という通知は欲しいです。
でも総合的には、目が見えなくても本当に楽しめるゲームでした!
運動障害者AIの体験談
次に、マウスが使えない運動障害者AIにプレイさせました:
私は脳性麻痺で、マウスを正確にクリックすることができません。普段は『キーボードのみ』でパソコンを使っています。
このゲームを初めて見た時、『将棋は無理だろうな...』と思いました。盤面が複雑で、マウスクリック前提に見えたからです。
でも、実際にプレイしてみたら...
✨ 素晴らしかった点:
-
矢印キーで盤面を自由に移動できる — WASDキーにも対応していて、右手だけでも操作できます。これは本当に助かります!
-
Enterキーだけで駒を選択・移動できる — 複雑なキーボードショートカットではなく、『矢印で選ぶ → Enter』のシンプルな操作。
-
フォーカスリングがはっきり見える — 今どこを選んでいるか、視覚的に明確。細かい操作が苦手な私でも迷いません。
-
ショートカットキーが豊富 — 1/2キーで駒台に直接移動できるので、Tab連打しなくていい。これは神機能!
😅 改善してほしい点:
-
フォーカスの移動範囲が広すぎる — Tabキーで『新しい対局』→『ヘルプ』→『投了』→『盤面』...と全部回るのは少し疲れます。『Escキーで盤面に戻る』とか、ショートカットがあると嬉しい。
-
成りダイアログの操作 — 「成る/成らない」を選ぶ時、矢印キーで選択できるけど、どちらが選ばれているか、もっと視覚的に分かりやすいと良い。
-
操作ミスしても大丈夫 — 『待った機能(Uキー)』があるのは最高!でも、初めて知るまで気づかなかった。最初に『Hキーでヘルプ』と表示してくれると親切かも。
でも正直に言って、このゲームはマウスなしで完全に遊べる数少ないゲームの一つです。開発者さん、本当にありがとうございます!
GitHub Copilot等のAIに「体験談」から改善案を聞く
これらの体験談をGitHub Copilot等に渡すと、以下のような具体的な改善案が提案されます:
- 全盲ユーザーの要望:AIの手を詳細に読み上げる(aria-live regionの充実)
- 運動障害者の要望:Escキーで盤面に戻る機能の追加
- 初心者向け:駒台エリアの説明をもっと明確に
本質:コードだけでなく「体験」を検証する
この章で重要なのは単なる自動テストではないということ:
従来のテスト:
✅ aria-labelが存在するか? → YES
✅ キーボード操作可能か? → YES
→ テスト合格!
AIペルソナテスト:
✅ aria-labelが存在する
❓ でも、全盲ユーザーは「分かりやすい」と感じるか?
❓ 実際にプレイして「楽しい」か?
→ AIペルソナに体験談として語ってもらう
→ 改善点を具体的に発見
→ GitHub Copilotで即座に改善案を生成
→ 実装 → 再テスト
つまり、「テストが通る」ことがゴールではなく、「実際のユーザーが快適にプレイできる」ことがゴールです。
AIペルソナとPuppeteerの組み合わせで、この検証サイクルを自動化・高速化できます。
【詳細】体験談から生成される具体的な改善案
上記の改善提案について、GitHub Copilotと確認した詳細情報:
改善提案1の詳細コード例
全盲ユーザーの「AIの手を詳細に読み上げたい」という要望への実装例:
// 改善後のコード
function announceAiMove(move) {
const liveRegion = document.querySelector('[aria-live="polite"]');
// moveオブジェクトから詳細を取得
const { from, to, piece, captured, promoted } = move;
// 詳細な読み上げテキストを構成
let announcement = `AIが${from.file}の${from.rank}の${piece}を`;
announcement += `${to.file}の${to.rank}に移動しました。`;
if (captured) {
announcement += ` ${captured}を取りました。`;
}
if (promoted) {
announcement += ` ${piece}が成りました。`;
}
liveRegion.textContent = announcement;
}
// 使用例:
// AIが5の4の歩を6の4に移動しました。
// AIが3の3の銀を4の4に移動しました。歩を取りました。
// AIが9の1の香を9の3に移動しました。香が成りました。
改善提案2の詳細コード例
運動障害者の「Escキーで盤面に戻りたい」という要望への実装例:
// keyboard-shortcuts.js に追加
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
// 現在フォーカスがゲーム盤面の外にある場合
const boardSection = document.querySelector('.board-section');
const focusedElement = document.activeElement;
if (!boardSection.contains(focusedElement)) {
// 盤面の中央のマスにフォーカスを戻す
const centerCell = document.querySelector('[data-rank="5"][data-file="5"]');
if (centerCell) {
centerCell.focus();
// スクリーンリーダーにも通知
const liveRegion = document.querySelector('[aria-live="polite"]');
liveRegion.textContent = '盤面に戻りました。5の5のマスにいます';
}
}
}
});
// さらに、ショートカット一覧(Hキー)にも追加:
// - Esc → 盤面に戻る
改善提案3の詳細コード例
全盲ユーザーの「駒台エリアをもっと分かりやすく」という要望への実装例:
<!-- HTML改善 -->
<div class="komadai"
role="region"
aria-label="持ち駒エリア。取った駒を盤面に打てます"
@focus="announceKomadaiEntry">
<button
aria-label="歩を盤面に打つ。現在3枚持っています"
data-piece="fu"
data-count="3">
歩 3
</button>
<!-- ... -->
</div>
<script>
function announceKomadaiEntry() {
const liveRegion = document.querySelector('[aria-live="polite"]');
liveRegion.textContent = '持ち駒エリアに入りました。取った駒を選んで盤面に打てます';
}
</script>
【詳細】Puppeteerのテスト実装コード
上記の体験談は、以下のようなPuppeteerテストから生成されています。
全盲ユーザーテストの実装例
// tests/a11y/test-blind-user.mjs
import puppeteer from 'puppeteer';
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
const BASE_URL = 'http://localhost:8000'; // ローカル環境
await page.goto(BASE_URL);
// 検証1: すべてのマスに適切なaria-labelがあるか
console.log('🔍 検証1: 盤面のaria-label検証');
const cells = await page.$$('[data-rank][data-file]');
let labelErrorCount = 0;
for (const cell of cells) {
const ariaLabel = await cell.evaluate(el => el.getAttribute('aria-label'));
if (!ariaLabel || ariaLabel.length === 0) {
labelErrorCount++;
}
}
if (labelErrorCount === 0) {
console.log('✅ すべてのマスに適切なaria-labelがあります');
}
// 検証2: キーボード操作、音声通知、手番交代などを検証
// (詳細な検証ロジックは省略)
console.log('✅ 全盲ユーザーのアクセシビリティ検証完了');
await browser.close();
})();
運動障害者テストの実装例
// tests/disability/test-motor-disability.mjs
import puppeteer from 'puppeteer';
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
const BASE_URL = 'http://localhost:8000';
await page.goto(BASE_URL);
console.log('🔍 運動障害者ペルソナ: マウスなしでの操作検証');
// マウス操作を完全に無効化
await page.evaluate(() => {
document.addEventListener('mousedown', (e) => e.stopImmediatePropagation(), true);
document.addEventListener('click', (e) => e.stopImmediatePropagation(), true);
});
// Tab + Enter だけでゲーム開始
await page.keyboard.press('Tab');
await page.keyboard.press('Enter');
await page.waitForTimeout(500);
// 矢印キー + Enter で10手プレイ
for (let turn = 0; turn < 10; turn++) {
// 駒を選択(矢印キーで移動 + Enter)
for (let i = 0; i < 3; i++) {
await page.keyboard.press('ArrowDown');
await page.waitForTimeout(100);
}
await page.keyboard.press('Enter');
await page.waitForTimeout(200);
// 移動先を選択
await page.keyboard.press('ArrowRight');
await page.keyboard.press('Enter');
await page.waitForTimeout(500);
// AIの手番を待つ
await page.waitForTimeout(1000);
}
console.log('✅ マウスなしで10手完了 - 運動障害者対応OK');
await browser.close();
})();
これらのテストが検証すること:
- 全盲ユーザー: aria-label、音声通知、キーボード操作のみで完全プレイ可能
- 運動障害者: マウス無しで矢印キー + Enter のシンプル操作で完全プレイ可能
第5章:Puppeteerで再現「モバイルボード縮小バグの原因特定」
アクセシビリティは「障害者対応」だけではない
前章では、全盲ユーザーや運動障害者といった障害者ペルソナの検証を見ました。
これがアクセシビリティの中核です。
しかし、「アクセス可能性」は障害の有無に関わらず、多様な環境・デバイスでも使えることを含みます:
- 小さい画面(モバイル) でもUIが崩れない
- 低速回線 でも操作できる
- 古いブラウザ でも動作する
このため、24種類のペルソナには 障害者ペルソナ(17種) に加えて、AIペルソナ(7種:モバイル、デザイナー、UX等) も含めています。
以下は、モバイル環境で発見されたバグの実例です。
😱 ユーザーレポート:盤面が縮小する現象
iPhone 11でのテスト時に、ゲーム中に盤面がみるみる縮小する現象が報告されました:
初期状態:盤面 320px(画面横幅400px の80%)
↓ 駒を1つ取る
→ 盤面 294px(6%縮小!)
↓ 駒を3つ取る
→ 盤面 186px(58%縮小!!)
何かが盤面サイズに影響を与えている?
→ Puppeteerで再現し、原因を特定する必要がある
🔍 Puppeteerで問題を再現し、原因特定
このバグの仕組みを特定するために、Puppeteerでブラウザの自動操作を記録します。
駒を取る前後で盤面サイズがどう変化するかを追跡することで、CSSレベルの問題を発見できます。
【詳細】Puppeteerでバグを追跡するコード
// debug-komadai.mjs - 盤面縮小バグを追跡
import puppeteer from 'puppeteer';
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setViewport({ width: 375, height: 667 }); // iPhone SE
const BASE_URL = 'http://localhost:8000'; // ローカル環境
await page.goto(BASE_URL);
await page.click('[role="button"]:has-text("新しい対局")');
// 15手進めながら、盤面サイズの変化を記録
const sizeHistory = [];
for (let i = 0; i < 15; i++) {
const moves = await page.evaluate(() =>
window.game.board.getLegalMoves()
);
if (moves.length === 0) break;
const move = moves[Math.floor(Math.random() * moves.length)];
// 駒を取る前のサイズ
const before = await page.evaluate(() => ({
komadai: getComputedStyle(document.querySelector('.komadai')).width,
board: getComputedStyle(document.querySelector('.board-section')).width
}));
await page.click(`[data-move="${move}"]`);
await page.waitForTimeout(300);
// 駒を取った後のサイズ
const after = await page.evaluate(() => ({
komadai: getComputedStyle(document.querySelector('.komadai')).width,
board: getComputedStyle(document.querySelector('.board-section')).width
}));
sizeHistory.push({
turn: i + 1,
komadai: `${before.komadai} → ${after.komadai}`,
board: `${before.board} → ${after.board}`
});
}
console.table(sizeHistory);
実行結果:
Turn 1: 駒台 90px → 90px, 盤面 320px → 320px ✅
Turn 2: 駒台 90px → 90px, 盤面 320px → 307px ❌ 縮小!
Turn 3: 駒台 90px → 90px, 盤面 307px → 294px ❌ さらに縮小!
Turn 4: 駒台 90px → 90px, 盤面 294px → 281px ❌ 継続して縮小...
...
Turn 15: 駒台 90px → 90px, 盤面 186px → 186px ❌ 最終的に62%に!
駒台の幅は固定(90px)のまま変わらない。
なのに盤面が次々と縮小している。これはCSS側の問題だ。
🛠️ CSSを調査して原因を特定
Puppeteerの追跡結果から、CSS メディアクエリのカスケード問題が原因だと判明しました。
小さい画面用のルールで、親のフレックス指定が完全に上書きされていなかったのです。
【詳細】CSS メディアクエリの誤りを修正
/* 799px以下のタブレット向け */
@media (max-width: 799px) {
.komadai {
flex: 0 0 90px; /* 駒台幅を90pxに固定 */
}
}
/* 480px以下のモバイル向け */
@media (max-width: 480px) {
.komadai {
max-width: none; /* ← 幅指定がない...! */
}
/* ← 799pxの flex: 0 0 90px がカスケードしている! */
}
修正:
@media (max-width: 480px) {
.komadai {
width: auto; /* 幅を自動に */
flex: 0 0 auto; /* フレックスの固定を解除 */
align-self: stretch; /* 親に合わせて広げる */
}
.komadai .hand-pieces {
flex-direction: row; /* ボタンを横並びに */
flex-wrap: wrap; /* 折り返しを許可 */
}
}
✅ 修正後の検証
修正したCSS設定を実際にスマートフォンやタブレットで検証した結果:
iPhone SE (375px):
駒台幅: 319px ✅ 画面幅に広がった!
盤面幅: 299px ✅ 縮小しない!
iPhone 14 (390px):
駒台幅: 334px ✅ OK
盤面幅: 320px ✅ OK
タブレット(600px):
駒台幅: 90px ✅ 意図通り
盤面幅: 620px ✅ OK
💡 本質的な学び
「正しいコード」と「良いユーザー体験」は異なる
テスト: ✅ CSS メディアクエリ構文は正しい
でも: ❌ ユーザー体験は破壊されているこれを見つけるのは「機械的なテスト」ではなく、
「複数のデバイスで実際にゲームをプレイして確認する」しかない
第6章:24種類のペルソナで790テスト——障害者ペルソナを中核に
アクセシビリティテストの優先順位
最優先:障害者ユーザーペルソナ(17種類)
- 全盲ユーザー、弱視ユーザー、運動障害者、発達特性...
- これがアクセシビリティの本質
- テスト数:227個(全790個の29%)
次点:多様な環境・専門家のペルソナ(7種類)
- モバイルユーザー、UXリサーチャー、教育者...
- デバイス・専門的観点からの品質検証
- テスト数:364個(全790個の46%)
テスト統計
以下は、790個のテスト内訳です(npm run test:all で実行):
| カテゴリ | 個数 | 詳細 |
|---|---|---|
| PHP Unit(ロジック) | 140 | — |
| アクセシビリティテスト | 227 | 全盲(87)、拡張(21)、弱視(35)、色対比(28)、周辺視野喪失(20)、パーキンソン病(7)、低スペック(12)、色覚異常(17) |
| AIペルソナテスト | 364 | 多様なペルソナ1(45)、多様なペルソナ2(33)、多様なペルソナ3(26)、高齢者(62)、子供・初心者(28)、UXリサーチャー(45)、教育者(30)、モバイルユーザー(28)、棋士(30)、デザイナー(37) |
| E2E 統合テスト | 59 | — |
| 合計 | 790 | — |
ペルソナ分類(24種類)
🧑🦯 【中核】障害者ユーザーペルソナ(17種類)
アクセシビリティの本質は、障害を持つユーザーが使えること。
以下の17種類のペルソナで、多様な障害に対応:
視覚障害関連 (6種)
- 全盲ユーザー(スクリーンリーダー利用)
- 弱視ユーザー(拡大表示対応)
- 全盲初心者(スクリーンリーダー + 将棋初心者)
- 弱視初心者(拡大表示 + 将棋初心者)
- 色覚異常ユーザー(P型色覚対応)
- 重度弱視ユーザー(400%ズーム対応)
運動障害関連 (3種)
- 上肢障害者(片手キーボード操作)
- 脳性麻痺(Tab + Enter のみ)
- 片麻痺(左手のみ操作)
聴覚障害関連 (1種)
- 聴覚障害者(視覚的フィードバック)
発達特性・学習障害関連 (4種)
- 発達特性/学習障害(ふりがな・平易な言葉)
- ADHD(感覚過敏対応)
- ディスレクシア(読字障害対応)
- 自閉スペクトラム(一貫性重視)
その他の障害 (3種)
- 知的障害(シンプルUI)
- てんかん(光感受性対応)
- 加齢による見えにくさ(弱視 + 手の震え対応)
🤖 【補助】AIペルソナ(7種類)
障害者対応を前提に、さらに多様な環境・視点で品質を検証:
- 棋士AI(将棋ルール正確性検証)
- WebデザイナーAI(UI/UX設計品質検証)
- UXリサーチャーAI(ヒューリスティック評価)
- 教育者AI(特別支援教育対応検証)
- 加齢AIペルソナ(デジタル不慣れ・72歳)
- 子供・初心者AI(小学生12歳対応検証)
- モバイルユーザーAI(スマートフォン通勤ユーザー)
実行例:障害者ペルソナのテストコード
障害者ペルソナの実際のテストコードを見てみましょう:
// tests/customer-ai/test-senior.mjs
// 【障害者ペルソナ】加齢による見えにくさのある人をシミュレート
const checks = [
{
name: 'テキストコントラスト比が4.5以上',
fn: async () => {
const color = await page.locator('.board-label')
.evaluate(el => getComputedStyle(el).color);
expect(contrastRatio(color)).toBeGreaterThanOrEqual(4.5);
}
},
{
name: 'ボタンサイズが最小44px',
fn: async () => {
const buttons = await page.locator('button').all();
for (const btn of buttons) {
const height = await btn.evaluate(el => el.offsetHeight);
expect(height).toBeGreaterThanOrEqual(44);
}
}
},
{
name: '画面ズーム200%でも操作可能',
fn: async () => {
await page.evaluate(() => {
document.body.style.zoom = '200%';
});
const piece = await page.locator('[data-piece="2f"]');
expect(await piece.isVisible()).toBe(true);
}
}
];
// 実行...
第7章:実装上の主な工夫
1. スクリーンリーダーで「正しく」読み上げられるHTMLセマンティクス
<!-- ❌ ダメな例 -->
<div class="piece" onClick="selectPiece('2f')">歩</div>
<!-- ✅ 良い例 -->
<button
class="piece"
data-piece="2f"
aria-label="先手の歩、5の3のマス"
@click="selectPiece"
>
歩
</button>
2. キーボード操作の状態管理
// ユーザーが一度キーボードを使ったら、
// 以降「フォーカスリング」を強調表示
let hasUsedKeyboard = false;
document.addEventListener('keydown', (e) => {
if (!hasUsedKeyboard) {
document.body.classList.add('keyboard-mode');
hasUsedKeyboard = true;
}
});
// CSS で強調表示
body.keyboard-mode *:focus {
outline: 3px solid #4F46E5;
outline-offset: 3px;
}
3. Puppeteerでの確実な待機パターン
// ❌ ダメ:ブラインド待機
await page.goto(url);
await page.waitForTimeout(500); // CPU浪費
// ✅ 良い:要素が表示されるまで待機
await page.goto(url);
await page.waitForSelector('.game-board', { timeout: 5000 });
4. アクセシビリティの「段階的改善」
Phase 1: セマンティック HTML(追加作業なし)
<button>, <a>, <nav> を正しく使う
Phase 2: ARIA 属性(追加ツール不要)
aria-label, role, aria-live etc
Phase 3: キーボード操作(少しの実装で対応可能)
@keydown.enter, @keydown.space
Phase 4: スクリーンリーダー完全対応(丁寧な実装が必要)
ARIA live regions, landmarks
Phase 5: ペルソナテスト(時間はかかるが価値大)
24種類のペルソナで実際に検証
↑ この順で進めるのが現実的
第8章:AI(GitHub Copilot等)との組み合わせ戦略
Puppeteer + AI のフィードバックループ
実装コード
↓
Puppeteerテスト実行(全790テスト)
- ARIA属性の検証
- キーボード操作の確認
- スクリーンリーダー互換性
- 視覚表示の確認
↓
初回実行 or 失敗検出時
↓
スクリーンショット + 詳細ログ収集
↓
AI分析(Vision API + ログ解析)
↓
改善提案生成(Copilot)
↓
コード修正
↓
再テスト → 合格 → 次の機能へ
具体的な改善例
例1:全盲ユーザーペルソナからの改善
【Puppeteer実行結果】
全盲ユーザーペルソナ: AIの手番が音声で伝わらない
【詳細ログ分析】
AI: 「aria-live領域が更新されていますが、テキストが空です」
【Copilotへのプロンプト】
「AIが指した手を詳細に読み上げるコードを書いてください。
例:『AIが5の4の歩を6の4に移動しました』」
【自動修正提案】
announceAiMove(move) 関数を提案
【再テスト】
全盲ペルソナテスト → 合格✅
例2:モバイルペルソナからの改善(第5章のバグ)
【Puppeteer実行結果】
モバイル iPhone SE: 駒を取るたびに盤面が縮小する
【スクリーンショット + ログ分析】
Turn 1: 盤面 320px ✅
Turn 2: 盤面 307px ❌ 4%縮小
Turn 5: 盤面 186px ❌ 42%縮小
【Copilotへのプロンプト】
「駒台はフレックスアイテムですが、flex-shrinkの初期値により
盤面が縮小しています。駒台を固定幅にしてください」
【自動修正提案】
.komadai { flex: 0 0 auto; } を提案
【再テスト】
全790テスト実行 → 合格✅
まとめ:「完全アクセシブル」とは
複数の背景を持つユーザー全てが使える状態
| 項目 | 詳細 |
|---|---|
| 実装ロジック | PHP Unit テストで正確性を検証 |
| ユーザー操作 | Puppeteer E2E で複数デバイス・操作方式を検証 |
| 視覚障害対応 | スクリーンリーダー、高コントラスト、拡大対応 |
| 運動障害対応 | キーボード操作のみ、大タッチターゲット |
| 発達特性対応 | シンプルUI、刺激を抑えた情報設計 |
| 加齢対応 | 大きいテキスト、反応速度考慮 |
| 初心者対応 | 詳細なチュートリアル、段階的学習 |
| 多様性対応 | 24種類のペルソナベーステスト |
| 継続改善 | GitHub Copilot + Puppeteer ループ |
段階的な改善アプローチ
アクセシビリティは一度に完璧を目指すのではなく、段階的に改善していくことが現実的です:
Phase 1: セマンティック HTML の徹底
→ 基礎的なアクセシビリティを確保
Phase 2: キーボード操作の実装
→ マウスに依存しない操作を実現
Phase 3: ARIA 属性の追加
→ 支援技術への情報提供を強化
Phase 4: スクリーンリーダー検証
→ 実際の支援技術での動作確認
Phase 5: ペルソナテストの導入
→ 多様な利用シーンを網羅的に検証
→ 手動では膨大な時間がかかるが、Puppeteer + AIで自動化可能
結論:
セマンティック HTML から始めることで、効率的に基盤を構築できる
AIペルソナを導入することで、継続的な検証が現実的になる
第9章:フィードバック機能の実装——実際の当事者の声を収集する
AIペルソナテストの限界
790個のテストと24種類のペルソナで99%のアクセシビリティを達成しましたが、重要な真実があります:
AIペルソナテストは「開発者が想定できる範囲」しかカバーできない
実際の障害を持つユーザーは、開発者が想像もしなかった使い方をします:
- スクリーンリーダーの設定が異なる
- 支援技術の組み合わせが予想外
- 文化的背景による期待値の違い
- 個人の認知スタイルの多様性
だからこそ、実際の当事者からのフィードバックが必須です。
フィードバック機能の設計方針
アクセシビリティを重視するなら、フィードバック機能自体もアクセシブルでなければなりません。
設計のポイント:
- プライバシー最優先 - DBに保存せず、メール送信のみで完結
- 3画面フロー - 入力→確認→完了で誤送信防止
- アクセシブルなフォーム - aria-label、キーボード操作、エラー通知
- レート制限 - スパム防止(5分間隔)
- AI推奨メッセージ - 「完璧ではない」ことを誠実に伝え、ユーザーを品質向上のパートナーとして位置づける
実例:当事者フィードバックから見つかった「AIペルソナでは検出しにくかった改善点」
リリース後、視覚障害者ユーザーより以下のフィードバックが報告されました:
「ランキング登録ダイアログで手数が『0手』と表示される」
改善が必要だった理由
AIペルソナテスト(24種類×790テスト)では、この改善点は 検出されていませんでした 。なぜか?
// 改善前のコード
function showRankingRegistrationDialog() {
// ダイアログを表示
rankingDialog.style.display = 'flex';
// 手数を表示(改善点:ページロード時の初期値を使用)
const rankingMovesEl = document.getElementById('ranking-moves');
rankingMovesEl.textContent = `{{ $game->total_moves ?? 0 }}手`; // ❌ 常に初期値
}
AIペルソナテストでは検出しにくかった理由:
- Puppeteerの自動テストでは、ゲーム中から 連続的に ダイアログ表示をテストしない
- 投了後の「ゲーム終了状態」を検証するテストと、その後の「ランキングダイアログ表示」テストが分かれていた
- つまり、実装の「状態遷移」までは テストしていなかった
これは AIペルソナテストの 本質的な限界 です。
改善内容
// app/Http/Controllers/GameController.php - resign()メソッド
public function resign(GameSession $session): JsonResponse {
$session->status = 'resigned';
$session->winner = 'ai';
$this->gameService->updateElapsedTime($session);
return response()->json([
'success' => true,
'status' => $session->status,
'winner' => $session->winner,
'moveCount' => $session->total_moves, // ✅ 最新の手数を返す
'elapsedSeconds' => $session->elapsed_seconds,
]);
}
// resources/views/game/show.blade.php - ダイアログ表示時
function showRankingRegistrationDialog() {
const gameData = window.gameData || {};
// ✅ 常に最新の moveCount を反映
const rankingMovesEl = document.getElementById('ranking-moves');
if (rankingMovesEl && gameData.moveCount !== undefined) {
rankingMovesEl.textContent = `${gameData.moveCount}手`;
}
rankingDialog.style.display = 'flex';
}
改善のポイント:
- API レスポンスに
moveCountを含める - ダイアログ表示時に 最新のゲーム状態を反映 する
- ページリロード時も、自動的にダイアログが表示される
この改善で学べることは?
「AIペルソナテストは『初期状態→最終状態』の検証には強いが、『状態遷移中の中間状態』は検証しにくい」
AIペルソナ + 実際の当事者 = 継続的改善
開発初期:AIペルソナテスト(790テスト)
↓
99% の品質達成
↓
リリース:フィードバック機能で実際の当事者の声を収集
↓
改善点を反映
↓
AIペルソナテストを追加(新しいテストケース)
↓
99.5% → 99.9% ... と継続的に改善
重要な教訓:
- AIペルソナテストは「スタート地点」を高くする
- 実際の当事者フィードバックは「ゴール」を更新し続ける
- 両方の組み合わせで「本当のアクセシビリティ」を実現
次のアクセシビリティ開発者へ
-
「視覚障害対応」だけでは完全ではない
- 複数層(視覚、運動、発達特性、加齢、初心者...)が存在
- 一つの層の最適化が別の層を阻害することもある
- 複数層の「共存」を実現しよう
-
「チャット指示」は入り口に過ぎない
- 実装後の「複数パターン検証」が全てを決める
-
複数のテスト方法を組み合わせよ
- Unit(ロジック)+ E2E(操作フロー)+ ペルソナテスト(体験)
-
AIはテストツール
- Puppeteer で「ユーザー行動」を自動化
- AI(Copilot等)で「改善案」を提案
- 人間が「最終判断」
-
「完全」を目指さず「継続的改善」を
- 99% 達成後も、フィードバックで改善し続ける
リソース
- 将棋ゲーム用URL: https://a11y-shogi.iesaba.jp
- GitHub: https://github.com/milyimi/a11y-shogi
- 前回の記事: 火星移住計画シミュレータのアクセシビリティ
- 参考: WCAG 2.1 AA 基準
- ツール: Puppeteer, GitHub Copilot, Laravel 12, PHP 8.3, Node.js
最後に
このプロジェクトを通じて学んだ最も大切な教訓:
アクセシビリティは「視覚障害対応」ではなく、「複数の背景を持つ全員が使える」状態を目指すプロセス
Vanilla JS を選択理由、Puppeteer による複数パターン検証、AI との組み合わせ——これらを通じて、
個人開発者でも「本当のアクセシビリティ」を目指せる時代が来ました。次のアクセシビリティ開発には、ぜひ複数層のペルソナテストの導入を検討してください。