softchris-patch-9
chris 1 month ago
parent 290b8248ab
commit fe82727158

@ -1,10 +1,10 @@
# AI Framework
Ever felt overwhelmed trying to build AI applications from scratch? You're not alone! AI frameworks are like having a Swiss Army knife for AI development - they're powerful tools that can save you tons of time and headaches when building intelligent applications. Think of an AI framework as your coding best friend: it provides pre-built components, standardized APIs, and smart abstractions so you can focus on solving cool problems instead of wrestling with boring implementation details.
Ever felt overwhelmed trying to build AI applications from scratch? You're not alone! AI frameworks are like having a Swiss Army knife for AI development - they're powerful tools that can save you time and headaches when building intelligent applications. Think of an AI framework as a well-organized library: it provides pre-built components, standardized APIs, and smart abstractions so you can focus on solving problems instead of wrestling with implementation details.
In this lesson, we're going to explore how frameworks like LangChain can turn what used to be complex, hair-pulling AI integration tasks into clean, readable code that actually makes sense. You'll discover how to tackle real-world challenges like keeping track of conversations, implementing tool calling (it's cooler than it sounds!), and juggling different AI models through one unified interface.
In this lesson, we'll explore how frameworks like LangChain can turn what used to be complex AI integration tasks into clean, readable code. You'll discover how to tackle real-world challenges like keeping track of conversations, implementing tool calling, and juggling different AI models through one unified interface.
By the time we're done here, you'll know exactly when to reach for frameworks instead of raw API calls, how to use their abstractions like a pro, and how to build AI applications that are actually ready for the real world. Ready to dive into the exciting world of AI frameworks and see what they can do for your projects? Let's go!
By the time we're done, you'll know when to reach for frameworks instead of raw API calls, how to use their abstractions effectively, and how to build AI applications that are ready for real-world use. Let's explore what AI frameworks can do for your projects.
## Why choose a framework?
@ -35,16 +35,16 @@ graph TD
G --> K[Error Handling]
```
**Here's why frameworks can be game-changers:**
- **Unifies** multiple AI providers under one roof - no more juggling different APIs!
- **Handles** conversation memory automatically - your AI will actually remember what you talked about
**Why frameworks matter:**
- **Unifies** multiple AI providers under one interface
- **Handles** conversation memory automatically
- **Provides** ready-made tools for common tasks like embeddings and function calling
- **Manages** all the annoying error handling and retry logic for you
- **Turns** complex workflows into simple, readable method calls
- **Manages** error handling and retry logic
- **Turns** complex workflows into readable method calls
> 💡 **Pro Tip**: Reach for frameworks when you're switching between different AI models or building complex features like agents, memory, or tool calling. Stick with direct APIs when you're just learning the basics or building something simple and focused.
> 💡 **Pro Tip**: Use frameworks when switching between different AI models or building complex features like agents, memory, or tool calling. Stick with direct APIs when learning the basics or building simple, focused applications.
**Bottom line**: It's all about picking the right tool for the job. Frameworks shine when you're building complex, feature-rich applications, while direct APIs are perfect for simple, straightforward use cases.
**Bottom line**: Like choosing between a craftsman's specialized tools and a complete workshop, it's about matching the tool to the task. Frameworks excel for complex, feature-rich applications, while direct APIs work well for straightforward use cases.
## Introduction
@ -56,7 +56,7 @@ In this lesson, we'll learn to:
## Your first AI prompt
Alright, let's jump in with both feet! We're going to start simple by creating your very first AI application that sends a question and gets an answer back. Don't worry if this seems a bit overwhelming at first - you'll be amazed at how much easier frameworks make this compared to dealing with raw HTTP requests.
Let's start with the fundamentals by creating your first AI application that sends a question and gets an answer back. Like Archimedes discovering the principle of displacement in his bath, sometimes the simplest observations lead to the most powerful insights - and frameworks make these insights accessible.
### Setting up LangChain with GitHub Models
@ -108,9 +108,9 @@ sequenceDiagram
## Building conversational AI
Okay, that first example was pretty cool, right? But it was just a one-and-done deal - you ask a question, get an answer, and that's it. In the real world, though, you want your AI to actually remember what you've been talking about, just like a real conversation with a friend.
That first example demonstrates the basics, but it's just a single exchange - you ask a question, get an answer, and that's it. In real applications, you want your AI to remember what you've been discussing, like how Watson and Holmes built their investigative conversations over time.
This is where LangChain really starts to shine! It gives you different message types that help structure conversations and even let you give your AI a personality. Before you know it, you'll be building chat experiences that feel surprisingly sophisticated.
This is where LangChain becomes particularly useful. It provides different message types that help structure conversations and let you give your AI a personality. You'll be building chat experiences that maintain context and character.
### Understanding message types
@ -124,7 +124,7 @@ Think of these message types as different "hats" that participants wear in a con
### Creating your first conversation
Time for some fun! Let's create a conversation where our AI gets to play a role. How about we make it pretend to be Captain Picard? This is going to be awesome:
Let's create a conversation where our AI assumes a specific role. We'll have it embody Captain Picard - a character known for his diplomatic wisdom and leadership:
```python
messages = [
@ -172,7 +172,7 @@ I believe in the importance of diplomacy, reason, and the pursuit of knowledge.
I hold the ideals of the Federation close to my heart, believing in the importance of cooperation, understanding, and respect for all sentient beings. My experiences have shaped my leadership style, and I strive to be a thoughtful and just captain. How may I assist you further?
```
Now here's where it gets really interesting - to make your AI actually remember the conversation (instead of having AI amnesia every time), you need to keep adding responses to your message list. Here's how to build that memory:
To maintain conversation continuity (instead of resetting context each time), you need to keep adding responses to your message list. Like the oral traditions that preserved stories across generations, this approach builds lasting memory:
```python
from langchain_core.messages import HumanMessage, SystemMessage
@ -221,7 +221,7 @@ I'll take that as a maybe ;)
## Streaming responses
Ever notice how ChatGPT seems to "type" its responses in real-time? That's streaming in action, and it's way cooler than waiting for a complete response to just appear out of nowhere. With streaming, you get to watch the AI think and respond as it goes - it makes the whole experience feel much more natural and interactive.
Ever notice how ChatGPT seems to "type" its responses in real-time? That's streaming in action. Like watching a skilled calligrapher work - seeing the characters appear stroke by stroke rather than materializing instantly - streaming makes the interaction feel more natural and provides immediate feedback.
### Implementing streaming with LangChain
@ -251,7 +251,7 @@ for chunk in llm.stream("Write a short story about a robot learning to code"):
## Prompt templates
Remember Mad Libs from when you were a kid? Prompt templates are basically the grown-up, super-useful version of that! They let you create reusable prompts where you can swap out different pieces of information without rewriting everything from scratch. Once you set up the template, you just fill in the blanks with whatever values you need.
Prompt templates work like the rhetorical structures used in classical oratory - think of how Cicero would adapt his speech patterns for different audiences while maintaining the same persuasive framework. They let you create reusable prompts where you can swap out different pieces of information without rewriting everything from scratch. Once you set up the template, you just fill in the variables with whatever values you need.
### Creating reusable prompts
@ -285,7 +285,7 @@ for question in questions:
## Structured output
Ever get frustrated trying to parse AI responses that come back as a wall of text? Yeah, me too! Structured output is like teaching your AI to fill out forms properly instead of just rambling. You can ask for JSON, specific data structures, or any format you want - and actually get it back in a way that's easy to work with.
Ever get frustrated trying to parse AI responses that come back as unstructured text? Structured output is like teaching your AI to follow the systematic approach that Linnaeus used for biological classification - organized, predictable, and easy to work with. You can request JSON, specific data structures, or any format you need.
### Defining output schemas
@ -335,7 +335,7 @@ print(f"Strengths: {', '.join(result['strengths'])}")
## Tool calling
Now we're getting to the really exciting stuff! Tools are basically how you give your AI superpowers. Think of it like this: instead of your AI just being able to chat, you're giving it the ability to actually *do* things. You describe what tools are available, and when someone asks for something that matches one of those tools, your AI gets to work!
Now we reach one of the most powerful features: tools. This is how you give your AI practical capabilities beyond conversation. Like how medieval guilds developed specialized tools for specific crafts, you can equip your AI with focused instruments. You describe what tools are available, and when someone requests something that matches, your AI can take action.
### Using Python
@ -431,7 +431,7 @@ TOOL CALL: 15
CONTENT:
```
Pretty cool, right? The AI looked at "What is 3 + 12" and thought, "Hey, this sounds like a job for my `add` tool!" It figured this out from the tool's name, description, and those field descriptions we set up. The fact that we get 15 as the answer comes from our `functions` dictionary actually running the tool:
The AI examined "What is 3 + 12" and recognized this as a task for the `add` tool. Like how a skilled librarian knows which reference to consult based on the type of question asked, it made this determination from the tool's name, description, and field specifications. The result of 15 comes from our `functions` dictionary executing the tool:
```python
print("TOOL CALL: ", functions[tool["name"]](**tool["args"]))
@ -439,7 +439,7 @@ print("TOOL CALL: ", functions[tool["name"]](**tool["args"]))
### A more interesting tool that calls a web API
Okay, adding numbers is neat and all, but let's be honest - that's pretty basic stuff. Real tools usually do something way more exciting, like calling actual web APIs! Let's spice things up and make our AI fetch some jokes from the internet:
Adding numbers demonstrates the concept, but real tools typically perform more complex operations, like calling web APIs. Let's expand our example to have the AI fetch content from the internet - similar to how telegraph operators once connected distant locations:
```python
class joke(TypedDict):
@ -525,7 +525,7 @@ print("CONTENT: ",res.content)
## Embeddings and document processing
Embeddings might sound scary, but they're actually pretty fascinating! Imagine if you could take any piece of text and turn it into a set of numbers that somehow captures what it *means*. That's exactly what embeddings do - they convert text into numerical coordinates in this massive multi-dimensional space where similar ideas end up close to each other. It's like having a GPS for meaning!
Embeddings represent one of the most elegant solutions in modern AI. Imagine if you could take any piece of text and convert it into numerical coordinates that capture its meaning. That's exactly what embeddings do - they transform text into points in multi-dimensional space where similar concepts cluster together. It's like having a coordinate system for ideas, reminiscent of how Mendeleev organized the periodic table by atomic properties.
### Creating and using embeddings
@ -591,7 +591,7 @@ for loader in [pdf_loader, csv_loader, json_loader, web_loader]:
## Building a complete AI application
Alright, this is where all your hard work pays off! We're going to take everything you've learned and put it together into something really cool - a coding assistant that can answer questions, use tools, and actually remember your conversation. This is the kind of app that could genuinely help you in your day-to-day coding!
Now we'll integrate everything you've learned into a comprehensive application - a coding assistant that can answer questions, use tools, and maintain conversation memory. Like how the printing press combined existing technologies (movable type, ink, paper, and pressure) into something transformative, we'll combine our AI components into something practical and useful.
### Complete application example
@ -698,11 +698,11 @@ graph TD
H --> C
```
**Cool features we've built:**
- **Remembers** your entire conversation - no more repeating yourself!
- **Actually does stuff** with tool calling, not just chat
- **Follows** clear interaction patterns so you know what to expect
- **Handles** the messy stuff like errors and complex workflows behind the scenes
**Key features we've implemented:**
- **Remembers** your entire conversation for context continuity
- **Performs actions** through tool calling, not just conversation
- **Follows** predictable interaction patterns
- **Manages** error handling and complex workflows automatically
## Assignment: Build your own AI-powered study assistant
@ -782,7 +782,7 @@ response = assistant.chat("Explain how Python functions work")
## Summary
Wow, look at you go! 🎉 You've just mastered the fundamentals of AI framework development and learned how to build some seriously sophisticated AI applications using LangChain. I'm genuinely impressed by how much ground we've covered together. Let's take a moment to appreciate all the amazing skills you've picked up along the way.
🎉 You've now mastered the fundamentals of AI framework development and learned how to build sophisticated AI applications using LangChain. Like completing a comprehensive apprenticeship, you've acquired a substantial toolkit of skills. Let's review what you've accomplished.
### What you've learned
@ -844,7 +844,7 @@ flowchart TD
- GitHub Models gives you access to cutting-edge AI capabilities - perfect for experimenting
- Keep practicing with different use cases - each project will teach you something new
Here's the thing: you now have the knowledge to build intelligent, conversational applications that can genuinely help people solve real problems. That's pretty incredible when you think about it. The future of AI development really is in your hands - so what are you going to build first? 🚀
You now have the knowledge to build intelligent, conversational applications that can help people solve real problems. Like the Renaissance craftsmen who combined artistic vision with technical skill, you can now merge AI capabilities with practical application. The question is: what will you create? 🚀
## GitHub Copilot Agent Challenge 🚀

@ -3,11 +3,11 @@
![JavaScript Basics - Data types](../../sketchnotes/webdev101-js-datatypes.png)
> Sketchnote by [Tomomi Imura](https://twitter.com/girlie_mac)
Hey there! Ready to dive into one of the most important concepts in JavaScript? Data types might sound intimidating, but they're actually pretty straightforward once you get the hang of them. Think of data types like different containers in your kitchen you wouldn't store soup in a colander or use a wine glass for cereal, right? JavaScript works the same way with different kinds of information!
Data types are one of the fundamental concepts in JavaScript that you'll encounter in every program you write. Think of data types like the filing system used by ancient librarians in Alexandria they had specific places for scrolls containing poetry, mathematics, and historical records. JavaScript organizes information in a similar way with different categories for different kinds of data.
In this lesson, we'll explore the core data types that make JavaScript tick. You'll learn how to work with numbers, text, true/false values, and discover why choosing the right type matters. Don't worry if some concepts seem tricky at first we'll take it step by step, and I promise you'll be working with data types like a pro by the end!
In this lesson, we'll explore the core data types that make JavaScript work. You'll learn how to handle numbers, text, true/false values, and understand why choosing the correct type is essential for your programs. These concepts might seem abstract at first, but with practice, they'll become second nature.
What's really cool is that understanding data types will make everything else in JavaScript so much easier. It's like learning the alphabet before writing stories these fundamentals will support everything you build going forward. Let's jump in and start exploring these digital building blocks!
Understanding data types will make everything else in JavaScript much clearer. Just as architects need to understand different building materials before constructing a cathedral, these fundamentals will support everything you build going forward.
## Pre-Lecture Quiz
[Pre-lecture quiz](https://ff-quizzes.netlify.app/web/)
@ -26,11 +26,9 @@ Let's start with variables and the data types that populate them!
## Variables
Let's talk about variables they're honestly one of the coolest things about programming! Imagine you have a bunch of sticky notes where you can write down important information and stick them wherever you need them. That's basically what variables do in your code.
Variables are fundamental building blocks in programming. Like the labeled jars that medieval alchemists used to store different substances, variables let you store information and give it a descriptive name so you can reference it later. Need to remember someone's age? Store it in a variable called `age`. Want to track a user's name? Keep it in a variable called `userName`.
Variables let you store information and give it a name so you can find it later. Want to remember someone's age? Store it in a variable called `age`. Need to keep track of a user's name? Pop it into a variable called `userName`. It's that simple!
Now, here's where it gets interesting we're going to learn the modern way to create variables in JavaScript. Trust me, once you see how clean and logical this is, you'll wonder how people ever coded without these techniques.
We'll focus on the modern approach to creating variables in JavaScript. The techniques you'll learn here represent years of language evolution and best practices developed by the programming community.
Creating and **declaring** a variable has the following syntax **[keyword] [name]**. It's made up of the two parts:
@ -47,10 +45,10 @@ Creating and **declaring** a variable has the following syntax **[keyword] [name
let myVariable;
```
**What just happened?**
- We told JavaScript "Hey, I want to create a storage spot called `myVariable`"
- JavaScript said "Sure!" and set aside some space in memory
- Right now it's empty (undefined), but we'll fix that in a moment
**What this accomplishes:**
- This tells JavaScript to create a storage location called `myVariable`
- JavaScript allocates space in memory for this variable
- The variable currently has no value (undefined)
2. **Give it a value**. Now let's put something in our variable:
@ -58,10 +56,10 @@ Creating and **declaring** a variable has the following syntax **[keyword] [name
myVariable = 123;
```
**Here's the magic:**
- That `=` sign is like saying "myVariable, please hold onto this number 123 for me"
- Now our variable has a real value instead of being empty
- We can use this number 123 anywhere in our code by just typing `myVariable`
**How assignment works:**
- The `=` operator assigns the value 123 to our variable
- The variable now contains this value instead of being undefined
- You can reference this value throughout your code using `myVariable`
> Note: the use of `=` in this lesson means we make use of an "assignment operator", used to set a value to a variable. It doesn't denote equality.
@ -71,10 +69,10 @@ Creating and **declaring** a variable has the following syntax **[keyword] [name
let myVariable = 123;
```
**Much cleaner, right?**
- We're creating the variable AND giving it a value in one line
- This is how most developers write their code
- Less typing, same result I love efficiency!
**This approach is more efficient:**
- You're declaring the variable and assigning a value in one statement
- This is the standard practice among developers
- It reduces code length while maintaining clarity
4. **Change your mind**. What if we want to store a different number?
@ -82,18 +80,18 @@ Creating and **declaring** a variable has the following syntax **[keyword] [name
myVariable = 321;
```
**Pretty cool, huh?**
- Our variable now holds 321 instead of 123
- The old value is gone variables can only hold one thing at a time
- This flexibility is why we use `let` it lets us change the value whenever we need to
**Understanding reassignment:**
- The variable now contains 321 instead of 123
- The previous value is replaced variables store only one value at a time
- This mutability is the key characteristic of variables declared with `let`
✅ Try it! You can write JavaScript right in your browser. Open a browser window and navigate to Developer Tools. In the console, you will find a prompt; type `let myVariable = 123`, press return, then type `myVariable`. What happens? Note, you'll learn more about these concepts in subsequent lessons.
## Constants
Now, what if you have some information that should NEVER change? Like the value of pi, or your app's name, or the number of days in a week? That's where constants come in!
Sometimes you need to store information that should never change during program execution. Think of constants like the mathematical principles that Euclid established in ancient Greece once proven and documented, they remained fixed for all future reference.
Constants are like variables with a superpower once you set their value, they become locked in place. No accidental changes, no oops moments. It's JavaScript's way of helping you protect important values from getting messed up by mistake.
Constants work similarly to variables, but with an important restriction: once you assign their value, it cannot be changed. This immutability helps prevent accidental modifications to critical values in your program.
Declaration and initialization of a constant follows the same concepts as a variable, with the exception of the `const` keyword. Constants are typically declared with all uppercase letters.
@ -151,9 +149,9 @@ Constants have two main rules:
## Data Types
Alright, here's where things get really interesting! JavaScript has different categories for different kinds of information we call these data types. Just like you wouldn't try to wear a book or read a shoe, JavaScript knows that numbers, text, and true/false values all need to be handled differently.
JavaScript organizes information into different categories called data types. This concept mirrors how ancient scholars categorized knowledge Aristotle distinguished between different types of reasoning, knowing that logical principles couldn't be applied uniformly to poetry, mathematics, and natural philosophy.
Why does this matter? Well, imagine trying to do math with someone's name, or trying to capitalize a number it just doesn't make sense! When you understand data types, you'll write code that actually works and avoid those "wait, why isn't this working?" moments that every developer has experienced.
Data types matter because different operations work with different kinds of information. Just as you can't perform arithmetic on a person's name or alphabetize a mathematical equation, JavaScript requires the appropriate data type for each operation. Understanding this prevents errors and makes your code more reliable.
Variables can store many different types of values, like numbers and text. These various types of values are known as the **data type**. Data types are an important part of software development because it helps developers make decisions on how the code should be written and how the software should run. Furthermore, some data types have unique features that help transform or extract additional information in a value.
@ -161,7 +159,7 @@ Variables can store many different types of values, like numbers and text. These
### Numbers
Let's start with numbers they're probably the most straightforward data type. Whether you're working with whole numbers like 42, decimals like 3.14, or even negative numbers like -5, JavaScript treats them all the same way. No fuss, no complications!
Numbers are the most straightforward data type in JavaScript. Whether you're working with whole numbers like 42, decimals like 3.14, or negative numbers like -5, JavaScript handles them uniformly.
Remember our variable from earlier? That 123 we stored was actually a number data type:
@ -169,18 +167,18 @@ Remember our variable from earlier? That 123 we stored was actually a number dat
let myVariable = 123;
```
**What's cool about this:**
- JavaScript automatically recognizes 123 as a number
- We can now do math with this variable
- No need to tell JavaScript "hey, this is a number" it just knows!
**Key characteristics:**
- JavaScript automatically recognizes numeric values
- You can perform mathematical operations with these variables
- No explicit type declaration is required
Variables can store all types of numbers, including decimals or negative numbers. Numbers also can be used with arithmetic operators, covered in the [next section](#arithmetic-operators).
### Arithmetic Operators
Time for some math! Don't worry this is the fun kind of math where you get to make the computer do all the work. Arithmetic operators are just the symbols you use to do calculations, like the ones you learned way back in elementary school.
Arithmetic operators allow you to perform mathematical calculations in JavaScript. These operators follow the same principles mathematicians have used for centuries the same symbols that appeared in the works of scholars like Al-Khwarizmi, who developed algebraic notation.
The best part? They work exactly like you'd expect them to. Plus becomes addition, minus becomes subtraction no surprises here!
The operators work as you would expect from traditional mathematics: plus for addition, minus for subtraction, and so forth.
There are several types of operators to use when performing arithmetic functions, and some are listed here:
@ -196,9 +194,9 @@ There are several types of operators to use when performing arithmetic functions
### Strings
Now let's talk about text! In JavaScript, any piece of text whether it's a single letter, a word, or an entire novel is called a string. The name is pretty cute when you think about it: imagine letters strung together like beads on a necklace.
In JavaScript, textual data is represented as strings. The term "string" comes from the concept of characters strung together in sequence, much like the way scribes in medieval monasteries would connect letters to form words and sentences in their manuscripts.
Strings are absolutely everywhere in web development. Every piece of text you see on a website usernames, button labels, error messages, content it's all strings. Master strings, and you're well on your way to building amazing user experiences!
Strings are fundamental to web development. Every piece of text displayed on a website usernames, button labels, error messages, content is handled as string data. Understanding strings is essential for creating functional user interfaces.
Strings are sets of characters that reside between single or double quotes.
@ -218,9 +216,9 @@ Remember to use quotes when writing a string, or else JavaScript will assume it'
### Formatting Strings
Here's where strings get really powerful you can combine them, mix in variables, and create dynamic text that changes based on what's happening in your program. It's like being able to construct sentences on the fly!
String manipulation allows you to combine text elements, incorporate variables, and create dynamic content that responds to program state. This technique enables you to construct text programmatically.
Let's see how this works. Sometimes you need to join strings together we call this concatenation (fancy word for "sticking things together").
Often you need to join multiple strings together this process is called concatenation.
To **concatenate** two or more strings, or join them together, use the `+` operator.
@ -263,9 +261,9 @@ You can achieve your formatting goals with either method, but template literals
### Booleans
Let's talk about the simplest but most powerful data type: booleans! These little guys can only be one of two things `true` or `false`. That's it. No maybes, no sort-ofs, just yes or no.
Booleans represent the simplest form of data: they can only hold one of two values `true` or `false`. This binary logic system traces back to the work of George Boole, a 19th-century mathematician who developed Boolean algebra.
Don't let their simplicity fool you though. Booleans are the decision-makers of the programming world. Every time your code needs to choose between two options "Is the user logged in?", "Did they click the button?", "Is it daytime?" booleans are there making it happen.
Despite their simplicity, booleans are essential for program logic. They enable your code to make decisions based on conditions whether a user is logged in, if a button was clicked, or if certain criteria are met.
Booleans can be only two values: `true` or `false`. Booleans can help make decisions on which lines of code should run when certain conditions are met. In many cases, [operators](#arithmetic-operators) assist with setting the value of a Boolean and you will often notice and write variables being initialized or their values being updated with an operator.
@ -296,9 +294,9 @@ Learn more about [agent mode](https://code.visualstudio.com/blogs/2025/02/24/int
## 🚀 Challenge
Ready for a fun detective mission? JavaScript has some quirky behaviors that can catch even experienced developers off guard! Here's a classic one to get you started: try typing this in your browser console: `let age = 1; let Age = 2; age == Age` and see what happens. Spoiler alert: it returns `false` can you figure out why?
JavaScript has some behaviors that can catch developers off guard. Here's a classic example to explore: try typing this in your browser console: `let age = 1; let Age = 2; age == Age` and observe the result. It returns `false` can you determine why?
This is just the tip of the iceberg. JavaScript has some wonderfully weird behaviors that once you know about them, you'll be prepared for anything. Happy hunting!
This represents one of many JavaScript behaviors worth understanding. Familiarity with these quirks will help you write more reliable code and debug issues more effectively.
## Post-Lecture Quiz
[Post-lecture quiz](https://ff-quizzes.netlify.app)

@ -6,11 +6,11 @@
## Pre-Lecture Quiz
[Pre-lecture quiz](https://ff-quizzes.netlify.app)
Ever felt like you're writing the same code over and over again? That's where functions come to the rescue! Think of functions like your favorite kitchen recipe once you write it down, you can use it whenever you want to make that dish, and you can even share it with friends.
Writing the same code repeatedly is one of programming's most common frustrations. Functions solve this problem by letting you package code into reusable blocks. Think of functions like the standardized parts that made Henry Ford's assembly line revolutionary once you create a reliable component, you can use it wherever needed without rebuilding from scratch.
Functions let you bundle up pieces of code so you can reuse them throughout your program. Instead of copying and pasting the same logic everywhere (which gets messy fast), you can create a function once and call it whenever you need it. Pretty neat, right?
Functions allow you to bundle pieces of code so you can reuse them throughout your program. Instead of copying and pasting the same logic everywhere, you can create a function once and call it whenever needed. This approach keeps your code organized and makes updates much easier.
In this lesson, we'll explore how to create your own functions, pass information to them, and get useful results back. You'll discover the difference between functions and methods, learn some modern syntax tricks, and even see how functions can work with other functions. Don't worry if that sounds complex we'll take it step by step, and soon you'll be writing functions like a pro!
In this lesson, you'll learn how to create your own functions, pass information to them, and get useful results back. You'll discover the difference between functions and methods, learn modern syntax approaches, and see how functions can work with other functions. We'll build these concepts step by step.
[![Methods and Functions](https://img.youtube.com/vi/XgKsD6Zwvlc/0.jpg)](https://youtube.com/watch?v=XgKsD6Zwvlc "Methods and Functions")
@ -20,17 +20,15 @@ In this lesson, we'll explore how to create your own functions, pass information
## Functions
So what exactly is a function? Think of it as a little worker in your code a self-contained block that has one job and does it well whenever you ask.
A function is a self-contained block of code that performs a specific task. It encapsulates logic that you can execute whenever needed.
Here's the magic: instead of writing the same code multiple times throughout your program, you can package it up in a function and just call that function whenever you need it. This keeps your code clean and makes updates much easier. Imagine if you had to change something and it was scattered across 20 different places that's a debugging nightmare waiting to happen!
Instead of writing the same code multiple times throughout your program, you can package it in a function and call that function whenever you need it. This approach keeps your code clean and makes updates much easier. Consider the maintenance challenge if you needed to change logic that was scattered across 20 different locations in your codebase.
Naming your functions well is super important too. A good function name is like a clear label on a jar you know exactly what's inside. When you see a function called `cancelTimer()`, you immediately know what it does, just like seeing a button labeled "Cancel timer" tells you exactly what will happen when you click it.
Naming your functions descriptively is essential. A well-named function communicates its purpose clearly when you see `cancelTimer()`, you immediately understand what it does, just as a clearly labeled button tells you exactly what will happen when you click it.
## Creating and calling a function
Ready to create your first function? Don't worry the syntax is pretty straightforward once you see it in action.
Here's what a basic function looks like:
Let's examine how to create a function. The syntax follows a consistent pattern:
```javascript
function nameOfFunction() { // function definition
@ -52,18 +50,18 @@ function displayGreeting() {
}
```
This function is pretty simple it just prints "Hello, world!" to the console. The cool thing is, once we've defined it, we can use it as many times as we want!
This function prints "Hello, world!" to the console. Once you've defined it, you can use it as many times as needed.
To actually use (or "call") your function, you write its name followed by parentheses. JavaScript is pretty flexible you can define your function before or after you call it, and JavaScript will figure it out.
To execute (or "call") your function, write its name followed by parentheses. JavaScript allows you to define your function before or after you call it the JavaScript engine will handle the execution order.
```javascript
// calling our function
displayGreeting();
```
When you run this line, it executes all the code inside your `displayGreeting` function, which means "Hello, world!" appears in your browser's console. You can call this function as many times as you want!
When you run this line, it executes all the code inside your `displayGreeting` function, displaying "Hello, world!" in your browser's console. You can call this function repeatedly.
> **Fun fact:** You've actually been using **methods** this whole time! `console.log()` is a method it's basically a function that belongs to the `console` object. The main difference is that methods are attached to objects, while functions stand on their own. Don't worry too much about this distinction right now many developers use the terms interchangeably.
> **Note:** You've been using **methods** throughout these lessons. `console.log()` is a method essentially a function that belongs to the `console` object. The key difference is that methods are attached to objects, while functions stand independently. Many developers use these terms interchangeably in casual conversation.
### Function best practices
@ -75,9 +73,9 @@ Here are a few tips to help you write great functions:
## Passing information to a function
Our `displayGreeting` function is nice, but it's a bit boring it can only say "Hello, world!" to everyone. Wouldn't it be cool if we could make it more personal?
Our `displayGreeting` function is limited it can only display "Hello, world!" for everyone. Parameters allow us to make functions more flexible and useful.
This is where **parameters** come in handy. Think of parameters like empty slots where you can plug in different values each time you use the function. This way, the same function can work with different information every time you call it.
**Parameters** act like placeholders where you can insert different values each time you use the function. This way, the same function can work with different information on each call.
You list parameters inside the parentheses when you define your function, separating multiple parameters with commas:
@ -100,14 +98,14 @@ function displayGreeting(name) {
Notice how we're using backticks (`` ` ``) and `${}` to insert the name directly into our message this is called a template literal, and it's a really handy way to build strings with variables mixed in.
Now when we call our function, we can pass in any name we want:
Now when we call our function, we can pass in any name:
```javascript
displayGreeting('Christopher');
// displays "Hello, Christopher!" when run
```
JavaScript takes the string `'Christopher'`, plugs it into the `name` parameter, and creates the message "Hello, Christopher!" much more personal!
JavaScript takes the string `'Christopher'`, assigns it to the `name` parameter, and creates the personalized message "Hello, Christopher!"
## Default values
@ -133,7 +131,7 @@ displayGreeting('Christopher', 'Hi');
// displays "Hi, Christopher"
```
In the first call, JavaScript uses the default "Hello" since we didn't specify a salutation. In the second call, it uses our custom "Hi" instead. Pretty flexible, right?
In the first call, JavaScript uses the default "Hello" since we didn't specify a salutation. In the second call, it uses our custom "Hi" instead. This flexibility makes functions adaptable to different scenarios.
## Return values
@ -166,11 +164,11 @@ To use the returned value, we can store it in a variable just like any other val
const greetingMessage = createGreetingMessage('Christopher');
```
Now `greetingMessage` contains "Hello, Christopher" and we can use it anywhere in our code maybe to display it on a webpage, send it in an email, or use it in another function!
Now `greetingMessage` contains "Hello, Christopher" and we can use it anywhere in our code to display it on a webpage, include it in an email, or pass it to another function.
## Functions as parameters for functions
Here's where things get really interesting you can actually pass functions to other functions! It might sound a bit mind-bending at first, but it's incredibly useful.
Functions can be passed as parameters to other functions. While this concept may seem complex initially, it's a powerful feature that enables flexible programming patterns.
This pattern is super common when you want to say "when something happens, do this other thing." For example, "when the timer finishes, run this code" or "when the user clicks the button, call this function."
@ -202,7 +200,7 @@ setTimeout(function() {
}, 3000);
```
Same result, but now we've defined the function right inside the `setTimeout` call. No separate function declaration needed!
This achieves the same result, but the function is defined directly within the `setTimeout` call, eliminating the need for a separate function declaration.
### Fat arrow functions
@ -218,11 +216,11 @@ setTimeout(() => {
}, 3000);
```
The `()` is where parameters would go (empty in this case), then comes the arrow `=>`, and finally the function body in curly braces. Same functionality, just more compact!
The `()` is where parameters would go (empty in this case), then comes the arrow `=>`, and finally the function body in curly braces. This provides the same functionality with more concise syntax.
### When to use each strategy
So when should you use each approach? Here's a simple rule of thumb: if you'll use the function multiple times, give it a name and define it separately. If it's just for one specific spot, go with an anonymous function. As for arrow functions vs traditional syntax, both work fine though you'll see arrow functions everywhere in modern JavaScript code.
When should you use each approach? A practical guideline: if you'll use the function multiple times, give it a name and define it separately. If it's for one specific use, consider an anonymous function. Both arrow functions and traditional syntax are valid choices, though arrow functions are prevalent in modern JavaScript codebases.
---

@ -4,17 +4,17 @@
> Sketchnote by [Tomomi Imura](https://twitter.com/girlie_mac)
Ever wonder how your favorite apps know what to show you? Like how Netflix suggests movies based on what you've watched, or how a weather app tells you whether to bring an umbrella? That's the magic of decision-making in code!
Have you ever wondered how applications make smart decisions? Like how a navigation system chooses the fastest route, or how a thermostat decides when to turn on the heat? This is the fundamental concept of decision-making in programming.
Just like you decide what to wear based on the weather or which route to take based on traffic, your JavaScript programs need to make choices based on different situations. This is what transforms boring, static code into smart, responsive applications that actually do useful things.
Just as Charles Babbage's Analytical Engine was designed to follow different sequences of operations based on conditions, modern JavaScript programs need to make choices based on varying circumstances. This ability to branch and make decisions is what transforms static code into responsive, intelligent applications.
In this lesson, you'll learn how to give your code a brain! We'll explore conditional statements, comparison operators, and logical expressions that help your programs think through problems and respond appropriately. Think of these as the "if this, then that" rules that make your code intelligent.
In this lesson, you'll learn how to implement conditional logic in your programs. We'll explore conditional statements, comparison operators, and logical expressions that allow your code to evaluate situations and respond appropriately.
## Pre-Lecture Quiz
[Pre-lecture quiz](https://ff-quizzes.netlify.app/web/quiz/11)
Making decisions and controlling which parts of your code run when is what makes programming really powerful. This section covers how to control the flow of your JavaScript programs using Boolean values (those true/false values we learned about before).
The ability to make decisions and control program flow is a fundamental aspect of programming. This section covers how to control the execution path of your JavaScript programs using Boolean values and conditional logic.
[![Making Decisions](https://img.youtube.com/vi/SxTp8j-fMMY/0.jpg)](https://youtube.com/watch?v=SxTp8j-fMMY "Making Decisions")
@ -24,9 +24,9 @@ Making decisions and controlling which parts of your code run when is what makes
## A Brief Recap on Booleans
Before we jump into making decisions, let's quickly revisit those Boolean values we talked about earlier. Remember, Booleans are like digital switches they're either on (`true`) or off (`false`). No middle ground, no "maybe" just yes or no.
Before exploring decision-making, let's revisit Boolean values from our previous lesson. Named after mathematician George Boole, these values represent binary states either `true` or `false`. There's no ambiguity, no middle ground.
These simple true/false values are the foundation of all decision-making in programming. Every time your code needs to choose between doing something or not doing something, it comes down to a Boolean.
These binary values form the foundation of all computational logic. Every decision your program makes ultimately reduces to a Boolean evaluation.
Creating Boolean variables is straightforward:
@ -35,15 +35,15 @@ let myTrueBool = true;
let myFalseBool = false;
```
Here we're creating two variables one that's `true` and one that's `false`. Simple as that!
This creates two variables with explicit Boolean values.
✅ Booleans are named after the English mathematician, philosopher and logician George Boole (18151864).
## Comparison Operators and Booleans
Now here's where it gets interesting! Most of the time, you won't manually set Booleans to `true` or `false`. Instead, you'll create them by asking questions in your code: "Is this number bigger than that one?" or "Are these two things equal?"
In practice, you'll rarely set Boolean values manually. Instead, you'll generate them by evaluating conditions: "Is this number greater than that one?" or "Are these values equal?"
That's where comparison operators come in. Think of them as your code's way of asking questions and getting yes/no answers.
Comparison operators enable these evaluations. They compare values and return Boolean results based on the relationship between the operands.
| Symbol | Description | Example |
| ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ |
@ -82,7 +82,7 @@ if (currentMoney >= laptopPrice) {
}
```
Since `1000 >= 800` is `true`, the code inside the curly braces runs, and you'll see "Getting a new laptop!" in the console. Makes sense, right?
Since `1000 >= 800` evaluates to `true`, the code inside the block executes, displaying "Getting a new laptop!" in the console.
## If..Else Statement
@ -109,9 +109,9 @@ Now since `500 >= 800` is `false`, JavaScript skips the first block and runs the
## Switch Statement
Sometimes you need to compare one value against several different options. You could write a bunch of `if..else` statements, but that gets messy quickly. The `switch` statement is like a clean, organized way to handle multiple choices.
Sometimes you need to compare one value against multiple options. While you could chain several `if..else` statements, this approach becomes unwieldy. The `switch` statement provides a cleaner structure for handling multiple discrete values.
Think of it like a vending machine you press one button (the value), and the machine does the corresponding action for that specific button.
The concept resembles the mechanical switching systems used in early telephone exchanges one input value determines which specific path the execution follows.
```javascript
switch (expression) {
@ -161,9 +161,9 @@ In this example, JavaScript sees that `dayNumber` is `2`, finds the matching `ca
## Logical Operators and Booleans
Real life isn't usually about simple yes/no questions. You might decide to go to the beach if it's sunny AND warm, or stay inside if it's raining OR snowing. Programming works the same way you often need to combine multiple conditions to make smart decisions.
Complex decisions often require evaluating multiple conditions simultaneously. Just as Boolean algebra allows mathematicians to combine logical expressions, programming provides logical operators to connect multiple Boolean conditions.
That's where logical operators come in. They let you connect multiple true/false questions together.
These operators enable sophisticated conditional logic by combining simple true/false evaluations.
| Symbol | Description | Example |
| ------ | ----------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- |
@ -194,7 +194,7 @@ if (currentMoney >= laptopPrice || currentMoney >= laptopDiscountPrice) {
}
```
Here's what's happening: we calculate a 20% discount price (640), then check if our money covers either the full price OR the discounted price. Since 600 is enough for the discounted laptop at 640, the condition is true and we get the laptop!
In this example: we calculate a 20% discount price (640), then evaluate whether our available funds cover either the full price OR the discounted price. Since 600 meets the discounted price threshold of 640, the condition evaluates to true.
### Negation Operator
@ -212,7 +212,7 @@ The `!` operator is like saying "the opposite of..." if something is `true`,
### Ternary Expressions
For simple decisions, JavaScript has a shortcut called the **ternary operator**. It's like a mini `if..else` statement that fits on one line. Great for when you need to assign one of two values to a variable based on a condition.
For simple conditional assignments, JavaScript provides the **ternary operator**. This concise syntax allows you to write a conditional expression in a single line, useful when you need to assign one of two values based on a condition.
```javascript
let variable = condition ? returnThisIfTrue : returnThisIfFalse;
@ -243,7 +243,7 @@ if (firstNumber > secondNumber) {
}
```
Both approaches do exactly the same thing the ternary operator is just more compact. Use whichever feels more readable to you!
Both approaches produce identical results. The ternary operator offers conciseness, while the traditional if-else structure may be more readable for complex conditions.
---

@ -6,11 +6,11 @@
## Pre-Lecture Quiz
[Pre-lecture quiz](https://ff-quizzes.netlify.app/web/quiz/13)
Ever wondered how websites keep track of shopping cart items or display your friend list? That's where arrays and loops come to the rescue! Arrays are like digital containers that hold multiple pieces of information, while loops are your coding superpowers that let you work with all that data without going crazy from repetition.
Ever wondered how websites keep track of shopping cart items or display your friend list? That's where arrays and loops come in. Arrays are like digital containers that hold multiple pieces of information, while loops let you work with all that data efficiently without repetitive code.
Together, these two concepts will completely change how you think about handling information in your programs. You'll go from manually writing out every single step to creating smart, efficient code that can process hundreds or even thousands of items in seconds.
Together, these two concepts form the foundation for handling information in your programs. You'll learn to move from manually writing out every single step to creating smart, efficient code that can process hundreds or even thousands of items quickly.
By the time we're done here, you'll be amazed at what you can accomplish with just a few lines of code. Ready to unlock these programming superpowers? Let's dive in!
By the end of this lesson, you'll understand how to accomplish complex data tasks with just a few lines of code. Let's explore these essential programming concepts.
[![Arrays](https://img.youtube.com/vi/1U4qTyq02Xw/0.jpg)](https://youtube.com/watch?v=1U4qTyq02Xw "Arrays")
@ -22,9 +22,9 @@ By the time we're done here, you'll be amazed at what you can accomplish with ju
## Arrays
Think of arrays as your digital toolbox - instead of having one drawer for one tool, you get a whole toolbox that can hold as many tools as you need! In programming terms, arrays let you store multiple pieces of information in one neat package.
Think of arrays as a digital filing cabinet - instead of storing one document per drawer, you can organize multiple related items in a single, structured container. In programming terms, arrays let you store multiple pieces of information in one organized package.
Whether you're building a photo gallery, managing a to-do list, or keeping track of high scores in a game, arrays are going to be your best friend. Let's see how they work!
Whether you're building a photo gallery, managing a to-do list, or keeping track of high scores in a game, arrays provide the foundation for data organization. Let's see how they work.
✅ Arrays are all around us! Can you think of a real-life example of an array, such as a solar panel array?
@ -38,9 +38,9 @@ const myArray = [];
```
**What's happening here?**
You've just created an empty container using those square brackets `[]`. Think of it like getting a fresh, empty shopping cart at the store - it's ready to hold whatever you want to put in it!
You've just created an empty container using those square brackets `[]`. Think of it like an empty library shelf - it's ready to hold whatever books you want to organize there.
But here's where it gets fun - you can fill your array right from the start!
You can also fill your array with initial values right from the start:
```javascript
// Your ice cream shop's flavor menu
@ -60,7 +60,7 @@ const scores = [95, 87, 92, 78, 85];
### Array Indexing
Here's something that might seem weird at first: arrays number their items starting from 0, not 1! I know, I know - it feels backwards, but you'll get used to it. Each spot in the array gets its own address number called an **index**.
Here's something that might seem unusual at first: arrays number their items starting from 0, not 1. This zero-based indexing has its roots in how computer memory works - it's been a programming convention since the early days of computing languages like C. Each spot in the array gets its own address number called an **index**.
| Index | Value | Description |
|-------|-------|-------------|
@ -153,11 +153,11 @@ const hasApple = fruits.includes("apple"); // Returns true
## Loops
Remember being a kid and having to write "I will not talk in class" 100 times on the chalkboard? Imagine if you could just tell someone "write this sentence 100 times" and walk away. That's exactly what loops do for your code!
Think of the famous punishment from Charles Dickens' novels where students had to write lines repeatedly on a slate. Imagine if you could simply instruct someone to "write this sentence 100 times" and have it done automatically. That's exactly what loops do for your code.
Loops are like having a super obedient assistant who never gets tired of doing the same thing over and over. Whether you need to check every item in a shopping cart or display all the photos in an album, loops have got your back.
Loops are like having a tireless assistant who can repeat tasks without error. Whether you need to check every item in a shopping cart or display all the photos in an album, loops handle the repetition efficiently.
JavaScript gives you several types of loops to choose from. Let's meet them and see which one fits different situations!
JavaScript provides several types of loops to choose from. Let's examine each one and understand when to use them.
### For Loop
@ -358,7 +358,7 @@ Learn more about [agent mode](https://code.visualstudio.com/blogs/2025/02/24/int
JavaScript offers several modern array methods that can replace traditional loops for specific tasks. Explore [forEach](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach), [for-of](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/for...of), [map](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/map), [filter](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/filter), and [reduce](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce).
**Here's your mission (if you choose to accept it):** Take that student grades example and give it a modern makeover using at least three different array methods. You'll be amazed at how much cleaner and more readable your code becomes!
**Your challenge:** Refactor the student grades example using at least three different array methods. Notice how much cleaner and more readable the code becomes with modern JavaScript syntax.
## Post-Lecture Quiz
[Post-lecture quiz](https://ff-quizzes.netlify.app/web/quiz/14)

@ -5,9 +5,9 @@
HTML, or HyperText Markup Language, is the foundation of every website you've ever visited. Think of HTML as the skeleton that gives structure to web pages it defines where content goes, how it's organized, and what each piece represents. While CSS will later "dress up" your HTML with colors and layouts, and JavaScript will bring it to life with interactivity, HTML provides the essential structure that makes everything else possible.
In this exciting lesson, you'll create the HTML structure for a beautiful virtual terrarium interface. This hands-on project will teach you fundamental HTML concepts while building something visually engaging. You'll learn how to organize content using semantic elements, work with images, and create the foundation for an interactive web application.
In this lesson, you'll create the HTML structure for a virtual terrarium interface. This hands-on project will teach you fundamental HTML concepts while building something visually engaging. You'll learn how to organize content using semantic elements, work with images, and create the foundation for an interactive web application.
By the end of this lesson, you'll have a working HTML page displaying plant images in organized columns, ready for styling in the next lesson. Don't worry if it looks basic at first that's exactly what HTML should do before CSS adds the visual polish. Let's dive in and start building your first web project!
By the end of this lesson, you'll have a working HTML page displaying plant images in organized columns, ready for styling in the next lesson. Don't worry if it looks basic at first that's exactly what HTML should do before CSS adds the visual polish.
## Pre-Lecture Quiz
@ -136,7 +136,7 @@ Update your HTML file to include the `<body>` element:
- **Creates** an empty body ready for your visible content
- **Follows** modern web development best practices
Now you're ready to add the visible elements of your terrarium! We'll use `<div>` elements as containers to organize different sections of content, and `<img>` elements to display the plant images.
Now you're ready to add the visible elements of your terrarium. We'll use `<div>` elements as containers to organize different sections of content, and `<img>` elements to display the plant images.
### Working with Images and Layout Containers
@ -213,7 +213,7 @@ Now add the plant images organized in two columns between your `<body></body>` t
- **Assigns** unique IDs to each plant image for JavaScript interaction later
- **Includes** proper file paths pointing to the images folder
> 🤔 **Consider This**: Notice that all images currently have the same alt text "plant". This isn't ideal for accessibility! Screen reader users would hear "plant" repeated 14 times without knowing which specific plant each image shows. Can you think of better, more descriptive alt text for each image?
> 🤔 **Consider This**: Notice that all images currently have the same alt text "plant". This isn't ideal for accessibility. Screen reader users would hear "plant" repeated 14 times without knowing which specific plant each image shows. Can you think of better, more descriptive alt text for each image?
> 📝 **HTML Element Types**: `<div>` elements are "block-level" and take up full width, while `<span>` elements are "inline" and only take up necessary width. What do you think would happen if you changed all these `<div>` tags to `<span>` tags?
@ -249,7 +249,7 @@ Let's add a proper heading to your terrarium page. Insert this line right after
| Button | `<button>Click me</button>` | `<span onclick="...">Click me</span>` |
| Article content | `<article><p></p></article>` | `<div class="content"><div></div></div>` |
> 🎥 **See It in Action**: Watch [how screen readers interact with web pages](https://www.youtube.com/watch?v=OUDV1gqs9GA) to understand why semantic markup is crucial for accessibility. Notice how proper HTML structure helps users navigate efficiently!
> 🎥 **See It in Action**: Watch [how screen readers interact with web pages](https://www.youtube.com/watch?v=OUDV1gqs9GA) to understand why semantic markup is crucial for accessibility. Notice how proper HTML structure helps users navigate efficiently.
## Creating the Terrarium Container
@ -284,7 +284,7 @@ Insert this markup above the last `</div>` tag (before the closing tag of the pa
---
## GitHub Copilot Agent Challenge 🚀
## GitHub Copilot Agent Challenge
Use the Agent mode to complete the following challenge:
@ -294,11 +294,11 @@ Use the Agent mode to complete the following challenge:
Learn more about [agent mode](https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode) here.
## 🚀 Explore HTML History Challenge
## Explore HTML History Challenge
**Learning About Web Evolution**
HTML has evolved significantly since its creation in the 1990s. Some older tags like `<marquee>` are now deprecated because they don't work well with modern accessibility standards and responsive design principles.
HTML has evolved significantly since Tim Berners-Lee created the first web browser at CERN in 1990. Some older tags like `<marquee>` are now deprecated because they don't work well with modern accessibility standards and responsive design principles.
**Try This Experiment:**
1. Temporarily wrap your `<h1>` title in a `<marquee>` tag: `<marquee><h1>My Terrarium</h1></marquee>`

@ -3,13 +3,13 @@
![Introduction to CSS](../../sketchnotes/webdev101-css.png)
> Sketchnote by [Tomomi Imura](https://twitter.com/girlie_mac)
Remember how your HTML terrarium looked pretty... basic? Well, that's about to change completely! CSS is where we turn that plain structure into something absolutely gorgeous.
Remember how your HTML terrarium looked quite basic? CSS is where we transform that plain structure into something visually appealing.
If HTML is like building the frame of a house, then CSS is everything that makes it feel like home - the paint colors, the furniture arrangement, the lighting, even the way the rooms flow together. It's the difference between a bare construction site and a place you'd actually want to live.
If HTML is like building the frame of a house, then CSS is everything that makes it feel like home - the paint colors, the furniture arrangement, the lighting, and how the rooms flow together. Think of how the Palace of Versailles started as a simple hunting lodge, but careful attention to decoration and layout transformed it into one of the world's most magnificent buildings.
Today, we're going to transform your terrarium from "functional but boring" to "wow, did I really build that?" You'll learn how to position elements exactly where you want them, make things respond beautifully to different screen sizes, and create that polished, professional look that makes websites feel alive.
Today, we'll transform your terrarium from functional to polished. You'll learn how to position elements precisely, make layouts respond to different screen sizes, and create the visual appeal that makes websites engaging.
By the time we're done, you'll be amazed at what a few lines of CSS can do. Ready to add some serious style to your terrarium? Let's make it beautiful!
By the end of this lesson, you'll see how strategic CSS styling can dramatically improve your project. Let's add some style to your terrarium.
## Pre-Lecture Quiz
@ -17,9 +17,9 @@ By the time we're done, you'll be amazed at what a few lines of CSS can do. Read
## Getting Started with CSS
Here's the thing about CSS - people sometimes think it's just about "making things pretty," but it's so much more! CSS is like being the director of a movie. You control not just how everything looks, but how it moves, how it responds when people interact with it, and how it adapts to different situations.
CSS is often thought of as just "making things pretty," but it serves a much broader purpose. CSS is like being the director of a movie - you control not just how everything looks, but how it moves, responds to interaction, and adapts to different situations.
The best part? Modern CSS is incredibly smart. You can write code that automatically adjusts your layout for phones, tablets, and desktop computers. You can create smooth animations that guide users' attention exactly where you want it. It's pretty magical when you see it all come together!
Modern CSS is remarkably capable. You can write code that automatically adjusts layouts for phones, tablets, and desktop computers. You can create smooth animations that guide users' attention where needed. The results can be quite impressive when everything works together.
> 💡 **Pro Tip**: CSS is constantly evolving with new features and capabilities. Always check [CanIUse.com](https://caniuse.com) to verify browser support for newer CSS features before using them in production projects.
@ -55,9 +55,9 @@ In your terrarium folder, create a new file called `style.css`, then link it in
## Understanding the CSS Cascade
Ever wondered why CSS is called "Cascading" Style Sheets? It's because styles literally cascade down like a waterfall, and sometimes they bump into each other!
Ever wondered why CSS is called "Cascading" Style Sheets? Styles cascade down like a waterfall, and sometimes they conflict with each other.
Imagine you're getting dressed and someone gives you three different instructions: "wear something blue," "wear something red," and "wear that specific red shirt." Your brain automatically knows the most specific instruction wins - you'd wear the red shirt. CSS works the same way, and once you understand this "pecking order," debugging becomes way less frustrating.
Consider how military command structures work - a general order might say "all troops wear green," but a specific order to your unit might say "wear dress blues for the ceremony." The more specific instruction takes precedence. CSS follows similar logic, and understanding this hierarchy makes debugging much more manageable.
### Experimenting with Cascade Priority
@ -96,9 +96,9 @@ h1 {
## CSS Inheritance in Action
CSS inheritance is just like genetics - kids inherit certain traits from their parents! If you set the font family on the body element, all the text inside automatically gets that same font. It's like saying "everyone in this family has brown eyes" and not having to specify it for each person individually.
CSS inheritance works like genetics - elements inherit certain properties from their parent elements. If you set the font family on the body element, all text inside automatically uses that same font. It's similar to how the Habsburg family's distinctive jawline appeared across generations without being specified for each individual.
But here's the catch - not everything gets inherited. Text styles like fonts and colors? Yes. Layout stuff like margins and borders? Nope. It's kind of like how kids might inherit eye color but not their parent's choice of clothing!
However, not everything gets inherited. Text styles like fonts and colors do inherit, but layout properties like margins and borders do not. Just as children might inherit physical traits but not their parents' fashion choices.
### Observing Font Inheritance
@ -128,9 +128,9 @@ Open your browser's developer tools (F12), navigate to the Elements tab, and ins
## Mastering CSS Selectors
Think of CSS selectors as your way of pointing at things and saying "style THIS one!" They're like being super specific when giving directions - instead of saying "the house," you might say "the blue house with the red door on Maple Street."
CSS selectors are your way of targeting specific elements for styling. They work like giving precise directions - instead of saying "the house," you might say "the blue house with the red door on Maple Street."
CSS gives you different ways to be specific, and choosing the right one is like choosing the right tool for the job. Sometimes you want to paint every door in the neighborhood the same color, and sometimes you just want to paint one specific door.
CSS provides different ways to be specific, and choosing the right selector is like choosing the appropriate tool for the task. Sometimes you need to style every door in the neighborhood, and sometimes just one specific door.
### Element Selectors (Tags)
@ -279,9 +279,9 @@ Now add these styles to your `style.css` file:
## Understanding CSS Positioning
CSS positioning is like being the stage director for a play - you get to tell every actor exactly where to stand and how to move around the stage. Some actors follow the script and stand in normal formation, while others might need to be positioned in very specific spots for dramatic effect.
CSS positioning is like being the stage director for a play - you direct where every actor stands and how they move around the stage. Some actors follow the standard formation, while others need specific positioning for dramatic effect.
Once you get the hang of positioning, you'll feel like you have superpowers. Want that navigation bar to stick to the top while people scroll? Easy. Want to create a tooltip that appears exactly where someone clicks? You've got this!
Once you understand positioning, many layout challenges become manageable. Need a navigation bar that stays at the top while users scroll? Positioning handles that. Want a tooltip that appears at a specific location? That's positioning too.
### The Five Position Values
@ -332,9 +332,9 @@ Our terrarium uses a strategic combination of positioning types to create the de
## Building the Terrarium with CSS
Okay, here's where things get really fun - we're going to build a glass jar using nothing but CSS! No images, no fancy graphics software, just pure code magic.
Now we'll build a glass jar using only CSS - no images or graphics software required.
It's kind of mind-blowing when you realize you can create realistic-looking glass, shadows, and depth effects using just some clever positioning and transparency tricks. By the end of this, you'll look at websites completely differently - you'll start seeing the CSS "building blocks" behind every design!
Creating realistic-looking glass, shadows, and depth effects using positioning and transparency demonstrates CSS's visual capabilities. This technique mirrors how architects in the Bauhaus movement used simple geometric forms to create complex, beautiful structures. Once you understand these principles, you'll recognize the CSS techniques behind many web designs.
### Creating the Glass Jar Components
@ -430,9 +430,9 @@ Learn more about [agent mode](https://code.visualstudio.com/blogs/2025/02/24/int
## 🚀 Challenge: Adding Glass Reflections
Want to take your terrarium from "pretty good" to "absolutely stunning"? Let's add some glass reflections that'll make it look like you could actually reach out and touch it!
Ready to enhance your terrarium with realistic glass reflections? This technique will add depth and realism to the design.
This is where you get to play artist and scientist at the same time. You'll be creating those little highlights that trick your brain into seeing real glass. Here's what you're aiming for:
You'll create subtle highlights that simulate how light reflects off glass surfaces. This approach is similar to how Renaissance painters like Jan van Eyck used light and reflection to make painted glass appear three-dimensional. Here's what you're aiming for:
![finished terrarium](./images/terrarium-final.png)
@ -449,13 +449,13 @@ This is where you get to play artist and scientist at the same time. You'll be c
## Expand Your CSS Knowledge
Don't worry if CSS feels overwhelming at first - everyone goes through that "how is this even possible?" phase! The secret is that once you understand the core concepts (which you're learning right now), everything else starts clicking into place.
CSS can feel complex initially, but understanding these core concepts provides a solid foundation for more advanced techniques.
**Your next CSS adventures:**
- **Flexbox** - makes aligning things so much easier (seriously, you'll wonder how you lived without it)
- **CSS Grid** - like having superpowers for creating complex layouts
- **CSS Variables** - because nobody likes repeating the same color code 47 times
- **Responsive design** - making your sites look great on everything from phones to giant monitors
**Your next CSS learning areas:**
- **Flexbox** - simplifies alignment and distribution of elements
- **CSS Grid** - provides powerful tools for creating complex layouts
- **CSS Variables** - reduces repetition and improves maintainability
- **Responsive design** - ensures sites work well across different screen sizes
### Interactive Learning Resources

@ -3,11 +3,11 @@
![DOM and a closure](../../sketchnotes/webdev101-js.png)
> Sketchnote by [Tomomi Imura](https://twitter.com/girlie_mac)
Welcome to one of my favorite parts of web development - making things interactive! The Document Object Model (DOM) is like a bridge between your HTML and JavaScript, and today we're going to use it to bring your terrarium to life. I still remember the first time I made something draggable on a webpage - it felt like magic!
Welcome to one of the most engaging aspects of web development - making things interactive! The Document Object Model (DOM) is like a bridge between your HTML and JavaScript, and today we'll use it to bring your terrarium to life. When Tim Berners-Lee created the first web browser, he envisioned a web where documents could be dynamic and interactive - the DOM makes that vision possible.
We'll also explore JavaScript closures, which might sound intimidating at first. Don't worry though - think of closures as creating little "memory pockets" where your functions can remember important information. It's like each plant in your terrarium having its own notebook to keep track of where it's been moved. By the end of this lesson, you'll see how natural and useful they really are.
We'll also explore JavaScript closures, which might sound intimidating initially. Think of closures as creating "memory pockets" where your functions can remember important information. It's like each plant in your terrarium having its own data record to track its position. By the end of this lesson, you'll understand how natural and useful they are.
Here's what we're building together: a terrarium where users can drag and drop plants anywhere they want! You'll learn the DOM manipulation techniques that power everything from drag-and-drop file uploads to interactive games. Ready to make your terrarium come alive? Let's dive in!
Here's what we're building: a terrarium where users can drag and drop plants anywhere they want. You'll learn the DOM manipulation techniques that power everything from drag-and-drop file uploads to interactive games. Let's make your terrarium come alive.
## Pre-Lecture Quiz
@ -15,9 +15,9 @@ Here's what we're building together: a terrarium where users can drag and drop p
## Understanding the DOM: Your Gateway to Interactive Web Pages
The Document Object Model (DOM) is basically how JavaScript gets to "talk to" your HTML elements. When your browser loads an HTML page, it creates a living, breathing representation of that page in memory - that's the DOM! I like to think of it as a family tree where every HTML element is a family member that JavaScript can visit, chat with, or even rearrange.
The Document Object Model (DOM) is how JavaScript communicates with your HTML elements. When your browser loads an HTML page, it creates a structured representation of that page in memory - that's the DOM. Think of it as a family tree where every HTML element is a family member that JavaScript can access, modify, or rearrange.
Here's why this matters: DOM manipulation is what turns boring static pages into the interactive websites you love. Every time you see a button change color when you hover over it, content update without the page refreshing, or - like we're building today - elements you can drag around, that's DOM manipulation working its magic.
DOM manipulation transforms static pages into interactive websites. Every time you see a button change color on hover, content update without page refresh, or elements you can drag around, that's DOM manipulation at work.
![DOM tree representation](./images/dom-tree.png)
@ -31,11 +31,11 @@ Here's why this matters: DOM manipulation is what turns boring static pages into
## JavaScript Closures: Creating Organized, Powerful Code
A [JavaScript closure](https://developer.mozilla.org/docs/Web/JavaScript/Closures) is like giving a function its own private room with a really good memory. Picture a function that can "remember" variables from when it was created, even long after its parent function has finished running. It sounds complicated, but you'll see how naturally this happens when we build our dragging feature!
A [JavaScript closure](https://developer.mozilla.org/docs/Web/JavaScript/Closures) is like giving a function its own private workspace with persistent memory. Consider how Darwin's finches on the Galápagos Islands each developed specialized beaks based on their specific environment - closures work similarly, creating specialized functions that "remember" their specific context even after their parent function has finished.
In our terrarium, closures help each plant remember its own position independently - like each plant having its own GPS tracker. This pattern shows up everywhere in professional JavaScript, so you're learning something really valuable here.
In our terrarium, closures help each plant remember its own position independently. This pattern appears throughout professional JavaScript development, making it a valuable concept to understand.
> 💡 **Don't Stress About This**: Closures are a big topic in JavaScript, and honestly, many developers use them for years before fully grasping all the theory. Today, we're focusing on seeing them in action - you'll watch closures naturally emerge as we build our interactive features. The "aha!" moment will come when you see how they solve real problems.
> 💡 **Understanding Closures**: Closures are a significant topic in JavaScript, and many developers use them for years before fully grasping all the theoretical aspects. Today, we're focusing on practical application - you'll see closures naturally emerge as we build our interactive features. Understanding will develop as you see how they solve real problems.
![DOM tree representation](./images/dom-tree.png)
@ -45,21 +45,21 @@ In this lesson, we will complete our interactive terrarium project by creating t
## Before We Begin: Setting Up for Success
I hope you've got your HTML and CSS files from the previous terrarium lessons handy - we're about to make that beautiful static design come to life! If you're joining us for the first time, you might want to go back and complete those lessons first (trust me, it'll make this much more satisfying).
You'll need your HTML and CSS files from the previous terrarium lessons - we're about to make that static design interactive. If you're joining for the first time, completing those lessons first will provide important context.
Here's what we're going to build together:
- **Smooth drag-and-drop** for all your terrarium plants (seriously, it feels so satisfying!)
- **Smart coordinate tracking** so plants remember where you put them
- **A complete interactive interface** using just vanilla JavaScript (no fancy frameworks needed!)
- **Clean, organized code** using closure patterns (you'll be impressed with how elegant it is)
Here's what we'll build:
- **Smooth drag-and-drop** for all terrarium plants
- **Coordinate tracking** so plants remember their positions
- **A complete interactive interface** using vanilla JavaScript
- **Clean, organized code** using closure patterns
## Setting Up Your JavaScript File
Alright, let's create the JavaScript file that's going to make your terrarium interactive! This is where the magic happens.
Let's create the JavaScript file that will make your terrarium interactive.
**Step 1: Create your script file**
In your terrarium folder, create a new file called `script.js`. Exciting, right?
In your terrarium folder, create a new file called `script.js`.
**Step 2: Link the JavaScript to your HTML**
@ -69,21 +69,21 @@ Add this script tag to the `<head>` section of your `index.html` file:
<script src="./script.js" defer></script>
```
**Why that little `defer` word matters so much:**
- **Makes sure** your JavaScript waits until all your HTML is loaded (no rushing ahead!)
- **Prevents** those annoying errors where JavaScript looks for elements that aren't there yet
- **Guarantees** all your plant elements are ready and waiting for interaction
- **Gives** you better performance than throwing scripts at the bottom of your page
**Why the `defer` attribute is important:**
- **Ensures** your JavaScript waits until all HTML is loaded
- **Prevents** errors where JavaScript looks for elements that aren't ready yet
- **Guarantees** all your plant elements are available for interaction
- **Provides** better performance than placing scripts at the page bottom
> ⚠️ **Trust me on this**: The `defer` attribute is your friend here. I've seen too many students get frustrated when their JavaScript tries to grab HTML elements that haven't loaded yet. This little word prevents those headaches!
> ⚠️ **Important Note**: The `defer` attribute prevents common timing issues. Without it, JavaScript may try to access HTML elements before they're loaded, causing errors.
---
## Connecting JavaScript to Your HTML Elements
Before we can make elements draggable, JavaScript needs to "find" them in the DOM. I like to think of this as getting each plant's phone number - once you have that direct line, you can call up any plant and tell it exactly how to behave when someone tries to drag it around!
Before we can make elements draggable, JavaScript needs to locate them in the DOM. Think of this like a library cataloging system - once you have the catalog number, you can find exactly the book you need and access all its contents.
We'll use the `document.getElementById()` method to make these connections. It's like having a really good address book - you give it an ID, and it finds exactly the element you're looking for in your HTML.
We'll use the `document.getElementById()` method to make these connections. It's like having a precise filing system - you provide an ID, and it locates exactly the element you need in your HTML.
### Enabling Drag Functionality for All Plants
@ -128,7 +128,7 @@ Closures are perfect for this task because they allow us to create "private" var
### Understanding Closures with a Simple Example
Let me show you a simple closure example that'll make this click:
Let me demonstrate closures with a simple example that illustrates the concept:
```javascript
function createCounter() {
@ -147,11 +147,11 @@ console.log(myCounter()); // 1
console.log(myCounter()); // 2
```
**Here's what's happening (and why it's actually pretty cool):**
- **Creates** a private `count` variable that only lives inside this closure
- **The inner function** can still access and change that outer variable (that's the closure magic!)
- **When we return** the inner function, it keeps its connection to that private data
- **Even after** `createCounter()` finishes, `count` sticks around and remembers its value
**Here's what's happening in this closure pattern:**
- **Creates** a private `count` variable that only exists within this closure
- **The inner function** can access and modify that outer variable (the closure mechanism)
- **When we return** the inner function, it maintains its connection to that private data
- **Even after** `createCounter()` finishes execution, `count` persists and remembers its value
### Why Closures Are Perfect for Drag Functionality
@ -196,7 +196,7 @@ function dragElement(terrariumElement) {
### Why Use Pointer Events?
You might be wondering why we're using `onpointerdown` instead of the more familiar `onclick`. Great question! Here's the deal:
You might wonder why we use `onpointerdown` instead of the more familiar `onclick`. Here's the reasoning:
| Event Type | Best For | The Catch |
|------------|----------|-------------|
@ -389,14 +389,14 @@ Congratulations! You've just built a sophisticated drag-and-drop system using va
### Testing Your Interactive Terrarium
This is the moment of truth! Open your `index.html` file in a web browser and try out your creation:
Now test your interactive terrarium! Open your `index.html` file in a web browser and try the functionality:
1. **Click and hold** any plant to start dragging (feels satisfying, doesn't it?)
2. **Move your mouse or finger** and watch the plant follow along smoothly
3. **Release** to drop the plant in its new spot
4. **Go wild!** Try different arrangements - this is your creative playground now
1. **Click and hold** any plant to start dragging
2. **Move your mouse or finger** and watch the plant follow smoothly
3. **Release** to drop the plant in its new position
4. **Experiment** with different arrangements to explore the interface
🥇 **Seriously, take a moment to appreciate what you just built!** You've created a fully interactive web application using core concepts that professional developers use every day. That drag-and-drop functionality you just coded? It's the same principle behind everything from file uploads to kanban boards. You should feel pretty proud right now!
🥇 **Achievement**: You've created a fully interactive web application using core concepts that professional developers use daily. That drag-and-drop functionality uses the same principles behind file uploads, kanban boards, and many other interactive interfaces.
![finished terrarium](./images/terrarium-final.png)

@ -1,10 +1,10 @@
# Creating a game using events
Have you ever wondered how websites know when you click a button or type in a text box? That's the magic of event-driven programming! And what better way to learn this essential skill than by building something absolutely fun - a typing speed game that reacts to every keystroke you make.
Have you ever wondered how websites know when you click a button or type in a text box? That's the magic of event-driven programming! What better way to learn this essential skill than by building something useful - a typing speed game that reacts to every keystroke you make.
I'm genuinely excited to walk you through this project because you're going to see firsthand how web browsers "talk" to your JavaScript code. Every time you click, type, or move your mouse, the browser is sending little messages (we call them events) to your code, and you get to decide how to respond!
You're going to see firsthand how web browsers "talk" to your JavaScript code. Every time you click, type, or move your mouse, the browser is sending little messages (we call them events) to your code, and you get to decide how to respond!
By the time we're done here, you'll have built a real typing game that tracks your speed and accuracy. More importantly, you'll understand the fundamental concepts that power every interactive website you've ever used. Ready to make some magic happen? Let's jump in!
By the time we're done here, you'll have built a real typing game that tracks your speed and accuracy. More importantly, you'll understand the fundamental concepts that power every interactive website you've ever used. Let's dive in!
## Pre-Lecture Quiz
@ -14,15 +14,15 @@ By the time we're done here, you'll have built a real typing game that tracks yo
Think about your favorite app or website - what makes it feel alive and responsive? It's all about how it reacts to what you do! Every tap, click, swipe, or keystroke creates what we call an "event," and that's where the real magic of web development happens.
Here's the thing that makes programming for the web so interesting (and sometimes tricky): we never know when someone will click that button or start typing in a text box. They might click immediately, wait five minutes, or maybe never click at all! This unpredictability means we need to think differently about how we write our code.
Here's what makes programming for the web so interesting: we never know when someone will click that button or start typing in a text box. They might click immediately, wait five minutes, or maybe never click at all! This unpredictability means we need to think differently about how we write our code.
Instead of writing code that runs from top to bottom like a recipe, we write code that sits patiently waiting for something to happen. It's like having a really attentive waiter who's always ready to spring into action the moment you need something!
Instead of writing code that runs from top to bottom like a recipe, we write code that sits patiently waiting for something to happen. It's similar to how telegraph operators in the 1800s would sit by their machines, ready to respond the moment a message came through the wire.
So what exactly is an "event"? Simply put, it's just something that happens! When you click a button - that's an event. When you type a letter - that's an event. When you move your mouse - yep, another event.
So what exactly is an "event"? Simply put, it's something that happens! When you click a button - that's an event. When you type a letter - that's an event. When you move your mouse - that's another event.
The beautiful thing about event-driven programming is that we can set up our code to be like a good friend who's always listening. We create special functions called **event listeners** that wait patiently for specific things to happen, then jump into action when they do.
Event-driven programming lets us set up our code to listen and respond. We create special functions called **event listeners** that wait patiently for specific things to happen, then spring into action when they do.
Think of event listeners like having a doorbell for your code. You set up the doorbell (`addEventListener()`), tell it what sound to listen for (like a 'click' or 'keypress'), and then specify what should happen when someone rings it (your custom function). Pretty neat, right?
Think of event listeners like having a doorbell for your code. You set up the doorbell (`addEventListener()`), tell it what sound to listen for (like a 'click' or 'keypress'), and then specify what should happen when someone rings it (your custom function).
**Here's how event listeners work:**
- **Listens** for specific user actions like clicks, keystrokes, or mouse movements
@ -53,9 +53,9 @@ There are [dozens of events](https://developer.mozilla.org/docs/Web/Events) avai
## Creating the game
Now that you understand how events work, let's put that knowledge into practice by building something engaging and useful. We'll create a typing speed game that demonstrates event handling while helping you develop a crucial developer skill.
Now that you understand how events work, let's put that knowledge into practice by building something useful. We'll create a typing speed game that demonstrates event handling while helping you develop an important developer skill.
We are going to create a game to explore how events work in JavaScript. Our game is going to test a player's typing skill, which is one of the most underrated skills all developers should have. We should all be practicing our typing! The general flow of the game will look like this:
We're going to create a game to explore how events work in JavaScript. Our game will test a player's typing skill, which is one of the most underrated skills all developers should have. Fun fact: the QWERTY keyboard layout we use today was actually designed in the 1870s for typewriters - and good typing skills are still just as valuable for programmers today! The general flow of the game will look like this:
```mermaid
flowchart TD
@ -84,7 +84,7 @@ Let's build our game, and learn about events!
### File structure
Before we start coding, let's get organized! I know it might seem like extra work now, but trust me - having a clean file structure from the beginning will save you tons of headaches later. Plus, it'll make you look like a pro! 😊
Before we start coding, let's get organized! Having a clean file structure from the beginning will save you headaches later and make your project more professional. 😊
We're going to keep things simple with just three files: `index.html` for our page structure, `script.js` for all our game logic, and `style.css` to make everything look great. This is the classic trio that powers most of the web!
@ -121,9 +121,9 @@ code .
## Create the user interface
Alright, let's build the stage where all our game action will happen! Think of this like designing the control panel for a spaceship - we need to make sure everything our players need is right where they expect it to be.
Now let's build the stage where all our game action will happen! Think of this like designing the control panel for a spaceship - we need to make sure everything our players need is right where they expect it to be.
Let's figure out what our game actually needs. If you were playing a typing game, what would you want to see on the screen? Here's what I'm thinking we'll need:
Let's figure out what our game actually needs. If you were playing a typing game, what would you want to see on the screen? Here's what we'll need:
| UI Element | Purpose | HTML Element |
|------------|---------|-------------|
@ -204,7 +204,7 @@ You should now see the page you created! Let's add some functionality.
## Add the CSS
Now for one of my favorite parts - making things look good! You know how satisfying it is when an app gives you instant feedback? Like when a button changes color when you hover over it, or when a form field turns red if you've made a mistake? That's exactly what we're going to create.
Now let's make things look good! Visual feedback has been crucial for user interfaces since the early days of computing. In the 1980s, researchers discovered that immediate visual feedback dramatically improves user performance and reduces errors. That's exactly what we're going to create.
Our game needs to be crystal clear about what's happening. Players should immediately know which word they're supposed to type, and if they make a mistake, they should see it right away. Let's create some simple but effective styling:
@ -236,9 +236,9 @@ Create a new file named `style.css` and add the following syntax.
## JavaScript
Okay, here's where things get really fun! 🎉 We've got our HTML structure and our CSS styling, but right now our game is like a beautiful car without an engine. JavaScript is going to be that engine - it's what makes everything actually work and respond to what players do.
Here's where things get interesting! 🎉 We've got our HTML structure and our CSS styling, but right now our game is like a beautiful car without an engine. JavaScript is going to be that engine - it's what makes everything actually work and respond to what players do.
I love this part because you'll literally see your creation come to life. We're going to tackle this step by step so nothing feels overwhelming:
This is where you'll see your creation come to life. We're going to tackle this step by step so nothing feels overwhelming:
| Step | Purpose | What You'll Learn |
|------|---------|------------------|
@ -256,7 +256,7 @@ But first, create a new file named `script.js`.
### Add the constants
Before we dive into the action, let's gather all our ingredients! Just like when you're cooking, it's so much easier when you have everything prepped and ready to go. This saves us from hunting around for things later and helps prevent those annoying typos that can drive you crazy.
Before we dive into the action, let's gather all our resources! Just like how NASA mission control sets up all their monitoring systems before launch, it's much easier when you have everything prepared and ready to go. This saves us from hunting around for things later and helps prevent typos.
Here's what we need to set up first:
@ -322,9 +322,9 @@ Take a minute to watch a video on using `const`, `let` and `var`
### Add start logic
This is it - the moment where everything clicks into place! 🚀 You're about to write your first real event listener, and I have to say, there's something pretty magical about the first time you see your code respond to a button click.
This is where everything clicks into place! 🚀 You're about to write your first real event listener, and there's something quite satisfying about seeing your code respond to a button click.
Think about it: somewhere out there, a player is going to click that "Start" button, and your code needs to be ready for them. We have no idea when they'll click it - could be immediately, could be after they grab a coffee - but when they do, boom! Your game springs to life.
Think about it: somewhere out there, a player is going to click that "Start" button, and your code needs to be ready for them. We have no idea when they'll click it - could be immediately, could be after they grab a coffee - but when they do, your game springs to life.
When the user clicks `start`, we need to select a quote, setup the user interface, and setup tracking for the current word and timing. Below is the JavaScript you'll need to add; we discuss it just after the script block.
@ -387,9 +387,9 @@ document.getElementById('start').addEventListener('click', () => {
### Add typing logic
Alright, here's where we tackle the heart of our game! Don't worry if this seems like a lot at first - I'm going to walk you through every piece, and by the end, you'll be amazed at how logical it all is.
Here's where we tackle the heart of our game! Don't worry if this seems like a lot at first - we'll walk through every piece, and by the end, you'll see how logical it all is.
What we're building here is pretty cool: every single time someone types a letter, our code is going to check what they typed, give them feedback, and decide what should happen next. It's like having a really fast, really patient teacher looking over their shoulder!
What we're building here is quite sophisticated: every single time someone types a letter, our code is going to check what they typed, give them feedback, and decide what should happen next. It's similar to how early word processors like WordStar in the 1970s provided real-time feedback to typists.
```javascript
// at the end of script.js
@ -469,9 +469,9 @@ flowchart TD
## Test your application
Holy moly, look what you've accomplished! 🎉 You just built a real, working typing game from scratch using event-driven programming. Seriously, take a moment to appreciate that - this is no small feat!
Look what you've accomplished! 🎉 You just built a real, working typing game from scratch using event-driven programming. Take a moment to appreciate that - this is no small feat!
Now comes the fun part - testing your creation! I always get a little nervous and excited at this stage. Will it work? Did I miss something? Here's the thing: if something doesn't work perfectly right away, that's totally normal. I've been doing this for years, and I still find bugs in my code all the time. It's all part of the process!
Now comes the testing phase! Will it work as expected? Did we miss something? Here's the thing: if something doesn't work perfectly right away, that's completely normal. Even experienced developers find bugs in their code regularly. It's all part of the development process!
Click on `start`, and start typing away! It should look a little like the animation we saw before.

@ -9,19 +9,17 @@
### Introduction
Have you ever wished you could add a custom button to your browser or automatically fill in forms with your information? That's exactly what browser extensions do! They're like having a personal assistant built right into your browser, ready to help with whatever you need.
Browser extensions are mini-applications that enhance your web browsing experience. Like Tim Berners-Lee's original vision of an interactive web, extensions extend the browser's capabilities beyond simple document viewing. From password managers that keep your accounts secure to color pickers that help designers grab perfect shades, extensions solve everyday browsing challenges.
Browser extensions are mini-applications that live inside your browser - think of them as your browser's superpowers. From password managers that keep your accounts secure to color pickers that help designers grab perfect shades, extensions make your web browsing so much more efficient and enjoyable.
Before we build your first extension, let's understand how browsers work. Just as Alexander Graham Bell needed to understand sound transmission before inventing the telephone, knowing browser fundamentals will help you create extensions that integrate seamlessly with existing browser systems.
Before we jump into building your very own extension, let's take a peek under the hood to see how browsers actually work. Don't worry - this isn't going to be a boring technical deep-dive! Understanding these basics will help you build extensions that work smoothly and make sense to your users.
By the end of this lesson, you'll not only understand how browsers tick, but you'll also have started building your first real extension. Pretty exciting, right? Let's get started!
By the end of this lesson, you'll understand browser architecture and have started building your first extension.
## Understanding Web Browsers
Let's start with the basics - what exactly is a browser, and how does it work its magic? Understanding this will help you build extensions that feel natural and work seamlessly with what your browser is already doing.
A web browser is essentially a sophisticated document interpreter. When you type "google.com" into the address bar, the browser performs a complex series of operations - requesting content from servers worldwide, then parsing and rendering that code into the interactive web pages you see.
Think of your web browser as a super-smart translator. When you type "google.com" into the address bar, your browser doesn't just magically know what to show you. It's actually doing a lot of behind-the-scenes work - like asking servers around the world for content, then translating all that code into the beautiful, interactive web pages you see every day.
This process mirrors how the first web browser, WorldWideWeb, was designed by Tim Berners-Lee in 1990 to make hyperlinked documents accessible to everyone.
**A little history**: The first browser was called 'WorldWideWeb' and was created by Sir Timothy Berners-Lee in 1990.
@ -30,7 +28,7 @@ Think of your web browser as a super-smart translator. When you type "google.com
### How Browsers Process Web Content
Ever wonder what happens in those few seconds between hitting Enter and seeing a webpage? Let's follow that journey together - it's actually pretty fascinating!
The process between entering a URL and seeing a webpage involves several coordinated steps that happen within seconds:
```mermaid
sequenceDiagram
@ -56,7 +54,7 @@ sequenceDiagram
### Browser Core Features
Now here's where it gets interesting for us extension builders! Modern browsers come packed with features that we can tap into to make our extensions awesome:
Modern browsers provide numerous features that extension developers can leverage:
| Feature | Purpose | Extension Opportunities |
|---------|---------|------------------------|
@ -74,7 +72,7 @@ Now here's where it gets interesting for us extension builders! Modern browsers
### Cross-Browser Development Considerations
Here's something that might surprise you - not all browsers are created equal! Each one has its own personality, if you will. Chrome might handle something differently than Firefox, and that's totally normal. As we build extensions together, we'll learn to work with these differences rather than fight against them.
Different browsers implement standards with slight variations, similar to how different programming languages might handle the same algorithm differently. Chrome, Firefox, and Safari each have unique characteristics that developers must consider during extension development.
> 💡 **Pro Tip**: Use [caniuse.com](https://www.caniuse.com) to check which web technologies are supported across different browsers. This is invaluable when planning your extension's features!
@ -88,9 +86,9 @@ Here's something that might surprise you - not all browsers are created equal! E
## Understanding Browser Extensions
You know those little moments when you're browsing and think "I wish I could just..."? Maybe you want to quickly save an article for later, or grab that perfect color from a website, or translate a funny meme your friend sent you. That's exactly where browser extensions shine!
Browser extensions solve common web browsing challenges by adding functionality directly to the browser interface. Rather than requiring separate applications or complex workflows, extensions provide immediate access to tools and features.
Extensions are like having a toolbox right inside your browser. Instead of opening separate apps or switching between windows, everything you need is just a click away. They're designed to solve those everyday web browsing frustrations and make your online life smoother.
This concept mirrors how early computer pioneers like Douglas Engelbart envisioned augmenting human capabilities with technology - extensions augment your browser's basic functionality.
**Popular extension categories and their benefits:**
- **Productivity Tools**: Task managers, note-taking apps, and time trackers that help you stay organized
@ -102,9 +100,7 @@ Extensions are like having a toolbox right inside your browser. Instead of openi
## Installing and Managing Extensions
Before we start building, let's get familiar with how extensions actually get into your browser. Think of this as learning the neighborhood before you move in - it'll help you understand what your users will experience when they install your creation!
The good news? Installing extensions is pretty straightforward across all browsers. There are a few small differences here and there, but once you've done it in one browser, you'll feel comfortable in any of them.
Understanding the extension installation process helps you anticipate the user experience when people install your extension. The installation process is standardized across modern browsers, with minor variations in interface design.
![screenshot of the Edge browser showing the open edge://extensions page and open settings menu](images/install-on-edge.png)
@ -146,13 +142,13 @@ npm run build
## Building Your Carbon Footprint Extension
Ready to build something cool? We're going to create a browser extension that shows you the carbon footprint of your region's energy use. Not only will this teach you all the essential extension development skills, but you'll also end up with something that's actually meaningful and useful!
We'll create a browser extension that displays the carbon footprint of your region's energy use. This project demonstrates essential extension development concepts while creating a practical tool for environmental awareness.
I love this project because it combines learning with purpose. Every time you use your extension, you'll get a little reminder about your environmental impact. Plus, you might be surprised by what you discover about your local energy sources - I know I was when I first built this!
This approach follows the principle of "learning by doing" that has proven effective since John Dewey's educational theories - combining technical skills with meaningful real-world applications.
### Project Requirements
Before we dive into the fun stuff, let's gather everything we need. Don't worry - it's not as complicated as it might look!
Before beginning development, let's gather the required resources and dependencies:
**Required API Access:**
- **[CO2 Signal API key](https://www.co2signal.com/)**: Enter your email address to receive your free API key
@ -166,7 +162,7 @@ Before we dive into the fun stuff, let's gather everything we need. Don't worry
### Understanding the Project Structure
Let's take a quick tour of our extension's folder structure. Think of this as getting familiar with your new workspace - once you know where everything lives, development becomes so much smoother!
Understanding the project structure helps organize development work efficiently. Like how the Library of Alexandria was organized for easy knowledge retrieval, a well-structured codebase makes development more efficient:
```
project-root/
@ -192,9 +188,9 @@ project-root/
## Creating the Extension Interface
Time for the exciting part - building what users will actually see and interact with! We're going to create two simple but effective screens that work together beautifully.
Now we'll build the user interface components. The extension uses a two-screen approach: a configuration screen for initial setup and a results screen for data display.
Think of it like this: the first screen is where users tell your extension about themselves (like their region and API key), and the second screen is where the magic happens - showing them their carbon footprint data. It's a simple, logical flow that won't confuse anyone.
This follows the progressive disclosure principle used in interface design since the early days of computing - revealing information and options in a logical sequence to avoid overwhelming users.
### Extension Views Overview
@ -206,7 +202,7 @@ Think of it like this: the first screen is where users tell your extension about
### Building the Configuration Form
Let's start with the setup form - this is where users will enter their information the first time they use your extension. The cool thing is, once they've set it up, they won't need to do this again!
The setup form collects user configuration data during initial use. Once configured, this information persists in browser storage for future sessions.
In the `/dist/index.html` file, add this form structure:
@ -284,13 +280,13 @@ At this point, you can test your extension:
3. **Verify** that the form displays correctly and looks professional
4. **Check** that all form elements are properly aligned and functional
**Look at what you've accomplished:**
**What you've accomplished:**
- **Built** the foundational HTML structure for your extension
- **Created** both configuration and results interfaces that actually look professional
- **Set up** a modern development workflow (you're basically a pro now!)
- **Prepared** everything for the next phase where we'll bring it to life with JavaScript
- **Created** both configuration and results interfaces with proper semantic markup
- **Set up** a modern development workflow using industry-standard tools
- **Prepared** the foundation for adding interactive JavaScript functionality
Seriously, take a moment to appreciate what you've just done! You've taken the first major step in browser extension development. The hardest part - getting started - is behind you. In our next lesson, we'll add the JavaScript magic that will make your extension truly interactive and useful. You're going to love seeing it come together!
You've completed the first phase of browser extension development. Like how the Wright brothers first needed to understand aerodynamics before achieving flight, understanding these foundational concepts prepares you for building more complex interactive features in the next lesson.
## GitHub Copilot Agent Challenge 🚀

@ -6,21 +6,21 @@
## Introduction
Hey there! Remember that browser extension you started building? Well, it's about to get really exciting! Right now you've got a nice-looking form, but it's basically just sitting there looking pretty. Time to wake it up and make it actually *do* something amazing!
Remember that browser extension you started building? Right now you've got a nice-looking form, but it's essentially static. Today we'll bring it to life by connecting it to real data and giving it memory.
Think about your favorite apps - they don't just show you static information, right? They talk to servers, remember your preferences, and update with fresh data. That's exactly what we're going to build today. Your extension will reach out to the internet, grab real environmental data, and even remember your settings for next time.
Think about the Apollo mission control computers - they didn't just display fixed information. They constantly communicated with spacecraft, updated with telemetry data, and remembered critical mission parameters. That's the kind of dynamic behavior we're building today. Your extension will reach out to the internet, grab real environmental data, and remember your settings for next time.
API integration might sound intimidating, but it's really just teaching your code how to have conversations with other services. Whether you're grabbing weather updates, social media posts, or carbon footprint data like we'll do today, it's all about making these digital connections. Plus, we'll explore how your browser can remember things - kind of like having a really good memory!
API integration might sound complex, but it's really just teaching your code how to communicate with other services. Whether you're fetching weather data, social media feeds, or carbon footprint information like we'll do today, it's all about establishing these digital connections. We'll also explore how browsers can persist information - similar to how libraries have used card catalogs to remember where books belong.
By the time we're done, you'll have a browser extension that feels alive - fetching real data, storing user preferences, and providing a smooth experience. Ready to dive into this digital magic? Let's go!
By the end of this lesson, you'll have a browser extension that fetches real data, stores user preferences, and provides a smooth experience. Let's get started!
✅ Follow the numbered segments in the appropriate files to know where to place your code
## Set up the elements to manipulate in the extension
Alright, let's connect the dots! Before your JavaScript can work its magic, it needs to know which parts of your HTML it's allowed to control. Think of it like introducing your code to each button, input field, and display area - "Hey JavaScript, meet the submit button. Submit button, this is JavaScript. You two are going to be working together!"
Before your JavaScript can manipulate the interface, it needs references to specific HTML elements. Think of it like a telescope needing to be pointed at particular stars - before Galileo could study Jupiter's moons, he had to locate and focus on Jupiter itself.
In your `index.js` file, we'll create some `const` variables that grab onto each important piece of your form. It's like creating a contact list for your code - instead of hunting around the entire page every time, your JavaScript can just look up exactly what it needs.
In your `index.js` file, we'll create `const` variables that capture references to each important form element. This is similar to how scientists label their equipment - instead of searching through the entire laboratory each time, they can directly access what they need.
```javascript
// form fields
@ -47,7 +47,7 @@ const clearBtn = document.querySelector('.clear-btn');
## Add event listeners
Time to make your extension actually respond to user actions! Event listeners are basically your code's way of paying attention to what users are doing. Think of them like a helpful friend who's always watching and saying, "Oh, they clicked that button? Let me handle that for you!" or "Looks like they submitted the form - I've got this!"
Now we'll make your extension respond to user actions. Event listeners are your code's way of monitoring user interactions. Think of them like the operators in early telephone exchanges - they listened for incoming calls and connected the right circuits when someone wanted to make a connection.
```javascript
form.addEventListener('submit', (e) => handleSubmit(e));
@ -65,9 +65,9 @@ init();
## Build the initialization and reset functions
Let's create the brain of your extension! The `init()` function is like your extension waking up and asking, "Okay, what's the situation here? Is this a new user, or have I seen them before?" It's surprisingly smart - it'll check if someone has used your extension before and adjust accordingly. Pretty cool, right?
Let's create the initialization logic for your extension. The `init()` function is like a ship's navigation system checking its instruments - it determines the current state and adjusts the interface accordingly. It checks if someone has used your extension before and loads their previous settings.
The `reset()` function is your extension's way of giving users a fresh start - kind of like hitting the "restart" button when things get messy.
The `reset()` function provides users with a fresh start - similar to how scientists reset their instruments between experiments to ensure clean data.
```javascript
function init() {
@ -116,13 +116,13 @@ function reset(e) {
- **Returns** `null` when no data exists for a given key
- **Provides** a simple way to remember user preferences and settings
> 💡 **Understanding Browser Storage**: [LocalStorage](https://developer.mozilla.org/docs/Web/API/Window/localStorage) is like giving your extension a memory! Imagine if every time you visited a website, it had to ask for your name again - pretty annoying, right?
> 💡 **Understanding Browser Storage**: [LocalStorage](https://developer.mozilla.org/docs/Web/API/Window/localStorage) is like giving your extension persistent memory. Consider how the ancient Library of Alexandria stored scrolls - information remained available even when scholars left and returned.
>
> **Here's the cool part:**
> - **Remembers** stuff even after you close your browser (unlike your short-term memory!)
> - **Survives** computer restarts, browser crashes, you name it
> - **Gives** you plenty of space - think thousands of user preferences
> - **Works** instantly - no waiting around for data to load
> **Key characteristics:**
> - **Persists** data even after you close your browser
> - **Survives** computer restarts and browser crashes
> - **Provides** substantial storage space for user preferences
> - **Offers** instant access without network delays
> **Important Note**: Your browser extension has its own isolated local storage that's separate from regular web pages. This provides security and prevents conflicts with other websites.
@ -134,9 +134,9 @@ You can view your stored data by opening browser Developer Tools (F12), navigati
## Handle form submission
Now for the moment of truth - what happens when someone actually uses your form? By default, browsers have their own ideas about form submission (usually involving page reloads), but we're going to politely interrupt and say, "Thanks browser, but we've got this!"
Now we'll handle what happens when someone submits your form. By default, browsers reload the page when forms are submitted, but we'll intercept this behavior to create a smoother experience.
This is where things get really interesting for modern web apps and extensions - instead of the old-school "submit and reload" approach, we're creating a smooth, seamless experience.
This approach mirrors how mission control handles spacecraft communications - instead of resetting the entire system for each transmission, they maintain continuous operation while processing new information.
Create a function that captures the form submission event and extracts the user's input:
@ -186,11 +186,11 @@ This function creates a seamless user experience by managing both data persisten
## Display carbon usage data
Okay, this is where things get really fun! We're about to turn your extension into something that talks to the wider internet and pulls in real, live data. It's like giving your extension superpowers!
Now we'll connect your extension to external data sources through APIs. This transforms your extension from a standalone tool into something that can access real-time information from across the internet.
**What's this API thing all about?**
**Understanding APIs**
[APIs](https://www.webopedia.com/TERM/A/API.html) are basically how different apps and services talk to each other. Think of them like a waiter at a restaurant - you tell the waiter what you want, they go to the kitchen (the server), and come back with your order (the data). Every time you check Instagram, ask Siri a question, or use a food delivery app, APIs are making it all happen behind the scenes.
[APIs](https://www.webopedia.com/TERM/A/API.html) are how different applications communicate with each other. Think of them like the telegraph system that connected distant cities in the 19th century - operators would send requests to distant stations and receive responses with the requested information. Every time you check social media, ask a voice assistant a question, or use a delivery app, APIs are facilitating these data exchanges.
**Key concepts about REST APIs:**
- **REST** stands for 'Representational State Transfer'
@ -200,13 +200,13 @@ Okay, this is where things get really fun! We're about to turn your extension in
✅ The [CO2 Signal API](https://www.co2signal.com/) we'll use provides real-time carbon intensity data from electrical grids worldwide. This helps users understand the environmental impact of their electricity usage!
> 💡 **Understanding Asynchronous JavaScript**: The [`async` keyword](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/async_function) is like teaching your code to multitask! When you ask a server for data, you don't want your entire extension to just freeze and wait - that would be like pausing your whole life while waiting for a text message reply.
> 💡 **Understanding Asynchronous JavaScript**: The [`async` keyword](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Statements/async_function) enables your code to handle multiple operations simultaneously. When you request data from a server, you don't want your entire extension to freeze - that would be like air traffic control stopping all operations while waiting for one plane to respond.
>
> **Here's why this is awesome:**
> - **Keeps** your extension responsive - users can still click buttons while data loads
> - **Lets** other parts of your code keep working while waiting for responses
> - **Makes** your code way easier to read than the old callback maze
> - **Helps** you handle problems gracefully when the internet is being grumpy
> **Key benefits:**
> - **Maintains** extension responsiveness while data loads
> - **Allows** other code to continue executing during network requests
> - **Improves** code readability compared to traditional callback patterns
> - **Enables** graceful error handling for network issues
Here's a quick video about `async`:
@ -281,15 +281,15 @@ async function displayCarbonUsage(apiKey, region) {
- **Object destructuring** to extract specific data from API responses
- **Method chaining** for multiple DOM manipulations
Look at what you just built! This function is doing some seriously impressive stuff - talking to external servers, handling authentication, processing data, updating your interface, and even dealing with errors like a pro. These are the exact skills that professional developers use every day!
This function demonstrates several important web development concepts - communicating with external servers, handling authentication, processing data, updating interfaces, and managing errors gracefully. These are fundamental skills that professional developers use regularly.
🎉 **Holy moly, look what you've accomplished!** You've created a browser extension that actually:
- **Reaches** out to the internet and grabs real environmental data
- **Remembers** user settings between sessions (so smart!)
- **Handles** problems gracefully instead of just crashing
- **Feels** smooth and professional to use
🎉 **What you've accomplished:** You've created a browser extension that:
- **Connects** to the internet and retrieves real environmental data
- **Persists** user settings between sessions
- **Handles** errors gracefully instead of crashing
- **Provides** a smooth, professional user experience
Go ahead and test it out - run `npm run build` and refresh your extension in the browser. You've got yourself a legitimate carbon footprint tracker that could genuinely help people! The only thing left is adding that dynamic icon in the next lesson, and then you'll have built something truly complete.
Test your work by running `npm run build` and refreshing your extension in the browser. You now have a functional carbon footprint tracker. The next lesson will add dynamic icon functionality to complete the extension.
---

@ -1,10 +1,10 @@
# Browser Extension Project Part 3: Learn about Background Tasks and Performance
Ever wonder what makes some browser extensions feel snappy and responsive while others seem sluggish? The secret lies in what's happening behind the scenes! While users click around your extension's interface, there's a whole world of background processes quietly managing data fetching, icon updates, and system resources.
Ever wonder what makes some browser extensions feel snappy and responsive while others seem sluggish? The secret lies in what's happening behind the scenes. While users click around your extension's interface, there's a whole world of background processes quietly managing data fetching, icon updates, and system resources.
This is our final lesson in the browser extension series, and we're going to make your carbon footprint tracker really shine. You'll add those satisfying dynamic icon updates and learn how to spot performance issues before they become problems. Think of it as giving your extension a turbo boost!
This is our final lesson in the browser extension series, and we're going to make your carbon footprint tracker work smoothly. You'll add dynamic icon updates and learn how to spot performance issues before they become problems. It's like tuning a race car - small optimizations can make a huge difference in how everything runs.
By the time we're done, you'll not only have a polished extension that works beautifully, but you'll also understand the performance principles that separate good web apps from great ones. Ready to make your extension lightning-fast? Let's jump in!
By the time we're done, you'll have a polished extension and understand the performance principles that separate good web apps from great ones. Let's dive into the world of browser optimization.
## Pre-Lecture Quiz
@ -12,23 +12,23 @@ By the time we're done, you'll not only have a polished extension that works bea
### Introduction
Look how far you've come! In our previous lessons, you built a form, connected it to an API, and even tackled asynchronous data fetching. Your extension is looking pretty good already, isn't it?
In our previous lessons, you built a form, connected it to an API, and tackled asynchronous data fetching. Your extension is taking shape nicely.
Now we need to add the finishing touches - like making that extension icon change colors based on the carbon data. This is the perfect moment to peek under the hood and see how browsers actually handle these background tasks. You'll be amazed at what's happening behind the scenes every time your code runs!
Now we need to add the finishing touches - like making that extension icon change colors based on the carbon data. This reminds me of how NASA had to optimize every system on the Apollo spacecraft. They couldn't afford any wasted cycles or memory because lives depended on performance. While our browser extension isn't quite that critical, the same principles apply - efficient code creates better user experiences.
## Web Performance Basics
Here's something cool: when your code runs efficiently, people can actually *feel* the difference! You know that satisfying moment when a page loads instantly or an animation flows perfectly? That's good performance at work, and you can learn to create those "wow" moments too.
When your code runs efficiently, people can actually *feel* the difference. You know that moment when a page loads instantly or an animation flows smoothly? That's good performance at work.
Performance isn't just about speed - it's about making web experiences that feel smooth and natural instead of clunky and frustrating. Let's explore the detective tools that help you figure out what's slowing things down, and then we'll use these insights to make your browser extension absolutely fly.
Performance isn't just about speed - it's about making web experiences that feel natural instead of clunky and frustrating. Back in the early days of computing, Grace Hopper famously kept a nanosecond (a piece of wire about a foot long) on her desk to show how far light travels in one billionth of a second. It was her way of explaining why every microsecond matters in computing. Let's explore the detective tools that help you figure out what's slowing things down.
> "Website performance is about two things: how fast the page loads, and how fast the code on it runs." -- [Zack Grossbart](https://www.smashingmagazine.com/2012/06/javascript-profiling-chrome-developer-tools/)
The topic of how to make your websites blazingly fast on all kinds of devices, for all kinds of users, in all kinds of situations, is unsurprisingly vast. Here are some points to keep in mind as you build either a standard web project or a browser extension.
The first step in making your site blazing fast? You need to see what's actually happening under the hood! Fortunately, your browser comes with amazing detective tools built right in.
The first step in optimizing your site is understanding what's actually happening under the hood. Fortunately, your browser comes with powerful detective tools built right in.
To open Developer Tools in Edge, just click those three dots in the top right corner, then go to More Tools > Developer Tools. Or if you're feeling speedy, use `Ctrl` + `Shift` + `I` on Windows or `Option` + `Command` + `I` on Mac. Once you're there, click on the Performance tab - this is where the magic happens!
To open Developer Tools in Edge, click those three dots in the top right corner, then go to More Tools > Developer Tools. Or use the keyboard shortcut: `Ctrl` + `Shift` + `I` on Windows or `Option` + `Command` + `I` on Mac. Once you're there, click on the Performance tab - this is where you'll do your investigation.
**Here's your performance detective toolkit:**
- **Open** Developer Tools (you'll use these constantly as a developer!)
@ -36,7 +36,7 @@ To open Developer Tools in Edge, just click those three dots in the top right co
- **Hit** that Record button and watch your page in action
- **Study** the results to spot what's slowing things down
Let's try this out! Open a website (Microsoft.com works great for this) and click that 'Record' button. Now refresh the page and watch the profiler capture everything that happens. When you stop recording, you'll see a fascinating breakdown of how the browser 'scripts', 'renders', and 'paints' the site. It's like watching a time-lapse of your webpage coming to life!
Let's try this out. Open a website (Microsoft.com works well for this) and click that 'Record' button. Now refresh the page and watch the profiler capture everything that happens. When you stop recording, you'll see a detailed breakdown of how the browser 'scripts', 'renders', and 'paints' the site. It reminds me of how mission control monitors every system during a rocket launch - you get real-time data on exactly what's happening and when.
![Edge profiler](./images/profiler.png)
@ -58,15 +58,15 @@ Check the Event Log pane to see if any event took longer than 15 ms:
## What to Look For When Profiling
Running the profiler is just the beginning - the real skill is knowing what those colorful charts are actually telling you! Don't worry, you'll get the hang of reading them. Experienced developers have learned to spot the warning signs before they become full-blown problems.
Running the profiler is just the beginning - the real skill is knowing what those colorful charts are actually telling you. Don't worry, you'll get the hang of reading them. Experienced developers have learned to spot the warning signs before they become full-blown problems.
Let's talk about the usual suspects - the performance troublemakers that love to sneak into web projects and cause headaches later. Catching these early will save you (and your users) a lot of frustration!
Let's talk about the usual suspects - the performance troublemakers that tend to sneak into web projects. Like how Marie Curie had to carefully monitor radiation levels in her lab, we need to watch for certain patterns that indicate trouble brewing. Catching these early will save you (and your users) a lot of frustration.
**Asset sizes**: Here's something interesting - websites have been getting "heavier" over the years, and a lot of that extra weight comes from images. It's like we've been stuffing more and more into our digital suitcases!
**Asset sizes**: Websites have been getting "heavier" over the years, and a lot of that extra weight comes from images. It's like we've been stuffing more and more into our digital suitcases.
✅ Check out the [Internet Archive](https://httparchive.org/reports/page-weight) to see how dramatically page sizes have grown over time - it's pretty eye-opening!
✅ Check out the [Internet Archive](https://httparchive.org/reports/page-weight) to see how page sizes have grown over time - it's quite revealing.
**Here's how to keep your assets lean and mean:**
**Here's how to keep your assets optimized:**
- **Compress** those images! Modern formats like WebP can cut file sizes dramatically
- **Serve** the right image size for each device - no need to send huge desktop images to phones
- **Minify** your CSS and JavaScript - every byte counts
@ -94,9 +94,9 @@ Now that you have an idea of how the browser renders the assets you send to it,
### Create a function to calculate color
Time for the fun part! We're going to create a function that turns boring numbers into meaningful colors. Think of it like a traffic light system - green for clean energy, red for high carbon intensity.
Now we'll create a function that turns numerical data into meaningful colors. Think of it like a traffic light system - green for clean energy, red for high carbon intensity.
This function will take the CO2 data from our API and figure out what color best represents the environmental impact. Pretty cool, right? Let's add this to `/src/index.js`, right after those `const` variables we set up earlier:
This function will take the CO2 data from our API and determine what color best represents the environmental impact. It's similar to how scientists use color-coding in heat maps to visualize complex data patterns - from ocean temperatures to star formation. Let's add this to `/src/index.js`, right after those `const` variables we set up earlier:
```javascript
function calculateColor(value) {
@ -148,7 +148,7 @@ The `chrome.runtime` [API](https://developer.chrome.com/extensions/runtime) is l
### Set a default icon color
Before we start fetching real data, let's give our extension a starting point. Nobody likes staring at a blank or broken-looking icon! We'll start with a friendly green color so users know the extension is working right from the get-go.
Before we start fetching real data, let's give our extension a starting point. Nobody likes staring at a blank or broken-looking icon. We'll start with a green color so users know the extension is working from the moment they install it.
In your `init()` function, let's set up that default green icon:
@ -168,7 +168,7 @@ chrome.runtime.sendMessage({
- **Ensures** users see a functional extension before data loads
### Call the function, execute the call
Now for the moment of truth! Let's connect everything together so that when fresh CO2 data comes in, your icon automatically updates with the right color. It's like watching your extension come alive!
Now let's connect everything together so that when fresh CO2 data comes in, your icon automatically updates with the right color. It's like connecting the final circuit in an electronic device - suddenly all the individual components work as one system.
Add this line right after you get the CO2 data from the API:
@ -212,25 +212,23 @@ function drawIcon(value) {
}
```
**Here's what this background script magic does:**
- **Listens** for messages from your main script (like a receptionist taking calls!)
**Here's what this background script does:**
- **Listens** for messages from your main script (like a receptionist taking calls)
- **Processes** those 'updateIcon' requests to change your toolbar icon
- **Creates** brand new icons on the fly using the Canvas API
- **Creates** new icons on the fly using the Canvas API
- **Draws** a simple colored circle that shows the current carbon intensity
- **Updates** your browser toolbar with the fresh icon
- **Uses** OffscreenCanvas for smooth performance (no UI blocking!)
- **Uses** OffscreenCanvas for smooth performance (no UI blocking)
✅ You'll learn more about the Canvas API in the [Space Game lessons](../../6-space-game/2-drawing-to-canvas/README.md).
**Time to test your masterpiece:**
**Time to test your extension:**
- **Build** everything with `npm run build`
- **Reload** your extension in the browser (don't forget this step!)
- **Open** your extension and watch that icon change colors like magic
- **Reload** your extension in the browser (don't forget this step)
- **Open** your extension and watch that icon change colors
- **Check** how it responds to real carbon data from around the world
How cool is that? Now you'll know at a glance whether it's a good time for that load of laundry or if you should wait for cleaner energy!
You've just built something genuinely useful AND learned a ton about browser performance along the way. That's what I call a win-win!
Now you'll know at a glance whether it's a good time for that load of laundry or if you should wait for cleaner energy. You've just built something genuinely useful and learned about browser performance along the way.
## GitHub Copilot Agent Challenge 🚀
@ -244,13 +242,13 @@ Learn more about [agent mode](https://code.visualstudio.com/blogs/2025/02/24/int
## 🚀 Challenge
Here's a fun detective mission: pick a few open source websites that have been around for years (think Wikipedia, GitHub, or Stack Overflow) and dig into their commit history. Can you spot where they made performance improvements? What problems kept cropping up?
Here's an interesting detective mission: pick a few open source websites that have been around for years (think Wikipedia, GitHub, or Stack Overflow) and dig into their commit history. Can you spot where they made performance improvements? What problems kept cropping up?
**Your investigation toolkit:**
- **Dive** into commit messages looking for words like "optimize," "performance," or "faster"
**Your investigation approach:**
- **Search** commit messages for words like "optimize," "performance," or "faster"
- **Look** for patterns - do they keep fixing the same types of issues?
- **Spot** the common culprits that slow down websites
- **Share** what you discover - other developers love learning from real-world examples!
- **Identify** the common culprits that slow down websites
- **Share** what you discover - other developers learn from real-world examples
## Post-Lecture Quiz

@ -2,11 +2,11 @@
![Space game animation showing gameplay](../images/pewpew.gif)
Ready to blast off into game development? We're about to build an awesome space game together using JavaScript! But here's the cool part while we're having fun creating something you can actually play, you'll also pick up some seriously valuable programming concepts that'll make you a much stronger developer.
Just like NASA's mission control coordinates multiple systems during a space launch, we're going to build a space game that demonstrates how different parts of a program can work together seamlessly. While creating something you can actually play, you'll learn essential programming concepts that apply to any software project.
We're going to explore how to organize code like a pro using two different approaches: inheritance and composition. Don't worry if these sound intimidating I'll show you exactly when and why to use each one. We'll also build a slick communication system called pub/sub (think of it like a really smart messaging app for your code) that lets different parts of your game talk to each other without getting tangled up.
We'll explore two fundamental approaches to organizing code: inheritance and composition. These aren't just academic concepts they're the same patterns that power everything from video games to banking systems. We'll also implement a communication system called pub/sub that works like the communication networks used in spacecraft, allowing different components to share information without creating dependencies.
By the time we're done, you'll know how to build apps that can grow and change without breaking whether you're making games, websites, or whatever your imagination comes up with. Ready to start this adventure?
By the end of this series, you'll understand how to build applications that can scale and evolve whether you're developing games, web applications, or any other software system.
## Pre-Lecture Quiz
@ -14,15 +14,15 @@ By the time we're done, you'll know how to build apps that can grow and change w
## Inheritance and Composition in Game Development
Here's something every developer figures out eventually: as your projects get bigger and more complex, the way you organize your code becomes super important. What starts as a simple script can quickly turn into a tangled mess if you're not careful!
As projects grow in complexity, code organization becomes critical. What begins as a simple script can become difficult to maintain without proper structure much like how the Apollo missions required careful coordination between thousands of components.
So let's talk about two really useful approaches for keeping your code clean and organized: inheritance and composition. Each one has its own strengths, and knowing both will help you pick the right tool for the job. We'll learn these concepts by building our space game, where you've got heroes, enemies, power-ups, and all sorts of objects that need to work together smoothly.
We'll explore two fundamental approaches for organizing code: inheritance and composition. Each has distinct advantages, and understanding both helps you choose the right approach for different situations. We'll demonstrate these concepts through our space game, where heroes, enemies, power-ups, and other objects must interact efficiently.
✅ One of the most famous programming books ever written has to do with [design patterns](https://en.wikipedia.org/wiki/Design_Patterns).
In any game, you've got `game objects` basically everything you see on screen that does something. Your hero, the enemies, power-ups, even that explosion when you blow something up they're all game objects! Each one lives at a specific spot on the screen using `x` and `y` coordinates, just like plotting points on a graph in math class.
In any game, you have `game objects` the interactive elements that populate your game world. Heroes, enemies, power-ups, and visual effects are all game objects. Each exists at specific screen coordinates using `x` and `y` values, similar to plotting points on a coordinate plane.
Here's the interesting part: even though these objects might look totally different, they usually share some basic behaviors:
Despite their visual differences, these objects often share fundamental behaviors:
- **They exist somewhere** Every object has x and y coordinates so the game knows where to draw it
- **Many can move around** Heroes run, enemies chase, bullets fly across the screen
@ -37,7 +37,7 @@ Now that you understand the common behaviors game objects share, let's explore h
**The Class-Based Approach**
One really neat way to organize all this is with `classes` and `inheritance`. Think of it like a family tree you start with a parent class that has all the basic stuff every game object needs, then create child classes that inherit those basics but add their own special abilities.
Classes and inheritance provide a structured approach to organizing game objects. Like the taxonomic classification system developed by Carl Linnaeus, you start with a base class containing common properties, then create specialized classes that inherit these fundamentals while adding specific capabilities.
✅ Inheritance is an important concept to understand. Learn more on [MDN's article about inheritance](https://developer.mozilla.org/docs/Web/JavaScript/Inheritance_and_the_prototype_chain).
@ -111,7 +111,7 @@ const tree = new Tree(10, 15);
**The Composition Approach**
Composition is like building with LEGO blocks instead of inheriting everything from a parent, you mix and match different pieces to create exactly what you need. It's super flexible because you can combine any behaviors you want without being locked into a rigid family tree structure.
Composition follows a modular design philosophy, similar to how engineers design spacecraft with interchangeable components. Instead of inheriting from a parent class, you combine specific behaviors to create objects with exactly the functionality they need. This approach offers flexibility without rigid hierarchical constraints.
```javascript
// Step 1: Create base behavior objects
@ -192,9 +192,9 @@ const tree = createStatic(0, 0, 'Tree');
## Communication Patterns: The Pub/Sub System
As your game gets more complex, you'll run into a tricky problem: how do you get different parts of your game to talk to each other without creating a tangled mess of dependencies? That's where the publish-subscribe pattern (we just call it pub/sub) comes to the rescue!
As applications grow complex, managing communication between components becomes challenging. The publish-subscribe pattern (pub/sub) solves this problem using principles similar to radio broadcasting one transmitter can reach multiple receivers without knowing who's listening.
Here's a perfect example: when your hero takes damage, lots of things need to happen the health bar updates, a hurt sound plays, maybe the screen flashes red. But here's the thing: your hero object shouldn't have to know about all these other systems. That would make your code super messy and hard to change later. With pub/sub, your hero just broadcasts "Hey, I took damage!" and everything else that cares about that message can respond automatically.
Consider what happens when a hero takes damage: the health bar updates, sound effects play, visual feedback appears. Rather than coupling the hero object directly to these systems, pub/sub allows the hero to broadcast a "damage taken" message. Any system that needs to respond can subscribe to this message type and react accordingly.
**Pub/Sub** stands for 'publish-subscribe'
@ -314,9 +314,9 @@ window.addEventListener('keydown', (event) => {
- Testing gets way simpler because each piece works independently
- When something breaks, you know exactly where to look
### Why Pub/Sub Scales Beautifully
### Why Pub/Sub Scales Effectively
The really cool thing about pub/sub is that it stays simple even as your game gets crazy complex. Whether you've got dozens of enemies, power-ups flying around, sound effects, UI updates it all just works. Want to add a new feature? Just plug into the existing event system without breaking anything that's already working.
The pub/sub pattern maintains simplicity as applications grow in complexity. Whether managing dozens of enemies, dynamic UI updates, or sound systems, the pattern handles increased scale without architectural changes. New features integrate into the existing event system without affecting established functionality.
> ⚠️ **Common Mistake**: Don't create too many specific message types early on. Start with broad categories and refine them as your game's needs become clearer.
>
@ -340,7 +340,7 @@ Learn more about [agent mode](https://code.visualstudio.com/blogs/2025/02/24/int
## 🚀 Challenge
Think about how the pub-sub pattern can enhance a game. Which parts should emit events, and how should the game react to them? Now's your chance to get creative, thinking of a new game and how its parts might behave.
Consider how the pub-sub pattern can enhance game architecture. Identify which components should emit events and how the system should respond. Design a game concept and map out the communication patterns between its components.
## Post-Lecture Quiz

@ -1,10 +1,10 @@
# Build a Space Game Part 2: Draw Hero and Monsters to Canvas
Ready for some visual magic? The Canvas API is honestly one of the coolest features in web development it lets you create dynamic, interactive graphics right in your browser! In this lesson, we're going to transform that blank HTML `<canvas>` element into an epic game world filled with heroes, monsters, and all sorts of visual effects. Think of the canvas as your digital art board where your code literally becomes visual magic.
The Canvas API is one of web development's most powerful features for creating dynamic, interactive graphics right in your browser. In this lesson, we'll transform that blank HTML `<canvas>` element into a game world filled with heroes and monsters. Think of the canvas as your digital art board where code becomes visual.
We're building on what you learned in the previous lesson, and now things get really exciting! You'll learn how to load and display game sprites, position elements exactly where you want them, and create the visual foundation for your space game. This is where we bridge the gap between those static web pages you're used to and dynamic, game-like experiences that actually respond to what players do.
We're building on what you learned in the previous lesson, and now we'll dive into the visual aspects. You'll learn how to load and display game sprites, position elements precisely, and create the visual foundation for your space game. This bridges the gap between static web pages and dynamic, interactive experiences.
By the time we're done here, you'll have a complete game scene with your hero ship positioned just right and enemy formations that look ready for battle. You'll understand how modern games actually render graphics in browsers, and you'll have the skills to create your own interactive visual experiences. Let's jump into the world of canvas graphics and bring your space game to life!
By the end of this lesson, you'll have a complete game scene with your hero ship positioned correctly and enemy formations ready for battle. You'll understand how modern games render graphics in browsers and gain skills to create your own interactive visual experiences. Let's explore canvas graphics and bring your space game to life!
## Pre-Lecture Quiz
@ -12,9 +12,9 @@ By the time we're done here, you'll have a complete game scene with your hero sh
## The Canvas
So what exactly is this `<canvas>` element? It's HTML5's brilliant solution for creating dynamic graphics and animations in web browsers. Unlike regular images or videos that are just... there, the canvas gives you pixel-level control over everything that appears on screen. This makes it absolutely perfect for games, data visualizations, and interactive art. I like to think of it as a programmable drawing surface where JavaScript becomes your paintbrush.
So what exactly is this `<canvas>` element? It's HTML5's solution for creating dynamic graphics and animations in web browsers. Unlike regular images or videos that are static, the canvas gives you pixel-level control over everything that appears on screen. This makes it perfect for games, data visualizations, and interactive art. Think of it as a programmable drawing surface where JavaScript becomes your paintbrush.
Here's the thing though by default, a canvas element just looks like a blank, transparent rectangle sitting on your page. Pretty boring, right? But that's where the magic happens! Its real power comes alive when you use JavaScript to draw shapes, load images, create animations, and make things respond to what users do.
By default, a canvas element looks like a blank, transparent rectangle on your page. But that's where the potential lies! Its real power emerges when you use JavaScript to draw shapes, load images, create animations, and make things respond to user interactions. It's similar to how early computer graphics pioneers at Bell Labs in the 1960s had to program every pixel to create the first digital animations.
✅ Read [more about the Canvas API](https://developer.mozilla.org/docs/Web/API/Canvas_API) on MDN.
@ -31,20 +31,20 @@ Here's how it's typically declared, as part of the page's body:
## Drawing Simple Geometry
Now that you know what the canvas element is, let's dive into the fun part actually drawing on it! The canvas uses a coordinate system that might feel familiar from math class, but there's one important twist that's specific to computer graphics.
Now that you know what the canvas element is, let's explore actually drawing on it! The canvas uses a coordinate system that might feel familiar from math class, but there's one important twist specific to computer graphics.
Remember those Cartesian coordinates from school? Well, the canvas uses something similar with an x-axis (horizontal) and y-axis (vertical) to position everything you draw. But here's the twist that trips up a lot of people at first: unlike the coordinate system you might remember from math class, the origin point `(0,0)` starts at the top-left corner, with x-values increasing as you move right and y-values increasing as you move down. It feels a bit backwards at first, but you'll get used to it quickly!
The canvas uses Cartesian coordinates with an x-axis (horizontal) and y-axis (vertical) to position everything you draw. But here's the key difference: unlike the coordinate system from math class, the origin point `(0,0)` starts at the top-left corner, with x-values increasing as you move right and y-values increasing as you move down. This approach dates back to early computer displays where electron beams scanned from top to bottom, making top-left the natural starting point.
![the canvas's grid](canvas_grid.png)
> Image from [MDN](https://developer.mozilla.org/docs/Web/API/Canvas_API/Tutorial/Drawing_shapes)
To draw on the canvas element, you'll always follow the same three-step dance that forms the foundation of all canvas graphics. Don't worry once you do this a few times, it'll become second nature:
To draw on the canvas element, you'll follow the same three-step process that forms the foundation of all canvas graphics. Once you do this a few times, it becomes second nature:
1. **Grab a reference** to your Canvas element from the DOM (just like you would any other HTML element)
2. **Get the 2D rendering context** this is what gives you all those cool drawing methods
3. **Start drawing!** Use the context's built-in methods to create your masterpiece
1. **Get a reference** to your Canvas element from the DOM (just like any other HTML element)
2. **Get the 2D rendering context** this provides all the drawing methods
3. **Start drawing!** Use the context's built-in methods to create your graphics
Let me show you how this looks in real code:
Here's how this looks in code:
```javascript
// Step 1: Get the canvas element
@ -76,9 +76,9 @@ You can draw all sorts of things with the Canvas API like:
## Load and Draw an Image Asset
Okay, drawing basic shapes is great for getting started, but let's be honest most games need actual images! Sprites, backgrounds, textures that's what makes games look awesome. Loading and displaying images on the canvas works a bit differently than drawing those geometric shapes, but don't worry, it's not complicated once you see how it works.
Drawing basic shapes is useful for getting started, but most games need actual images! Sprites, backgrounds, and textures are what give games their visual appeal. Loading and displaying images on the canvas works differently than drawing geometric shapes, but it's straightforward once you understand the process.
Here's the deal: we need to create an `Image` object, load our image file (this happens asynchronously, which is just a fancy way of saying "in the background"), and then draw it to the canvas once it's ready. This approach makes sure your images show up properly without freezing your whole application while they load.
We need to create an `Image` object, load our image file (this happens asynchronously, meaning "in the background"), and then draw it to the canvas once it's ready. This approach ensures your images display properly without blocking your application while they load.
### Basic Image Loading
@ -98,7 +98,7 @@ img.onload = () => {
### A Better Way to Load Images
Now, I'm going to show you a cleaner way to handle image loading that most professional developers use. We'll wrap the image loading in a Promise-based function it might look a bit fancy at first, but it makes your code much more organized and handles errors gracefully:
Here's a more robust way to handle image loading that professional developers commonly use. We'll wrap the image loading in a Promise-based function this approach, popularized when JavaScript Promises became standard in ES6, makes your code more organized and handles errors gracefully:
```javascript
function loadAsset(path) {
@ -163,7 +163,7 @@ async function renderGameScreen() {
## Now It's Time to Start Building Your Game
Alright, this is where things get really exciting! You've got a solid understanding of canvas fundamentals and image loading techniques, so now we're going to put it all together to create the visual foundation of your space game. This hands-on section will walk you through building a complete game screen with properly positioned sprites that actually look professional.
Now we'll put everything together to create the visual foundation of your space game. You have a solid understanding of canvas fundamentals and image loading techniques, so this hands-on section will guide you through building a complete game screen with properly positioned sprites.
### What to Build
@ -212,7 +212,7 @@ npm start
- **Watches** your files for changes so you can develop smoothly
- **Gives you** a professional development environment to test everything
> 💡 **Pro Tip**: Your browser will show a blank page initially that's expected! As you add code, refresh your browser to see your changes. Many developers use browser extensions like LiveReload for automatic refresh functionality.
> 💡 **Note**: Your browser will show a blank page initially that's expected! As you add code, refresh your browser to see your changes. This iterative development approach is similar to how NASA built the Apollo guidance computer testing each component before integrating it into the larger system.
### Add code

@ -1,10 +1,12 @@
# Build a Space Game Part 3: Adding Motion
Here's where things get really exciting! Think about your favorite games what makes them captivating isn't just pretty graphics, it's the way everything moves and responds to your actions. Right now, your space game is like a beautiful painting, but we're about to turn it into a living, breathing world that reacts to every keystroke.
Think about your favorite games what makes them captivating isn't just pretty graphics, it's the way everything moves and responds to your actions. Right now, your space game is like a beautiful painting, but we're about to add movement that brings it to life.
In this lesson, we'll unlock the secrets behind game movement. You'll learn how to make spaceships glide across the screen, respond to player commands, and create those satisfying moments when everything just *feels* right. Don't worry if the concepts seem complex at first we'll break everything down into bite-sized pieces that build on each other naturally.
When NASA's engineers programmed the guidance computer for the Apollo missions, they faced a similar challenge: how do you make a spacecraft respond to pilot input while automatically maintaining course corrections? The principles we'll learn today echo those same concepts managing player-controlled movement alongside automatic system behaviors.
By the time we're done here, you'll have players flying their hero ship around the screen while enemy vessels patrol menacingly overhead. More importantly, you'll understand the core principles that power every game you've ever played. Ready to bring your creation to life? Let's dive in!
In this lesson, you'll learn how to make spaceships glide across the screen, respond to player commands, and create smooth movement patterns. We'll break everything down into manageable concepts that build on each other naturally.
By the end, you'll have players flying their hero ship around the screen while enemy vessels patrol overhead. More importantly, you'll understand the core principles that power game movement systems.
## Pre-Lecture Quiz
@ -12,12 +14,12 @@ By the time we're done here, you'll have players flying their hero ship around t
## Understanding Game Movement
You know what's not fun? Staring at a screen full of motionless spaceships! Games come alive when things start moving around, and there are really just two ways this happens:
Games come alive when things start moving around, and there are fundamentally two ways this happens:
- **Player-controlled movement**: When you press a key or click your mouse, something moves. This is the direct connection between you and your game world.
- **Automatic movement**: When the game itself decides to move things like those enemy ships that need to patrol the screen whether you're doing anything or not.
Now, here's the thing about making stuff move on a computer screen it's actually simpler than you might think! Remember those x and y coordinates from math class? That's literally all we're working with here.
Making objects move on a computer screen is simpler than you might think. Remember those x and y coordinates from math class? That's exactly what we're working with here. When Galileo tracked Jupiter's moons in 1610, he was essentially doing the same thing plotting positions over time to understand motion patterns.
Moving things on screen is like creating a flipbook animation you need to follow these three simple steps:
@ -50,9 +52,11 @@ ctx.drawImage(heroImg, hero.x, hero.y);
## Handle keyboard events
This is where the magic happens connecting your player's fingers to the action on screen! When someone hits the spacebar to fire a laser or taps an arrow key to dodge an asteroid, your game needs to know about it instantly.
This is where we connect player input to game action. When someone hits the spacebar to fire a laser or taps an arrow key to dodge an asteroid, your game needs to detect and respond to that input.
Keyboard events happen at the window level, meaning your entire browser window is listening for those keypresses. Mouse clicks, on the other hand, can be tied to specific elements (like clicking a button). For our space game, we'll focus on keyboard controls since that's what gives players that classic arcade feel.
Here's something that might surprise you: keyboard events happen at the window level, meaning your entire browser window is listening for those keypresses. Mouse clicks, on the other hand, can be tied to specific elements (like clicking a button). For our space game, we'll focus on keyboard controls since that's what gives players that classic arcade feel.
This reminds me of how telegraph operators in the 1800s had to translate morse code input into meaningful messages we're doing something similar, translating keypresses into game commands.
To handle an event you need to use the window's `addEventListener()` method and provide it with two input parameters. The first parameter is the name of the event, for example `keyup`. The second parameter is the function that should be invoked as a result of the event taking place.
@ -82,9 +86,9 @@ For key events there are two properties on the event you can use to see what key
### Special keys: a heads up!
Here's something that'll save you from a frustrating debugging session some keys have built-in browser behaviors. You know how arrow keys scroll the page and spacebar jumps down? When you're playing your game, you probably don't want the screen bouncing around while you're trying to pilot your spaceship!
Some keys have built-in browser behaviors that can interfere with your game. Arrow keys scroll the page and spacebar jumps down behaviors you don't want when someone is trying to pilot their spaceship.
The good news is we can tell the browser "hey, when someone hits these keys, just let our game handle it." Here's how:
We can prevent these default behaviors and let our game handle the input instead. This is similar to how early computer programmers had to override system interrupts to create custom behaviors we're just doing it at the browser level. Here's how:
```javascript
const onKeyDown = function (e) {
@ -113,9 +117,9 @@ window.addEventListener('keydown', onKeyDown);
## Game induced movement
Now let's talk about the stuff that moves without any help from the player. Think about those enemy ships that need to cruise across the screen, or bullets that fly in straight lines, or maybe clouds drifting in the background. This is what makes your game world feel alive even when nobody's touching the controls.
Now let's talk about objects that move without player input. Think about enemy ships cruising across the screen, bullets flying in straight lines, or clouds drifting in the background. This autonomous movement makes your game world feel alive even when nobody's touching the controls.
The secret is using JavaScript's built-in timers to nudge things along at regular intervals. It's like having a tiny robot that taps each object on the shoulder every few milliseconds and says "time to move!" Here's how simple it can be:
We use JavaScript's built-in timers to update positions at regular intervals. This concept is similar to how pendulum clocks work a regular mechanism that triggers consistent, timed actions. Here's how simple it can be:
```javascript
const id = setInterval(() => {
@ -132,11 +136,11 @@ const id = setInterval(() => {
## The game loop
Alright, here's the big concept that ties everything together the game loop! If your game were a movie, the game loop would be the film projector, showing frame after frame so fast that everything appears to move smoothly.
Here's the concept that ties everything together the game loop. If your game were a movie, the game loop would be the film projector, showing frame after frame so fast that everything appears to move smoothly.
Every great game has one of these loops running behind the scenes. It's basically a function that says "okay, let's update everything, draw everything, and do it all again!" It keeps track of your hero, all the enemies, any lasers flying around the whole cast of characters. When something gets destroyed (like an enemy ship taking a hit), it simply stops including that object in future frames.
Every game has one of these loops running behind the scenes. It's a function that updates all game objects, redraws the screen, and repeats this process continuously. This keeps track of your hero, all the enemies, any lasers flying around the entire game state.
This might sound complex, but you'll see it's actually pretty straightforward once we build one together.
This concept reminds me of how early film animators like Walt Disney had to redraw characters frame by frame to create the illusion of movement. We're doing the same thing, just with code instead of pencils.
Here's what a game loop can typically look like, expressed in code:
@ -163,15 +167,15 @@ const gameLoopId = setInterval(() => {
## Continuing the Space Game
Time for the fun part let's get everything moving! We're going to take that beautiful static scene you built and turn it into something you can actually play. Don't worry if this feels like a big step; we'll go through everything piece by piece.
Now we'll add movement to the static scene you built previously. We're going to transform it from a screenshot into an interactive experience. We'll work through this step by step to ensure each piece builds on the last.
Grab the code from where we left off in the previous lesson (or start with the code in the [Part II- starter](your-work) folder if you need a fresh start).
**Here's what we're building today:**
- **Hero controls**: Arrow keys will pilot your spaceship around the screen
- **Enemy movement**: Those alien ships will start their menacing advance
- **Enemy movement**: Those alien ships will start their advance
Ready? Let's make some magic happen!
Let's begin implementing these features.
## Recommended steps
@ -512,20 +516,20 @@ The above will start a HTTP Server on address `http://localhost:5000`. Open up a
## GitHub Copilot Agent Challenge 🚀
Ready for a real challenge? Let's push your space game to the next level! This is where you get to flex those problem-solving muscles and create something that feels polished and professional.
Here's a challenge that will improve your game's polish: adding boundaries and smooth controls. Currently, your hero can fly off the screen, and the movement might feel choppy.
**Your Mission:** Make your spaceship feel more realistic by adding boundaries and smooth controls. Right now, your hero can probably fly right off the screen (which looks pretty weird), and the movement might feel a bit choppy. Let's fix that!
**Your Mission:** Make your spaceship feel more realistic by implementing screen boundaries and fluid movement. This is similar to how NASA's flight control systems prevent spacecraft from exceeding safe operational parameters.
**Here's what to build:** Create a system that keeps your hero spaceship on screen, and make the controls feel silky smooth. When players hold down an arrow key, the ship should glide continuously rather than hopping along. Bonus points if you can add some visual flair when the ship bumps against the screen edges maybe a subtle glow or color change to let players know they've hit the boundary.
**Here's what to build:** Create a system that keeps your hero spaceship on screen, and make the controls feel smooth. When players hold down an arrow key, the ship should glide continuously rather than moving in discrete steps. Consider adding visual feedback when the ship reaches screen boundaries perhaps a subtle effect to indicate the edge of the play area.
Learn more about [agent mode](https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode) here.
## 🚀 Challenge
Here's something every developer learns the hard way code has a sneaky habit of becoming a tangled mess when you're not looking! You might have noticed your file getting pretty crowded with functions, variables, and classes all mixed together.
Code organization becomes increasingly important as projects grow. You might have noticed your file getting crowded with functions, variables, and classes all mixed together. This reminds me of how the engineers organizing the Apollo mission code had to create clear, maintainable systems that multiple teams could work on simultaneously.
**Your mission (should you choose to accept it):**
Take a step back and think like an architect. How would you organize your code so that six months from now, you (or a teammate) could jump right back in and understand what's happening? Even if everything stays in one file for now, you can still create order from chaos:
**Your mission:**
Think like a software architect. How would you organize your code so that six months from now, you (or a teammate) could understand what's happening? Even if everything stays in one file for now, you can create better organization:
- **Grouping related functions** together with clear comment headers
- **Separating concerns** - keep game logic separate from rendering

@ -4,25 +4,23 @@
[Pre-lecture quiz](https://ff-quizzes.netlify.app/web/quiz/35)
Ever wonder what makes a game exciting? It's those moments when your spaceship's laser hits an enemy, or when you narrowly avoid a collision! That's collision detection in action, and it's what transforms boring static images into thrilling interactive experiences.
Think about the moment in Star Wars when Luke's proton torpedoes hit the Death Star's exhaust port. That precise collision detection changed the fate of the galaxy! In games, collision detection works the same way - it determines when objects interact and what happens next.
In this lesson, we're going to add some serious firepower to your space game. You'll learn how to shoot lasers (pretty cool, right?) and detect when things crash into each other. Don't worry if this sounds complex - we'll break it down into bite-sized pieces that anyone can understand.
In this lesson, you'll add laser weapons to your space game and implement collision detection. Just like NASA's mission planners calculate spacecraft trajectories to avoid debris, you'll learn to detect when game objects intersect. We'll break this down into manageable steps that build on each other.
Here's what you'll be able to do by the end: fire lasers at enemies, watch them explode on impact, and handle all sorts of game interactions. Plus, these skills aren't just for games - the same principles power interactive websites and modern web apps. Ready to make some digital fireworks? Let's dive in!
By the end, you'll have a functioning combat system where lasers destroy enemies and collisions trigger game events. These same collision principles are used in everything from physics simulations to interactive web interfaces.
✅ Do a little research on the very first computer game ever written. What was its functionality?
Let's build something amazing together!
## Collision detection
Think of collision detection as your game's referee - it decides when things bump into each other and what happens next. Without it, your laser would pass right through enemies like a ghost!
Collision detection works like the proximity sensors on the Apollo lunar module - it constantly checks distances and triggers alerts when objects get too close. In games, this system determines when objects interact and what should happen next.
Here's the clever part: we treat every game object like a rectangle. Your spaceship? Rectangle. Enemy ships? Rectangles. Lasers? You guessed it - rectangles! This might seem oversimplified, but it works beautifully and keeps the math manageable.
The approach we'll use treats every game object as a rectangle, similar to how air traffic control systems use simplified geometric shapes to track aircraft. This rectangular method might seem basic, but it's computationally efficient and works well for most game scenarios.
### Rectangle representation
Every game object needs to know where it exists in space - kind of like giving it an address! Here's how we create that invisible boundary box:
Every game object needs coordinate boundaries, similar to how the Mars Pathfinder rover mapped its location on the Martian surface. Here's how we define these boundary coordinates:
```javascript
rectFromGameObject() {
@ -43,7 +41,7 @@ rectFromGameObject() {
### Intersection algorithm
Now for the fun part - figuring out if two rectangles are bumping into each other! The logic here is pretty clever:
Detecting rectangle intersections uses logic similar to how the Hubble Space Telescope determines if celestial objects are overlapping in its field of view. The algorithm checks for separation:
```javascript
function intersectRect(r1, r2) {
@ -54,17 +52,17 @@ function intersectRect(r1, r2) {
}
```
**Here's the clever thinking:**
**The separation test works like radar systems:**
- Is rectangle 2 completely to the right of rectangle 1?
- Is rectangle 2 completely to the left of rectangle 1?
- Is rectangle 2 completely below rectangle 1?
- Is rectangle 2 completely above rectangle 1?
If none of these are true, then they must be overlapping! It's like asking "Are they completely separated?" - if the answer is no, they're touching.
If none of these conditions are true, the rectangles must be overlapping. This approach mirrors how radar operators determine if two aircraft are at safe distances.
## Managing object lifecycles
When a laser hits an enemy, both should disappear, right? But we can't just delete them immediately - that might break our game loop! Instead, we use a clever "mark for deletion" system. Think of it like putting a sticky note on something that says "throw this away later."
When a laser hits an enemy, both objects need to be removed from the game. However, deleting objects mid-loop can cause crashes - a lesson learned the hard way in early computer systems like the Apollo Guidance Computer. Instead, we use a "mark for deletion" approach that safely removes objects between frames.
Here's how we mark something for removal:
@ -92,7 +90,7 @@ gameObjects = gameObjects.filter(go => !go.dead);
## Implementing laser mechanics
Time for the satisfying part - shooting lasers! Every time you press the spacebar, you'll create a new laser that streaks across the screen. It's like magic, but with code.
Laser projectiles in games work on the same principle as photon torpedoes in Star Trek - they're discrete objects that travel in straight lines until they hit something. Each spacebar press creates a new laser object that moves across the screen.
To make this work, we need to coordinate a few different pieces:
@ -104,9 +102,9 @@ To make this work, we need to coordinate a few different pieces:
## Implementing firing rate control
Imagine if you could fire a million lasers per second - sounds awesome, but it would crash your game faster than you can say "pew pew!" Plus, where's the challenge in that?
Unlimited firing rates would overwhelm the game engine and make gameplay too easy. Real weapon systems face similar constraints - even the USS Enterprise's phasers needed time to recharge between shots.
We need a cooldown system, just like in your favorite video games. Think of it as your laser gun needing a moment to recharge between shots:
We'll implement a cooldown system that prevents rapid-fire spamming while maintaining responsive controls:
```javascript
class Cooldown {
@ -144,9 +142,9 @@ class Weapon {
## Building the collision system
You'll extend your existing space game code to create a fully functional combat system. This implementation will bring together all the concepts we've discussed into working game mechanics.
You'll extend your existing space game code to create a collision detection system. Like the International Space Station's automated collision avoidance system, your game will continuously monitor object positions and respond to intersections.
Starting from your previous lesson's code, you'll add comprehensive collision detection with specific game rules that create engaging gameplay challenges.
Starting from your previous lesson's code, you'll add collision detection with specific rules that govern object interactions.
> 💡 **Pro Tip**: The laser sprite is already included in your assets folder and referenced in your code, ready for implementation.
@ -198,7 +196,7 @@ Open your browser and navigate to `http://localhost:5000` to see your current ga
### Step-by-step implementation
Alright, let's build this thing! We'll take it one step at a time, and before you know it, you'll have lasers flying everywhere.
Like the systematic approach NASA used to program the Voyager spacecraft, we'll implement collision detection methodically, building each component step by step.
#### 1. Add rectangle collision bounds
@ -416,13 +414,13 @@ class Hero extends GameObject {
### Testing your implementation
Drumroll please... your space game is now a full-blown combat simulator! 🚀 Go ahead and test these awesome features:
- **Fly around** with your arrow keys (smooth as butter!)
- **Blast away** with the spacebar - but don't spam it, the cooldown is working!
- **Watch enemies explode** when your lasers connect (so satisfying!)
- **Marvel** at how smoothly everything appears and disappears
Your space game now features complete collision detection and combat mechanics. 🚀 Test these new capabilities:
- **Navigate** with arrow keys to verify movement controls
- **Fire lasers** with the spacebar - notice how the cooldown prevents spam-clicking
- **Observe collisions** when lasers hit enemies, triggering removal
- **Verify cleanup** as destroyed objects disappear from the game
You've just built a complete game from scratch - that's seriously impressive! Take a moment to appreciate what you've accomplished.
You've successfully implemented a collision detection system using the same mathematical principles that guide spacecraft navigation and robotics.
## GitHub Copilot Agent Challenge 🚀

@ -4,13 +4,13 @@
[Pre-lecture quiz](https://ff-quizzes.netlify.app/web/quiz/37)
Ready to make your space game feel like a real game? Let's add the satisfying elements that keep players coming back for more - scoring points and managing lives! This is where your game truly comes alive.
Ready to make your space game feel like a real game? Let's add scoring points and managing lives - the core mechanics that transformed early arcade games like Space Invaders from simple demonstrations into addictive entertainment. This is where your game becomes truly playable.
## Drawing Text on Screen - Your Game's Voice
Want to show off that epic score you're racking up? We need to learn how to put text on the screen! The secret weapon here is the `fillText()` method on your canvas object. Think of it as your game's way of talking to the player.
To display your score, we need to learn how to render text on the canvas. The `fillText()` method is your primary tool for this - it's the same technique used in classic arcade games to show scores and status information.
Here's the cool part - you get to control everything about how that text looks:
You have complete control over the text appearance:
```javascript
ctx.font = "30px Arial";
@ -23,20 +23,20 @@ ctx.fillText("show this on the screen", 0, 0);
## Lives - More Than Just a Number
Here's something interesting: in games, a "life" is really just a number that counts down. But what makes it feel meaningful? In space games, you typically start with a few lives, and each time an enemy ship crashes into you, you lose one.
In game design, a "life" represents the player's margin for error. This concept dates back to pinball machines, where you'd get multiple balls to play with. In early video games like Asteroids, lives gave players permission to take risks and learn from mistakes.
The magic happens when you represent this visually - instead of just showing "Lives: 3", you might display tiny ship icons or hearts. It's amazing how much more engaging this feels for players!
Visual representation matters significantly - displaying ship icons instead of just "Lives: 3" creates immediate visual recognition, similar to how early arcade cabinets used iconography to communicate across language barriers.
## Building Your Game's Reward System
Time to add those satisfying game elements that'll make players want to keep playing! Here's what we're going to implement:
Now we'll implement the core feedback systems that keep players engaged:
- **Scoring system**: Every enemy ship you blast out of the sky earns you points - let's say 100 points per ship because round numbers feel good! We'll display this score in the bottom left corner.
- **Life counter**: Your hero starts with three lives (the classic amount!). Each collision with an enemy costs you one life. We'll show this in the bottom right using this neat little graphic ![life image](solution/assets/life.png).
- **Scoring system**: Each destroyed enemy ship awards 100 points (round numbers are easier for players to calculate mentally). The score displays in the bottom left corner.
- **Life counter**: Your hero starts with three lives - a standard established by early arcade games to balance challenge with playability. Each collision with an enemy costs one life. We'll display remaining lives in the bottom right using ship icons ![life image](solution/assets/life.png).
## Let's Get Building!
First things first - let's get your workspace ready. Navigate to the files in your `your-work` sub folder. You should see these familiar files waiting for you:
First, set up your workspace. Navigate to the files in your `your-work` sub folder. You should see these files:
```bash
-| assets
@ -48,14 +48,14 @@ First things first - let's get your workspace ready. Navigate to the files in yo
-| package.json
```
Ready to see your game in action? Start your project by jumping into the `your_work` folder and firing up the server:
To test your game, start the development server from the `your_work` folder:
```bash
cd your-work
npm start
```
This creates a local server at `http://localhost:5000`. Pop that address into your browser, and you should see your hero ready for action! Try moving with the arrow keys and shooting down some enemies - satisfying, right?
This runs a local server at `http://localhost:5000`. Open this address in your browser to see your game. Test the controls with arrow keys and try shooting enemies to verify everything works.
### Time to Code!
@ -77,7 +77,7 @@ This creates a local server at `http://localhost:5000`. Pop that address into yo
2. **Set up your game variables**. Add some code to track your total score (starting at 0) and remaining lives (starting at 3). We'll display these on screen so players always know where they stand.
3. **Make collisions matter**. Extend your `updateGameObjects()` function to detect when enemies crash into your hero:
3. **Implement collision detection**. Extend your `updateGameObjects()` function to detect when enemies collide with your hero:
```javascript
enemies.forEach(enemy => {
@ -130,7 +130,7 @@ This creates a local server at `http://localhost:5000`. Pop that address into yo
drawLife();
```
1. **Make the game rules feel real**. Now for the exciting part - implementing the consequences and rewards:
1. **Implement game consequences and rewards**. Now we'll add the feedback systems that make player actions meaningful:
1. **Collisions cost lives**. Every time your hero crashes into an enemy, you should lose a life.
@ -145,7 +145,7 @@ This creates a local server at `http://localhost:5000`. Pop that address into yo
}
```
2. **Shooting enemies earns points**. Every successful hit should reward you with 100 points - because destroying space enemies is no small feat!
2. **Shooting enemies earns points**. Each successful hit awards 100 points, providing immediate positive feedback for accurate shooting.
Extend your Hero class with this increment method:
@ -172,9 +172,9 @@ This creates a local server at `http://localhost:5000`. Pop that address into yo
✅ Curious about other games built with JavaScript and Canvas? Do some exploring - you might be amazed at what's possible!
When you're done with all this coding, take a step back and admire what you've built! You should now see those little life ship icons in the bottom right, your points proudly displayed in the bottom left, and watch as your life count drops when enemies hit you and your points climb when you blast them away.
After implementing these features, test your game to see the complete feedback system in action. You should see life icons in the bottom right, your score in the bottom left, and watch as collisions reduce lives while successful shots increase your score.
This is starting to feel like a real game, isn't it? You're almost there!
Your game now has the essential mechanics that made early arcade games so compelling - clear goals, immediate feedback, and meaningful consequences for player actions.
---
@ -190,7 +190,7 @@ Use the Agent mode to complete the following challenge:
## 🚀 Challenge
You're so close to having a complete game! What features are you excited to add next?
You now have a functional game with scoring and lives. Consider what additional features might enhance the player experience.
## Post-Lecture Quiz

@ -1,10 +1,10 @@
# Build a Space Game Part 6: End and Restart
Every great game needs that satisfying "Game Over" moment and the irresistible "Play Again?" button, right? You've come so far with your space game - we're talking movement, explosions, scoring, the works! Now it's time for the grand finale: making your game actually end properly and giving players that sweet, sweet restart option.
Every great game needs clear end conditions and a smooth restart mechanism. You've built an impressive space game with movement, combat, and scoring - now it's time to add the final pieces that make it feel complete.
Think about it - you've built something pretty amazing already. Your little ship zips around, lasers fly everywhere, enemies explode in digital glory. But right now, it probably just keeps going forever, which is... well, a bit like a song that never ends (and trust me, that gets old fast!).
Your game currently runs indefinitely, like the Voyager probes that NASA launched in 1977 - still traveling through space decades later. While that's fine for space exploration, games need defined endpoints to create satisfying experiences.
Today, we're going to wrap up your space adventure with proper win/lose conditions and a restart system that'll keep players coming back for "just one more game." By the time we're done, you'll have a complete, polished game that feels professional. Ready to cross that finish line?
Today, we'll implement proper win/lose conditions and a restart system. By the end of this lesson, you'll have a polished game that players can complete and replay, just like the classic arcade games that defined the medium.
## Pre-Lecture Quiz
@ -12,9 +12,9 @@ Today, we're going to wrap up your space adventure with proper win/lose conditio
## Understanding Game End Conditions
So, when should your game actually end? It's a bigger question than you might think! Every game needs clear rules about when the fun stops and the victory dance begins (or when you face defeat and shake your fist at the screen).
When should your game end? This fundamental question has shaped game design since the early arcade era. Pac-Man ends when you're caught by ghosts or clear all dots, while Space Invaders ends when aliens reach the bottom or you destroy them all.
As the game creator, you get to decide what counts as "winning" or "losing." It's like being the referee of your own sport! For our space game, here are some classic approaches that work really well:
As the game creator, you define the victory and defeat conditions. For our space game, here are proven approaches that create engaging gameplay:
- **`N` Enemy ships have been destroyed**: It's quite common if you divide up a game into different levels that you need to destroy `N` Enemy ships to complete a level
- **Your ship has been destroyed**: There are definitely games where you lose the game if your ship is destroyed. Another common approach is that you have the concept of lives. Every time a your ship is destroyed it deducts a life. Once all lives have been lost then you lose the game.
@ -23,15 +23,15 @@ As the game creator, you get to decide what counts as "winning" or "losing." It'
## Implementing Game Restart Functionality
Here's the thing about good games - they're like potato chips. Nobody has just one! When someone beats your game (or spectacularly crashes and burns), the first thing they'll want to do is try again. Maybe they want to beat their high score, or maybe they're convinced they can do better this time.
Good games encourage replayability through smooth restart mechanisms. When players complete a game (or meet defeat), they often want to try again immediately - whether to beat their score or improve their performance.
A clunky restart process is like having to unwrap each potato chip individually - it kills the momentum. We want that seamless "Ooh, let me try that again!" experience. So we're going to build a restart system that wipes the slate clean and gets players right back into the action.
Tetris exemplifies this perfectly: when your blocks reach the top, you can instantly start a new game without navigating complex menus. We'll build a similar restart system that cleanly resets the game state and gets players back into action quickly.
**Reflection**: Think about the games you've played. Under what conditions do they end, and how are you prompted to restart? What makes a restart experience feel smooth versus frustrating?
## What You'll Build
Time for the exciting part - let's add those final touches that'll make your game feel complete and professional! We're talking about the features that separate "cool coding project" from "actual game I want to show my friends."
You'll implement the final features that transform your project into a complete game experience. These elements distinguish polished games from basic prototypes.
**Here's what we're adding today:**
@ -42,7 +42,7 @@ Time for the exciting part - let's add those final touches that'll make your gam
## Getting Started
Alright, let's get your workspace ready! You should have all your space game files from the previous lessons - if you're looking at a folder full of game assets and code, you're in the right place.
Let's prepare your development environment. You should have all your space game files from the previous lessons ready.
**Your project should look something like this:**
@ -57,19 +57,19 @@ Alright, let's get your workspace ready! You should have all your space game fil
-| package.json
```
**Fire up your development server:**
**Start your development server:**
```bash
cd your-work
npm start
```
**This command is your friend - it:**
- Gets a local server running on `http://localhost:5000`
- Makes sure all your files load properly
- Automatically refreshes when you make changes (pretty handy!)
**This command:**
- Runs a local server on `http://localhost:5000`
- Serves your files properly
- Automatically refreshes when you make changes
Head over to `http://localhost:5000` in your browser and make sure your game is running. You should be able to fly around, shoot lasers, and dodge enemies. If that's all working, we're ready to add the finishing touches!
Open `http://localhost:5000` in your browser and verify your game is running. You should be able to move, shoot, and interact with enemies. Once confirmed, we can proceed with the implementation.
> 💡 **Pro Tip**: To avoid warnings in Visual Studio Code, declare `gameLoopId` at the top of your file as `let gameLoopId;` instead of declaring it inside the `window.onload` function. This follows modern JavaScript variable declaration best practices.
@ -77,7 +77,7 @@ Head over to `http://localhost:5000` in your browser and make sure your game is
### Step 1: Create End Condition Tracking Functions
Let's start with the basics - we need a way to check if the game should end. Think of these as the "referees" of your game, constantly watching to see if someone has won or lost.
We need functions to monitor when the game should end. Like sensors on the International Space Station that constantly monitor critical systems, these functions will continuously check the game state.
```javascript
function isHeroDead() {
@ -99,7 +99,7 @@ function isEnemiesDead() {
### Step 2: Update Event Handlers for End Conditions
Now we need to wire up these condition checks to actually do something! Every time something explodes or crashes in your game, we want to pause and ask: "Hey, did we just win or lose?" This way, the game can react instantly to important moments.
Now we'll connect these condition checks to the game's event system. Every time a collision occurs, the game will evaluate whether it triggers an end condition. This creates immediate feedback for critical game events.
```javascript
eventEmitter.on(Messages.COLLISION_ENEMY_LASER, (_, { first, second }) => {
@ -179,7 +179,7 @@ KEY_EVENT_ENTER: "KEY_EVENT_ENTER",
### Step 5: Create the Message Display System
Time to give your game a voice! When someone wins or loses, you want to let them know loud and clear. We're going to create a message system that can celebrate victories with green text or break the bad news with red text - kind of like a digital scoreboard announcer.
Your game needs to communicate results clearly to players. We'll create a message system that displays victory and defeat states using color-coded text, similar to the terminal interfaces of early computer systems where green indicated success and red signaled errors.
**Create the `displayMessage()` function:**
@ -290,14 +290,14 @@ clear() {
## Congratulations! 🎉
👽 💥 🚀 **Look at you go, space commander!** You've just completed a full-fledged game from scratch! We're talking proper win conditions, lose conditions, restart functionality - the whole nine yards. This isn't just a coding exercise anymore; it's a real game that people can actually enjoy. 🚀 💥 👽
👽 💥 🚀 You've successfully built a complete game from the ground up. Like the programmers who created the first video games in the 1970s, you've transformed lines of code into an interactive experience with proper game mechanics and user feedback. 🚀 💥 👽
**Just look at what you've pulled off:**
- **Built** a game that actually knows when to end (and tells you about it!)
- **Created** that addictive "just one more game" restart experience
- **Designed** clear, helpful messages that guide players through wins and losses
- **Mastered** game state management (trust me, that's harder than it sounds)
- **Put together** all the pieces that make a game feel professional and polished
**You've accomplished:**
- **Implemented** complete win and lose conditions with user feedback
- **Created** a seamless restart system for continuous gameplay
- **Designed** clear visual communication for game states
- **Managed** complex game state transitions and cleanup
- **Assembled** all components into a cohesive, playable game
## GitHub Copilot Agent Challenge 🚀

@ -1,8 +1,8 @@
# Build a Banking App Part 1: HTML Templates and Routes in a Web App
Think about the last time you used your favorite social media app or checked your bank account online. Notice how smoothly everything flows? You click a button, and boom new content appears instantly without that jarring white flash of a page reload. That's the magic of modern web applications, and you're about to learn how to build that same smooth experience yourself.
When Apollo 11's guidance computer navigated to the moon in 1969, it had to switch between different programs without restarting the entire system. Modern web applications work similarly they change what you see without reloading everything from scratch. This creates the smooth, responsive experience users expect today.
Unlike the websites of yesteryear that would reload entire pages for every little interaction, today's web apps are much smarter. They update just the parts that need changing, creating that fluid, app-like feel we've all come to expect.
Unlike traditional websites that reload entire pages for every interaction, modern web apps update only the parts that need changing. This approach, much like how mission control switches between different displays while maintaining constant communication, creates that fluid experience we've come to expect.
Here's what makes the difference so dramatic:
@ -20,11 +20,11 @@ Here's what makes the difference so dramatic:
- **User expectations** now favor instant, seamless interactions
- **Performance benefits** include reduced bandwidth and faster responses
In this lesson, we're going to build something pretty cool a banking app with multiple screens that flow together seamlessly. No page reloads, no annoying flashes, just smooth navigation that feels professional and polished.
In this lesson, we'll build a banking app with multiple screens that flow together seamlessly. Like how scientists use modular instruments that can be reconfigured for different experiments, we'll use HTML templates as reusable components that can be displayed as needed.
You'll get hands-on experience with HTML templates (think of them as reusable blueprints), JavaScript routing (the magic that switches between screens), and the browser's history API (so the back button actually works like users expect). These aren't just academic concepts they're the same techniques powering apps like React, Vue, and Angular.
You'll work with HTML templates (reusable blueprints for different screens), JavaScript routing (the system that switches between screens), and the browser's history API (which keeps the back button working as expected). These are the same fundamental techniques used by frameworks like React, Vue, and Angular.
By the time we're done, you'll have a working banking app that looks and feels like something from a professional development team. Ready to dive in?
By the end, you'll have a working banking app that demonstrates professional single-page application principles.
## Pre-Lecture Quiz
@ -78,9 +78,9 @@ On your computer, create a folder named `bank` with a file named `index.html` in
## HTML Templates
Templates are honestly one of my favorite features for building dynamic web apps. Instead of juggling multiple HTML files for each screen (imagine the headache!), templates let you define reusable HTML structures that you can load and display whenever needed. It's like having a toolbox of pre-built components ready to go.
Templates solve a fundamental problem in web development. When Gutenberg invented movable type printing in the 1440s, he realized that instead of carving entire pages, he could create reusable letter blocks and arrange them as needed. HTML templates work on the same principle instead of creating separate HTML files for each screen, you define reusable structures that can be displayed when needed.
Here's a helpful way to think about it: templates are like blueprints for different parts of your app. An architect doesn't build a different blueprint for every identical room they create one blueprint and use it multiple times. That's exactly what we're doing here. The browser keeps these templates hidden backstage until your JavaScript gives them the cue to appear.
Think of templates as blueprints for different parts of your app. Just as an architect creates one blueprint and uses it multiple times rather than redrawing identical rooms, we create templates once and instantiate them as needed. The browser keeps these templates hidden until JavaScript activates them.
If you want to create multiple screens for a web page, one solution would be to create one HTML file for every screen you want to display. However, this solution comes with some inconvenience:
@ -168,9 +168,9 @@ Then we'll add another HTML template for the dashboard page. This page will cont
## Bringing Templates to Life with JavaScript
Now comes the fun part making our templates actually do something! Right now, they're just sitting there invisibly, like blueprints gathering dust. JavaScript is what transforms these hidden templates into the screens your users will actually see.
Now we need to make our templates functional. Like how a 3D printer takes a digital blueprint and creates a physical object, JavaScript takes our hidden templates and creates visible, interactive elements that users can see and use.
The process is pretty straightforward and follows three steps that you'll use over and over again. Once you get the hang of this pattern, you'll recognize it everywhere in modern web development.
The process follows three consistent steps that form the foundation of modern web development. Once you understand this pattern, you'll recognize it across many frameworks and libraries.
If you try your current HTML file in a browser, you'll see that it gets stuck displaying `Loading...`. That's because we need to add some JavaScript code to instantiate and display the HTML templates.
@ -253,9 +253,9 @@ updateRoute('login');
## Creating Routes
Routing might sound fancy, but it's really just about connecting URLs to the right content. Think about how Gmail works when you click on your inbox, the URL changes to something like `/inbox`, but the page doesn't reload. That's routing in action, and it's what makes web apps feel so smooth and responsive.
Routing is essentially about connecting URLs to the right content. Consider how early telephone operators used switchboards to connect calls they would take an incoming request and route it to the correct destination. Web routing works similarly, taking a URL request and determining which content to display.
Traditionally, web servers handled this automatically by serving different HTML files for different URLs. But since we're building a single-page app, we need to handle this ourselves with JavaScript. The good news? This gives us way more control over how everything works together.
Traditionally, web servers handled this by serving different HTML files for different URLs. Since we're building a single-page app, we need to handle this routing ourselves with JavaScript. This approach gives us more control over the user experience and performance.
```mermaid
flowchart LR
@ -343,9 +343,9 @@ Here we mapped the routes we declared to the corresponding template. You can try
## Adding Navigation
Having solid routing is great, but users need an actual way to navigate around your app! In traditional websites, clicking a link reloads the entire page definitely not the smooth experience we're going for. Instead, we'll set up navigation that updates both the URL and the content without any jarring page refreshes.
With routing established, users need a way to navigate through the app. Traditional websites reload entire pages when clicking links, but we want to update both the URL and content without page refreshes. This creates a smoother experience similar to how desktop applications switch between different views.
We need to coordinate two things: updating the browser's URL so users can bookmark pages and share links, and actually displaying the right content. Get this right, and everything just works the way users expect it to.
We need to coordinate two things: updating the browser's URL so users can bookmark pages and share links, and displaying the appropriate content. When implemented correctly, this creates the seamless navigation users expect from modern applications.
> 🏗️ **Architecture Insight**: Navigation System Components
>
@ -453,9 +453,9 @@ Try clicking on these links, you should be now able to navigate between the diff
## Making the Back and Forward Buttons Work
Here's something that trips up a lot of developers: users absolutely expect the back button to work. It's such a fundamental part of web browsing that when it doesn't work, people get frustrated fast. The forward button should work too, obviously!
The back and forward buttons are fundamental to web browsing, much like how NASA mission controllers can review previous system states during space missions. Users expect these buttons to work, and when they don't, it breaks the expected browsing experience.
The thing is, our single-page app needs a little extra help to make this happen. The browser keeps track of where users have been using something called the history stack (which we've been adding to with `history.pushState`). When someone hits the back button, the browser knows where to go but our app needs to actually update what's showing on screen.
Our single-page app needs additional configuration to support this. The browser maintains a history stack (which we've been adding to with `history.pushState`), but when users navigate through this history, our app needs to respond by updating the displayed content accordingly.
```mermaid
sequenceDiagram

@ -4,13 +4,13 @@
[Pre-lecture quiz](https://ff-quizzes.netlify.app/web/quiz/43)
Ever filled out a form online and had it yell at you for entering your email wrong? Or worse, had it completely lose all your information when you clicked submit? Yeah, we've all been there, and it's pretty frustrating.
Ever filled out a form online and had it reject your email format? Or lost all your information when you clicked submit? We've all encountered these frustrating experiences.
Forms might seem simple on the surface, but they're actually the bridge between your users and everything your app can do. When done right, they feel smooth and helpful. When done wrong... well, let's just say users won't stick around long.
Forms are the bridge between your users and your application's functionality. Like the careful protocols that air traffic controllers use to guide planes safely to their destinations, well-designed forms provide clear feedback and prevent costly errors. Poor forms, on the other hand, can drive users away faster than a miscommunication in a busy airport.
In this lesson, we're going to take your static banking app and give it some real functionality. Users will be able to create accounts, log in, and actually interact with the app instead of just looking at it. You'll learn how to build forms that are smart enough to catch mistakes before they happen and communicate with a server to save user data.
In this lesson, we'll transform your static banking app into an interactive application. You'll learn to build forms that validate user input, communicate with servers, and provide helpful feedback. Think of it as building the control interface that lets users navigate your application's features.
By the time we're done, you'll have a proper login and registration system that actually works complete with validation that helps users instead of frustrating them. Ready to make your app come alive?
By the end, you'll have a complete login and registration system with validation that guides users toward success rather than frustration.
## Prerequisites
@ -45,9 +45,9 @@ curl http://localhost:5000/api
## Understanding HTML Forms and Controls
HTML forms are basically how users talk to your web app. They're the digital equivalent of filling out paperwork, except way more powerful. When built well, they can catch typos, guide users toward the right format, and even provide helpful suggestions.
HTML forms are how users communicate with your web application. Think of them as the telegraph system that connected distant places in the 19th century they're the communication protocol between user intent and application response. When designed thoughtfully, they catch errors, guide input formatting, and provide helpful suggestions.
These days, forms are a lot smarter than just basic text boxes. HTML5 gave us some pretty neat input types that automatically handle things like email validation and number formatting. Plus, they work better with screen readers and mobile devices right out of the box.
Modern forms are significantly more sophisticated than basic text inputs. HTML5 introduced specialized input types that handle email validation, number formatting, and date selection automatically. These improvements benefit both accessibility and mobile user experiences.
### Essential Form Elements
@ -91,9 +91,9 @@ These days, forms are a lot smarter than just basic text boxes. HTML5 gave us so
```
**Here's what each button type does:**
- **Submit buttons**: These actually send your form data somewhere (usually a server)
- **Reset buttons**: Hit this and poof everything goes back to how it was when the page loaded
- **Regular buttons**: These don't do anything special unless you write JavaScript to make them useful
- **Submit buttons**: Trigger form submission and send data to the specified endpoint
- **Reset buttons**: Restore all form fields to their initial state
- **Regular buttons**: Provide no default behavior, requiring custom JavaScript for functionality
> ⚠️ **Important Note**: The `<input>` element is self-closing and doesn't require a closing tag. Modern best practice is to write `<input>` without the slash.
@ -249,11 +249,11 @@ graph TD
| `GET` | Search queries, filters | URL parameters | Low (visible) | ~2000 characters |
| `POST` | User accounts, sensitive data | Request body | Higher (hidden) | No practical limit |
**Here's the basic difference:**
- **GET**: Sticks your form data right in the URL for everyone to see (useful for search forms)
- **POST**: Hides the data in the request body (much better for passwords and personal info)
- **GET downsides**: Limited space, everything shows up in the address bar, gets saved in browser history
- **POST benefits**: Can handle large amounts of data, keeps sensitive info private, supports file uploads
**Understanding the fundamental differences:**
- **GET**: Appends form data to the URL as query parameters (appropriate for search operations)
- **POST**: Includes data in the request body (essential for sensitive information)
- **GET limitations**: Size constraints, visible data, persistent browser history
- **POST advantages**: Large data capacity, privacy protection, file upload support
> 💡 **Best Practice**: Use `GET` for search forms and filters (data retrieval), use `POST` for user registration, login, and data creation.
@ -308,9 +308,9 @@ Let's configure your registration form to communicate properly with the backend
## Modern Form Handling with JavaScript
Remember how we talked about avoiding those jarring page reloads? Well, that applies to forms too. When someone submits a form in a traditional website, the whole page refreshes and you lose your place. Not exactly smooth.
Traditional form submissions cause full page reloads, similar to how early space missions required complete system resets for course corrections. This approach disrupts the user experience and loses application state.
With JavaScript, we can intercept that form submission and handle everything behind the scenes. Users stay right where they are, we can show loading spinners, display error messages nicely, and update the page based on what the server tells us. Much better experience all around.
JavaScript form handling works like the continuous guidance systems used by modern spacecraft making real-time adjustments without losing navigation context. We can intercept form submissions, provide immediate feedback, handle errors gracefully, and update the interface based on server responses while maintaining the user's position in the application.
### Why Avoid Page Reloads?
@ -406,11 +406,11 @@ const formData = new FormData(registerForm);
// }
```
**Why the FormData API is pretty awesome:**
- **Grabs everything**: Text fields, checkboxes, file uploads it doesn't miss anything
- **Smart handling**: Knows how to deal with different input types without you having to code each one
- **Less work**: Instead of manually collecting each field's value, FormData does it all at once
- **Flexible**: Works great even if you add or remove form fields later
**FormData API advantages:**
- **Comprehensive collection**: Captures all form elements including text, files, and complex inputs
- **Type awareness**: Handles different input types automatically without custom coding
- **Efficiency**: Eliminates manual field collection with single API call
- **Adaptability**: Maintains functionality as form structure evolves
### Creating the Server Communication Function
@ -556,9 +556,9 @@ async function register() {
## Comprehensive Form Validation
Nobody likes filling out a form only to find out they did something wrong after hitting submit. Good validation catches problems early and helps users fix them before they get frustrated.
Form validation prevents the frustrating experience of discovering errors only after submission. Like the multiple redundant systems on the International Space Station, effective validation employs multiple layers of safety checks.
The best approach uses multiple layers some basic checks happen right in the browser, more complex stuff gets handled by JavaScript, and the server does a final security check. This way, users get immediate feedback, but you're still protected if someone tries to send malicious data.
The optimal approach combines browser-level validation for immediate feedback, JavaScript validation for enhanced user experience, and server-side validation for security and data integrity. This redundancy ensures both user satisfaction and system protection.
### Understanding Validation Layers
@ -620,11 +620,11 @@ input:focus:invalid {
}
```
**What these styles accomplish:**
- **Green borders**: "You got it right!"
- **Red borders**: "Something's not quite right here"
- **Focus highlights**: Shows users exactly where they are in the form
- **Consistent look**: Users learn what to expect across your whole app
**What these visual cues accomplish:**
- **Green borders**: Indicate successful validation, like green lights in mission control
- **Red borders**: Signal validation errors requiring attention
- **Focus highlights**: Provide clear visual context for current input location
- **Consistent styling**: Establish predictable interface patterns users can learn
> 💡 **Pro Tip**: Use the `:valid` and `:invalid` CSS pseudo-classes to provide immediate visual feedback as users type, creating a responsive and helpful interface.

@ -1,12 +1,10 @@
# Build a Banking App Part 3: Methods of Fetching and Using Data
Think about the last time you checked your bank balance or scrolled through social media. Notice how the content updates instantly without the page flickering or reloading? That's the magic of dynamic data fetching in action! Every smooth interaction you've come to expect from modern apps relies on the techniques we're about to explore together.
Think about the Enterprise's computer in Star Trek - when Captain Picard asks for ship status, the information appears instantly without the whole interface shutting down and rebuilding itself. That seamless flow of information is exactly what we're building here with dynamic data fetching.
Here's what's exciting about this lesson: we're going to breathe life into your static banking app. Right now, it's like a beautiful storefront window - nice to look at, but not very interactive. By the time we're done, it'll feel like a real banking app that fetches actual account data, updates in real-time, and responds to user actions seamlessly.
Right now, your banking app is like a printed newspaper - informative but static. We're going to transform it into something more like mission control at NASA, where data flows continuously and updates in real-time without interrupting the user's workflow.
You'll master the art of talking to servers without interrupting your users, handle data that arrives asynchronously (because servers don't always respond instantly!), and transform that raw data into meaningful information your users can actually use. This is where your app stops being a demo and starts feeling professional.
Ready to make the leap from static to dynamic? Let's dive in!
You'll learn how to communicate with servers asynchronously, handle data that arrives at different times, and transform raw information into something meaningful for your users. This is the difference between a demo and production-ready software.
## Pre-Lecture Quiz
@ -25,10 +23,10 @@ curl http://localhost:5000/api
# Expected response: "Bank API v1.0.0"
```
Don't worry if this feels a bit technical - we're just making sure everything's talking to each other properly! This quick test:
- Checks that Node.js is playing nice with your system
- Confirms your API server is awake and ready to serve data
- Ensures your app can actually reach the server (no point building a phone if there's no one to call!)
This quick test ensures all components are communicating properly:
- Verifies that Node.js is running correctly on your system
- Confirms your API server is active and responding
- Validates that your app can reach the server (like checking radio contact before a mission)
---
@ -40,7 +38,7 @@ Let's explore how traditional websites worked compared to the dynamic, responsiv
### Traditional Multi-Page Applications (MPA)
Picture this: it's the early 2000s, and every time you clicked a link, the entire webpage would disappear, show you a brief flash of white, and then slowly rebuild itself. Remember that jarring experience? That was the reality of early web applications - every interaction meant starting completely over.
In the early days of the web, every click was like changing channels on an old television - the screen would go blank, then slowly tune into the new content. This was the reality of early web applications, where every interaction meant completely rebuilding the entire page from scratch.
```mermaid
sequenceDiagram
@ -65,7 +63,7 @@ sequenceDiagram
### Modern Single-Page Applications (SPA)
Now imagine a different world - one where clicking updates just the part of the page that needs to change, like magic! This is what AJAX (Asynchronous JavaScript and XML) brought to the web. Despite the name mentioning XML, we mostly use JSON these days, but the core idea remains brilliant: why reload everything when you only need to update a small piece?
AJAX (Asynchronous JavaScript and XML) changed this paradigm entirely. Like the modular design of the International Space Station, where astronauts can replace individual components without rebuilding the entire structure, AJAX allows us to update specific parts of a webpage without reloading everything. Despite the name mentioning XML, we mostly use JSON today, but the core principle remains: update only what needs to change.
```mermaid
sequenceDiagram
@ -92,7 +90,7 @@ sequenceDiagram
### The Evolution to Modern Fetch API
Here's some good news: we don't have to wrestle with the old, clunky [`XMLHttpRequest`](https://developer.mozilla.org/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest) anymore! Modern browsers gave us the much friendlier [`Fetch` API](https://developer.mozilla.org/docs/Web/API/Fetch_API), which feels like a breath of fresh air. It uses promises (which make async code way more readable) and practically speaks JSON natively.
Modern browsers provide the [`Fetch` API](https://developer.mozilla.org/docs/Web/API/Fetch_API), which replaces the older [`XMLHttpRequest`](https://developer.mozilla.org/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest). Like the difference between operating a telegraph and using email, Fetch API uses promises for cleaner asynchronous code and handles JSON naturally.
| Feature | XMLHttpRequest | Fetch API |
|---------|----------------|----------|
@ -110,9 +108,9 @@ Here's some good news: we don't have to wrestle with the old, clunky [`XMLHttpRe
### Implementing User Login and Data Retrieval
Alright, enough theory - let's get our hands dirty! We're about to build the login system that'll make your banking app feel real. The cool part? When users log in, they'll see their actual account data appear instantly, without any page refreshes or loading screens.
Now let's implement the login system that transforms your banking app from a static display into a functional application. Like the authentication protocols used in secure military facilities, we'll verify user credentials and then provide access to their specific data.
I'll walk you through this step by step so nothing feels overwhelming. We'll start simple and gradually add the exciting data-fetching magic.
We'll build this incrementally, starting with basic authentication and then adding the data-fetching capabilities.
#### Step 1: Create the Login Function Foundation
@ -155,13 +153,13 @@ async function getAccount(user) {
- **Converts** the response to JSON format for easy data manipulation
- **Handles** errors gracefully by returning an error object instead of crashing
> ⚠️ **Security Heads-up**: That `encodeURIComponent()` function might look like overkill, but it's actually your friend! Imagine if someone's username was "user#1" - without encoding, that `#` would confuse the URL and break your request.
> ⚠️ **Security Note**: The `encodeURIComponent()` function handles special characters in URLs. Like the encoding systems used in naval communications, it ensures your message arrives exactly as intended, preventing characters like "#" or "&" from being misinterpreted.
>
**Why this matters:**
- Prevents weird characters from breaking your URLs (trust me, users will find ways to break things!)
- Keeps malicious users from trying sneaky URL tricks
- Makes sure your server receives exactly what you intended to send
- Just good, clean coding practice that'll save you headaches later
- Prevents special characters from breaking URLs
- Protects against URL manipulation attacks
- Ensures your server receives the intended data
- Follows secure coding practices
#### Understanding HTTP GET Requests
@ -195,11 +193,11 @@ async function login() {
}
```
Look at what's happening here - it's actually pretty elegant:
- We grab the username from the form (easy peasy)
- Ask the server for that user's account data and patiently wait for an answer
- If something goes wrong, we log it (we'll make this prettier for users in a moment)
- If everything's good, we save the account data and whisk the user off to their dashboard
This function follows a clear sequence:
- Extract the username from the form input
- Request the user's account data from the server
- Handle any errors that occur during the process
- Store the account data and navigate to the dashboard upon success
> 🎯 **Async/Await Pattern**: Since `getAccount` is an asynchronous function, we use the `await` keyword to pause execution until the server responds. This prevents the code from continuing with undefined data.
@ -274,23 +272,22 @@ If something's not working, don't panic! Most issues are simple fixes like typos
You might be wondering: "How is my web app talking to this API server when they're running on different ports?" Great question! This touches on something every web developer bumps into eventually.
> 🔒 **Here's the deal**: Browsers are naturally suspicious. They don't want random websites making requests to other websites on your behalf - that could be dangerous! So they enforce this "same-origin policy" where web pages can normally only talk to servers on the exact same domain and port.
> 🔒 **Cross-Origin Security**: Browsers enforce a "same-origin policy" to prevent unauthorized communication between different domains. Like the checkpoint system at the Pentagon, they verify that communication is authorized before allowing data transfer.
>
**In our case:**
- Your web app runs on `localhost:3000` (your development server)
- Your API server runs on `localhost:5000` (your backend)
- Normally, browsers would block this cross-port conversation
- But our API server is polite and sends special [CORS headers](https://developer.mozilla.org/docs/Web/HTTP/CORS) saying "hey browser, it's cool - localhost:3000 is allowed to talk to me"
**In our setup:**
- Your web app runs on `localhost:3000` (development server)
- Your API server runs on `localhost:5000` (backend server)
- The API server includes [CORS headers](https://developer.mozilla.org/docs/Web/HTTP/CORS) that explicitly authorize communication from your web app
This setup mimics real-world development where your frontend and backend often live on different servers. Pretty neat how it all works together, right?
This configuration mirrors real-world development where frontend and backend applications typically run on separate servers.
> 📚 **Learn More**: Dive deeper into APIs and data fetching with this comprehensive [Microsoft Learn module on APIs](https://docs.microsoft.com/learn/modules/use-apis-discover-museum-art/?WT.mc_id=academic-77807-sagibbon).
## Bringing Your Data to Life in HTML
This is where things get really exciting! You've successfully fetched user data from the server, but right now it's just sitting there invisible in JavaScript land. Time to make that data shine by displaying it in ways your users can actually see and interact with.
Now we'll make the fetched data visible to users through DOM manipulation. Like the process of developing photographs in a darkroom, we're taking invisible data and rendering it into something users can see and interact with.
We're about to explore the art of DOM manipulation - essentially teaching your JavaScript to redecorate your webpage on the fly. This is what transforms a static page into a dynamic, responsive application that feels alive.
DOM manipulation is the technique that transforms static web pages into dynamic applications that update their content based on user interactions and server responses.
### Choosing the Right Tool for the Job
@ -312,11 +309,11 @@ const balanceElement = document.getElementById('balance');
balanceElement.textContent = account.balance;
```
**Why textContent is awesome:**
- Treats everything as plain text (no sneaky scripts can run)
- Clears out any existing content automatically
- Super efficient for simple text updates
- Protects your users from malicious content
**Benefits of textContent:**
- Treats everything as plain text (prevents script execution)
- Automatically clears existing content
- Efficient for simple text updates
- Provides built-in security against malicious content
#### Creating Dynamic HTML Elements
@ -336,19 +333,19 @@ container.append(transactionItem);
- **Allows** for complex, nested element structures
- **Preserves** security by separating structure from content
> ⚠️ **A Word of Caution**: You'll see [`innerHTML`](https://developer.mozilla.org/docs/Web/API/Element/innerHTML) used in tutorials all over the web, and while it works, it's like leaving your front door unlocked. Sure, most of the time nothing bad happens, but why take the risk?
> ⚠️ **Security Consideration**: While [`innerHTML`](https://developer.mozilla.org/docs/Web/API/Element/innerHTML) appears in many tutorials, it can execute embedded scripts. Like the security protocols at CERN that prevent unauthorized code execution, using `textContent` and `createElement` provides safer alternatives.
>
**Here's why innerHTML can bite you:**
- If user data contains `<script>` tags, they'll actually run (yikes!)
- Malicious users can inject harmful code into your app
- Security vulnerabilities are no joke in production apps
- The safe alternatives we're using are just as easy and way more secure
**Risks of innerHTML:**
- Executes any `<script>` tags in user data
- Vulnerable to code injection attacks
- Creates potential security vulnerabilities
- The safer alternatives we're using provide equivalent functionality
### Making Errors User-Friendly
Right now, when login fails, your error messages are hiding in the browser console where only developers look. That's like whispering important information - your users can't hear you! Let's fix this by creating error messages that actually help people understand what went wrong.
Currently, login errors only appear in the browser console, which is invisible to users. Like the difference between a pilot's internal diagnostics and the passenger information system, we need to communicate important information through the appropriate channel.
This small change will make your app feel professional and considerate. No more leaving users wondering "Did it work? Why isn't anything happening?"
Implementing visible error messages provides users with immediate feedback about what went wrong and how to proceed.
#### Step 1: Add a Spot for Error Messages
@ -377,11 +374,11 @@ function updateElement(id, text) {
}
```
**Why this tiny function is brilliant:**
- Takes an element ID and some text - that's it!
- Finds the element and updates it safely
- You'll use this pattern so often, it's worth having a shortcut
- Keeps your code clean and consistent
**Function benefits:**
- Simple interface requiring only an element ID and text content
- Safely locates and updates DOM elements
- Reusable pattern that reduces code duplication
- Maintains consistent updating behavior across the application
#### Step 3: Show Errors Where Users Can See Them
@ -444,9 +441,9 @@ if (data.error) {
## Creating Your Dynamic Dashboard
This is the moment we've been building toward! You're about to transform your static dashboard into something that feels alive - a real banking interface that shows actual account data, updates in real-time, and responds to your users' needs.
Now we'll transform your static dashboard into a dynamic interface that displays real account data. Like the difference between a printed flight schedule and the live departure boards at airports, we're moving from static information to real-time, responsive displays.
We'll take all those DOM manipulation skills you've learned and put them to work creating something genuinely impressive. By the time we're done, your dashboard will rival what you'd see on real banking websites.
Using the DOM manipulation techniques you've learned, we'll create a dashboard that updates automatically with current account information.
### Getting to Know Your Data
@ -466,7 +463,7 @@ Before we start building, let's peek at what kind of data your server sends back
}
```
**Pretty neat, right? Here's what we're working with:**
**This data structure provides:**
- **`user`**: Perfect for personalizing the experience ("Welcome back, Sarah!")
- **`currency`**: Makes sure we display money amounts correctly
- **`description`**: A friendly name for the account
@ -576,9 +573,9 @@ Your dashboard should now display dynamic account information that updates based
## Building Smart Transaction Lists with Templates
Here's where things get really clever! Instead of writing HTML for every single transaction by hand, we're going to create a template - like a cookie cutter for HTML - that can stamp out perfectly formatted transaction rows automatically.
Instead of manually creating HTML for each transaction, we'll use templates to generate consistent formatting automatically. Like the standardized components used in spacecraft manufacturing, templates ensure every transaction row follows the same structure and appearance.
This is the same powerful technique you used for navigation in [lesson 1](../1-template-route/README.md), but now we're applying it to repetitive content. Whether your user has 3 transactions or 3,000, your code will handle them all with the same elegant approach.
This technique scales efficiently from a few transactions to thousands, maintaining consistent performance and presentation.
```mermaid
flowchart LR
@ -666,7 +663,7 @@ updateElement('transactions', transactionsRows);
- **Collects** all rows in the fragment before adding to the DOM
- **Performs** a single DOM update instead of multiple individual insertions
> ⚡ **Performance Secret**: [`document.createDocumentFragment()`](https://developer.mozilla.org/docs/Web/API/Document/createDocumentFragment) is like a backstage area for your DOM elements. You can prepare all your transaction rows behind the scenes, then add them to the page all at once. This prevents the browser from having to redraw the page after each row - much smoother!
> ⚡ **Performance Optimization**: [`document.createDocumentFragment()`](https://developer.mozilla.org/docs/Web/API/Document/createDocumentFragment) works like the assembly process at Boeing - components are prepared off the main line, then installed as a complete unit. This batching approach minimizes DOM reflows by performing a single insertion instead of multiple individual operations.
### Step 5: Enhance the Update Function for Mixed Content
@ -697,13 +694,13 @@ Time for the moment of truth! Let's see your dynamic dashboard in action:
If everything's working, you should see a fully functional transaction list on your dashboard! 🎉
**What you've accomplished is pretty amazing:**
- Built a dashboard that adapts to any amount of data
**What you've accomplished:**
- Built a dashboard that scales with any amount of data
- Created reusable templates for consistent formatting
- Implemented efficient, performant DOM manipulation
- Made something that actually feels like real banking software
- Implemented efficient DOM manipulation techniques
- Developed functionality comparable to production banking applications
You've officially crossed the line from static webpage to dynamic web application!
You've successfully transformed a static webpage into a dynamic web application.
---

@ -6,13 +6,13 @@
## Introduction
You know what's funny about state management? It's absolutely everywhere in web development, yet most of us don't really think about it until our apps start acting weird. Ever built something that works perfectly, only to refresh the page and watch everything disappear? That's state management (or lack thereof) in action!
State management is like the navigation system on the Voyager spacecraft when everything's working smoothly, you barely notice it's there. But when things go wrong, it becomes the difference between reaching interstellar space and drifting lost in the cosmic void. In web development, state represents everything your application needs to remember: user login status, form data, navigation history, and temporary interface states.
Think of state as your app's memory it's everything your application needs to remember while it's running. User login status, form data, which page you're on, that shopping cart full of items all of this is state. As your banking app has grown from a simple login form into something more sophisticated, you've probably started noticing some... let's call them "quirks."
As your banking app has evolved from a simple login form into a more sophisticated application, you've likely encountered some common challenges. Refresh the page and users get logged out unexpectedly. Close the browser and all progress disappears. Debug a problem and you're hunting through multiple functions that all modify the same data in different ways.
If you've been following along with the previous lessons, you might have experienced some frustrating moments: refresh the page and suddenly you're logged out, close your browser and all your progress vanishes, or maybe you've noticed it's getting harder to keep track of what's happening where in your code. Don't worry you're not doing anything wrong! These are the growing pains that every developer faces when their apps start getting real.
These aren't signs of poor coding they're the natural growing pains that occur when applications reach a certain complexity threshold. Every developer faces these challenges as their apps transition from "proof of concept" to "production ready."
Today, we're going to transform your banking app from "it works on my machine" to "this feels professional." You'll learn how to wrangle state like a pro, make data stick around when it should, and create that smooth user experience that makes people think "wow, this just works." Trust me, once you get the hang of state management, you'll wonder how you ever built apps without it!
In this lesson, we'll implement a centralized state management system that transforms your banking app into a reliable, professional application. You'll learn to manage data flows predictably, persist user sessions appropriately, and create the smooth user experience that modern web applications require.
## Prerequisites
@ -41,32 +41,32 @@ curl http://localhost:5000/api
---
## Let's Talk About What's Actually Happening Here
## Diagnosing the Current State Issues
Okay, so you've got a banking app that works congratulations! But before we start celebrating, let's do a little detective work. I want you to try something that'll probably make you go "oh no" (in the best educational way).
Like Sherlock Holmes examining a crime scene, we need to understand exactly what's happening in our current implementation before we can solve the mystery of disappearing user sessions.
Here's a simple experiment that reveals what we're really dealing with:
Let's conduct a simple experiment that reveals the underlying state management challenges:
**🧪 Try This (It's Going to Be Painful, But Enlightening):**
1. Log into your banking app and get to that beautiful dashboard
2. Now, take a deep breath and refresh the page
3. Watch what happens and try not to facepalm
**🧪 Try This Diagnostic Test:**
1. Log into your banking app and navigate to the dashboard
2. Refresh the browser page
3. Observe what happens to your login status
Did you get kicked back to the login screen? Welcome to the wonderful world of state management problems! This isn't your fault it's just what happens when we don't think about how data flows through our applications.
If you're redirected back to the login screen, you've discovered the classic state persistence problem. This behavior occurs because our current implementation stores user data in JavaScript variables that reset with each page load.
**Why Our Current Approach Makes Users (and Us) Sad:**
**Current Implementation Problems:**
That simple `account` variable we created in the [previous lesson](../3-data/README.md)? It seemed so innocent, but it's actually causing us three major headaches:
The simple `account` variable from our [previous lesson](../3-data/README.md) creates three significant issues that affect both user experience and code maintainability:
| What's Breaking | Why It Hurts | What Users Think |
| Problem | Technical Cause | User Impact |
|---------|--------|----------------|
| **Nothing Sticks Around** | Hit refresh and poof you're logged out | "This app has the memory of a goldfish" |
| **State Updates Everywhere** | Functions all over the place are changing our data | "Why is debugging this like finding a needle in a haystack?" |
| **Messy Logout** | Logging out doesn't actually clear everything | "Wait, can other people see my data?" |
| **Session Loss** | Page refresh clears JavaScript variables | Users must re-authenticate frequently |
| **Scattered Updates** | Multiple functions modify state directly | Debugging becomes increasingly difficult |
| **Incomplete Cleanup** | Logout doesn't clear all state references | Potential security and privacy concerns |
**Here's What We're Really Up Against:**
**The Architectural Challenge:**
We could try fixing these problems one by one, but that's like putting band-aids on a leaky boat you'll just end up with more problems. Instead, let's step back and ask the real question:
Like the Titanic's compartmentalized design that seemed robust until multiple compartments flooded simultaneously, fixing these issues individually won't address the underlying architectural problem. We need a comprehensive state management solution.
> 💡 **What are we actually trying to accomplish here?**
@ -144,17 +144,17 @@ const account = state.account;
> 💡 **Note**: This refactoring doesn't immediately solve our problems, but it creates the essential foundation for the powerful improvements coming next!
## Let's Get Control of Our Data Changes
## Implementing Controlled State Updates
Now that we've got our state organized in one place, it's time to tackle something that might sound a bit fancy but is actually pretty straightforward: making sure we know exactly when and how our data changes.
With our state centralized, the next step involves establishing controlled mechanisms for data modifications. This approach ensures predictable state changes and easier debugging.
Here's the big idea: instead of letting any function just reach in and mess with our state whenever it feels like it, we're going to create one special function that handles all the changes. It's like having a bouncer at the door of your data nothing gets in or out without going through the proper channels.
The core principle resembles air traffic control: instead of allowing multiple functions to modify state independently, we'll channel all changes through a single, controlled function. This pattern provides clear oversight of when and how data changes occur.
**The "Don't Touch That" Principle:**
**Immutable State Management:**
We're going to treat our `state` object as [*immutable*](https://en.wikipedia.org/wiki/Immutable_object) which is just a fancy way of saying "hands off, don't change this directly." Instead of modifying the existing state, we'll create a brand new state object every time something needs to change.
We'll treat our `state` object as [*immutable*](https://en.wikipedia.org/wiki/Immutable_object), meaning we never modify it directly. Instead, each change creates a new state object with the updated data.
I know, I know it sounds wasteful. "Why create a new object when I could just update the old one?" Trust me, this approach is going to save you so many headaches down the road.
While this approach might initially seem inefficient compared to direct modifications, it provides significant advantages for debugging, testing, and maintaining application predictability.
**Benefits of immutable state management:**
@ -234,11 +234,11 @@ Try registering a new account, logging out and in again to check that everything
> Tip: you can take a look at all state changes by adding `console.log(state)` at the bottom of `updateState()` and opening up the console in your browser's development tools.
## Making Things Stick Around (Finally!)
## Implementing Data Persistence
Remember that frustrating moment when you refreshed the page and got booted back to the login screen? Well, we're about to fix that once and for all! It's time to make our app remember things like a proper, professional application should.
The session loss issue we identified earlier requires a persistence solution that maintains user state across browser sessions. This transforms our application from a temporary experience into a reliable, professional tool.
You know how you can close Netflix, restart your computer, and when you come back it still knows you were halfway through that show you're definitely not binge-watching? That's the kind of experience we want to create. No more "who am I again?" moments when users refresh the page.
Consider how atomic clocks maintain precise time even through power outages by storing critical state in non-volatile memory. Similarly, web applications need persistent storage mechanisms to preserve essential user data across browser sessions and page refreshes.
**Strategic Questions for Data Persistence:**
@ -377,11 +377,11 @@ return navigate('/dashboard');
🎉 **Achievement Unlocked**: You've successfully implemented persistent state management! Your app now behaves like a professional web application.
## Keeping Things Fresh (Because Stale Data is Nobody's Friend)
## Balancing Persistence with Data Freshness
So our persistence system is working great users stay logged in, life is good. But we've accidentally created a new problem that happens in real apps all the time. Imagine this: you're checking your bank balance on your phone while your spouse is transferring money from the computer. Your phone still shows the old balance because it's using that saved data. Oops!
Our persistence system successfully maintains user sessions, but introduces a new challenge: data staleness. When multiple users or applications modify the same server data, local cached information becomes outdated.
This is the classic "my cache is lying to me" problem, and we need to fix it before someone gets confused about how much money they actually have (which, let's be honest, is stressful enough already).
This situation resembles Viking navigators who relied on both stored star charts and current celestial observations. The charts provided consistency, but navigators needed fresh observations to account for changing conditions. Similarly, our application needs both persistent user state and current server data.
**🧪 Discovering the Data Freshness Problem:**
@ -496,22 +496,20 @@ Use the Agent mode to complete the following challenge:
Learn more about [agent mode](https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode) here.
## 🚀 Challenge Time: Become a Storage Optimization Pro
Alright, you've built something pretty awesome here! Your app remembers users, refreshes data when needed, and handles state like a champ. But here's a question that'll make you think like a senior developer: are we being a bit... wasteful with our storage?
## 🚀 Challenge: Storage Optimization
Here's the thing do we really need to save every single piece of account data in localStorage? It's kind of like carrying your entire filing cabinet with you when all you really need is your ID card.
Your implementation now handles user sessions, data refresh, and state management effectively. However, consider whether our current approach optimally balances storage efficiency with functionality.
**Your Mission (Should You Choose to Accept It):**
Like chess masters who distinguish between essential pieces and expendable pawns, effective state management requires identifying which data must persist versus which should always be fresh from the server.
Put on your detective hat and figure out what data actually needs to stick around versus what should always be fresh from the server.
**Optimization Analysis:**
**Some Detective Questions to Get You Started:**
- What's the absolute minimum information needed to prove "hey, this person is logged in"?
- Which data changes so often that storing it locally is kind of pointless?
- How can we be smart about this without making the user experience worse?
Evaluate your current localStorage implementation and consider these strategic questions:
- What's the minimum information required to maintain user authentication?
- Which data changes frequently enough that local caching provides little benefit?
- How can storage optimization improve performance without degrading user experience?
This is the kind of thinking that separates good developers from great ones optimizing without breaking things!
This type of architectural analysis distinguishes experienced developers who consider both functionality and efficiency in their solutions.
**Implementation Strategy:**
- **Identify** the essential data that must persist (likely just user identification)

@ -1,10 +1,10 @@
# Using a Code Editor: Mastering VSCode.dev
Ever wished you could code anywhere without worrying about software installations or carrying your laptop everywhere? Well, you're in for a treat! Today we're diving into VSCode.dev a game-changing browser-based code editor that's like having a professional development studio that lives in the cloud.
Remember in *The Matrix* when Neo had to plug into a massive computer terminal to access the digital world? Today's web development tools are the opposite story incredibly powerful capabilities accessible from anywhere. VSCode.dev is a browser-based code editor that brings professional development tools to any device with an internet connection.
Here's what makes this so exciting: imagine you're at school, a coffee shop, or visiting a friend, and suddenly you get an idea for your website or need to fix a quick bug. With VSCode.dev, you just open a browser tab and boom you're coding with the same powerful tools professional developers use every day. No downloads, no "sorry, I can't install software on this computer" moments.
Just like how the printing press made books accessible to everyone, not just scribes in monasteries, VSCode.dev democratizes coding. You can work on projects from a library computer, a school lab, or anywhere you have browser access. No installations, no "I need my specific setup" limitations.
By the time we're done here, you'll be editing code like a pro, managing projects effortlessly, and even tracking your changes with Git all from your browser. These aren't just cool tricks; they're the real skills that'll power your entire web development journey ahead.
By the end of this lesson, you'll understand how to navigate VSCode.dev, open GitHub repositories directly in your browser, and use Git for version control all skills that professional developers rely on daily.
## What You'll Learn
@ -18,50 +18,52 @@ After we walk through this together, you'll be able to:
## What You'll Need
Don't worry the setup for this is super simple:
The requirements are straightforward:
- A free [GitHub account](https://github.com) (if you don't have one, no stress we'll walk you through it!)
- Basic comfort with using a web browser (if you can navigate websites, you're all set)
- Having done our GitHub Basics lesson helps, but isn't required
- A free [GitHub account](https://github.com) (we'll guide you through creation if needed)
- Basic familiarity with web browsers
- The GitHub Basics lesson provides helpful background, though it's not essential
> 💡 **New to GitHub?** No problem! [Creating an account](https://github.com/) takes just a minute and it's completely free. Think of it as your coding passport you'll use it everywhere in the dev world.
> 💡 **New to GitHub?** Creating an account is free and takes minutes. Like how a library card gives you access to books worldwide, a GitHub account opens doors to code repositories across the internet.
## Why Web-Based Code Editors Are Game-Changers
## Why Web-Based Code Editors Matter
Let me paint you a picture: remember the old days when you needed to install heavy software on every computer you wanted to code on? Those days are over! A code editor is basically your coding headquarters where you write, edit, and organize all your code. But unlike basic text editors (think Notepad), professional code editors are like having a smart assistant that highlights your code, catches mistakes, and keeps everything organized.
Before the internet, scientists at different universities couldn't easily share research. Then came ARPANET in the 1960s, connecting computers across distances. Web-based code editors follow this same principle making powerful tools accessible regardless of your physical location or device.
VSCode.dev takes all that power and puts it in your browser. Here's why this is such a big deal:
A code editor serves as your development workspace, where you write, edit, and organize code files. Unlike simple text editors, professional code editors provide syntax highlighting, error detection, and project management features.
**Why you'll love web-based editing:**
VSCode.dev brings these capabilities to your browser:
| What's Awesome | What It Means | Why You'll Care |
**Web-based editing advantages:**
| Feature | Description | Practical Benefit |
|---------|-------------|----------|
| **Works Everywhere** | Any computer with a browser becomes your coding machine | Code at school, home, library wherever! |
| **Zero Hassle Setup** | Click a link and you're coding | No "can I install this?" conversations |
| **Always Fresh** | You automatically get the latest features | No update notifications interrupting your flow |
| **Cloud-Powered** | Your GitHub repositories are just a click away | Everything syncs perfectly |
| **Platform Independence** | Runs on any device with a browser | Work from different computers seamlessly |
| **No Installation Required** | Access through a web URL | Bypass software installation restrictions |
| **Automatic Updates** | Always runs the latest version | Access new features without manual updates |
| **Repository Integration** | Direct connection to GitHub | Edit code without local file management |
**Think about it** this completely changes the game:
- No more "I can't work on this because I'm not on my computer"
- Your coding environment looks and feels the same whether you're on Windows, Mac, or Chromebook
- You can jump into any project and start collaborating immediately
- Your computer's storage stays happy (no massive downloads!)
**Practical implications:**
- Work continuity across different environments
- Consistent interface regardless of operating system
- Immediate collaboration capabilities
- Reduced local storage requirements
## Let's Jump Into VSCode.dev!
## Exploring VSCode.dev
Ready to see some magic? We're about to explore VSCode.dev, and I think you'll be amazed at how much power is packed into a simple browser tab. This isn't just any web app it's got all the professional tools you'd expect from a desktop application.
Just as Marie Curie's laboratory contained sophisticated equipment in a relatively simple space, VSCode.dev packs professional development tools into a browser interface. This web application provides the same core functionality as desktop code editors.
First things first: head over to [vscode.dev](https://vscode.dev) in your browser. Pretty cool, right? No download bars, no "please restart your computer" messages just pure coding goodness loading up instantly.
Start by navigating to [vscode.dev](https://vscode.dev) in your browser. The interface loads without downloads or system installations a direct application of cloud computing principles.
### Connecting Your GitHub Account
Here's where things get really exciting! When VSCode.dev asks if you want to sign in with GitHub, definitely say yes. Trust me on this one it's like unlocking a whole new level of awesome.
Like how Alexander Graham Bell's telephone connected distant locations, linking your GitHub account bridges VSCode.dev with your code repositories. When prompted to sign in with GitHub, accepting this connection is recommended.
**Here's what happens when you connect:**
- All your GitHub repositories show up right in the editor (no more tab-switching!)
- Your favorite settings and extensions follow you to any device you use
- You can save your work directly to GitHub without leaving the page
- Everything stays personalized just the way you like it
**GitHub integration provides:**
- Direct access to your repositories within the editor
- Synchronized settings and extensions across devices
- Streamlined saving workflow to GitHub
- Personalized development environment
### Getting to Know Your New Workspace
@ -79,11 +81,11 @@ Once everything loads up, you'll see a beautifully clean workspace that's design
- Notice how the sidebar updates to show different information pretty neat, right?
- The Explorer view (📁) is probably where you'll spend most of your time, so get comfortable with it
## Opening GitHub Repositories (This Is Where It Gets Fun!)
## Opening GitHub Repositories
Okay, here's where VSCode.dev really shows off. You can open and edit any GitHub repository right in your browser no cloning, no downloading, no "let me set this up on my machine first." Want to fix a typo in someone's documentation? Done. Need to explore how a cool project works? Easy. Want to contribute to open source? You're just a click away!
Before the internet, researchers had to physically travel to libraries to access documents. GitHub repositories work similarly they're collections of code stored remotely. VSCode.dev eliminates the traditional step of downloading repositories to your local machine before editing.
I'll show you two ways to do this, and both are super handy depending on what you're trying to do.
This capability enables immediate access to any public repository for viewing, editing, or contributing. Here are two methods for opening repositories:
### Method 1: The Point-and-Click Way
@ -111,23 +113,23 @@ Want to feel like a coding wizard? Try this keyboard shortcut: Ctrl+Shift+P (or
- Once you get used to it, you'll feel like you're coding at lightning speed
- It's basically VSCode.dev's version of "Hey Siri, but for coding"
### Method 2: The URL Trick (This One's My Favorite!)
### Method 2: URL Modification Technique
Okay, get ready for what might be the coolest web development trick you'll learn today. You can edit ANY GitHub repository by just changing the URL. Seriously, it's that simple!
Like how HTTP and HTTPS use different protocols while maintaining the same domain structure, VSCode.dev uses a URL pattern that mirrors GitHub's addressing system. Any GitHub repository URL can be modified to open directly in VSCode.dev.
**Here's the magic formula:**
**URL transformation pattern:**
| What You're Looking At | Normal GitHub URL | VSCode.dev URL (Just Change This Part!) |
| Repository Type | GitHub URL | VSCode.dev URL |
|----------------|---------------------|----------------|
| **Any Public Repo** | `github.com/microsoft/Web-Dev-For-Beginners` | `vscode.dev/github/microsoft/Web-Dev-For-Beginners` |
| **Your Own Projects** | `github.com/your-username/my-project` | `vscode.dev/github/your-username/my-project` |
| **Someone's Cool Project** | `github.com/their-username/awesome-repo` | `vscode.dev/github/their-username/awesome-repo` |
| **Public Repository** | `github.com/microsoft/Web-Dev-For-Beginners` | `vscode.dev/github/microsoft/Web-Dev-For-Beginners` |
| **Personal Project** | `github.com/your-username/my-project` | `vscode.dev/github/your-username/my-project` |
| **Any Accessible Repo** | `github.com/their-username/awesome-repo` | `vscode.dev/github/their-username/awesome-repo` |
**The secret sauce:**
- Just swap `github.com` with `vscode.dev/github` that's it!
- Everything else stays exactly the same
- Works with any repository you can normally see on GitHub
- Boom you're editing in seconds, not minutes
**Implementation:**
- Replace `github.com` with `vscode.dev/github`
- Maintain all other URL components unchanged
- Works with any publicly accessible repository
- Provides immediate editing access
> 💡 **Life-changing tip**: Bookmark the VSCode.dev versions of your favorite repositories. I have bookmarks like "Edit My Portfolio" and "Fix Documentation" that take me straight to editing mode!
@ -143,22 +145,22 @@ Let's dive into the everyday tasks that'll make up most of your coding workflow.
### Creating New Files
Adding new files is super easy and works with all the file types you'll use in web development HTML, CSS, JavaScript, you name it.
Like organizing blueprints in an architect's office, file creation in VSCode.dev follows a structured approach. The system supports all standard web development file types.
**Here's how to create a file:**
**File creation process:**
1. Find the folder where you want to add your file in the Explorer sidebar
2. Hover over that folder name and you'll see a "New File" icon (📄+) appear click it!
3. Type your filename with its extension (like `style.css`, `script.js`, or `index.html`)
4. Hit Enter and voilà your new file is ready to go!
1. Navigate to the target folder in the Explorer sidebar
2. Hover over the folder name to reveal the "New File" icon (📄+)
3. Enter the filename including the appropriate extension (`style.css`, `script.js`, `index.html`)
4. Press Enter to create the file
![Creating a new file](../images/create-new-file.png)
**Some friendly naming tips:**
- Give your files descriptive names that make sense later (trust me, "untitled1.js" will confuse you next week!)
- Always include the file extension it helps VSCode give you the right colors and suggestions
- Keep things organized from the start your future self will thank you
- Stick to lowercase and use hyphens instead of spaces (like `my-awesome-styles.css`)
**Naming conventions:**
- Use descriptive names that indicate file purpose
- Include file extensions for proper syntax highlighting
- Follow consistent naming patterns throughout projects
- Use lowercase letters and hyphens instead of spaces
### Editing and Saving Files
@ -181,15 +183,15 @@ This is where the real fun begins! VSCode.dev's editor is packed with helpful fe
> ⚠️ **Quick tip**: Even though auto-save has your back, hitting Ctrl+S or Cmd+S is still a good habit. It immediately saves everything and triggers some extra helpful features like error checking.
### Version Control with Git (Don't Worry, It's Easier Than It Sounds!)
### Version Control with Git
Here's one of my favorite VSCode.dev features built-in Git support! If Git feels intimidating, think of it as a "save game" system for your code. You can create checkpoints of your work and always go back if something breaks. Plus, you can do it all without leaving your browser!
Like how archaeologists create detailed records of excavation layers, Git tracks changes in your code over time. This system preserves project history and enables you to revert to previous versions when needed. VSCode.dev includes integrated Git functionality.
**Getting familiar with Source Control:**
**Source Control interface:**
1. Click the Source Control icon (🌿) in the Activity Bar this shows all your changes
2. You'll see any files you've modified listed in the "Changes" section
3. Green highlights show what you've added, red shows what you've removed (like track changes in a word processor)
1. Access the Source Control panel via the 🌿 icon in the Activity Bar
2. Modified files appear in the "Changes" section
3. Color coding indicates change types: green for additions, red for deletions
![Viewing changes in Source Control](../images/working-tree.png)
@ -219,11 +221,11 @@ flowchart TD
> 💡 **Quick navigation tip**: Use the hamburger menu (☰) at the top left to jump back to your GitHub repository and see your committed changes online. It's like a portal between your editing environment and your project's home on GitHub!
## Supercharge Your Coding with Extensions
## Enhancing Functionality with Extensions
Okay, this is where VSCode.dev goes from "pretty cool" to "absolutely amazing." Extensions are like apps for your code editor they add superpowers that make coding faster, easier, and way more fun. Want your code to format itself perfectly? There's an extension for that. Want to see a live preview of your website while you code? Yep, there's one for that too!
Just as a craftsperson's workshop contains specialized tools for different tasks, VSCode.dev can be customized with extensions that add specific capabilities. These community-developed plugins address common development needs like code formatting, live preview, and enhanced Git integration.
The extension marketplace is like a candy store for developers thousands of free tools created by the coding community to solve real problems we all face. The best part? You can pick and choose exactly what you want, creating a coding environment that feels perfectly tailored to how you like to work.
The extension marketplace hosts thousands of free tools created by developers worldwide. Each extension solves particular workflow challenges, allowing you to build a personalized development environment suited to your specific needs and preferences.
### Finding Your Perfect Extensions
@ -318,19 +320,19 @@ As you discover more cool extensions, you'll want to keep your collection tidy a
## GitHub Copilot Agent Challenge 🚀
Ready to put all these skills together? Here's a fun challenge that'll help you practice everything we've covered while building something real!
Like the structured approach NASA uses for space missions, this challenge involves systematic application of VSCode.dev skills in a complete workflow scenario.
**Your mission:** Create a complete web development workflow using VSCode.dev that shows off your new professional project management skills.
**Objective:** Demonstrate proficiency with VSCode.dev by establishing a comprehensive web development workflow.
**What you're going to build:** Use the Agent mode to help you set up a project that includes:
1. Fork an existing repository or create a brand new one from scratch
2. Build a proper project structure with HTML, CSS, and JavaScript files that actually work together
3. Install and configure at least 3 extensions that'll make your development process smoother
4. Practice making meaningful commits with clear, descriptive messages
5. Try creating a feature branch and making some changes (don't worry, you can't break anything!)
6. Document everything in a README.md file that explains your workflow and what you learned
**Project requirements:** Using Agent mode assistance, complete these tasks:
1. Fork an existing repository or create a new one
2. Establish a functional project structure with HTML, CSS, and JavaScript files
3. Install and configure three development-enhancing extensions
4. Practice version control with descriptive commit messages
5. Experiment with feature branch creation and modification
6. Document the process and learnings in a README.md file
By the end of this challenge, you'll have a real project that demonstrates you know your way around VSCode.dev like a pro. Plus, you'll have a workflow you can use for all your future projects!
This exercise consolidates all VSCode.dev concepts into a practical workflow that can be applied to future development projects.
Learn more about [agent mode](https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode) here.
@ -362,8 +364,8 @@ You've got a solid foundation now, but there's so much more cool stuff to discov
---
**Congratulations you've just unlocked a superpower!** 🎉 You can now code professionally from literally anywhere with just a browser tab. Whether you're working on a school computer, borrowing a friend's laptop, or even using a tablet, you've got a complete development environment at your fingertips.
**You've mastered browser-based development!** 🎉 Like how the invention of portable instruments allowed scientists to conduct research in remote locations, VSCode.dev enables professional coding from any internet-connected device.
This isn't just a cool party trick you've learned skills that professional developers use every day. Browser-based development is the future, and you're already there! From quick bug fixes to major project collaborations, you're equipped with a flexible, powerful workflow that'll grow with you as you take on bigger and more exciting coding challenges.
These skills reflect current industry practices many professional developers use cloud-based development environments for their flexibility and accessibility. You've learned a workflow that scales from individual projects to large team collaborations.
Now go build something amazing! 🚀
Apply these techniques to your next development project! 🚀

@ -1,16 +1,16 @@
# Build a Chat Assistant with AI
Have you ever wished you could just chat with your computer and get helpful, thoughtful responses? Well, guess what you absolutely can! What once seemed like pure science fiction is now something you can build in an afternoon. In this lesson, we're going to create your very own AI chat assistant that's genuinely useful and surprisingly smart.
Remember in Star Trek when the crew would casually chat with the ship's computer, asking it complex questions and getting thoughtful responses? What seemed like pure science fiction in the 1960s is now something you can build using web technologies you already know.
Here's the cool part: you'll use the same web development skills you've been learning HTML, CSS, JavaScript, and some backend magic to create something that feels almost like talking to a really knowledgeable friend.
In this lesson, we'll create an AI chat assistant using HTML, CSS, JavaScript, and some backend integration. You'll discover how the same skills you've been learning can connect to powerful AI services that can understand context and generate meaningful responses.
Think of AI like that one friend who seems to know a little bit about everything except this friend has read practically the entire internet! When you ask a question, they don't just give you a generic answer; they actually think about what you're asking and craft a response that makes sense for your specific situation.
Think of AI like having access to a vast library that can not only find information but also synthesize it into coherent answers tailored to your specific questions. Instead of searching through thousands of pages, you get direct, contextual responses.
The real magic happens when you connect this AI brain to the web technologies you already know. Your HTML creates the chat interface, CSS makes it look amazing, JavaScript handles all the user interactions, and a backend API bridges everything together. It's like being the conductor of a technological orchestra!
The integration happens through familiar web technologies working together. HTML creates the chat interface, CSS handles the visual design, JavaScript manages user interactions, and a backend API connects everything to AI services. It's similar to how different sections of an orchestra work together to create a symphony.
What we're really doing here is building a bridge between how humans naturally communicate and how machines process information. You'll discover not just the nuts and bolts of connecting to AI services, but also the thoughtful design choices that make interactions feel smooth and natural.
We're essentially building a bridge between natural human communication and machine processing. You'll learn both the technical implementation of AI service integration and the design patterns that make interactions feel intuitive.
I promise you this: by the time we're done, AI won't feel like some mysterious black box anymore. You'll see it for what it really is an incredibly powerful tool that you can weave into web applications using patterns you already understand. Even better? You'll have that "aha!" moment when you realize how apps like ChatGPT and Claude actually work behind the scenes.
By the end of this lesson, AI integration will feel less like a mysterious process and more like another API you can work with. You'll understand the foundational patterns that power applications like ChatGPT and Claude, using the same web development principles you've been learning.
Here's what your finished project will look like:
@ -18,13 +18,13 @@ Here's what your finished project will look like:
## Understanding AI: From Mystery to Mastery
Okay, before we start writing code, let's take a moment to understand what we're actually working with here. If you've worked with APIs before (and I bet you have!), you already know the basic pattern: send a request, get a response back.
Before diving into the code, let's understand what we're working with. If you've used APIs before, you know the basic pattern: send a request, receive a response.
AI APIs work in a surprisingly similar way, but here's where it gets interesting instead of just looking up pre-stored information in a database, they're actually creating brand new responses on the spot, based on patterns they've learned from an enormous amount of text.
AI APIs follow a similar structure, but instead of retrieving pre-stored data from a database, they generate new responses based on patterns learned from vast amounts of text. Think of it like the difference between a library catalog system and a knowledgeable librarian who can synthesize information from multiple sources.
### What is "Generative AI" Really?
Here's how I like to think about it: imagine you have a friend who's read every book in the library, every article on Wikipedia, and somehow managed to skim through most of the internet. When you ask them a question, they don't just recite something word-for-word they actually think about what you're asking and craft a completely new answer just for you.
Consider how the Rosetta Stone allowed scholars to understand Egyptian hieroglyphics by finding patterns between known and unknown languages. AI models work similarly they find patterns in vast amounts of text to understand how language works, then use those patterns to generate appropriate responses to new questions.
**Let me break this down with a simple comparison:**
- **Traditional database**: Like asking for your birth certificate you get the exact same document every time
@ -43,13 +43,13 @@ graph LR
### How AI Models Learn (The Simple Version)
So how do these AI models get so smart? Picture this: they spend their "childhood" reading billions of web pages, books, articles, and conversations. Through all this reading, they start picking up on patterns:
- How people structure their thoughts when they write
- Which words tend to hang out together
- How conversations flow naturally
- The difference between asking a serious question and cracking a joke
AI models learn through exposure to enormous datasets containing text from books, articles, and conversations. Through this process, they identify patterns in:
- How thoughts are structured in written communication
- Which words commonly appear together
- How conversations typically flow
- Contextual differences between formal and informal communication
**Think of it like learning a language as a kid**: You don't study grammar rules first you just listen to millions of conversations until you naturally understand not just the words, but the rhythm, the context, and even the cultural nuances that make communication work.
**It's similar to how archaeologists decode ancient languages**: they analyze thousands of examples to understand grammar, vocabulary, and cultural context, eventually becoming able to interpret new texts using those learned patterns.
### Why GitHub Models?
@ -67,7 +67,7 @@ graph LR
B --> A
```
For our backend setup, we're going with GitHub Models because it offers professional-grade AI capabilities with a really developer-friendly interface. I'd recommend taking a few minutes to explore the [GitHub Models Playground](https://github.com/marketplace/models/azure-openai/gpt-4o-mini/playground) it's like a test kitchen where you can try different AI models and see what they can do.
We'll use GitHub Models for our backend integration, which provides access to professional-grade AI capabilities through a developer-friendly interface. The [GitHub Models Playground](https://github.com/marketplace/models/azure-openai/gpt-4o-mini/playground) serves as a testing environment where you can experiment with different AI models and understand their capabilities before implementing them in code.
![GitHub Models AI Playground interface with model selection and testing area](./assets/playground.png)
@ -160,18 +160,18 @@ messages=[
- **User message**: "Can you explain how vaccines work?"
- **Assistant response**: Sarah responds as a friendly doctor, not as a lawyer or a chef
### Demystifying AI Parameters: Fine-Tuning Your AI's Personality
### Understanding AI Parameters: Fine-Tuning Response Behavior
Okay, those numbers in the API call might look random, but they're actually super powerful controls for shaping how your AI behaves. Let's break them down with examples that actually make sense:
The numerical parameters in AI API calls control how the model generates responses. These settings allow you to adjust the AI's behavior for different use cases:
#### Temperature (0.0 to 2.0): The Creativity Dial
**What it does**: Controls how "creative" or "unpredictable" the AI gets with its responses.
**What it does**: Controls how creative or predictable the AI's responses will be.
**I like to think of it like ordering coffee:**
- **Temperature = 0.1**: "I'll have my usual" (very predictable, same thing every time)
- **Temperature = 0.7**: "I'll try something new, but nothing too wild" (balanced and interesting)
- **Temperature = 1.5**: "Surprise me with your most creative drink!" (totally unpredictable)
**Think of it like a jazz musician's improvisation level:**
- **Temperature = 0.1**: Playing the exact same melody every time (highly predictable)
- **Temperature = 0.7**: Adding some tasteful variations while staying recognizable (balanced creativity)
- **Temperature = 1.5**: Full experimental jazz with unexpected turns (highly unpredictable)
```python
# Very predictable responses (good for factual questions)
@ -449,9 +449,9 @@ Understanding system prompts gives you incredible power to create specialized AI
## Building the Web API with FastAPI: Your High-Performance AI Communication Hub
Now that we understand how AI works, let's build the bridge that connects your frontend to the AI service. We're going to use FastAPI and trust me, once you try it, you'll wonder why anyone uses anything else for building APIs!
Now let's build the backend that connects your frontend to AI services. We'll use FastAPI, a modern Python framework that excels at building APIs for AI applications.
FastAPI is like the sports car of Python web frameworks. It's built for speed, handles async operations beautifully (perfect for AI calls that take a few seconds), and automatically generates documentation for your API. Think of your FastAPI server as a smart translator that takes requests from your frontend, chats with the AI service, and sends back responses all without breaking a sweat.
FastAPI offers several advantages for this type of project: built-in async support for handling concurrent requests, automatic API documentation generation, and excellent performance. Your FastAPI server acts as an intermediary that receives requests from the frontend, communicates with AI services, and returns formatted responses.
### Why FastAPI for AI Applications?
@ -472,11 +472,11 @@ You might be wondering: "Can't I just call the AI directly from my frontend Java
**Data Processing**: You might want to save conversations, filter inappropriate content, or combine multiple AI services. The backend is where this logic lives.
**Think of it like a restaurant:**
- **Frontend**: The dining room where customers sit
- **Backend API**: The waiter who takes orders and brings food
- **AI Service**: The kitchen that prepares the meal
- **Database**: The pantry where ingredients (data) are stored
**The architecture resembles a client-server model:**
- **Frontend**: User interface layer for interaction
- **Backend API**: Request processing and routing layer
- **AI Service**: External computation and response generation
- **Environment Variables**: Secure configuration and credentials storage
### Understanding the Request-Response Flow
@ -705,7 +705,7 @@ Now that we have our AI integration and FastAPI server ready, let's get everythi
### Python Environment Setup
Alright, let's get your Python environment ready for some AI magic! Setting up a virtual environment might seem like extra work, but trust me it's like having a clean workspace just for this project. No messy dependency conflicts, no weird version issues just a pristine environment where everything works perfectly.
Let's set up your Python development environment. Virtual environments are like the Manhattan Project's compartmentalized approach each project gets its own isolated space with specific tools and dependencies, preventing conflicts between different projects.
```bash
# Navigate to your backend directory
@ -1123,7 +1123,7 @@ echo 'export GITHUB_TOKEN="your_token_here"' >> ~/.bashrc
## Creating the Frontend Chat Interface: Where Humans Meet AI
Alright, now for the fun part building the interface that people will actually use! This is where your web development skills really shine. We're not just throwing together a basic form; we're crafting an experience that makes chatting with AI feel as natural as texting a friend.
Now we'll build the user interface the part that determines how people interact with your AI assistant. Like the design of the original iPhone's interface, we're focusing on making complex technology feel intuitive and natural to use.
### Understanding Modern Frontend Architecture
@ -1162,10 +1162,10 @@ Every frontend application from simple websites to complex apps like Discord
- Talks to your backend and updates the page
- Makes everything interactive and dynamic
**I like to think of it like building a house:**
- **HTML**: The frame and rooms (what exists and where)
- **CSS**: The paint, furniture, and decor (how it looks and feels)
- **JavaScript**: The electricity, plumbing, and smart home tech (what it can do)
**Think of it like architectural design:**
- **HTML**: The structural blueprint (defining spaces and relationships)
- **CSS**: The aesthetic and environmental design (visual style and user experience)
- **JavaScript**: The mechanical systems (functionality and interactivity)
### Why Modern JavaScript Architecture Matters
@ -1864,7 +1864,7 @@ Learn more about [agent mode](https://code.visualstudio.com/blogs/2025/02/24/int
## Assignment: Build Your Personal AI Assistant
Alright, here's where things get really exciting it's time to create your own unique AI assistant! This isn't just about copying what we've built; it's your chance to get creative and make something that's uniquely yours.
Now you'll create your own AI assistant implementation. Rather than simply replicating the tutorial code, this is an opportunity to apply the concepts while building something that reflects your own interests and use cases.
### Project Requirements

Loading…
Cancel
Save