# Project export: ActiveCard

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 2024
- Tagline: Revolutionizing learning for students 4th-8th with the power of active learning and Artificial Intelligence
- Devpost: https://devpost.com/software/activecard
- GitHub: https://github.com/zorazrr/activ-card
- Video: https://www.youtube.com/embed/oxTm3vrDh4s?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 3 GitHub contributor(s) — Archna-1 (34 commits), zorazrr (32 commits), vasuchal (29 commits)

## Devpost submission (written by the team)

### Inspiration

Current study resources for classrooms are not built to support long-term content retention through active learning and effective memory retrieval techniques. This is a detriment for both students and teachers. How does this affect students? With the combination of the rise of social media and the after-effects of COVID-19, many students have shortened attention spans and shorter windows of retention, often unable to retain key fundamentals past the unit they learn it in. This can lead to “dangerous knowledge gaps” as they progress to upper grade levels, where mastery of these fundamentals is essential. How does this affect teachers? Currently, there is a significant time investment teachers must make to create study materials for their students. Creating and/or finding engaging learning material while also closely tracking students' progress is challenging. Thus, teachers lose time every year trying to tackle these issues. Furthermore, if students lack fundamental understanding of subjects due to the aforementioned “dangerous knowledge gaps,” teachers become burdened with more responsibility and have to shift their curriculum to meet the needs of their students. This is an important problem because, when students don’t interact with the content in an impactful manner, they become disengaged and don’t commit what they learn to long-term memory. Thus, the burden on teachers to play “catch-up” continues to snowball, especially at higher grade levels.

### What it does

Through our user research with various K-12 teachers in the state of Illinois, we were able to firsthand see how COVID-19 and social media impact student focus, and, consequently, their content retention rates and literacy levels. To address this, we introduce an application that increases content retention and student engagement in classrooms by combining the power of active learning with flashcards through AI. We re-define the notion of what a flashcard can be and present it as a multipurpose, multimedia tool that drives active learning. How it works Teacher Experience Teachers create flashcard sets for their classrooms, developing accurate, impactful and re-usable study materials for students to interface with. We allow teachers to build their curriculum for the future through our platform and create sets with ease. (a) How can they create effective sets efficiently? Multimedia support → Can prompt our AI through uploading existing worksheets, quizzes, and exams. Our tool will return a set of flashcards based on the given material. These can be used for unit reviews, literacy practice, or exam wrappers. Generative Content → Can prompt our AI through text to generate higher-level flashcard questions based on the levels of Bloom’s Taxonomy the educator wants to focus on Remember vs Understand vs Apply vs Design Remember vs Understand vs Apply vs Design Iterative Creation: Once sets are created by our AI, through our focus on seamless, user-friendly design, teachers will be able to quickly review and modify the cards and their configurations as they deem fit before publishing. (b) How can they incorporate active learning into flashcards? Students are more motivated when they can take more ownership in their learning. We allow for students to engage with flashcards through various active-learning formats including (but not limited to): Written response: Encourage “In-your-own” word definitions and breakdowns As the response will be checked using AI, students have the flexibility to explain concepts by putting them into their own words rather than having to practice “word-for-word memorization.” Audio response: Speaking answers to flashcards rather than typing For literacy acceleration, students can use flashcards to record themselves practicing reading with terms and can be assessed by AI. For foreign languages, teachers can also choose different focus points, such as pronunciation, grammar, etc to be tracked by AI Interleaving: Mixing multiple subjects or topics while studying Teachers can choose to combine x% of older unit sets with newer units so students continuously gain exposure and practice recall. Dual Encoding Can generate images next to the flashcards automatically to help students associate content better through “dual-encoding” Written response: Encourage “In-your-own” word definitions and breakdowns As the response will be checked using AI, students have the flexibility to explain concepts by putting them into their own words rather than having to practice “word-for-word memorization.” As the response will be checked using AI, students have the flexibility to explain concepts by putting them into their own words rather than having to practice “word-for-word memorization.” Audio response: Speaking answers to flashcards rather than typing For literacy acceleration, students can use flashcards to record themselves practicing reading with terms and can be assessed by AI. For foreign languages, teachers can also choose different focus points, such as pronunciation, grammar, etc to be tracked by AI For literacy acceleration, students can use flashcards to record themselves practicing reading with terms and can be assessed by AI. For foreign languages, teachers can also choose different focus points, such as pronunciation, grammar, etc to be tracked by AI Interleaving: Mixing multiple subjects or topics while studying Teachers can choose to combine x% of older unit sets with newer units so students continuously gain exposure and practice recall. Teachers can choose to combine x% of older unit sets with newer units so students continuously gain exposure and practice recall. Dual Encoding Can generate images next to the flashcards automatically to help students associate content better through “dual-encoding” Can generate images next to the flashcards automatically to help students associate content better through “dual-encoding” Students Experience (a) How do students learn? Students actively practice recall by interacting with the flashcard in their own words and on their own terms. In the future, students also will be able to access a personalized assistant chatbot that will act as a “teaching assistant or guide” that will help students by providing them intermediate, guidance questions while they solve problems. (b) How do we maintain student focus and engagement? We will be utilizing the Pomodoro technique that suggests focused sessions of learning with gamified “brain breaks” in between. We encourage healthy gamification where we don’t sacrifice the quality of learning for student engagement. We will be utilizing the Pomodoro technique that suggests focused sessions of learning with gamified “brain breaks” in between. We encourage healthy gamification where we don’t sacrifice the quality of learning for student engagement. For every X cards or X minutes that students study, they will be able to play a mini drawing game for a small interval of time before beginning their next session. Their drawings will be generated into an animated badge through generative AI. They will be able to store a collection of badges and contribute to a class gallery, incentivizing their participation. For every X cards or X minutes that students study, they will be able to play a mini drawing game for a small interval of time before beginning their next session. Their drawings will be generated into an animated badge through generative AI. They will be able to store a collection of badges and contribute to a class gallery, incentivizing their participation. Classroom Experience (a) How can teachers better understand student progress? Group metrics: Analyzes what concepts the classroom is struggling with and presents teacher analytics on areas to focus on reviewing Student metrics: Analyzes each student’s performance and highlights to teachers students who may need extra support, provides granularity into each student (i.e. stopped trying, started trying but gave up, literacy issue, calculation errors, etc) (b) How do we support various student groups? Using Internationalization and Language Learning Models for Content Translation, we make this accessible to students and teachers of all languages through providing translation of all content generated on the site

