---
# System prepended metadata

title: 'MSTU5003 Final: easytypING'

---

# <mark style="background-color: black; color: white;">**Website Name: easytypING**</mark>
> Course: MSTU5003 Section: 004
> Assignment: Project: Final
> Codepen: https://codepen.io/zl3323/pen/qBgegZz
> Group Members:
> 1. Zehao Li, zl3323
> 2. Yiran Yuan, yy3368
> 3. Suzy Wang, sw3821
> 4. Yu Fu, yf2674


# <mark style="background-color: black; color: white;">*1. What this is?*</mark>

## 1.1 Problem: 

<p>Typing has become an essential skill in today's digital world, facilitating tasks like essay writing, research, and email communication. However, this process can often feel boring, simply tapping away at the keyboard. For those eager to acquire this skill, finding a free and developed platform can be challenging.
</p>

## 1.2 Target Audience:

<p>Typing novices of all ages
</p>

## 1.3 Goals:

<p>For the online platform of our project, we hope to:

* empower the acquisition of typing skills for typing novices.

* present an engaging and interactive approach through a diverse array of practices and games.

* offering free sign-ups, ensuring accessibility for all eager learners.

* foster confidence in navigating the keyboard in the prevailing digital trend.

</p>

# <mark style="background-color: black; color: white;">*2. WireFrame/User Journey*</mark>

<p>
The structure of our website includes several key pages: a main page, a sign-up page, a sign-in page, an activity preview page, a word typing practice page, a sentence typing practice page, and a type fall game page. Each page is equipped with buttons facilitating users to move to the next page or return to the previous one.

The following points explicitly explain key components of our website and how users navigate through:

</p>

## 2.1 Main Page
<p>
Upon entering our website, title "easytyping" appears on the left side of the menu bar, accompanied by three buttons on the right. Clicking each button smoothly scrolls users to specific sections of the main page.
</p>

### Homepage:
<ol>
<li>
    New users clicking the "Sign Up" button are directed to the sign-up page.</li>
<li>Returning users clicking the "Sign In" button are directed to the sign-in page.</li>
</ol>
    
### About:
<ol>
<li>
    It provides information about the goals of our website.</li>
</ol>

### Contact:
<ol>
<li>
    Users can submit inquiries if they have any questions or require assistance.
</li>
</ol>

## 2.2 Sign-up Page
<ol>
    <li>
Users create a free account by completing the required fields.
</li>
    <li>
Afterward, they proceed to the sign-in page to access typing activities.
</li>
    </ol>

## 2.3 Sign-in Page
<ol>
    <li>Users enter their account information and access typing activities.
</li>
    
</ol>

## 2.4 Activity Preview Page
<p>
After the successful sign-in, users will be directed to the activity preview page, offering a choice between different types of typing activities. Practices focus on skill development while games bring joy. They both are interactive.
</p>
<ol>
    <li>
Practices: Currently, two practice activities are available - Word Typing and Sentence Typing. Clicking on the respective image directs users to the chosen practice activity.
</li>
    <li>
Games: Currently, one game activity is available - Type Fall. Clicking on the image directs users to the game.
</li>   
</ol>

## 2.5 Word Typing Practice Page
<p>
At the start, the interface displays the remaining time, accuracy, and the count of errors made.
</p>
<ol>
    <li>
Click on the "Music" button in the top left corner for background music.</li>
    <li>
When users' are ready, initiate the practice by clicking the area marked "start typing here".</li>
    <li>
The goal is to swiftly and accurately type the word displayed at the top.
</li>
    <li>
The purpose of the practice is to enhance user’s typing accuracy.
</li>
    <li>If an error is made, the mistyped letter will be highlighted in red. Users need to delete and correct it accordingly in order to proceed.
</li>
    <li>Upon completing three attempts of this practice activity, users will progress to the next level, which involves sentence typing practice.
</li>
</ol>

## 2.6 Sentence Typing Practice Page
<p>
    At the start, the interface displays the remaining time, accuracy, typing speed, and the count of errors made.
</p>

<ol>
    <li>
