Skip to content

Latest commit

ย 

History

49 Commits

Folders and files

NameName
Last commit message
Last commit date
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

Code Tamagotchi - Your virtual pet for learning to program
Code Tamagotchi Logo

๐Ÿพ Code Tamagotchi

Your study buddy that evolves while you code

Latest release MIT License Build status


> ./code-tamagotchi --status
> Status: ACTIVE  Platform: ANDROID  Language: 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.

Download the APK Explore features

English ยท ๐Ÿ‡ช๐Ÿ‡ธ Espaรฑol


๐Ÿ“‹ Navigation

[โœจ Features](#-features) ยท [๐Ÿ“ธ Screenshots](#-screenshots) ยท [๐Ÿ› ๏ธ Tech Stack](#๏ธ-tech-stack) ยท [๐Ÿ—๏ธ Architecture](#๏ธ-architecture) ยท [โš™๏ธ Mechanics](#-game-mechanics-in-real-code) ยท [๐Ÿ’พ Persistence](#-persistence--room-v5) ยท [๐Ÿงฉ Live systems](#-live-systems-petviewmodel) ยท [โฐ Background work](#-background-work-workmanager) ยท [๐Ÿ”Œ DI](#-dependency-injection-koin) ยท [๐Ÿ–Œ๏ธ Rendering](#-procedural-rendering) ยท [๐Ÿ“ฑ Widget](#-home-screen-widget) ยท [๐Ÿงช Tests](#-testing) ยท [โšก Quick Start](#-quick-start) ยท [๐ŸŽฎ How to Play](#-how-to-play) ยท [๐ŸŽจ Themes](#-themes) ยท [๐ŸŒ Localization](#-localization) ยท [๐Ÿ—บ๏ธ Roadmap](#๏ธ-roadmap) ยท [๐Ÿค Contributing](#-contributing)

โœจ Features

๐Ÿพ Virtual pet

  • Dynamic emotional states (HAPPY, SLEEPING, STUDYING, SICK, HUNGRY, SAD, EXCITED, DEAD)
  • Health, hunger and energy in real time with progressive decay
  • โ˜ ๏ธ Death & revival system โ€” if health hits 0, Codey shows up under a tombstone and you can revive him with Bytes
  • State-based animations (breathing, trembling, hunger pulse, blinking)
  • ๐Ÿ–Œ๏ธ Codey is drawn 100% procedurally with Compose Canvas โ€” no sprite PNGs; the home-screen widget reuses the same renderer
  • Level, XP and Bytes (virtual currency) system
  • Daily study streaks and offline rewards
  • ๐Ÿ… Visual evolution โ€” 5 stages: Egg โ†’ Baby โ†’ Adult โ†’ Veteran โ†’ Legendary
  • ๐Ÿ˜Š Moodlets โ€” random events that shift the mood for hours
  • ๐Ÿ‘ซ Pair Programming โ€” Buggy shows up randomly and multiplies XP ร—1.5

๐Ÿ’ป Learn by coding

  • Challenges in Kotlin, JavaScript, PHP and Python
  • Trivia and debugging questions
  • Special algorithm challenges that unlock visual themes
  • Educational feedback on every answer, in Codey's voice
  • Progress and accuracy rewards
  • 96 built-in coding challenges (90 regular + 6 special)

โฑ๏ธ Built-in Pomodoro

  • 15, 25 or 50 minute sessions
  • Persistent study log
  • XP and Bytes per minute
  • Bonus for 25+ minute sessions (+50 Bytes, +75 XP)
  • 8 study topics: Kotlin, JavaScript, PHP, Python, SQL, Clean Code, Git, Data Structures
  • Active sessions auto-resume when opening the app

๐Ÿ•น๏ธ Debugging Arcade

  • ๐Ÿ› Bug Hunt โ€” Terminal Panic: find bugs in code snippets
  • ๐Ÿ™ Git Rescue: Git decisions to save a repo on fire
  • ๐Ÿ”ง Refactor Rush: reorder code blocks until it compiles
  • ๐Ÿ“ Code Review: spot errors in 10 multi-language snippets
  • ๐Ÿ† Hackathon: weekly event with 3 problems of rising difficulty
  • Codey's humorous explanations on every round
  • Daily cooldown to prevent currency farming
  • ๐ŸŽฎ Classic arcade (Guess the Bit, Bug Catch, Server/Script/Hacker)

โš™๏ธ Extra features

  • ๐Ÿ”‡ 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)

