開発ブログ

BLOG

練習の統計に、1 年のカレンダー・週の目標・レベルを加えた

統計を作り直し、練習した日を 1 年分並べたカレンダー、週ごとに数える連続記録(ストリーク)、週の目標、レベルとクエスト、節目のお祝いを加えた。統計でできることを順に紹介し、作る途中で直した不具合を 2 つ書く。

公開 2026年10月8日

Metronome.fm の統計を作り直しました。これまでの統計で見られたのは、週ごとの練習時間と、設定ごとの内訳だけでした。今回、1 年分の練習を振り返れる「1 年」のタブを加え、週の目標やクエストなど、練習を続けるための仕組みも用意しました。

統計は、メニューの「統計チャート」で開きます。自分の記録を見るにはサインインが要りますが、無料のアカウント(Free プラン)ですべて使えます。

統計チャートの 1 年のタブ。番号 1 は 1 年のタブ、番号 2 は練習のレベル(Lv. 26)、番号 3 は今週のクエストの 3 つの項目
統計チャートの 1 年のタブ(サインイン前に出すサンプルの数字)
  1. 新しく加えた 1 年のタブ。これまでの週ごとのグラフは隣のタブに移した
  2. 練習のレベル。練習した時間とクエストで上がる
  3. 週のクエスト。月曜に入れ替わる

この記事では、統計でできることを順に紹介します。最後に、作る途中で見つけて直した不具合を 2 つ書きます。

1 年分の練習カレンダー

1 年のタブの中心は、練習カレンダーです。GitHub で開発の活動を表す、通称「草」のグラフと同じ形にしました。1 マスが 1 日で、1 年分(53 週)を並べています。長く練習した日ほど濃くなり、マスを押すとその日の練習時間が出ます。

練習カレンダー。番号 1 は少から多までの 5 段階の凡例、番号 2 はマスを押したときに出る日付と練習時間(2025年10月26日(日)・22m)
1 年分の練習カレンダー
  1. 濃さの段階。境目は 5 分・15 分・30 分で固定している
  2. マスを押すと、その日の練習時間が出る

濃さの境目は、5 分・15 分・30 分に固定しました。GitHub は、その人の 1 年分の記録から境目を決めています。この方法だと、長く練習した日が 1 日あるとほかの日が薄くなり、同じ 20 分でも人によって色が変わります。練習時間は「何分やったか」がそのまま意味を持つので、決まった分数で区切ることにしました。

境目の値は、Free プランで鳴らせる時間(1 日 20 分)から決めています。Free でも、記録のない日を除いた 4 段のうち短いほうから 3 段目まで届き、いちばん濃い段は 30 分を超える長い練習の色になります。

カレンダーの上には、これまでの合計の練習時間、今週の練習時間(先週との差)、直近 30 日に練習した日数と、練習した日 1 日あたりの平均の練習時間も出します。

週で数えるストリーク

続けて練習した期間(ストリーク)は、日ではなく週で数えます。週(月曜始まり)に 1 日でも練習すれば、ストリークが続きます。

統計の要約の欄。番号 1 は WEEK STREAK(18 週)と BEST STREAK(31 週)
週単位のストリーク
  1. 今続いている週の数と、これまでの最長

楽器の練習には、休む日があって当たり前です。日で数えると、1 日休んだだけで記録が 0 に戻ります。記録が途切れると、続ける人が減ることもわかっています。運動について調べた Silverman と Barasch の研究(2023 年)では、記録が途切れていない人は約 66% が次の運動を選び、途切れた人では約 58% に下がりました。週で数えれば、休んだ日があっても、その週に 1 日練習していれば記録は途切れません。Strava・Simply Piano・Yousician も、ストリークを週で数えています。

今週まだ練習していなくても、週が終わるまでは、先週までのストリークが途切れていないものとして数えます。月曜の朝に開いたら 0 になっていた、とはなりません。

週の目標

週の練習時間の目標を、30 分から 7 時間のあいだで決められます。決めると、1 年のタブに今週の進み具合と、目標まであとどれだけかが出ます。目標はアカウントに保存するので、ほかの端末でも同じです。

レベルとクエスト

クエストは、週に 3 つ出る小さな目標です。「3 日練習する」「合計 60 分練習する」など 8 つの候補から、週と利用者ごとに 3 つを選び、月曜に入れ替えます。どれも Free プランの時間で届くものにしています。

練習した時間で、レベルが上がります。経験値が入るのは、練習したとき(1 分で 10 XP)と、クエストを達成したとき(その報酬)です。レベルは下がらず、上がるにつれて「ビギナー」「リズムキーパー」などの呼び名が変わります。今のレベルは、アプリのメニューにあるアカウント欄にも出ます。

節目と祝い

累計の練習時間(1 時間・10 時間・100 時間など)と、ストリーク(2 週・12 週・52 週など)には節目があります。達した節目と、次の節目までの残りを出します。

新しく節目に達したり、週の目標・レベル・クエストを達成したりしたときは、再生を止めたときに紙吹雪つきで知らせます。練習の最中には出しません。端末で動きを減らす設定にしている人には、紙吹雪を出しません。

週ごとのグラフ

これまでの週ごとの表示は、「週ごと」のタブに移しました。週の練習時間と練習した日数、日ごとの棒グラフ、設定ごとの内訳を見られます。

統計チャートの週ごとのタブ。番号 1 は日ごとの練習時間の棒グラフ、番号 2 は設定ごとの練習時間の内訳
週ごとのタブ
  1. 日ごとの練習時間。棒は設定ごとに積み上げている
  2. 設定ごとの内訳。行か棒を押すと、その設定を強調する

作る途中で見つけて直したこと

ひとつめは、記録の日付です。日本では、朝 9 時より前の練習が前日の記録に入っていました。記録を受ける Server Action が、日付をサーバーの時刻で決めていたためです。Vercel のサーバーは UTC で動いているので、日本時間の 0 時から 9 時までは、UTC ではまだ前日です。そこで、ブラウザの時刻帯を入れた Cookie(mfm_tz)で日付を決めるように直しました。この Cookie は、プランの上限を毎日 0 時に戻すのにも使っています。

// 利用者のブラウザの時刻帯での今日。Cookie が読めなければ UTC で数える
const recordedDate = recordedDateOf(
  periodKeyOf("day", new Date(), await getRequestTimeZone()),
);

ふたつめは、統計の画面のちらつきです。練習した時間は、鳴らしているあいだ 10 秒ごとに Server Action で記録しています。記録のたびに updateTag で統計のキャッシュを捨てるようにしたところ、開いている統計が 10 秒ごとに読み込み中の表示に戻るようになりました。Server Action で updateTag を呼ぶと、今のページ全体がサーバーで描き直されるためです(Next.js のドキュメントにも書かれています)。統計を読むのは、開いたときと、開いているあいだに記録できたときだけです。そのため、統計の取得をキャッシュするのをやめて、updateTag も呼ばないようにしました。

この記事を共有

X でポストはてなブックマーク