- ブラウザ上のキー入力・クリック・スクロールなど7種類の操作を自動でポイント化する仕組みを構築した
- 1日28段階でドット絵モンスターが成長し、翌日リセットされる育成サイクルを設計した
- HTMLプロトタイプからChrome拡張に移行し、どのサイトでもバックグラウンド計測できるようにした

日々のPC作業、どれくらい集中できているか可視化できたら面白いと思いませんか。タイピング量やクリック回数をポイントに変換して、キャラクターが育っていく仕組みがあれば、単調な作業にもゲーム感覚で取り組めるはずです。スケジュールとタスク管理だけでは、モチベーションが保てないので、ゲーミフィケーションを取り入れました。
この記事では、ブラウザ操作を自動計測してドット絵モンスターを育てるChrome拡張 HARD WORK MONSTER を実際に作った過程を紹介します。設計の考え方からChrome拡張のインストール方法まで、振り返りを兼ねて記録に残しておきます。
どんなアプリを作ったのか?全体像の紹介
ブラウザ上の操作をリアルタイムで計測し、ドット絵モンスターが28段階で成長するChrome拡張機能です。


コンセプトは作業量の見える化。日々の仕事をポイントに変換して、タマゴから孵化したモンスターが手足を生やし、最終的に王冠をかぶった伝説のモンスターに成長します。翌日にはリセットされ、またタマゴからスタートするサイクルです。

