Work/KURA
macOS · File Manager

KURA

A Finder Replacement for macOS

macOSのFinderに代わるファイルマネージャー

KURA icon
01

Overview

概要

A kura (蔵) is the thick-walled storehouse at the back of a Japanese property — where a household keeps what it owns but does not use. Everything ends up in one, and nobody knows what is in theirs. The app does three things about that: browse, measure, and clean.

蔵(くら)は、日本の家の奥にある分厚い壁の倉庫で、持っているけれど使っていないものをしまう場所です。何でも最後は蔵に入り、誰も自分の蔵に何があるか知りません。このアプリはそれに対して3つのことをします。見る、測る、片付ける。

Disk-space tools tell you what is big. Finder tells you what is there. Neither answers the question people actually have, which is what is growing. Kura remembers every measurement it takes, so the second time you look at a folder it can show a sparkline and a delta since last time — and a breadcrumb running the whole way back to / where each crumb it has measured before carries what it measured.

ディスク容量ツールは何が大きいかを教えてくれます。Finderは何があるかを教えてくれます。けれどもどちらも、本当に知りたい「何が増えているか」には答えません。Kuraは測定結果をすべて記憶するため、2回目にフォルダを開いたときには、前回からの増減と推移の小さなグラフを表示できます。ルート(/)までのパンくずリストにも、測定済みの階層にはその結果が表示されます。

02

How it was built

開発

Most of the engineering went into behaving well at sizes that break file managers. A folder of two hundred thousand files takes seconds to stat, and returning it in one call meant a frozen window followed by one enormous JSON payload for the webview to parse on its main thread. Rust now streams the listing in slices of 500 and the view fills as it reads: the first slice renders immediately, the rest are pooled and flushed on a timer, because every flush re-sorts the whole list and sorting two hundred thousand entries sixty times a second is its own freeze. Navigating away cancels the read rather than finishing a job nobody is waiting for.

開発の大半は、一般的なファイルマネージャーが破綻する規模でもきちんと動くことに費やしました。20万ファイルのフォルダは情報の取得だけで数秒かかり、それを1回で返すと、ウィンドウが固まった後に巨大なJSONが届き、webviewがメインスレッドでそれを解析することになります。現在はRustが500件ずつ分割して送り、読み込みながら表示が埋まっていきます。最初の500件はすぐに描画し、残りはまとめてタイマーで反映します。反映のたびに一覧全体を並べ替えるため、20万件を毎秒60回並べ替えると、それ自体が固まりの原因になるからです。別の場所へ移動すれば読み込みは中止し、誰も待っていない処理を続けることはしません。

03

What it does

機能
01
Five Layouts, in Tabs
タブで使える5つの表示

List, Grid, Gallery, Miller Columns and Focus. Columns shows the hierarchy left to right so you can see what is beside you at every level of the path — drilling in opens a column rather than navigating, so Back still means what it meant. Each tab owns its own history, because tabs sharing a history stack are one window wearing two hats, and you find that out the first time you use them to copy between two folders.

リスト、グリッド、ギャラリー、カラム、フォーカスの5種類。カラム表示は階層を左から右へ並べ、パスのどの階層でも隣に何があるかが見えます。中へ進むと移動ではなく列が開くので、「戻る」の意味は変わりません。タブごとに履歴を持ちます。履歴を共有するタブは一つのウィンドウが二役をしているだけで、2つのフォルダ間でコピーしようとした瞬間にそれがわかるからです。

02
Space — What Is Growing
容量:何が増えているか

A squarified treemap for proportion, the 300 largest files ranked, and a breakdown by file kind. Every measurement is kept, so repeat visits answer the change over time rather than just the current total.

割合を示すツリーマップ、大きい順の上位300ファイル、ファイルの種類別の内訳。測定はすべて記録されるため、再訪するたびに今の合計だけでなく時間による変化がわかります。

03
Clean, With the Cost Named
代償を明記したクリーンアップ

