A walk through the app as a new Form 4 student, with one question: what brings me back tomorrow?
The app has a streak, freezes, a weekly quest, a league, a star jar, badges, coins, a feed and a daily word. What it does not have is the two things that actually produce a return visit:
And the first session is front-loaded: seven required fields, an email code, then an eight-screen warm-up before the first minute of English. Meanwhile production still runs the 20-minute day the interviews already called heavy. The 5-minute day, the feed and the long-lesson row are all on staging.
The single biggest stickiness action is not a design change. It is promoting staging to main. Until then, every return-rate read comes from the version we already decided against.
Staging shape, Form 4, day 1. Times are my own on a laptop; a student on a phone with data will be slower.
Full name, username, email, mobile, state, school, form. The school picker is excellent. Mobile is collected and never used anywhere. A consumer signing up alone has no reason to give a school yet.
Fine. Students never check email (Yu Juinn), so expect the drop here to be real on prod.
Feels like content, not a test. Mic offered, never required. BM button and slow play are exactly the embarrassment-blocker answer. Step 2 asks the student to "Help Aina answer" and the answer is a question ("Can I have iced Milo?"), which reads oddly. Ends by dropping the student straight into Day 1, no Home detour. Good.
I answered wrong. The card explained why and then offered Collect +15 XP. Grammar Tap and Story Stack already pay nothing for a wrong answer; Listen still does. The explanation also uses an em dash and "signals a one-off change", above the B1 line.
Collecting XP returns to Home. Home is 3.5 screens long. The student scrolls past the feed teaser, stats, and the weekly quest to find step 2. This happens three times per day.
Four items, one rule card. Item 4 is "I see your point, but I disagree" and the feedback still says "give one reason with because". A student who reads feedback once and finds it generic stops reading feedback. This is the open per-item follow-up from PR #179 and it is visible on day 1.
Roly says "Give your view and one reason. SPM-style answer." On what? The topic only appears if you tap Hint. The one speaking moment of the day starts in confusion. The blocked-mic path is very good: clear message, try again, or type it.
"That is today done. Five minutes, and you showed up for them." Then Say More, a feed handoff, "Tomorrow: Day 2 · Giving an opinion", and "Start day 2 now". PR #180 tightens this to one Keep going button. Neither version tells me what will be new tomorrow.
The voice is right ("handphone is fine la"). Payoffs land. I reached the bottom in one scroll: "That is everything for now. Roly pun rehat dah." The thesis said never show the bottom. Votes live in localStorage only.
Listen → Build → Speak with a fixed 60-XP day is honest, finishable and legible. "Today · about 5 minutes" is the best line on Home. The 4th-row long lesson (greyed, playable, "open any time") is the right pattern for optional depth.
Staging · lib/program-v2.tsEvery speaking surface has a tap or type fallback with plain copy. For a product whose root blocker is embarrassment, this is the feature. Keep it sacred.
Calibration, micro-speak, v1 recorderTwo minutes that feel like play, land the student in content, and quietly record signals. The only onboarding step that earns its place.
lib/quiet-calibration.ts"Your 5-day streak paused. That's all it is, paused." Keeps XP, shows the best run, one CTA. This is how you keep a lapsed student instead of shaming them. The streak is now server-backed on bootstrap, so An Ran's reset bug should be closed.
components/screens/StreakLost.tsxSchool-life polls, Manglish quick picks, chat choices with real consequences. Self-refilling units that cost nothing to answer. "New cards tomorrow" is the strongest tomorrow-hook in the app, and it is on the one page that is off in prod.
lib/feed/bank.ts · 51 cardsPostHog identifies by backend user id, resets on logout, and fires lesson_started, lesson_abandoned and day_completed. Return rate is readable from day one of the v2 launch. Define D1 and D7 on day_completed and read it weekly.
lib/track.tsThe day is not time-gated, the free head start is 7 days, and the done screen invites "Start day 2 now". Bingeing is fine; the problem is that tomorrow offers nothing you cannot have now. Only the games (daily word, crossword), the feed and the star jar are on a calendar, and they all sit below the fold.
Each step ends on Home. The hero updates ("Up next 2 of 3") but the student re-reads greeting, feed teaser, stats and quest card to reach the next step. On a phone that is a lot of thumb for a 5-minute promise.
Wrong Listen answers pay full XP. Grammar Tap shows one rule for four different items. Speak has no visible question. Each one alone is small; together they teach a student that the app is not really paying attention, and attention is the whole pitch of "Roly listens".
Seven fields, a code, eight warm-up screens. The warm-up earns its time. The form does not: a consumer student cannot see why a mobile number or a school is required to try a lesson.
Coins appear on lesson rows, the quest, the jar, the milestones and the freeze sheet. Their only sink is one streak freeze at 120. The weekly quest pays 60, the full star jar 20. Two perfect weeks for one freeze is a bad deal, and a student notices.
Order today: greeting, hero, feed teaser, stats, weekly quest (with a boba cup), then today's steps, Say More, six game tiles. The thing we want done is the sixth thing on the page.
31 cards, then "That is everything for now". The window is 8 cards a day plus four back-days; a first-day student clears it in two minutes. Votes are per device, so a cleared cache re-asks everything.
Prod Home: "This day was already complete" on an unstarted day. Warm-up done: "Start Day 1 · One short lesson" while the v2 day is three steps. Listen explanations with em dashes and idioms. Calibration step 2 says "answer" and expects a question.
Searched the whole client: no push notifications, no service worker, no PWA manifest or install prompt, no reminder setting, no email beyond the login code, no share card except the feed's "Who are you" result. If a student closes the tab, the app has no voice.
Weekly XP leaderboard, prizes off in prod, polled every 30 seconds. On a small cohort it is five names. Under v2 the day is capped at 60 XP, so the board becomes "who did the most bonus", which is the opposite of the 5-minute promise. Hide the drawer row until a class of 30+ is live, or scope it to the class.
"Practise on 3 days", "Finish 9 activities", "Complete 2 full days" overlap almost entirely. One task, "Finish 3 days this week", says the same thing in a quarter of the space and does not need a boba meter.
Two optional clips behind a lock on a day that is already only three steps. A padlock on optional content reads as a wall. The long-lesson row already does greyed-but-playable; do the same here.
Star jar, Daily Word, Spelling Bee, Balloon Rescue, Crossword: six tiles and two calendars ("new jar on Monday", "new puzzle tomorrow"). Keep Daily Word (one a day, a real tomorrow hook). Fold Spelling Bee and Balloon Rescue into Say More. Drop the star jar or the crossword; one calendar reward is enough.
Neither is used by the product today. Every field before the first lesson is a drop-off point on a phone.
It scrolls Home to the quest card. A menu row that goes to the same page it came from is confusing on a phone.
"Learn · phrases", "Listen to a model answer" and the four-lesson listening block go away with the v2 promote. Do not carry any of them into the v2 Home.
Everything below assumes students are on the 5-minute day. Today they are not.
Done screen names what arrives tomorrow and the nearest badge. Then a reminder channel so the app can say it out loud.
Email, username, form. School moves to Join a class. Keep the warm-up exactly as it is.
Chain Listen → Build → Speak. Reorder Home so today's steps sit under the hero. Unlock Say More.
No XP for a wrong Listen answer. Per-item Grammar Tap rules. Show the Speak question. Fix the day-1 copy.
How to know it worked: D1 and D7 return on day_completed in PostHog, split by feed door versus Home. Baseline the week before the promote so v1 and v2 can be compared.
| Mechanic | Comes back tomorrow? | Survives a new phone? | Note |
|---|---|---|---|
| Streak | Calendar day | Yes (server on bootstrap) | Freezes and milestones still local only |
| Weekly quest | Mon–Mon reset | No (localStorage) | 60 coins, three overlapping tasks |
| League | Weekly reset | Yes | Prizes flag off in prod |
| Star jar | Empties Monday | No | 1 star per game per day, 20 coins per jar |
| Daily Word | One per day | No | No XP by design; real tomorrow hook |
| Crossword | One per day | No | Second calendar in the same block |
| Feed | 8 new cards a day | No | Off in prod; end card visible |
| Day N+1 | Available now | Yes | No wait; 7-day free head start |
| Coins | n/a | Hybrid | Only sink: freeze at 120 |
| Badges | 3 / 7 / 14 / 30 / 60 days | Local | Only visible on Profile |
| Push / email / share | — | — | Not built |
Not verified in this pass: the live league screen (needs the backend), audio quality on prod, and the LLM coach on a real recording. The v1 speaking lesson with a blocked mic shows "Didn't catch that, tap the mic or type", which is the right fallback.