### How we built it

We leveraged OpenAI API to perform a variety of tasks that involves multimedia Gpt-turbo-3.5 LLM model performs (1) generating study sets from given text information (2) checking student answer against given definition (3) generating explanation and feedback for students Throughout the process, we also experimented with prompt engineering Throughout the process, we also experimented with prompt engineering Whisper-1 model performs speech-to-text recognition to convert students’ audio answer to text answer for AI to perform checks DALL·E 2 model performs image generation based on student drawing We leveraged AWS to interact with multimedia content, notably png and pdf files S3: for temporary storage of user-uploaded files Textract: for extracting text information from various file types such as pdf and png Our web application tech stack includes Next.js tRPC NextAuth: for authentication with Google on GCP Prisma: ORM for connecting to the database ChakraUI and Tailwind CSS: for UI components and custom styling MongoDB: for storing user, classroom, card, and set information

### Challenges we ran into

Before working with ChatGPT to generate images based on stickers students drew, we tested what it could do using the chatbot. We would provide an image and a prompt, like “make a kid-friendly cartoon version of the provided image.” This resulted in the following transformation: We soon realized the OpenAI image generation API was not as robust as the end-user chat bot, and pivoted to temporarily using image masking and manipulation to create abstract art inspired by the students’ drawings. Another challenge is handling file transfer between the web application and OpenAI API. In our application, we had to handle multimedia including image, audio, and pdf files. To tackle this challenge, we leveraged different technologies from AWS S3 for file storage and access, Textract for file conversion, and MediaStream API with DataUrl manipulation to process media content.

### Accomplishments we're proud of

We’re really happy to see how our work came together on a project with a really large scope. It is intuitive to use and has a clean UI, which we wanted to emphasize since our target users are teachers and young students. Tackling the challenges in handling AI communication with multimedia content is especially exciting. Seeing the drawing minigame work was satisfying: from the image generation to the pomodoro technique to make the application engaging and good for retention.

