A galaxy for a family’s memory

Ten pencil sheets, 385 people to lay out, and an app the family opens without creating an account.

My mother kept the family tree in pencil, on a scroll several metres long spread over ten numbered sheets. Every branch she added meant re-cutting the layout, and nobody else could really read it. I built Parenthèse for that, from the first sketch through to production, and the code has been public since September.

Visit the site
A galaxy for a family’s memory
Project details
Client
Personal product
Year
2026
Role
Product design, art direction, UX/UI, development, deployment
Deliverables
Interface decisions, design system, layout engine, deployed React app, privacy page, open and self-hostable code

Where it started

We looked for an online tool before I built one. The ones we found ask for exact dates, sources and certificates to attach, they are made for people doing research. My mother is not doing research. She wants to keep her grandfather’s photo, her aunt’s voice and the story that goes with them, and she wants the rest of the family to read it without a manual. That was the whole brief.

A map rather than a table

The first decision was not to build a box tree. A generation table reads at a glance as long as it fits one screen, and past that it becomes a document you scroll without ever knowing where you are. I went for a map you move through, each person carrying their photos, videos and recordings around them. That choice has a price, and I spent much of the rest of the project paying it. A map removes the overview, so it needed search, automatic framing on open, and levels of detail that change with zoom so the screen stays readable at every scale. The tree draws itself on open, generation by generation, so you understand its shape before you can get lost in it.

Reading without an account

A tree opens with a link and a reading password, no sign-up. A second password grants the right to contribute. That setting is why the family actually used it, where a sign-up would have stopped half of them. In exchange, the app does not know who is behind a shared password, so there is no named edit history. A card opens on the side with civil details, places, occupation, family and media, while the person stays visible in the tree.

Contributing without breaking anything

Adding something requires the second password, and whatever arrives goes through the tree owner before it shows. It is deliberate friction, and my mother can switch it off from her settings the day she trusts everyone. Contribution mode also opens an annotation palette, pencil, text, sticker and photo, to leave a note or circle a branch straight on the map. A cousin who cannot fill in a form can still draw an arrow and write next to it.

The real problem, placing 385 people

My family’s actual tree holds 385 people, 138 unions, 485 parent-child links and fifteen generations. At that size the layout stopped looking like a family. A child sat a median 394 pixels from their parents’ union, and in the top decile 1,689 pixels, fourteen thumbnail widths. The cause was the family of algorithms I was using, a layered layout that sorts each generation independently by barycentre, with the family block existing nowhere as a unit. I built a bench and compared five model families across thirteen variants, on the real tree rather than a test set. The graph engine left free separates 94 couples out of 138 to minimise crossings, which says plainly that it optimises what you ask, and that minimising crossings does not produce a family tree. Constrained, crossings drop from 23 to about ten, but the computation goes from 9 milliseconds to 500 or 700, which forces a worker and 300 more kilobytes, and changes nothing about what actually bothered the eye.

What the chosen model costs

The model in production drops that engine. A couple and their children form a block, blocks stack by generation, and parents sit centred above their children by construction rather than by heuristic. The average parent-children gap goes from 210 to 179 pixels, the median child-to-parents distance from 394 to 294, and the computation stays at 9 milliseconds. It costs 15 % more width and leaves 25 crossings, which come from marriages between two families already in the tree. A person is placed once, under one of their two lineages, and no layered algorithm removes that, you only choose which lineage keeps them. I tested four settings and the simplest one wins. One variant reduced width by reordering siblings, widest subtree in the middle, and I dropped it because birth order matters more to a family than a few per cent of width.

Running on the family’s machines

The canvas cost 12.7 milliseconds per frame while nobody was touching anything. The profile showed 832 drop shadows and 779 radial gradients drawn every frame, plus two functions scanning all 385 people and 472 media linearly for each node. Indexing those lookups, drawing only what is on screen and simplifying the render when zoomed out brings it to 1.3 milliseconds. Redrawing only when something changed brings it to 0.1. The simplification thresholds are art direction decisions as much as performance ones, the shadow disappears below a certain zoom, years and the media orbit one step further, and the first name fades progressively rather than switching off.

Opening the code

This tree holds 472 media, including recordings of people who are gone. If I stop the service one day, all of it goes with me, and I was not going to ask other families to hand me the same thing and take my word for it. The code is public under the PolyForm Noncommercial licence, readable, modifiable and runnable at home with a docker compose up. A permissive licence would have let anyone resell the work, and a classic free licence does not prevent commercial use either. This one allows personal use and forbids trade, which is what I wanted. Parenthèse stays free, and there is no artificial intelligence in it because nothing in the journey called for any.