# Project export: Doomo

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: OpenAI Build Week
- Tagline: Doomo turns your daily choices into a companion you care about. Learning and real-world quests help him flourish; mindless phone use drains him.
- Devpost: https://devpost.com/software/doomo
- GitHub: https://github.com/GitZohair/doomo-build-week
- Demo: https://github.com/GitZohair/doomo-build-week/releases/latest
- Video: https://www.youtube.com/embed/o9nys8A2LKs?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 1 GitHub contributor(s) — Zohair Ahmed (31 commits)

## Devpost submission (written by the team)

### Inspiration

Screen-time numbers are easy to ignore. We wanted your habits to become something you could actually see and care about.

### What it does

Wasting time on phone weakens Doomo; studying and completing small real-world quests help him recover.

### How we built it

We used Codex and GPT-5.6 with React Native, Android usage data, an offline behavior engine, and spaced-repetition study cards.

### Challenges we ran into

Making Doomo motivating without making the user feel judged and keeping Android tracking reliable and battery-friendly.

### Accomplishments we're proud of

We turned screen habits and learning progress into an emotional companion instead of another analytics dashboard. The isometric room was also cool.

### What we learned

People respond more strongly to a character that reflects them than to charts, warnings, or screen-time limits.

### What's next

More expressive animations, smarter study-card generation, and deeper changes to Doomo’s room and personality. Integrating google classroom for more personalized feel and realtime conversation. Migrate to android native for more control.

## README (from the GitHub repository)

# Doomo

<p align="center">
  <img src="media/doomo-thumbnail.png" alt="Doomo in his study room" width="760" />
</p>

<p align="center"><strong>Your habits shape him.</strong></p>

<p align="center">
  <img alt="Android" src="https://img.shields.io/badge/Android-24%2B-3DDC84?logo=android&logoColor=white" />
  <img alt="Expo" src="https://img.shields.io/badge/Expo-SDK%2057-000020?logo=expo&logoColor=white" />
  <img alt="React Native" src="https://img.shields.io/badge/React%20Native-0.86-61DAFB?logo=react&logoColor=111827" />
  <img alt="TypeScript" src="https://img.shields.io/badge/TypeScript-6-3178C6?logo=typescript&logoColor=white" />
  <img alt="OpenAI" src="https://img.shields.io/badge/OpenAI-Codex%20%2B%20GPT--5.6-412991?logo=openai&logoColor=white" />
  <img alt="Offline first" src="https://img.shields.io/badge/Core-offline--first-0F766E" />
</p>

Doomo turns your screen habits into the health of a virtual owl. Doomscrolling weakens him; reviewing your own study cards and completing small real-world quests helps both of you recover.

**OpenAI Build Week track: Education** — Doomo turns a student's own notes into focused study cards, schedules them with spaced repetition, and makes consistent learning emotionally visible.

## Try it

