# 画像クイズ王グランプリ 出題ツール

**操作画面**（司会のPC）と**モニター画面**（会場の大型モニター）の2画面で動くクイズ出題ツールです。
同じPCの2つの窓で動き、通信はローカルストレージ。問題と画像は `questions.json` と `images/` を直接参照します。
早押しボタン・フリップ・採点はアナログ運用の前提で、モニターに出るのは「出題画像」「現在のレベル」「次のレベルまでの残り時間」だけです。

```
フォルダ構成
├─ quiz.html          … これを開く
├─ questions.json     … 問題データ（これを編集する）
├─ images/            … 出題する画像（cat1〜3.jpg を同梱）
├─ bgm/               … 任意。BGM の音声ファイル
└─ sounds/            … 任意。効果音を差し替えたいとき
```

---

## 1. 起動

1. このフォルダで `python -m http.server 8765` を実行
2. ブラウザで `http://localhost:8765/quiz.html` を開く
3. `questions.json` を編集した後は、ブラウザを再読み込み
4. 操作画面右上の **「モニターを開く」** を押し、モニター側の窓を **F キーかダブルクリックで全画面**

### 画像の渡し方（重要）

- 画像は `images/` に置き、`questions.json` の `image` に相対パスで記述します。例：`"image": "images/food.jpg"`
- 画像が見つからない問題は、一覧に赤く **「画像なし」** と出ます。ファイル名とJSONの記述を確認してください。

> IBM Plex Sans JP はインターネット接続時に Google Fonts から読み込みます。圏外でもシステムのゴシック体に自動で切り替わって動きます。

---

## 2. 操作画面

```
┌ 問題一覧 ┬──────── ミラー（モニターと同じ表示） ────────┬ 正解           ┐
│ サムネ付き │ 進行ボタン・レベル手動送信                         │ 効果音         │
│ クリックで │  出題 停止 再開 正解表示 次の問題 タイトルへ戻る   │ 正解〜ジャーン   │
│ 選択      │  レベルを手動で送る                              │ BGM 再生/停止  │
└──────────┴──────────────────────────────────────────────┴───────────────┘
```

### 進行

| ボタン | キー | 動作 |
|---|---|---|
| 出題 | `Enter` | 選択中の問題をレベル5から自動再生（一覧のダブルクリックでも可）。再生中は効かない（先にタイトルへ戻る） |
| 停止 | `Space` | 進行を一時停止。モニターに「一時停止中」 |
| 再開 | `Space` | 残り時間から再開 |
| タイトルへ戻る（リセット） | `T` / `R` | タイマーと進行をリセットしてタイトル画面へ戻る |
| 正解表示（レベル0） | `A` / `0` | 完全な画像と「答え：◯◯」。自動では出ません。右側のプレートは「レベル0／正解」 |
| 次の問題 | `N` | 次の問題を選んで待機状態に（`P` で前へ） |
| レベル手動 | `1`〜`5` | 指定レベルへ飛ぶ（数字＝レベル）。`0` はレベル0＝正解表示 |
| 問題を選ぶ | `↑` `↓` | 一覧の上下 |

レベル1まで進むと自動で止まります（「レベル1で終了」）。**次に押すボタンは金色の枠で光ります**（待機中→出題、出題中→停止、終了→正解表示、正解表示→次の問題）。

### 誤操作を防ぐ動作

- 出題中・一時停止中は、問題一覧と `↑` / `↓` / `P` による問題切替を受け付けません。先に `T` または `R` でタイトルへ戻ってください。
- 一時停止中にレベルを手動で変更した場合は、そのレベルの持ち時間から再開します。

### 効果音（ファイル不要、内蔵合成）

| ボタン | キー | 音 |
|---|---|---|
| 正解 | `C` | ピンポーン |
| 不正解 | `X` | ブブー |
| ドラムロール | `D` | 2秒のロール → シンバル |
| ジャーン | `J` | 正解発表のファンファーレ |

`questions.json` の `sounds` にファイルを書けば、そのボタンはファイルを再生します（下記）。

### BGM

`questions.json` の `bgm` に書いたファイルが選択肢に並びます。
再生／停止は `B`。音量スライダーつき。

---

## 3. モニター画面

モニターに出るのは3つだけです。

- **出題画像**：左に大きく、金縁の出題パネル。元画像の縦横比のまま表示
- **レベルの進行（右側）**：「第◯問」バッジ、現在のレベルと点数のプレート（色はレベルに追従）、**次のレベルまでの残り秒数**（0.1秒刻みの大きな数字。残り1秒で点滅）
- **残り時間バー（画面下部）**：次のレベルまでの残り時間が右から減っていく。1秒ごとの目盛りつき。色はレベルに追従

一時停止中は左上にバッジ、正解表示はバーの位置が「答え：◯◯」に差し替わります。タイトル画面（出題前・幕間用）へは `T` または `R` で進行をリセットして戻ります。

テーマはポップ固定です。

---

## 4. questions.json

