自分は技術書などの書籍のメモはスクリーンショットを撮ってそれにメモを追加するという形で取っています。 以前はOneNoteにスクショを貼り付けていましたが、OneNoteを立ち上げるのが面倒なので、去年mumemoというスクリーンショットベースのメモアプリを書いて、メモはGitHubのPrivateリポジトリで管理するようにしました。

この記事では、スクリーンショットべースのメモを取るmumemoというアプリを紹介します。

mumemo

mumemoは、次のような機能をもっています。

  • スクリーンショットを取りフォーカスしているエリアを自動的に切り取る
  • 選択しているテキスト または クリップボードの内容を引用として取得できる
  • あわせてメモを書くと、テンプレートに従って特定のファイルへメモと画像を追記していく
  • また、メモを書く必要がない場合はNo UIモードをサポートしている

追記されるメモは設定ファイルのテンプレートで変更できます。 自分の場合は、Markdownでメモを書いているので、デフォルトの次のような形式でメモが追記されていきます。

![](${imgPath})
> クリップボードの内容 or 選択しているテキスト

メモの内容

基本的にmumemoは追記Onlyのメモを取るアプリです。 mumemoのメニューから、現在のメモファイルを変更、開いたりできるので、そこから先は別のエディタアプリで加工できます。

スクリーンショットを取りフォーカスしているエリアを自動的に切り取る

mumemoでは、スクリーンショットそのものではなくフォーカスしているエリアを自動的に切り取ります。 これは、スクリーンショットそのものだと無駄に大きくて、スクショだけ見ても何が書かれている場所なのか(何をメモしたのか)がわからなくなるためです。 そのため、OpenCV.jsを使ってフォーカスエリアを自動的に切り取ります。

mumemo

mumemoでスクショした画像はプレビューしながらメモをかける

詳細はREADMEでも書いていますが、次のようにスクリーンショットからハイライトされている場所を矩形として抽出し、マウスカーソルの近い場所をフォーカスしている場所として探索して、その矩形の集合を切り出しています。

mumemoのスクショ切り取りの処理

この処理はWebAssemblyにコンパイルしたOpenCV.jsと、Flatbushを使って当たり判定の処理で画像処理しています。

具体的な処理は次の場所で書かれています。(DEBUG:trueのオプションを使うとステップごとの画像が見れます)

スクリーンショット自体はmacOSのscreencaptureコマンドを使っています。 今の所、macOSしかサポートしてないですが、スクショの部分をどうにかすれば他のプラットフォームでも動くと思います(PR待っています)

このスクリーンショットの切り出しによって、メモとしてもある程度見やすいスクショが手に入ります。(書影に依存します)

OpenCV.jsを使っているからか結構バッテリーを使うのがネックではあります。

mumemoのインストール

現在はmacOSだけですが、次の場所からバイナリをダウンロードできます。

アプリは署名をしていないので、初回は次の手順で開く必要があります。

  1. mumemo.appを選択
  2. コンテキストメニューから "開く" を選択

普通のElectronアプリなので、cloneしてローカルでビルドして使うこともできます。

起動すると、次のパーミッションが要求されます。 これらのパーミッションをシステム環境設定から許可してアプリ再起動が必要です。

  • Accessibility
    • グローバルショートカットのため
  • Screen Recording
    • 現在アクティブなウィンドウの情報を取るため

mumemoの使い方

起動するとメニューバーにmumemoがでるので、Change output directoryからメモを出力するディレクトリを指定します。

  • Change output directory → メモファイルを出力するディレクトリを指定する

