Loci: a landscape for your notes
A post on r/secondbrain, Maps organize information through landscapes — why?, stopped me for a minute. It brought back Moonwalking with Einstein, Joshua Foer's year with competitive memorizers, and the old trick at the center of it: put each thing you want to remember in a place, then walk the places. The Romans called the places loci. I have a few thousand notes, clippings and links. I can search them when I remember a word. I cannot walk them. So I built a landscape for them and called it Loci.
Here is the idea in twenty notes. I imported twenty short Markdown files with tags and [[wikilinks]]. They became five hills. I clicked one note, and then I orbited the terrain.

What a hill is
Every note is a point. Notes that mean the same thing sit near each other. Groups of near notes become regions, and each region is a hill. The hill with the most notes is the tallest and the widest. Height is a count, not a judgment. A tall hill means you wrote a lot about that topic, not that the topic matters more. Contour rings follow the summed surface, so when two hills run together the rings wrap both of them, like a real ridge.

Three signals place the notes:
- Meaning. A small sentence model,
all-MiniLM-L6-v2, turns each note into a 384-number vector. The quantized weights are about 23 MB. The model runs in the browser, on WebGPU when the machine has it and on WASM when it does not. Long notes are split into overlapping windows of 200 tokens, and the window vectors are averaged into one vector per note. - Words and tags. A weighted vocabulary and shared tags carry notes that have no vector yet, and they add a little to notes that do.
- Links. A
[[wikilink]]is a solid connection. Loci resolves it by path, then by title or alias.
Regions come from farthest-first seeds followed by spherical k-means over the vectors. A small stress solver then arranges regions and notes so that related ones are near each other. The layout is deterministic: the same collection always gives the same map.
Two views, one geography
The 2D atlas and the 3D terrain use the same coordinates. A note keeps its place when you switch. The atlas is for finding. The terrain is for wandering. In 3D, left-drag orbits and right-drag pans. In 2D, drag pans.

Select a note and the panel shows its nearby thoughts: explicit links first, then the closest vectors. Cmd+K is full-text search. The serendipity button opens a random saved note. That one is the point of the whole project. You do not need the title. You walk to the neighborhood, recognize a neighbor, and follow the path back.
How it is built
The interface is vanilla JavaScript. No framework, no bundler. One Rust crate, loci-core, owns storage: SQLite with FTS5 for full-text search, sqlite-vec for cosine nearest neighbors, a small edge table for the graph, and a recursive SQL query for traversal. Imports are transactions. A bad note rolls the whole batch back.
The same interface runs in two hosts. Tauri 2 gives the desktop app, with native folder dialogs and Apple Notes automation on macOS. An Axum server gives browser mode on loopback. The release binary embeds the interface, the model and the ONNX runtime, so it runs without Node or a checkout. Nothing calls a remote inference service. Your notes stay on your machine.

The Hill base slider widens every footprint. At the default, neighboring hills run together into one meadow. Lower it and you get separate mountains with valleys between them.
Bring notes in
- Apple Notes. The Mac app reads unlocked notes as plain text through macOS automation. Locked notes are skipped. Originals are never changed.
- Obsidian vault. Point it at a folder. Markdown, YAML tags, inline tags and wikilinks are read. A vault note is identified by its path inside the vault, so moving the folder does not duplicate anything.
- Markdown or text files, and a JSON backup from a previous export.
Imports are snapshots. Reimport a source and its copy updates. Edit a note and its vector is dropped until you refine the landscape again. The current limits are 5,000 notes, 2 MB per note and 64 regions.
What it does not claim
Distances are approximate. The projection, the clustering and the space reserved for the hills all distort something. MiniLM is a compact English model, not the best multilingual one, and I chose it to keep the install small. Above 600 notes the layout samples candidate pairs instead of comparing every pair, so nearest-neighbor accuracy drops for big vaults. The demo above has twenty notes and no embeddings at all; it is the vocabulary map. The real test is your own notes, and I have not measured anything beyond "I found things I had forgotten."
Try it
Clone github.com/mraad/loci. Then:
npm ci --ignore-scripts
npm run setup:embeddings
npm start
Open http://127.0.0.1:4173. Import a folder of Markdown. Open Settings. Click Refine semantic landscape. Then orbit.
Next is a larger evaluation on a few hundred labeled note pairs, and a multilevel atlas for collections that outgrow 64 hills. More to come :-)
Comments