```json
{
  "title": "画像クイズ王グランプリ",
  "subtitle": "9月の誕生日会",
  "defaults": {
    "mode": "mosaic",
    "secondsPerLevel": 5,
    "levelPoints": [5, 4, 3, 2, 1]
  },
  "bgm": [
    { "name": "シンキングタイム", "file": "bgm/thinking.wav" }
  ],
  "sounds": {
    "correct": "sounds/correct.mp3",
    "wrong": "sounds/wrong.mp3",
    "drumroll": "sounds/drumroll.mp3",
    "fanfare": "sounds/fanfare.wav"
  },
  "questions": [
    {
      "id": "q1",
      "image": "images/basashi.jpg",
      "answer": "馬刺し",
      "mode": "mosaic",
      "memo": "実家の話を振る",
      "params": { "blocks": [10, 16, 26, 44, 84] }
    }
  ]
}
```

`id`、`image`、`answer` は必須です。`image` は `images/` からの相対パス、`mode` は表示方式、`params` は表示方式ごとの任意設定です。レベルは5〜0、配点は5〜0点、レベル5〜1の持ち時間は各5秒で固定です。`defaults` や問題ごとの配点・秒数指定では変更できません。

`sounds` で使えるキー：`correct` `wrong` `drumroll` `fanfare`。

読み込み時には、問題IDの重複、存在しない表示モード、`focus` の範囲外指定をエラーとして表示します。

### 音源ライセンス

正解・不正解・ドラムロールには OtoLogic の素材を使用しています（CC BY 4.0）。公開・配布時は、ゲーム内の操作画面に表示されるクレジットを残すか、同等の帰属表示を付けてください。詳細な素材一覧とライセンスは `AUDIO_CREDITS.md` を参照してください。

### 表示モード

操作画面の「表示モード比較」で、自分の画像を全モード並べて確認できます。画像をクリックすると `focus` の値が出るので JSON に貼ってください。

| `mode` | 名前 | 性質 | `params`（既定値：左がレベル5→右がレベル1） |
|---|---|---|---|
| `mosaic` | モザイク画像クイズ | 色の塊で当てる | `blocks: [6,10,16,26,40]` |
| `mono` | 白黒モザイククイズ | 色の手がかりを消す | `blocks: [8,13,20,32,48]` |
| `zoom` | ズームアウトクイズ | 極端に寄った状態から引く。寄っている間はカメラが上下左右に動き回る | `scale: [40,20,10,5,2.2]` / `focus: [x,y]` / `wander: 0.35` |
| `puzzle` | パズルクイズ | 細かいタイルがランダムに**ひっくり返って**開く | `grid: [16,9]` / `reveal: [0.04,0.12,0.25,0.42,0.62]` |
| `blur` | ぼかしクイズ | 時間とともに連続でピントが合う | `radius: [140,90,50,26,12]` |
| `spotlight` | スポットライトクイズ | 小さな灯りが動き回る。レベルで数が増える | `count: [1,2,3,5,8]` / `radius: [0.04,…,0.06]` / `speed: 1` |
| `slit` | スリットクイズ | 細い縦の隙間が横に流れ続ける。レベルで本数が増える | `slits: [1,2,3,5,8]` / `width: 0.02` / `speed: 0.12` |
| `warp` | 歪みクイズ | **うねり続ける歪み**が弱まっていく | `amp: [0.45,0.3,0.2,0.12,0.06]` / `speed: 1` |
| `noise` | ノイズクイズ | **ちらつく砂嵐**→晴れる | `cover: [0.99,0.95,0.88,0.78,0.65]` / `grain: 4` |
| `kaleido` | 万華鏡クイズ | **回り続ける鏡合わせの模様**。鏡の枚数が減って元の絵に近づく | `segments: [12,8,6,4,2]` / `zoom: [3,2.5,2,1.6,1.3]` / `focus` / `speed: 0.25` |

配列は左がレベル5（最難）→右がレベル1。レベル数が5以外でも自動で按分されます。
**レベル5は判別不能、レベル1でもまだ完全には見えない**値にしてあります。完全な画像は**レベル0（正解表示）**でだけ出ます。
`zoom` `spotlight` `slit` `warp` `noise` `kaleido` は常にアニメーションし（一時停止中も動きます）、`puzzle` はレベルが上がった瞬間にタイルがめくれ、`blur` は一時停止すると止まります。

---

## 5. 仕組み（トラブル時に）

- 操作画面が `localStorage` の `quiz:state` に状態を、`quiz:img:<問題id>` に縮小画像を書き、モニター窓とミラーがそれを読んで描画します。同じブラウザで開いてください
- 画像がモニターに出ないとき：操作画面の一覧に「画像なし」が出ていないか、`questions.json` の相対パスと `images/` 内のファイル名を確認してください
- モニターが「接続」にならないとき：モニター窓が同じブラウザ（同じプロファイル）で開いているか確認してください。別のブラウザだとローカルストレージが共有されません
- 音が出ないとき：操作画面をどこか一度クリックしてから鳴らしてください（ブラウザの自動再生制限）
- BGM のファイルが再生できないとき：mp3 / m4a / wav / ogg を使ってください