作業したらキャラが育つって、たまごっちみたいで楽しいよね。サボるとずっとタマゴのまま…!
計測できる操作は7種類
| 操作 | 計測方法 | ポイント |
|---|---|---|
| キー入力 | 50回ごとにバッチ付与 | +1 PT |
| Enterキー | 2倍カウント(25回で+1PT相当) | +1 PT |
| クリック | 20回ごと | +1 PT |
| スクロール | 30回ごと | +1 PT |
| マウス移動 | 200回ごと | +1 PT |
| タブ切替 | 即時付与 | +2 PT |
| コピー・ペースト | 即時付与 | +2 PT |
これに加えて、30分連続集中で+8PT、60分連続で+20PT、9時前に作業開始すると早起きボーナス+15PTといった時間ベースのボーナスも組み込んでいます。
28段階の成長ステージ
モンスターの進化は作業時間に連動しています。1日14時間の作業でStage 28の最終形態に到達する設計にしました。
| Phase | Stage | 各段階の所要時間 | 見た目の変化 |
|---|---|---|---|
| Phase 1 | 1〜7 | 各25分 | タマゴ → ひび割れ → 孵化 |
| Phase 2 | 8〜14 | 各28分 | 目が開く → にっこり → 中サイズ |
| Phase 3 | 15〜21 | 各32分 | 手が生える → 足が生える → 立派に |
| Phase 4 | 22〜28 | 各35分 | ツノ → 王冠 → 伝説のハードワークモンスター |
序盤のPhaseほど進化が早く、後半になるほど時間がかかるようにしています。最初の25分で2段階ほど変化が見えるので、作業を始めてすぐに達成感を感じられるのがポイントです。
Chrome拡張のインストール方法
自作のChrome拡張は、Chromeウェブストアを経由せずにローカルから直接読み込む方法でインストールします。手順は3ステップで完了します。
Step 1:フォルダを準備する
ダウンロードしたZIPファイルを解凍し、任意の場所に配置します。フォルダの中身は以下のような構成になっているはずです。
hard-work-monster-ext/ ├── manifest.json ├── background.js ├── content.js ├── popup.html ├── popup.js ├── slime-renderer.js ├── icon48.png └── icon128.png
Step 2:Chromeのデベロッパーモードを有効にする
Chromeのアドレスバーに以下を入力して、拡張機能の管理画面を開きます。
chrome://extensions
画面右上にあるデベロッパーモードのトグルスイッチをONにしてください。これで自作の拡張を読み込めるようになります。
Step 3:フォルダを読み込む
デベロッパーモードをONにすると、画面左上にパッケージ化されていない拡張機能を読み込むというボタンが表示されます。これをクリックして、Step 1で解凍したフォルダを選択してください。
読み込みに成功すると、拡張機能の一覧に HARD WORK MONSTER が追加され、ブラウザのツールバーにアイコンが表示されます。アイコンをクリックするとモンスターのポップアップが開きます。
拡張の更新方法
ファイルを修正した場合は、chrome://extensionsの管理画面で HARD WORK MONSTER のカード右下にある更新ボタンをクリックしてください。その後、開いているタブをリロードすれば変更が反映されます。
なお、拡張を更新してもchrome.storage.localに保存されたデータは消えません。ポイントやストリークはそのまま引き継がれます。
開発の流れ:HTMLプロトタイプからChrome拡張へ
最初にブラウザで動くHTMLデモを作り、仕様が固まった段階でChrome拡張に移行する2段階の手順で進めました。
HTMLプロトタイプで設計を詰める
いきなりChrome拡張を作るのではなく、まずは単体のHTMLファイルでUIと仕様を固めました。実際に触りながら、ポイントバランスの調整やモンスターのドット絵デザインを何度も修正しています。
この段階ではSPACEキーで作業時間を30分スキップできるデモモードを入れておき、28段階の進化が自然に見えるかを素早く検証できるようにしました。
Chrome拡張のファイル構成と役割
| ファイル | 役割 | 動作タイミング |
|---|---|---|
| manifest.json | 拡張の名前・権限・ファイル構成を定義 | インストール時 |
| background.js | 1秒タイマー、ポイント計算、データ保存 | ブラウザ起動中ずっと |
| content.js | キー入力・クリック等を検知してbackgroundに送信 | 各ページを開くたび |
| popup.html / popup.js | モンスターの表示UI | アイコンクリック時 |
| slime-renderer.js | ドット絵のCanvas描画 | popupから呼び出し |
役割が明確に分かれている点がChrome拡張開発のコツです。content.jsがページ上の操作を検知し、background.jsがデータの集計と保存を担当します。ポップアップはあくまで表示専用で、データの参照しか行いません。
つまずいたポイントと解決策
開発中に遭遇した主なトラブルは、Chrome拡張特有のService Workerの制約でした。
alarmの最小間隔は30秒
当初、1秒ごとの作業時間カウントにchrome.alarmsを使っていました。しかし、Manifest V3ではalarmの最小間隔が30秒に制限されており、1秒タイマーが動作しません。
解決策として、setIntervalで1秒ごとのティックを実行し、alarmはService Workerのキープアライブ用としてのみ利用する構成に変更しました。
// 1秒ごとの作業時間カウント
setInterval(async () => {
const s = await loadState();
// ... 作業時間の加算やステージ判定
}, 1000);
// Service Workerが停止しないようにキープアライブ
chrome.alarms.create('keepAlive', { periodInMinutes: 0.5 });
初回起動時に離席中と判定される問題
初期状態でlastActにDate.now()を設定していたため、ユーザーが何も操作していないのにAFK判定のカウントダウンが始まってしまう問題がありました。
lastActの初期値を0にし、最初の操作があるまでタイマーを開始しないように修正して解決しています。
function newDayState() {
return {
// ...
lastAct: 0, // 初期値を0にして、操作があるまでカウントしない
// ...
};
}
content.jsの通信エラー
拡張を更新した直後、古いタブに残ったcontent.jsが無効なコンテキストでsendMessageを呼び出してエラーになるケースがありました。try-catchとlastErrorチェックで黙殺する対応を入れています。
try {
if (chrome.runtime && chrome.runtime.sendMessage) {
chrome.runtime.sendMessage({ type: 'activity', data }, () => {
if (chrome.runtime.lastError) { /* 無視 */ }
});
}
} catch(e) { /* 拡張がアンロードされた場合 */ }
データの保存と日次リセットの仕組み
計測データはchrome.storage.localに保存され、ブラウザを閉じても消えない仕組みです。日付が変わると自動でリセットされます。
background.jsの1秒タイマー内で現在の日付をチェックし、保存データの日付と異なっていれば前日の結果をストリークデータに記録してからリセットを実行します。
if (s.date !== todayStr()) {
// 前日の結果をストリークに保存
streakCache.days[s.date] = {
workSec: s.workSec,
cleared: s.dailyDone,
stage: s.stage,
};
// 新しい日の状態にリセット
stateCache = newDayState();
await saveState();
}
この仕組みにより、7日連続でデイリークリア(14時間達成)したかどうかをストリークとして追跡できます。ストリークデータは日付をキーにしたオブジェクトで、過去分も含めて保持される構造です。
カスタマイズしたくなったら
ポイントバランスや進化速度を変更したい場合は、background.jsの定数を書き換えるだけで対応できます。
たとえばデイリー目標を8時間に短縮したい場合、以下の2箇所を変更します。
// background.js と popup.js の両方で変更 const DAILY_GOAL = 8 * 3600; const STAGE_RATES = [850, 960, 1100, 1230];
AFK判定の閾値を30分に短縮したい場合はこちらです。
const AFK_THRESHOLD = 1800; // 3600(1時間)→ 1800(30分)
変更後はchrome://extensionsで拡張の更新ボタンを押し、開いているタブをリロードすれば反映されます。今回、仕様書も別途作成したので、どのファイルのどの行を変えればいいかはそちらを参照してください。
まとめ
- 7種類のブラウザ操作をバックグラウンドで自動計測し、ポイントに変換する仕組みを構築した
- HTMLプロトタイプで設計を固めてからChrome拡張に移行し、デベロッパーモードで3ステップのインストールが可能
- 定数の変更だけでポイントバランスや進化速度をカスタマイズできる設計にしたので、運用しながら調整が可能
実際に数日使ってみると、ポイントバランスの感覚は机上の計算とかなり異なることに気づくはずです。まずは現状の設定で使ってみて、自分の作業スタイルに合わせて閾値や目標時間を調整してみてください。
今回作成したHARD WORK MONSTERのChrome拡張ファイル一式と仕様書は、以下からダウンロードできます。
| ファイル | 内容 | ダウンロード |
|---|---|---|
| hard-work-monster-ext.zip | Chrome拡張ファイル一式(8ファイル) | ダウンロード |
| HARD_WORK_MONSTER_仕様書.md | カスタマイズガイド(どこを修正すればいいか一覧) | ダウンロード |
ZIPファイルを解凍したら、上記のインストール手順に従ってchrome://extensionsから読み込んでください。仕様書にはポイントバランス・進化速度・モンスター名など、各カスタマイズ項目の変更箇所がファイル名・コード付きでまとめてあります。
- Q他のブラウザ(Safari・Firefox等)でも計測されますか?
- A
計測されません。Chrome拡張はインストールしたブラウザでのみ動作します。Firefoxにも対応させる場合はmanifest.jsonの微調整が必要ですが、基本的なコードはほぼ流用可能です。
- Qブラウザ以外のアプリ(VS Codeやターミナル)の操作は計測できますか?
- A
Chrome拡張ではブラウザ外の操作は計測できません。PC全体の操作を取得したい場合は、Electronアプリ化してuiohook-napiなどのグローバル入力監視ライブラリを使う方法があります。
- Qデータはどこに保存されていますか?外部に送信されますか?
- A
すべてのデータはchrome.storage.local(ブラウザ内のローカルストレージ)に保存されます。外部サーバーへの送信は一切行っていないため、プライバシーの心配はありません。
- Q拡張を更新したらデータは消えますか?
- A
消えません。chrome.storage.localのデータは拡張の更新では削除されず、そのまま引き継がれます。ただし拡張自体をアンインストールすると全データが消去されるのでご注意ください。
- QデベロッパーモードをONにしたままで問題ありませんか?
- A
セキュリティ上の大きなリスクはありません。ただしChrome起動時にデベロッパーモードの警告バナーが表示される場合があります。自作拡張を使い続ける限りONのままにしておく必要があるため、バナーは無視して問題ありません。



コメント