The idea
Streaks today work in Zeeguu the way they do everywhere: practice every day and the number goes up; miss a single day and it resets to zero. That's a powerful motivator when your streak is short, but brutal once it gets long — a 200-day streak that breaks because you caught the flu feels devastating, and most people who lose a long streak just quit instead of starting over from one.
What if streaks behaved like planets in space? Two big enough streaks that sit close enough together would pull each other in and merge into a single streak. A 200-day streak will automatically pull together a fresh 10-day streak over a two day break. They'd snap together with a satisfying pull could be nicely visualized, and you'd be back at "210 days, with one day off." The longer your streaks, the more forgiving the universe is about a gap between them.
The rule is the same one gravity uses: pull strength depends on how big each streak is and how close they sit, and it falls off fast as the gap grows. Tiny streaks can't reach across anything. Big streaks can bridge a few days. Two enormous streaks separated by two weeks still won't merge — the universe rewards investment, not infinite slack. People intuit gravity already, so there's no rule to memorize: bigger pulls harder, far doesn't pull at all.
The killer moment is the merge itself. A user finishes their first session after a gap, opens the streak page, and watches their old streak visibly drift across the empty days and snap into the new one:
Your 47-day streak from February pulled your new 8-day streak in.
Combined: 55 days.
That's a screenshot moment. The explanation page can be a little physics playground — two draggable streak-blobs and a slider for the gap — so people learn the rule by playing with it instead of reading docs.
The mechanic does the thing streaks need to do (small streaks still die when you miss a day, so the daily pull on new users is as urgent as ever) while quietly fixing the thing that makes long streaks brittle: one bad week erasing a year of practice. It feels generous without feeling cheap, because the forgiveness is earned — you only get it after you've already invested.
The formula
For two adjacent streaks of length `L₁` and `L₂` separated by a gap of `G` days:
```
pull = (L₁ × L₂) / G²
```
If `pull > THRESHOLD`, they snap together.
Examples (with `THRESHOLD = 50`):
| Streak A |
Gap |
Streak B |
Pull |
Snaps? |
| 30 |
1 |
30 |
900 |
yes |
| 30 |
7 |
30 |
18 |
no |
| 100 |
14 |
100 |
51 |
yes |
| 5 |
1 |
5 |
25 |
no |
| 5 |
1 |
100 |
500 |
yes (rescues a long streak) |
| 5 |
10 |
100 |
5 |
no |
Honest counting
The combined number is `L₁ + L₂` (the gap days don't count as practiced — that would be a lie). The visual is one continuous block with a faint gap-shadow showing the days the gravity bridged. Honest data, magical UX.
Schema implication
The current `user_language.daily_streak` counter only models the current streak — past streaks are lost. To support this we need streaks as intervals:
```sql
CREATE TABLE streak_interval (
id INT PRIMARY KEY,
user_language_id INT NOT NULL,
start_date DATE NOT NULL,
end_date DATE NOT NULL,
merged_into_id INT NULL -- snap pointer, NULL until pulled
);
```
Backfill is one row per existing user: `(last_practiced - daily_streak + 1, last_practiced)`. The `daily_streak` column becomes derived.
This also unlocks, more or less for free:
- A GitHub-style contribution heatmap
- "Longest streak ever" leaderboards
- Historical streak browsing
- Honest recompute if someone restores from backup
Open questions (want feedback!)
- Threshold tuning. 50 is a guess. Should it scale with the user's overall practice volume so power users don't trivially snap everything?
- Cascading snaps. If A snaps to B and later B snaps to C, does A come along? Probably yes (transitive feels right), but it changes the feel.
- Snap permanence. Once a snap fires, does it lock in, or can it un-snap if the second streak later breaks before reaching some stability?
- Per-language vs cross-language. Probably per-language, but interesting to consider whether a long French streak could lend gravity to a starting-up Spanish one.
- Anti-gaming. Could someone exploit this by deliberately taking strategic breaks? Probably not — the math punishes long gaps hard — but worth modelling.
Prior art
Closest thing in the wild is Duolingo's Streak Freeze (one-day passive grace) and Streak Repair (paid restore). Neither requires earning the recovery. The "snap two streaks together" mechanic appears to be novel — couldn't find anyone shipping it. Duolingo has actually A/B-tested stronger forgiveness and seen engagement drop, which is part of why this approach is interesting: it doesn't soften the daily pull at all, it only rewards long-term investment.
🤖 Drafted with Claude Code
The idea
Streaks today work in Zeeguu the way they do everywhere: practice every day and the number goes up; miss a single day and it resets to zero. That's a powerful motivator when your streak is short, but brutal once it gets long — a 200-day streak that breaks because you caught the flu feels devastating, and most people who lose a long streak just quit instead of starting over from one.
What if streaks behaved like planets in space? Two big enough streaks that sit close enough together would pull each other in and merge into a single streak. A 200-day streak will automatically pull together a fresh 10-day streak over a two day break. They'd snap together with a satisfying pull could be nicely visualized, and you'd be back at "210 days, with one day off." The longer your streaks, the more forgiving the universe is about a gap between them.
The rule is the same one gravity uses: pull strength depends on how big each streak is and how close they sit, and it falls off fast as the gap grows. Tiny streaks can't reach across anything. Big streaks can bridge a few days. Two enormous streaks separated by two weeks still won't merge — the universe rewards investment, not infinite slack. People intuit gravity already, so there's no rule to memorize: bigger pulls harder, far doesn't pull at all.
The killer moment is the merge itself. A user finishes their first session after a gap, opens the streak page, and watches their old streak visibly drift across the empty days and snap into the new one:
That's a screenshot moment. The explanation page can be a little physics playground — two draggable streak-blobs and a slider for the gap — so people learn the rule by playing with it instead of reading docs.
The mechanic does the thing streaks need to do (small streaks still die when you miss a day, so the daily pull on new users is as urgent as ever) while quietly fixing the thing that makes long streaks brittle: one bad week erasing a year of practice. It feels generous without feeling cheap, because the forgiveness is earned — you only get it after you've already invested.
The formula
For two adjacent streaks of length `L₁` and `L₂` separated by a gap of `G` days:
```
pull = (L₁ × L₂) / G²
```
If `pull > THRESHOLD`, they snap together.
Examples (with `THRESHOLD = 50`):
Honest counting
The combined number is `L₁ + L₂` (the gap days don't count as practiced — that would be a lie). The visual is one continuous block with a faint gap-shadow showing the days the gravity bridged. Honest data, magical UX.
Schema implication
The current `user_language.daily_streak` counter only models the current streak — past streaks are lost. To support this we need streaks as intervals:
```sql
CREATE TABLE streak_interval (
id INT PRIMARY KEY,
user_language_id INT NOT NULL,
start_date DATE NOT NULL,
end_date DATE NOT NULL,
merged_into_id INT NULL -- snap pointer, NULL until pulled
);
```
Backfill is one row per existing user: `(last_practiced - daily_streak + 1, last_practiced)`. The `daily_streak` column becomes derived.
This also unlocks, more or less for free:
Open questions (want feedback!)
Prior art
Closest thing in the wild is Duolingo's Streak Freeze (one-day passive grace) and Streak Repair (paid restore). Neither requires earning the recovery. The "snap two streaks together" mechanic appears to be novel — couldn't find anyone shipping it. Duolingo has actually A/B-tested stronger forgiveness and seen engagement drop, which is part of why this approach is interesting: it doesn't soften the daily pull at all, it only rewards long-term investment.
🤖 Drafted with Claude Code