# Project export: booksy

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: TreeHacks 2025
- Tagline: Stories built together, memories cherished forever.
- Devpost: https://devpost.com/software/booksy
- GitHub: https://github.com/gigabite-pro/treehacks-25
- Video: https://www.youtube.com/embed/rNGf3JaDF5w?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 2 GitHub contributor(s) — Oorjit Chowdhary (8 commits), Vaibhav (7 commits)

## Devpost submission (written by the team)

### Inspiration

💡 40–60% of parents feel they don’t spend enough time with their children, and the average family manages just 6 precious hours together each week. This isn’t just a statistic: it’s a missed opportunity for connection, learning, and shared joy. Research shows that meaningful parent-child interactions foster crucial parts of child development, including emotional development, academic success, and long-term well-being. Yet, between work, school, and digital distractions, family time often slips through the cracks. We believe that storytelling is one of the most powerful ways to bond across generations. How could we help families turn limited time together into collaborative, creative storytelling experiences? That’s why we created booksy - an AI-powered storytelling platform that allows families to co-create interactive storybooks together, blending AI-generated narratives, illustrations, and personal video recordings.

### What it does

📖 Introducing booksy: Stories built together, memories cherished forever. booksy redefines family storytelling by combining AI-powered story generation, interactive decision-making, and multimedia preservation. booksy integrates three different forms of media real-time: text, image, and voice, transforming it into an interactive, real-time storytelling experience. (the demo video in this submission has been sped up to be under the time limit.) Families can: 📚 Create personalized storybooks – Choose a genre and co-create with your loved ones and AI to generate unique children’s stories that are illustrated, narrated, and generated in real-time. 🎭 Shape the narrative together – Engage in a choose-your-own-adventure format where parents and children make decisions that influence the storyline. 📰 Relive the magic – Experience an AI-narrated playback that combines the story, illustrations, and family-recorded audios into a unique digital time capsule. booksy isn’t just about reading stories – it’s about creating them together, making storytelling a shared experience that brings families closer together.

### How we built it

🛠️ booksy is built with handcrafted design and AI to create an intuitive, immersive, and magical storytelling experience. Design Approach Every aspect of booksy, from assets and animations to UI elements and backgrounds, was designed from scratch. We started with sketching user flows to ensure a seamless user experience, and then developed our vector-based art using Figma and Linearity. We focused on three key design principles: 🎨 Creativity: Making the platform visually engaging and fun for children. 🧩 Accessibility – Crafting a simple, child-friendly UI that is intuitive and easy to navigate. 🚀 Immersion – Bringing booksy to life with an interactive, personality-driven mascot and fluid transitions that make storytelling feel magical. Technical Implementation booksy is a single-page web app, built with React and powered by a Node.js server. Some key parts of our technical implementation include: 📖 AI-Powered Storytelling – We leverage Groq-hosted Llama-70B for lightning-fast, real-time story generation, adapting to user choices instantly. 🎨 Dynamic Illustrations – Each story’s visuals are uniquely crafted using LumaLabs’ Photon image generation model, making every book a one-of-a-kind creation. 🐭 Sassy AI Narration – Our mascot, booksy the mouse, is voiced using ElevenLabs’ custom voice model, bringing a playful and engaging narration to life. 📚 Effortless Book Management – We use Supabase’s database and object storage to keep track of every story created, ensuring families can revisit their cherished tales anytime. 🔐 Secure Authentication – Auth0 handles sign-in and sign-up, providing a frictionless onboarding experience for users. By seamlessly integrating text, illustrations, and voice in real-time, booksy transforms passive reading into an interactive, co-created experience—making every story feel personal, magical, and memorable. 🚀📖

### Challenges we ran into

On the technical side, the core challenge we faced was minimizing application load times as we needed to generate multimodal elements (story text, accompanying illustrations, and our booksy narrator) in real-time. Another challenge was keeping every new dynamically created page linked with the previous pages of a book. (Think: a linked listed with no previous pointer) For minimizing load times and latency, we relied on the ultra-fast Groq inference for Llama-70B and parallel processed creating the booksy’s voice and accompanying illustrations. For keeping pages linked to each other, we generated a custom UUID for each new book and kept passing this token between the server and the frontend to continue creating new story pages. A challenge we experienced on the UI/UX side was crafting a user interface that would resonate with both parents and children while maintaining intuitive functionality. Creating an experience that feels magical and engaging for a child, yet remains practical and navigable for adults, requires careful consideration. We wanted to prioritize playful elements without overwhelming the core storytelling experience. We ultimately achieved this balance through a mascot-guided interface and a familiar digital bookshelf element.

### Accomplishments we're proud of

We're proud of how our diverse team of first-time and experienced hackers came together to create something special. Our Stanford first-timers brought fresh perspectives that complemented the technical expertise of our seasoned hackers from UBC and UW, leading to an application that exceeded our initial vision and turned into a project that we could all walk away proud of. The design team crafted an interface that perfectly balances whimsy with functionality. On the technical side, we successfully implemented real-time processing of three different types of media - generating text narratives, creating images, and producing voice output - all while maintaining a smooth user experience. Perhaps most importantly, we're proud of creating a platform that doesn't just tell stories, but helps families create and preserve meaningful moments together.

### What we learned

We quickly learned that effective communication was a powerful tool, being clear and honest about our vision while remaining realistic about what we could accomplish in the hackathon timeframe. Our design team discovered the importance of being responsive, constantly adjusting our UI/UX priorities based on real-time development progress.

### What's next

Our primary focus is expanding the platform's collaborative features, enabling extended family members to become involved in a story's narrative. We would plan on integrating video calling capabilities, ensuring that distance never stands in the way of storytime. We're also excited about incorporating more interactive elements and diverse genres, while giving our beloved mascot, booksy the mouse, a more prominent role as an engaging guide through the app's features. Another idea we are excited about is having parents share their own childhood memories and experiences, transforming them into personalized stories that create deeper connections.

## README (from the GitHub repository)

## Inspiration 💡

**40–60% of parents feel they don’t spend enough time with their children**, and the average family manages **just 6 precious hours** together each week.

This isn’t just a statistic: it’s a **missed opportunity for connection, learning, and shared joy.** Research shows that meaningful parent-child interactions foster crucial parts of child development, including **emotional development, academic success, and long-term well-being**. Yet, between work, school, and digital distractions, family time often slips through the cracks.

We believe that storytelling is one of the most powerful ways to bond across generations. _How could we help families turn limited time together into collaborative, creative storytelling experiences?_

That’s why we created **booksy** - an **AI-powered storytelling platform** that allows families to **co-create interactive storybooks** together, blending AI-generated narratives, illustrations, and personal video recordings. 


## What it does 📖

Introducing **booksy**: _Stories built together, memories cherished forever._ booksy redefines family storytelling by combining AI-powered story generation, interactive decision-making, and multimedia preservation.

booksy integrates three different forms of media **real-time**: text, image, and voice, transforming it into an interactive, real-time storytelling experience.

(the demo video in this submission has been sped up to be under the time limit.)

Families can:

📚 **Create personalized storybooks** – Choose a genre and co-create with your loved ones and AI to generate unique children’s stories that are illustrated, narrated, and generated in real-time.

🎭 **Shape the narrative together** – Engage in a choose-your-own-adventure format where parents and children make decisions that influence the storyline.

📰 **Relive the magic** – Experience an AI-narrated playback that combines the story, illustrations, and family-recorded audios into a unique digital time capsule.

booksy isn’t just about reading stories – it’s about creating them together, making **storytelling a shared experience** that brings families closer together.

## How we built it 🛠️
booksy is built with **handcrafted design and AI** to create an intuitive, immersive, and magical storytelling experience.

**Design Approach**
Every aspect of booksy, from assets and animations to UI elements and backgrounds, was **designed from scratch**. We started with sketching user flows to ensure a seamless user experience, and then developed our vector-based art using Figma and Linearity.

We focused on three key design principles:

🎨 **Creativity**: Making the platform visually engaging and fun for children.

🧩 **Accessibility** – Crafting a simple, child-friendly UI that is intuitive and easy to navigate.

🚀 **Immersion** – Bringing booksy to life with an interactive, personality-driven mascot and fluid transitions that make storytelling feel magical.

**Technical Implementation**
booksy is a single-page web app, built with React and powered by a Node.js server. Some key parts of our technical implementation include:

📖 **AI-Powered Storytelling** – We leverage Groq-hosted Llama-70B for lightning-fast, real-time story generation, adapting to user choices instantly.

🎨 **Dynamic Illustrations** – Each story’s visuals are uniquely crafted using LumaLabs’ Photon image generation model, making every book a one-of-a-kind creation.

🐭 **Sassy AI Narration** – Our mascot, booksy the mouse, is voiced using ElevenLabs’ custom voice model, bringing a playful and engaging narration to life.

📚 **Effortless Book Management** – We use Supabase’s database and object storage to keep track of every story created, ensuring families can revisit their cherished tales anytime.

🔐 Secure Authentication – Auth0 handles sign-in and sign-up, providing a frictionless onboarding experience for users.

By seamlessly integrating text, illustrations, and voice in real-time, booksy transforms passive reading into an interactive, co-created experience—making every story feel personal, magical, and memorable. 🚀📖

## Challenges we ran into

On the technical side, the core challenge we faced was minimizing application load times as we needed to generate multimodal elements (story text, accompanying illustrations, and our booksy narrator) in real-time. Another challenge was keeping every new dynamically created page linked with the previous pages of a book. (Think: a linked listed with no previous pointer) For minimizing load times and latency, we relied on the ultra-fast Groq inference for Llama-70B and parallel processed creating the booksy’s voice and accompanying illustrations. For keeping pages linked to each other, we generated a custom UUID for each new book and kept passing this token between the server and the frontend to continue creating new story pages.

A challenge we experienced on the UI/UX side was crafting a user interface that would resonate with both parents and children while maintaining intuitive functionality. Creating an experience that feels magical and engaging for a child, yet remains practical and navigable for adults, requires careful consideration. We wanted to prioritize playful elements without overwhelming the core storytelling experience. We ultimately achieved this balance through a mascot-guided interface and a familiar digital bookshelf element. 

## Accomplishments that we're proud of

We're proud of how our diverse team of first-time and experienced hackers came together to create something special. Our Stanford first-timers brought fresh perspectives that complemented the technical expertise of our seasoned hackers from UBC and UW, leading to an application that exceeded our initial vision and turned into a project that we could all walk away proud of. The design team crafted an interface that perfectly balances whimsy with functionality. On the technical side, we successfully implemented real-time processing of three different types of media - generating text narratives, creating images, and producing voice output - all while maintaining a smooth user experience. Perhaps most importantly, we're proud of creating a platform that doesn't just tell stories, but helps families create and preserve meaningful moments together. 

## What we learned

We quickly learned that effective communication was a powerful tool, being clear and honest about our vision while remaining realistic about what we could accomplish in the hackathon timeframe. Our design team discovered the importance of being responsive, constantly adjusting our UI/UX priorities based on real-time development progress. 

## What's next for booksy

Our primary focus is expanding the platform's collaborative features, enabling extended family members to become involved in a story's narrative. We would plan on integrating video calling capabilities, ensuring that distance never stands in the way of storytime. 

We're also excited about incorporating more interactive elements and diverse genres, while giving our beloved mascot, booksy the mouse, a more prominent role as an engaging guide through the app's features. 

Another idea we are excited about is having parents share their own childhood memories and experiences, transforming them into personalized stories that create deeper connections. 


## Detected evidence (automated analysis)

Indexed codebase: 22 recognized source files, 47 KB.
- CSS (language) — detected in the code
- Express (technology) — detected in the code
- HTML (language) — detected in the code
- JavaScript (language) — detected in the code
- React (technology) — detected in the code
- Supabase (technology) — detected in the code

## Codebase structure (from repository index)

### Files (26 of 26)

```
.gitignore
frontend/.gitignore
frontend/eslint.config.js
frontend/index.html
frontend/package.json
frontend/README.md
frontend/src/App.jsx
frontend/src/components/Background.jsx
frontend/src/components/Book.jsx
frontend/src/components/BookSelect.jsx
frontend/src/components/CreateNew.jsx
frontend/src/components/Dashboard.jsx
frontend/src/components/LoginButton.jsx
frontend/src/components/LogoutButton.jsx
frontend/src/components/Modal.jsx
frontend/src/components/Share.jsx
frontend/src/components/WavingMouse.jsx
frontend/src/index.css
frontend/src/main.jsx
frontend/vite.config.js
README.md
server/app.js
server/package.json
server/routes/api.js
server/utils/chroma.js
server/utils/supabase.js
```

### Dependencies