Click on the "Play Music" button in the top left corner for background music.</li>
    <li>
The goal is to swiftly and accurately type the sentence displayed at the top.
</li>
    <li>
The purpose of the practice is to enhance user’s typing speed.
</li>
    <li>
If an error is made, the mistyped letter will be highlighted in red. But users can choose to delete and correct it accordingly or continue typing.
</li>
    <li>To make another attempt, simply hit the "Restart" button.
</li>
</ol>

## 2.7 Type Fall Game Page
<p>
    At the start, the interface displays the remaining time and accumulated points.
</p>
<ol>
    <li>Prior to starting the game, select the speed setting.</li>
    <li>As letters fall, use the keyboard to tap the corresponding letter. Doing so will make the letter fade away and earn a point.</li>
<li>Correctly tapping a falling letter will also produce a sound effect.</li>
</ol>


# <mark style="background-color: black; color: white;">*3. Main Functions of JavaScript*</mark>

## 3.1 Scroll
```function scrollToContact() {
var targetDiv = document.getElementById('contact');
targetDiv.scrollIntoView({ behavior: 'smooth' });
}

function scrollToAbout() {
var targetDiv = document.getElementById('about');
targetDiv.scrollIntoView({ behavior: 'smooth' });
}
```
<p>
    The parent element \<ul\> has three list items of the children element \<li\>. The \<div\> elements with ids 'about' and 'contact' serve as anchor points for smooth scrolling when the corresponding navigation link (href="#about", href="#contact") are clicked. When users click on a navigation link, an 'onclick' event triggers a JavaScript function called 'scrollToDic(sectionID)', invoked with the 'sectionID' parameter, representing the ID of the section to scroll to. When the function is triggered, it will retrieve the specific section target for scrolling and then undergoes the 'scrollIntoView' method to instruct the scrolling effect with the inserted property of smooth behavior.
</p>

## 3.2 Page Transition
<p>
    To achieve page transition in Codepen, I used the \<div\> elements to group each page into different sections. Then, using the querying DOM elements:
    </p>
    
```javascript
    let mainPage = document.querySelector(".main-page");
```
<p>
    I selected the HTML elements with specific class names. The selected elements represent different pages of the web application.

Next, I used the ‘display’ property, to effectively hide all pages when the script is first executed. 
    </p> 
    ```
    signUpPage.style.display = "none";
    ```
<p>
        The following functions handle page transitions by showing one specific page and hiding the rest:
    </p>
    
```javascript
goToSignUp():  Displays the sign-up page and hides other pages.
goToMainPage(): Displays the main page and hides other pages.
goToSignIn(): Displays the sign-in page and hides other pages.
goToPreview(): Displays the preview page and hides other pages.
backToPreview(): Clears intervals, shows the game cover, hides the game area, and then goes to the preview page.
goToWordTyping(): Displays the word typing page and hides other pages.
goToSentenceTyping(): Displays the sentence typing page and hides other pages.
goToGameTyping(): Displays the game typing page and hides other pages.
```
## 3.3 Forms
<p>
    There are 3 forms used in this website: Contact, Sign-Up, and Sign- In. 

In the contact form, the code uses document.getElementById to retrieve references to three HTML elements with specific IDs: "name1," "e-mail1," and "comments1."
    </p>

```javascript
var name = document.getElementById("name1");
var email = document.getElementById("e-mail1");
var comments = document.getElementById("comments1");
```
<p>
    The if statement checks whether any of the form fields (name, email, or comments) are empty. If at least one of them is empty, it displays an alert with the message "Please fill in all fields." This serves as a basic validation to make sure that the user provides information in all required fields before submitting the form.
    </p>
    
```javascript
if (name.value === "" || email.value === "" || comments.value === "") {
    alert("Please fill in all fields");
} else {
 }
```
    
<p>
    If all fields are filled (i.e., the else block), it displays an alert with the message "Message Submitted!" indicating that the form submission was successful. Additionally, it clears the values in the name, email, and comments fields, presumably to reset the form for potential subsequent submissions.
    </p>
    