Named rules for caches, build artefacts, device backups and stale downloads, plus the big creative ones — DaVinci Resolve's render cache, optimised media and proxies read from Resolve's configured working folder rather than guessed at, and Lightroom and Capture One previews. Each rule says what it is, how big it is, and what taking it costs you. A rule is not all-or-nothing: expand it and any single file can be spared, with the total dropping to match.

キャッシュ、ビルド成果物、端末のバックアップ、古いダウンロードなどに名前のついたルールがあり、クリエイター向けの大物にも対応します。DaVinci Resolveのレンダーキャッシュ、最適化メディア、プロキシは推測ではなくResolveの作業フォルダ設定から読み取り、LightroomやCapture Oneのプレビューも対象です。各ルールは、それが何か、どれだけの大きさか、消すと何を失うかを示します。ルールは全部か無しかではなく、展開すれば個別のファイルを残すことができ、合計もそれに合わせて減ります。

04
Nothing Is Deleted
何も削除しない

Every removal is a move to the Trash via NSFileManager.trashItemAtURL — the same call Finder makes — so Put Back works. Which also means trashing a 40 GB cache does not give you 40 GB back; it moves it. The Clean view says so at the top, every time. Emptying the Trash is the sole exception, behind a typed confirmation that touches nothing outside ~/.Trash.

削除はすべて、Finderと同じNSFileManager.trashItemAtURLによるゴミ箱への移動なので、「戻す」が使えます。つまり40GBのキャッシュをゴミ箱に入れても40GBは空かず、移動するだけです。クリーンアップ画面の上部には毎回そう表示されます。唯一の例外はゴミ箱を空にする操作で、文字を入力して確認する必要があり、~/.Trashの外には一切触れません。

05
Copies as Jobs, Not as a Frozen Window
コピーはジョブとして、ウィンドウを固めない

A toolbar chip shows a real fraction measured in bytes rather than items, because a folder of one 4 GB clip and two hundred JPEGs is not 99% done when the JPEGs are. Clicking it opens an activity panel: every running job with its own bar, current file, rate, time remaining and Stop button. Progress and cancellation are per file, so a 40 GB folder is no longer one indivisible step where Stop cannot take effect until the thing you wanted stopped has already happened.

ツールバーの表示は、項目数ではなくバイト数で測った実際の進捗を示します。4GBの動画1本とJPEG 200枚のフォルダは、JPEGが終わっても99%完了ではないからです。クリックするとアクティビティパネルが開き、実行中のジョブごとに進捗バー、現在のファイル、速度、残り時間、停止ボタンが表示されます。進捗とキャンセルはファイル単位なので、40GBのフォルダも、止めたいことが終わるまで停止が効かない分割不能な一歩ではなくなりました。

06
Finder's Own Tags
Finderと同じタグ

The real com.apple.metadata:_kMDItemUserTags extended attribute, read through Spotlight and written as a binary plist. What you tag in Kura shows up in the Finder sidebar, in every open dialog and in Spotlight — a private tag store would only be a worse copy of something the OS already does well. Every tag in use on the machine appears as its own sidebar section, each row a saved search over kMDItemUserTags, which is all a tag ever was.

本物のcom.apple.metadata:_kMDItemUserTags拡張属性を、Spotlight経由で読み、バイナリplistとして書き込みます。Kuraでつけたタグは、Finderのサイドバー、すべてのファイル選択画面、Spotlightに表示されます。独自のタグ保存先を作っても、OSが既にうまくやっていることの劣化版にしかなりません。マシンで使われているタグはそれぞれサイドバーの項目になり、各行はkMDItemUserTagsを検索する保存済み検索です。タグとは本来それだけのものです。

07
Duplicates, Identical and Similar
完全一致と類似の重複検出

Identical is byte-for-byte, grouped on size first so almost everything is discarded before a byte is hashed. Similar is perceptual — a difference hash catching burst frames, re-exports and resized copies — run over previews Kura has already cached. Indexing lifts that beyond a single folder, so any photograph can answer where else does this live: the same frame filed under a client folder, an archive drive and a Desktop export is three copies nothing else would put side by side.