- frontend/package.json: @auth0/auth0-react@^2.3.0, @eslint/js@^9.19.0, @gsap/react@^2.1.2, @types/react@^19.0.8, @types/react-dom@^19.0.3, @vitejs/plugin-react@^4.3.4, eslint@^9.19.0, eslint-plugin-react@^7.37.4, eslint-plugin-react-hooks@^5.0.0, eslint-plugin-react-refresh@^0.4.18, globals@^15.14.0, groq-sdk@^0.15.0, gsap@^3.12.7, motion@^12.4.3, react@^19.0.0, react-dom@^19.0.0, react-mic@^12.4.6, react-pageflip@^2.0.3, react-router-dom@^7.1.5, use-sound@^4.0.3, vite@^6.1.0
- server/package.json: @supabase/supabase-js@^2.48.1, axios@^1.7.9, chromadb@^1.10.4, chromadb-default-embed@^2.13.2, cors@^2.8.5, dotenv@^16.4.7, elevenlabs@^1.51.0, express@^4.21.2, groq-sdk@^0.15.0, lumaai@^1.4.0, nodemon@^3.1.9, uuid@^11.0.5

### Recent commits (newest first)

- Update README.md
- final
- ui list, share, story continuation
- book page
- render portrait image
- prompt engineered ready to go
- next page logic almost done + some cleanup
- create new story
- landing and animations
- dashboard, modal, isAuthenticated
- lumalabs images
- elevenlabs and supabase bucket
- add groq api
- init node (#1)
- init, auth
- Initial commit

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

### server/package.json

```
{
  "name": "server",
  "version": "1.0.0",
  "description": "",
  "main": "app.js",
  "scripts": {
    "start": "node app.js",
    "dev": "nodemon app.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@supabase/supabase-js": "^2.48.1",
    "axios": "^1.7.9",
    "chromadb": "^1.10.4",
    "chromadb-default-embed": "^2.13.2",
    "cors": "^2.8.5",
    "dotenv": "^16.4.7",
    "elevenlabs": "^1.51.0",
    "express": "^4.21.2",
    "groq-sdk": "^0.15.0",
    "lumaai": "^1.4.0",
    "uuid": "^11.0.5"
  },
  "devDependencies": {
    "nodemon": "^3.1.9"
  }
}

```

### frontend/package.json

```
{
  "name": "frontend",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "lint": "eslint .",
    "preview": "vite preview"
  },
  "dependencies": {
    "@auth0/auth0-react": "^2.3.0",
    "@gsap/react": "^2.1.2",
    "groq-sdk": "^0.15.0",
    "gsap": "^3.12.7",
    "motion": "^12.4.3",
    "react": "^19.0.0",
    "react-dom": "^19.0.0",
    "react-mic": "^12.4.6",
    "react-pageflip": "^2.0.3",
    "react-router-dom": "^7.1.5",
    "use-sound": "^4.0.3"
  },
  "devDependencies": {
    "@eslint/js": "^9.19.0",
    "@types/react": "^19.0.8",
    "@types/react-dom": "^19.0.3",
    "@vitejs/plugin-react": "^4.3.4",
    "eslint": "^9.19.0",
    "eslint-plugin-react": "^7.37.4",
    "eslint-plugin-react-hooks": "^5.0.0",
    "eslint-plugin-react-refresh": "^0.4.18",
    "globals": "^15.14.0",
    "vite": "^6.1.0"
  }
}

```

### server/app.js

```javascript
const express = require("express");
const path = require("path");
const cors = require("cors");
const { v4: uuidv4 } = require("uuid");

require("dotenv").config();

const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, "public")));
app.use(cors());

app.get("/", (req, res) => {
    res.send("hello from booksy!");
});

const supabase = require("./utils/supabase");
const axios = require("axios");

app.get("/login", async (req, res) => {
    const { email, name } = req.query;

    const { data, error } = await supabase.from("users").insert({ email: email, name: name }).select();

    if (error) {
        console.error("Error adding user:", error);
        return res.status(500).json({ error: "Failed to add user" });
    }

    res.json({ message: "User added successfully" });
});

// new creates a Page instance (with groq, lumalabs, elevenlabs)
// Page instance has metadata (book-uuid)
app.get("/new", async (req, res) => {
    const { genre } = req.query;

    const email = "abc@xyz.com";

    // generate story
    const groqPrompt = `Tell me a ${genre} story!`;
    console.log(`${req.protocol}://${req.get("host")}/api/story?prompt=${encodeURIComponent(groqPrompt)}`);
    const groqResponse = await axios.get(`${req.protocol}://${req.get("host")}/api/story?prompt=${encodeURIComponent(groqPrompt)}`);
    let groqJson = await groqResponse.data.choices[0].message.content;
    let context = await groqResponse.data.codingContext;
    groqJson = JSON.parse(groqJson);
    console.log(groqJson);
    // console.log("context", context);

    // TODO on api.js: prompt engineer to make it into a 2 person narration and randomly ask user for next input

    try {
        // parallel process image and voiceover
        const [lumaResponse, elevenResponse] = await Promise.all([
            axios.get(`${req.protocol}://${req.get("host")}/api/image?prompt=${encodeURIComponent(groqJson.story)}`),
            axios.get(`${req.protocol}://${req.get("host")}/api/voice?text=${encodeURIComponent(groqJson.story)}`),
        ]);

        const lumaJson = await lumaResponse.data.url;
        const elevenJson = await elevenResponse.data.url;

        const bookId = `book-${uuidv4()}`;
        const pages = [];
        pages.push({
            text: groqJson.story,
            image_url: lumaJson,
            voice_url: elevenJson,
            pause_for_input: groqJson.pause_for_input,
        });

        // push to supabase
        const { data, error } = await supabase.from("pages").insert({
            book_id: bookId,
            text: groqJson.story,
            image_url: lumaJson,
            voice_url: elevenJson,
            title: groqJson.title,
            user_id: email,
            context: context,
            pages: pages,
            genre: genre,
        });

        if (error) {
            console.error("Error adding page:", error);
            return res.status(500).json({ error: "Failed to add page" });
        }

        return res.json({
            story: groqJson.story,
            pause_for_input: groqJson.pause_for_input,
            book_id: bookId,
            image: lumaJson,
            voice: elevenJson,
            title: groqJson.title,
            message: "Page generated successfully",
        });
    } catch (error) {
        console.error("Error generating page:", error);
        return res.status(500).json({ error: "Failed to generate page" });
    }
});

app.get("/next", async (req, res) => {
    const { book_id, prompt } = req.query;

    const email = "abc@xyz.com";
    console.log("book_id", book_id);

    // get past context from supabase
    const { data: pagesData, error } = await supabase.from("pages").select().eq("book_id", book_id);
    if (error) {
        console.error("Error fetching pages:", error);
        return res.status(500).json({ error: "Failed to fetch pages" });
    }

    console.log(pagesData);
    const pastContext = pagesData[0].context;
    // console.log("past-context", pastContext);
    const pages = pagesData[0].pages;
    const groqResponse = await axios.get(`${req.protocol}://${req.get("host")}/api/story?prompt=${prompt}&context=${JSON.stringify(pastContext)}`);
    let groqJson = await groqResponse.data.choices[0].message.content;
    let context = await groqResponse.data.codingContext;
    groqJson = JSON.parse(groqJson);

    console.log(groqJson);
    console.log("new-context", context);

    try {
        // parallel process image and voiceover
        const [lumaResponse, elevenResponse] = await Promise.all([
            axios.get(`${req.protocol}://${req.get("host")}/api/image?prompt=${encodeURIComponent(groqJson.story)}`),
            axios.get(`${req.protocol}://${req.get("host")}/api/voice?text=${encodeURIComponent(groqJson.story)}`),
        ]);

        const lumaJson = await lumaResponse.data.url;
        console.log(lumaJson);
        const elevenJson = await elevenResponse.data.url;
        console.log(elevenJson);

        const newPages = [
            ...pages,
            {
                text: groqJson.story,
                image_url: lumaJson,
                voice_url: elevenJson,
                pause_for_input: groqJson.pause_for_input,
            },
        ];

        // update supabase
        const { data, error } = await supabase
            .from("pages")
            .update({
                context: context,
                pages: newPages,
            })
            .eq("book_id", book_id);
        // const { data, error } = await supabase.from("pages").insert({
        //     book_id: book_id,
        //     text: groqJson.story,
        //     image_url: lumaJson,
        //     voice_url: elevenJson,
        //     context: context,
        // });

        if (error) {
            console.error("Error adding page:", error);
            return res.status(500).json({ error: "Failed to add page" });
        }

        return
[truncated — 1085 more characters]
```

### frontend/src/main.jsx

```javascript
import { createRoot } from "react-dom/client";
import "./index.css";
import { Auth0Provider } from "@auth0/auth0-react";
import { createBrowserRouter, RouterProvider } from "react-router-dom";
import App from "./App.jsx";
import Dashboard from "./components/Dashboard.jsx";
import Book from "./components/Book.jsx";
import Share from "./components/Share.jsx";

const router = createBrowserRouter([
    {
        exact: true,
        path: "/",
        element: <App />,
    },
    {
        exact: true,
        path: "/dashboard",
        element: <Dashboard />,
    },
    {
        path: "/book",
        element: <Book />,
    },
    {
        path: "/share",
        element: <Share />,
    },
]);

const rootElement = document.getElementById("root");
const root = createRoot(rootElement);

root.render(
    <Auth0Provider
        domain="dev-3eayae31z7ls84il.ca.auth0.com"
        clientId="r5LroNz0mqWWemrNxxos1ypAZLTXi2ZM"
        authorizationParams={{
            redirect_uri: "http://localhost:5173/dashboard",
        }}
    >
        <RouterProvider router={router} />
    </Auth0Provider>
);

```

### frontend/src/App.jsx

```javascript
/* eslint-disable react/prop-types */
import { motion } from "motion/react";
import { useEffect, useRef } from "react";
import { preload } from "react-dom";
import useSound from "use-sound";
import gsap from "gsap";
import { useGSAP } from "@gsap/react";

gsap.registerPlugin(useGSAP);

function App() {
    preload("./src/assets/landing_open.png");
    const bgMusic = "./bg_music.mp3";
    const doorSound = "./door.mp3";
    const transitionSound = "./transition.mp3";
    const doorRef = useRef(null);
    const containerRef = useRef(null);
    const [play, { pause }] = useSound(bgMusic, {
        volume: 0.6,
    });
    const [doorPlay] = useSound(doorSound, {
        volume: 1,
    });
    const [transitionPlay] = useSound(transitionSound, {
        volume: 1,
    });

    useEffect(() => {
        play();
        return () => {
            pause();
        };
    });

    function playDoorSound() {
        pause();
        gsap.to(doorRef.current, {
            duration: 0.7,
            scaleX: 0.6,
            x: -50,
            rotate: -5,
        });
        doorPlay();
        transitionPlay();
        gsap.to(containerRef.current, {
            delay: 0.7,
            duration: 5.1,
            scale: 15,
            opacity: 0,
            ease: "power2.in",
            onComplete: () => {
                window.location.href = "/dashboard";
            },
        });
    }

    return (
        <div ref={containerRef} className="container">
            <div className="landing-main"></div>
            <motion.div whileHover={{ scale: 1.1 }} whileTap={{ scale: 0.8 }} onClick={playDoorSound} className="enter-btn"></motion.div>
            <div ref={doorRef} className="door"></div>
        </div>
    );
}

export default App;

```

### frontend/vite.config.js

```javascript
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

// https://vite.dev/config/
export default defineConfig({
  plugins: [react()],
})

```

### frontend/index.html

```html
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <link rel="icon" type="image/png" href="/mouse.png" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>Booksy</title>
    </head>
    <body>
        <div id="root"></div>
        <script type="module" src="/src/main.jsx"></script>
    </body>
</html>

```

### frontend/eslint.config.js

```javascript
import js from '@eslint/js'
import globals from 'globals'
import react from 'eslint-plugin-react'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'

export default [
  { ignores: ['dist'] },
  {
    files: ['**/*.{js,jsx}'],
    languageOptions: {
      ecmaVersion: 2020,
      globals: globals.browser,
      parserOptions: {
        ecmaVersion: 'latest',
        ecmaFeatures: { jsx: true },
        sourceType: 'module',
      },
    },
    settings: { react: { version: '18.3' } },
    plugins: {
      react,
      'react-hooks': reactHooks,
      'react-refresh': reactRefresh,
    },
    rules: {
      ...js.configs.recommended.rules,
      ...react.configs.recommended.rules,
      ...react.configs['jsx-runtime'].rules,
      ...reactHooks.configs.recommended.rules,
      'react/jsx-no-target-blank': 'off',
      'react-refresh/only-export-components': [
        'warn',
        { allowConstantExport: true },
      ],
    },
  },
]

```

### server/utils/supabase.js

```javascript
const { createClient: createSupabaseClient } = require('@supabase/supabase-js');

const supabase = createSupabaseClient(process.env.SUPABASE_URL, process.env.SUPABASE_SERVICE_KEY);

module.exports = supabase;

```

### server/utils/chroma.js

```javascript
const { ChromaClient } = require('chromadb');

const chroma = new ChromaClient({
    path: "https://api.trychroma.com:8000",
    auth: { provider: "token", credentials: process.env.CHROMA_TOKEN, tokenHeaderType: "X_CHROMA_TOKEN" },
    tenant: process.env.CHROMA_TENANT,
    database: 'treehacks-25'
});

module.exports = chroma;

```

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