PRODUCT NOTE / PRD

Dotpile

積んで、崩して、また積む。
この文書は「何ができるか」ではなく、同じ 1 つのものに複数の意味を持たせると決めた理由と、その決めを守るために作った仕掛けの記録です。

ステータスWeb / Android は nzw.jp から直配布中(v1.1.2 build 8。iOS は App Store へ提出済み)
現行バージョンv1.1.2(build 8)
リリース日未定(2026 年 10 月中としていた予定を外した)
プラットフォームAndroid / ブラウザ版(iOS は未リリース。App Store へ提出済みで審査待ち)
収録17 ジャンル 3,154 問/誤答の一行 9,462 件/完成図 36 枚
対象ユーザーすきま時間に何か覚えたいが、点数だけ出る問題集では続かない人
出自Engly で踏んだ設計上の失敗を、最初から潰した状態で作り直したもの
最終更新2026-10-10
関連リンク プロダクトページ ・ ブラウザで遊ぶ ・ 更新履歴 ・ Engly ・ 開発ノート一覧
TL;DR

ひとことで

指標を増やすかわりに、1 つのものに意味を重ねた。ドットの山が、得点であり、残り体力であり、どこまで進んだかの表示でもある。

スコアの数字もライフのハートも置いていない。「画面に指標を足したくなったら、まず山に持たせられないかを考える」を規約にしてある。

Decision Log

主要な意思決定ログ

v1.1.22026-09-21 ジャンルの升目を本の形にし、厚みは影ではなく背とずらしたページの束で出した
DECISION

ホームのジャンル升目を、左に背・右下にページの束が覗く「本」の形にした。影と新しい色は使わない。

背は既存の補助色、束は地の色に罫線を 1 本通すだけで、表紙と束をずらしたぶん右上と左下が欠けて外形が四角でなくなる。背と束が食う 10pt は表紙の内側の余白を詰めて取り返し、升目の高さは変えなかった。

WHY / 仮説

称号はジャンルを 1 つずつ制覇するほど上がる数え方にしてある(17 ジャンルのつまみ食いを勧めないため)。なのに升目はほかのカードと同じ四角で、「1 冊を終わらせる」という単位が見た目に無かった。

ジャンル=問題集 1 冊に見えれば、踏破の帯が「その本をどこまで解いたか」として読める。
厚みを影で出すのはデザインの決まり(罫線と面の差だけで区切る)に反する。

代わりに外形を欠けさせて、カードではなく物に見せた。

RESULT

升目の横幅は 3 列で 100pt ほどしかなく、背と束はそのまま名前の幅を削る。

いちばん多い 390pt 幅で 17 ジャンルの名前がすべて 1 行に収まることをテストで押さえた(背や束を太らせると、6 文字の名前から 2 行に折れ始める)。

明るい設定・暗い設定の両方で、背と束が見分けられることを確かめた。

v1.1.1 build 62026-09-21 APK 版に更新の通知を入れ、署名は新しい鍵に替えずに v1.0.0 からの鍵を控えて固定した
DECISION

engly や Certly と共通の更新の仕組み(nzw_app_updater)を入れ、APK 版は起動時に update.json を 1 回読んで新しい版を知らせるようにした。

設定画面に「更新を確認」は置かない。署名は、専用の鍵を新しく作る案をやめ、v1.0.0 から配ってきた APK を署名していた鍵(Android の開発用の鍵)を手元に控えて固定した。

鍵が無いときは、そのときの Mac の鍵に黙って落とさず、ビルドを止める。

WHY / 仮説

きっかけは「engly と同じように、APK 版もアプリの中で更新できるか」という問い。調べると Dotpile は更新を知らせる手段を持っておらず、配った人は更新履歴を見に来ない限り古い版のままだった。


もう一つ見つかったのが署名で、リリースがプロジェクトを作ったときの初期設定のまま、ビルドした Mac の開発用の鍵で署名されていた。

この鍵は Mac ごとに違うので、Mac が変わった日に上書き更新が通らなくなる。最初は専用の鍵に替えるつもりだったが、替えると利用者全員にアンインストールを頼むことになり、そのとき踏破・勲章・称号が消える。

