BinaryDevil/bunny-math
BinaryDevil/bunny-math has 34 GitHub stars and 18 forks. GitHot measured 0 stars in 24 hours. Last checked 2026-11-09 17:12 UTC. Last push 2026-11-04.
Cute maths practice for kids around 8: adding and taking away, or all four operations. Adventures with Rascal, 5-emoji share codes, step-by-step "Show me how", printable worksheets, 9 languages. No accounts; progress stays on the device. Play at bunnyland.app.
Measured star growth
- in 24h
- 0
- in 7 days
- Collecting history
- in 15 days
- Collecting history
- in 1 month
- Collecting history
Net star changes over overlapping periods, not daily totals. Missing measurements are left blank. Stars measure attention, not software quality.
README.md
OriginalBunny Math 🐰
Cute maths practice for kids around 8: adding and taking away, or all four operations. Play it at bunnyland.app, the home of the Bunny games.
There are no accounts. Progress is saved on the device. The only thing that ever goes to a server is the optional carrot leaderboard, under a made-up name.
What's in it
Practice
- Two modes, picked on the first visit and switchable from the home screen:
- Add & take away, 6 levels: within 20, no carrying, carrying/borrowing, two-digit sums, three-digit sums, and three-digit sums with lots of carrying (including borrowing across a zero)
- All four, 4 levels: tables of 2, 5 and 10; tables up to 5; tables up to 10; two-digit × and ÷ by one digit. Two thirds of the questions are × or ÷.
- 5 question types: type the answer, pick the answer, missing number, compare (< = >), picture stories
- Missed questions come back at the end; results show stars, skills, and a sticker reward
- Printable worksheets with an answer key (🖨️ on the home screen)
Worksheet pages (for search engines, and for parents who arrive from one)
- bunnyland.app/worksheets/: a plain page per level with a printable sheet and its answers, in all 9 languages (
/zh-cn/worksheets/,/fr/worksheets/, …). No JavaScript needed. - "Practice online" opens the app at that level, in that language (
?code=…&lang=fr). - Made by
npm run build, together withsitemap.xml. Page addresses (SLUGSinsrc/pages/worksheets.ts) must never change, because search results link to them.
Adventure (meet Rascal, Bunny's mischievous twin)
- Cross 3 meadows of questions with 3 hearts, then beat Rascal in a showdown at the end of each one
- Right answers win carrots: harder levels and harder sums pay more
- New things unlock one run at a time: treats at rest stops (lucky clover, carrot cake, magnifier), then a Sunny or Tricky path, then a tougher Rascal after 3 wins
Share codes
- Every quiz and adventure has a 5-emoji code, like 🍓🦄🌙🐱🌸. Typing it in (🔑 Have a code?) or opening a
?code=link gives exactly the same questions on any device, so siblings can race each other. No server is involved. - Old
?seed=123links still work.
Carrot Champs leaderboard
- All-time carrot totals from Adventure, shared across every Bunny game
- Names are picked from kid-safe word lists (like "Bouncy Otter"), never typed
- Runs played offline are sent once the device is back online
Show me how
- Explains each question step by step, in one of two styles (the choice is remembered):
- Blocks: hundreds, tens and ones blocks, and dot arrays for × and ÷
- Columns: the written column method (竖式), one column at a time, with carried digits, borrow dots, and long division
9 languages: English, 简体中文, 繁體中文, Français, Español, Deutsch, 日本語, 한국어, Português. The 🌐 button picks one; on the first visit it follows the browser's language.
Run it
npm install
npm run dev
npm test
npm run build && npm run test:e2e # every screen, 9 languages, phone/landscape/desktop sizes in WebKit (~5 min); needs `npx playwright install webkit` once
npm run dev runs without the leaderboard, which just doesn't show. To try it against the live server, put VITE_LEADERBOARD_URL=https://api.bunnyland.app in .env.local. Builds (npm run build) always use the address in .env.production.
Deploy
The site is a Cloudflare Worker serving the built files, set up in wrangler.toml.
- Automatic: Cloudflare builds every push to
main(npm test && npm run build, thennpx wrangler deploy) and puts it live at bunnyland.app. If a test fails, nothing is deployed. Pushes to other branches get a preview build. The build settings live in the Cloudflare dashboard: Workers & Pages → bunnyland → Settings → Builds. - By hand:
npm run deploybuilds and deploys from your machine (runnpx wrangler loginonce first).
The build uses relative paths, so it also works under a sub-path like bunnyland.app/math/.
The leaderboard server (worker/) is a separate Worker and is deployed by hand: see worker/README.md. The app finds it through VITE_LEADERBOARD_URL in .env.production.
Checks: the Checks workflow (.github/workflows/ci.yml) runs the app's and the leaderboard server's tests on every PR and on main.
GitHub Pages only forwards old links now. Every push to main publishes redirect/index.html, which sends binarydevil.github.io/bunny-math/… to bunnyland.app and keeps ?code= links working (see .github/workflows/deploy.yml).
Where things are
src/lib/generator.ts: makes the questions for each levelsrc/lib/explain.ts: builds the "Show me how" stepssrc/lib/run.ts: one Adventure run (meadows, hearts, showdowns, treats, paths), as plain data with no screenssrc/lib/carrots.ts: what Adventure pays in carrots. The leaderboard server uses it too, to turn away impossible scores.src/lib/codes.ts: the 5-emoji share codessrc/lib/leaderboard.ts: talks to the leaderboard server, with an offline queuesrc/lib/names.ts: the word lists for leaderboard names, shared with the server. Only add words to the end.src/lib/storage.ts: everything saved on the devicesrc/lib/worksheet.ts: the questions on a printed sheet, shared by the app and the worksheet pagessrc/pages/worksheets.ts: the static worksheet pages and the sitemap, written intodist/by a small plugin invite.config.tssrc/components/: the screens (home, quiz, results, adventure, leaderboard, sticker book, worksheet) and the two bunnies (Bunny.tsx,Rascal.tsx)src/i18n/: translations, one file per language, pluspages.tsfor the worksheet pages (see below)public/: copied into the site as is: icons,og.png,robots.txt,manifest.webmanifest(for adding the app to a home screen)src/styles.css: colors, fonts, and layouts for tablets and phonesworker/: the leaderboard server (Cloudflare Worker + D1 database)e2e/: browser tests that screenshot every screenredirect/: the page GitHub Pages serves to forward old linksdesign/: the original clickable mockup, a gallery of screens, andog-card.html, the picture shown when the link is shared (public/og.png, 1200×630). After editing it, take a 1200×630 screenshot of it and save overpublic/og.png.
Languages
All the words the app shows, including the "Show me how" steps and the printed worksheets, live in src/i18n/. en.ts is the source of truth: every other language is typed as Messages, so TypeScript reports a missing or extra key, and npm test checks that every language has the same keys and {placeholders} as English.
{name}is filled in by the code;*stars*mark highlighted words in the explanations._one/_otherpairs are plurals (picked withIntl.PluralRules). Languages without plurals repeat the same text.- Numbers always use the digits 0–9, and the signs + − × ÷ stay the same in every language.
- The choice is saved on the device. Until a language is picked, it follows
navigator.languages(zh-TW, zh-HK and zh-Hant → 繁體中文, other zh → 简体中文, pt-BR and pt-PT → Português), falling back to English. - The link preview tags in
index.htmlstay in English, since link previews don't run the app. - The words on the worksheet pages are in
src/i18n/pages.ts, kept apart so the app doesn't download them. Same rules: every language has the same keys and{placeholders}as English (checked bynpm test).
To add a language:
- Copy
src/i18n/fr.tstosrc/i18n/<code>.ts, rename the export, and translate the values (keep{placeholders}and*stars*). - In
src/i18n/index.ts, add it toLANGS(code, native name, short badge) and toMESSAGES. If the browser uses a different code for it, teachdetectLangthe mapping. - If it uses a script the web fonts don't cover, add system fonts for it in
src/styles.css(see the--cjklines). - Run
npm testandnpm run build.
License
All rights reserved. The code is public to read, not to reuse: see LICENSE.
Explore related projects
sindresorhus/awesome
😎 Awesome lists about all kinds of interesting topics [NOTE: Pull requests are temporarily disabled until I have a chance to catch up with the existing ones]
534,238 starsEbookFoundation/free-programming-books
:books: Freely available programming books
401,384 starsnilbuild/developer-roadmap
Interactive roadmaps, guides and other educational content to help developers grow in their careers.
371,671 starsvinta/awesome-python
The definitive list that answers "I want to do X in Python, which tool should I use?"
333,607 stars