Skip to content

Family Tree

It renders all nodes extracted from the family's own PDF — pan, zoom, and reset.
Piet — family-tree prototype notes, February 2026

The Family Tree was in Piet’s founding list from the first letter — “films, audio stories, photographs, maps, timelines and family trees within a curated narrative structure.” His prototype rendered a real family’s tree straight from the PDF they already had, preserving its layout: the room’s founding instinct is assembled from what the family already has, not re-entered into a genealogy tool.

The room exists so a family can arrive at and share their stories. The tree is the map; a story is the destination. It is deliberately not Ancestry: no research tools, no sources, no hints, no records grid.

The tree opens on you; step out to the whole family; search for a name; land on the person, their wall label and how they are related to you — the Ashworth demo on staging.

The tree opens on you. A visitor whose sign-in email a curator has put on a person (loginEmail) lands on that person: their branch pruned into view, their wall label already open. A visitor who is not in the tree — a friend, an advisor, a curator — lands on the person the family chose as the starting point (startHere); if nobody is ticked, on the person with the most descendants — it needs no dates and gives the same answer every time. Nobody arrives at a wall of strangers.

Theo Ashworth, signed in: his branch on the left — parents, partner, children — and his wall label on the right.

The wall label is the destination: name, lifespan, a few sentences, then parents, each partnership and the children on their own lines with their years. On the chart a dashed line marks a partnership that ended; a solid line one that did not.

Three ways to move from there. Find someone searches by the name on the tree, the name they were born with, or the name the family called them, and shows lifespans in the list so two people with the same name are told apart:

Typing “Voss” in Find someone lists eight people with their years.

Arriving from search, the wall label also says how this person is related to you — “Your uncle” — and the you came by trail along the bottom keeps the way back:

Henry Voss reached from search: “Your uncle”, a full birth date, and the trail Theo Ashworth › Henry Voss.

The whole family steps out to everyone, fitted to the stage and deliberately not legible — impressive rather than readable, so gaps in a family’s knowledge never read as broken. From here a tap on anyone glides the camera to them:

The whole Ashworth family fitted to the stage, with “Back to you” waiting at the top left.

And Back to you — plus the you came by trail along the bottom — returns a visitor to where they started, however far they have wandered.

Two smaller things. Share a person: the address bar always points at whoever is on screen (?person=…), so a link opens the room on them. And the room works without a pointer: arrow keys move through the family by relationship (up to a parent, down to a child, left and right along partners and siblings), Enter opens the wall label, and Escape steps out one level at a time — person, then home, then the whole family.

The tree is the map; what a person carries is the destination. Below the people on a wall label come the photographs and films that person appears in, each section with its count.

  • A photograph opens the Photo Exhibit lightbox on that photograph, and the person’s other photographs are one arrow key away inside it. It is the same lightbox as the gallery, not a third viewer.
  • Films are stills for now — title, duration, a play mark — and not yet buttons. Playback arrives with the data model.
  • One record can hang on several walls. A wedding photograph is attached to both partners and appears on each of their walls from a single entry. Attachments are keyed by record, never by name: two relatives sharing a name is the normal case in a family record.
  • Most people carry nothing, and their wall label simply has no such section.

Today this runs on a hand-keyed fixture for the Ashworth demo (Alice Voss carries six photographs and the family’s two films). The curator-side model is CDI-1694.

One room, one base — Ashworth — Family Tree for the demo. Three tables, in the same shape as the Photo Exhibit: make the people first, relate them afterwards, exactly as photos are related to sets through Curation.

One row per person. The primary field is the person’s Name, because that is what you pick from when setting a parent or partner. Every column carries its own description inside Airtable — hover the ⓘ next to the column name:

The Ashworth People table in Airtable, with the description of the born column open: a year, a full date, or an approximation.

Field Notes
Name Primary. What appears under the portrait, and in every picker.
preferredName Optional. What the family actually called them — “Ken”, “Oma”. When set, the plate and every chip say it; the wall label leads with Name and adds “Known as”.
birthName Optional. The name they were born with, when it differs — a maiden name. The wall label shows “Born as”, and a visitor can search by it.
born / died Free text on purpose: 1918, 03/14/1943, or about 1890. Airtable has no partial-date type and family records are full of approximations. Shown exactly as written.
birthPlace / deathPlace Optional. Where. The wall label reads 03/14/1943 · Kyoto; either half alone still shows.
gender Descriptive and extendable — add a choice if none fit. Never displayed; see below.
photoUrl Blank gives a dignified initials plate, never a blank square.
shortBio The wall label’s few sentences.
notes Curator-private. Never shown in the museum.
visible Unchecked = this person does not appear at all.
generation Optional. The generation as the family names it — “Issei”, “Nisei”, “Sansei”, or anything else. Shown exactly as typed on the plate and the wall label; blank shows nothing.
loginEmail A visitor signed in with this email opens the tree on this person. Matched on the server, case-insensitively; never shown in the museum.
startHere Tick one person: where the tree opens for a visitor who is not in it (a friend, an advisor, a curator). Two ticks resolve to the lower record id.