このアプリで記録が消えるのは、山を 1 から積み直させることと同じ。鍵の出自より、記録が残ることを取った。

RESULT

エミュレータで build 5 に 1 問ぶんの記録を作り、build 6 を上書きしても踏破 1 と「続きから」が残ることを確かめた。

更新のお知らせから、ダウンロード・インストールまでも通った —— と思っていたが、これは debug の APK での話で、配った release の APK では通信の許可が無く動いていなかった(下の「うまくいかなかったこと」。v1.1.2 build 8 で直した)。


また通知の仕組みは build 6 から入ったものなので、build 5 以前の人には届かない。その人たちには今回だけ、更新履歴から入れ直してもらう必要がある。

v1.1.12026-09-20 難易度をジャンルの中の相対順位で付けるのをやめ、ジャンルをまたぐ物差しに置き換えた
DECISION

level の意味を文章で決め(初級=そのジャンルを勉強していなくても、生活やニュースで目に入る範囲で答えられる)、その物差しから外れる 36 問を中級へ降ろし、足りないぶん 337 問を新しく書いた。

初級より下の段を作る案は採らなかった。

WHY / 仮説

きっかけは「全体的に問題が難しい」という申告。数えると初級は全体の 17% しかなく、しかも「計算と公式」の初級 20 問のうち 9 問が三角関数だった(sin 30°、cos 90°、sin²θ+cos²θ=1)。

原因は基準がどこにも書かれていなかったことで、結果としてジャンルの中で相対的に付いていた —— そのジャンルでいちばん易しい問題が、他のジャンルと比べて何であろうと初級になる。

だから「世界の首都」の中級が「チェコの首都は?」で、「計算と公式」の初級より易しいという並びが起きていた。
入門レベルを新設する案も検討したが、基準が無いままでは 4 段に同じばらつきが再現されるだけだと判断した。

段を増やすと解放の梯子が 1 段伸び、称号のマスが 51 から 68 に増えて、すでに制覇していた人の記録が剥がれる副作用もある。

RESULT

3,154 問のうち 813 問(26%)が初級になった。

混ぜて出すコースは問題数の比率のまま引いていたので 10 問中 2 問も初級が来なかったが、ジャンルを均していた仕組みを難易度にも通して 初級 4・中級 3・上級 3 で配るようにした。


「産地と順位」だけは 11% で止めた。りんご=青森は常識でも、こんにゃくいも=群馬はそうではない。

いちばん易しい問いでも常識にならないジャンルがあると認めて、数を合わせるために基準を曲げるのはやめた —— 初級の意味が壊れると、易しくした意味がなくなる。

v1.1.12026-09-20 「踏破は単調に増えるから剥奪は起きない」が嘘になり、解放のしきい値を半分から 1 割に下げた
DECISION
次の難易度が開く条件を「一つ前の難易度をその範囲で半分踏破」から「1 割踏破」に変えた。
WHY / 仮説

解放を保存しないと決めたときの根拠は「踏破(一度でも正解した問題の数)は単調にしか増えないので、数え直しても剥奪が起きない」だった。

これは問題数が固定のときだけ成り立つ。要る数は割合なので、問題を足すと分母が増えて上がる。

初級を 337 問足す計算をしたところ、「国のかたち」では中級が開く条件が 9 問から 31 問へ跳ね上がり、すでに中級を開いていた人がそれを失うところだった。

全ジャンルで剥奪が起きない上限を計算すると 0.148 だったので、下回る 1 割にした。

RESULT

開いていた段が閉じることはなくなった。いちばん厳しかったケース(初級 17 問・踏破 9 問の状態から初級を 61 問に増やす)をテストに固定し、コメントにも「問題を足す回はここを見る」と書き残した。


副作用として梯子は緩くなり、1 セット解けばたいてい次が開く。ただし初級をやさしく・多くした以上、842 問の半分を踏破しろというのはそもそも遠すぎたので、これは元に戻すべき緩みではないと考えている。

v1.1.12026-09-20 間違えられる回数を、難易度で変えた
DECISION
10 問なら 初級 4・中級 5・上級 6 回。難易度を混ぜて出すコースはいちばん上の段に合わせる。
WHY / 仮説

