▍AI Dev Lab
AtlasQuest

AtlasQuest ができるまで — 国旗クイズと世界地図で学ぶ

国旗クイズと世界地図の学習ツールの開発ログ。 d3-geo と world-atlas で地図を描き、 60 か国の国旗を出題する仕組みと、 空港の発着案内板を模した画面をどう組んだかを記録しています。

·decision改善·stage公開中

AtlasQuest は、 国旗 + 世界地図 クイズ。 主要 60 ヶ国 (大陸網羅) を 4 モード (国旗→国名 / 国名→国旗 / 国旗→大陸 / 国旗→首都) × 3 レベルで出題、 正解時は d3-geo の世界地図で該当国を amber に highlight。 ラボ 26本目、 インタラクティブ学習 ジャンル 2本目 (ToneQuest = 音感 に続く)。

#なぜこの形にしたか

直近 5本に学習ゼロ。 作ろうと決めていた 8 ジャンルは 7/8 で、 シリーズ深掘り基調。 候補:

  • 国旗クイズ (採用、 SEO 巨大 + 教育)
  • タイピング練習 (ありふれ)
  • 暗算 (弱)
  • WebGL シェーダー学習 (ShaderToy 圧倒)
  • 漢字クイズ (中庸)

選んだ理由:

  • 「国旗 クイズ」「世界地図 クイズ」 は子供向け教育 + 受験生 + 一般教養層で SEO ボリューム巨大
  • 既存大手 (Sporcle / GeoGuessr) は英語 UI / アカウント要 / 重いビルド
  • 「 + 日本語 + 即動く + 世界地図ハイライト」 で差別化
  • d3-geo + topojson + world-atlas + flagcdn という地理スタック (まだラボ未使用) を投入できる

#見た目をどう決めたか

直近 5本の 見た目 を書き出す:

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 (玩具箱)

題材 「世界 / 国旗 / 地図 / クイズ」 → モチーフ 候補:

  • 古地図 (wiki-orbit と被るので避ける)
  • 学校の地理教室 (黒板 モチーフ、 弱め)
  • 空港 departure board (LED + amber、 旅行感) ← 採用
  • 新聞 / 報道 (グレー黒赤、 既存と被るリスク)

採用 3 要素:

  • 配色: dark navy #0c1828 + amber departure #ffb84a + safety yellow #ffe14a + alert red #ff5050 + steel gray #3d4554 + paper white
  • astro-cast (midnight space + sun emission) と surface 黒は近いが、 配色 = amber + safety yellow + alert red の departure board 系で完全別軸
  • モチーフ: 空港 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

ts
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

ts
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 Dev Lab は介在しない。

#4 モードのロジック

ts
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

tsx
{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 に塗って国名ラベル表示。

#まだやっていないこと

  • 全 195 ヶ国 (大陸単位拡張、 アフリカ全国 / ヨーロッパ全国 等)
  • localStorage 永続化 + 学習進捗グラフ
  • ハードモード (国旗の一部だけ表示 / モノクロ化 / ぼかし)
  • 都市当て / 通貨当て / 時差クイズ / 国際情勢クイズ のモード追加
  • 共有 URL でスコア自慢
  • 連続正解バッジ (10 連続 / 50 連続 / 100 連続)
  • Daily Challenge (毎日 1 ヶ国)
  • マップクリックで国を選ぶ pin モード (GeoGuessr 風)

[ ./next_action ]

読んだら、 AtlasQuest を実際に動かす。

この開発ログは AtlasQuest をどう作ったかの記録です。 読み終わったらそのままサービス本体へ戻って、 実物で価値を確かめてください。

[ ./related_logs ]

関連する開発ログ

all logs →
ShadowTwin

立体パズルの別解を作る:同じ影と最少の積み木

ShadowTwinの開発記録。3方向の図から別々の最少配置を2つ探す仕組み、5問の独立全探索、スマホの横並び比較、保存・再編集と入力検査を解説します。実照明の計算や能力診断ではありません。

read log →
SlitCard

スリットアニメーションを作る:4コマの合成と透明原稿の設計

SlitCardの開発記録。4コマの帯を交互に合成し、すき間と黒帯で別のコマを見せる仕組みを解説。同縮尺の台紙・透明シートSVG、50mm確認線、手動プレビュー・初期非表示、再編集と実出力検査を整理します。

read log →
WindowLight

日当たりシミュレーションを作る:窓の光を床へ投影する幾何モデル

WindowLightの開発記録。太陽位置近似から窓の4隅を床へ投影し、凸多角形を部屋で切り取る設計を解説。国立天文台の16時刻との限定照合、大気差・低高度・実際の採光との違い、SVGと設定の再編集を整理します。

read log →
GridLights

電源構成の比較を作る:割合と実量を100個の電球で読み解く

電源構成比較GridLightsの開発記録。12か国の年次発電データを最大剰余法で100個の電球に変換し、割合とTWhを比較する設計を解説。欠損を0補完しない7分類、予想と実値、出典付きSVGと実データ検証を整理します。

read log →
SoundLoom

音のお絵かきを作る:実WAVから絵を測り直す設計

音のお絵かきの開発記録。描画を正弦波のPCMとWAVへ変換し、保存音声の周波数をGoertzel法で測って比較する仕組みを解説。音量・測定窓・量子化の限界と、編集・離脱時の古い結果を抑止する検証を整理します。

read log →
MazeLoom

宝探し迷路を作る:寄り道まで含めた最短ルートの探索

宝探し迷路の開発記録。通路を木として生成し、現在地と3つの宝の取得状態を組み合わせて最短ルートを探す仕組みを解説。問題コードの版固定、画面と解答付きPDFの一致、手数と印刷の検証を整理します。

read log →