完全一致はバイト単位の比較で、まずサイズでグループ分けするため、ほとんどのファイルはハッシュ計算の前に除外されます。類似は知覚的な比較で、差分ハッシュにより連写、再書き出し、リサイズしたコピーを見つけます。対象はKuraが既にキャッシュしているプレビューです。インデックスを作れば単一フォルダを超えて検索でき、どの写真についても「他にどこにあるか」がわかります。クライアントのフォルダ、アーカイブ用ドライブ、デスクトップの書き出しにある同じ1枚は、他のどのツールも並べて見せてくれない3つのコピーです。

08
⌘K and Saved Searches
⌘Kと保存済み検索

A command palette over places, favourites, recent folders and every action, with whole-disk Spotlight results folded in underneath. A query containing kMDItem is passed through raw, so predicates like kMDItemISOSpeed > 3200 work — and any query that finds what you wanted can be saved as a smart folder in the sidebar. Results cap at 500 and the header says so, because a list that stops at 500 without mentioning it is lying about the size of the answer.

場所、お気に入り、最近のフォルダ、すべての操作を対象にしたコマンドパレットで、その下にディスク全体のSpotlight検索結果も表示します。kMDItemを含む検索語はそのまま渡すため、kMDItemISOSpeed > 3200のような条件も使えます。目的のものが見つかった検索は、スマートフォルダとしてサイドバーに保存できます。結果は500件までで、見出しにそう表示します。黙って500件で止まる一覧は、答えの大きさについて嘘をついているからです。

04

Under the hood

技術の詳細

Streaming two hundred thousand files20万ファイルを分割して送る

Returning a large folder in one call meant seconds of frozen window followed by one enormous JSON payload parsed on the webview's main thread. Rust sends slices of 500 instead: the first renders immediately, the rest are pooled and flushed on a timer, because each flush re-sorts the whole list and sorting two hundred thousand entries sixty times a second is its own freeze.

大きなフォルダを1回で返すと、数秒間ウィンドウが固まった後、巨大なJSONをwebviewのメインスレッドで解析することになっていました。現在はRustが500件ずつ送ります。最初の分はすぐ描画し、残りはまとめてタイマーで反映します。反映のたびに一覧全体を並べ替えるため、20万件を毎秒60回並べ替えると、それ自体で固まってしまうからです。

Selection by arithmetic, not measurement測定ではなく計算による選択

Tiles are a uniform size, so which are visible is arithmetic and the only measured value is row height for wrapped captions. The rubber band works the same way — O(what you selected) rather than O(what is in the folder), and the only way a band dragged past the bottom of the screen can take items the window has left unmounted.

タイルは一定サイズなので、どれが見えているかは計算で決まり、測定するのは折り返したキャプションの行の高さだけです。範囲選択も同じ仕組みで、処理量はフォルダの規模ではなく選択した数に比例します。画面下まではみ出してドラッグしても、描画されていない項目まで選択できる唯一の方法でもあります。

Why drag and drop is hand-rolledドラッグ&ドロップを自作した理由

macOS routes every drag over a webview through the native view first, and Tauri installs a handler there so files from Finder arrive with real filesystem paths — something the DOM will not give us. That handler consumes the drag before WebKit sees it, so dragover and drop never fire on anything in the page. Doing it from pointer events keeps both halves working, and lets the label under the cursor say whether the drop will copy or move.

macOSはwebview上のドラッグをまずネイティブのビューに渡し、TauriはFinderからのファイルを実際のパスで受け取るためにそこへハンドラーを設置します。DOMからは得られない情報です。そのハンドラーがWebKitより先にドラッグを受け取るため、ページ内ではdragoverもdropも発生しません。ポインターイベントで実装すれば両方が動き、カーソルの下のラベルでコピーか移動かも示せます。

Undo that does not lie嘘をつかない取り消し

⌘Z undoes a rename or a move, but not a trash. macOS has no public Put Back API, and an undo that silently did something other than what it said would be worse than not offering one.