きっかけは「3 問失敗でゲームオーバーは難しいかも」という申告。それまではどの難易度でも問題数の 3 割で固定していたが、難しい段ほど間違えやすいので、同じ割合にすると上級だけが早く終わる。


「実際に出た 10 問の難易度を数えて平均する」案も考えたが採らなかった。同じ「ランダムクイズ」でも回ごとに体力が変わることになり、崩れ方が読めなくなる。

出す前に決まっている値(選んだ難易度)から決めて、あとから決め直さないことにした。

RESULT

山の高さは変わっていない。1 問あたりの粒を減らし、最初の蓄えを増やして辻褄を合わせている(満点のときの高さを先に決めてから逆算しているため)。


この変更で、スクリーンショット用のツールが静かに壊れていたのが見つかった。ゲームオーバー画面を撮るために誤答を 3 回入れる作りだったが、初級の体力が 4 回になったのでゲームオーバーに届かなくなっていた。

演出を数で決め打つ場所は、体力を変えたら一緒に直す必要がある。

v1.1.02026-09-13 「すべて」のボタンを畳み、出す範囲を重ならない 3 つにして複数選べるようにした
DECISION

難易度と出す範囲をいくつでも ON にできる升目にし、「すべて」の升目を置くのをやめた。あわせて出す範囲の定義を組み替え、はじめて(まだ出ていない)/まちがえた(出たが正解していない)/正解済の重ならない 3 つにした。

従来の「未正解」は はじめて+まちがえた の 2 つで表す。

WHY / 仮説

きっかけは「未回答と不正解の 2 種類を出したい」という申告。従来の「未正解」は「はじめて」を内側に含んでいたので、そのまま複数選択にすると 2 つ押しても片方だけと同じ結果になり、押した意味が消える。

重なりを消すか、重なったまま OR にするかで実装が変わるので先に決めた。重なりを消すほうを選んだのは、申告の言い方(未回答「と」不正解)がそもそも排他を前提にしていたため。

ただし勲章と称号が使う「一度でも正解した」の定義だけは動かせない —— そこを崩すと 踏破 + 未正解 = 問題数 が成り立たなくなり、保存しない設計の根拠が消える。

3 つとも isSolved / isUnseen から導く形にして、はじめて ∪ まちがえた が 正解済 のちょうど裏側になるよう組み直した。

RESULT

「漢字の初級と中級を、まだ出ていない問題とまちがえた問題だけ、20 問ランダムで」まで作れるようになった。入口は 1 つも増えていない(升目は 3 つのまま、「すべて」が消えたぶん 1 つ減った)。


思わぬ副産物として、難易度の解放から特別扱いが 1 つ消えた。以前は「『すべて』は全部の難易度が開いてから開く」という規則を別に持っていたが、複数選択なら閉じた段はそもそも押せないので、全部 ON にできるのは全部開いたときだけになる。

LevelUnlock から null 分岐を削除した。
逆に、この作業中に既存の穴が 1 つ見つかった。

成績の集計が届くまでの間、空の集計を「全部開いている」と読んでしまい、閉じているはずの難易度が「開いた」と表示されて押せていた。

端末では一瞬だが、起動の遅いブラウザ版では見えていた。集計が空のときは初級だけ開いている扱いに直した。

v1.1.02026-09-13 アイコンだけは「中身と同じ作り方」をやめ、手で決めた 1 枚にした
DECISION
アイコンの生成を、本編と同じ砂山のシミュレーション(乱数で 38 粒落とす)から、左右対称の山と、その上から降ってくる 1 粒を手で置いたドット絵に変えた。
WHY / 仮説

きっかけは「山なのか、うんこなのか分からない」という申告。作り方は正しかった —— 中身と同じ砂山で積めば、アプリを開いたときの印象とずれない、という理屈で作っていた。

だが乱数で積むと稜線が片側へ流れ、不定形の塊になる。アプリの中では 25 列あるので不揃いが「積もった感じ」に見えるが、アイコンは 9 列・60pt にしかならないので、同じ不揃いが単なる歪みになる。

「中身と同じ作り方であること」より「その大きさで何に見えるか」が先に来ると判断した。

RESULT

対称にしただけで「意図して置いた形」に見えるようになった。三角だけではただの図形なので、上から降ってくる粒を 1 つ足してアプリの動き(正解すると粒が積もる)を持たせている。

粒と山のあいだは 1 行空ける —— 詰めると山の一部に見える。
列は 9 のままにした。

11 列にすると 1 マスが 5.5pt を切り、降ってくる粒がゴミに見える。180 / 120 / 80 / 60px に縮めて比べてから決めた。

tool/build_icon.py は形の検算(正方形・行の長さ・使える文字)を持ち、実行すると ASCII で形を出す。

端末に焼いてから気づくのを避けるため。

v1.0.0 build 22026-09-08 「白黒だとモチベーションが上がらない」に、色ではなく面の反転で答えた
DECISION
有彩色を増やさない。達成の瞬間(称号・勲章・完成図・開いたばかりの難易度・10 連正解)を地と文字を入れ替えた面で際立たせる。あわせて効果音と手触りを入れ、どちらも設定で切れるようにした。
WHY / 仮説

きっかけは「白黒の画面だとモチベーションが上がらない」という申告。ただし「モノクロが動機づけを下げる」という主張に強い根拠は無い(色彩心理学は再現性が低く、達成課題では赤がむしろ成績を下げるという報告すらある)。

そこでコードを数えたところ、原因は色ではなかった —— AnimationController がプロジェクト全体で 0 件、効果音 0 件、触覚 1 件、ホーム画面は 1 フレームも動かない。

達成の瞬間に何も起きていなかった。有能感は「上がったこと」ではなく「上がったと分かること」を経由して効く。

色を 3 つ目にすると correct / wrong = 正誤 の 1 対 1 が崩れ、「緑は正解、金は達成」を覚え直させることになる。

RESULT

白い面が並ぶ中で 1 枚だけ黒地になるので、称号や勲章を取った回が一目で分かるようになった。色トークンは 1 つも増えていない。

使ってよい場所を 5 つに限った —— 常に出るものに使うと、その 1 枚が効かなくなるため。
うまくいかなかったこともある。

選択肢を画面の下に貼り付けた結果、山と問題文のあいだに余白が空いたので「余白は山で埋める」を試したが、成り立たなかった。

1 粒の大きさは横 25 列で決まっているので、縦だけ伸ばしても粒は大きくならず、行間が開いて山が縞に見える。行間を粒に合わせて段を増やすと、今度は空の地紋ばかりになって山が底に沈む。

余白は余白のまま残し、その事実を _kMountainRatio の注記に書いて次に読む人が同じ道を歩かないようにした。

v1.0.0 build 22026-09-08 読むものはスクロール、押すものは画面の下に貼り付ける
DECISION
クイズ画面の 4 択を画面の下に固定し、送れるのは問題文と解説だけにする。図版の 2×2 は貼り付けた枠に合わせて縮める。答え合わせに移ったら選択肢はスクロールへ戻し、解説に場所を譲る。
WHY / 仮説

都道府県の形(図版の問題 + 文字の 4 択)で4 つ目の選択肢が画面の外に出ていた。

縦を数えると、iPhone の使える 759pt に対して固定部分だけで 238pt を取り、残り 521pt に 480〜690pt を入れようとしていた。

読むものが隠れるのは送れば済むが、押すものが隠れるのは行き止まりなので、扱いを分ける必要がある。

RESULT

文字の 4 択でも図版の 2×2 でも、4 つとも画面に収まるようになった。長い問題文・iPhone SE の画面・図版の 2×2 の 3 通りでテストが自動で見張っている(quiz_layout_test.dart)。

あわせて、結果画面の「ホームへ」が 1 つ戻るだけでジャンル画面に落ちていたのを、ホームまで戻すよう直した。

v1.0.0 build 12026-09-06 問題に「出典」を持たせ、答え合わせの画面に出すことにした
DECISION
統計から作った問題に reference(資料名と年、URL)を持たせ、解説の下にリンクとして出す。常識で答えられる問題には付けない。
WHY / 仮説

きっかけは「埼玉県は 7 つの都県と接する」という解説を疑われたこと。実際には正しかった(長野県と三国峠で接する)が、そのとき「どこの数字か」を答えられなかった。

順位を問う問題は年で答えが入れ替わるので、出典が言えないものは検証も修正もできない。

RESULT

産地と順位の 157 問すべて、山と湖の 87 問に出典を付けた。あわせて統計の一次資料(農林水産省・国土地理院・総務省統計局)から数字を機械で抜き直し、手で書き写す工程を無くした。

官公庁の統計は公共データ利用規約で商用利用できるが出典の記載が条件なので、この対応は有償化の下地にもなっている。

v1.0.0 build 12026-09-06 2 位を問う問題は「下の順位と 8% 以上離れているとき」しか作らない
DECISION
順位の問題を事実テーブルから生成するとき、1 位を問う問題は全項目、2 位とトップ 3 を問う問題は差が十分あるものだけ作る。判定は生成側に置き、人が選ばない。
WHY / 仮説

日本なしの収穫量は 2 位が茨城と栃木で同率、ピーマンは 3 位と 4 位が同値だった。こういうものに「2 位はどこ?」と聞くと、統計が新しくなった瞬間に正解が入れ替わって嘘になる。

作らないことをデータ側で決めておかないと、問題を足すたびに人が判断することになる。

RESULT
63 項目のうち、2 位を問えるものは 48、トップ 3 を問えるものは 46 に落ち着いた。落とした分は「1 位を問う問題」として残っている。
v1.0.0 build 12026-09-05 誤答の選択肢すべてに「それが何なのか」を書くことを必須にした
DECISION
4 択の外れ 3 つに、5〜60 字の一行を必ず付ける。付いていない問題はテストで落ちる(TC-QD-015)。正解には付けない(解説が同じことを言うため)。
WHY / 仮説

消去法で当たっても、次に形を変えて出されたら解けない。「コルドバ」がアルゼンチンの別の都市なのか、そもそも実在しない語なのか分からないままだと、間違えた選択肢は覚えようがない。

1 問から 4 つ学べる形にしたかった。

RESULT
8,391 件。問題を足すコストは上がったが、答え合わせの画面の情報量が 4 倍になった。生成ジャンルでは事実テーブルから機械的に組み立てている。
v1.0.0 build 12026-09-05 危険度を「残りの割合」ではなく「残りの回数」で決めた
DECISION
山が痩せて警告色に寄る条件を、残り体力の割合ではなくあと何回まちがえられるかで判定する。
WHY / 仮説
間違えられる回数は問題数の 3 割にしてあるので、100 問なら 30 回ある。割合で判定すると、まだ 15 回残っているのに「半分使ったから赤い」ことになり、警告として意味を持たない。
RESULT
10 問でも 100 問でも、赤くなるのは「あと数回」のときになった。ウィジェットごとに赤くせず、AppPalette.atRisk だけで作る規約とセットにしてある。
v1.0.0 build 12026-09-03 「間違えた問題」の判定を 1 か所に閉じた
DECISION
苦手かどうかの判定は domain/review.dart の Review.needsReview だけを通す。ほかの場所で条件を書かない。
WHY / 仮説
Engly は累積誤答と直近誤答という2 つの定義が別々の場所にあり、復習の入口ごとに出てくる問題が違うという壊れ方をした。どちらが正しいかを議論する前に、まず 1 つに減らす必要があった。
RESULT
苦手クイズ・統計画面・結果画面が同じ判定を見るようになった。定義を変えたいときも直す場所が 1 つで済む。
v1.0.0 build 12026-09-05 完成図は「全問正解した回」だけに出す。難易度では分けない
DECISION
ドット絵の ID を <ジャンル>:<short | long> にした。難易度は入れない。まちがえずに解ききった回にだけ、積み上がった山がその絵に変わる。
WHY / 仮説

山の形が毎回同じでは、集める理由も狙う理由も生まれない。一方で難易度を ID に入れると 3 倍の 78 枚になり、手で描ききれない。

1 マスが 14px 程度にしかならないので、線 1 本ぶんの模様は潰れて読めず、量産もできない。

