# Project export: CodeCrack

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: Master coding interviews with CodeCrack: a voice-driven AI agent simulating dynamic, real-time mock interviews, delivering interactive feedback to sharpen your skills.
- Devpost: https://devpost.com/software/codecrack
- GitHub: https://github.com/kkarenvoo/TreeHacks2025
- Video: https://www.youtube.com/embed/dz0O5mzjFH0?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Result: winner (ElevenLabs: Best Use of ElevenLabs (11M Credits + AirPods Max per team member [1st] & 8.11M Credits + Merch [2nd] & 5.11M Credits + Merch [3rd]))
- Team: 4 GitHub contributor(s) — Karen Vo (32 commits), Natalia Pahlavan (15 commits), achinnak (10 commits), Louis Jordan (1 commits)

## Devpost submission (written by the team)

### Inspiration

Want to ace that upcoming technical interview for your dream job? LeetCode is a great place to start for developing good problem solving skills, but it lacks the interactive communication demands of a live coding interview where interviewers assess your problem-solving, debugging, and communication skills in addition to your ability to code. It’s fun to recruit your friends to help conduct a mock interview but these resources are not available to everyone. From under-resourced students to experienced builders, interview preparation materials and access to experienced coders can be an obstacle. As engineering students who have undergone Software Engineering recruiting, we wanted to build a tool that bridges this gap - allowing coders to improve their skill set while simulating the pressure of a live interview with real-time feedback. We built CodeCrack to empower anyone to crack their interview with confidence.

### How we built it

We built CodeClack on a Vercel web platform with functional modifications made for integrating the AI agents to execute their client tasks, keep track of state, and upstream information to the voice. On top of this, we built on the user interface to reflect the various components of our project. For instance, we’ve integrated an IDE with Monaco, the code editor behind VScode, and Pyodide, a Python interpreter so users can run and execute their code. Leveraging ElevenLabs voice agents, CodeCrack offers both behavioral and technical interviews. To simulate a Software Engineering coding interview as closely as possible, In the technical coding challenge, the AI agent will introduce themselves, give an overview of the interview, give the user a moment to introduce themselves, and then will dive into the coding challenge, populating the user’s screen with the challenge and reading it outloud. The agent is designed to take on the persona of a more senior level Software Engineering interviewer, processing how the user breaks down the problem and explores various paths before diving into an approach, offering an open-ended hint if the user indicates they are stuck or asking a follow-up question if they are on the right track. Within our agentic system, there are two main flows of information sharing: agent to client and client to agent. For the coding challenge question, we retrieved leetcode questions and solutions from a HuggingFace dataset, and in the first agent to client stream, we developed a client tool, sendNewQuestion, that randomly retrieves a question within the user’s difficulty preference, upstreaming it to the voice agent to read aloud. The other mode, client to agent, is activated when the user clicks “Run Code”, so the user’s code submission can be tested for functionality and the agent can generate feedback on code style. The agentic system is keeping track of the state of interactions, making decisions to pivot the conversation to get the user closer to a functional solution without revealing too much information. After the user ends the interview, an API call is sent to ElevenLabs’ criteria evaluation feature to get the agent’s feedback on communication, problem-solving, and debugging based on the overall state of interactions.

### Challenges we ran into

With no prior experience building with AI agents, the primary challenge we initially faced was understanding how agentic frameworks are built, and the tradeoffs between multi-agent frameworks and single agent frameworks. The next challenge we faced was learning how to influence single agent frameworks, and specifically, how to send information to it and retrieve information from it for various components of our project’s functionality. For instance, after retrieving a leetcode question we wanted to upstream this information to populate the user’s screen and have the AI agent read the problem out loud, but we faced difficulty understanding and building on the information streams that come with client tools. Expanding on this, all the builders on the team are most comfortable with Python and have no experience building extensive frontends. After realizing our Python client tools were not easily compatible with the AI agent codebase, we converted that entire part of our codebase to lay within Next.js and React, with some help from the ElevenLabs sponsor with only hours left before the deadline.

### What we learned

Over the last 36 hours we learned how to build our first tools with AI agents. In particular, we designed an AI agent for our interviewer persona and built various client tools to handle retrieving leetcode questions, evaluating the user’s code on run, and populating the UI with the coding challenge and comprehensive feedback. Specifically in terms of new technologies, we had no prior experience working with Node.js and React, so it was an exciting challenge to focus on user interface design.

### What's next

We look forward to building a more comprehensive system including System Design, Python trivia, and resume-based questions!

## README (from the GitHub repository)

<p align="center">
  <a href="https://demo.useliftoff.com">
    <img alt="CodeCrack – AI-Powered Mock Interviews" src="https://drive.google.com/uc?id=1PRzt9zw3pJdKV0Bg07YJlzY7Wsa0n0pn">
  </a>
</p>

<p align="center">
  Mock Interview Simulator with Conversational AI-Powered Feedback
</p>

<p align="center">
  <a href="#introduction"><strong>Introduction</strong></a> ·
  <a href="#tech-stack--features"><strong>Tech Stack + Features</strong></a> ·
</p>
<br/>

## Introduction

CodeCrack is an interview preparation tool that provides AI speech-to-speech feedback on your mock interviews, helping you crack your real interview.

## Tech Stack + Features

![Landing Page](https://ik.imagekit.io/9km72asqu/CleanShot_2023-05-31_at_12.43.54_svKkqF7dA.png?updatedAt=1685551454273)

![Interview Selection](https://ik.imagekit.io/9km72asqu/CleanShot_2023-05-31_at_13.35.55_xohCRNMlJ.png?updatedAt=1685554576155)

### Frameworks

- [Next.js](https://nextjs.org/) – React framework for building performant apps with the best developer experience

### Platforms

- [Vercel](https://vercel.com/) – Easily preview & deploy changes with git
- [Upstash](https://upstash.com/) - Serverless Data Platform (here using serverless Redis for rate limiting)
- [ElevenLabs](https://elevenlabs.io/) - Conversational AI Integration

### UI

- [Tailwind CSS](https://tailwindcss.com/) – Utility-first CSS framework for rapid UI development
- [Framer Motion](https://framer.com/motion) – Motion library for React to animate components with ease
- [`ImageResponse`](https://beta.nextjs.org/docs/api-reference/image-response) – Generate dynamic Open Graph images at the edge
- [HeadlessUI](https://headlessui.com/) - Completely unstyled, fully accessible UI components, designed to integrate beautifully with Tailwind CSS

### Code Quality

- [TypeScript](https://www.typescriptlang.org/) – Static type checker for end-to-end typesafety
- [Prettier](https://prettier.io/) – Opinionated code formatter for consistent code style
- [ESLint](https://eslint.org/) – Pluggable linter for Next.js and TypeScript

### Miscellaneous

- [FFMPEG.WASM](https://ffmpegwasm.netlify.app/) – Transcode video/audio files
- [React Webcam](https://github.com/mozmorris/react-webcam) - Webcam component for React
- [Stripe Gradient Animation](https://whatamesh.vercel.app/) - [@jordienr](https://twitter.com/jordienr) released a Mesh Gradient that uses WebGL and animates a beautiful gradient

## How it all works

CodeCrack is powered by ElevenLabs' AI and Vercel's web platform.


## Detected evidence (automated analysis)

Indexed codebase: 20 recognized source files, 242 KB.
- CSS (language) — detected in the code
- JavaScript (language) — detected in the code
- Next.js (technology) — detected in the code
- OpenAI (technology) — detected in the code
- React (technology) — detected in the code
- Tailwind CSS (technology) — detected in the code
- TypeScript (language) — detected in the code
- Node.js (technology) — claimed on Devpost, not found in the code
- Python (language) — claimed on Devpost, not found in the code
- Vercel (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (25 of 25)

```
.env.example
.eslintrc.json
.gitignore
app/layout.tsx
app/page.tsx
app/sitemap.ts
components/CodeRunner.tsx
components/Conversation.tsx
components/Gradient.js
components/UploadStep.tsx
LICENSE.md
middleware.ts
next.config.js
package.json
pages/_app.tsx
pages/api/blocked.ts
pages/api/generate.ts
pages/api/transcribe.ts
pages/demo.tsx
postcss.config.js
README.md
styles/globals.css
tailwind.config.js
tsconfig.json
utils/OpenAIStream.ts
```

### Dependencies

- package.json: @11labs/react@^0.0.7, @ffmpeg/core@^0.11.0, @ffmpeg/ffmpeg@^0.11.6, @headlessui/react@^1.7.14, @monaco-editor/react@^4.7.0, @tailwindcss/typography@^0.5.9, @types/formidable@^2.0.5, @types/node@20.2.5, @types/react@18.2.7, @types/react-dom@18.2.4, @upstash/ratelimit@^0.4.2, @upstash/redis@^1.20.6, autoprefixer@^10.4.14, clsx@^1.2.1, encoding@^0.1.13, eslint@8.41.0, eslint-config-next@13.4.4, eventsource-parser@^1.0.0, formidable@^2.1.1, framer-motion@^10.12.5, lucide-react@^0.475.0, next@^15.1.7, openai@^3.2.1, postcss@^8.4.24, react@18.2.0, react-dom@18.2.0, react-webcam@^7.0.1, tailwindcss@^3.3.2, typescript@5.0.4, uuidv4@^6.2.13

### Recent commits (newest first)

- Delete file
- Update README.md
- Merge remote changes and resolve conflicts
- new updates
- Update UI
- Merge remote changes
- Fixed UI
- Update README.md
- Update README.md
- Update README.md
- Update README.md
- Update README.md
- Update README.md
- Update README.md
- Update README.md
- Update README.md
- Update README.md
- Updates
- change name
- Merge branch 'main' of https://github.com/kkarenvoo/TreeHacks2025

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

### LICENSE.md

```markdown
MIT License

Copyright (c) 2023 Tyler Meyer

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

```

### package.json

```
{
  "name": "liftoff",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "@11labs/react": "^0.0.7",
    "@ffmpeg/core": "^0.11.0",
    "@ffmpeg/ffmpeg": "^0.11.6",
    "@headlessui/react": "^1.7.14",
    "@monaco-editor/react": "^4.7.0",
    "@types/node": "20.2.5",
    "@types/react": "18.2.7",
    "@types/react-dom": "18.2.4",
    "@upstash/ratelimit": "^0.4.2",
    "@upstash/redis": "^1.20.6",
    "clsx": "^1.2.1",
    "encoding": "^0.1.13",
    "eslint": "8.41.0",
    "eslint-config-next": "13.4.4",
    "eventsource-parser": "^1.0.0",
    "formidable": "^2.1.1",
    "framer-motion": "^10.12.5",
    "lucide-react": "^0.475.0",
    "next": "^15.1.7",
    "openai": "^3.2.1",
    "react": "18.2.0",
    "react-dom": "18.2.0",
    "react-webcam": "^7.0.1",
    "typescript": "5.0.4",
    "uuidv4": "^6.2.13"
  },
  "devDependencies": {
    "@tailwindcss/typography": "^0.5.9",
    "@types/formidable": "^2.0.5",
    "autoprefixer": "^10.4.14",
    "postcss": "^8.4.24",
    "tailwindcss": "^3.3.2"
  }
}

```

### app/layout.tsx

```typescript
import "../styles/globals.css";
import { Metadata } from "next";

export const metadata: Metadata = {
  title: "Liftoff - AI-Powered Mock Interviews",
  openGraph: {
    title: "Liftoff - AI-Powered Mock Interviews",
    description:
      "Liftoff is an AI-powered mock interview platform that helps you practice for your next job interview.",
    images: [
      {
        url: "https://demo.useliftoff.com/opengraph-image",
      },
    ],
  },
  twitter: {
    card: "summary_large_image",
    title: "Liftoff - AI-Powered Mock Interviews",
    description:
      "Liftoff is an AI-powered mock interview platform that helps you practice for your next job interview.",
    images: ["https://demo.useliftoff.com/opengraph-image"],
    creator: "@tmeyer_me",
  },
  metadataBase: new URL("https://demo.useliftoff.com"),
  themeColor: "#FFF",
};

export default async function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body className="scroll-smooth antialiased [font-feature-settings:'ss01']">
        {children}
      </body>
    </html>
  );
}

```

### postcss.config.js

```javascript
module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
}

```

### next.config.js

```javascript
/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  async headers() {
    return [
      {
        source: "/(.*)",
        headers: [
          {
            key: "Cross-Origin-Embedder-Policy",
            value: "require-corp",
          },
          {
            key: "Cross-Origin-Opener-Policy",
            value: "same-origin",
          },
        ],
      },
    ];
  },
};

module.exports = nextConfig;

```

### tailwind.config.js

```javascript
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./pages/**/*.{js,ts,jsx,tsx,mdx}",
    "./components/**/*.{js,ts,jsx,tsx,mdx}",
    "./app/**/*.{js,ts,jsx,tsx,mdx}",
  ],
  future: {
    hoverOnlyWhenSupported: true,
  },
  theme: {
    extend: {
      backgroundImage: {
        "gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
        "gradient-conic":
          "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))",
      },
    },
  },
  plugins: [],
};

```

### middleware.ts

```typescript
import { Ratelimit } from "@upstash/ratelimit";
import { Redis } from "@upstash/redis";
import { NextFetchEvent, NextRequest, NextResponse } from "next/server";

export default async function middleware(
  request: NextRequest,
  event: NextFetchEvent
): Promise<Response | undefined> {
  const ip = request.ip ?? "127.0.0.1";

  // ratelimit for demo app: https://demo.useliftoff.com/
  if (
    process.env.NODE_ENV != "development" &&
    process.env.UPSTASH_REDIS_REST_URL &&
    process.env.UPSTASH_REDIS_REST_TOKEN
  ) {
    const ratelimit = new Ratelimit({
      redis: Redis.fromEnv(),
      // Rate limit to 6 attempts per 2 days
      limiter: Ratelimit.cachedFixedWindow(12, `${24 * 60 * 60}s`),
      ephemeralCache: new Map(),
      analytics: true,
    });

    const { success, pending, limit, reset, remaining } = await ratelimit.limit(
      `ratelimit_middleware_${ip}`
    );
    event.waitUntil(pending);

    const res = success
      ? NextResponse.next()
      : NextResponse.redirect(new URL("/api/blocked", request.url));

    res.headers.set("X-RateLimit-Limit", limit.toString());
    res.headers.set("X-RateLimit-Remaining", remaining.toString());
    res.headers.set("X-RateLimit-Reset", reset.toString());
    return res;
  }
}

export const config = {
  matcher: ["/api/transcribe", "/api/generate"],
};

```

### styles/globals.css

```css
@tailwind base;
@tailwind components;
@tailwind utilities;

#gradient-canvas {
  --gradient-color-1: #bde1ff;
  --gradient-color-2: #6ca0f4;
  --gradient-color-3: #e2d8ee;
  --gradient-color-4: #94c8ff;
}

```

### app/sitemap.ts

```typescript
import { MetadataRoute } from "next";

export default function sitemap(): MetadataRoute.Sitemap {
  return [
    {
      url: "https://demo.useliftoff.com",
      lastModified: new Date(),
    },
    {
      url: "https://demo.useliftoff.com/demo",
      lastModified: new Date(),
    },
  ];
}

```

### pages/_app.tsx

```typescript
import "@/styles/globals.css";
import type { AppProps } from "next/app";

function MyApp({ Component, pageProps }: AppProps) {
  return (
    <main className="scroll-smooth antialiased [font-feature-settings:'ss01']">
      <Component {...pageProps} />
    </main>
  );
}

export default MyApp;

```

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