やったこと概要
小学理科の学習コンテンツを、Miller Column レイアウトの専用ページとして新規構築した。中学受験向け参考書の全100トピックを目次として登録し、そのうち5トピック分のインタラクティブコンテンツを実装。クイズシステム、復習機能、オシロスコープ風の波形表示UIまで一日で作り切った。
Miller Column レイアウト
macOS の Finder でおなじみの、カラムが横に並ぶナビゲーションを採用した。理科コンテンツは階層が深い(大カテゴリ → 中カテゴリ → セクション → コンテンツ本体)ため、ツリー構造を一覧しながら掘り下げていける Miller Column が合っていた。
4カラム構成:
- 大カテゴリ: 水溶液と気体、物の燃え方、熱・光・音、力とエネルギーなど
- 中カテゴリ(トピック): ロウソクの燃え方、水の三態変化、音の性質など
- セクション: 基本のしくみ、くわしく知ろう、チャレンジ問題など
- コンテンツ本体: Vue コンポーネントまたはクイズ
ready 状態のトピックだけがクリック可能で、未実装のものはグレーアウト表示になる。categories.ts に sections: [] と書いておけば自動的に「準備中」扱いになる仕組み。
100トピックの目次登録
参考書の全100トピックを categories.ts に登録した。大カテゴリは10個前後に分けている。
水溶液と気体(1-10)/ 実験器具(11-12)/ 物の燃え方(13-17)
熱・光・音(18-28)/ 力とエネルギー(29-40)/ ...
大半は sections: [] の空状態だが、全体の見通しが立つことで「次にどこを埋めるか」が明確になった。100トピック全てを一度に作るのは現実的ではないので、子供が興味を持ったトピックから順に埋めていく方針。
React JSX から Vue SFC への変換
既存の React 実装(JSX)を Vue SFC に変換するスラッシュコマンド /convert-science-content を作った。
変換の要点:
useState→ref/reactiveuseEffect→watch/onMounted- JSX の
className→ template のclass - イベントハンドラの記法変換(
onClick→@click)
手動で書き直すと同じパターンの繰り返しになるため、スキル化して効率を上げた。入力として React コンポーネントを渡すと、Vue SFC に変換して出力する。
変換した5トピック
今回コンテンツを実装したのは以下の5つ。
| トピック | 主なコンテンツ |
|---|---|
| ロウソクの燃え方 | 炎の3層構造、温度分布の図解 |
| 水の三態変化 | 状態変化ダイアグラム、融点・沸点の比較表 |
| 音の性質 | 波形の基礎、モノコードの法則 |
| 音の秘密 | 音速計算、波形の性質比較 |
| てこ | 3種のてこ分類、つり合いの計算 |
各トピックは複数のセクション(3〜5個)に分かれていて、セクションごとに Vue コンポーネント1つが対応する。最後のセクションはクイズ。
クイズシステム
basic-english で実装済みだったスクロールリスト型のクイズパターンを踏襲した。
動作:
- 問題と選択肢を表示
- 選択すると即時フィードバック(正解/不正解 + 解説)
- 全問終了後にスコア表示
- 間違えた問題だけをリトライできるボタン
クイズデータは quiz-data/ ディレクトリに TypeScript ファイルとして分離。candle-quiz.ts、state-change-quiz.ts のようにトピックごとにファイルを分けている。
復習機能
useScienceQuizHistory composable で、間違えた問題の履歴を localStorage に保存する仕組みを作った。
- クイズ完了時に間違えた問題を記録
- 3回連続正解でその問題を復習リストから除外
- Miller Column 内に「復習」モードとして統合
復習モードに入ると、全トピックの間違い履歴を横断して出題する。トピックをまたいだ弱点克服ができる。
オシロスコープ風 波形表示 UI
音のトピックで作った SoundPlayground.vue が今回のハイライト。
見た目:
- CRT モニタ風の暗い背景(黒に近いグレー)
- 蛍光グリーンの波形描画(Canvas 2D)
- グリッド線も薄い緑で表示
機能:
- 周波数スライダー(220〜880Hz)
- 振幅スライダー
- 倍音合成スライダー(基本波〜第7倍音まで個別調整)
- プリセット: サイン波、矩形波、三角波、のこぎり波
Web Audio API の OscillatorNode を倍音の数だけ生成し、加法合成で音を作る。Canvas にはリアルタイムで合成波形を描画する。倍音スライダーを動かすと波形の形が変わり、同時に音色も変わる。
プリセットの実装は単純で、倍音スライダーの値を配列で持っているだけ。
const presets = [
{ label: 'サイン波', values: [100, 0, 0, 0, 0, 0, 0] },
{ label: '矩形波', values: [100, 0, 33, 0, 20, 0, 14] }, // 奇数倍音 1/n
{ label: 'のこぎり波', values: [100, 50, 33, 25, 20, 17, 14] }, // 全倍音 1/n
]
矩形波が「奇数次倍音だけ」というのは物理の話だが、スライダーで実際に音を聞きながら確認できるので理解しやすい。
スタイリング方針の転換
最初はカラフルな装飾(色付き背景、アイコン多用、ボーダー装飾)で作っていたが、途中でシンプル路線に切り替えた。
変更前: 各セクションに独自の背景色、太いボーダー、大きなアイコン 変更後: グレー背景のハイライトボックスに統一、装飾は最小限
理由は、コンテンツが増えるほど装飾が邪魔になること。100トピック分のスタイルを個別に管理するのは現実的ではない。ScienceSectionBlock と ScienceInfoCard という共通コンポーネントにまとめ、見た目を統一した。
/generate-science-content スキル
/convert-science-content が既存の React コードを変換するスキルだったのに対し、/generate-science-content はゼロからコンテンツを生成するスキル。トピック名を指定すると、セクション構成・Vue コンポーネント・クイズデータを一括で生成する。
その他の実装
- インデックスページへの理科カード追加: トップページから
/scienceへの導線を追加 - 矢印キーナビゲーション: セクション間を上下矢印キーで移動できるようにした。Miller Column の3列目(セクション一覧)にフォーカスがある状態で上下キーを押すと、前後のセクションに切り替わる
- Chrome DevTools での表示確認: MCP 経由でリモートデバッグ用 Chrome を起動し、レイアウト崩れや Canvas 描画の確認を行った
振り返り
一日でここまで作れたのは、既存のクイズシステム(basic-english)とスラッシュコマンドによる変換自動化が大きい。React → Vue の変換は手作業だと面倒だが、パターンが決まっているのでスキル化すると速い。
100トピック中5つしか埋まっていないが、枠組みが完成したことで「あとはコンテンツを入れるだけ」の状態になった。子供が「てこ」の問題を解いて間違えた後に復習モードで再挑戦している様子を見ると、作った甲斐がある。