A table of three splits a $96 dinner equally. One of them skipped the cocktails and still pays $32. I wanted a way to split one dinner by who ate what, shared plates included, and to send the result to friends who will not install anything. The result is Dollopify, a single HTML file.
Money is whole units
Amounts are integers in minor units, so a float never touches a price. A dish is split evenly among the people on it. When it does not divide evenly, the spare cents go to its owners one each, round robin, so nobody always pays them. Tax, tip and service charge are shared in proportion to what each person ordered, using the largest remainder method with BigInt for exact products.
import { fromWire } from './src/core/codec.js'
import { allocate } from './src/core/split.js'
const bill = fromWire({ v: 1, c: 'USD', p: ['Ava', 'Ben'], i: [['Pizza', 2000, 3], ['Beer', 800, 2]], x: [0, 400, 0] })
console.log(allocate(bill).people.map((p) => [p.name, p.total]))
// [ [ 'Ava', 1143 ], [ 'Ben', 2057 ] ]
A randomized test builds 3,000 bills and checks that every share adds up to the dishes plus the extras to the unit.
The bill is the link
There is no backend. The page keeps the bill in the URL fragment as minified JSON, encoded as UTF-8 and then as unpadded base64url. Each dish is a name, a price and a bitmask of who shares it. A 20 dish bill for 8 people is 710 characters after the #, or 752 with the hosted address. Browsers do not send the fragment to a server, and the build adds a Content Security Policy that blocks every network request, which a browser test checks.
A link is untrusted input
Anyone can edit a link, so the decoder validates every field: the schema version, the currency, name length, owner masks, amounts and the 8192 character limit. Names reach the page only as text, and a test feeds it an image tag and a script tag to confirm nothing runs.
What is rough
You type the amounts, because there is no receipt scanner. I ran the browser tests in Chromium and Firefox, with phone profiles for the link check, and I have not tried Safari or a physical phone. Anyone who has a link can read the bill.
The code is MIT licensed. If you have a bill where the rounding feels unfair, I would like to see it.

Top comments (0)