```javascript
alert("Message Submitted!");
name.value = "";
email.value = "";
comments.value = "";
``` 
 <p>
     In the sign-up form, I used query selectors to retrieve the values entered by the user in different input fields of a registration form. The IDs such as "age," "experience," "signupEmail," etc., correspond to various form fields. Below shows one of the value examples:
    </p> 
    
```javascript
let userAge = document.querySelector("#age").value;
```   
    
<p>
       Then, I used form validation to check for the validity. If any required field is empty, it displays an alert instructing the user to fill out all spaces. If the confirmation password does not match the original password, it alerts the user. In addition, it checks if the user has accepted the agreements and policy: 
    </p>
    
```javascript
if (!userAge || !userExperience || !userEmail || !userName || !userPassword || !userFirstName || !userConfirmPassword) {
  alert("Please fill out all spaces");
  return null;
}
if (userConfirmPassword != userPassword) {
  alert("Passwords do not match!");
  return null;
}
if (!privacyCheck) {
  alert("Please accept the agreement and policy!");
  return null;
}
```

<p>
        If the form data passes through the validity check, then the new object ‘newUser’ is created. This object is then pushed into the ‘userArray’ to store the information. 
</p>

```javascript
let newUser = {};
newUser.age = userAge;
newUser.experience = userExperience;
newUser.email = userEmail;
newUser.username = userName;
newUser.password = userPassword;
newUser.firstName = userFirstName;
userArray.push(newUser);
```
<p>
    Then, after storing the information, the section resets the form and calls the function ‘goToSignIn()’ and takes the user to the sign-in page.
    </p>

```javascript
userAge = document.querySelector("#age").value = "";
privacyCheck = document.querySelector("#privacy").checked = false;
goToSignIn();
```
<p>
    For the sign-in form, first, the variables are declared. Again, these lines retrieve references to HTML elements with the IDs "signInUsername" and "signInPassword."
    </p>
    
```javascript
var signInUsername = document.getElementById("signInUsername");
var signInPassword = document.getElementById("signInPassword");
```
<p>
    The if statement checks whether either the username or the password field is empty. If any of them is empty, it displays an alert with the message "Please fill in all fields. And if the user has entered the values in the fields, the message “Signed In Successfully!” will be displayed and will call the function goToPreview() to go to the preview page.
    </p>
    
```javascript
if (signInUsername.value === "" || signInPassword.value === "" ) {
    alert("Please fill in all fields");
  } else {
    alert("Signed In Successfully!");
    signInUsername.value = "";
    signInPassword.value = "";
    goToPreview();
  }
}
```
## 3.3 Word Typing Practice Page
<p>
    The two typing practices in JavaScript is quite similar, but there are some subtle differences. The following section will focus on the core, most engaging, yet challenging JavaScript functions of the two games:
    </p>
    
<ol>
    <li>**Updating Words and Rollover Mechanism**</li>
<p>
    The `updateWord` function is crucial for displaying the new word for the user to type and handling the rollover of words. Here's a detailed breakdown:
    </p>
    
```javascript
function updateWord() {
  quote_text.textContent = null; // Clears the current displayed word
  current_word = words_array[wordIndex]; // Selects a new word from the array

  // Splits the word into individual characters and creates a span for each
  current_word.split("").forEach((char) => {
    const charSpan = document.createElement("span");
    charSpan.innerText = char;
    quote_text.appendChild(charSpan);
  });

  // Rollover logic
  if (wordIndex < words_array.length - 1) wordIndex++;
  else wordIndex = 0;
}
```
<p>
        The function first clears any existing text in the `quote_text` element.
It then selects the next word in the `words_array` using the `wordIndex` variable.
The selected word is split into individual characters, and each character is wrapped in a span element. This allows for individual styling of each character.
The `wordIndex `is then incremented to point to the next word in the array. If the end of the array is reached (i.e., wordIndex is at the last item), it resets to 0, enabling the rollover effect.

</p>

<li>**Letter-by-Letter Formatting**</li>
<p>
    The `processCurrentText` function plays a critical role in providing real-time feedback to the user by formatting each letter they type.