### What we learned

We learned a lot about AI, prompt engineering, our target market, handling multimedia content, and developing a good UI/UX.

### What's next

Our next steps include polishing up the application and user testing. As we have developed an MVP of our web app, we will get into contact with our teacher contacts and test ActiveCard out in their classrooms. We hope to get some early adopters and flesh out our metrics dashboard to convince districts to pick up the tool, at which point we can start monetizing the platform. Some larger features we plan to develop for a V1 of the application after user testing are interleaving sets and spaced repetition. These techniques will further utilize active learning in our application. We will also switch to using more specialized AI models to target each of the specific tasks we have (i.e. image generation, speech recognition, etc.). In addition, we’ll have our tool be able to generate more flashcards with given content (i.e. worksheets). Finally, we plan to create a more cohesive classroom experience by allowing students to view other students’ generated custom badges in a gallery view, and we will add additional group study features for peer-to-peer learning. We have designs for how the application will look after MVP user testing. We’re super excited to see where ActiveCard goes as we’re very passionate about the space, especially after talking to teachers and really understanding how deep-rooted the problem is!

## README (from the GitHub repository)

# ActiveCard

AI-powered active learning suite for 4th - 8th students and teachers, with multimedia support, LLM-assisted question generation and answer validation, and iterative creation.

<p align="center">
<img src="https://github.com/zorazrr/activ-card/blob/main/public/assets/flashcard.png" alt="Flashcard Demo" width="600">
</p>

## Getting Started

Clone this repository

```
git clone https://github.com/zorazrr/activ-card.git
```

Create a `.env` file 

```
DATABASE_URL=
NEXTAUTH_URL=
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
OPENAI_API_KEY=
REACT_APP_AWS_ACCESS_KEY_ID=
REACT_APP_AWS_SECRET_ACCESS_KEY=
REACT_APP_AWS_REGION=
REACT_APP_S3_BUCKET_NAME=
```

Running the app

```
yarn && yarn dev
```

Then go to http://localhost:3000 in your browser.



## Technology