Download the latest judge builds from [GitHub Releases](https://github.com/GitZohair/doomo-build-week/releases/latest):

- **Android phone:** `doomo-arm64-v8a-release.apk`
- **Android/Appetize emulator:** `doomo-x86_64-release.apk`

Open **Demo** inside the app for sample usage and a starter study deck. Real screen-time reflection requires Android Usage Access and is best tested on a physical phone.

## Current room

<p align="center">
  <img src="media/doomo-current.png" alt="Doomo inside the current isometric room" width="360" />
</p>

The current room makes study, rest, air, health, and resets part of Doomo's home instead of another dashboard.

<details>
  <summary><strong>Version 1</strong> — the earlier flat room</summary>
  <p align="center">
    <img src="media/doomo-home.png" alt="Version 1 of Doomo's room" width="360" />
  </p>
</details>

## What it does

- Reflects selected-app screen time through Doomo's health, mood, and room.
- Turns notes into concise GPT-5.6 study cards through a server-only endpoint.
- Reviews cards offline with FSRS spaced repetition.
- Offers small reset quests: study, drink water, or step outside.
- Keeps the core loop local; cloud voice and AI card generation are optional.

## Tech stack

| Layer | Technology |
| --- | --- |
| Mobile | Expo SDK 57, React Native 0.86, TypeScript |
| Android | Kotlin native module, `UsageStatsManager` |
| Experience | React Native Skia, Moti, Reanimated, DeviceMotion |
| Learning | GPT-5.6, FSRS, local lecture decks and imports |
| Storage | Expo SQLite |
| Optional voice | OpenAI Realtime over WebRTC |
| Server | Node.js 20, OpenAI Responses and Realtime APIs |

## Run locally

Requirements: Node.js 20+, JDK 17, Android Studio, and an Android emulator or phone.

```powershell
git clone https://github.com/GitZohair/doomo-build-week.git
cd doomo-build-week\mobile
npm ci
npx tsc --noEmit
npm test
npx expo run:android
```

After the native client is installed, use Metro for fast iteration:

```powershell
cd mobile
npx expo start --dev-client
```

The app works without an OpenAI key. For optional GPT-5.6 card generation and Realtime voice, run the server and keep the key there—never in the Android client:

```powershell
cd server
npm ci
$env:OPENAI_API_KEY = "your-key"
$env:DOOMO_SAFETY_SALT = "a-long-random-secret"
npm start
```

## How Codex and GPT-5.6 were used

**Codex** was the main engineering partner throughout the build: it helped turn the concept into the Android product, wire the native usage module, build the learning and room flows, debug Gradle/native dependencies, run tests, and produce verified ARM64 and x86_64 builds.

**GPT-5.6** powers the notes-to-cards path. The server sends student notes to GPT-5.6 with a strict schema, validates the result, and imports the atomic cards into Doomo's offline FSRS review loop. No API key is shipped in the app.

## Privacy

Screen-time history, health state, streaks, and card scheduling stay on-device. Camera quests are optional, and optional cloud features clearly require a user action.

## Repository

This repository is publicly viewable for OpenAI Build Week judging. The project remains all rights reserved; see [LICENSE](LICENSE). APKs are provided only as hackathon testing builds.


## Detected evidence (automated analysis)

Indexed codebase: 109 recognized source files, 801 KB.
- JavaScript (language) — detected in the code
- Kotlin (language) — detected in the code
- Python (language) — detected in the code
- React (technology) — detected in the code
- TypeScript (language) — detected in the code
- OpenAI (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (120 of 144)

```
.gitattributes
.gitignore
LICENSE
mobile/.gitignore
mobile/android/.gitignore
mobile/android/app/build.gradle
mobile/android/app/proguard-rules.pro
mobile/android/app/src/debug/AndroidManifest.xml
mobile/android/app/src/debugOptimized/AndroidManifest.xml
mobile/android/app/src/main/AndroidManifest.xml
mobile/android/app/src/main/java/com/zohai/doomo/MainActivity.kt
mobile/android/app/src/main/java/com/zohai/doomo/MainApplication.kt
mobile/android/app/src/main/res/drawable/ic_launcher_background.xml
mobile/android/app/src/main/res/drawable/rn_edit_text_material.xml
mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
mobile/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
mobile/android/app/src/main/res/values-night/colors.xml
mobile/android/app/src/main/res/values/colors.xml
mobile/android/app/src/main/res/values/strings.xml
mobile/android/app/src/main/res/values/styles.xml
mobile/android/build.gradle
mobile/android/gradle.properties
mobile/android/gradle/wrapper/gradle-wrapper.properties
mobile/android/gradlew
mobile/android/gradlew.bat
mobile/android/settings.gradle
mobile/app.json
mobile/App.tsx
mobile/assets/mascot/2d-production/final/doomo-alpha-registration-qa.json
mobile/assets/mascot/doomo-mascot.blend
mobile/assets/mascot/dusk-owl-preview/doomo-dusk-owl-preview.blend
mobile/assets/mascot/moon-mole/doomo-moon-mole.blend
mobile/assets/mascot/production/doomo-production.blend
mobile/assets/mascot/upright/doomo-upright.blend
mobile/assets/room/bongseng/LICENSE.md
mobile/babel.config.js
mobile/index.ts
mobile/LICENSE
mobile/modules/doomo-usage/android/build.gradle
mobile/modules/doomo-usage/android/src/main/AndroidManifest.xml
mobile/modules/doomo-usage/android/src/main/java/expo/modules/doomousage/DoomoUsageModule.kt
mobile/modules/doomo-usage/expo-module.config.json
mobile/modules/doomo-usage/index.ts
mobile/modules/doomo-usage/LICENSE
mobile/modules/doomo-usage/src/DoomoUsage.types.ts
mobile/modules/doomo-usage/src/DoomoUsageModule.ts
mobile/modules/doomo-usage/src/DoomoUsageModule.web.ts
mobile/package.json
mobile/patches/@expo+metro-file-map+57.0.1.patch
mobile/src/components/Button.tsx
mobile/src/components/DoomoPet.tsx
mobile/src/components/DoomoPet2D.tsx
mobile/src/components/DoomoProofCamera.tsx
mobile/src/components/LivingRoomDecor.tsx
mobile/src/components/StreakChip.tsx
mobile/src/core/constants.ts
mobile/src/core/engine.test.ts
mobile/src/core/engine.ts
mobile/src/core/types.ts
mobile/src/data/localLectureDecks.ts
mobile/src/data/starterDeck.ts
mobile/src/decks/generateCards.test.ts
mobile/src/decks/generateCards.ts
mobile/src/decks/importDeck.test.ts
mobile/src/decks/importDeck.ts
mobile/src/decks/pickDeckFile.ts
mobile/src/mascot/affect.test.ts
mobile/src/mascot/affect.ts
mobile/src/mascot/animationChoreography.test.ts
mobile/src/mascot/animationChoreography.ts
mobile/src/mascot/doomo2dAssets.ts
mobile/src/mascot/index.ts
mobile/src/mascot/visualState.test.ts
mobile/src/mascot/visualState.ts
mobile/src/needs/expressionTiers.ts
mobile/src/needs/needsSelector.ts
mobile/src/needs/sleep.test.ts
mobile/src/needs/sleep.ts
mobile/src/notifications/gentleReminder.native.ts
mobile/src/notifications/reminderPolicy.test.ts
mobile/src/notifications/reminderPolicy.ts
mobile/src/realtime/DoomoRealtimeSession.test.ts
mobile/src/realtime/DoomoRealtimeSession.ts
mobile/src/realtime/index.ts
mobile/src/realtime/realtimeEvents.test.ts
mobile/src/realtime/realtimeEvents.ts
mobile/src/realtime/webrtcRuntime.native.ts
mobile/src/realtime/webrtcRuntime.ts
mobile/src/realtime/webrtcRuntime.web.ts
mobile/src/resets/catalog.ts
mobile/src/resets/index.ts
mobile/src/resets/mixer.test.ts
mobile/src/resets/mixer.ts
mobile/src/resets/types.ts
mobile/src/room/DoomoDollhouseScene.tsx
mobile/src/room/RoomHotspots.tsx
mobile/src/room/RoomScene.tsx
mobile/src/room/roomState.ts
mobile/src/room/StudyRewardMoment.tsx
mobile/src/room/useParallax.ts
mobile/src/room/usePeek.ts
mobile/src/screens/home/Hotspots.tsx
mobile/src/screens/home/HudOverlay.tsx
mobile/src/screens/home/PadScene.tsx
mobile/src/screens/home/padState.ts
mobile/src/screens/home/RoomNavDock.tsx
mobile/src/screens/home/RoomProgressRail.tsx
mobile/src/screens/home/RoomToyStrip.tsx
mobile/src/screens/home/SceneActionSheet.tsx
mobile/src/screens/onboarding/BaselinePlanScreen.tsx
mobile/src/screens/onboarding/MirrorRevealScreen.tsx
mobile/src/screens/onboarding/OnboardingFlow.tsx
mobile/src/screens/onboarding/WelcomeScreen.tsx
mobile/src/screens/study/StudyEducationPanels.tsx
mobile/src/storage/codec.test.ts
mobile/src/storage/codec.ts
mobile/src/storage/doomoStore.ts
mobile/src/storage/setupProfile.test.ts
mobile/src/storage/setupProfile.ts
mobile/src/storage/snapshotPersistence.test.ts
[24 more files omitted for size]
```

### Dependencies

- mobile/package.json: @expo/metro-runtime@~57.0.6, @expo/vector-icons@^15.0.2, @shopify/react-native-skia@2.6.2, @types/papaparse@^5.5.2, @types/react@~19.2.2, babel-preset-expo@^57.0.3, expo@~57.0.6, expo-camera@^57.0.3, expo-dev-client@~57.0.6, expo-document-picker@~57.0.1, expo-file-system@~57.0.1, expo-notifications@~57.0.6, expo-sensors@~57.0.2, expo-splash-screen@~57.0.4, expo-sqlite@~57.0.1, expo-status-bar@~57.0.1, expo-system-ui@~57.0.1, moti@^0.30.0, papaparse@^5.5.4, patch-package@^8.0.1, react@19.2.3, react-dom@19.2.3, react-native@0.86.0, react-native-reanimated@4.5.0, react-native-safe-area-context@~5.7.0, react-native-web@^0.21.2, react-native-webrtc@^124.0.7, react-native-worklets@0.10.0, ts-fsrs@^5.4.1, typescript@~6.0.3, vitest@^4.1.10
- server/package.json: pdf-parse@^2.4.5

### Recent commits (newest first)

- docs: publish judging license
- docs: show current isometric room
- feat: ship Doomo Build Week submission
- UI: Refactor to use design tokens and remove inline hex
- feat(home): make the room the primary interaction surface
- fix(mascot): prevent blank idle frame playback
- feat(copy): morality-arc voice on the room/room copy
- fix(room): add emulator touch parallax fallback
- fix(build): sdk57-compatible native deps
- fix(room): add required Reanimated runtime
- feat(room): study-home earned props
- feat(room): health-driven room mood
- feat(room): idle peek
- feat(room): tilt parallax
- feat(room): layered 2.5D scene + shadow
- feat(retention): verify + polish streak chip
- fix(mascot): idle flicker — guard undefined frames + reject in validator
- feat(retention): surface kind streak
- feat(mascot): play idle + relief animation clips
- feat(brand): app icon + splash

## Key source files (fetched from GitHub, selected and truncated for size)

### mobile/assets/room/bongseng/LICENSE.md

```markdown
# Bongseng Isometric Apartment Asset Pack

Source: https://bongseng.itch.io/isometric-apartment-asset-pack

The creator permits commercial and non-commercial use in projects, including modification.
Do not redistribute or resell the source assets (including edited source assets) on their own.
Credit requested: **Bongseng — Isometric Apartment Asset Pack**.

The curated room composite under `assets/room/bongseng/` is derived from this pack for use
inside Doomo only. Keep this repository private unless the asset licensing plan is reviewed.

```

### server/package.json

```
{
  "name": "doomo-realtime-session-service",
  "version": "1.0.0",
  "private": true,
  "type": "module",
  "engines": {
    "node": ">=20"
  },
  "scripts": {
    "start": "node src/server.mjs",
    "test": "node --test src/*.test.mjs"
  },
  "dependencies": {
    "pdf-parse": "^2.4.5"
  }
}

```

### mobile/package.json

```
{
  "name": "mobile",
  "version": "1.0.0",
  "main": "index.ts",
  "dependencies": {
    "@expo/metro-runtime": "~57.0.6",
    "@expo/vector-icons": "^15.0.2",
    "@shopify/react-native-skia": "2.6.2",
    "@types/papaparse": "^5.5.2",
    "expo": "~57.0.6",
    "expo-camera": "^57.0.3",
    "expo-dev-client": "~57.0.6",
    "expo-document-picker": "~57.0.1",
    "expo-file-system": "~57.0.1",
    "expo-notifications": "~57.0.6",
    "expo-sensors": "~57.0.2",
    "expo-splash-screen": "~57.0.4",
    "expo-sqlite": "~57.0.1",
    "expo-status-bar": "~57.0.1",
    "expo-system-ui": "~57.0.1",
    "moti": "^0.30.0",
    "papaparse": "^5.5.4",
    "react": "19.2.3",
    "react-dom": "19.2.3",
    "react-native": "0.86.0",
    "react-native-reanimated": "4.5.0",
    "react-native-safe-area-context": "~5.7.0",
    "react-native-web": "^0.21.2",
    "react-native-webrtc": "^124.0.7",
    "react-native-worklets": "0.10.0",
    "ts-fsrs": "^5.4.1"
  },
  "devDependencies": {
    "@types/react": "~19.2.2",
    "babel-preset-expo": "^57.0.3",
    "patch-package": "^8.0.1",
    "typescript": "~6.0.3",
    "vitest": "^4.1.10"
  },
  "scripts": {
    "start": "expo start",
    "android": "expo run:android",
    "ios": "expo run:ios",
    "web": "expo start --web",
    "test": "vitest run",
    "test:watch": "vitest",
    "postinstall": "patch-package"
  },
  "private": true
}

```

### mobile/index.ts

```typescript
import { registerRootComponent } from 'expo';

import App from './App';

// registerRootComponent calls AppRegistry.registerComponent('main', () => App);
// It also ensures that whether you load the app in Expo Go or in a native build,
// the environment is set up appropriately
registerRootComponent(App);

```

### server/src/server.mjs

```
import http from 'node:http';
import { pathToFileURL } from 'node:url';

import { createCardsGenerateHandler, loadCardsConfig } from './cardsEndpoint.mjs';
import { createRealtimeSessionHandler, loadRealtimeConfig } from './realtimeSession.mjs';

const cardsRoute = (request) => {
  try {
    return new URL(request.url ?? '/', 'http://localhost').pathname === '/v1/cards/generate';
  } catch {
    return false;
  }
};

export const createDoomoServer = ({ config, realtimeConfig = config, cardsConfig, ...options } = {}) => {
  const realtime = createRealtimeSessionHandler({
    ...options,
    config: realtimeConfig ?? loadRealtimeConfig(),
  });
  const cards = createCardsGenerateHandler({
    ...options,
    config: cardsConfig ?? loadCardsConfig(),
  });
  return http.createServer((request, response) => (cardsRoute(request) ? cards(request, response) : realtime(request, response)));
};

const isEntrypoint = process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href;
if (isEntrypoint) {
  const port = Number(process.env.PORT || 8787);
  const server = createDoomoServer({
    cardsConfig: loadCardsConfig(),
    realtimeConfig: loadRealtimeConfig(),
  });
  server.listen(port, '0.0.0.0', () => {
    console.log(`Doomo service listening on http://0.0.0.0:${port}`);
  });
}

```

### mobile/src/realtime/index.ts

```typescript
export * from './DoomoRealtimeSession';
export * from './realtimeEvents';

```

### mobile/src/resets/index.ts

```typescript
export * from './catalog';
export * from './mixer';
export * from './types';

```

### mobile/src/mascot/index.ts

```typescript
export * from './affect';
export * from './animationChoreography';
export * from './visualState';

```

### mobile/modules/doomo-usage/index.ts

```typescript
import DoomoUsageModule from './src/DoomoUsageModule';

import type {
  UsageAccessSettingsResult,
  UsageAccessStatus,
  UsageRangeRequest,
  UsageRangeResult,
} from './src/DoomoUsage.types';

// The default export is useful for low-level Android-only integration.
export default DoomoUsageModule;
export * from './src/DoomoUsage.types';

export function getUsageAccessStatus(): UsageAccessStatus {
  return DoomoUsageModule.getUsageAccessStatus();
}

export function openUsageAccessSettings(): Promise<UsageAccessSettingsResult> {
  return DoomoUsageModule.openUsageAccessSettings();
}

export function getUsageForRange(request: UsageRangeRequest): Promise<UsageRangeResult> {
  return DoomoUsageModule.getUsageForRange(
    request.startMs,
    request.endMs,
    [...request.packageNames]
  );
}

```

### mobile/babel.config.js

```javascript
module.exports = function (api) {
  api.cache(true);
  return {
    presets: ['babel-preset-expo'],
    // Worklets plugin powers reanimated (and moti). MUST be listed last.
    plugins: ['react-native-worklets/plugin'],
  };
};

```

[100 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]