月の満ち欠けシミュレーター機能強化
PR#55「月の満ち欠けシミュレーター」のレビュー対応として実施した一連の機能強化の記録。
背景
月の満ち欠けシミュレーター(moon-simulator.vue)を作成し、PRを出したところ、複数のレビューコメントが付いた。それらへの対応と、Chrome DevTools MCPを使ったデザイン確認の過程で、いくつかの問題が発覚し、大幅な改修が必要になった。
Tailwind CSS問題の発覚
Chrome DevTools MCPでページを確認したところ、CSSが全く適用されていなかった。
発覚の経緯
- ブラウザでmoon-simulatorページを開く
- CSSが適用されていない(背景が白、レイアウトが崩れている)
- 他のページ(animation-demo-1など)は正常
- コンソールにエラーなし
- ネットワークリクエストも全て成功
原因特定
moon-simulator.vueではTailwindCSSのクラス(bg-gradient-to-b, from-gray-900など)を使っていたが、このプロジェクトにはTailwindCSSがインストールされていなかった。
他のVueページ(animation-demo-1.vue)を確認すると、すべてscoped CSSで書かれていた。
対応:scoped CSSへの変換
Tailwindクラスをすべてscoped CSSに書き直した。
<style scoped>
.simulator-container {
min-height: 100vh;
background: linear-gradient(to bottom, #111827, #1f2937, #111827);
padding: 2rem 1rem;
}
.content-wrapper {
max-width: 64rem;
margin: 0 auto;
}
/* 以下、全てのスタイルをscoped CSSで定義 */
</style>
日食・月食シミュレーターの追加
ユーザーから「日食と月食も追加してほしい」というリクエストがあり、別ページとしてeclipse-simulator.vueを新規作成した。
機能要件
- 太陽、地球、月の位置関係を表示
- 地球の公転(365日)と月の公転(約27日)をシミュレート
- 月の軌道傾斜(約5.14°)を考慮し、日食・月食が起きる条件を表示
- 「日食位置へジャンプ」「月食位置へジャンプ」ボタン
位置関係の検証
Chrome DevTools MCPでスクリーンショットを撮りながら、位置関係が正しいか検証した。
月食(moonAngle=0°)の配置:
- 太陽(黄色)→ 地球(青)→ 月(赤い点)の順
- 地球から右に伸びる影の中に月がいる
日食(moonAngle=180°)の配置:
- 太陽(黄色)→ 月(赤い点)→ 地球(青)の順
- 月が太陽と地球の間
「地球から見た様子」セクションの追加
シミュレーターだけでは「実際に何が見えるのか」がわからないため、地球から見た様子を表示するセクションを追加した。
- 日食時: 太陽が月に隠され、周囲にコロナが見える
- 月食時: 赤い満月(ブラッドムーン)
当初は日食・月食発生時のみ表示していたが、「一瞬しか映らないので見えない」というフィードバックを受け、常時表示に変更。発生時は外枠を黄色で強調表示するようにした。
<div class="observation-card" :class="{ 'eclipse-active': isSolarEclipse }">
<!-- 日食の説明(常時表示) -->
</div>
.eclipse-active {
border-color: #fbbf24;
box-shadow: 0 0 20px rgba(251, 191, 36, 0.5);
}
日本から見える頻度の説明追加
「日本に住んでいて、この日食・月食が見える頻度は?」という質問から、頻度情報を追加。
| 種類 | 世界のどこかで | 日本から見える頻度 |
|---|---|---|
| 部分日食 | 年2〜5回 | 数年に1回 |
| 皆既日食 | 年0〜2回 | 同じ場所では平均370年に1回 |
| 部分月食 | 年2回程度 | 年1〜2回 |
| 皆既月食 | 年0〜2回 | 1〜2年に1回程度 |
パンくずリストへのシミュレーターパス追加
moon-simulatorとeclipse-simulatorがvuePagePathsに含まれていなかったため、パンくずリストに「一覧」が表示されていた。
// Breadcrumb.vue
const vuePagePaths = [
'animation-demo-1',
'animation-demo-2',
// ... 他のパス
'moon-simulator', // 追加
'eclipse-simulator', // 追加
];
Before: Home / 一覧 / moon-simulatorAfter: Home / moon-simulator
SEOメタタグ(OGタグ)の追加
両シミュレーターにOGメタタグを追加した。
useSeoMeta({
title: '月の満ち欠けシミュレーター - 月相の仕組みを視覚的に理解',
description: '太陽・地球・月の位置関係から月の満ち欠けが起きる仕組みを学べるインタラクティブなシミュレーター',
ogTitle: '月の満ち欠けシミュレーター',
ogDescription: '太陽・地球・月の位置関係から月の満ち欠けが起きる仕組みを学べるインタラクティブなシミュレーター',
ogType: 'website',
});
アクセシビリティ属性の追加
ボタンとスライダーにアクセシビリティ属性を追加した。
ボタン
<button
class="control-btn"
aria-label="アニメーションを再生"
@click="startAnimation"
>
▶ 再生
</button>
スライダー
<input
type="range"
:value="currentAngle"
min="0"
max="360"
aria-label="月の角度"
aria-valuemin="0"
aria-valuemax="360"
:aria-valuenow="currentAngle"
:aria-valuetext="`${currentAngle}度 (${currentPhaseName})`"
@input="onAngleChange"
/>
フォーカススタイル
.control-btn:focus {
outline: 2px solid #60a5fa;
outline-offset: 2px;
}
input[type="range"]:focus {
outline: 2px solid #60a5fa;
outline-offset: 2px;
}
ユニットテストの追加
シミュレーターのロジック(月相計算、日食・月食判定)をテストするユニットテストを追加した。
// moon-simulator.test.ts
describe('Moon Simulator', () => {
describe('getMoonPhaseName', () => {
it('should return "新月" for angle 0', () => {
expect(getMoonPhaseName(0)).toBe('新月');
});
it('should return "上弦の月" for angle 90', () => {
expect(getMoonPhaseName(90)).toBe('上弦の月');
});
// ...
});
});
// eclipse-simulator.test.ts
describe('Eclipse Simulator', () => {
describe('isSolarEclipse', () => {
it('should detect solar eclipse when moon is between sun and earth', () => {
// 太陽-月-地球が一直線
expect(checkSolarEclipse(earthAngle, moonAngle)).toBe(true);
});
});
});
まとめ
今回のPRレビュー対応で実施した改善:
- Tailwind CSS → scoped CSS変換: プロジェクトにTailwindがないことを発見し、全てscoped CSSに書き直し
- Chrome DevTools MCPによる確認: デザイン崩れを視覚的に確認し、修正
- 日食・月食シミュレーター新規追加: 別ページとして作成
- 「地球から見た様子」セクション: 常時表示 + 発生時の強調表示
- 日本から見える頻度: 教育的な情報を追加
- パンくずリストの修正: vuePagePathsに追加
- SEOメタタグ: OGタグを追加
- アクセシビリティ: aria属性とフォーカススタイルを追加
- ユニットテスト: 月相計算と日食・月食判定のテストを追加