Compute Dynamic Beverage Nutrition Facts for the exact drink a customer ordered β from your POS, kiosk, or ordering app. Fully integrated with Foodlang and ORF, so an executable recipe and its label share one source. The engine runs in the browser today; a hosted REST API is on the way.
What you can build
Drop in engine.js and call window.BevFacts β compute, round, declare, and render labels with zero network calls.
Parse any Foodlang .food drink into a label, and export drinks as ORF-style .food.yaml. Details below β
Encode a whole drink into a shareable link or QR code. Scannable by any phone, resolvable with no backend.
Compute and persist labels server-side, render PNG/SVG, and pull vendor recipe tables over HTTP.
Subscribe to cup.returned and label.created events with signed, replay-protected payloads.
Publish and consume base recipes, milks, syrups, and toppings as machine-readable JSON.
Quickstart
The engine is a single static file with no dependencies. Everything below runs on this very page β open your console and try it.
<script src="engine.js"></script>
<script>
// Base recipe + the modifiers the customer ordered
const order = {
drinkName: "Caramel Latte",
calories: 250, sugars: 33, addedSugars: 28, caffeine: 150,
totalFat: 7, satFat: 4.5, sodium: 170, totalCarb: 35, protein: 10,
sweetness: 100, pumps: 3, shots: 2 // +3 syrup pumps, +2 espresso shots
};
const facts = BevFacts.compute(order); // unrounded, as-ordered
const declared = BevFacts.declare(facts); // 21 CFR 101.9 rounded strings
const warnings = BevFacts.warnings(facts); // e.g. ["added_sugars_over_100pct_dv"]
const link = BevFacts.link(order); // shareable deep link / QR target
</script>
Live playground
Edit the order JSON and press Run. This calls the real window.BevFacts API loaded on this page β the same code your integration would ship.
Order (JSON)
Result
Rendered label
Reference
window.BevFacts API| Member | Signature | Returns |
|---|---|---|
version | string | Spec version, e.g. "1.0-draft" |
DV | object | Daily-value table (added sugars 50, sodium 2300, β¦) |
PRESETS | array | Example base recipes |
compute(order) | (state) β nutrients | Unrounded as-ordered vector (sweetness, pumps, shots applied) |
declare(nutrients) | (nutrients) β strings | FDA-rounded declaration strings + %DV |
warnings(nutrients) | (nutrients) β string[] | Machine-readable warning flags |
round | {calories, fat, β¦} | The individual 21 CFR 101.9 rounding functions |
labelHTML(order) | (state) β string | Inner HTML of a ready-to-style Nutrition Facts label (add qr:true for a scannable QR) |
labelSVG(order) | (state) β string | A standalone, print/PNG-ready SVG label (no foreignObject) |
encodeState / decodeState | (obj) β (string) | Compact URL-fragment codec (short keys, defaults omitted) |
link(order) | (state) β string | A deep-link URL encoding the whole order (the QR target) |
foodlang | {parse, estimate, toFood, toORF, fromRecipe} | The Foodlang/ORF bridge β see below |
pdf | {singleLabel, sheet} | FreshPDF (freshpdf.com) β build a real PDF from rasterized label images, in-browser |
Integrations
BevFacts is the nutrition layer for Foodlang β the ORF-compatible executable-recipe language. A .food drink compiles to coffee machines, robots, and the web; BevFacts makes the same source compile to a Nutrition Facts label.
Paste any Foodlang drink into the generator (or call BevFacts.foodlang.parse + estimate) and its ingredients are costed against the DBNF reference tables into a full label. Unmatched ingredients are reported, never silently guessed β same honesty rule as Foodlang's fidelity grades.
Export any recipe-builder drink as a .food document (ingredients + phases) or as ORF-style .food.yaml with X-Phases and an X-Nutrition block carrying the DBNF values β the X- prefix per the ORF extension convention.
// the foodlang.com homepage example, straight into a label const rec = BevFacts.foodlang.parse(`drink "Iced Vanilla Latte" { ingredients { coffee 18 g; vanilla_syrup 20 ml; milk 10 oz; ice 140 g } }`); const { state, unmatched } = BevFacts.foodlang.estimate(rec); document.body.innerHTML = BevFacts.labelHTML(state); // 144mg caffeine, 24g sugarβ¦ // and back out: recipe-builder drink β ORF-style .food.yaml const food = BevFacts.foodlang.fromRecipe({ base: "latte", milk: "oat", pumps: 3, syrup: "flavor" }, BevFacts); BevFacts.foodlang.toORF(food, state, BevFacts); // recipe_name / X-Phases / X-Nutrition
Draft Β· hosted API
The wire format is specified and stable enough to build against; endpoints are not yet hosted. Full details β auth, idempotency, pagination, webhooks, and errors β live in Part 5 of the spec.
| Endpoint | Purpose |
|---|---|
POST /v1/labels | Compute & optionally render a label (PNG / SVG / JSON) |
GET /v1/labels/{id} | Retrieve a computed label document by id or hash |
GET /v1/presets | List a vendor's published base recipes |
GET /v1/cups/{id} | Deposit / return state for a reusable cup |
POST /v1/cups/{id}/return | Record a return scan; emit cup.returned |
curl https://api.bevfacts.example/v1/labels \
-H "Authorization: Bearer bf_live_β¦" \
-H "Content-Type: application/json" \
-d '{ "drink": { "name": "Caramel Latte", "servingSize": { "amount": 16, "unit": "fl_oz", "ml": 473 } },
"base": { "calories": 250, "sugars_g": 33, "addedSugars_g": 28, "caffeine_mg": 150 },
"modifiers": [ { "type": "syrup_pump", "count": 3 }, { "type": "espresso_shot", "count": 2 } ],
"render": ["png", "json"] }'
Want the hosted API, webhooks, or an SDK for your stack?
The REST surface, event signatures, and cup-return lifecycle are specified in the open. Follow along or weigh in via GitHub, or read the full API specification.