尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证正在加载完整 README。 以下为已保存的摘录。
Build and keep your family tree. Works in English and Urdu, on a phone or a
laptop, and is designed so that someone who is not comfortable with software can
still use it on their own.
A Next.js app, local-first with a Supabase database behind it. You sign in with
your phone number and a password, your families are kept in the browser as you
work and saved online a moment later, so they come back on any phone you sign in
on — and a cleared browser is no longer the end of them.查看完整 README ↗Build and keep your family tree. Works in English and Urdu, on a phone or a laptop, and is designed so that someone who is not comfortable with software can still use it on their own.
A Next.js app, local-first with a Supabase database behind it. You sign in with your phone number and a password, your families are kept in the browser as you work and saved online a moment later, so they come back on any phone you sign in on — and a cleared browser is no longer the end of them.
There is no sign-up. Somebody asks to be let in and gives their number, the owner creates the account and sends them a link and a password. Nothing is sent by SMS or email, so no messaging provider is needed and nothing costs anything per user. See Accounts.
npm install
npm run dev # http://localhost:3000
npm run build && npm start # production
Copy .env.local.example to .env.local and fill in the two
NEXT_PUBLIC_SUPABASE_* values to connect the database. Without them the app
still runs — it falls back to local-only, where a number is just a label again
and nothing is saved online. That is the same thing a dead network gets, on
purpose, so a bad connection never locks anybody out of their own tree.
There is no sign-up screen, no OTP and no SMS provider. An account exists because you made one:
npm run invite -- +923001234567 "Nani Amma" # create, print link + password
npm run invite -- +923001234567 --reset # send them a new password
It prints a link and a password to pass on however you like — WhatsApp, a text, or read down the phone. The link carries the number, so the person only has to type the password. Passwords are generated in three short groups with no lookalike characters, because they get dictated to people.
This works with no messaging provider because phone_confirm marks the number
confirmed on the grounds that you confirmed it, by talking to them. Supabase
never sends the person anything.
scripts/invite.mjs needs SUPABASE_SERVICE_ROLE_KEY in .env.local. That key
bypasses row level security; it has no NEXT_PUBLIC_ prefix, so Next.js never
puts it in the browser bundle. Keep it that way.
To take somebody's access away without deleting anything, set
family_accounts.is_active to false.
This part drove most of the design decisions, so they are worth spelling out:
| View | What it is for |
|---|---|
| Family | One person and their immediate family. The default, and the easiest. |
| Whole tree | The full chart — pan, zoom, collapse branches. |
| List | Every person, searchable. |
Choosing اردو sets lang and dir on the document, and the layout flips
right-to-left throughout — the back arrow, the tabs, the cards, the forms.
Urdu text is set in Noto Nastaliq Urdu with the extra leading Nastaliq needs.
Every person can carry two names, one in Latin script and one in Urdu. Whichever matches the current language is shown large, and the other is shown underneath, so a family with relatives who read only one of the two scripts still works.
The language switch sits in the header on every screen rather than inside Settings, and each option is written in its own script — someone who opens the app in a language they cannot read is still one tap from fixing it.
Two places, and that is deliberate.
The browser holds the copy you are working on, filed under your number, so the
app is instant, works with no signal, and can undo. A second or so after you stop
editing, each changed family is written to the family_trees table in Supabase.
The line under the family list says which of those has happened.
Signing in on a new phone pulls your families down. Row level security is what
keeps them yours: every policy is owner_id = auth.uid(), so the database itself
refuses to hand your trees to anyone else.
A sync never destroys a tree. When the two copies disagree, the one edited
more recently wins, and a family that only one side has is kept rather than
deleted — the same rule the backup import has always followed. The reasoning is
in lib/cloud.ts: for somebody whose only other copy is a file they have
probably never saved, a wrong deletion is unrecoverable and a duplicate is not.
Deleting a family on your device does delete it online; a family that merely went
missing is treated as one to restore.
Settings → Backup → Save a backup file still writes everything to one JSON file, and still works offline — it is the one copy that does not depend on anybody else's servers.
Off until you ask for it. Share on a family card gives a link that anyone can open, with no account, to read that family — they cannot change anything. Turn it off and the link stops working. Nothing else about you is on that page.
{
"version": 1,
"settings": { "locale": "en", "textScale": 1 },
"trees": [
{
"id": "t1a2b3c4",
"name": "The Khan Family",
"nameUr": "خان خاندان",
"rootId": "karim-khan",
"focusId": "karim-khan",
"people": [
{
"id": "karim-khan",
"name": "Karim Khan",
"nameUr": "کریم خان",
"gender": "m",
"birth": "1948",
"fatherId": null,
"motherId": null,
"spouseIds": ["ayesha-khan"],
"notes": "Free text."
}
]
}
]
}
Only id and name are required on a person. Dates are free text on purpose —
1952, c. 570 CE and 11 AH / 632 CE all work, and nothing tries to parse
them.
Imports are repaired rather than rejected: references to people who are not in the file are dropped, marriages are made to point both ways, duplicate ids are renamed, and any parent link that would make someone their own ancestor is removed.
"See an example" loads the lineage of Prophet Muhammad ﷺ — 85 people from ʿAdnan down to the beginnings of the sayyid and sharif houses. It sits alongside your own families and can be removed like any other.
The ascending chain from the Prophet ﷺ to ʿAdnan — 21 forefathers — is the portion the classical biographers agree on; Ibn Ishaq (through Ibn Hisham's Sira), Ibn Saʿd's Tabaqat and al-Tabari's Tarikh all transmit it identically. Ancestry above ʿAdnan, up to Ismaʿil ibn Ibrahim, is disputed and is deliberately left out — Ibn Ishaq himself stops there. Where the sources disagree with each other (Shahrbanu's identity, whether Maria al-Qibtiyya is counted among the wives), the note on that person says so.
Names carry an Urdu spelling alongside the Latin one, and titles are given in both languages. The longer historical notes are in English only.
Dates are approximate: pre-Hijra figures CE only, later ones AH/CE, and c.
marks anything the sources do not fix precisely.
Solid lines follow the paternal line. Each person appears exactly once, under their father where the father is in the chart and under their mother otherwise — which is what keeps a grandchild attached through their mother when the father married in from outside the family.
Dashed lines mark the other parent where both are in the chart. Spouses are not given cards of their own; they are listed on their partner's card and have full entries everywhere else. That is why the example draws 46 cards for 85 people.
app/
layout.tsx fonts, providers, document shell
page.tsx home - the list of families
settings/page.tsx language, text size, backup
tree/[id]/page.tsx one family, and the three views
globals.css theme tokens, type scale, RTL-safe base styles
components/
LocaleShell.tsx puts language and text size onto <html>
Header.tsx header bar and the language switch
FamilyView.tsx the default one-person-at-a-time view
ChartView.tsx the pan/zoom chart
ListView.tsx searchable list
PersonSheet.tsx one person: details and every action
PersonForm.tsx add and edit
ui.tsx buttons, fields, sheet, confirm, avatar
Toast.tsx one message at a time, with an undo action
lib/
types.ts Person, Tree, Settings
family.ts relationship rules, repair, attach
layout.ts chart shape and positioning
store.tsx state, device storage, undo, import/export
accounts.ts phone numbers: normalising, and which one is open
cloud.ts reading and writing trees in Supabase, and the merge rule
supabase.ts the one browser client
seed.ts the bundled example
scripts/
invite.mjs create an account and print its link and password
supabase/migrations/ the family_accounts and family_trees schema
lib/family.ts, lib/layout.ts, lib/accounts.ts and lib/cloud.ts are plain
functions with no React in them,
so the rules about how relatives hang together can be reasoned about — and
tested — on their own.
npm run invite -- <number> --reset.