</p>
    
```javascript
function processCurrentText() {
  let curr_input = input_area.value;  // 1. Capturing User Input
  let curr_input_array = curr_input.split("");  // 2. Splitting Input into Characters

  let charSpanArray = quote_text.querySelectorAll("span");  // 3. Selecting Character Spans
  charSpanArray.forEach((charSpan, index) => {  // 4. Iterating Over Each Character Span
    let typedChar = curr_input_array[index];  // 5. Retrieving the Corresponding Typed Character

    // 6. Comparing and Applying Styling
    if (typedChar == null) {
      charSpan.classList.remove("correct_char", "incorrect_char");
    } else if (typedChar === charSpan.innerText) {
      charSpan.classList.add("correct_char");
      charSpan.classList.remove("incorrect_char");
    } else {
      charSpan.classList.add("incorrect_char");
      charSpan.classList.remove("correct_char");
    }
  });
  // Additional ...
}
```
<p>
        This function is triggered each time the user types a character.
It splits the current input into an array of characters and compares each character with the corresponding character in the current word.
For each character in the input, it applies a CSS class to indicate whether it's correct (`correct_char`) or incorrect (`incorrect_char`). This real-time feedback helps the user to correct mistakes on the fly.
    </p>
    <li>**Calculating Accuracy and Errors**
</li>
    <p>
        The accuracy and error calculations provide insight into the user's typing performance.
    </p>
    
```javascript
// Updating Errors
  if (wordError) {
    total_errors++;  // Increment total_errors if the current word has an error
  }
  error_text.textContent = total_errors;

  // Checking if the word is completely and correctly typed
  if (curr_input === current_word) {
    updateWord();  // Update to the next word
    input_area.value = "";  // Clear the input area for the next word
  }
}
```
<p>
    
**Error Tracking:**
The `wordError` flag is introduced to track if there is an error in the current word.
As the user types, if any character does not match the expected character, `wordError` is set to true.

**Updating Error Count:**
After iterating through all characters, if `wordError` is true, it indicates that the user made a mistake while typing the current word.
In this case, the total error count (`total_errors`) is incremented.
The error count is then updated in the corresponding display element (`error_text`).

**Progressing to the Next Word:**
The function checks if the user's input (`curr_input`) matches the entire current word (`current_word`).
If there is a match, it means the user has correctly typed the whole word. The function then calls `updateWord()` to display the next word. It also clears the input area (`input_area.value = ""`), preparing for the user to start typing the new word.
</p>
    
```javascript
  // Calculate and display accuracy
  if (characterTyped > 0) {
    let accuracy = (1 - total_errors / characterTyped) * 100;
    accuracy = Math.max(0, Math.min(accuracy, 100));
    accuracy_text.textContent = Math.round(accuracy) + "%";
  } else {
    accuracy_text.textContent = "0%";
  }
```
<p>
    
**Tracking Correct Characters:**
A new variable `correctChars` is introduced to keep track of the number of characters correctly typed by the user.

**Calculating Accuracy:**
After processing each character, the function calculates the accuracy.
The accuracy is the ratio of `correctChars` to the total number of characters the user has typed (`curr_input_array.length`).
This ratio is then multiplied by 100 to convert it into a percentage.

**Updating Accuracy Display:**
The calculated accuracy is rounded to the nearest whole number and displayed in the `accuracy_text` element.
This provides the user with real-time feedback on how accurately they are typing.
</p>
</ol>
    
## 3.4 Sentence Typing Practice Page
<ol>
    <li>**Progressing to the Next Sentence**</li>
    
<p>
        When comparing the logic of progressing to the next word or sentence in Typing Practice I and Typing Practice II, a key difference emerges in how they handle user input and errors.
</p>
    
```javascript
    if (curr_input.length == current_quote_2.length) { 
  updateQuote_2();  // Update to the next quote
  total_errors_2 += errors_2; 
  input_area_2.value = "";  // Clear the input area for the next quote
}
```
<p>
    