RESULT
36 枚(17 ジャンル × 短い・長い + 全ジャンル 2 枚)。太い塊と、抜きで作る 1〜2 か所の特徴だけで描く方針に落ち着いた。
v1.0.0 build 12026-09-06 問題の中身を確かめる画面を、テストとは別に作った
DECISION
2,797 問を 1 件ずつ送り読みして OK / NG と理由を付ける画面(tool/review/)を作り、nzw.jp に置いてスマホから進められるようにした。
WHY / 仮説

テストは形式(ID の一意性・誤答が 3 つ・図版コードの実在)までしか見られない。「その答えは本当に正しいか」「解説はそれを説明できているか」は人が読むしかない。

そして 2,000 問を PC の前で読み切ることはない。

RESULT

判定は文言の指紋(FNV-1a)で管理していて、判定したあとに問題を直すとその問題だけ「要再確認」に戻る。ID は直しても変わらないので、ID だけを見ていると古い OK が残り続ける。

機械で確かめられる生成ジャンルは、ボタン 1 つでまとめて対象外にできる。

v1.0.0 build 12026-09-04 問題数の厳密一致をテストに書かないと決めた
DECISION
問題データのテストは下限だけを見る(1 ジャンル 100 問以上、ジャンル × 難易度で 10 問以上)。「ちょうど N 問」は書かない。
WHY / 仮説
Engly は「ちょうど 393 問」と書いていて、問題を足すたびにテストが落ち、やがてテストごと放置された。壊れてほしいのは件数が変わったときではなく、遊べなくなる性質が壊れたときだった。
RESULT
1,512 問から 2,084 問へ 572 問足したときも、テストは 1 行も直さずに通った。かわりに「同じ問いが二度出てこない」「誤答すべてに一行がある」など、壊れると困る性質を全問について見ている。
Failures

うまくいかなかったこと

Milestones

これまでの歩み

方針2026-10-10

リリース日を未定にする(2026 年 10 月中の予定を外した)/3,154 問の中身をレビュー画面で見直し終えるまで、日付を置かない

v1.1.22026-09-21

ジャンルの升目を本の形に(背とページの束、影なし)/更新のお知らせに要る通信の許可を足した(build 8。build 6・7 には無かった)

v1.1.1 build 62026-09-21

APK 版に更新の通知(起動時に update.json を読む)/署名鍵を v1.0.0 からの鍵に固定/問題と遊び方は build 5 と同じ

v1.1.12026-09-20

初級の基準をジャンル横断で決め直して 337 問追加(3,154 問)/混ぜて出すコースで難易度を均す/解放を 1 割に/体力を難易度べつに

v1.1.02026-09-13

出す範囲を重ならない 3 つに組み替えて複数選択に/「すべて」の升目を廃止/アイコンを対称の山に描き直し

v1.0.0 build 22026-09-11

ごほうびを面の反転で立てる(色は増やさない)/効果音と手触りを追加(設定で切れる)/選択肢を画面の下に貼り付け、4 つとも収まるように

v1.0.0 build 22026-09-08

ジャンルをテーマ別 5 ステップにまとめる/難易度を一つずつ開く梯子に/称号を「1 ジャンルを丸ごと終わらせる」10 段に

data2026-09-07

宇宙と天体を追加して 17 ジャンル 2,797 問/誤答の一行 8,391 件/完成図 36 枚

v1.0.0 build 12026-09-06

Android・Web を nzw.jp で先行配布/16 ジャンル 2,084 問/統計の問題に出典リンク/完成図 34 枚

data2026-09-06

産地と順位・小説と作家・山と湖・花の名前を追加(1,512 → 2,084 問)/数字は官公庁の一次資料から機械で抽出

review2026-09-05

問題レビュー画面を公開(文言の指紋で「要再確認」に戻す/スマホから進められる)

art2026-09-04

全問正解した回だけ山がドット絵になり、コレクションに溜まる

data2026-09-03

全ジャンルを 100 問以上に(305 → 1,512 問)/問題数を選べるようにし、どのコースでも中断・再開できるように

Roadmap / Open Questions

未解決のこと