⌘Zで名前の変更や移動は取り消せますが、ゴミ箱への移動は取り消せません。macOSには「戻す」の公開APIがなく、表示とは違うことを黙って行う取り消しなら、ない方がましだからです。

05

Stack

技術構成

Tauri 2 with a Rust core and a React 19 / Vite / Tailwind 4 front end. Directory walking is jwalk running parallel on a background thread with a cancel button and progress events, because a home folder is routinely several hundred thousand entries. The grid and list virtualise: tiles are a uniform size so visibility is arithmetic rather than measurement, spacers stand in for what is not drawn so the scrollbar still describes the whole folder, and the entrance animation is dropped past 400 items — a stagger across forty tiles is a nice touch, across four thousand it is four thousand simultaneous transforms. Rubber-band selection works by index arithmetic too, which is both O(what you selected) rather than O(what is in the folder) and the only way a band dragged past the bottom of the screen can take items the window has left unmounted. Dragging is done from pointer events rather than HTML5 drag and drop, which cannot work in this window at all: macOS routes every drag over a webview through the native view first, and Tauri installs a handler there so Finder's files arrive with real filesystem paths — that handler consumes the drag before WebKit sees it, so dragover and drop never fire in the page. Kura registers as a Viewer for folders and volumes at rank Alternate, which is the honest one: Finder owns folders, Kura offers to.

Tauri 2とRustのコア、React 19・Vite・Tailwind 4のフロントエンド。ホームフォルダは数十万項目になることが珍しくないため、ディレクトリの走査はjwalkでバックグラウンドスレッドで並列に行い、キャンセルボタンと進捗イベントを備えています。グリッドとリストは仮想化しています。タイルは一定サイズなので、表示範囲は測定ではなく計算で決まり、描画しない部分はスペーサーで埋めるため、スクロールバーはフォルダ全体を正しく表します。登場アニメーションは400項目を超えると省きます。40個のタイルに時間差をつけるのは良い演出ですが、4,000個では4,000個の同時変形になるからです。範囲選択もインデックス計算で行うため、処理量はフォルダの規模ではなく選択した数に比例し、画面下まではみ出してドラッグしても、描画されていない項目まで選択できます。ドラッグはHTML5のドラッグ&ドロップではなくポインターイベントで実装しています。このウィンドウではHTML5の方式がそもそも動かないからです。macOSはwebview上のドラッグをまずネイティブのビューに渡し、TauriはFinderのファイルを実際のパスで受け取るためにそこへハンドラーを設置します。そのハンドラーがWebKitより先にドラッグを受け取ってしまうため、ページ内ではdragoverもdropも発生しません。Kuraはフォルダとボリュームの「代替」ビューアとして登録しています。フォルダの持ち主はFinderで、Kuraは選択肢を提供する、という正直な位置づけです。

06

Where it is now

現状と今後

Kura is a working Finder replacement — five layouts, streaming listings, per-file copy jobs, real Finder tags, treemap sizing, duplicate detection and Trash-only cleanup — running as a local build. It is not signed or released; notarisation and a DMG are what stand between it and being installable by anyone else.

Kuraは実際に使えるFinderの代替で、5つの表示、分割読み込み、ファイル単位のコピージョブ、本物のFinderタグ、ツリーマップによる容量表示、重複検出、ゴミ箱への移動だけのクリーンアップを備え、ローカル版として動いています。署名とリリースはまだで、公証とDMGを用意すれば誰でもインストールできるようになります。

The rule that shaped the whole app is that it never deletes anything and never pretends to have done more than it did. A cleaner that quietly frees nothing, or a search that silently stops at 500, is worse than no tool at all — you cannot audit a lie you were never told.

アプリ全体を形づくったルールは、何も削除しないこと、そして実際にしたこと以上のことをしたふりをしないことです。何も解放しないクリーナーや、黙って500件で止まる検索は、ツールがないより悪い。知らされていない嘘は確かめようがないからです。

Next case study 次の実績
CAUSEWAY
A Space Racer Built to Look Like 1993
→