**Sentence Completion Check:**
The function checks if the length of the user's input (`curr_input`) matches the length of the current quote (`current_quote_2`).
This comparison determines if the user has finished typing the entire quote.

**Updating to Next Quote:**
If the user has completed the quote, `updateQuote_2()` is called to display the next quote in `quotes_array_2`.
The function also updates the total error count (`total_errors_2`) with the errors made in the current quote (`errors_2`).
    
**Resetting Input Area:**
After updating the quote, the input area is cleared (`input_area_2.value = ""`), readying it for the user to start typing the new quote.
    
**Purpose:**
Typing Practice II’s approach is more lenient regarding errors, focusing more on typing speed. It simulates a more realistic typing scenario where maintaining a flow and speed is important, even if minor errors occur.
This method is beneficial for practicing speed typing, where users learn to maintain momentum while typing extensive content.
    </p>
    <li>**Calculating CPM and WPM**</li>
    <p>
        Unlike , Typing Practice II which focuses primarily on accuracy, Typing Practice II emphasizes typing speed. Calculating CPM and WPM aligns with its objective of improving the user's typing speed. These metrics provide users with a quantitative assessment of their typing performance, making them aware of their speed and encouraging them to improve.
    </p>
```javascript
    function finishGame_2() { 
  let cpm = Math.round(((characterTyped_2 / timeElapsed_2) * 60)); 
  let wpm = Math.round((((characterTyped_2 / 5) / timeElapsed_2) * 60)); 
  cpm_text_2.textContent = cpm; 
  wpm_text_2.textContent = wpm; 
}
```
<p>
    
**CPM Calculation:**
Characters Per Minute (CPM) is calculated by dividing the total number of characters typed (`characterTyped_2`) by the total time elapsed in minutes (`timeElapsed_2`).
The result is then rounded and displayed in `cpm_text_2`.
    
**WPM Calculation:**
Words Per Minute (WPM) is estimated by assuming an average of 5 characters per word.
The total characters typed are divided by 5 to get an approximate word count, which is then divided by the time elapsed in minutes.
The final WPM value is rounded and displayed in `wpm_text_2`.
    
**Function Trigger:**
`finishGame_2()` is called when the game timer reaches zero, concluding the game and displaying the user's typing speed metrics.
    
These functions together create a responsive and engaging typing experience, encouraging the user to improve their typing accuracy and speed while providing clear and immediate feedback on their performance.
    </p>
    </ol>

## 3.5 Type Fall Game

<p>
Overall, the core logic of this game includes dynamically creating and manipulating DOM elements (create, modify, or delete HTML elements, i.e., letters, in real-time), handling events, and updating game status. 

Key functionalities include: 1) game initialization; 2) letter creation and movement; 3) score and time left value tracking; and 4) game ending conditions.

To better understand the typing game, especially the JavaScript section, the following part will explain the codes by different functions.
</p>
    
<ol>
    <li>Game Initialization:
</li>
<p>

We set two initial variables at the beginning, `score` and `life` with the value “0” and “50”, respectively, which is a visible element recording interaction between the game and users.
    
`gameInterval` was set to control the main loop of the game. It is commonly used for some periodical tasks in coding. 
It works through the `setInterval` function. That is to say, when the `startGame` function is called, `setInterval` is set to periodically execute the `createAndMoveLetter` function. 
The `speed` variable, which is selected by users before they start the game, determines how often the `setInterval` function is executed. This is calculated by dividing 5000 by the selected speed value, resulting in the time interval (in milliseconds) between two executions of the `createAndMoveLetter` function.
</p>
    <li>startGame Function:</li>
<p>

This function checks if a game speed is selected. If not, an alert will pop up to notify the users.
    
It also hides the cover page by using the same method as we mentioned for going to different pages.
```javascript
E.g., document.getElementById('gameCover').style.display = 'none'
```
    
It displays the game area page and resets scores and life.
</p>
    <li>createAndMoveLetter Function:</li>
<p>
This function dynamically creates a letter element, which is one of the core functions of a typing game.

The function will also assign the letter a random position and implement its downward movement. This function will increase the difficulty and engagement of the game.
```javascript
E.g., letter.style.left = ${Math.floor(Math.random() * 90)}%;
```
`Math.random` function will generate a random number between 0 and 1, and the times 90, which will put every single letter in a random position between 0% and 90% horizontal position
`Math.floor` function will ensure that the left margin (`left` attribute in the whole function) of each letter will be some integer percentage between 0% and 90%
</p>
    <li>updateScoreBoard Function:</li>
<p>
First part of the function is updating the score and the left time in real-time. Those two variables are visible to users on the game area page.

Besides, the function will visually adjust the life bar based on the remaining life.
`(life / 50) * 100%`, this formula calculates the current life as a percentage of full and converts it to a percentage of the width. Then, update it by changing the `style.width` property.
</p>
    <li>endGame Function:</li>
<p>
This function clears the game interval and alerts the player of their score when the game ends.

When users achieve any of the two conditions, `endGame` function will be called.
```javascript
if (life <= 0) endGame();
if (score >= 50) endGame();
```
In either case, once `endGame` is triggered, the function first clears the `gameInterval`, which means it stops generating new letters. After that, it will then pop up an alert to inform the player that the game is over and show them their score.
</p>
    
<li>EventListener:</li>
<p>
The game listens for a click on the start button to initiate gameplay and key-down events to match letters and update scores.   

```javascript
document.getElementById('startButton').addEventListener('click', startGame);
```
    
The above event listener is used to play the game interactively by clicking the start button.
    
```javascript
document.addEventListener('keydown', (e) => { /*
```
The second one works for the entire document to detect when the player presses any key on the keyboard. This event listener can response to users’ input and update the game status in real-time.
When the player presses a key, the listener triggers and checks all letter elements on the page to see if any letter corresponds to the key pressed.
If a match is found, the letter is removed, the player's score is increased, and a sound effect is played.
</p>
    </ol>
    
# <mark style="background-color: black; color: white;">*4. Main Functions of CSS*</mark>
<p>
    Besides JS functions, we also input various css code that can make our website interactive and engaging.
    </p>
    
## 4.1 Color Scheme
<p>
    The theme is unified with a combination of white and gray-ish colors for backgrounds and texts. Examples include '#fff', '#f0f0f0',  and 'rgba(0, 0, 0, 0.6)', providing a clean and visually appealing interface.
    </p>
    
## 4.2 Font Style
<p>
        The website uses an external resource of a pixel art style font to maintain a unique visual identity.
        
```css
<link href="https://fonts.googleapis.com/css?family=Press+Start+2P" rel="stylesheet">
<link href="https://unpkg.com/nes.css/css/nes.css" rel="stylesheet" />
```
</p>
## 4.3 Hover Effect
    <p>
        Hovering over list items on the main page ("Homepage", “About”, “Contact”) triggers a color change effect. The text color shifts from '#fff' to black, while the background transforms from black to' #fff' within 0.3s. This provides a visual cue, signaling anticipation for a click action.

Hovering over images in the activity preview page applies a transformative effect, magnifying them by a factor of 1.1. This magnification adds a touch of interactivity, engaging users visually.
</p>
    
## 4.4 Page Layout
<p>
        The website's overall layout predominantly uses 'justify-content: center' to center most content. It enhances visualization and readability, ensuring a focused and organized presentation of information.

The About section of the main page uses '@media screen and (max-width: 768px)' to optimize responsiveness. This helps adjusting specific elements when the screen size is smaller, optimizing the display for mobile devices.
</p>
    
    
# <mark style="background-color: black; color: white;">*5. Challenges & Struggles*</mark>
    
