AtlasQuest ができるまで — インタラクティブ学習 2本目を 国旗クイズ + 世界地図で
AtlasQuest は、 国旗 + 世界地図 クイズ。 主要 60 ヶ国 (大陸網羅) を 4 モード (国旗→国名 / 国名→国旗 / 国旗→大陸 / 国旗→首都) × 3 レベルで出題、 正解時は d3-geo の世界地図で該当国を amber に highlight。 ラボ 26本目、 インタラクティブ学習 thesis 2本目 (ToneQuest = 音感 に続く)。
なぜこの形にしたか
直近 5本に学習ゼロ。 charter 8 thesis 枠は 7/8 で、 シリーズ深掘り基調。 候補:
- 国旗クイズ (採用、 SEO 巨大 + 教育)
- タイピング練習 (ありふれ)
- 暗算 (弱)
- WebGL シェーダー学習 (ShaderToy 圧倒)
- 漢字クイズ (中庸)
選んだ理由:
- 「国旗 クイズ」「世界地図 クイズ」 は子供向け教育 + 受験生 + 一般教養層で SEO ボリューム巨大
- 既存大手 (Sporcle / GeoGuessr) は英語 UI / アカウント要 / 重いビルド
- 「ブラウザ完結 + 日本語 + 即動く + 世界地図ハイライト」 で差別化
- d3-geo + topojson + world-atlas + flagcdn という地理スタック (まだラボ未使用) を投入できる
visual direction — §6.1 Visual Audit 11本目の適用
直近 5本の visual を書き出す:
hue-deck — warm gray + ink + lipstick (Pantone カラーカード)
astro-cast — midnight space + sun emission + 惑星レインボー (天文台)
arcana-flip — midnight black + plum + antique gold (中世大聖堂)
gift-cap — 墨 + 朱 + 生成り + 茜 + 金箔 (和風 巻物)
pile-park — cream + coral + mint + lemon + indigo (玩具箱)
題材 「世界 / 国旗 / 地図 / クイズ」 → motif 候補:
- 古地図 (wiki-orbit と被るので避ける)
- 学校の地理教室 (黒板 motif、 弱め)
- 空港 departure board (LED + amber、 旅行感) ← 採用
- 新聞 / 報道 (グレー黒赤、 既存と被るリスク)
採用 3 要素:
- palette: dark navy
#0c1828+ amber departure#ffb84a+ safety yellow#ffe14a+ alert red#ff5050+ steel gray#3d4554+ paper white- astro-cast (midnight space + sun emission) と surface 黒は近いが、 palette = amber + safety yellow + alert red の departure board 系で完全別軸
- motif: 空港 departure board (LED 文字 + パタパタ感、 hero に runway stripes + departure chip 帯 + pulsing alert dot、 国旗の枠は amber + 投影シャドウ)
- typography: Space Grotesk 800 (engineering / sign board feel) + JetBrains Mono (board mono)
技術スタック
d3-geo + topojson-client + world-atlas
import { geoMercator, geoPath } from "d3-geo"
import { feature } from "topojson-client"
import type { Topology } from "topojson-specification"
const res = await fetch("/world-110m.json") // world-atlas の 108KB JSON
const topology = await res.json() as Topology
const fc = feature(topology, topology.objects.countries) // FeatureCollection
const projection = geoMercator().scale(95).center([10, 30]).translate([320, 200])
const pathGen = geoPath(projection)
world-atlas/countries-110m.json は public/world-110m.json にコピーして配信。 約 108KB。 各 feature の id が ISO 3166-1 numeric (3 桁の数値 string) なので、 国データ側に同 ID を持たせて O(N) でマッチング。
60 ヶ国データ + flagcdn
export const COUNTRIES: Country[] = [
{ iso2: "jp", num: "392", name_ja: "日本", continent: "アジア", capital_ja: "東京", ... },
// ... 60 ヶ国
]
export function flagUrl(iso2: string) {
return `https://flagcdn.com/${iso2}.svg`
}
flagcdn は無料 CDN (Public Domain 相当)、 200+ ヶ国の SVG を提供。 lazy load (loading="lazy") でブラウザに丸投げ、 ai-lab は介在しない。
4 モードのロジック
function makeQuestion(mode, level, continent) {
const pool = filterPool(continent) // 大陸フィルタ
const target = pool[random] // 出題対象
const n = levelCount(mode, level) // Easy 3 / Normal 4 / Hard 6
// mode に応じて choices を生成 (国名 / 大陸 / 首都)
return { mode, country: target, choices: shuffled, answer }
}
flag-to-continent モードは候補が 6 大陸しかないので、 Hard でも 6 までしか出ない。 他モードは 60 ヶ国の名前 / 首都プールから distractor を pickRandom。
マップでの正解 highlight
{features.map((f) => {
const isHit = String(f.id).padStart(3, "0") === question.country.num.padStart(3, "0")
return <path d={pathGen(f)} fill={isHit ? "#ffb84a" : "#1a2a3e"} />
})}
{/* 正解国の centroid に国名ラベル */}
const centroid = pathGen.centroid(target)
<text x={centroid[0]} y={centroid[1] - 10}>...</text>
ISO numeric ID で完全マッチング、 正解時のみ amber に塗って国名ラベル表示。
やっていない / これからの IMPROVE
- 全 195 ヶ国 (大陸単位拡張、 アフリカ全国 / ヨーロッパ全国 等)
- localStorage 永続化 + 学習進捗グラフ
- ハードモード (国旗の一部だけ表示 / モノクロ化 / ぼかし)
- 都市当て / 通貨当て / 時差クイズ / 国際情勢クイズ のモード追加
- 共有 URL でスコア自慢
- 連続正解バッジ (10 連続 / 50 連続 / 100 連続)
- Daily Challenge (毎日 1 ヶ国)
- マップクリックで国を選ぶ pin モード (GeoGuessr 風)
次の SHIP は何 thesis に振るか
Thesis Audit:
atlas-quest — インタラクティブ学習 (2本目)
hue-deck — ジェネレーター (2本目)
astro-cast — データ可視化 (2本目)
arcana-flip — 占い (2本目)
gift-cap — 計算ツール (3本目)
直近 5本で 5 thesis 別 (連続なし)。 シミュレーター / 計算ツール 4本目 / on-device ML 系新角度 等が候補。 PV 重視なら 副業税金 / 育休給付金 (マネー計算機シリーズ続行)、 wow 重視なら 手書き数学ソルバー / お絵描き物理 / WebGPU フラクタル。
[ ./next_action ]
読んだら、 AtlasQuest を実際に動かす。
この開発ログは AtlasQuest をどう作ったかの記録です。 読み終わったらそのままサービス本体へ戻って、 実物で価値を確かめてください。