๐Ÿ“ธ Screenshots

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.


โšก Quick Start

# 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.apk

Or 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.


๐Ÿ”„ Progress loop

    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.


๐Ÿ˜Š Codey's states

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.


๐Ÿ› ๏ธ Tech Stack

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

๐Ÿ—๏ธ Architecture

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 ------+

Project structure

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

โš™๏ธ Game mechanics in real code

Every snippet below is copied verbatim from the source โ€” no pseudo-code.

Stat decay (util/DecayCalculator.kt)

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

Status resolution (util/StatusCalculator.kt)

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"
}

Economy (util/RewardCalculator.kt)

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 1

Level curve (util/LevelCalculator.kt)

var 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.


๐Ÿ’พ Persistence โ€” Room v5

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.


๐Ÿงฉ Live systems (PetViewModel)

๐Ÿ˜Š Moodlets โ€” 6 random events

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 timestamp

Roll: every 30 minutes, 5% chance (checkAndTriggerMoodlet).

๐Ÿ‘ซ Pair Programming Buddy

fun checkAndActivatePairBuddy() {
    if (pairBuddyState.value != null) return
    if (kotlin.random.Random.nextFloat() < 0.2f) activatePairBuddy()
}
// PairBuddyState(name = "Buggy", remainingChallenges = 3, xpMultiplier = 1.5f)

๐ŸŒณ Skill Tree โ€” XP burned, not spent

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.

๐ŸŽซ Season Pass

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 DataStore

๐Ÿ“‹ Weekly Missions & ๐Ÿ† Hackathon

WeeklyMissionData("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.

๐Ÿ”‡ DND detection โ€” real Android API

val filter = notificationManager.currentInterruptionFilter
isDndActive.value = filter == INTERRUPTION_FILTER_PRIORITY ||
        filter == INTERRUPTION_FILTER_NONE || filter == INTERRUPTION_FILTER_ALARMS

When active: notifications silenced and +10% XP on learning rewards.

โ˜ ๏ธ Death & revival

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

โฐ Background work (WorkManager)

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)
        }
    }

๐Ÿ”Œ Dependency injection (Koin)

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.


๐Ÿ–Œ๏ธ Procedural rendering

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.HAPPY

The 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

๐Ÿ“ฑ Home-screen widget

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.


๐Ÿง  Public API cheat-sheet (PetViewModel)

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

๐Ÿงช Testing

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

๐ŸŽฎ How to Play

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

Quick economy

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

๐ŸŽจ Themes

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.


๐ŸŒ Localization

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.


๐Ÿ—บ๏ธ Roadmap

  • ๐Ÿพ 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

๐Ÿค Contributing

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.

  1. Fork the repository
  2. Create a branch (git checkout -b feature/new-challenges-rust)
  3. Commit your changes (git commit -m 'feat: add Rust challenges')
  4. Push the branch (git push origin feature/new-challenges-rust)
  5. Open a Pull Request

Not a dev? Still useful:

  • ๐Ÿ› Report bugs and missing challenge answers
  • ๐ŸŽจ Suggest theme palettes or hat designs
  • ๐ŸŒ Improve these translations (open a docs: PR)

๐Ÿ“„ License

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. ๐Ÿ˜‰


โญ Star History

Star History Chart

Repository stars Repository forks

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 ๐Ÿ›

About

๐Ÿพ A virtual pet that evolves as you code โ€” gamified Pomodoro, 88+ coding challenges, arcade debugging games, 12 animated themes. Kotlin + Jetpack Compose, 100% offline.

Topics

Resources

Code of conduct

Contributing

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages