Build a Digital Pet Game - Build a Digital Pet Game

Tell us what’s happening:

Hi everyone,

I’m working on the Digital Pet Game lab and keep failing the first test:

“When the page loads, there should be a visible form element.”

Because of this, tests 1-10 continue to fail, and I suspect the issue is affecting the rest of the test suite as well.

I’ve tried different approaches, but the test runner still doesn’t detect the form correctly. Has anyone experienced this issue or can point me in the right direction?

Any help would be greatly appreciated. Thanks…

Your code so far

<!-- file: index.html -->
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Digital Pet Game</title>

    <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=Tektur:wght@400..900&display=swap" rel="stylesheet">

        <link rel="stylesheet" href="styles.css" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.development.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.development.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.26.5/babel.min.js"></script>
    <script
      data-plugins="transform-modules-umd"
      type="text/babel"
      src="index.tsx"
    ></script>
  </head>
  <body>
    <div id="root"></div>
    <script
      data-plugins="transform-modules-umd"
      type="text/babel"
      data-presets="react"
      data-type="module"
    >
      import { PetGame } from './index.tsx';
      ReactDOM.createRoot(document.getElementById('root')).render(<PetGame />);
    </script>
  </body>
</html>
/* file: index.tsx */

const { useState, useEffect } = React;

enum PetMood {
  HAPPY = "HAPPY",
  EXCITED = "EXCITED",
  CONTENT = "CONTENT",
  SAD = "SAD",
  TIRED = "TIRED",
  SICK = "SICK",
  HUNGRY = "HUNGRY",
}

enum PetAction {
  EAT = "EAT",
  PLAY = "PLAY",
  SLEEP = "SLEEP",
}

const moodEmoji: Record<PetMood, string> = {
  [PetMood.HAPPY]: "😊",
  [PetMood.EXCITED]: "🤩",
  [PetMood.CONTENT]: "🙂",
  [PetMood.SAD]: "😢",
  [PetMood.TIRED]: "😴",
  [PetMood.SICK]: "🤒",
  [PetMood.HUNGRY]: "🍔",
};

export const PetGame = () => {
  const [petName, setPetName] = useState("");
  const [started, setStarted] = useState(false);

  const [hunger, setHunger] = useState(0);
  const [energy, setEnergy] = useState(100);
  const [happiness, setHappiness] = useState(100);

  useEffect(() => {
    if (!started) return;

    const timer = setTimeout(() => {
      setHunger(100);
      setEnergy(100);
      setHappiness(0);
    }, 5000);

    return () => clearTimeout(timer);
  }, [started]);

  const startGame = (e) => {
    e.preventDefault();

    const input = document.getElementById(
      "pet-name"
    ) as HTMLInputElement;

    if (input && input.value.trim()) {
      setPetName(input.value);
      setStarted(true);
    }
  };

  const performAction = (action: PetAction) => {
    switch (action) {
      case PetAction.EAT:
        if (hunger > 0) {
          setHunger((h) => Math.max(0, h - 10));
        }

        if (energy < 100) {
          setEnergy((e) => Math.min(100, e + 10));
        }
        break;

      case PetAction.PLAY:
        if (energy > 0) {
          setEnergy((e) => Math.max(0, e - 10));
        }

        if (happiness < 100) {
          setHappiness((h) => Math.min(100, h + 10));
        }
        break;

      case PetAction.SLEEP:
        if (hunger < 100) {
          setHunger((h) => Math.min(100, h + 10));
        }

        if (energy < 100) {
          setEnergy((e) => Math.min(100, e + 10));
        }
        break;
    }
  };

  let mood: PetMood = PetMood.CONTENT;

  if (hunger > 70) {
    mood = PetMood.HUNGRY;
  } else if (energy < 30) {
    mood = PetMood.TIRED;
  } else if (happiness < 30) {
    mood = PetMood.SAD;
  } else if (happiness > 80 && energy > 70) {
    mood = PetMood.EXCITED;
  } else if (happiness > 60) {
    mood = PetMood.HAPPY;
  }

  return (
    <div>
      {!started ? (
        <form onSubmit={startGame}>
          <label htmlFor="pet-name">
            Name your pet
          </label>

          <input
            id="pet-name"
            type="text"
          />

          <button type="submit">
            Start Game
          </button>
        </form>
      ) : (
        <div>
          <div className="pet-name">
            {petName}
          </div>

          <div>{moodEmoji[mood]}</div>

          <div className="stat">
            Hunger
            <span className="stat-value">
              {hunger}
            </span>
          </div>

          <div className="stat">
            Energy
            <span className="stat-value">
              {energy}
            </span>
          </div>

          <div className="stat">
            Happiness
            <span className="stat-value">
              {happiness}
            </span>
          </div>

          <button
            id="eat-action"
            onClick={() =>
              performAction(PetAction.EAT)
            }
          >
            EAT
          </button>

          <button
            id="play-action"
            onClick={() =>
              performAction(PetAction.PLAY)
            }
          >
            PLAY
          </button>

          <button
            id="sleep-action"
            onClick={() =>
              performAction(PetAction.SLEEP)
            }
          >
            SLEEP
          </button>
        </div>
      )}
    </div>
  );
};

/* file: styles.css */
:root {
  /* Backgrounds */
  --bg-gradient-start: #dbeafe;
  --bg-gradient-mid: #faf5ff;
  --bg-gradient-end: #fce7f3;

  /* Text */
  --text-primary: #1f2937;
  --text-muted: #6b7280;
  --text-muted-2: #9ca3af;

  /* Card / surface */
  --card-bg-translucent: rgba(255, 255, 255, 0.6);
  --card-bg-solid: rgba(255, 255, 255, 0.8);

  /* Accent / brand */
  --accent-purple: #8b5cf6;
  --accent-purple-dark: #7c3aed;

  /* Actions */
  --action-feed: #10b981;
  --action-feed-dark: #059669;
  --action-play: #3b82f6;
  --action-play-dark: #2563eb;
  --action-sleep: #8b5cf6;
  --action-sleep-dark: #7c3aed;
  --action-heal: #ec4899;
  --action-heal-dark: #db2777;

  /* Stats */
  --stat-high: #10b981;
  --stat-medium: #f59e0b;
  --stat-low: #ef4444;

  /* UI greys */
  --ui-bg-light: #e5e7eb;
  --ui-fill: #8b5cf6; /* used for exp fill as accent */

  /* Shadows */
  --shadow-strong: rgba(0, 0, 0, 0.25);
  --shadow-soft: rgba(0, 0, 0, 0.1);
}

html {
  /*color-scheme: light dark;*/
  font-family: system-ui;
  display: flex;
  justify-content: center;
  font-family:
    -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu",
    "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  background: linear-gradient(135deg, #dbeafe 0%, #faf5ff 50%, #fce7f3 100%);
  min-height: 100vh;
  padding: 1rem;
}

header {
  text-align: center;
  margin-bottom: 2rem;
}

body {
  max-width: 400px;
}

.base-container {
  background: rgba(255, 255, 255, 0.6);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border-radius: 1.5rem;
  padding: 2rem;
  box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
  .pet-name {
    text-align: center;
  }
}

.game-container {
  margin-bottom: 1.5rem;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

/* Stats Grid */
.stats-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1rem;
  margin-bottom: 1.5rem;
}

.stat-bar {
  background: rgba(255, 255, 255, 0.8);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border-radius: 0.75rem;
  padding: 1rem;
  box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1);
  transition: all 0.2s ease;
}

.stat-bar:hover {
  box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
}

.stat-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 0.5rem;
}

.stat-label {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.stat-icon {
  font-size: 1.25rem;
}

.stat-name {
  font-weight: 500;
  color: #374151;
}

.stat-value {
  font-weight: bold;
  color: #1f2937;
}

.stat-progress {
  width: 100%;
  height: 0.75rem;
  background: #e5e7eb;
  border-radius: 9999px;
  overflow: hidden;
}

.stat-fill {
  height: 100%;
  transition: width 0.5s ease-out;
  border-radius: 9999px;
}

.stat-fill.high {
  background: #10b981;
}

.stat-fill.medium {
  background: #f59e0b;
}

.stat-fill.low {
  background: #ef4444;
}

.pet-buttons {
  width: auto;
  display: flex;
  flex-direction: row;
  gap: 1rem;
}

.pet-buttons .pet-button {
  min-width: 80px;
  background: #c2214a;
  color: white;
  border-radius: 13%;
  border-style: solid;
  border-color: #870b04;
  box-shadow: rgba(120, 25, 23, 0.2) 2px 2px 4px 2px;
  &:active {
    transform: scale(0.95);
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15) inset;
  }
  text-align: center;
  cursor: pointer;
  padding: 0.5rem 1rem;
}

.pet-sprite {
  font-size: xxx-large;
  text-align: center;
}

.data-management * {
  margin: 0 0.5rem 0 0;
}

.info-panel {
  text-align: center;
}
.info-panel #hud,
.info-panel .start-questions {
  display: flex;
  align-items: center;
  flex-direction: column;
  gap: 1rem;
}

.info-panel #hud p {
  margin: 0rem;
}

.info-panel .start-questions div * {
  margin: 0 0.5rem 0 0;
}

#pet-fact {
  color: var(--text-muted-2);
  margin: 0 0 0.5rem 0;
}
#set-name-btn {
  display: inline-block;
  padding: 14px 28px;
  font-size: 1.15rem;
  font-weight: 600;
  background: linear-gradient(135deg, #6b8cff, #5ec2ff);
  color: #fff;
  border: none;
  border-radius: 10px;
  box-shadow: 0 6px 18px rgba(92, 132, 255, 0.25);
  cursor: pointer;
  transition:
    transform 0.08s ease,
    box-shadow 0.12s ease,
    opacity 0.12s;
}

#set-name-btn:hover {
  opacity: 0.98;
}

#set-name-btn:active,
#set-name-btn.pressed {
  transform: translateY(2px) scale(0.995);
  box-shadow: 0 3px 8px rgba(92, 132, 255, 0.18);
}

#set-name-btn:focus {
  outline: 3px solid rgba(94, 190, 255, 0.28);
  outline-offset: 2px;
}

Your browser information:

User Agent is: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36 Edg/149.0.0.0

Challenge Information:

Build a Digital Pet Game - Build a Digital Pet Game

GitHub Link: freeCodeCamp/curriculum/challenges/english/blocks/lab-digital-pet-game/68c362b379059c388d3874f2.md at main · freeCodeCamp/freeCodeCamp · GitHub

hello!

there is an error in the challenge console that says –

Error: index.tsx(51,22): error TS7006: Parameter 'e' implicitly has an 'any' type.

this is probably about the e parameter in your startGame function. try to declare its type as well (React has type definitions for various events).

Hi Sampatee,

Thank you so much for your help and for taking the time to assist me. I really appreciate it :folded_hands: