# Project export: StudyWorld

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: CruzHacks 2026
- Tagline: A gamified focus-first study environment where AI adapts to how you learn and not just what you type all powered by OpenNote memory.
- Devpost: https://devpost.com/software/studyworld
- GitHub: https://github.com/ShryukGrandhi/StudyHub
- Video: https://www.youtube.com/embed/UJZo9x0KfJo?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 1 GitHub contributor(s) — ShryukGrandhi (2 commits)

## Devpost submission (written by the team)

### Inspiration

Studying today is fragmented: assignments live in one place, class files in another, and “AI help” usually lives in a separate chat tab. Even when students use AI, the tool typically has no idea what happens after it responds—whether the student actually understood, got distracted, or became dependent on asking for the next step. We wanted a workspace that feels like a place to study, where focus and learning are supported in real time, not just through prompts.

### What it does

StudyWorld is a pixel-style student “office” where you can interact with specialized AI teacher agents organized by department (Math, Science, English) and then enter the Focus Room—the core experience—where you lock in on real tasks. In the Focus Room, students can: Choose tasks/assignments and run a timed study session Ask subject specialists for guided help and explanations Get learning supports like structured guidance and visual explanations (including Manim-style visuals) Use a real-time computer-vision attention signal layer to detect engagement drops during study and provide supportive interventions View session insights and AI decisions logged with timestamps It also integrates with Opennote as the long-term learning workspace/memory layer, so studying becomes continuous across sessions rather than isolated chats.

### How we built it

Frontend: A web app with a pixel-office hub world and a Focus Room page for sessions, tasks, and specialist interaction AI agents: Department-based “teacher” agents designed to guide learning with subject-appropriate styles Focus Room signals: Integrated a live CV pipeline (OpenCV-based) to derive attention/engagement signals during study sessions Logging & insights: Session events and AI decisions are captured with timestamps and displayed in the UI Opennote integration: Used Opennote as the central workspace for study artifacts and structured session insights so the system can “pick up where you left off”

### Challenges we ran into

Not becoming “just another chatbot”: We focused on making StudyWorld a learning environment with a dedicated Focus Room rather than a chat-first app. Designing CV support responsibly: We wanted the focus signals to feel helpful—not punitive—while avoiding storing sensitive raw video. Making adaptive behavior explainable: Logging decisions in a way that’s understandable and tied to timestamps and session context. Meaningful Opennote integration: Ensuring Opennote is used as a real memory/workspace layer, not a simple export button.

### Accomplishments we're proud of

Built a gamified office UI that makes studying feel like an interactive space Shipped a working Focus Room that combines tasks, timed sessions, specialist help, and real-time engagement signals Implemented timestamped decision/insight logging so the system isn’t a black box Integrated Opennote as a backbone for continuity across sessions

### What we learned

The biggest gap in AI studying tools isn’t generating answers—it’s structure, timing, and follow-through. UI/UX changes how people learn: making it feel like a “place” increases engagement compared to a blank chat box. Explainability matters: if a system adapts in real time, users need to see why it changed course.

### What's next

Build a full knowledge graph view that visually shows how concepts connect over time using Opennote’s logged artifacts and relationships Add deeper student/teacher analytics (focus patterns, misconception trends, intervention effectiveness) Improve personalization: adapt focus plans and teaching style based on longer-term patterns and outcomes Expand interactive learning modes (retrieval drills, spaced repetition scheduling, and more visual-first explanations)

## README (from the GitHub repository)

# OfficeMates / CampusSuite

**Multi-Agent Student Productivity Platform with Voice-First AI**

CruzHacks 3.0 Project - Pixelated office of AI agents that process student inputs (slides, audio, PDFs, voice) and create polished notes saved to Opennote.

---

## Quick Start

### 1. Install Dependencies

```bash
# Backend
cd backend
pip install -r requirements.txt

# Frontend
cd frontend
npm install
```

### 2. Configure Environment

Copy `.env` and fill in your API keys:

```bash
cp .env.example .env
```

### 3. Run the Application

```bash
# Terminal 1: Backend
cd backend
python main.py
# or: uvicorn main:app --reload --port 8000

# Terminal 2: Frontend
cd frontend
npm run dev
```

---

## API Keys Required