<p>
        Our project encountered two main challenges. Firstly, we struggled with the technical aspect, particularly in establishing connections between different pages for redirection. Initially, we explored the possibility of achieving page jumping in CodePen, only to discover its limitations in URL redirection. Fortunately, our TA suggested a workaround: encapsulating each page within a \<div\> element and toggling their visibility using JavaScript. While this approach seemed logical, its implementation took longer than expected. Using the hide and show method for page navigation posed the biggest issue: consolidating all seven pages' code into a single CodePen. This made the debugging process frustrating. Additionally, using the hide and show method in JavaScript was a new knowledge for us. Adapting the logic to ensure that when one page is displayed, others are hidden involves manipulating the JavaScript function to alter the display style between 'block' or 'none'. Secondly, regarding teamwork, our struggles emerged during the code integration phase. Initially, each team member handled a specific page of coding. However, during the consolidation phase, overlapping class names became a significant issue, impacting our CSS. To address this, we introduced 'id' elements to the repeated classes, allowing for more precise targeting of elements. Despite this solution, combining the code resulted in a slightly messy final product, as the sequence of elements and styles was disrupted, making it more challenging to maintain cleanliness and coherence in the codebase.
    </p>
    
# <mark style="background-color: black; color: white;">*6. Reflections*</mark>
## Yiran Yuan
<p>
As a coding novice, I feel nervous entering this class, particularly due to not feeling confident in logic-related areas. I really struggle a little bit in writing codes when numerous new coding terms and functions come in at once. However, at the same time, I have learned a lot. Most importantly, I am able to read code now! I can briefly explain how each line works and its effect on display. I learned that the basic structure of HTML should include \<head\> and \<body\>, and I always remember to use closing tags! I've learned how to insert a picture, a form and a button. To differentiate different elements, I can give them a class or id. For CSS, I learned to use a dot for class selectors and a hashtag for id selectors. Also, there are more selectors we can use in complex scenarios. In JavaScript, I learned about different types of data, such as string, number, boolean, array, function, and object. Additionally, I learned how to use event listeners on HTML elements to interact with user inputs.
         </p>
    
## Suzy Wang
<p>
This semester, I have familiarized myself with HTML, CSS, and Javascript. I learned how they are related to each other, as well as how to link them together for a creation to function. At first, coding seemed so intimidating and distant, but throughout the semester, I was able to take small steps in understanding them, and eventually be able to code something cool on my own. I learned computational thinking, which breaks down designs at technical and granular levels. I started to look at and analyze different designs in a way I had never done before. Learning about JavaScript has also helped greatly with my logical thinking ability, as it is all about building up your own system of logic, and how you want your code to work. 
    </p>
    
## Yu Fu
<p>
When I first started this course, I was nervous about the unknown world of coding, especially given my minimal experience in logical thinking. The initial challenge was an influx of new codes and programming concepts. Despite these difficulties, my path has been rewarding. I've learnt to comprehend code, which was previously unknown to me. I can now explain what every line of code performs and how it impacts the entire application. My comprehension of HTML fundamentals has also deepened through different doodles and projects. I've also gotten better at adding interactive features to web pages, and by learning JavaScript, I investigated different data types and the usage of different functions. This course has fundamentally shifted my approach to problem-solving and analytical thinking in coding.Besides, I particularly enjoyed building up the final project in the past two weeks, which enabled me to apply what I've learnt into real world scenarios.
</p>
    
## Zehao Li
<p>
Reflecting on the coding learning over the past semester, starting from scratch, I have to say that I was initially overwhelmed by the complexity of different programming languages, and they drove me crazy. However, I do find something that encouraged me to learn: coding is like a point where creativity and thinking meet logic.
Through projects like crafting my personal webpage, simulating a dryer machine, developing a web for English teachers, creating interactive Canva, and finally, the multi-page typing game website, I have gained the understanding that HTML provides a method of laying out content in a meaningful and accessible way; CSS provides how to style and animate elements to attract audiences (which I love the most, and I do spend a lot of time on that for each project); JS, which makes my project alive by bringing interactivity and dynamicity (btw, I also like that, but it is much more difficult, so it may rank the NO.2).
Those projects that I mentioned, especially the final typing web, include and also show all the skills I have acquired from the course, e.g., DOM manipulation, conditional logic, etc. Even though keeping coding consistent within group projects, debugging codes, and learning new functions often felt like getting lost in a huge maze, I still want to explore more and feel excited about transferring my ideas into a real, interactive, functional project.
</p>

