# Project export: PantryPilot

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 2026
- Tagline: Recipes or utube videos can’t see your pan. When heat, timing, or texture feel wrong, cooking becomes guesswork. My system watches the process and gives real time guidance for more confident results.
- Devpost: https://devpost.com/software/pantrypilot-94jzqa
- GitHub: https://github.com/Akash1912-hub/tree-hacks
- Demo: https://drive.google.com/drive/folders/1fwQC6aRqOZwvJZ11TzTpnzzTEGiIylmT
- Team: 1 GitHub contributor(s) — Akash1912-hub (1 commits)

## Devpost submission (written by the team)

### Inspiration

Cooking and meal planning can be stressful for many reasons. People often watch YouTube videos or follow random online recipes, only to realize they don’t have the right ingredients or that the recipes are too complex or time-consuming. Pantry items are forgotten or go unused, leading to wasted TIME and wasted INGREDIENTS. Many users struggle with deciding what to cook each day, planning balanced meals, or even tracking what’s already in their pantry. These issues create frustration, increase food waste, and make daily meal planning overwhelming. We wanted to solve these problems by making a tool that helps users cook smarter, plan meals efficiently, and make the most of the ingredients they already have. That’s how PantryPilot came to life a vision-powered cooking assistant designed to help people manage their pantry and meals without the stress, save What It Does PantryPilot looks at your pantry using computer vision and figures out what ingredients you have. Then, it suggests recipes you can actually make. You can tell it your dietary preferences, how much time you have, or what type of meal you want, and it gives you personalized meal plans, shopping lists, and ingredient substitutions. Basically, it helps you save food, save money, and cook more confidently. How We Built It We built PantryPilot as a full-stack platform: Frontend: React + Tailwind CSS for a clean and interactive UI. Backend: Flask + Python handles ingredient recognition and recipe suggestions. Machine Learning: A computer vision model detects pantry items and their amounts. A simple recommendation engine matches your ingredients to recipes. A computer vision model detects pantry items and their amounts. A simple recommendation engine matches your ingredients to recipes. Database: Firebase stores pantry data, user preferences, and recipe history. It took a few tries to get the dashboard right, but now it shows real-time recipe suggestions and meal planning summaries clearly. Challenges We Faced One tricky part was teaching the system to recognize ingredients under different lighting. Another challenge was making the recommendations feel useful and not overwhelming. Finally, designing the UI to be simple but informative required some trial and error. Accomplishments During the hackathon, we managed to: Build a working platform that scans pantries and suggests recipes. Make a recommendation engine that adapts to what ingredients are available. Create dashboards showing recipes, shopping lists, and substitutions. Help users reduce food waste, save money, and plan meals faster. What We Learned We learned that small design tweaks can make a big difference in usability. Also, combining computer vision with live recipe suggestions needs careful attention to speed and accuracy. We realized that showing alternatives and substitutions makes users trust the system more. What’s Next Next, we want to add more ingredients, introduce voice guidance, and make a mobile app. We also plan to send smart reminders for expiring ingredients or missing items. Ultimately, we hope PantryPilot becomes a friendly AI companion in every kitchen.

## README (from the GitHub repository)

# React + Vite

This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.

Currently, two official plugins are available:

- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) (or [oxc](https://oxc.rs) when used in [rolldown-vite](https://vite.dev/guide/rolldown)) for Fast Refresh
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh

## React Compiler

The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).

## Expanding the ESLint configuration

If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project.


## Detected evidence (automated analysis)

Indexed codebase: 18 recognized source files, 89 KB.
- CSS (language) — detected in the code
- HTML (language) — detected in the code
- JavaScript (language) — detected in the code
- React (technology) — detected in the code
- Tailwind CSS (technology) — detected in the code
- Firebase (technology) — claimed on Devpost, not found in the code
- Flask (technology) — claimed on Devpost, not found in the code
- Python (language) — claimed on Devpost, not found in the code
- TensorFlow (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (20 of 20)

```
.gitignore
eslint.config.js
index.html
package.json
README.md
src/App.jsx
src/components/Demo.jsx
src/components/EverydayDishes.jsx
src/components/Features.jsx
src/components/Footer.jsx
src/components/Hero.jsx
src/components/Navbar.jsx
src/components/Preorder.jsx
src/components/ui/Aurora.jsx
src/components/ui/BlurText.jsx
src/components/ui/LiquidEther.css
src/components/ui/LiquidEther.jsx
src/index.css
src/main.jsx
vite.config.js
```

### Dependencies

- package.json: @eslint/js@^9.39.1, @tailwindcss/vite@^4.1.18, @types/react@^19.2.7, @types/react-dom@^19.2.3, @vitejs/plugin-react@^5.1.1, autoprefixer@^10.4.24, eslint@^9.39.1, eslint-plugin-react-hooks@^7.0.1, eslint-plugin-react-refresh@^0.4.24, globals@^16.5.0, lucide-react@^0.564.0, postcss@^8.5.6, react@^19.2.0, react-dom@^19.2.0, tailwindcss@^4.1.18, three@^0.182.0, vite@^7.3.1

### Recent commits (newest first)

- fixed the entire frontend
- fix: navbar
- fix:background
- Fix: frontend
- Initial commit of PantryPilot website

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

### package.json

```
{
  "name": "temp_app",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "lint": "eslint .",
    "preview": "vite preview"
  },
  "dependencies": {
    "lucide-react": "^0.564.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "three": "^0.182.0"
  },
  "devDependencies": {
    "@eslint/js": "^9.39.1",
    "@tailwindcss/vite": "^4.1.18",
    "@types/react": "^19.2.7",
    "@types/react-dom": "^19.2.3",
    "@vitejs/plugin-react": "^5.1.1",
    "autoprefixer": "^10.4.24",
    "eslint": "^9.39.1",
    "eslint-plugin-react-hooks": "^7.0.1",
    "eslint-plugin-react-refresh": "^0.4.24",
    "globals": "^16.5.0",
    "postcss": "^8.5.6",
    "tailwindcss": "^4.1.18",
    "vite": "^7.3.1"
  }
}

```

### src/main.jsx

```javascript
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import App from './App.jsx'

createRoot(document.getElementById('root')).render(
  <StrictMode>
    <App />
  </StrictMode>,
)

```

### src/App.jsx

```javascript
import Navbar from './components/Navbar'
import Hero from './components/Hero'
import Features from './components/Features'
import Demo from './components/Demo'
import EverydayDishes from './components/EverydayDishes'
import Preorder from './components/Preorder'
import Footer from './components/Footer'
import LiquidEther from './components/ui/LiquidEther'

function App() {
  return (
    <div className="relative min-h-screen font-sans text-slate-800 bg-[#fbfbf9]">
      {/* Fluid Background */}
      <div className="fixed inset-0 z-0 opacity-40 pointer-events-none">
        <LiquidEther
          colors={["#d76609", "#da5a16", "#e16d0e"]}
          mouseForce={20}
          cursorSize={100}
          isViscous
          viscous={30}
          iterationsViscous={32}
          iterationsPoisson={32}
          resolution={0.5}
          isBounce={false}
          autoDemo
          autoSpeed={0.5}
          autoIntensity={2.2}
          takeoverDuration={0.25}
          autoResumeDelay={3000}
          autoRampDuration={0.6}
        />
      </div>

      {/* Main Content */}
      <div className="relative z-10">
        <Navbar />
        <Hero />
        <Features />
        <Demo />
        <EverydayDishes />
        <Preorder />
        <Footer />
      </div>
    </div>
  )
}

export default App

```

### vite.config.js

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

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

```

### index.html

```html
<!doctype html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <link rel="icon" type="image/svg+xml" href="https://lucide.dev/favicon.ico" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
  <link href="https://fonts.googleapis.com/css2?family=Outfit:wght@100..900&family=Syne:wght@400..800&display=swap"
    rel="stylesheet">
  <title>PantryPilot - Cook with Confidence</title>
</head>

<body>
  <div id="root"></div>
  <script type="module" src="/src/main.jsx"></script>
</body>

</html>
```

### eslint.config.js

```javascript
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import { defineConfig, globalIgnores } from 'eslint/config'

export default defineConfig([
  globalIgnores(['dist']),
  {
    files: ['**/*.{js,jsx}'],
    extends: [
      js.configs.recommended,
      reactHooks.configs.flat.recommended,
      reactRefresh.configs.vite,
    ],
    languageOptions: {
      ecmaVersion: 2020,
      globals: globals.browser,
      parserOptions: {
        ecmaVersion: 'latest',
        ecmaFeatures: { jsx: true },
        sourceType: 'module',
      },
    },
    rules: {
      'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }],
    },
  },
])

```

### src/index.css

```css
@import "tailwindcss";

@theme {
    --animate-float: float 6s ease-in-out infinite;
    --animate-float-delayed: float 6s ease-in-out 3s infinite;
    --animate-bounce-slow: bounce-slow 4s ease-in-out infinite;

    --font-heading: "Syne", sans-serif;
    --font-body: "Outfit", sans-serif;

    @keyframes float {

        0%,
        100% {
            transform: translateY(0px);
        }

        50% {
            transform: translateY(-20px);
        }
    }

    @keyframes bounce-slow {

        0%,
        100% {
            transform: translateY(0);
        }

        50% {
            transform: translateY(-10px);
        }
    }
}

@layer base {
    body {
        font-family: var(--font-body);
        @apply antialiased text-slate-900;
    }

    h1,
    h2,
    h3,
    h4,
    h5,
    h6 {
        font-family: var(--font-body);
    }
}

@layer utilities {
    .box-shadow-green {
        box-shadow: 0 0 15px rgba(34, 197, 94, 0.4);
    }
}
```

### src/components/Demo.jsx

```javascript
import { useState } from 'react'

export default function Demo() {
    const steps = [
        {
            id: "01",
            title: "Scan Your Pantry",
            desc: "Point your camera at your fridge or shelves. PantryPilot instantly identifies ingredients you already have using advanced computer vision."
        },
        {
            id: "02",
            title: "Get Matched Recipes",
            desc: "Our AI generates instant recipe ideas based on what’s available, helping you use up ingredients before they spoil."
        },
        {
            id: "03",
            title: "Cook & Enjoy",
            desc: "Follow simple, personalized guides. Save time, reduce waste, and discover new favorites without a grocery run."
        }
    ]

    const [activeStep, setActiveStep] = useState(0)

    return (
        <section id="demo" className="py-24 bg-transparent">
            <div className="container mx-auto px-6 max-w-7xl">
                <div className="text-center max-w-3xl mx-auto mb-16">
                    <h2 className="text-3xl md:text-5xl font-bold text-slate-900 mb-6 tracking-tight">How It Works</h2>
                    <p className="text-xl text-slate-500 font-medium">From setup to serving, we guide you every step of the way.</p>
                </div>

                <div className="grid lg:grid-cols-2 gap-12 lg:gap-20 items-center">
                    {/* Video Container */}
                    <div className="relative group">
                        <div className="absolute -inset-1 bg-gradient-to-r from-orange-500 to-pink-500 rounded-2xl blur opacity-25 group-hover:opacity-50 transition duration-1000 group-hover:duration-200"></div>
                        <div className="relative bg-black rounded-2xl overflow-hidden shadow-2xl ring-1 ring-slate-900/5 aspect-video">
                            <video
                                className="w-full h-full object-cover"
                                controls
                                poster="https://images.unsplash.com/photo-1556910103-1c02745a30bf?ixlib=rb-1.2.1&auto=format&fit=crop&w=800&q=80"
                            >
                                <source src="/video.mp4" type="video/mp4" />
                                Your browser does not support the video tag.
                            </video>
                        </div>
                        <p className="mt-4 text-center text-sm font-medium text-slate-500"> Watch the full walkthrough</p>
                    </div>

                    {/* Simple Text Steps */}
                    <div className="space-y-12">
                        {steps.map((step, index) => (
                            <div key={step.id} className="relative pl-6 border-l-2 border-slate-200 hover:border-orange-500 transition-colors duration-300">
                                <h3 className="text-2xl font-bold text-slate-900 mb-3">
                                    {step.title}
                                </h3>
                                <p className="text-lg text-slate-600 leading-relaxed max-w-md">
                                    {step.desc}
                                </p>
                            </div>
                        ))}
                    </div>
                </div>
            </div>
        </section>
    )
}

```

### src/components/Navbar.jsx

```javascript
import { Menu, Search, User, ShoppingCart, X } from 'lucide-react'
import { useState, useEffect } from 'react'

export default function Navbar() {
    const [isOpen, setIsOpen] = useState(false)
    const [isScrolled, setIsScrolled] = useState(false)

    useEffect(() => {
        const handleScroll = () => {
            setIsScrolled(window.scrollY > 20)
        }
        window.addEventListener('scroll', handleScroll)
        return () => window.removeEventListener('scroll', handleScroll)
    }, [])

    return (
        <nav className={`fixed left-1/2 -translate-x-1/2 z-50 transition-all duration-500 ease-in-out flex items-center justify-between
            ${isScrolled
                ? 'top-4 w-[90%] max-w-6xl h-16 bg-white/90 backdrop-blur-md shadow-lg rounded-full border border-slate-200/50'
                : 'top-6 w-[95%] max-w-7xl h-20 bg-white/40 backdrop-blur-sm rounded-2xl border border-white/40 shadow-sm'}
        `}>
            <div className="w-full px-8 flex justify-between items-center h-full">
                {/* Logo */}
                <a href="#" className={`font-heading font-extrabold text-orange-500 tracking-tight hover:text-orange-600 transition-all duration-300
                    ${isScrolled ? 'text-2xl' : 'text-3xl'}
                `}>
                    PantryPilot
                </a>

                {/* Desktop Links */}
                <div className="hidden md:flex items-center gap-8">
                    <ul className="flex gap-8 font-heading font-semibold text-slate-700 text-sm">
                        <li><a href="#home" className="hover:text-orange-500 transition-colors">Our Product</a></li>
                        <li><a href="#demo" className="hover:text-orange-500 transition-colors">How it Works</a></li>
                        <li><a href="#about" className="hover:text-orange-500 transition-colors">Mission</a></li>
                        <li><a href="#contact" className="hover:text-orange-500 transition-colors">Contact</a></li>
                    </ul>

                    <div className="flex gap-6 text-slate-600 items-center border-l pl-6 border-slate-200">
                        <button className="hover:text-orange-500 transition-colors"><Search size={20} /></button>
                        <button className="hover:text-orange-500 transition-colors"><User size={20} /></button>
                        <button className="hover:text-orange-500 transition-colors"><ShoppingCart size={20} /></button>
                    </div>
                </div>

                {/* Mobile Menu Button */}
                <button
                    className="md:hidden text-slate-700 hover:text-orange-500 transition-colors p-2"
                    onClick={() => setIsOpen(!isOpen)}
                >
                    {isOpen ? <X size={28} /> : <Menu size={28} />}
                </button>
            </div>

            {/* Mobile Menu Overlay */}
            {isOpen && (
                <div className={`absolute left-0 w-full bg-white border border-slate-200 shadow-xl md:hidden flex flex-col p-6 gap-4 animate-in slide-in-from-top-2 rounded-2xl mt-2
                    ${isScrolled ? 'top-16' : 'top-24'}
                `}>
                    <a href="#home" className="text-lg font-heading font-medium text-slate-700 hover:text-orange-500 py-2 border-b border-slate-100" onClick={() => setIsOpen(false)}>Our Product</a>
                    <a href="#demo" className="text-lg font-heading font-medium text-slate-700 hover:text-orange-500 py-2 border-b border-slate-100" onClick={() => setIsOpen(false)}>How it Works</a>
                    <a href="#about" className="text-lg font-heading font-medium text-slate-700 hover:text-orange-500 py-2 border-b border-slate-100" onClick={() => setIsOpen(false)}>Mission</a>
                    <a href="#contact" className="text-lg font-heading font-medium text-slate-700 hover:text-orange-500 py-2" onClick={() => setIsOpen(false)}>Contact</a>
                </div>
            )}
        </nav>
    )
}

```

### src/components/EverydayDishes.jsx

```javascript
export default function EverydayDishes() {
    const dishes = [
        {
            name: "White Sauce Pasta",
            image: "https://images.unsplash.com/photo-1555949258-eb67b1ef0ceb?ixlib=rb-1.2.1&auto=format&fit=crop&w=600&q=80"
        },
        {
            name: "Fried Chicken",
            image: "https://images.unsplash.com/photo-1626082927389-6cd097cdc6ec?ixlib=rb-1.2.1&auto=format&fit=crop&w=600&q=80"
        },
        {
            name: "Aglio Olio Pasta",
            image: "https://images.unsplash.com/photo-1626844131082-256783844137?ixlib=rb-1.2.1&auto=format&fit=crop&w=600&q=80"
        },
        {
            name: "Jeera Aloo Dry",
            image: "https://images.unsplash.com/photo-1601050690597-df0568f70950?ixlib=rb-1.2.1&auto=format&fit=crop&w=600&q=80"
        },
        {
            name: "Hakka Chowmein",
            image: "https://images.unsplash.com/photo-1585032226651-759b368d7246?ixlib=rb-1.2.1&auto=format&fit=crop&w=600&q=80"
        }
    ];

    // Duplicate for seamless loop
    const scrollDishes = [...dishes, ...dishes];

    return (
        <section className="py-20 bg-transparent overflow-hidden">
            <style>{`
                @keyframes scroll {
                    0% { transform: translateX(0); }
                    100% { transform: translateX(-50%); }
                }
                .animate-scroll {
                    display: flex;
                    width: max-content;
                    animation: scroll 30s linear infinite;
                }
                .animate-scroll:hover {
                    animation-play-state: paused;
                }
            `}</style>
            <div className="container mx-auto px-4 lg:px-8">
                {/* Header */}
                <div className="text-center mb-20">
                    <h2 className="text-5xl md:text-6xl font-black text-slate-900 mb-6 tracking-tighter">
                        Your <span className="bg-gradient-to-r from-orange-500 to-coral-500 bg-clip-text text-transparent">Everyday Dishes</span>, Made <span className="bg-gradient-to-r from-orange-500 to-coral-500 bg-clip-text text-transparent">Simpler</span>
                    </h2>
                    <p className="text-xl text-slate-600 italic font-semibold">
                        Shared by real users: <span className="underline decoration-orange-400/50 decoration-4 underline-offset-8">everyday dishes made in PantryPilot</span>
                    </p>
                </div>

                {/* Infinite Marquee */}
                <div className="relative w-full overflow-hidden" style={{ maskImage: 'linear-gradient(to right, transparent, black 15%, black 85%, transparent)', WebkitMaskImage: 'linear-gradient(to right, transparent, black 15%, black 85%, transparent)' }}>
                    <div className="animate-scroll gap-6 py-4">
                        {scrollDishes.map((dish, index) => (
                            <div key={index} className="w-[320px] flex-shrink-0 bg-white/40 backdrop-blur-xl rounded-[2.5rem] overflow-hidden shadow-2xl border border-white/40 group transition-all duration-500 hover:-translate-y-2">
                                <div className="aspect-[4/3] overflow-hidden">
                                    <img
                                        src={dish.image}
                                        alt={dish.name}
                                        className="w-full h-full object-cover transform group-hover:scale-110 transition-transform duration-[2s] ease-out"
                                    />
                                </div>
                                <div className="p-8 text-center bg-white/10 backdrop-blur-md">
                                    <h3 className="font-black text-slate-900 leading-tight text-xl tracking-tight uppercase italic">{dish.name}</h3>
                                </div>
                            </div>
                        ))}
                    </div>
                </div>
            </div>
        </section>
    )
}

```

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