Your study buddy that evolves while you code
> ./code-tamagotchi --status > Status:ACTIVEPlatform:ANDROIDLanguage:KOTLIN / COMPOSE
Code Tamagotchi turns programming study into an experience of care, progress and rewards. Solve challenges, finish Pomodoro sessions, earn Bytes and keep Codey happy, healthy and ready to compile.
English ยท ๐ช๐ธ Espaรฑol
|
|
|
|
- ๐ DND Mode โ focus mode that mutes notifications and grants +10% XP
- ๐ณ Skill Tree โ 3 branches, 9 unlockable nodes
- ๐ Daily rewards streak & offline rewards
- ๐ซ Season Pass โ 30-day battle pass with 20 levels
- ๐ Weekly Missions โ 3 rotating missions every Monday with rewards
- ๐ฑ Home-screen widget โ watch Codey with health, energy and hunger meters (compact 2ร2, resizable)
| Home | Challenges | Pomodoro |
|---|---|---|
![]() |
![]() |
![]() |
| Arcade | Shop | Weekly Missions |
![]() |
![]() |
![]() |
| Themes | Skill Tree | Season Pass |
![]() |
![]() |
![]() |
๐จ 12 premium themes with unique animated Canvas backgrounds. ๐พ Watch Codey evolve from Egg to Legendary as you study.
# Clone
git clone https://github.com/fguzman-stack/CodePet.git
cd CodePet
# Build the dev APK
./gradlew clean assembleDebug
# Install on device/emulator
adb install -r app/build/outputs/apk/debug/app-debug.apkOr just grab the prebuilt APK from Releases โ no build tools needed.
The project uses Gradle 9.x with the Gradle Wrapper. Requires: JDK 17+, Android SDK (API 36). The app is 100% offline โ no API keys, accounts or secrets needed to build or play.
STUDIES SOLVES EARNS
+------------+ +------------+ +------------+
| Pomodoro | --> | Dev | ---> | XP + Bytes |
| | | challenges | | |
+------------+ +------------+ +-----+------+
|
v
+------------+
| CARES |
| CODEY |
+-----+------+
|
v
UNLOCKS THEMES
Every finished session strengthens your pet. Every correct challenge speeds up its evolution.
| State | Main trigger | Behavior |
|---|---|---|
๐ HAPPY |
Balanced stats | Gentle floating, blinking |
๐ด SLEEPING |
User enables rest | Recovers energy (+12/h), breathing backdrop |
๐ STUDYING |
Pomodoro in progress | Focused on learning |
๐ค SICK |
Health below 20% | Trembles, needs care |
๐ฝ๏ธ HUNGRY |
Hunger below 20% | Alert pulse |
๐ข SAD |
Energy below 15% | Low activity |
๐ EXCITED |
Max happiness | Fast bouncing |
โ ๏ธ DEAD |
Health hits 0 | Static tombstone, revival dialog |
Status is a priority chain resolved in
StatusCalculator.determineStatus()โ see game mechanics.
| Technology | Used for |
|---|---|
| Kotlin 2.2.10 | Main language |
| Jetpack Compose | Declarative UI with native animations |
| Material 3 | Components & visual system (Material You) |
| Room v5 | Local SQLite persistence with migrations |
| DataStore | User prefs, themes, cooldowns |
| ViewModel + StateFlow | Reactive state & lifecycle |
| Coroutines + Flow | Async work and data streams |
| Koin 4.0.2 | Dependency injection |
| KSP | Compile-time annotation processing |
| WorkManager | Periodic jobs (stat decay every 4h) |
| Roborazzi | Visual regression tests via screenshots |
The project follows MVVM + Repository with dependency injection via Koin.
+------------------------------------------------------------------+
| ๐ฅ๏ธ PRESENTATION (UI Layer) |
| Compose Screens ยท Material 3 ยท StateFlow ยท Animations |
| HomeScreen | LearnScreen | FocusScreen | ShopScreen |
| GamesScreen | BugHuntScreen | SettingsScreen | OnboardingScreen |
| CodeReviewScreen | HackathonScreen |
+------------------------------------------------------------------+
| ๐ง DOMAIN (ViewModel) |
| PetViewModel |
| - Pet state management |
| - Study timer logic (start/cancel/complete) |
| - Challenge submission & reward calculation |
| - Shop purchases & skin equipping |
| - Theme switching & unlock |
| - Game cooldowns |
| - Offline reward detection |
| - DND Mode, sound effects, daily commit generator |
| - Seasonal events: Hackathon, Weekly Missions, Season Pass |
+------------------------------------------------------------------+
| ๐ DATA (Data Layer) |
| PetRepository | UserPreferencesRepository | AchievementsRepository|
| DecayCalculator | RewardCalculator | LevelCalculator |
| StatusCalculator | SoundManager |
| (Moodlets, Pair Buddy & Skill Tree logic live in the ViewModel) |
+------------------------------------------------------------------+
| ๐พ PERSISTENCE (Storage Layer) |
| Room / SQLite |
| - PetStateEntity | StudySessionEntity | FocusSessionEntity |
| - CodeCardEntity | QuestEntity | OwnedItemEntity |
| - LanguageProgressEntity | ActivityLogEntity |
| DataStore Preferences |
| - Onboarding, theme, difficulty, sound, motion, DND, colors |
+------------------------------------------------------------------+
Data flow:
User โ Composable (Screen) โ ViewModel โ Repository โ DAO โ SQLite
^ |
+------- StateFlow ------+
CodePet/
โโโ app/src/main/java/com/tamagotchi/code/
โ โโโ CodeTamagotchiApp.kt # Application (Koin, channels, 3 WorkManager jobs, widget observer)
โ โโโ SplashActivity.kt # 2s intro -> MainActivity
โ โโโ MainActivity.kt # Entry point (Theme, Nav, koinViewModel)
โ โโโ data/
โ โ โโโ ChallengesData.kt # 90 coding challenges
โ โ โโโ ChallengesDataEn.kt # EN mirror keyed by stable challenge id
โ โ โโโ SpecialChallengesData.kt # 6 algorithm/architecture challenges (+En)
โ โ โโโ CodeReviewData.kt # Code review snippets (+ CodeReviewDataEn)
โ โ โโโ CodeCards.kt # 40 trivia cards (+ CodeCardsEn)
โ โ โโโ LocalizedContent.kt # localized() extensions per content type
โ โ โโโ PersonalityMissions.kt # Mission definitions
โ โ โโโ database/ # AppDatabase (v5), PetDao, entities
โ โ โโโ repository/ # Pet, preferences & achievements repos
โ โโโ di/AppModule.kt # Koin DI module (entire graph, 19 lines)
โ โโโ navigation/AppNavigation.kt # NavHost, Routes, BottomNav
โ โโโ feature/
โ โ โโโ home/ learn/ focus/ shop/ onboarding/ settings/
โ โ โโโ games/ # BugHunt, GitRescue, RefactorRush,
โ โ โ # CodeReview, Hackathon + classic arcade
โ โ โ # (BinaryGuess, BugSmasher, RockPaperSci)
โ โ โโโ skills/ # SeasonPass, SkillTree, WeeklyMissions
โ โโโ ui/
โ โ โโโ viewmodel/PetViewModel.kt # central game brain (~1,500 lines)
โ โ โโโ components/ # ViewportCard, CodeySprite (procedural
โ โ โ # Canvas), CodeyBitmap (widget renderer),
โ โ โ # AnimatedThemeBackground, PairBuddy...
โ โ โโโ theme/ # ThemeConfig (12 themes), Theme, Type
โ โโโ widget/
โ โ โโโ CodePetWidgetProvider.kt # RemoteViews + procedural bitmap
โ โ โโโ WidgetUpdateWorker.kt # hourly refresh
โ โโโ util/ # Decay/Reward/Level/Status calculators,
โ # SoundManager, DailyCommitGenerator,
โ # CommitWorker, PetCheckWorker, ContentKeys
โโโ app/src/test/ # JVM + Robolectric + Roborazzi tests
โโโ gradle/libs.versions.toml # Gradle version catalog
Every snippet below is copied verbatim from the source โ no pseudo-code.
Decay is offline-safe: nothing runs on a timer while you're away. When the app (or PetCheckWorker) wakes up, the elapsed time since lastUpdated is converted to hours and applied in one pass:
val hours = elapsedMs.toFloat() / (1000f * 60f * 60f)
...
if (state.currentStatus == "SLEEPING") {
newEnergy = (newEnergy + (hours * 12f)).coerceIn(0f, 100f)
newHunger = (newHunger - (hours * 1f)).coerceIn(0f, 100f)
if (newEnergy >= 100f) {
newStatus = "HAPPY"
}
} else {
newHunger = (newHunger - (hours * 2.5f)).coerceIn(0f, 100f)
newEnergy = (newEnergy - (hours * 2f)).coerceIn(0f, 100f)
}
val baseHealthDecay = hours * 1.5f
newHealth = (newHealth - baseHealthDecay).coerceIn(0f, 100f)| Rule | Effect |
|---|---|
| Awake decay | hunger โ2.5/h ยท energy โ2/h ยท health โ1.5/h |
| Sleeping | energy +12/h (auto-wakes at 100), hunger only โ1/h |
| Starving (hunger = 0) | extra health โ3/h |
| Exhausted (energy โค 10) | extra health โ1/h |
| No study in 72 h | extra health โ1.5/h |
| No study in 48 h | streak resets to 0 |
| Health โค 0 | isDead = true, status DEAD |
A priority chain โ first match wins, which is why a sleeping pet never shows as hungry:
return when {
isDead -> "DEAD"
isExcited -> "EXCITED"
isStudying -> "STUDYING"
isSleeping -> "SLEEPING"
health < 20f -> "SICK"
hunger < 20f -> "HUNGRY"
energy < 15f -> "SAD"
else -> "HAPPY"
}val baseBytes = minutes * 2
val baseXP = minutes * 3
val bonusBytes = if (minutes >= 25) 50 else 0
val bonusXP = if (minutes >= 25) 75 else 0
val energyCost = (minutes * 0.5f).coerceAtMost(30f)fun calculateChallengeReward(type: String): ChallengeReward {
val bytes = if (type == "DEBUG") 30 else 25
val xp = if (type == "DEBUG") 25 else 20
return ChallengeReward(bytes = bytes, xp = xp, hungerRestore = 15f, healthRestore = 20f)
}
fun calculateMinigameReward(score: Int, maxBytes: Int): Int {
return (score * 10).coerceAtMost(maxBytes)
}
fun calculateRefactorReward(attempts: Int): Int {
return maxOf(50 - attempts * 5, 10)
}Streaks use calendar days, not rolling 24 h windows:
val studiedYesterday = lastCal.get(Calendar.YEAR) == yesterdayCal.get(Calendar.YEAR) &&
lastCal.get(Calendar.DAY_OF_YEAR) == yesterdayCal.get(Calendar.DAY_OF_YEAR)
newStreak = if (studiedYesterday) currentStreak + 1 else 1var level = 1
var requiredXp = 100
while (xp >= requiredXp) {
level++
requiredXp += level * 100
}Cumulative XP: L2 = 100 ยท L3 = 300 ยท L4 = 600 ยท L5 = 1000 ยท L6 = 1500 โ each new level costs level ร 100 XP, so evolution stages feel earned.
Eight entities, five versions, four explicit migrations:
@Database(
entities = [
PetStateEntity::class, StudySessionEntity::class, FocusSessionEntity::class,
CodeCardEntity::class, QuestEntity::class, OwnedItemEntity::class,
LanguageProgressEntity::class, ActivityLogEntity::class
],
version = 5,
exportSchema = false
)| Migration | What it does (real SQL in AppDatabase.kt) |
|---|---|
1 โ 2 |
CREATE TABLE focus_sessions โ live Pomodoro timer state |
2 โ 3 |
ALTER TABLE pet_state ADD hasRenamed |
3 โ 4 |
ALTER TABLE pet_state ADD isDead โ death system |
4 โ 5 |
code_cards, quests, owned_items, language_progress, activity_logs |
The pet row is a singleton pattern (WHERE id = 1 LIMIT 1), exposed reactively:
@Query("SELECT * FROM pet_state WHERE id = 1 LIMIT 1")
fun getPetState(): Flow<PetStateEntity?>
@Transaction
suspend fun completeOfflineSession(sessionId: Long, status: String, petState: PetStateEntity) {
updateFocusSessionStatus(sessionId, status)
insertOrUpdatePetState(petState)
}PetStateEntity fields: name ยท language ยท level ยท xp ยท hunger ยท health ยท energy ยท bytes ยท streak ยท lastUpdated ยท lastStudyDate ยท currentStatus ยท hasRenamed ยท isDead. Anything non-critical (theme, DND, cooldowns, moodlets, skill tree, season pass) lives in DataStore Preferences instead of a schema change.
val eventTypes = listOf("bug_prod", "tabs", "spaces", "bad_commit", "clean_code", "spilled_coffee")
val type = eventTypes.random()
val duration = when (type) {
"bug_prod" -> 2L
"spilled_coffee" -> 1L
"bad_commit" -> 2L
"clean_code" -> 3L
else -> 1L
} // hours, persisted with an expiry timestampRoll: every 30 minutes, 5% chance (checkAndTriggerMoodlet).
fun checkAndActivatePairBuddy() {
if (pairBuddyState.value != null) return
if (kotlin.random.Random.nextFloat() < 0.2f) activatePairBuddy()
}
// PairBuddyState(name = "Buggy", remainingChallenges = 3, xpMultiplier = 1.5f)val cost = (node.currentTier + 1) * 100 // tier 1 = 100 XP, tier 2 = 200 XP...
if (pet.xp < cost) return@launch
val updated = pet.copy(xp = pet.xp - cost)3 branches ร 3 nodes, each node upgradable through maxTier = 3.
val newXp = current.xp + xp
val newLevel = current.level + (newXp / 100)
val remainingXp = newXp % 100
val updated = current.copy(xp = remainingXp, level = newLevel.coerceAtMost(20)) // then persisted to DataStoreWeeklyMissionData("wm1", ..., 100, 50) // XP, Bytes
WeeklyMissionData("wm2", ..., 200, 100)
WeeklyMissionData("wm3", ..., 150, 75)
// HackathonData(attempts, bestTimeMs, expiresAt = now + 48h)Titles are resolved by stable id at display time (LocalizedGameText.kt), so mission text localizes without touching the persisted state.
val filter = notificationManager.currentInterruptionFilter
isDndActive.value = filter == INTERRUPTION_FILTER_PRIORITY ||
filter == INTERRUPTION_FILTER_NONE || filter == INTERRUPTION_FILTER_ALARMSWhen active: notifications silenced and +10% XP on learning rewards.
fun reviveWithBytes() {
val cost = deathReviveCost.value
if (pet.bytes < cost) return@launch
val revived = pet.copy(
isDead = false, health = 50f, energy = 50f, hunger = 50f,
currentStatus = "HAPPY", bytes = pet.bytes - cost, ...
)
}| Path | Cost | Restored stats |
|---|---|---|
reviveWithBytes() |
Bytes price (dynamic) | 50 / 50 / 50 |
reviveForFree() |
0 Bytes | 40 / 40 / 40 โ the "hard reset" mercy path |
All jobs are scheduled from CodeTamagotchiApp.onCreate():
| Job | Schedule | Policy | Notes |
|---|---|---|---|
pet_check |
every 4 h | KEEP |
setRequiresBatteryNotLow(true), 2 h initial delay |
widget_update |
every 1 h | KEEP |
keeps launcher meters fresh even if the app never opens |
daily_commit |
one-shot at midnight | REPLACE |
reschedules itself for the next midnight |
val request = PeriodicWorkRequestBuilder<PetCheckWorker>(4, TimeUnit.HOURS)
.setConstraints(Constraints.Builder().setRequiresBatteryNotLow(true).build())
.setInitialDelay(2, TimeUnit.HOURS)
.build()
WorkManager.getInstance(this)
.enqueueUniquePeriodicWork("pet_check", ExistingPeriodicWorkPolicy.KEEP, request)PetCheckWorker routes alerts by severity into 5 notification channels (grouped under pet_care):
val channelId = when {
petState.health < 5f || petState.hunger < 5f || petState.energy < 5f -> "pet_critical"
petState.hunger < 20f -> "pet_hunger"
petState.health < 20f -> "pet_health"
petState.energy < 15f -> "pet_energy"
else -> "pet_care_reminder"
}The widget-update trick: the Application observes Room, not a screen lifecycle, so even background writes (workers) refresh the launcher instantly:
combine(petRepository.petState.distinctUntilChanged(), preferences.currentTheme)
{ state, theme -> state to theme }.collect { (state, theme) ->
val pixelMode = theme == "Retro Pixel"
manager.getAppWidgetIds(provider).forEach { id ->
CodePetWidgetProvider.updateAppWidget(this, manager, id, state, pixelMode)
}
}di/AppModule.kt โ the entire graph, 19 lines:
val appModule = module {
single { AppDatabase.getDatabase(androidContext()) }
single { get<AppDatabase>().petDao() }
single { PetRepository(get()) }
single { UserPreferencesRepository(androidContext()) }
single { AchievementsRepository(androidContext()) }
viewModel { PetViewModel(get(), get(), get()) }
}Screens get it with viewModel<PetViewModel>(koin = koin) / koinViewModel() โ there is exactly one game brain.
There are zero PNGs for Codey. The persisted status string maps to an enum and a single Canvas draws everything:
internal enum class PetMood { HAPPY, SLEEPING, STUDYING, SICK, HUNGRY, SAD, EXCITED, DEAD }
internal fun codeyMood(status: String, isDead: Boolean = false): PetMood =
if (isDead) PetMood.DEAD
else PetMood.entries.firstOrNull { it.name == status } ?: PetMood.HAPPYThe renderer is a toolbox of DrawScope extensions, all in CodeySprite.kt:
drawEgg ยท drawRobot ยท drawVisorFace ยท drawCore ยท drawAntenna ยท drawWing ยท drawLimb ยท drawBackpack ยท drawBadge ยท drawPropellerCap ยท drawHeadphones ยท drawCircuitCrown ยท drawEnergyCape ยท drawEvolutionBurst ยท drawDeadScene ยท drawTombstone ยท drawGhost
Design decisions:
- 5 evolution stages swap
stagePalette()and bolt on parts โ egg โ baby bot โ โฆ โ circuit crown + energy cape at Legendary - Blinking, breathing, trembling and hunger-pulse come from
rememberInfiniteTransition, and every one respects the Reduce Motion preference - The user's accent color (persisted in DataStore, costs 30 Bytes) tints visor and core โ so no two pets look identical
- The DEAD scene is fully drawn too: tombstone + ghost, deliberately static
RemoteViews can't run Compose, so the widget renders the same procedural Codey into a Bitmap via CodeyBitmap.kt:
views.setImageViewBitmap(
R.id.widget_pet_image,
renderCodeyBitmap(
petState?.level ?: 1,
effectiveStatus ?: "HAPPY",
petState?.isDead ?: false,
pixelMode = pixelMode
)
)
views.setProgressBar(R.id.health_bar, 100, health, false)Compact 2ร2, resizable, tap opens MainActivity. pixelMode switches the renderer to 8-bit when the Retro Pixel theme is active. Covered by CodePetWidgetRenderingTest on the JVM โ no emulator needed.
| Method | Responsibility |
|---|---|
submitAnswer(optionIndex) |
grading, rewards, moodlet/buddy rolls, season-pass XP, quest & language progress |
startStudyTimer / completeFocusSession / cancelStudyTimer |
Pomodoro lifecycle + persistence + auto-resume |
buyShopItem / buySkin / equipSkin |
shop economy, @Transaction item equipping |
petThePet / cleanThePet / toggleSleep |
care actions (drive quests & daily commits) |
canPlayGame / recordGamePlay |
24 h arcade cooldowns |
checkDailyRewardEligibility / claimDailyReward |
offline & daily rewards |
loadMoodlet / triggerRandomMoodlet |
moodlet system |
unlockSkillNode |
skill-tree progression (XP burn) |
addSeasonPassXp |
battle-pass leveling |
completeWeeklyMission |
Monday-reset mission board |
submitHackathonSolution / consumeHackathonAttempt |
48 h weekly event |
checkDeathState / reviveWithBytes / reviveForFree |
death & revival |
checkDndMode |
system interruption-filter probe |
| Test | What it pins down |
|---|---|
StatusCalculatorTest |
status priority chain and thresholds |
GameEconomyTest |
reward math, cooldown logic, settings validation |
LocalizedContentTest |
ESโEN id parity for all 90+6 challenges, 10 snippets, 40 cards |
CodeyRendererTest / CodeySpriteTest |
procedural renderer across every stage & mood |
PetAnimationConfigTest |
animation config per state |
ThemeContrastTest |
readable contrast on all 12 themes |
CodePetWidgetRenderingTest |
widget bitmap + RemoteViews construction |
GreetingScreenshotTest |
Roborazzi golden (app/src/test/screenshots/greeting.png) |
./gradlew :app:testDebugUnitTest # all JVM/Robolectric tests
./gradlew :app:testDebugUnitTest --tests "com.tamagotchi.code.StatusCalculatorTest"
./gradlew :app:verifyRoborazziDebug # visual regression
./gradlew :app:lintDebug # Android lint| Step | Action | Reward |
|---|---|---|
01 |
Name your pet during onboarding | Start of the adventure |
02 |
Complete challenges in LEARN | XP, Bytes, health and food |
03 |
Start a Pomodoro in STUDY | XP and Bytes per minute |
04 |
Buy resources in SHOP | Restore stats |
05 |
Play minigames | Bytes and bonuses |
06 |
Keep the daily streak | Steady progress |
07 |
Solve special challenges | Unlock new visual themes |
| Activity | Bytes | XP |
|---|---|---|
| Regular challenge | +25 to +30 | +20 to +25 |
| Special challenge | +50 | โ |
| Study per minute | +2 | +3 |
| 25+ min session bonus | +50 | +75 |
| Code Review | Up to +60 | โ |
| Hackathon (full) | +180 | +175 |
Code Tamagotchi ships with 12 premium themes. Each configures colors, typography, corners, gradients and a unique animated Canvas background.
| Theme | Personality |
|---|---|
| ๐ฅ๏ธ Matrix Green | Hacker terminal, pure monospace |
| ๐ Galactic | Deep purples and cosmic flashes |
| ๐ Cyberpunk | Electric pink and cyan against the dark |
| ๐ธ Sakura | Japanese elegance in soft pink |
| โช Minimalist | Pure white with subtle accents |
| ๐ก Neon | Total darkness with vibrant flashes |
| ๐ Ocean | Deep blues, underwater calm |
| ๐ Volcanic | Fire under the surface |
| โ๏ธ Samurai | Steel, blood and ancient gold |
| ๐ Aurora | Northern lights on the dark sky |
| ๐ Night | Elegant iOS-style night |
| ๐น๏ธ Retro Pixel | FINAL THEME โ definitive 8-bit, pixel art |
Pick one from the visual carousel in Settings. Solve special challenges to unlock new themes.
Code Tamagotchi is fully bilingual (English + Spanish) and follows your system language automatically โ there is no in-app switcher:
- โ
UI, dialogs, game texts, notifications and widget:
values/(es) +values-en/(en) - โ
Learning content: 90 code challenges, 6 special algorithm challenges, 10 code-review snippets and 40 code cards translated to English (matched by stable id, order-checked in
LocalizedContentTest) โ ๏ธ Notification channel labels (Android Settings) are created once with the language active at first installโ ๏ธ Theme names are shown in Spanish by design (they are stable identifiers stored in preferences)
Translations live next to the original data: ChallengesDataEn.kt, SpecialChallengesDataEn.kt, CodeReviewDataEn.kt, CodeCardsEn.kt. PRs to fix wording (either language) are very welcome.
The mechanism is a single extension per content type, resolved at display time โ Spanish stays the source of truth and the DB never stores translations:
fun isEnglishContent(): Boolean = Locale.getDefault().language.equals("en", ignoreCase = true)
fun CodingChallenge.localized(): CodingChallenge {
if (!isEnglishContent()) return this
val en = ChallengesDataEn.translations[id]
?: SpecialChallengesDataEn.translations[id]
?: return this
return copy(language = en.language, title = en.title, question = en.question,
codeSnippet = en.codeSnippet ?: codeSnippet, options = en.options, explanation = en.explanation)
}LocalizedContentTest asserts that every Spanish id has an English twin and that option order (hence correctAnswerIndex) is preserved.
- ๐พ Virtual pet with emotional states and decay
- ๐ป 90 coding challenges + 6 special (Kotlin, JS, PHP, Python)
- โฑ๏ธ Persistent Pomodoro with auto-resume
- ๐จ 12 premium themes with animated Canvas backgrounds
- ๐น๏ธ 6 minigames: Bug Hunt, Git Rescue, Refactor Rush, Code Review, Hackathon, Classic Arcade
- ๐ Visual pet evolution (5 stages: Egg โ Legendary)
- ๐ Moodlet system (6 random events)
- ๐ซ Pair Programming Buddy (Buggy, XP ร1.5)
- ๐ DND Mode (focus mode +10% XP)
- ๐ณ Skill Tree (3 branches, 9 unlockable nodes)
- ๐ซ Season Pass (30 days, 20 levels, free/premium)
- ๐ Weekly Missions (3 missions, reset every Monday)
- ๐ Local achievements and reward system
- ๐ Personality notifications (reminders & rewards)
- ๐ฑ Home-screen widget
- ๐ Challenges in Ruby, Go, Rust and Swift โ want to help? this is the easiest contribution!
- โ๏ธ Firebase Firestore sync
- ๐ฅ Multiplayer and leaderboards
The fastest way in: add coding challenges for a language we don't cover yet (Rust, Go, Ruby, Swift...). Check CONTRIBUTING.md and the good first issue label.
- Fork the repository
- Create a branch (
git checkout -b feature/new-challenges-rust) - Commit your changes (
git commit -m 'feat: add Rust challenges') - Push the branch (
git push origin feature/new-challenges-rust) - Open a Pull Request
- ๐ Report bugs and missing challenge answers
- ๐จ Suggest theme palettes or hat designs
- ๐ Improve these translations (open a
docs:PR)
Released under the MIT License โ which in plain language means you are free to:
- โ Use it for anything, including commercial projects
- โ Fork and adapt it (new challenge languages, other platforms, classroom tools...)
- โ Translate the UI to any language and ship the fork publicly
- โ Sell a service or derivative built on top of it
The only requirement is keeping the copyright notice and license text in source copies. No CLA, no copyleft โ attribution in the code is enough. If you build something cool on top of CodePet, a shout-out in the Discussions is always welcome, but not required. ๐
Code Tamagotchi v3.0 โ where bugs become pets and code becomes affection.
Questions? Open an issue or check the full documentation (ES).
MIT License ยท Made with โ and ๐