| Service | Environment Variable | Get Key |
|---------|---------------------|---------|
| Google AI (Gemini) | `GOOGLE_API_KEY` | [Google AI Studio](https://makersuite.google.com/app/apikey) |
| LiveKit | `LIVEKIT_API_KEY`, `LIVEKIT_API_SECRET` | [LiveKit Cloud](https://cloud.livekit.io/) |
| Deepgram | `DEEPGRAM_API_KEY` | [Deepgram Console](https://console.deepgram.com/) |
| Opennote | `OPENNOTE_API_KEY` | [Opennote Docs](https://opennote-4c3f15e9.mintlify.app/) |
| Unwrap.ai | `UNWRAP_API_KEY` | [Unwrap.ai](https://unwrap.ai/) |

---

## Architecture

```
┌─────────────────────────────────────────────────────────────────────────┐
│                           FRONTEND (React + PixiJS)                      │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐  ┌─────────────┐    │
│  │ Pixel Map   │  │ Voice UI    │  │ Gradebook   │  │ Agent View  │    │
│  │ (PixiJS)    │  │ (LiveKit)   │  │ (XP/Badges) │  │ (Progress)  │    │
│  └─────────────┘  └─────────────┘  └─────────────┘  └─────────────┘    │
└─────────────────────────────────────────────────────────────────────────┘
                              │
                              ▼ WebSocket / REST
┌─────────────────────────────────────────────────────────────────────────┐
│                           BACKEND (FastAPI)                              │
│  ┌─────────────────────────────────────────────────────────────────┐   │
│  │                    MULTI-AGENT ORCHESTRATOR                      │   │
│  │  ┌────────┐ ┌──────────┐ ┌────────┐ ┌──────────┐ ┌──────────┐  │   │
│  │  │ Intake │→│ Processor│→│ Editor │→│Researcher│→│ Actioner │  │   │
│  │  └────────┘ └──────────┘ └────────┘ └──────────┘ └──────────┘  │   │
│  └─────────────────────────────────────────────────────────────────┘   │
│                              │                                          │
│  ┌───────────────┬───────────────┬───────────────┬───────────────┐    │
│  │ LiveKit       │ Deepgram      │ Opennote      │ Unwrap.ai     │    │
│  │ (Voice)       │ (STT)         │ (Notes/AI)    │ (Social)      │    │
│  └───────────────┴───────────────┴───────────────┴───────────────┘    │
└─────────────────────────────────────────────────────────────────────────┘
```

---

## Agent Pipeline

| Agent | Role | Opennote | Unwrap |
|-------|------|----------|--------|
| **Intake** | Parse metadata, extract due dates | - | - |
| **Processor** | Heavy LLM work (summaries, OCR, STT) | Feynman-3 model | - |
| **Editor** | Clean, normalize, polish content | Feynman-3 model | - |
| **Researcher** | Enrich with community context | - | Search API |
| **Actioner** | Create gradebook entries, save notes | Create Note API | - |
| **QA** | Validate, confidence scoring | - | - |
| **Personality** | UI messages, voice responses | - | - |

---

## Voice Interaction Flow

```
User speaks → LiveKit captures audio
                    ↓
            Deepgram STT transcribes
                    ↓
            Intent Detection
            ┌───────┴───────┐
      Question?         Dictation?
           ↓                 ↓
      Search Notes     Run Agent Pipeline
           ↓                 ↓
      Voice Response   Create Note → Opennote
                             ↓
                       Voice Confirmation
```

---

## API Endpoints

### Tasks
- `POST /api/tasks` - Create processing task
- `GET /api/tasks/{id}` - Get task status
- `GET /api/tasks?user_id=xxx` - List user tasks

### Voice
- `POST /api/voice/session` - Create voice session (returns LiveKit token)
- `POST /api/voice/transcript` - Process transcript
- `GET /api/livekit/token` - Get LiveKit token directly

### Users
- `GET /api/users/{id}/xp` - Get XP and level
- `POST /api/users/{id}/xp` - Update XP

### Departments
- `GET /api/departments` - List all departments

### WebSocket
- `WS /ws/{user_id}` - Real-time updates

---

## WebSocket Events

### Client → Server
```json
{ "event": "transcript", "text": "...", "is_final": true }
{ "event": "ping" }
```

### Server → Client
```json
{ "event": "task_progress", "current_agent": "Processor", "progress": 0.5 }
{ "event": "task_completed", "xp_awarded": 15, "opennote_note_id": "..." }
{ "event": "voice_response", "text": "...", "agent": "Professor Pixel" }
{ "event": "xp_update", "level": 3, "level_up": true }
```

---

## Department Personalities

| Department | Agent | Catchphrase | Color |
|------------|-------|-------------|-------|
| Math | Professor Pixel | "Let me calculate..." | #4A90D9 |
| Science | Dr. Beaker | "Hypothesis confirmed!" | #5CB85C |
| English | Scribe McWrite | "A tale worth telling..." | #F0AD4E |
| Study Hub | Coach Campus | "You've got this!" | #9B59B6 |

---

## Gamification

### XP Rewards
- Note created: 10 XP
- Voice note: 15 XP
- Flashcard correct: 5 XP
- Quiz completed: 15 XP
- Streak day: 20 XP

### Levels
1. Freshman (0 XP)
2. Sophomore (100 XP) - Custom avatar color
3. Junior (300 XP) - Desk plant
4. Senior (600 XP) - Custom agent name
5. Graduate (1000 XP) - Gold badge
10. Professor (5000 XP) - All decorations

---

## Demo Script (3 min)

```
0:00 - Hook: "This is CampusSuite: your pixel office where agents do the heavy lifting."

0:10 - Drag lecture slides to Math Intake → show agent procession

0:30 - Processor shows summary; Researcher pulls community tips from Unwrap

0:50 - Actioner saves note to Opennote (show success)

1:10 - Open Gradebook, mark item done → XP + decor unlock

1:25 - Voice demo: "Hey, can you explain integrals?" → Agent responds

1:45 - Show Manim video generation for equation

2:00 - Quick flashcard quiz from note

2:20 - Wrap: API log screenshot proving Opennote & Unwrap integration
```

---

## Project Structure

```
CruzHacks3.0/
├── .env                          # Environment variables
├── MASTER_CONFIG.py              # All prompts, schemas, configs
├── README.md
│
├── backend/
│   ├── main.py                   # FastAPI server
│   ├── requirements.txt
│   └── manim_scenes/            # Manim video templates
│
└── frontend/
    ├── package.json
    └── src/
        ├── lib/
        │   └── livekit-voice.ts  # LiveKit integration
        ├── hooks/
        │   └── useVoiceSession.ts
        └── components/
            └── VoiceInterface.tsx
```

---

## Troubleshooting

### LiveKit connection fails
- Check `LIVEKIT_API_KEY` and `LIVEKIT_API_SECRET`
- Ensure LiveKit URL starts with `wss://`

### Deepgram not transcribing
- Verify `DEEPGRAM_API_KEY` is valid
- Check browser microphone permissions
- Ensure sample rate matches (16000 Hz)

### Demo mode
Set `ENABLE_MOCKS=true` in `.env` for stable demo with mock responses.

---

## Team

CruzHacks 3.0 - Built with LiveKit, Deepgram, Opennote, Unwrap.ai, Manim, and love.


## Detected evidence (automated analysis)

Indexed codebase: 30 recognized source files, 646 KB.
- CSS (language) — detected in the code
- FastAPI (technology) — detected in the code
- JavaScript (language) — detected in the code
- Next.js (technology) — detected in the code
- Python (language) — detected in the code
- React (technology) — detected in the code
- Tailwind CSS (technology) — detected in the code
- TypeScript (language) — detected in the code
- AI coding agent: Claude Code — evidence: config files committed to the repository

## Codebase structure (from repository index)

### Files (37 of 37)

```
.claude/settings.local.json
.gitignore
backend/__init__.py
backend/debug_context.py
backend/debug_video.py
backend/main.py
backend/manim_96e99001-be71-455f-b211-6f3fd51f7538.py
backend/requirements.txt
backend/seed_data/english_hamlet.md
backend/seed_data/math_derivatives.md
backend/seed_data/science_photosynthesis.md
backend/seed_journals.py
backend/vid.txt
check_cv.py
check_gemini.py
frontend/next-env.d.ts
frontend/next.config.js
frontend/package.json
frontend/src/app/globals.css
frontend/src/app/layout.tsx
frontend/src/app/page.tsx
frontend/src/components/ChatFlashcards.tsx
frontend/src/components/CodeViewer.tsx
frontend/src/components/FocusRoom.tsx
frontend/src/components/FocusTracker.tsx
frontend/src/components/KumospaceCharacter.tsx
frontend/src/components/PixelCharacter.tsx
frontend/src/components/SimpleCharacter.tsx
frontend/src/components/VoiceInterface.tsx
frontend/src/hooks/useVoiceSession.ts
frontend/src/lib/livekit-voice.ts
frontend/tsconfig.json
frontend/tsconfig.tsbuildinfo
manim_07ad941a-aeae-4d88-baed-42443cfab32c.py
MASTER_VOICE_AGENT_PROMPT.md
README.md
update_prompt.py
```

### Dependencies

- backend/requirements.txt: aiohttp, fastapi, google-generativeai, httpx, livekit-api, mediapipe@>=0.10.0, numpy, opencv-python, pillow, pydantic, PyJWT, python-dotenv, python-multipart, requests, uvicorn[standard], websockets
- frontend/package.json: @livekit/components-react@^2.0.0, @livekit/track-processors@^0.3.0, @pixi/react@^7.1.0, @types/node@^20.11.0, @types/react@^18.2.48, @types/react-dom@^18.2.18, autoprefixer@^10.4.17, eslint@^8.56.0, eslint-config-next@^14.1.0, framer-motion@^11.0.0, livekit-client@^2.0.0, lucide-react@^0.323.0, next@^14.1.0, pixi.js@^8.0.0, postcss@^8.4.35, react@^18.2.0, react-dom@^18.2.0, swr@^2.2.4, tailwindcss@^3.4.1, typescript@^5.3.3, zustand@^4.5.0

### Recent commits (newest first)

- feat: Add auto-engagement video generation on distraction detection
- Initialize StudyHub (Secure)

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

### MASTER_VOICE_AGENT_PROMPT.md

```markdown
# MASTER VOICE AGENT PROMPT
## OfficeMates / CampusSuite - Complete System Prompt for LiveKit Voice Agents

---

## ENVIRONMENT KEYS (Configure in .env)

```bash
# LiveKit (Real-time Voice)
LIVEKIT_URL=wss://cruz-0e6uhtze.livekit.cloud
LIVEKIT_API_KEY=APIW8dAjQQEySiS
LIVEKIT_API_SECRET=QG7IBIffd7bKZafel2I7W7ernz5ReLidP8Xmffe9OG4QA

# Deepgram (Speech-to-Text)
DEEPGRAM_API_KEY=8b1de584cc42876cae5f735af4d4184b81201c1a

# Google AI (Gemini)
GOOGLE_API_KEY=AIzaSyC8bsj8Oc9HAoji-1rUHK9gXPYhJGRNtYs

# Opennote (Notes API)
OPENNOTE_API_KEY=<your-opennote-key>
OPENNOTE_BASE_URL=https://api.opennote.me/v1

# Unwrap.ai (Social Enrichment)
UNWRAP_API_KEY=<your-unwrap-key>
```

---

## MASTER SYSTEM PROMPT (Copy this for your voice agent)

```
═══════════════════════════════════════════════════════════════════════════════
VOICE AGENT SYSTEM PROMPT - OFFICEMATES
═══════════════════════════════════════════════════════════════════════════════

You are OfficeMates, a voice-first AI study assistant powered by LiveKit. You help students:
1. Take notes from voice dictation
2. Answer questions about their study materials
3. Create flashcards and quizzes
4. Search community tips from Reddit/StackOverflow via Unwrap
5. Generate visual explanations using Manim
6. Track progress with XP and gamification

═══ VOICE INTERACTION RULES ═══
- Keep responses CONCISE (under 30 words for voice output)
- Be encouraging but not condescending
- Use the department personality when responding
- Acknowledge input before processing ("Got it! Let me work on that...")
- Confirm actions when complete ("Your note has been saved!")

═══ DEPARTMENT PERSONALITIES ═══
- MATH (Professor Pixel): Nerdy, loves equations. Says "Let me calculate..."
- SCIENCE (Dr. Beaker): Curious, experimental. Says "Hypothesis confirmed!"
- ENGLISH (Scribe McWrite): Eloquent, bookish. Says "A tale worth telling..."
- STUDY_HUB (Coach Campus): Motivating, energetic. Says "You've got this!"

═══ INTENT DETECTION ═══
Listen for these patterns:

QUESTION INTENT:
- "What is...", "How do I...", "Can you explain...", "Tell me about..."
→ Search notes first, then answer or offer to create notes

COMMAND INTENT:
- "Save this", "Create flashcards", "Open my notes", "Quiz me", "Search for..."
→ Execute the command and confirm

DICTATION INTENT:
- "My notes on...", "For the homework...", "The lecture said..."
→ Run through agent pipeline: Intake → Processor → Editor → Actioner
→ Save to Opennote

CONVERSATION INTENT:
- Greetings, unclear requests, casual chat
→ Respond warmly, guide toward study tasks

═══ AGENT PIPELINE ═══
For dictation/content processing:

1. INTAKE: Parse metadata, detect topic, estimate priority
2. PROCESSOR: Create summary, extract key points, identify if visualization needed
3. EDITOR: Clean grammar, normalize notation, generate tags
4. RESEARCHER: Query Unwrap for community tips (if enabled)
5. ACTIONER: Format final note, create flashcards, save to Opennote
6. QA: Validate before final save

═══ RESP
[truncated — 13183 more characters]
```

### backend/seed_data/math_derivatives.md

```markdown
# Calculus: The Study of Change

## Core Concept: Derivative
The derivative measures the instantaneous rate of change of a function. It represents the slope of the tangent line to the curve at a point.

## Rules of Differentiation

### Power Rule
$$ \frac{d}{dx}(x^n) = nx^{n-1} $$
*Example*: $\frac{d}{dx}(x^3) = 3x^2$

### Product Rule
$$ (uv)' = u'v + uv' $$

### Quotient Rule
$$ (\frac{u}{v})' = \frac{u'v - uv'}{v^2} $$

### Chain Rule
Used for composite functions:
$$ \frac{d}{dx}f(g(x)) = f'(g(x)) \cdot g'(x) $$

## Common Derivatives
- $\sin(x) \rightarrow \cos(x)$
- $\cos(x) \rightarrow -\sin(x)$
- $e^x \rightarrow e^x$
- $\ln(x) \rightarrow \frac{1}{x}$

```

### backend/requirements.txt

```
# OFFICEMATES BACKEND - PYTHON DEPENDENCIES
# Core - Install these first
fastapi
uvicorn[standard]
python-multipart
pydantic
websockets

# LiveKit
livekit-api
PyJWT

# Google AI
google-generativeai

# HTTP
requests
httpx
aiohttp

# Environment
python-dotenv

# OpenCV for distraction detection (legacy - being migrated to MediaPipe)
opencv-python
numpy
pillow

# MediaPipe for robust face detection and object recognition
mediapipe>=0.10.0

```

### frontend/package.json

```
{
  "name": "officemates-frontend",
  "version": "1.0.0",
  "description": "OfficeMates - Multi-Agent Student Productivity Platform",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "next": "^14.1.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",

    "livekit-client": "^2.0.0",
    "@livekit/components-react": "^2.0.0",
    "@livekit/track-processors": "^0.3.0",

    "pixi.js": "^8.0.0",
    "@pixi/react": "^7.1.0",

    "zustand": "^4.5.0",
    "swr": "^2.2.4",

    "framer-motion": "^11.0.0",
    "lucide-react": "^0.323.0",

    "tailwindcss": "^3.4.1",
    "autoprefixer": "^10.4.17",
    "postcss": "^8.4.35",

    "typescript": "^5.3.3",
    "@types/node": "^20.11.0",
    "@types/react": "^18.2.48",
    "@types/react-dom": "^18.2.18"
  },
  "devDependencies": {
    "eslint": "^8.56.0",
    "eslint-config-next": "^14.1.0"
  }
}

```

### frontend/src/app/layout.tsx

```typescript
import type { Metadata } from 'next';
import './globals.css';

export const metadata: Metadata = {
  title: 'Study Hub - AI Study Assistant',
  description: 'Multi-Agent Student Productivity Platform with Voice-First AI',
};

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <head>
        <link
          href="https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap"
          rel="stylesheet"
        />
      </head>
      <body>{children}</body>
    </html>
  );
}

```

### check_cv.py

```python
import cv2
import os

print(f"OpenCV Version: {cv2.__version__}")
print(f"Haarcascades Path: {cv2.data.haarcascades}")

face_xml = os.path.join(cv2.data.haarcascades, 'haarcascade_frontalface_default.xml')
eye_xml = os.path.join(cv2.data.haarcascades, 'haarcascade_eye.xml')

print(f"Checking {face_xml}: {'FOUND' if os.path.exists(face_xml) else 'MISSING'}")
print(f"Checking {eye_xml}: {'FOUND' if os.path.exists(eye_xml) else 'MISSING'}")

try:
    face_cascade = cv2.CascadeClassifier(face_xml)
    if face_cascade.empty():
        print("Error: Face cascade loaded but empty!")
    else:
        print("Success: Face cascade loaded.")
except Exception as e:
    print(f"Exception loading face cascade: {e}")

```

### check_gemini.py

```python

import os
import sys
import google.generativeai as genai

# Add backend to path to import config
sys.path.append(os.path.join(os.getcwd(), "backend"))
from MASTER_CONFIG import Keys

def check_models():
    print(f"API Key: {Keys.GOOGLE_API_KEY[:10]}...")
    
    try:
        genai.configure(api_key=Keys.GOOGLE_API_KEY)
        
        print("\nListing available models:")
        for m in genai.list_models():
            if 'generateContent' in m.supported_generation_methods:
                print(f"- {m.name}")
                
        print("\nTesting gemini-1.5-flash...")
        try:
            model = genai.GenerativeModel('gemini-1.5-flash')
            response = model.generate_content("Hello")
            print(f"Success! Response: {response.text}")
        except Exception as e:
            print(f"Failed: {e}")
            
        print("\nTesting gemini-2.0-flash...")
        try:
            model = genai.GenerativeModel('gemini-2.0-flash')
            response = model.generate_content("Hello")
            print(f"Success! Response: {response.text}")
        except Exception as e:
            print(f"Failed: {e}")
            
    except Exception as e:
        print(f"Configuration/Listing Error: {e}")

if __name__ == "__main__":
    check_models()

```

### update_prompt.py

```python

import os

new_prompt = r'''MASTER_SYSTEM_PROMPT = """
🧠 MASTER SYSTEM PROMPT
Focus Room — Behavior-Aware Learning Orchestrator
SYSTEM ROLE: Focus Room Orchestrator

You are the intelligence core of the Focus Room — the primary learning environment where the student spends most of their time engaging deeply with academic material.

Your goal is NOT to answer questions or generate content on demand.
Your goal is to OBSERVE how the student responds to learning experiences in real time and to ADAPT teaching, focus strategies, and learning trajectories accordingly.

This system is explicitly designed to reduce AI dependency and increase independent understanding.

--------------------------------
CORE THESIS (NON-NEGOTIABLE)
--------------------------------

Most AI learning tools understand what students TYPE.
This system understands how students RESPOND.

You must reason primarily from:
• attention patterns
• engagement duration
• hesitation and recovery
• distraction type and frequency
• application of explanations
• behavioral change over time

Text input is OPTIONAL and SECONDARY.

--------------------------------
FOCUS ROOM = PRIMARY INTERFACE
--------------------------------

The Focus Room is the system's PRIMARY mode.
All major learning decisions originate here.

When the student is in the Focus Room, you operate in BEHAVIOR-FIRST mode.

--------------------------------
SENSING & REAL-TIME OBSERVATION (OPENCV LAYER)
--------------------------------

You receive continuous, timestamped behavioral signals derived from local computer vision and activity monitoring (processed locally, no raw video stored):

Examples of signals (non-exhaustive):
• gaze direction and stability
• eye openness / blink rate
• head pose changes
• face presence / absence
• re-reading duration
• inactivity vs engagement
• abrupt attention drops
• recovery time after distraction
• interaction latency after explanation

Each signal arrives with:
• start_timestamp
• end_timestamp
• confidence score

You must NEVER infer medical diagnoses.
You must ONLY infer learning-relevant behavioral states.

--------------------------------
BEHAVIORAL EVENT DETECTION
--------------------------------

From raw signals, you must infer higher-level LEARNING EVENTS, such as:
• sustained focus
• shallow engagement
• cognitive overload
• confusion without asking
• distraction by device / environment
• fatigue or mental drift
• successful application of explanation
• disengagement after explanation

Each inferred event MUST:
• have a type
• have timestamps
• include evidence signals
• update the Shared Student Model
• be logged to Opennote

--------------------------------
SHARED STUDENT MODEL (LIVE & HISTORICAL)
--------------------------------

You maintain a continuously evolving model of the student, including:
• concept-level confidence
• preferred teaching modalities
• response effectiveness of visuals vs text
• typical focus window length
• distraction triggers
• recovery effectiveness
• time-of-day learning quality
• historical reflections
• intervention success rates

This model updates ONLY when behavior demonstrates learning or failure — not when content is generated.

--------------------------------
OPNNOTE = MEMORY + DECISION LOG (CRITICAL)
--------------------------------

Opennote is NOT a notes app.
Opennote is the authoritative MEMORY and REASONING RECORD of the Focus Room.

You must use Opennote to store:

1) Concept Nodes
   • title
   • department
   • confidence score
   • misconceptions
   • linked concepts (typed edges)

2) Learning Events
   • timestamped behavioral events
   • inferred cause
   • response effectiveness

3) Focus Sessions
   • start/end times
   • plan used
   • adaptations made
   • outcomes

4) Decision Logs (MANDATORY)
   For every non-trivial action you take, log:
   • timestamp
   • action taken
   • triggering evidence
   • alternative actions considered
   • reason chosen

The student MUST be able to click any decision and see:
"Why did the system do this?"

If a decision is not explainable, it must not occur.

--------------------------------
ADAPTIVE FOCUS PLANNING
--------------------------------

At the start of a Focus Room session:
• Generate a realistic, personalized plan informed by Opennote history.
• Prefer conservative plans unless evidence supports ambition.

During the session:
• Continuously evaluate focus quality and learning effectiveness.
• Adapt plans ONLY when evidence justifies it.
• Use the smallest effective change.
• Never adapt more than once per short interval unless critical.

Allowed adaptations:
• focus block length
• break timing and type
• goal decomposition
• teaching modality
• deferring explanation

--------------------------------
TEACHING & EXPLANATION POLICY
--------------------------------

Teaching must be TIMED and EARNED.

You may generate explanations or visuals ONLY IF:
• the student is attentive
• the student is not fatigued
• prior explanation failed
• behavior indicates conceptual confusion

You must WITHHOLD teaching when:
• attention is low
• student is disengaged
• explanation would create dependency

--------------------------------
MANIM VISUAL GENERATION
--------------------------------

You may generate Manim visuals to explain concepts, NOT to solve the student's exact problem.

Rules:
• visuals must explain intuition
• visuals must be reusable across problems
• visuals must be linked to concept nodes
• visuals must update concept confidence only after engagement

Every visual generation must be logged with:
• timestamp
• concept target
• reason for generation
• observed effect after viewing

--------------------------------
SEMANTIC SEARCH OVER CLASS FILES
--------------------------------

You have access to indexed class materials:
• lecture slides
• PDFs
• homework
• prior notes
• past Focus Room sessions

You may proactively:
• surface relevant prior explanations
• remind the student of related concepts
• suggest reviewing prer
[truncated — 2967 more characters]
```

### manim_07ad941a-aeae-4d88-baed-42443cfab32c.py

```python
import numpy as np
from manim import *

class IntegralExplanation(Scene):
    def construct(self):
        # -- 0. Introduction: What is an Integral? --
        title = Text("What is an Integral?", font_size=55).to_edge(UP, buff=0.5)
        self.play(Write(title))
        self.wait(1)

        # Setup Axes
        axes = Axes(
            x_range=[0, 3, 1],
            y_range=[0, 5, 1],
            x_length=6,
            y_length=4.5,
            axis_config={"include_numbers": True},
            tips=False # No arrows on axes for cleaner look
        ).to_edge(LEFT, buff=1)
        axes_labels = axes.get_axis_labels(x_label="x", y_label="f(x)")

        self.play(Create(axes), Create(axes_labels), run_time=1.5)
        self.wait(0.5)

        # Define a simple function: f(x) = x^2
        func = axes.get_graph(lambda x: x**2, x_range=[0, 2.5], color=BLUE_C)
        func_label = axes.get_graph_label(func, label="f(x) = x^2", x_val=2.2, direction=UP_RIGHT, color=BLUE_C)
        self.play(Create(func), FadeIn(func_label, shift=UP))
        self.wait(1)

        # -- 1. The Problem: Finding Area Under a Curve --
        area_problem_text = Text("How do we find the exact area under this curve?", font_size=32).next_to(title, DOWN)
        self.play(Transform(title, area_problem_text), FadeOut(func_label))
        self.wait(0.5)

        # Shade the area from x=0 to x=2
        area_x_range = [0, 2]
        area = axes.get_area(func, x_range=area_x_range, color=BLUE_A, opacity=0.6)
        self.play(FadeIn(area, shift=DOWN))
        self.wait(2)
        self.play(FadeOut(area)) # Fade out the exact area to prepare for approximation

        # -- 2. Approximation with Rectangles (Riemann Sums) --
        approx_text = Text("We can approximate it with rectangles!", font_size=38).next_to(title, DOWN)
        self.play(Transform(title, approx_text))
        self.wait(1)

        # Initial rectangles (n=4)
        num_rects_initial = 4
        rects = self._get_riemann_rectangles(
            axes, func, x_range=area_x_range, num_rects=num_rects_initial, color=GREEN_B, opacity=0.7
        )
        self.play(Create(rects))
        self.wait(1)

        # Highlight one rectangle and its dimensions
        one_rect_index = 1 # Pick the second rectangle for highlighting
        original_rect_state = rects[one_rect_index].copy() # Store original state
        one_rect_highlight = rects[one_rect_index].copy().set_color(YELLOW).set_stroke(YELLOW, width=3)
        self.play(Transform(rects[one_rect_index], one_rect_highlight))

        # Calculate coordinates for labels on the highlighted rectangle
        x_min_rect = area_x_range[0] + (one_rect_index * (area_x_range[1] - area_x_range[0]) / num_rects_initial)
        x_mid_rect = x_min_rect + (area_x_range[1] - area_x_range[0]) / (2 * num_rects_initial)
        y_height_rect = func.underlying_function(x_min_rect) # Height is f(x) at left edge

        dx_label = MathTex(r"\Delta x").next_to(axes.c2p(x_mid_rect, 0), DOWN, buff=0.1)
        
        # Position f(x) label on the left side, midway up the height
        left_midpoint_screen_coords = axes.c2p(x_min_rect, y_height_rect / 2)
        fx_label = MathTex(r"f(x)").next_to(left_midpoint_screen_coords, LEFT, buff=0.1)
        
        self.play(Write(dx_label), Write(fx_label))
        self.wait(1)

        # Introduce the area of one rectangle and the sum
        sum_formula_part = MathTex(r"f(x) \Delta x").move_to(axes).shift(RIGHT*2.5 + UP*1.5)
        area_text = Text("Area of one rectangle:", font_size=28).next_to(sum_formula_part, UP, buff=0.2, aligned_edge=LEFT)
        self.play(Write(area_text), Write(sum_formula_part))
        self.wait(1)

        total_sum_formula = MathTex(r"\sum_{i=1}^{n} f(x_i) \Delta x").next_to(sum_formula_part, DOWN, buff=0.5, aligned_edge=LEFT)
        total_sum_text = Text("Sum of all rectangle areas:", font_size=28).next_to(total_sum_formula, UP, buff=0.2, aligned_edge=LEFT)
        self.play(Write(total_sum_text), Write(total_sum_formula))
        self.wait(2)
        
        # Clean up labels and reset highlighted rectangle
        self.play(
            FadeOut(area_text), FadeOut(sum_formula_part),
            FadeOut(dx_label), FadeOut(fx_label),
            Transform(rects[one_rect_index], original_rect_state) # Transform it back to original state
        )
        self.wait(0.5)

        # -- 3. Improving the Approximation --
        improve_text = Text("More rectangles mean a better approximation!", font_size=38).next_to(title, DOWN)
        self.play(Transform(title, improve_text))
        self.wait(1)

        # Use ValueTracker for dynamic N
        n_value_tracker = ValueTracker(num_rects_initial)
        n_label = MathTex("n = ").next_to(total_sum_formula, LEFT)
        n_display = DecimalNumber(n_value_tracker.get_value(), num_decimal_places=0).next_to(n_label, RIGHT)
        
        self.play(FadeIn(n_label), FadeIn(n_display))

        # Updater for rectangles to change with n_value_tracker
        def update_rectangles(mob):
            new_num_rects = int(n_value_tracker.get_value())
            if new_num_rects < 1: new_num_rects = 1 # Ensure at least one rectangle
            new_rects = self._get_riemann_rectangles(
                axes, func, x_range=area_x_range, num_rects=new_num_rects, color=GREEN_B, opacity=0.7
            )
            mob.become(new_rects)

        rects.add_updater(update_rectangles)
        n_display.add_updater(lambda m: m.set_value(n_value_tracker.get_value()))
        self.add(n_display, rects) # Add rects with updater to scene for continuous updates

        self.play(n_value_tracker.animate.set_value(8), run_time=1)
        self.wait(0.5)
        self.play(n_value_tracker.animate.set_value(16), run_time=1)
        self.wait(0.5)
        self.play(n_value_tracker.animate.set_value(32), run_time=1)
        self.wait(0.5)
        self.play(n_value_tracker.animate.set_value(64), run_time=1.5)
        self.wait(1
[truncated — 5013 more characters]
```

### backend/__init__.py

```python
# OfficeMates Backend

```

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