# Project export: Desktoski

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: Cal Hacks 11.0
- Tagline: Oski right at your desktop
- Devpost: https://devpost.com/software/desktoski
- GitHub: https://github.com/miraprabhakar/Desktoski
- Team: 4 GitHub contributor(s) — ved-birla (15 commits), Theman1483 (8 commits), Mira Prabhakar (6 commits), katelynsun (5 commits)

## Devpost submission (written by the team)

### Inspiration

: desktop pets we had growing up

### What it does

: It can keep track of your to do list, remind you of your schedule, and you can feed it with coins gained by completing your to do options

### How we built it

: We built it using python and tinter

### Challenges we ran into

: A large challenge was making the noise tracking work, as the image was not pausing when we hovered with a mouse

### Accomplishments we're proud of

: We're all fairly new to programming, so actually submitting a project was a huge accomplishment!

### What we learned

: We learned a lot about the tkinter package and how we can use such functions to manipulate images on a desktop

### What's next

: We hope to connect canvas to it to help it gamify the studying process!

## README (from the GitHub repository)

# Desktoski

## Detected evidence (automated analysis)

Indexed codebase: 4 recognized source files, 28 KB.
- Python (language) — detected in the code

## Codebase structure (from repository index)

### Files (8 of 8)

```
.DS_Store
.gitignore
main.py
README.md
requirements.txt
thought_bubble.py
todo_list.json
vedantsedits.py
```

### Dependencies

- requirements.txt: cachetools@==5.5.0, certifi@==2024.8.30, charset-normalizer@==3.4.0, contourpy@==1.3.0, cycler@==0.12.1, fonttools@==4.54.1, google-api-core@==2.21.0, google-api-python-client@==2.149.0, google-auth@==2.35.0, google-auth-httplib2@==0.2.0, google-auth-oauthlib@==1.2.1, googleapis-common-protos@==1.65.0, httplib2@==0.22.0, idna@==3.10, kiwisolver@==1.4.7, matplotlib@==3.9.2, numpy@==2.1.2, oauthlib@==3.2.2, packaging@==24.1, pillow@==11.0.0, proto-plus@==1.24.0, protobuf@==5.28.2, pyasn1@==0.6.1, pyasn1_modules@==0.4.1, pyparsing@==3.2.0, python-dateutil@==2.9.0.post0, requests@==2.32.3, requests-oauthlib@==2.0.0, rsa@==4.9, six@==1.16.0, tk@==0.1.0, uritemplate@==4.1.1, urllib3@==2.2.3

### Recent commits (newest first)

- Update thought_bubble.py
- some edits idk
- added desktop png
- font colors in todo list
- fixed walking
- Merge branch 'main' of https://github.com/miraprabhakar/Desktoski
- updated walking animation
- Add files via upload
- 10:21am status
- dynamic screen pt 2
- Merge branch 'main' of https://github.com/miraprabhakar/Desktoski
- dynamic screen pet lheight
- Merge branch 'main' of https://github.com/miraprabhakar/Desktoski
- todo
- todo
- walking animation
- walking
- very basic shop
- fixed bubble placement
- Update thought_bubble.py

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

### requirements.txt

```
cachetools==5.5.0
certifi==2024.8.30
charset-normalizer==3.4.0
contourpy==1.3.0
cycler==0.12.1
fonttools==4.54.1
google-api-core==2.21.0
google-api-python-client==2.149.0
google-auth==2.35.0
google-auth-httplib2==0.2.0
google-auth-oauthlib==1.2.1
googleapis-common-protos==1.65.0
httplib2==0.22.0
idna==3.10
kiwisolver==1.4.7
matplotlib==3.9.2
numpy==2.1.2
oauthlib==3.2.2
packaging==24.1
pillow==11.0.0
proto-plus==1.24.0
protobuf==5.28.2
pyasn1==0.6.1
pyasn1_modules==0.4.1
pyparsing==3.2.0
python-dateutil==2.9.0.post0
requests==2.32.3
requests-oauthlib==2.0.0
rsa==4.9
six==1.16.0
tk==0.1.0
uritemplate==4.1.1
urllib3==2.2.3

```

### main.py

```python
import tkinter as tk
from PIL import Image, ImageTk
import random

class DesktopPet:
    def __init__(self, root, image_path, window_size=(1200, 800)):
        self.root = root
        self.root.title("Desktop Pet")
        self.root.geometry(f"{window_size[0]}x{window_size[1]}")

        self.pet_image, self.pet_width, self.pet_height = self.resize(image_path, 200, 200)
        self.pet_label = tk.Label(self.root, image=self.pet_image)
        self.pet_label.place(x=800, y=640)

        self.stop_walk = False
        self.walk_after_id = None

        self.pet_label.bind("<Enter>", self.on_mouse_enter)
        self.pet_label.bind("<Leave>", self.on_mouse_leave)

    @staticmethod
    def resize(image_path, width, height):
        img = Image.open(image_path)
        img_resized = img.resize((width, height))
        return ImageTk.PhotoImage(img_resized), width, height

    def pet_walk(self):
        if not self.stop_walk:
            current_x, current_y = self.pet_label.winfo_x(), self.pet_label.winfo_y()
            target_lower = max(current_x - 300, 0)
            target_upper = min(current_x + 300, 1200)
            target_x = random.randint(target_lower, target_upper)
            
            step_size = 2

            def move_step():
                nonlocal current_x
                if current_x > target_x:
                    current_x -= step_size
                elif current_x < target_x:
                    current_x += step_size

                self.pet_label.place(x=current_x, y=640)
                
                if abs(current_x - target_x) > step_size:
                    self.walk_after_id = self.root.after(100, move_step)
                else:
                    self.walk_after_id = self.root.after(random.randint(1000, 4000), self.pet_walk)

            move_step()

    def on_mouse_enter(self, event):
        self.stop_walk = True
        if self.walk_after_id is not None:
            self.root.after_cancel(self.walk_after_id)
            self.walk_after_id = None

    def on_mouse_leave(self, event):
        self.stop_walk = False
        if self.walk_after_id is None:
            self.pet_walk()

    def run(self):
        self.pet_walk()
        self.root.mainloop()

if __name__ == "__main__":
    root = tk.Tk()
    pet = DesktopPet(root, "pngs/oski_bear.png")
    # pet2 = DesktopPet(root, "pngs/oski_image.png")
    pet.run()
```

### thought_bubble.py

```python
import math
import tkinter as tk
from tkinter import simpledialog
from tkinter import Tk, Button, PhotoImage
from tkinter import Checkbutton, IntVar
from PIL import Image, ImageTk
import random
import json
import os
balance = 0

class DesktopPetWithPopup:
    def __init__(self, root, window_size=(1200, 800)):
        self.root = root
        self.root.title("Desktop Pet")
        self.root.geometry(f"{window_size[0]}x{window_size[1]}")

        self.stationary_image_path = "pngs/oski front facing.png"
        self.right_animation = ["pngs/right1.png", "pngs/right2.png"]
        self.left_animation = ["pngs/left1.png", "pngs/left2.png"]

        # Load and set the background image
        # self.bg_image_path = "pngs/desktop.png"
        # self.background_label = tk.Label(self.root, image=self.bg_image_path)
        

        self.pet_image, self.pet_width, self.pet_height = self.resize(self.stationary_image_path, 200, 200)
        self.pet_label = tk.Label(self.root, image=self.pet_image)
        self.position_pet()

        self.stop_walk = False
        self.walk_after_id = None
        self.current_animation = None
        self.animation_frame = 0

        self.pet_label.bind("<Enter>", self.on_mouse_enter)
        self.pet_label.bind("<Leave>", self.on_mouse_leave)

        # Load and create small images
        self.small_images = []
        self.small_labels = []
        for i in range(5):
            img, _, _ = self.resize("pngs/blank_bubble.png", 30, 30)
            self.small_images.append(img)
            label = tk.Label(self.root, image=img)
            label.bind("<Button-1>", self.on_small_image_click)
            self.small_labels.append(label)

        # Load todo list from file
        self.todo_list = self.load_todo_list()

        # Bind the window resize event
        self.root.bind("<Configure>", self.on_window_resize)

    def position_pet(self):
        window_height = self.root.winfo_height()
        current_x = self.pet_label.winfo_x()
        pet_y = window_height - self.pet_height
        self.pet_label.place(x=current_x, y=pet_y)

    def on_window_resize(self, event):
        self.position_pet()

    @staticmethod
    def resize(image_path, width, height):
        img = Image.open(image_path)
        img_resized = img.resize((width, height))
        return ImageTk.PhotoImage(img_resized), width, height

    def pet_walk(self):
        if not self.stop_walk:
            current_x = self.pet_label.winfo_x()
            window_width = self.root.winfo_width()
            target_lower = max(current_x - 300, 0)
            target_upper = min(current_x + 300, window_width - self.pet_width)
            target_x = random.randint(target_lower, target_upper)
            
            step_size = 2

            def move_step():
                nonlocal current_x
                if current_x > target_x:
                    current_x -= step_size
                    self.current_animation = self.left_animation
                elif current_x < target_x:
                    current_x += step_size
                    self.current_animation = self.right_animation
                else:
                    self.current_animation = None

                self.position_pet()  # Update y-position
                self.pet_label.place(x=current_x)
                
                if self.current_animation:
                    self.animate_pet()
                
                if abs(current_x - target_x) > step_size:
                    self.walk_after_id = self.root.after(100, move_step)
                else:
                    self.current_animation = None
                    self.update_pet_image(self.stationary_image_path)
                    self.walk_after_id = self.root.after(random.randint(1000, 4000), self.pet_walk)

            move_step()

    def animate_pet(self):
        if self.current_animation:
            self.animation_frame = (self.animation_frame + 1) % len(self.current_animation)
            self.update_pet_image(self.current_animation[self.animation_frame])

    def update_pet_image(self, image_path):
        new_image, _, _ = self.resize(image_path, 200, 200)
        self.pet_label.configure(image=new_image)
        self.pet_label.image = new_image

    def on_mouse_enter(self, event):
        self.stop_walk = True
        if self.walk_after_id is not None:
            self.root.after_cancel(self.walk_after_id)
            self.walk_after_id = None
        self.show_small_images()

    def on_mouse_leave(self, event):
        self.stop_walk = False
        if self.walk_after_id is None:
            self.pet_walk()
        self.hide_small_images()

    def show_small_images(self):
        pet_x = self.pet_label.winfo_x()
        pet_y = self.pet_label.winfo_y()
        center_x = pet_x + self.pet_width // 2
        center_y = pet_y

        num_images = len(self.small_labels)
        radius = 55  # Adjust this value to change the size of the arc
        start_angle = -math.pi  # Start from the top
        angle_step = math.pi / (num_images - 1)  # Distribute evenly across the top half

        for i, label in enumerate(self.small_labels):
            angle = start_angle + i * angle_step
            x = center_x + int(radius * math.cos(angle)) - 20  # 20 is half the width of small images
            y = center_y + int(radius * math.sin(angle)) + 100
            label.place(x=x, y=y)

    def hide_small_images(self):
        self.stop_walk = False
        for label in self.small_labels:
            label.place_forget()

    def on_small_image_click(self, event):
        if event.widget == self.small_labels[0]:  # Middle right image
            self.pop_up_todo()
        if event.widget == self.small_labels[1]:  # Image 2
            self.pop_up_shop()

    

    def pop_up_shop(self):
        shop_window = tk.Toplevel(self.root)
        shop_window.title("Oski's Shop")
        shop_window.geometry("800x600")
        shop_window.configure(bg='#F0F0F0')

        e
[truncated — 5965 more characters]
```

### vedantsedits.py

```python
import math
import tkinter as tk
from tkinter import simpledialog, messagebox
from tkinter import Tk, Button, PhotoImage
from tkinter import Checkbutton, IntVar
from PIL import Image, ImageTk
import random
import json
import os

balance = 0

class DesktopPetWithPopup:
    def __init__(self, root, window_size=(1200, 800)):
        self.root = root
        self.root.title("Desktop Pet")
        self.root.geometry(f"{window_size[0]}x{window_size[1]}")

        self.stationary_image_path = "pngs/oski front facing.png"
        self.right_animation = ["pngs/right1.png", "pngs/right2.png"]
        self.left_animation = ["pngs/left1.png", "pngs/left2.png"]

        self.pet_image, self.pet_width, self.pet_height = self.resize(self.stationary_image_path, 200, 200)
        self.pet_label = tk.Label(self.root, image=self.pet_image)
        self.position_pet()

        self.stop_walk = False
        self.walk_after_id = None
        self.current_animation = None
        self.animation_frame = 0

        self.pet_label.bind("<Enter>", self.on_mouse_enter)
        self.pet_label.bind("<Leave>", self.on_mouse_leave)

        # Load and create small images
        self.small_images = []
        self.small_labels = []
        for i in range(5):
            img, _, _ = self.resize("pngs/blank_bubble.png", 30, 30)
            self.small_images.append(img)
            label = tk.Label(self.root, image=img)
            label.bind("<Button-1>", self.on_small_image_click)
            self.small_labels.append(label)

        # Load todo list from file
        self.todo_list = self.load_todo_list()

        # Bind the window resize event
        self.root.bind("<Configure>", self.on_window_resize)

        # Initialize balance
        self.balance = self.load_balance()

    def position_pet(self):
        window_height = self.root.winfo_height()
        current_x = self.pet_label.winfo_x()
        pet_y = window_height - self.pet_height
        self.pet_label.place(x=current_x, y=pet_y)

    def on_window_resize(self, event):
        self.position_pet()

    @staticmethod
    def resize(image_path, width, height):
        img = Image.open(image_path)
        img_resized = img.resize((width, height))
        return ImageTk.PhotoImage(img_resized), width, height

    def pet_walk(self):
        if not self.stop_walk:
            current_x = self.pet_label.winfo_x()
            window_width = self.root.winfo_width()
            target_lower = max(current_x - 300, 0)
            target_upper = min(current_x + 300, window_width - self.pet_width)
            target_x = random.randint(target_lower, target_upper)
            
            step_size = 2

            def move_step():
                nonlocal current_x
                if current_x > target_x:
                    current_x -= step_size
                    self.current_animation = self.left_animation
                elif current_x < target_x:
                    current_x += step_size
                    self.current_animation = self.right_animation
                else:
                    self.current_animation = None

                self.position_pet()  # Update y-position
                self.pet_label.place(x=current_x)
                
                if self.current_animation:
                    self.animate_pet()
                
                if abs(current_x - target_x) > step_size:
                    self.walk_after_id = self.root.after(100, move_step)
                else:
                    self.current_animation = None
                    self.update_pet_image(self.stationary_image_path)
                    self.walk_after_id = self.root.after(random.randint(1000, 4000), self.pet_walk)

            move_step()

    def animate_pet(self):
        if self.current_animation:
            self.animation_frame = (self.animation_frame + 1) % len(self.current_animation)
            self.update_pet_image(self.current_animation[self.animation_frame])

    def update_pet_image(self, image_path):
        new_image, _, _ = self.resize(image_path, 200, 200)
        self.pet_label.configure(image=new_image)
        self.pet_label.image = new_image

    def on_mouse_enter(self, event):
        self.stop_walk = True
        if self.walk_after_id is not None:
            self.root.after_cancel(self.walk_after_id)
            self.walk_after_id = None
        self.show_small_images()

    def on_mouse_leave(self, event):
        self.stop_walk = False
        if self.walk_after_id is None:
            self.pet_walk()
        self.hide_small_images()

    def show_small_images(self):
        pet_x = self.pet_label.winfo_x()
        pet_y = self.pet_label.winfo_y()
        center_x = pet_x + self.pet_width // 2
        center_y = pet_y

        num_images = len(self.small_labels)
        radius = 55  # Adjust this value to change the size of the arc
        start_angle = -math.pi  # Start from the top
        angle_step = math.pi / (num_images - 1)  # Distribute evenly across the top half

        for i, label in enumerate(self.small_labels):
            angle = start_angle + i * angle_step
            x = center_x + int(radius * math.cos(angle)) - 20  # 20 is half the width of small images
            y = center_y + int(radius * math.sin(angle)) + 50
            label.place(x=x, y=y)

    def hide_small_images(self):
        self.stop_walk = False
        for label in self.small_labels:
            label.place_forget()

    def on_small_image_click(self, event):
        if event.widget == self.small_labels[0]:  # Middle right image
            self.pop_up_todo()
        if event.widget == self.small_labels[1]:  # Image 2
            self.pop_up_shop()

    def setup_google_calendar(self):
        creds = None
        if os.path.exists('token.json'):
            creds = Credentials.from_authorized_user_file('token.json', SCOPES)
        if not creds or not creds.valid:
            if creds and creds.expired and creds.refresh_token:
                creds.refres
[truncated — 8251 more characters]
```