.me

Splitting your Bill

This demo teaches one simple idea:

Shared expenses settle themselves — every balance updates the moment a payment lands.

Three friends share a trip wallet. One pays the hotel. Another pays dinner. The graph tracks who’s owed what in real time — no spreadsheet, no app, no reconciliation step.

.me Docs · WalletSplit Source Code


The Tiny Mental Model

me.wallets.vancouver.total(300)
me.wallets.vancouver["="]("per_person", "total / members.count")
me.wallets.vancouver["="]("balance_jabellae", "paid.jabellae - per_person")

No event listeners. No recalculation calls. When total changes, per_person changes, and every balance updates — because the dependency was already declared.


What The Demo Builds

Layer Path What it means
Wallet wallets.vancouver.total Running total of all expenses
Members wallets.vancouver.members.count Number of participants
Derived wallets.vancouver.per_person Fair share — total / members.count
Payment wallets.vancouver.paid.jabellae What each person has contributed
Balance wallets.vancouver.balance_jabellae paid - per_person — positive means owed back

Step 1: Create the Wallet

me.wallets.vancouver.description("Vancouver trip — 3 people")
me.wallets.vancouver.members.count(3)
me.wallets.vancouver.total(0)

me.wallets.vancouver["="]("per_person", "total / members.count")

Step 2: Track What Each Person Paid

me.wallets.vancouver.paid.jabellae(0)
me.wallets.vancouver.paid.ana(0)
me.wallets.vancouver.paid.pedro(0)

me.wallets.vancouver["="]("balance_jabellae", "paid.jabellae - per_person")
me.wallets.vancouver["="]("balance_ana",      "paid.ana      - per_person")
me.wallets.vancouver["="]("balance_pedro",    "paid.pedro    - per_person")

Positive balance = owed money back. Negative = owes the group.


Step 3: Jabellae Pays the Hotel ($300)

me.wallets.vancouver.paid.jabellae(300)
me.wallets.vancouver.total(300)

Every balance recalculates immediately:

me("wallets.vancouver.per_person")        // 100
me("wallets.vancouver.balance_jabellae")  // +200  ← owed back
me("wallets.vancouver.balance_ana")       // -100  ← owes
me("wallets.vancouver.balance_pedro")     // -100  ← owes

Step 4: Ana Pays Dinner ($90)

me.wallets.vancouver.paid.ana(90)
me.wallets.vancouver.total(390)

The fair share shifts. All balances update:

me("wallets.vancouver.per_person")        // 130
me("wallets.vancouver.balance_jabellae")  // +170
me("wallets.vancouver.balance_ana")       //  -40
me("wallets.vancouver.balance_pedro")     // -130

Pedro owes the most — he hasn’t paid anything yet.


Explainability

Any balance can explain its own derivation:

me.explain("wallets.vancouver.balance_jabellae")
// → {
//     value: 170,
//     expression: "paid.jabellae - per_person",
//     dependsOn: ["wallets.vancouver.paid.jabellae", "wallets.vancouver.per_person"]
//   }

The chain continues: per_person depends on total and members.count. The full audit trail is always one call away.


Build It Yourself

cd npm
npm install
node tests/Demos/WalletSplit.ts

To run every demo:

npm run test:demos:run-all

The Big Idea

Group finances have one hard problem: every new payment changes everyone’s balance. Normally that means a central app maintaining state, broadcasting updates, and resolving conflicts.

In .me, the graph IS the ledger:

payment recorded → total updates → per_person updates → all balances update

No settlement engine. No reconciliation job. The reactive graph settles automatically — because that’s what derived values do.