MonoStartは、ブラウザ標準の新規タブページを、高速でカスタマイズ可能な個人用ダッシュボードに変えます。ブックマーク、タスクリスト、簡易メモ、集中タイマーを、設定可能なワークスペースにまとめます。Manifest V3のChrome拡張機能として構築されており、すべてをデバイス上にローカルで保存します。アカウントも、サーバーのデータベースも、分析(アナリティクス)もありません。

作ったもの
- カスタマイズ可能なダッシュボード: ネストされたウィジェットグループを含むドラッグ&ドロップのグリッドで、ウィジェット(クイックリンク、カテゴリ分けされたフォルダ、メモ、ToDoリスト、カウントダウンタイマー、リマインダー、音声検索、Google Lensによるビジュアル検索)をどんなワークフローにも合わせて配置できます。
- クイックアクセスのレイアウト: ヘッダーに固定したリンクとグループ化されたフォルダが、深い階層のブックマークメニューに取って代わり、よく使うサイトをワンクリックで開ける状態に保ちます。
- テーマのカスタマイズ: Chrome自身の「Chromeをカスタマイズ」パレットからリバースエンジニアリングした15種類の組み込みカラーテーマ、カスタムの16進数カラーピッカー、ライト/ダークモード対応、そしてグラデーションまたは壁紙の背景。
- 生産性ツール: ローカルの音声アラートとデスクトップ通知を伴う、内蔵のカウントダウンタイマーとスケジュール済みリマインダー。
- ローカルファーストのストレージ: メモ、ToDo、レイアウト、画像はデバイス上のchrome.storage.localとIndexedDBに保存されます。ユーザーアカウントもサーバーのデータベースもありません。唯一のネットワーク呼び出しは、検索オートコンプリートのためのGoogleの公開サジェストAPIへのもので、これはChrome自身のアドレスバーが使っているのと同じものです。
なぜ意味があったか
新規タブページは一日に何十回も開かれます。MonoStartはその何もない空間を、プライバシーを尊重する即座でローカルファーストな生産性ダッシュボードに変えます。あなたのデータがデバイスの外に出ることはありません。
これが存在する理由
私は一日に200回ほど新規タブを開きますが、何年もの間そこから返ってくるものは何もありませんでした。検索バーと、Googleが推測したサイトのグリッドだけです。本当の問題は空白のページそのものではなく、それに対処するために自分がやっていたことすべてでした。URLを再入力しないためだけに、3つのChromeプロファイルにまたがって40個以上のタブを開いたままにしており、そのひとつひとつがChromeが常時ウォームに保っていた稼働中のプロセスでした。私は自分の作業を整理していたのではなく、ページではなくポインタを保持し続けるためにRAMとファンの税金を払っていたのです。試した既存の新規タブ拡張機能はどれも、その空白のページを、もっと悪いものと引き換えにしていました。筋肉記憶を壊す見慣れないUI、アカウントとクラウド同期、スポンサーリンク、テレメトリです。私が唯一のコントリビューターで、2026年6月以降222コミット、今も活発にメンテナンスされています。まず自分自身のブラウザを直すために作り、その次に公開の拡張機能として出荷しました。
ただひとつのルール:アプリではなくChromeのように見えること
このコードベースにおけるあらゆる決定は、ひとつの制約に答えるものです。Chromeがどこで終わり、ダッシュボードがどこから始まるのか、わからないようにすることです。だからこそ、独自の履歴インデックスを必要とするカスタム検索UIではなく、本物のGoogle検索バーと本物のChrome履歴サジェストがそのまま残されています。オンボーディングフローも、ログイン画面も、アカウントシステムも存在しないのは、新規タブを開くことが何もインストールされていないかのように感じられるべきだからです。ページを別のアプリのように感じさせる機能は、どれだけ便利であっても出荷されませんでした。
音声を再生できないサービスワーカーでの音声再生
Manifest V3のバックグラウンドスクリプトはサービスワーカーであり、サービスワーカーは音声を直接、確実に再生することができません。Chromeはメモリを回収したいときにいつでもサービスワーカーを一時停止・破棄します。再生の途中であっても例外ではありません。それでもリマインダーには、実際に鳴る音が必要です。この修正では、chrome.alarmsを使ってリマインダーをスケジュールします。アラームは破棄されたサービスワーカーを乗り越えて生き残り、それを再び起こすことができるからです。そして再生自体はサービスワーカーではなくchrome.offscreenドキュメントを経由させます。これはChromeがまさにこうしたタスクのために生かし続ける非表示のページです。これは、MV3では永続的なバックグラウンドページがもはや存在しないため、ほとんどのMV3拡張機能がいずれ行き着くのと同じ種類の回避策です。
Chrome自身からリバースエンジニアリングしたテーマ
任意のカラーパレットを考案するのではなく、MonoStartの15種類の組み込みテーマはChrome自身の「Chromeをカスタマイズ」のシードカラーから抽出されており、その抽出プロセスはリポジトリ内に手順ごとに文書化されています。この抽出処理の初期バージョンには色相がずれるバグがありました。修正はv1.1.1で出荷され、古い計算式のもとで既にテーマを選んでいたユーザー向けの移行パスも用意されたので、既存のユーザーが自分の選んだ色とは違う色で目を覚ますことはありませんでした。
セキュリティ:サニタイザーだけに頼らない埋め込みの無害化
画像と埋め込みのウィジェットは任意のHTMLを受け付け、描画前にDOMPurifyを通して無害化されます。DOMPurifyだけでは十分ではありませんでした。srcdoc属性を取り除かないためです。srcdocが設定されたiframeは拡張機能自身のオリジンを継承し、拡張機能のCSPがいつか緩んだ場合に実際のXSS経路になり得ます。DOMPurify単体が何を許可するかにかかわらず、srcdocはサニタイザー内で明示的に取り除かれます。ひとつのライブラリを完全に信頼するのではなく、独立した第二の層を設けています。
データモデルと規模
- テキストデータ(メモ、ToDo、レイアウト、リマインダー、設定)はchrome.storage.localに保存されます。
- 壁紙と背景画像は代わりに別のIndexedDBデータベースに保存され、削除または置き換えられた画像が静かに蓄積しないよう、孤立した参照のガベージコレクションを備えています。
- chrome.storage.localの約10MBという上限は
unlimitedStorage権限によって解除されています。これは画像がそのクォータから完全に外れた時点で必要になったものです。 - 25ファイルにわたる216個のテスト(Vitest、jsdom、fake-indexeddb)が、その上に乗るUIだけでなく、このストレージ層そのものを直接カバーしています。
ローカルのみのストレージは見落としではなく意図的なトレードオフです。マシンやプロファイルをまたいだ同期がないことを意味しますが、同じ仕組みによって、構築・保護すべき共有アカウントシステムなしに、3つのChromeプロファイルがそれぞれ独立した隔離されたダッシュボードを無料で持てます。検索バーのオートコンプリートはアプリ全体で唯一のネットワーク呼び出しであり、Chrome自身のアドレスバーと同じ方法でGoogleの公開サジェストAPIにアクセスします。ユーザーが実際に作成するものはすべてローカルにとどまります。
自作か既製品か
独自のドラッグ&ドロップエンジンはありません。衝突判定やリサイズハンドルをゼロから再実装する代わりに、react-grid-layoutがネストされたグループを含むグリッドを扱います。独自のコンポーネントライブラリもありません。shadcn/uiの、不透明なUIパッケージをインストールするのではなくRadixベースのコンポーネントを直接コピーするパターンにより、すべてのコンポーネントのコードと、そこからの逸脱が可視化・編集可能な状態に保たれます。独自のローカライズパイプラインもありません。手作りの文字列ルックアップの代わりに、react-i18nextと拡大し続けるロケールファイル群(50以上の言語)を使っています。
Stack
React 19、Vite、TypeScript、Tailwind CSS、Radix UIプリミティブ上のshadcn/ui、ダッシュボードのグリッドにreact-grid-layout、ローカライズにreact-i18next、埋め込みの無害化にDOMPurify、テストにVitest、ChromeのManifest V3拡張機能プラットフォーム(chrome.alarms、chrome.offscreen、chrome.storage、IndexedDB)、PolyForm Noncommercial 1.0.0のもとでライセンスされています。