RevenueCat Shipaton 2026 · Nutrition & Healthy Eating

Your lunch is paid for. Lauk asks what it's missing.

Rice and one side from the stall downstairs, already bought, eaten in minutes. Tap it, tap what you'd spend, and Lauk returns three one-add upgrades, cheapest first — from 40 hand-authored adds across 12 plates. Raw veg + chili takes this plate from 2 of 5 to 4 of 5.

View on GitHub Pitch deck Google Play · coming soon

offline · no account · no backend

The pillar ring around the plate: filling lit, rich half-lit; the add you pick lights more. 2 of 5 LIT

LAUK · ORDER SLIP

Rice plate + one sidebought
ceiling · Small≤ Rp 2k
plate2 of 5 → 2 of 5 lit
filling ● fresh ○ rich ◐ bright ○ crunch ○
Eat until satisfied, not until empty.

Rung up at the counter · every number is in the repo

Checked before a single plate is served.

76tests passingnpm test
150,000queries checked, 0 violationstests/exhaustive.test.ts
12RevenueCat calls, one fileapp/src/rc/purchases.ts
22 → 0banned words found in the copyapp/src/core/lint.ts

The plate check · the same answer, twice

The app and the terminal agree — one pure function.

The ranker in app/src/core/rank.ts runs on the phone and in your terminal. Same plate, same ceiling, same two cards, deterministic across 1,000 runs.

Lauk on Android: Rice plate + one side, Small ≤ $1, 2 of 5 lit. Lime wedge, free, lifts bright; raw veg + chili, ≤ $1, lifts fresh and bright.
the cards · 2 of 5 lit
After tapping lime wedge: 3 of 5 lit, and the line: Eat until satisfied, not until empty.
tap one · 3 of 5 lit
zsh — lauk
$ npm run check -- rice_side 1

Rice plate + one side (nasi + 1 lauk) · Small ≤ Rp 2k
plate  filling ●  fresh ○  rich ◐  bright ○  crunch ○   2 of 5 lit

1. Lime wedge (jeruk nipis) — Free → lifts bright
   after  filling ●  fresh ○  rich ◐  bright ◐  crunch ○   3 of 5 lit
2. Raw veg + chili (lalapan + sambal) — Rp 2.000 → lifts fresh + bright
   after  filling ●  fresh ◐  rich ◐  bright ◐  crunch ○   4 of 5 lit

Eat until satisfied, not until empty.

Screens: signed release APK on an Android 15 emulator, 2026-09-26, USD locale. Terminal: run 2026-09-26, IDR reference prices. Same tier, same two cards — outside IDR the labels are tier ceilings, not exact prices.

On the counter · six real screens, one flow

From the plate you bought to a face after the meal.

No search, no camera, no typing. The faces at the end are the only tracking — they nudge tomorrow's cards, and empty days stay blank.

  1. Onboarding: Where do you mostly eat? Student housing, An office, On the road.

    Slip 1 · where you eat sets the offer

  2. Plates: What is in front of you? Checks today 0 of 1; Counter, Instant, Delivery and Cafeteria decks.

    Slip 2 · tap the plate · 12 tiles

  3. How much more would you spend? Free, Small, Medium, Treat.

    Slip 3 · tap what you'd spend

  4. One add that would help: 2 of 5 lit, lime wedge free, raw veg + chili ≤ $1.

    Slip 4 · cheapest add first

  5. Lime wedge: 3 of 5 lit. Eat until satisfied, not until empty.

    Slip 5 · the ring fills

  6. After the meal — how was it? still hungry, fine, satisfied; this week's strip.

    Slip 6 · one face, no streaks

What's in the kitchen

Five parts, one ten-second flow.

RevenueCat is the gate, not a tip jar

A locked deck opens a paywall named after the plate you tapped; the second check of the day opens presentPaywallIfNeeded; a Targeting rule serves the Semester pass to student housing. Remove RevenueCat and every deck but Counter stays locked.

FreeCounter deck · 1 check a day
Any one deckonce · that deck + 3 checks a day
Unlimitedevery deck, no cap · 7 days free once the Play products are live
configuresetAttributessyncAttributesAndOfferingsIfNeededgetOfferingsgetCurrentOfferingForPlacementpresentPaywallpresentPaywallIfNeededgetCustomerInfoaddCustomerInfoUpdateListenerpurchasePackagerestorePurchasespresentCustomerCenter

Five pillars, never a count

Filling, fresh, rich, bright, crunch. A hollow pillar is an outline, a lit one is amber. No number about the food is ever shown.

core/pillars.ts

Cheapest first, same every time

One pure function ranks 40 adds by what they lift and what they cost. Offline, deterministic across 1,000 runs.

core/rank.ts · p95 6.0 µs

Starts from the bought plate

12 plate tiles in four decks — Counter, Instant, Delivery, Cafeteria. Universal lunches, local currency.

12 plates · 4 decks

Three faces, no streaks

Still hungry, fine, satisfied. Faces nudge five pillar weights by η = 0.15; resettable in Settings.

core/weights.ts

Honest by design · lifted from the repo

What isn't done yet, in its own words.

“Google Play: not yet published. Nothing in this repo claims a live listing.”
— JUDGE.md · Honest limitations
“The release APK has run on an Android emulator (2026-09-26), not a physical device.”
— JUDGE.md · Honest limitations
“The test was due 2026-09-20 and has not run yet”
— DEMO.md · The stall test

Questions a judge would ask

Asked at the counter.

Longer answers, and the receipts behind them, live in JUDGE.md and DEMO.md.

Can I try it today?

Not from Google Play yet — the production release is pending review. The repo builds it (npx expo run:android), and npm run check -- rice_side 1 prints the same cards in a terminal, no device needed.

What does it cost?

Free: the Counter deck, 1 check a day. Any one deck, bought once: that deck plus 3 checks a day. Unlimited: every deck, no cap — with a 7-day free trial once the Play products are live.

Is anything mocked?

No demo flag, no mock mode, no seeded user data. Without a RevenueCat key every deck but Counter stays locked and the app says so.

Why no numbers about the food?

The brief asks for more satisfying meals without counting or restrictive plans. Lauk ranks by five sensory pillars, and a test fails if any of 22 listed words appears in the app's copy.

Does it need the internet?

The plate check doesn't: the ranker is pure TypeScript, offline, no backend, no account. Buying a deck goes through Google Play via RevenueCat.

Is there a demo video?

Not yet. Until it exists, the six screens above are from the signed release build, and the terminal run is reproducible from a fresh clone.