This project uses the [T3 Stack](https://create.t3.gg/).

- [Next.js](https://nextjs.org)
- [NextAuth.js](https://next-auth.js.org)
- [Prisma](https://prisma.io)
- [Tailwind CSS](https://tailwindcss.com)
- [tRPC](https://trpc.io)

Additional technologies used:

- [OpenAI API](https://platform.openai.com/docs/overview)
- [AWS](https://aws.amazon.com/) (S3 and Textract)

## Detected evidence (automated analysis)

Indexed codebase: 61 recognized source files, 176 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
- AWS (technology) — claimed on Devpost, not found in the code
- MongoDB (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (68 of 68)

```
.env.example
.eslintrc.cjs
.gitignore
next.config.js
package.json
postcss.config.cjs
prettier.config.js
prisma/schema.prisma
README.md
src/components/AddClassModal.tsx
src/components/AudioRecorder.tsx
src/components/BadgeGallery.tsx
src/components/Button.tsx
src/components/CancelSetCreationOrUpdateModal.tsx
src/components/Canvas.tsx
src/components/CanvasWrapper.tsx
src/components/Card.tsx
src/components/CardNew.tsx
src/components/CardPair.tsx
src/components/Countdown.tsx
src/components/DashboardTabs.tsx
src/components/FileUpload.tsx
src/components/Flashcard.tsx
src/components/ImageModal.tsx
src/components/JoinClassModal.tsx
src/components/Modal.tsx
src/components/Progress/ProgressBar.tsx
src/components/Progress/ProgressMetric.tsx
src/components/ProtectedPage.tsx
src/components/SideBar/ClassRadioButton.tsx
src/components/SideBar/SideBar.tsx
src/components/TeacherDashboardPanels/Metrics.tsx
src/components/TeacherDashboardPanels/Sets.tsx
src/components/TeacherDashboardPanels/StudentRoster.tsx
src/env.js
src/pages/_app.tsx
src/pages/api/auth/[...nextauth].ts
src/pages/api/trpc/[trpc].ts
src/pages/create/set/[id].tsx
src/pages/create/set/medium.tsx
src/pages/dashboard.tsx
src/pages/draw.tsx
src/pages/index.tsx
src/pages/login.jsx
src/pages/redirect.tsx
src/pages/set/[id].tsx
src/pages/signout.tsx
src/pages/signup.jsx
src/server/api/root.ts
src/server/api/routers/badge.ts
src/server/api/routers/card.ts
src/server/api/routers/classroom.ts
src/server/api/routers/gpt.ts
src/server/api/routers/set.ts
src/server/api/routers/student.ts
src/server/api/routers/teacher.ts
src/server/api/routers/user.ts
src/server/api/trpc.ts
src/server/auth.ts
src/server/db.ts
src/styles/chakra-theme.js
src/styles/globals.css
src/utils/api.ts
src/utils/helpers.ts
src/utils/types.ts
start-database.sh
tailwind.config.ts
tsconfig.json
```

### Dependencies

- package.json: @aws-sdk/client-s3@^3.515.0, @aws-sdk/client-textract@^3.515.0, @aws-sdk/lib-storage@^3.515.0, @aws-sdk/s3-request-presigner@^3.515.0, @chakra-ui/icons@^2.1.1, @chakra-ui/react@^2.8.2, @emotion/react@^11.11.3, @emotion/styled@^11.11.0, @fortawesome/fontawesome-svg-core@^6.5.2, @fortawesome/free-solid-svg-icons@^6.5.2, @fortawesome/react-fontawesome@^0.2.0, @next-auth/prisma-adapter@^1.0.7, @prisma/client@^5.6.0, @t3-oss/env-nextjs@^0.7.1, @tanstack/react-query@^4.36.1, @trpc/client@^10.43.6, @trpc/next@^10.43.6, @trpc/react-query@^10.43.6, @trpc/server@^10.43.6, @types/eslint@^8.44.7, @types/node@^18.17.0, @types/react@^18.2.37, @types/react-dom@^18.2.15, @typescript-eslint/eslint-plugin@^6.11.0, @typescript-eslint/parser@^6.11.0, autoprefixer@^10.4.14, aws-sdk@^2.1560.0, eslint@^8.54.0, eslint-config-next@^14.0.4, framer-motion@^11.0.5, html2canvas@^1.4.1, next@^14.0.4, next-auth@^4.24.5, openai@^4.28.0, postcss@^8.4.31, prettier@^3.1.0, prettier-plugin-tailwindcss@^0.5.7, prisma@^5.6.0, react@18.2.0, react-canvas-draw@^1.2.1, react-color@^2.19.3, react-dom@18.2.0, react-icons@^5.0.1, superjson@^2.2.1, tailwindcss@^3.3.5, typescript@^5.1.6, zod@^3.22.4

### Recent commits (newest first)

- Add gpt prompting
- Edit metrics
- Metrics frontend (#116)
- Add more focused prompting (#115)
- Implement idk explanation (#114)
- Vc styling (#113)
- Finish more styling todos (#112)
- Add card flip animation and logic (#108)
- Add styling todo/suggestion
- Teacher config options (#110)
- Complete more styling todos (#105)
- Merge branch 'main' of github.com:zorazrr/activ-card
- Add keys
- Restyle end page (#104)
- Fix image prompting
- Remove edit and delete buttons for student
- Fix delete bug (#103)
- Set size appropriately (#102)
- Fix styling (#101)
- Fix styling (#100)

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

### package.json

```
{
  "name": "activ-card",
  "version": "0.1.0",
  "private": true,
  "type": "module",
  "scripts": {
    "build": "next build",
    "db:push": "prisma db push",
    "db:studio": "prisma studio",
    "dev": "next dev",
    "postinstall": "prisma generate",
    "lint": "next lint",
    "start": "next start"
  },
  "dependencies": {
    "@aws-sdk/client-s3": "^3.515.0",
    "@aws-sdk/client-textract": "^3.515.0",
    "@aws-sdk/lib-storage": "^3.515.0",
    "@aws-sdk/s3-request-presigner": "^3.515.0",
    "@chakra-ui/icons": "^2.1.1",
    "@chakra-ui/react": "^2.8.2",
    "@emotion/react": "^11.11.3",
    "@emotion/styled": "^11.11.0",
    "@fortawesome/fontawesome-svg-core": "^6.5.2",
    "@fortawesome/free-solid-svg-icons": "^6.5.2",
    "@fortawesome/react-fontawesome": "^0.2.0",
    "@next-auth/prisma-adapter": "^1.0.7",
    "@prisma/client": "^5.6.0",
    "@t3-oss/env-nextjs": "^0.7.1",
    "@tanstack/react-query": "^4.36.1",
    "@trpc/client": "^10.43.6",
    "@trpc/next": "^10.43.6",
    "@trpc/react-query": "^10.43.6",
    "@trpc/server": "^10.43.6",
    "aws-sdk": "^2.1560.0",
    "framer-motion": "^11.0.5",
    "html2canvas": "^1.4.1",
    "next": "^14.0.4",
    "next-auth": "^4.24.5",
    "openai": "^4.28.0",
    "react": "18.2.0",
    "react-canvas-draw": "^1.2.1",
    "react-color": "^2.19.3",
    "react-dom": "18.2.0",
    "react-icons": "^5.0.1",
    "superjson": "^2.2.1",
    "zod": "^3.22.4"
  },
  "devDependencies": {
    "@types/eslint": "^8.44.7",
    "@types/node": "^18.17.0",
    "@types/react": "^18.2.37",
    "@types/react-dom": "^18.2.15",
    "@typescript-eslint/eslint-plugin": "^6.11.0",
    "@typescript-eslint/parser": "^6.11.0",
    "autoprefixer": "^10.4.14",
    "eslint": "^8.54.0",
    "eslint-config-next": "^14.0.4",
    "postcss": "^8.4.31",
    "prettier": "^3.1.0",
    "prettier-plugin-tailwindcss": "^0.5.7",
    "prisma": "^5.6.0",
    "tailwindcss": "^3.3.5",
    "typescript": "^5.1.6"
  },
  "ct3aMetadata": {
    "initVersion": "7.26.0"
  },
  "packageManager": "yarn@1.22.19"
}

```

### src/pages/index.tsx

```typescript
import Head from "next/head";
import Link from "next/link";
import Img from "next/image";
import StyledButton from "~/components/Button";

export default function Home() {
  return (
    <>
      <Head>
        <title>ActiveCard</title>
        <meta name="description" content="Generated by create-t3-app" />
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <div className="main-class flex items-center justify-between space-x-4">
        <div className="p-5 hover:opacity-75">
          <Link href="/">
            <Img src="/assets/logo.png" alt="header" width={65} height={65} />
          </Link>
        </div>
        <div className="main-class flex items-center justify-between space-x-4 p-5">
          <Link href="/login">
            <StyledButton label="Log In" colorInd={0} onClick={() => {}} />
          </Link>
          <Link href="/signup">
            <StyledButton label="Sign Up" colorInd={1} onClick={() => {}} />
          </Link>
        </div>
      </div>
      <div
        className="main-class justify-content flex items-center"
        style={{
          width: "100%",
          paddingTop: "5%",
          paddingLeft: "25%",
          paddingRight: "15%",
        }}
      >
        <div
          className="main-class justify-content flex-col items-center"
          style={{ margin: "auto", paddingBottom: "30%" }}
        >
          <div className="h1 text-darkBlue" style={{ margin: "auto" }}>
            ActiveCard
          </div>
          <div style={{ margin: "auto" }}>
            <Link href="/signup">
              <StyledButton
                label="Get Started"
                colorInd={0}
                onClick={() => {}}
                style={{ width: "65%", height: "50px" }}
              />
            </Link>
          </div>
        </div>
        <div
          style={{ marginRight: "10%", marginTop: "5%" }}
          className="custom-image-class relative inline-block"
        >
          <Img
            src="/assets/big_logo.png" // Assume your image is in the public/images folder
            alt="Logo"
            width={650} // Desired width of the image in pixels
            height={390} // Desired height of the image in pixels
            className="custom-image-class block"
          />
          <div
            className="typewriter absolute left-3/4 top-1/2 -translate-x-3/4 -translate-y-3/4 transform text-white"
            style={{ width: "150%", fontSize: "18px", marginTop: "5%" }}
          >
            <h1>Active Learning &#129309; Meets &#129309; Flashcards </h1>
          </div>
        </div>
      </div>
    </>
  );
}

```

### prettier.config.js

```javascript
/** @type {import('prettier').Config & import('prettier-plugin-tailwindcss').PluginOptions} */
const config = {
  plugins: ["prettier-plugin-tailwindcss"],
};

export default config;

```

### next.config.js

```javascript
/**
 * Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially useful
 * for Docker builds.
 */
await import("./src/env.js");

/** @type {import("next").NextConfig} */
const config = {
  reactStrictMode: true,

  /**
   * If you are using `appDir` then you must comment the below `i18n` config out.
   *
   * @see https://github.com/vercel/next.js/issues/41980
   */
  i18n: {
    locales: ["en"],
    defaultLocale: "en",
  },
  images: {
    domains: [
      "oaidalleapiprodscus.blob.core.windows.net",
      `${process.env.REACT_APP_S3_BUCKET_NAME}.s3.${process.env.REACT_APP_AWS_REGION}.amazonaws.com`,
    ],
  },
};

export default config;

```

### start-database.sh

```shell
#!/bin/bash
# Use this script to start a docker container for a local development database

# TO RUN ON WINDOWS: 
# 1. Install WSL (Windows Subsystem for Linux) - https://learn.microsoft.com/en-us/windows/wsl/install
# 2. Install Docker Desktop for Windows - https://docs.docker.com/docker-for-windows/install/
# 3. Open WSL - `wsl`
# 4. Run this script - `./start-database.sh`

# On Lunux and macOS you can run this script directly - `./start-database.sh`

DB_CONTAINER_NAME="activ-card-mysql"

if ! [ -x "$(command -v docker)" ]; then
  echo "Docker is not installed. Please install docker and try again.\nDocker install guide: https://docs.docker.com/engine/install/"
  exit 1
fi

if [ "$(docker ps -q -f name=$DB_CONTAINER_NAME)" ]; then
  docker start $DB_CONTAINER_NAME
  echo "Database container started"
  exit 0
fi

# import env variables from .env
set -a
source .env

DB_PASSWORD=$(echo $DATABASE_URL | awk -F':' '{print $3}' | awk -F'@' '{print $1}')

if [ "$DB_PASSWORD" == "password" ]; then
  echo "You are using the default database password"
  read -p "Should we generate a random password for you? [y/N]: " -r REPLY
  if ! [[ $REPLY =~ ^[Yy]$ ]]; then
    echo "Please set a password in the .env file and try again"
    exit 1
  fi
  DB_PASSWORD=$(openssl rand -base64 12)
  sed -i -e "s/:password@/:$DB_PASSWORD@/" .env
fi

docker run --name $DB_CONTAINER_NAME -e MYSQL_ROOT_PASSWORD=$DB_PASSWORD -e MYSQL_DATABASE=activ-card -d -p 3306:3306 docker.io/mysql

echo "Database container was succesfuly created"



```

### tailwind.config.ts

```typescript
import { type Config } from "tailwindcss";
import { fontFamily } from "tailwindcss/defaultTheme";

const plugin = require("tailwindcss/plugin");

const CardFlipStyles = plugin(function ({ addUtilities }) {
  addUtilities({
    ".my-rotate-x-180": {
      transform: "rotateX(180deg)",
    },
    ".preserve-3d": {
      transformStyle: "preserve-3d",
    },
    ".perspective": {
      perspective: "1000px",
    },
    ".backface-hidden": {
      "-moz-backface-visibility": "hidden",
      "backface-visibility": "hidden",
    },
  });
});

export default {
  content: ["./src/**/*.tsx"],
  theme: {
    extend: {
      fontFamily: {
        sans: ["var(--font-sans)", ...fontFamily.sans],
        roboto: ["Roboto", "sans-serif"],
      },
      minHeight: {
        screen: "100vh",
      },
      fontSize: {
        "h1-size": "96px", // Existing custom font size
        "h2-size": "64px", // New custom font size
        "h3-size": "48px",
        "h4-size": "36px",
        "h4-5-size": "30px",
        "h5-size": "24px",
        "text-size": "16px",
      },
      fontWeight: {
        extrabold: "900", // Ensure extrabold is correctly mapped if not already
        semibold: "600",
        medium: "400",
      },
      colors: {
        darkBlue: "#1A3F67",
        mediumBlue: "#4A729D",
        midBlue: "#88ADD5",
        lightBlue: "#BEDDFC",
        black: "#000000",
        white: "#FFFFFF",
        lightGray: "#F5F9FA",
        darkGray: "#BDBDBD",
        veryDarkGray: "#1E1D1E",
      },
      keyframes: {
        flip: {
          "0%": {
            transform: "rotateX(0deg)",
          },
          "100%": {
            transform: "rotateX(180deg)",
          },
        },
      },
      animation: {
        flip: "flip 1.1s linear",
      },
    },
  },
  plugins: [CardFlipStyles],
} satisfies Config;

```

### src/env.js

```javascript
import { createEnv } from "@t3-oss/env-nextjs";
import { z } from "zod";

export const env = createEnv({
  /**
   * Specify your server-side environment variables schema here. This way you can ensure the app
   * isn't built with invalid env vars.
   */
  server: {
    DATABASE_URL: z
      .string()
      .url()
      .refine(
        (str) => !str.includes("YOUR_MYSQL_URL_HERE"),
        "You forgot to change the default URL"
      ),
    NODE_ENV: z
      .enum(["development", "test", "production"])
      .default("development"),
    NEXTAUTH_SECRET:
      process.env.NODE_ENV === "production"
        ? z.string()
        : z.string().optional(),
    NEXTAUTH_URL: z.preprocess(
      // This makes Vercel deployments not fail if you don't set NEXTAUTH_URL
      // Since NextAuth.js automatically uses the VERCEL_URL if present.
      (str) => process.env.VERCEL_URL ?? str,
      // VERCEL_URL doesn't include `https` so it cant be validated as a URL
      process.env.VERCEL ? z.string() : z.string().url()
    ),
    // DISCORD_CLIENT_ID: z.string(),
    // DISCORD_CLIENT_SECRET: z.string(),
    GOOGLE_CLIENT_ID: z.string(),
    GOOGLE_CLIENT_SECRET: z.string(),
  },

  /**
   * Specify your client-side environment variables schema here. This way you can ensure the app
   * isn't built with invalid env vars. To expose them to the client, prefix them with
   * `NEXT_PUBLIC_`.
   */
  client: {
    // NEXT_PUBLIC_CLIENTVAR: z.string(),
  },

  /**
   * You can't destruct `process.env` as a regular object in the Next.js edge runtimes (e.g.
   * middlewares) or client-side so we need to destruct manually.
   */
  runtimeEnv: {
    DATABASE_URL: process.env.DATABASE_URL,
    NODE_ENV: process.env.NODE_ENV,
    NEXTAUTH_SECRET: process.env.NEXTAUTH_SECRET,
    NEXTAUTH_URL: process.env.NEXTAUTH_URL,
    // DISCORD_CLIENT_ID: process.env.DISCORD_CLIENT_ID,
    // DISCORD_CLIENT_SECRET: process.env.DISCORD_CLIENT_SECRET,
    GOOGLE_CLIENT_ID: process.env.GOOGLE_CLIENT_ID,
    GOOGLE_CLIENT_SECRET: process.env.GOOGLE_CLIENT_SECRET,
  },
  /**
   * Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation. This is especially
   * useful for Docker builds.
   */
  skipValidation: !!process.env.SKIP_ENV_VALIDATION,
  /**
   * Makes it so that empty strings are treated as undefined. `SOME_VAR: z.string()` and
   * `SOME_VAR=''` will throw an error.
   */
  emptyStringAsUndefined: true,
});

```

### src/components/CanvasWrapper.tsx

```typescript
import dynamic from "next/dynamic";

const CanvasDraw = dynamic(() => import("./Canvas"), {
  ssr: false,
});

export default CanvasDraw;

```

### src/pages/draw.tsx

```typescript
import * as React from "react";
import CanvasWrapper from "../components/CanvasWrapper";

export default function Index() {
  return <CanvasWrapper />;
}

```

### src/pages/signout.tsx

```typescript
import { signOut } from "next-auth/react"

const Signout = () => {
    return <button onClick={() => signOut({ callbackUrl: "/" })}>Sign out</button>
}

export default Signout;
```

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