The ParentChild table — one row per parent → child link, picked by name, with the relationship column’s description open.

The Partnerships table scrolled to status — current, former or widowed — with its description open.

Two join tables. Each row links to People by record, so Airtable itself guarantees both ends exist — you pick a person from a list rather than typing an id, and a typo can no longer make a relative silently vanish.

  • ParentChild — one row per parent→child link. A child with two parents has two rows. Someone with no row here is a top of the tree. The optional relationship (adopted · step · foster; blank = a birth parent) draws that line dotted and names the relationship beside the parent on the child’s wall label. Children stand in birth order on the map, eldest first.
  • Partnerships — one row per couple. The order of the two columns carries no meaning. A remarriage is simply two rows; nothing special is needed. startYear, endYear, endReason and place (the town of the wedding) are all optional, because a family often knows the couple but not the dates. status is the one field the line is drawn from: current, former or widowed, as of today. The room reads this and nothing else — it never infers it from the years or the reason, because a partnership that ended in a death is not one that ended in a divorce, and only the curator knows which. former draws the line with a break and stands that partner on the person’s left, an earlier partnership further out; current and widowed keep a solid line, to the right. Blank draws the partnership plainly.

Each join table’s first column is a Label that exists only because Airtable demands a primary field and refuses to accept a record link as one. Set it to a formula so the row reads as its two names:

IF({parent}, ARRAYJOIN({parent}) & " → " & ARRAYJOIN({child}), "—")
  1. Create the People rows first — everyone, before any relationships.
  2. Add ParentChild rows, picking a parent and a child by name.
  3. Add Partnerships rows for couples, with whatever dates the family knows.
  4. Register the base in the config base’s Collections table (type family-tree, status active), and add a Rooms row of type family-tree. See Setting up a room.

The BFF reads the three tables and transforms them into the node/union shape the charting library wants, so the curated data stays normalised and the library stays swappable. That transform is a single pure function; the browser never sees the edge tables.

Airtable (per family) BFF Room
People ──┐
ParentChild ──┼──▶ assembleFamilyTree() ──▶ family-chart nodes
Partnerships ──┘ (pure, unit-tested) (client-only, d3)

Reads are live from Airtable today, with a Neon served path in front of it for families that have been cut over — the same live-first shape the Cinema and Story Collections rooms were built in.

The charting library reads gender for exactly one purpose: which side of a couple a person stands on. Nothing is coloured or labelled by it — the room draws its own square plates precisely so the library’s blue/rose default never applies — and only the main person’s value is ever read.

That is why the field is an open vocabulary and why any value is safe: a non-binary or blank entry simply mirrors the couple, and same-sex couples lay out correctly. The person’s gender and the chart’s layout hint are different things and are deliberately not the same field.

  • A curator can assert something impossible — a person as their own parent, or a cycle — and nothing catches it today. A cycle would most likely hang the browser. Detecting these and telling the curator is planned; the storage deliberately does not try to prevent it.
  • Content per person (films, photographs, letters) is CDI-1554.
  • The Label formula above must be set by hand: the Airtable API cannot convert a text field to a formula.
  • Room-local, not the shared People store. An earlier note on this page said the tree would read the shared per-family People store the Photo and Story rooms feed. It does not, and the reason is worth knowing: those rows only ever appear via promotion from a gallery base, so that store holds exactly the people who show up in a photo or story — and a family tree holds the ones who don’t. Joining the two planes is the work that comes with content-per-person.
  • Edge tables, not a parents list on the person. The relationships stay normalised so the charting library can be replaced without touching how a family curates.
  • Dates are text. See born/died above — this is what lets a family write down what they actually know.
  • Home is resolved, not computed. Signed-in person → the family’s startHere → most descendants. The middle tier exists so that which person a family starts from is the family’s statement, not a line of code’s. The old fallback — the first row with no recorded parents — was Airtable row order once a family had more than one such person, which every family past about twenty people does.
  • The whole-family view is a scale moment, not a front door. It was never broken, only miscast: as a place to choose from it fails harder the bigger the family; as a way to feel the family’s size it works because the plates are illegible. So it stopped being the landing view and stopped drawing names.
  • No minimap. An Ancestry-style movable magnifier was asked for and deliberately not built: it is a second synchronised viewport in a view already carrying a tree, a wall label and the exits, and its job — knowing where you are in the whole — mostly disappears once you never land in the whole. Search and relationships reach any person without it. Open to revisit after the genealogist conversation.