このoutput directoryにはREADME.mdimg/*.png 作成されていきます。 そのため、基本的には書籍ごとにディレクトリをかえてメモを取っていく感じです。 この辺は、設定ファイルで自動化もできます。

設定が終わったら、ショートカットキーでmumemoを起動して、スクショに対するメモを書いていくだけです。

  1. CommandOrControl+Shift+X を押す (これはmumemo.config.jsで変更できます)
  2. フォーカスしているエリアのキャプチャが取れる
  3. メモがあるなら書く
  4. "Save"で保存する

メモを保存すると先ほど設定したoutput directoryのREADME.mdimg/*.pngに追記されます。 あとは、書籍読みながらメモをしていくだけです。

設定ファイル

~/.config/mumemo/mumemo.config.js設定ファイルを置けます。 設定はJavaScriptでかけるのでかなり細かい事もできます。

  • ショートカットの変更(アプリの再起動が必要)
  • オプション値の変更
  • アプリごとの設定
  • No UIモードの設定(autoSave)

たとえば、次のように書けばCommandOrControl+Shift+Mを押すだけで、 スクショとメモ画面が開きそのまま3秒放置していると自動的にメモとして保存されます。

module.exports.shortcutKey = "CommandOrControl+Shift+M"
module.exports.create = ({ app, path }) => {
    return {
        autoFocus: false,
        autoSave: true,
        autoSaveTimeoutMs: 3 * 1000,
    };
}

次のようにアプリごとに別の設定もできます。 active-winを使ってフォーカスしているアプリのタイトルやURL、アプリ名などを取得できます。

アクティブなアプリの情報を使って、Kindleなら引用をクリップボードの中身から取得するという設定にしている例です。 (KindleはCmd+Cのコピーだと余計なものが入ったり回数制限があるので、検索をhookしてclipboardに選択しているテキストを書き込みするスクリプトと組み合わせたりできます。)

module.exports.create = ({ app, path, activeWindow }) => {
    // Note: macOS's activeWindow has owner.bundleId
    const isKindle = activeWindow?.owner?.bundleId?.includes("Kindle")
    return {
        autoFocus: true,
        autoSave: true,
        quoteFrom: isKindle ? "clipboard" : "selectedText"
    };
}

他にもBraveブラウザからショートカットキーを押した場合は、見ているサイトを {yyyy}/browserという場所に自動的に追記していくといったこともできます。

function yyyy(dt) {
  const y = dt.getFullYear();
  return String(y);
}
const brwoser = {
    is(activeWindow) {
        return activeWindow.owner.bundleId === "com.brave.Browser";
    },
    create(activeWindow) {
        const title = activeWindow.title;
        const url = activeWindow.url;
        return {
            outputDir: `~/memo/${yyyy(new Date())}/browser`,
            outputContentTemplate: ({ imgPath, inputContent }) => {
                return (
                    `## ${title}\n\n` +
                    `![](${imgPath})\n` +
                    `> [${title}](${url})\n\n` +
                    inputContent.raw +
                    "\n\n---\n\n"
                );
            },
        }
    }
}
module.exports.shortcutKey = "CommandOrControl+Option+Shift+M";
module.exports.create = ({ app, path, activeWindow }) => {
    if (brwoser.is(activeWindow)) {
        return brwoser.create(activeWindow);
    }
    return {
        autoFocus: true,
        autoSave: true,
    };
}

詳しい設定はREADMEを参照してください。

おわりに

昔から読書メモはスクリーンショットベースでやっていましたが、去年から本格的にMarkdown/GitHubベースにメモを移行しました。

基本的に過去の分もリポジトリに入れていますが、文字ベースより容量を食うといってもまだ1GBには行ってない程度なのでなんとかなっています。

リポジトリにしたことで、どこからでもウェブページとしてメモにアクセスでき、検索もできるようになったので意外と便利です。 (大体のメモアプリはSyncがあって、モバイルだと結局見なかった)

また、自分は{yyyy}/書籍タイトル/のディレクトリ構造で管理しているので、自動的に目次を更新するスクリプトを組み合わせておけば、読んだものが自動的に一覧できるようになって便利になりました。

メモリポジトリ

mumemoベースのメモにすることで、アプリごとにメモを取る方法をかえたりしなくなったのは良かったです。

  • PDF: azu/mu-pdf-viewer → mumemo
  • ePub: azu/mu-epub-reader → mumemo
  • Kindle: Kindleのハイライトは殆どみてないけど、フォーカスするエリアを強調するためにハイライトして → mumemo
  • ウェブ: ブックマークの方使うのであんまり取らないけど、サイトごとの設定をして → mumemo

メモ自体は基本的にシンプルなMarkdownと画像ファイルだけのメモなので、他の方法で記録もできます。 たとえば、iPadでの読書メモは同じようにスクショをとって、ショートカット.appでファイルとして書き込むようなものを作って、リポジトリにコミットしています。 (ショートカット.appでリマインダーをKVSとして使うと色々自由度が上がります。)

今年は大量に本を読んでいて、次の記事も基本的にはmumemoでとったスクショベースものをあとで見てまとめた感じです。

書籍のメモを手書きすると、単純に読むよりもはるかに時間がかかるので、このコストを減らしたいというのがスクショベースをやっている理由の一つです。 (少なくても本文を引用してメモするみたいなコスト減らせると思います。)

ビル・ゲイツさんも書籍のメモを取ると大体2倍程度かかると言っていました。

On vacation I get to read about 3 hours a day so I get through a lot of books. I only take notes on about 20% of the books I read. It takes me at least 2x as much time when I write notes but for a lot of books that is key to my learning.

mumemoを使ってスクショベースにしていますが、手書きのメモも一緒に書いているので、単純に読むだけに比べると2倍はかかっている気もするので、大体そんな感じなのかなと思いました。

GitHub Sponsorsで📖Book Supporterの費用を使って、Online Learning and Training - O'Reilly Mediaに登録したりしてるので、読める技術書などの幅が以前より広がっています。 色々読むためには読むスピードとかコンテキストスイッチを減らしたりなどの改善が必要になるので、この辺はもっと改善できるといいなと思いました。 mumemoもこの辺のコンテキストスイッチを減らすのに役立っている感じがします。

おまけ

特に書籍とは関係ない話ですが、ここ最近は英語の勉強をするために英語のまま文章を読むのは辞めるということ意識していました。 元から、英語以外も外国語の記事や書籍なども読むようにしてたので、技術的な文章を読んで英語の勉強になるみたいな副産物は期待していませんでしたが、 英語の勉強のために英語の記事を読まないようにするという意識を持つようにしてました。

次の記事でこれを結構意識するようになりました。

無理に英語のまま読むより、すぐ翻訳を使ったり、辞書を簡単に引けたほうが早く読めるので、そこは諦めるようにしました。 機械翻訳もツールとして使って、それを上手く使う方向にふった方がもっと色々読めると思いました。

英語以外だとThougWorksの@phodalさんは中国語ですがThinking in Microfrontend (微前端的那些事儿)とか結構納得感があるものを書いてたり、台湾の@aszx87410さんがCORS 完全手冊(一):為什麼會發生 CORS 錯誤? - Huliという良くまとまったCORSの話を書いてたりします。

もっといろいろなものを読めたほうが楽しいので、そういうのを意識してツールを書いたりしています。