Category: From Youtube

  • Fable 5 is BACK! Here are the first 8 things you need to do…

    The moment you’ve been waiting for happened. Claude Fable 5 is officially back. It is the greatest AI model. Nay, the greatest technology I’ve ever used in my entire life. It was taken away from us. It was ripped out of our hands and it is finally back. You can now use it in Claude, Claude Code, any platform that uses Claude, Cursor, everything, all of them. It is by You don’t need me to convince you. You already know. It’s the best technology ever made. It is by far the best model ever. I have the first eight things you need to do with Claude Fable 5 now that it is back. These eight things will help you get so much more out of it. If you feel like everyone else on the internet’s getting tons of usage out of Fable 5 but you, this video is for you. But before we get into that, let’s just go over the news and what the pricing is like now, what the usage is like now, how Claude Fable 5 will work moving forward. Check this out. You have 50% usage through July 7th. What does that mean? You can use this model up to the first 50% of your usage. Once you’re at 50% of your usage, then you have to pay API pricing. Just as a reminder, Claude Fable 5 is very expensive. So, this will get very expensive once you used 50% of your usage with this model. You have to manually turn on extra usage if you want to keep using it after that. That is a button in your settings. You turn that on. It basically allows you to deposit money and that money is used as credits towards your extra usage. So, it’s API pricing. And then on top of that, there’ll be much more tight security with Fable, meaning if you ask it to do things that are kind of iffy, hey, hack this other government. Hey, steal all the money from my friend, it’ll be like, nuh-uh, we’re falling back to Opus. And it will automatically switch to Opus for those tasks. My guess is it will be a little trigger happy with the security. will fall back a little bit too often. You got to imagine they’re going to be super careful now that the US government has cracked down on them. So, that is kind of the bad news of all this. Uh you can use it a lot less and if you use it more, it’s very expensive. I will say this before we get into those eight big things you need to do the moment it releases, which is right now. Here’s the story. I’m turning on extra usage. I’m going to deposit I think it is like $1,000. You can buy $1,000 worth of credits for $700. I’m going to take that deal because I think it is a pretty solid deal. Claude Fable 5 isn’t just a step better than what the other models were before. It is a gargantuan step forward. And so the people that use Fable 5 will have an outrageous advantage against those who don’t. So if you are building a business right now, if you’re trying to earn revenue, you need every advantage you can get. So for me personally, I will be paying the API pricing for the extra usage. And I think you should consider it too. I’m not sponsored by Claude. They’re not paying me. No one from their team has ever reached out to me. I am not affiliated with their company in any sort of way. But Fable 5 is incredible. So, I’ll be paying the extra money. Now, let’s go into those eight use cases. What are those first eight things you should be doing now that Claude Fable 5 is back? These first two things I’m going to go over is for those out there who vibe code, who build apps, who have been maybe vibe coding the last couple weeks. The first thing you want to do is find exactly all the code you wrote the last couple weeks while Claude Fable has been gone and fix all of it. Opus is a great model, don’t get me wrong, but Fable is literally 10 times better. I mean, it’s just so much better. So, what you want to be doing is, and I will put all these prompts down below. Everything will be down below. Please check all the pull requests we merged the last two weeks. Do a code review. Find any optimizations or improvements we can make. I did this on Fable 5 on high. For code reviews like this, we’re fine with high. We don’t need to go to ultra code. Let’s just stick with high for that. And then you hit enter on that. If you don’t use proper GitHub best practices, you can just say look at all the code from the last two weeks that we wrote. It’ll go through its memory and find all the changes it made. But you want to make sure all nonfable code is found and improved and checked. Fable is so much better at writing code. The first thing you want to do is fill any gaps. get out any unoptimized code, anything like that. Any code that might have security issues, use this, put it in, it’ll check the code, you’re good to go. The second tip takes advantage of a feature not many people use. So, this will be a good one to set up just for everything you do moving forward, and that is taking advantage of the Claude for Chrome extension. Claude is amazing at browser use. It is amazing at controlling browse. And by the way, if you don’t vibe code as much, you can just skip to the third lesson from here. we get into more general tasks. I want to start a little bit with vibe coding first, but taking advantage of that Chrome extension. And so the prompt you want to steal is this again down below. Walk through every major user path in the app you’re building using browser control. Write a report on where users can get confused and what I can do to improve the UX. If you don’t have the Chrome extension installed yet, just say, “Hey, how do I install the Chrome extension?” It’ll set it up for you. You just have to go into your settings. And then from there, what will happen is Fable will literally open up your browser, open up a new tab, and walk through whatever app you’re building and test it like a real user would. Then it’s going to write a report. It’s going to tell you how you can improve the user experience, and it’ll do it for you. Fable is the most human-like model I’ve ever used, and using it in this way will get you such better improvements out of the user experience. I also like to just do all testing of all code I write. This way, anytime code’s written, I’ll go and say, “Hey, now pop open a browser and test it for yourself.” So, this is a tip you want to use over and over and over again inside Claude Code. Just as a side note, this is Claude Code for desktop. I think it’s the best way to use Claude Code. I think it’s better than the CLI. Makes it really easy to manage all your sessions. So, just a little side tip there. For this next use case you should be doing, immediately I switched over to the chat section of the Claw Desktop app. I went in here, Fable 5 Hive. This next one’s going to help us figure out businesses we can create with Claude Fable. If you’re looking to start a digital business, much like I have, I have like eight or nine different businesses I started. Brainstorming with AI is one of the best ways to do it. And Claude Fable 5 is by far the best business planner I’ve ever talked to in my entire life. So, what you want to do is steal this prompt. And again, I will put it down below for you so you can just copy and paste it in. But basically, what Fable 5 will do is act as a business consultant. He will figure out my goals, my ambitions, my priorities, what my passions are, what my audiences are, what my different assets are, what value I can provide to the internet, and then come up with direct plans for what I can build to start making money online. If you’re not making revenue online right now, you should at least be striving to get there. It allowed me to quit my job. I quit my job three years ago because of all my different business lines. My YouTube’s blowing up. I have different SAS creator buddy, Henry intelligent machines. I have my community. All these are different things that I’ve built and brainstormed with AI. And you should be doing the exact same thing. I promise I’m nothing special about me. You can be doing it, too. This is how you do it. Seal this prompt. What it will do is interview you question by question by question to understand you on a really deep level. And then it will give you precise recommendations about the products and services you can create to start making money online, start generating revenue, even if it’s just side revenue to your current job today. This will help you through it. Fable is the best like business consultant planner I’ve ever talked to in my life. Steel’s prompt is down below. Next, let’s talk about looping. Looping is the topic of the day. Everyone’s talking about looping. Inside of Clawed Code, you have a slashloop skill. The way this works is you can do slashloop, give it a amount of time. So we’re going to do 24 hours, and then we can give it a task to do every 24 hours. So if you want to do this every 5 minutes, you can do that. If you want to do it every 10 minutes, you can do that as well. But what we’re going to do is because Fable is so good at security, we’re going to make sure that our app is secure. So if you are a Vibe coder, this is something you want to do quite often. The biggest attack vector of vibecoded apps is API routes. And so one thing I’ve been doing that is really helpful here is you do /loop 24 hours, you can say check out our API endpoints and make sure they are secure. And now every 24 hours when I hit enter on this, Fable will go in and loop through every single API endpoint in our app and make sure they’re not hackable. Make sure no one can get in. Delete data from your database or anything like that. If you are vibe coding anything right now, this is a security practice you 100% want to do. Do do slashloop. Give it whatever time period you want. For this, I’m going to do once a day just because Fable is so expensive. and we’re going to say check out our API endpoints and make sure they are secure. Now, we have an agent that’s like our protector, our Batman of the app we’re vibe coding to make sure our app and all our API endpoints are very secure. It’s the reason why my app creator buddy hasn’t had a single security incident in the year and a half it’s been out is because I’m constantly having agents pound the API endpoints and find any security issues that might be going around. The next thing I’d want you to do is take advantage of the XMCP. If you use TwitterX at all, this is an amazing amazing tool I’ve been using recently. I’ll put a link down for this down below if you want to use it. This has been an amazing tool for customer research. So, basically way the XMCP works is it allows Claude and Fable to actually go in and look at your tweets, look at your post, search for other people’s posts. It basically just gives it access to all of Twitter. And so me as a business creator, I like to go in and see based on my tweets and based on other people’s tweets, what are other businesses I can start? What are other apps I can build to solve their challenges? So if you take the link to XMCP below, you give it to Claude Code. You give it to Fable and say, “Hey, set this up.” It’ll walk you through setup. You then can do interesting things like say, “Look at my last hundred posts and let me know five SAS ideas I could build out based on my strengths and interests.” So if you tweet on Twitter and you got a bunch of tweets, they are good data and context you can feed into your Claude code agent to figure out apps to build out. This is an awesome one. Take the link down below from XMCP. There’s so many other things you can do here as well. You can even say search through X, find other use cases people are doing with Claude Fable and let me know the top five use cases of Claude Fable and that will go and kind of crowdsource what everyone’s doing with Claude Fable, which is really awesome as well. Set that up. It’s an ultra valuable tool for everything you’re doing in Claude. You just deposit a couple bucks into XMC accounts. You can pull a ton of different posts and you can use it as data for everything you build, which is really, really sick. The next use case you can do is really cool if you’re a nerd like me and enjoy building video games. If you’re one of those people that were building a bunch of really cool 3JS games as like the first thing you do with every new model that comes out, I have an upgrade for you which is the Unreal 5.8 MCP. This is completely free. This allows you to build really really sick games using Unreal Engine which is just like a hundred times better uh than 3JS. It’s completely free. It plugs into Claude code. And if you use Claude Fable, it’s just like 10,000 times better at building games. You can just go in and say, “Hey, build me this in the game. Make the guy do this. Give it this gun. Make it shoot this.” And Claude Code will go in and add all those things to the 3D game you’re building. And obviously, this just looks like a hundred times better than anything you get in 3JS. If you’re a nerd and you’ve experimented around with building games inside Claude Code and maybe you used weaker libraries like 3JS, you want to upgrade, try out Unreal 5.8 MV. It’s the first like major video game engine that you can connect to Claude Code and Claude Fable and actually use it to build games directly without any technical knowledge at all. So, this was a really fun one. I’ll leave the link down below for Unreal MCP as well. And this last one is great if you just don’t know how to get the most out of these models. And this is an exercise I have everyone do that I work with. And that is write down every task you do today. Every single task, write it down on a piece of paper. Use a pen and paper. As you walk around your apartment, your house, whatever it is, write down your task. Put them on a piece of paper. I have like my 20 different tasks I’m doing today here. Then you go into Claude. You go into Fable. You list every single task you did that day. Whether it’s checking emails, responding to things, building things, whatever it is, you put it in and then you ask Claude Fable, “Take a look at my tasks I did today. How can I use you to better handle, automate, and complete these tasks? How could you be the most service to me and save me as much time as possible?” You hit enter. This is what I call reverse prompting, asking the agent what it can do for you. Fable will then go and figure out how it can save you the most time, automate your task, do the most work possible for you. Everyone should continuously be doing reverse prompting exercises like this every single day to discover new things the agent can be doing for you. I don’t care if you’re at work. You put in all your tasks that you’re doing at work. This will help you figure out how to automate and handle as as much of your life as humanly possible. Reverse prompt. I’ll take this. I’ll put this down below. All the prompts for all these things are down below. Just copy paste. Take whatever you want. Fable 5 is back. Take advantage of this. Make sure to use as much of this free credit they’re giving you for the next week as possible. You should be disappointed in yourself if this weekend ends and you didn’t use your 50% of your usage. It’s such an incredible technology. It’s such an amazing time to be alive. I am so grateful. If you learn anything at all, leave a like, subscribe, turn notifications. I’m going to do a live full boot camp this Friday on Claude Fable 5 inside the Vibe Coding Academy. Make sure to hit the link down below to join that. Ask me questions. see how I use Claude Fable 5. I hope this was helpful.

  • Every Level of Hermes Agent Explained

    I have spent hundreds of hours in Hermes Agent building, experimenting, and I’ve seen every single masterass. And in this video, I’m going to take you through the seven levels of Hermes Agent step by step so you know what to expect at each level, the exact mistakes that you need to avoid, and what you need to do to progress to the next level so you can save more time, make more money, and get light years ahead of everybody else. And if you’re new, I’m Jack. I built and saw my LTC startup with a gazillion customers. Now I build my own AI companies and I share here the stuff that actually works. So if you haven’t already, grab that beautiful coffee and let’s dive straight in. Now there are seven levels to this Hermes agent. And if you make it towards the end of the video, they’re going to be saying, “Hey, who is this super intelligent Hermes individual I see before me?” That’s what they’re going to be saying about you when you make it to the end of this video. Now, we’re going to go through every level of Hermes from one prompt to an agent that literally does wonderful and fantastical things and a lot of mistakes. Now, here’s the thing. What? Level zero is where everybody’s at. Cuz just for context, nobody’s using this stuff. Like you’re seeing all this content cuz you watch it, but just like for context, barely anybody is using AI, let alone Hermes agent. So you are already ahead. Now let’s begin with level one, which is the beginner. This is basically the download and go individual. Essentially, what’s happened here is you understood that it’s an agent and not a chatbot. We know that chat bots you can have conversations with like Claude and Chat GPT. Hermes is something that actually goes ahead and does things for us. And to have reached level one, what you needed to have done is actually gone ahead to basically the website, grab the information and download Hermes onto your computer. And if this sounds like I’m speaking German, click this link on screen. I see the full process of getting it set up. But effectively, you’ve gone and you’ve installed it on your computer. Now, you’ve installed it on your computer and you’re connected to Telegram or your messaging platform of choice. Now, at level one, you’re using it for simple tasks. So you might say something like, “Hey there, I am going from Dubai to a random country in Europe for 3 months. Do some research. Write me a list of the best countries to go to with some insights and just save that HTML file on my desktop so I can check it out for me later when I come back.” Send that off and literally Hermes agent is going to do this for us and just save things for us to check whenever we want to. And as you can see, Hermes agent completes things for us. It uses tools. It’s got the chat. I can just do anything we want to in those current environments. And now I can even open this up and see its output. Now as you can see I open up and it’s given me a nice little breakdown of all the things that I want to do. Key difference here is that you’re using Hermes agent for anything and also tool calling to build interesting things. Now the biggest drawback at level one is you’re just using it for long oneshot prompt things. You need to make sure that you’re collaborating with Hermes agent. Ask it to understand your stated intention. Go back and forward and just be mindful of your context window. You could probably expect to save about 30 minutes a day when you’re using it in this type of fashion. And this brings us on to the second level of Hermes agent and one of its strongest features that if you don’t use it, you are not utilizing Hermes properly. Now with the apprentice at this level, effectively Hermes is getting to know you as an individual. Now the key thing about Hermes agent is that the more that it knows you, the better it actually gets. And I can show you here for example with this memory system. The more information, the more you speak to Hermes agent, the more information that you give it, the higher performance it will actually get. But what do I mean by that? Let me explain. So Hermes itself has a very cool memory system. For example, you can say to Hermes agent, hey, what was that thing? Could you just tell me one thing that we spoke about 2 days ago, please? You can actually get Hermes agent to recall specifically things that happened on days. Now, the cool thing is Hermes will commit to its own internal memory the more that you actually talked about it. But it isn’t even just about its memory on a service level because this is just basic at level two. It’s also its ability here to know who you are and tailor its specific advice based on what you’re trying to actually get. And as you can see, it’s talking about alarm, which is a video that came out a couple of days ago on my channel. Now, you are missing out on Hermes magic unless it knows about you. So, what you want to do effectively is use what we call a Hermes soul.md. What do I mean by that? Well, if I show you here, for example, on the OS, if I come down here, you can actually categorize your user profile and actually physically give it a soul. This is stuff like how do I want you to address me? Information about you and basically your business or whatever it is that you actually are physically doing. And I’ll put a link down below for the soul. Hermes template that takes you through everything, mission goals, your business, key metrics, all this sort of stuff. The be the beautiful part of Hermes, okay, is that if two people speak to Hermes and ask it the same question, they should get radically different answers because it understands context. It’s all about context engineering. It needs to know about you and your information, your data, so it can best help you. And that’s one of the biggest differentiatories that we start to see at level two on our seven level scale. That’s why we call it the apprentice. And the key point here is that Hermes never starts from zero. It’s the agent that remembers your birthday. Its memory is one of its most coolest features and it should it should know that stuff about you. So at this level we should be looking at roughly 5 hours a week that we’re claiming back. Key thing is if it knows you, you can stop carrying all the information in your head. And remember this when we’re thinking about how much time it saves you. There’s such a thing as context switching, right? It isn’t just how much time did I spend doing something. You lose things when you switch between tasks. So having one of the world’s most intelligent personal AI assistants is an unbelievable gamecher and why it’s blowing up so much and it’s going to be such a huge thing in the future. Key details, it remembers your preferences, it can recall past chats, and there’s no need to reexlain. Now, custom instructions are one thing, but if you don’t use skills and commands properly in level three, you’re not utilizing its full potential. What do I physically mean by that? Well, we’re looking at two key things here. Okay, first thing I want to touch on here is some of the key commands and controls that will radically change your experience as her with Hermes. At this level, you’re starting to basically really utilize its functionality and how cool it freaking is. Let me show you exactly what I mean. First of all, I might give it a prompt that sounds something like this. Hey there, I would like to go online and find for me what are what is the best advice to scale my LinkedIn and acquire clients in that channel. Do some deep research for me and find that out. Okay, so you can give Hermes a prompt like this. We could be in the gym. We could be anywhere. Now, crucially, I can do a couple of things. I can do forward slash. I can do steer. And steer basically will guide it in one direction. I specifically want you to look at top creators on LinkedIn who are already doing very well and also YouTube. Now, what this means is I’m kind of like it’s it’s going to use this and think about this prompt before it’s even completed. Now, and it’s a great little hack. Another one I can do is background, which basically means whilst it’s doing that task, fire this one off in the background. So, I could say, “Hey there. I’d like to go ahead and do some research on the best way for me to grow my Instagram. Specifically, go and find me great Instagram creators and build me a beautiful list of ways that I can improve my Instagram.” Now, background tasks themselves happen in the background and it doesn’t even interact with the core thing that Hermes agent is doing. So, the idea here is that we’re using more of the features that exist within Hermes. We’ve got handoff, we’ve got clear, basically clear functions. And again, there’s lots of different things you can do. Now, the other really interesting one here is the model. Now, at this level, at level three, we’re basically using what I call model agnostic behavior. What the hell does that mean, Jack? What it basically means is that we tag in the best model for the job. That’s simply it. In fact, I can even show you with the Hermes app. If I pull this up, and even if you see here, for example, in the operating system for Hermes, if I come over here, you can see the model that we currently have tagged in. In my previous video, I also showed you how you can run this 100% privately, which is crazy. Now, the point here is that we can see the model we’re dealing with. We’re talking to chat 5.5 and if I have a conversation, I’ve got that freaking awesome. So, for example, if you can come now, you can see the different models I have within her agent, right? Anthropic, GitHub, open air codeex, open reach, etc. So, I speak to people all the time about Hemy’s agent. Now, some say, Jack, my credit was credits went very quickly. Your core model, okay, think of it like this. You want to connect your chat GPT subscription to Hermes agent. Super duper important that lets you use your $20 chat GPT subscription for anything. It is a coding powerhouse. Now the most intelligent model is Opus 4.8. But the reality is you don’t need it for everything. We don’t need astrophysicists, you know, basically building Legos for us. It’s not required. Sonet 4.6 is a very good middle ground of like really good performance, but it’s not going to burn your cost. These are API costs. The other model you need to have in here as well is Grock. Grock also connects via oorthth which means open authentication. You literally connect it, you sign in, and you’re basically using Grock within the engine. Now, the cool thing about Grock, again, it’s on your subscription and you get access to the entirety of X. So, you can say, hey, uh, what’s happening this week with websites? And it’ll tell you all the top posts. It’s freaking amazing. Then, we want to tag in the right models. You want to make sure that you’ve got Open Routter as well. Open router is a very important piece of software that effectually lets us connect to anything in the world that we want to. Why do I like it? Well, let me show you this. If I come over to rankings, you can see we have access to every model. You can access free models. You can access any model that you wish. It’s really freaking impressive. This is how I personally access 4.8 um with Claude. And essentially, we can ratchet it down whenever we want to. We can even use DeepSeek V4 Flash, which is fantastic. So we get to basically ratchet it up based on performance and cost and also privacy. So we get to move those dials up to get the right models we want to. And at level three of the system guys, what we’re doing is leveraging the right model for the right task. This is also the level where we begin to introduce skills. Now when it comes to skills, what I think is really important is the skills are only as good as the model doing the skill and what the skill actually is. So, for example, in the pantheon here, I’ve got in the operating system. One of the things that I’m very specific about when I add my skills is specifying three things. So, let’s go with the alchemist in this case, right? I specify what the job is, a description of that job, and then a system prompt, which is completely optional. And then, crucially, I come down and I actually specifically outline what the model is. Why? Because I don’t want 4.8, which is really expensive, doing something that we could delegate to a free model or something on Deep Seek. And of course, we can connect this entire thing. Then if I want to change my primes, I can visually come in, see them, and make adjustments as I want, as I come and go. Now, why is this so important? This really, if you’re down to it at level three, are some of the biggest time saves that you’re going to get because it can do things like go and do my competitive research, go and find for me all the outliers that exist on Instagram. And you can build software that looks like this. And this, for example, if you’re trying to grow on Instagram, as for instance, shows you all of the outliers. I scrapped this from my community. Why is this so cool? Well, this would be something that you could have spent hours doing. And this is why this can save you up to a day a week cuz you can now delegate tasks and automations and research to Hermes and it will execute for you perfectly. Now this sounds like I’m actually speaking Portuguese. I’m going to put a link down below for this full claw code course that will take you from foundation and setups, building websites, power features, memory systems, Hermes setup, stuff I have never covered on YouTube before. I’m going to put all down below. People mess about this course all the freaking time. You also get complete immediate access to this entire operating system. I’ll put a link down below so you can check that and upgrade if that’s valuable to you. And just FYI, by the way, um our price on our community is popping up on the 13th. So if you see it ahead of time, we’d love to welcome you. So we’ve covered this in level three and it does lead us very nicely onto the fourth level of Hermes, which is the integrator. Now in the integrator section, this is where really Hermes goes to a completely new level. And if you look at this graphic as a for instance, okay, what we’re really doing is connecting it and giving it the ability to connect to your world because the more things that you touch and interact with that we can plug into Hermes, the more it can really do. A lot of the stuff that we’ve covered so far is you speaking to Hermes and Hermes doing things like create me a report that does X or go and research Y. In level four, we really unlock the new capabilities when we give it access to things like reading our emails, things like creating calendar appointments with us and our friends and our our colleagues and potential business partners, looking at notion for like things like our to-do list, plugging into Slack so I can get immediate updates. For example, maybe you’re on ClickUp, right? One of the things that we could do with ClickUp is have our team, this is one of the things I implemented, basically giving updates on that. And now basically when I want to know what’s going on in my business, I can say, “Hey, Hermes, what were the numbers this week?” And the really cool thing and I want to stress this upon you, okay? Is that you give it text but also numbers. So if I’m saying, “Hey, I’m thinking about this from a strategic point of view. What are your thoughts on this strategy?” And one of the things my Homies agent will know to do depending upon what I’m talking about is it can go to different databases. Say you’re connected on ClickUp or whatever you are. It can go through the latest updates that you had that week from your team and say, “Well, actually Jack, did you know that um you know Kevin or I don’t know Sarah M or whatever actually submitted a report that unlocked this new thing?” that’s really relevant for you to know. So the idea is you don’t have to rely on your memory or you shouldn’t have to rely on your memory. Plugging Hermes into your world will create new optionality for you. And this is a key thing that everybody’s missing. How do I actually plug in new things? Well, it’s so unbelievably straightforward. Let me show you what I mean. So say we have our Hermes agent here, right? And again, it’s even working now in the background answering our things before. And I’m going to come down here. I’m going to do a for slash and we’re going to stop, which is going to kill all the background processes. And that’ll be the end of it. But let’s say I want to connect something. So, one of the big ones I love to connect to is Granola. They’re not sponsoring this video or anything, but the point with Granola is they will let you chat to any of your meeting histories. For example, I could say, “Hey, dude. Um, what was the title of the last meeting I had, and can you tell me one action I took from it, please?” Now, when you connect anything to Hermes agent, sometimes you’ll just store the API key on your desktop. Other times, you can literally log in by via an MCP, which is freaking awesome. And bear in mind, guys, this is one of the cool benefits of having this on your desktop. like it’s already got all of your signins and credentials, so you don’t need to duplicate this. I mean, I’m not getting paid tens of thousands of dollars to sell you some kind of VPS. I tell you exactly what I do in these situations, which is run it locally on my computer. I don’t really see the point or value in running it on a VPS to be honest with you. So, it’s just really cool and just makes it a lot easier to do things like this. So, we would just come down and we click on allow access in this case. And as you can see down here, one action you took away from AI automation coffee was to collaborate with someone in the workshop regarding iOS knowledge graph. There you go. You can see exactly how that’s connected and we even set the one up together. And the other thing to bear in mind is if you’re ever not sure how to connect something, just say, “Hey, I want to give you the ability to do this thing. What do you need from me to do it?” And just follow through the instructions. One little side hack for you. Don’t ever paste those API keys directly in Hermes. You can save them on your desktop or it’ll give you a terminal command. You can enter that in and it will throw basically explain everything to you step by step. Now, where most people get stuck at this level is they basically give it the MCP candy store. We give you imagine giving the 5-year-old all the candy in the world in a candy shop, it would go freaking in ballistic. So, same thing here. Now, the more MCPs that we give to him, his agent, the bigger its context window actually grows. Now, there are cool tools we can do like laser loading them and stuff, but fundamentally we don’t want to give it loads of garbage that we’re not physically using. So it’s context window doesn’t balloon significantly. That’s just one to watch out. And the idea is the fewer number of keys we can give it the better. Now a couple things I really want to bear in mind with this. First of all, emails. I personally do not give it the ability to send emails. It can draft them. It can add things to my calendar, but it can’t send emails just yet. So I kind of like to keep that one internally rather than sending it out. Some point it will be fine, but at the moment I just like to keep that um requirement to myself. And so really level four is about crushing your admin. It should be able to do anything you need it to do. Anything that you would personally do on a laptop, Hermes should be able to do that for you. And if it can’t, just ask yourself, why doesn’t it have that access and just connect it to Hermes. It’s a really good exercise to do and will save you so much time. Now, level five is when it starts to get very interesting. We call this level the orchestration level. Effectively, where Hermes becomes not only an executing agent, but a manager that manages other agents to do different tasks. It can in fact spin up multiple agents and every single update that you see with Claude Opus 4.8 can now do this cool thing. It can do ultra work. Hermes can do the exact same thing. Remember someone asked me recently, Jack, what’s better, Claude or Hermes? It’s like asking me what is better, Lewis Hamilton or Ferrari. They’re different, right? Hermes is the if you think of Hermes is more kind of like the the actual agent system and then the actual driver, the race car drivers are things like Claude and Chat GPT. This is more of a system that surrounds her. Now, the key thing here is that Hermes itself can use Opus 4.8 and all of these individual models to do many different things at the exact same time. And we just mentioned, didn’t we, about the Pantheon, this idea that we can actually go ahead, if I bring up the right actual tab here and show you this all these different systems, these different skills that we want to build out to do various different things. But what is really cool about Hermes agent is that we can actually ask it to do multiple things at the same time. Let me show you what I mean. And this is really where the sub agents come to play. So I can say hey there I would like you to create for me a team of agents. I would like one of the sub aents to be called it chat GBT 5.5. I want to use DeepSeek V4 and I’d like to task Deepseek V4 with going and doing some comprehensive research on the best industries to sell websites to. I want GPT4, excuse me, GPT 5.5 to critique it and I want them to go around in a loop until they’ve solved the issue. And then I would like to have Opus 4.8 eight as an orchestrative agent that will oversee it like his team, spin up as many sub agents as you see fit, but a lot of the work I want done by the very cheap Deep Seek V4. And as you can see, it’s actually going ahead and doing that for us. So, we have multiple agents in Hermes working in parallel. Now, this is the reason why this is even better in some respects than Opus 4.8 is mainly because we’re not just using Claude here. Now obviously you can connect these things to Claude which is fine but again I get to bring in any model I want to to do anything that I want. You can do this within Claude but I also think it’s one of the coolest things that we can do in Hermes which is completely model agnostic. We bring in the best model for the job and we have these fantastic parallel agents working for us. Now on level five itself this is where you can really explode your output if you know what you’re applying for. Remember the biggest hallmark basically of a of a beginner automator is that you automate stuff that should simply should not exist. The idea is this is high leverage when you know the high leverage thing that you’re focusing in on. Right? We don’t just talk about AI here. We talk about in the context of winning like in life like in business in our physical health in our relationships. We want to be the best version of ourselves and that means we know the problem that we’re solving. AI is an accelerant to that end. So the point is you can start to tank your output if you know what you’re focusing on and what your bottleneck is in your particular business or situation. So it’s a real explosive feature. But it brings us very nicely onto the sixth level where it takes one step further and this one is known as the builder. So first thing to understand about Hermes agent is that it does ship real things. Anything I’m getting fired up right now. Anything you can build in claude code you can build in Hermes agent. And honestly for me guy, this was the coolest unlock to be at the gym doing my bench press. I used to decline, incline, whatever you want to do and being able to actually code things and build things is a freaking unbelievable. If you’re building software, the ability to have those conversations, spin up the different sub aents and build software whilst you’re doing anything else you want to is literally gamechanging. It is no longer just a chatbot. This is software. You are building software and I’m telling you right now that is the future. Building these micro softwares, these micro apps is insane. If you have the idea, if you can imagine it, you can build it. That’s kind of the point here. Hermes lets us do this remotely. And in my view, no other app items of like, you know, Codeex and Claude really compete with Hermes remote ability. You can hack it and make it hacky, but then what you start to realize is you’re basically just rebuilding Hermes anyway. So, this is why this is so freaking sick. And at level six as well, you start to use its automation features. And what do I mean by that? I mean about asking it to do things at certain times. Taking what we call asynchronosity, which means that most people do this, I answer, you respond. You you ask a question, I respond. What people in level six do at the builder level is they’re actually adding scheduled tasks. They’re saying, “Hey, Hermes, um, I need to go and have a conversation this weekend with, you know, I don’t know, Mckenzie and K. um do some deep research over the next 24 hours and then on Friday afternoon make sure you give me a fresh report on my desk find the email addresses of all the board the members of the board and actually draft me an email or you’ll say and also send me a reminder on Thursday evening that I need to go ahead and do this thing and you’re basically creating your schedule tasks and it’s unbelievably easy to do for example you just say hey there I’ve got a big meeting on Sunday could you just set me a reminder I don’t know midday at 12:00 on Saturday Dubai time to do some preparation for my meeting with uh in the video. I want you to do some deep research between now and then. Find out who the members of the board are and then also go ahead and um find me five interesting things to talk about in that meeting. Whatever the thing is, I can send that off and I’m just explaining it. I’m yapping in English. By the way, when I’m not using Glider, which I’m using for my speech dictation, fastest in the world right now, I typically do my voice message when I’m talking to Hermes and I just yap and I talk because the speed at which you can get information out is four or five times faster, which is why I speech type. It’s like honestly the biggest productivity hack I’ve had and something I use with Hermes all the time. Now Hermes is setting a reminder to remind me of something. I mean, this sends me a daily brief every single day. It’s freaking incredible. And then it’s always going to do some research and come back and make that reality. Look at this right now. Set a wonderful reminder research for June 6, you know, midday. It’s like an executive assistant, but it never forgets and and it’s like the most intelligent thing in the world. You’re only really limited by how you’re physically applying her to your situation. And what level six is going to give you is something really powerful. And it’s this idea I mentioned of asynchronosity that it ships without you. It does things without you and your relationship goes from being I say you respond to something completely asynchronous and it does that. So things get built even when you’re not thinking about them. That’s like the huge unlock for level six with Hermes. And that then takes us to the doorstep of the most powerful level of Hermes agent and that is the agentic power user. And the idea behind the agentic power us is we have one operating system for every AI. What do I physically mean when I say that? Well, I best showing you. So this for example is the agentic operating system that I use. Now here obviously we’ve got a full overview of all the brands that we’re connected to, all the different integrations that we have. We can talk to Hermes. I’ve been over the incredible functionalities. This has this ability to create midterm goals for your business. And it breaks down in steps and give you like eight different steps of what Hermes is going to do, what you’re going to do, and vice versa. The pan tend to look at our different skills. And this is where it gets really interesting, right? After we’ve got the memory, we’ve got the Obsidian integration, we’ve got all our documents, which is crazy. If I want to look at, for example, something Hermes made for me, I can look at this. There is nothing else to do this right now. Like, you’re going to build PDFs, you’re going to build documents, you’re going to build softwares, but they just live in the chat or they’re just filed somewhere. The ability to actually physically see in a dashboard all the stuff that Hermes does for you is incredible. Like let’s say that you want to write an invoice to the UFC for your UFC debut. You want to do a headcake or something like that. Well, okay, it’s great that it’s in the chat and it can send things, but wouldn’t be I want to come back and look at it and do various different things. I can do that. But the real unlock is connecting your world together. Remember, context engineering is one of the biggest trends that you’re going to see. It is exploding. And the idea here for me to see my spend across every model, claude code, codeex, anti-gravity to have the ability to have basically Hermes agent dream for me. What do I mean by that? I mean it’s going to look at every message that I’ve said to it. It’s going to look at all the stuff that I’ve done not only in Hermes but in Claude code, in anti-gravity, in codeex, in anything else that I’m touching. And we use all of that data, all the skills to proactively think about are there ways that I can improve this? like what does Jack what is Jack not doing that he should be doing what are the skills that he’s not using that he should be using to do research and feed that back to you and crucially the ability and I got here in the memory section right now to see everything from my Obsidian memory that connects everything together and literally even the code memory and the Hermes memory the Agentic operating system users are individuals that don’t operate in silos they have their entire AI connectivity in one location and it basically means that I do coding on claude code. Cool. I do coding in Hermes. They’re no longer separate. That gap is completely bridged and unlocks capabilities that people don’t even realize actually exist. And at this level, not only is it running without you, it reports and does work for you whilst you are actually physically sleeping. So, three truths you really need to understand. It’s not a better coder than Claude code. It is literally using claude code. That’s really important to understand. The number here is that you can’t really have over a thousand agents running simultaneously. The agreed number of agents that we think can be done does vary based on different models, but realistically it’s not going to be a thousand. And the magic itself isn’t something you need to wait 17 years to do. This is something you can build and learn in a couple of videos if you just apply yourself. Now, understanding where you’re at in those seven levels and where they fall apart, the next thing we need to do is embrace the most powerful level. And that’s learning exactly how to utilize this agentic operating system, which we’re going to do together in this video. Right.

  • Claude Sonnet 5 just dropped. I’m changing how I use AI…

    It happens. Claude Sonnet 5 has released and it is by far the best bang for your buck in AI right now. It has almost the performance of Opus 48 but for a fraction of the price. In this video, we’ll go through every single change with Sonnet 5, but more importantly tell you how you should be using it now, should you be using it in Hermes, should you be using Open Claw, should you be using it in Claude Code, and where you shouldn’t even be touching it at all. I’ll also give you a few tips on how you can get the absolute most out of this model immediately. And then on top of that, we’ll go into what this potentially means for Claude Fable 5. Now, let’s lock in and get into it. So, this is a big one. It is a full number upgrade. This isn’t a 4849. No, it is Sonnet 5, a full number upgrade. And it comes with a lot of big changes. First of all, let’s talk performance. One, it blows Opus 46 out of the water. I don’t know if you remember, it was like a month and a half ago. Opus 46 comes out and it was really good. This lightweight, cheaper, quicker model destroys it. That is massive. And that is big because Claude has been number one when it comes to Agentic models forever. When it comes to OpenClaw and Hermes, nothing comes close. And a lot of people have been upset because you got to pay API pricing for clawed models inside Hermes. Well, now you don’t need to pay as much cuz you can use Sonnet 5. It is almost as good as Opus 48. And I’ll show you some of the numbers in a second here, so stick around for that. But it’s almost as good as Opus 48, which Opus 48 I believe is the smartest model on planet Earth right now if you don’t count Fable 5. More on that later. Here’s a big one. Fraction the price. Everyone in their mothers has been crying that AI has gotten too expensive lately. Everyone’s been crying again about paying API prices for Claude with Hermes. With Open Claw, fraction of the price, you’re saving a ton. If you’re anything like me, your usage with Hermes is out of control when you use Claude. I’ve spent $1,300 in the last month on Claude tokens inside Hermes. So, yeah, this is a big welcome upgrade. It is significantly faster. That is a big sticking point with Opus as well. It can get pretty slow at times. And the big upgrades come to reasoning, tool use, coding, and knowledge work. Basically, the four horsemen of agentic work. I really think this is the model Anthropic puts out to really nail open claw and Hermes use cases. This isn’t your clawed code, a gentic loop, infinite autonomy model. This is your you’re working with Hermes. You’re working with OpenClaw. You’re doing basic coding tasks and it is your agent that is partnering with you. So, let’s talk about the numbers real quick. Absolutely destroys Sonnet 46 on basically every single measurable benchmark there is when it comes to Opus 48. Doesn’t beat it in any specific benchmark, but it comes really, really close. A little bit better on knowledge work, but computer use, everything else, it is very, very close. But again, that is amazing because you’re not paying nearly as much for Sonnet 5 as you are for Opus. That’s why you’re now plugging this into everything you do. Now, let’s look at cost versus performance. If you take a look here, for similar task, you’re paying out $8 for Opus 48 on medium. Similar task, you are paying about half that price for Sonnet 5 and only getting a small 5% downgrade on the pass rate. So, you’re paying about half the price for roughly a little bit worse performance than Opus 48. That’s pretty good, especially if you’re using any sort of agents. So, let’s do this. First, we’re going to do a quick performance test of Sonnet to see how it fares against Chad GBT55 and then we’ll go into how to use it best. I’ll show you some best practices with using it for Claude code as well as Hermes. So, I am in Claude Code Desktop. I believe this is the best way to be using Claude. A lot of people use the CLI. I like the desktop. You can monitor all your sessions really well. The user experience is really nice. You can plug in anything you want. I use linear and a whole bunch of other plugins. So, I’m using Claw Desktop. I recommend you use the same thing. If you go to the bottom right, you’ll see it right there. Sonnet 5, Miss You Fable 5. Sonnet 5. Boom. I’m going to put in a prompt I will also be giving to Chad GBT55 so we can run this test cuz I think those are two comparable models. This with Chad GBT55. This is going to build a really nice 3D boat simulator. I’m going to put the prompt down below if you want to copy it and run it yourself as well. I’m going to hit enter on that. I am also going to be putting this in codecs and giving this to just Chad GBT55 medium. I’m going to hit send on that at the same time, but we’re going to see what performs better, Chad GBT55 or Sonnet. Then I’m going to give you all those master tips on how to be getting the most out of Sonnet. All right, let’s do this. Let’s start with Chad GBT55. This was Chad GBT55’s 3D ship simulator. In the prompt, if you take a look at it, it says allow to configure the rain, the wind, the waves. Uh, a little disappointing. One, I can’t move the camera at all. Two, the ship is not moving. Three, the water is not moving. Uh, the rain actually is quite impressive to be quite honest with you. That is a lot of rain. Let’s see. We go wave height. Nothing happens. Rain density. That is a lot of rain. Uh, the weather’s nice. Everything else night, not so much. Let’s take a look at what Sonnet 5 did here. I like it better. The waves are moving. The ship is moving. Is there any rain going on at the moment? Know, you can kind of see thunder there, but I like the way the ship and the waves look a lot more. Let’s bump up the wind. Yeah, it makes the waves Oh, yeah, the wave. Oh, the waves are crashing into that ship. Wow, the ship is going nuts. I would not want to be on that ship. This is rather impressive. It looks like it is better than 55 to be quite honest you based on this test. So, one thing to note here as well from a pricing perspective, even though I like these results better from Sonnet 5 than from Chad GPT, and the UI is still way better with Claude Sonnet than Chad GBT, I don’t know why Chad GBT can’t figure out the UI side. I will say this, the pricing is still significantly better with Chad GBT in almost every single aspect. So if price is important to you, if you’re paying for API usage for your pure coding efforts like this, I still probably lean chat. So we’re back in Claude Code Desktop here. Again, what I believe is the best way to use Claude and Claude Code. Here is how you want to use Sonnet. You want to use Sonnet for all your basic coding tasks and you want to use Opus 48 in the ultra mode for a lot of your planning and really complex tasks. So for instance, I’m starting out this new project. It is a productivity app. What I’m going to do is I’m going to go into plan mode. And what I’ll also do is go into Opus 48 and go into Ultra Code. Now, this is probably only safe for you if you’re in the 20x max. If you’re anything lower, you probably just want to go into max mode here. But if you have the 20X, you go into ultra code. This is where you’re going to do the planning of the entire app. So if you’re building an application, you’re planning some monster functionality out, some monster app out, you go into plan mode, you go into Ultra Code. The reason why I like Ultra Code is it can spin up workflows at any time. For those who don’t know, workflows is basically Claude’s sub agent functionality where it spins up potentially thousands of sub aents to do work for you. So I like the Ultra Code mode. So I have a prompt to build this productivity. I have basically a notion clone. I’m going to hit enter on that. In plan mode, in ultra code, it is going to use tons of compute to make sure this is planned out. Well, this is the key here. When you’re doing actual execution, you don’t need a ton of compute. If the plan mode was done with a lot of compute, right? So, if you have a really nice detailed plan, you don’t need the smartest model in the world to do the execution. So, we still use Opus 48 for the planning, but what we’re going to do in a second is use Sonnet 5 for the execution of that detailed plan. So, we’re going through the plan mode. It’s asking a ton of great questions around, do I want it to be multiplayer? What kind of writing support does it have? Is it a writing system? Yep. We’re going to give it Notion AI functionality. This is a great strategy. If you pay for any apps, just rebuild it in cloud code, right? You’ll save tons of money. We’re going to do MVP first. So, it’s going in. It’s building the plan. And here is what I love. It is starting a workflow to design the architecture. So what you’ll see here is actually spin up tons of sub aents to design the architecture. This doesn’t happen with sonnet, right? So this is why you want to be doing this opus so you get the maximum compute in the important part which is the planning. Look at this. Five agents working, tons of tokens, tons of tool use. This is awesome. All right. Looks like it built out the entire plan. Put it in a markdown file which is sick. I’m going to go into Sonnet 5. And because we have such a good plan built out, we can go in do Sonnet 5 on medium. So, this can be dirt cheap. And we can say, “Okay, now execute on the plan.” And Son of 5 will get to work. If we were doing Opus 48 with this, this would cost us way more money. This would be very expensive to do. But now that Sonnet 5 is past opus 46, almost 48, we can run on Sonnet. will get the same quality project done for way less. This is great if you’re on one of the cheaper plan models. As for Hermes Agent Open Claw, if you are watching this video shortly after I put it out, Sonnet 5 probably won’t be in your directory of new models. But what you can do is go to your agent if you’re already using the Claude API. Just say, “Hey, switch the Claw API to this set five string. Look it up online.” and it can switch in the back end for you and you’ll be good to go. You’ll be on the new Sonnet 5 model. I recommend using Sonnet 5 now in your Hermes and Open Claw. Claude again makes the best models when it comes to agents. It really isn’t close. Chad GBT 5.5 is usable. Claude is the goat though. The issue again very expensive. Sonnet 5 brings those cost down. I’d recommend using Sonnet 5 through the API. As for Fable 5, it looks like it is going to return soon. A bunch of strings have been found in the clawed code around Fable 5, including looking like it is going to require API usage, as well as looking like it is going to require verification. So, you’re actually going to need to identity verify to make sure you’re in the United States of America. If you’re outside the US, I’m so sorry. If you’re inside the US, prepare to give up your identity in order to use it, which is fine. I guess it is what it is. I just want the model back. I personally will be giving the identification so I can use the model. I don’t do anything crazy or illegal with AI, so I really have nothing to fear. But good news, looks like Fable 5 is coming back very, very soon. The bad news is uh you’re going to have to pay API pricing and you’re going to have to give up your identity in order to use it. It is what it is. That is Sonnet 5. It is not replacing Opus 48 for me. It’s only replacing Opus 48 for cheap and quick and easy tasks in times in which I’m looking to save money like with using OpenClaw and Hermes because I am spending thousands a month on those. This should bring down my bills by a little bit while getting me comparable performance to Opus 46. So, it is not a full replacement for Opus. It is a replacement in very strategic areas. If you learned anything at all, leave a like down below, subscribe, turn notifications. All I do is make amazing videos about AI. doing full live boot camp on sonnet 5 this week in the vibe coding academy link for that is down below is a number one community in AI on the entire internet make sure to join you will learn a ton it’ll be the best time of your life sign up for that hope this was helpful see you in the next Here.

  • ChatGPT 5.6 has been announced. I’m done…

    Chad GPT 5.6 just got announced and it is legitimately the worst news of the entire year. Let me explain. And no, it’s not because it was named after three failed cryptocurrencies. No, that’s not it at all. Few things to note here is one, it is better than Mythos. So looking at the benchmarks, it beats Mythos on Terminal Bench. On top of that, it’s also onethird of the price of Mythos. So it’s better than the best AI model you’ve ever used in your life. It is a third of the price. But here’s where it absolutely blows. It’s not available to you. You can’t use it. It is only available to 20 companies in the world that OpenAI and the US government has hand selected to win. That’s right. Much like Fable 5, you cannot use the best technology out there anymore. The people that determine who can use the most powerful technology ever created are the CEOs and the government. That’s it. There’s a small group of winners and you ain’t one of them. So, yes, there will be three versions of chat GBT 5.6 Soul, which is the big mama jama, the fable five version. Terra, which is like their downthe middle 55 thinking version, which apparently beats 55 for a fraction of the price. And there’s Luna, which is their smaller model, which comparably is their smaller model, but it’s not nearly as small as like their micro or mini model. So, I guess the micro models are getting bigger now. Those are the three versions. They’re all great and we won’t be using it anytime soon. In a second, I’m going to tell you what you need to do about this, what your next steps are to take advantage of this moment. But let’s talk about why this is absolutely horrible news for America and absolutely horrible news for the world. America for the first time is decelerating their innovation, decelerating their technology. Unlike many countries out there, there weren’t many rules or regulations. You can build new technology, put it out there, make money off it, and innovate quickly. This allowed us to be the number one country in the world when it came to AI models. We had the best AI models on planet Earth. Now, for the first time, we’re being decelerated. You have to review the models with the government. And if the government decides it’s not safe in your hands, you don’t get to use it. Now, this isn’t a political channel. I’m not getting into politics, but I think taking politics out of it, you can objectively say this is not good. When governments and executives can decide who winners are, who can use the great technology, who can use the crap technology, that is not good for anyone. Winners shouldn’t be handpicked. It should be a meritocracy. Everyone should have equal access in opportunity, and the ones that use it the best are the winners, and they earn their right to win. That’s no longer the case. I have been talking about the permanent underclass for a long time now. This has pissed off many many people. But this is what the permanent underclass is. When certain people get access to certain resources and this is the most valuable resource ever created, frontier intelligence cuz when you use this you can build and do anything you want. Those people end up being winners and everyone else ends up being losers. If you are building a business and only you have access to the best intelligence and everyone else has no access, you’re going to dominate them. They will have zero shot. It’s like getting into a boxing ring where one boxer has bricks tied on their hands and the other has the hands tied behind their back. The one with the bricks is going to dominate. Up until this point, this was all democratized. Anyone can use this amazing technology. Now it’s not democratized. Now it’s handpicked winners. So, it’s not about who’s the best, who’s working the hardest, who has the most skills. No, it’s not about who’s contributing the most to society. It’s about who’s the best friends with the executives in the government. That absolutely sucks. I was hoping with Fable 5 being taken away, maybe Chad GBT can somehow snake their way to being the good guys and be able to release our Miles. And listen, I get it. This isn’t up to them. This isn’t up to Open AI. It wasn’t their choice to hold this back. After seeing what happened with Anthropic, I’m sure they was like, “No, we don’t we don’t want any part of that. We don’t want to do that. We’ll just hold it back and be safe.” But this absolutely sucks. We are all losers. Open AAI did say this will be available broadly in the coming week. So, I am hoping by the end of July, we’re able to get access to this. And if you look at the Poly Market, it’s looking like by July 17th, we will get Fable 5 back. That is very good news. Apparently, people with a lot of money I’ll get this crap off my screen. people with a lot of money are betting on by end of July getting people back. So, it looks like July is the month we get our hands on the Frontier technology. The challenge is there’s going to be a lot of people, a lot of businesses who are hand selected who will be using this until then and will have a distinct advantage on us. What does that mean for you? What should you be doing? Well, let’s go to this slide over here and I’m going to go into more detail. So, stick around for us. By the way, if you learn anything so far, leave a like down below, subscribe, turn notifications. All I do is create amazing content about AI and keep you up to date with what’s going on. Uh, number one, I still think 55 is the best right now. I think 55 is the best model. I believe that because I think Codeex is the best agent harness. I actually think Opus might be a better model, but Codeex is so good at controlling your computer, doing computer use, browser use, all that. I believe it makes 55 better. So 55 is the model I’d be using right now. Here’s where things switch up a little bit. I’d research local AI. What do I mean by that? I just went out to MicroEnter. Hey, MicroEnter, sponsor me. I went there. I built this computer. You see here it’s sitting down there. I’m going be playing Cyberpunk on it tonight. It is an RTX5090 build. It’s got 64 gigs of RAM. It would have cost me like $2,000 more dollars to make it 128 gigs of RAM. Anyway, I built this computer. I am building a home lab. If you’ve watch this channel, if you follow my Twitter, you know I’ve already been building a home lab. I have three Mac Studio 512 GB, two Mac minis, and a DGX Spark. Now, I have this RTX5090. I am building my own home lab so I can run the most powerful models on planet earth. I want to invest in local models. I want to invest in a home AI lab where governments and executives cannot take away my AI. Where I can build my own sovereign intelligence, build my own systems and no one can control it. No one can gateep it. Nothing like that. I believe everyone should be investigating local AI right now. Do I believe you should go out and spend $10,000 on a computer right this moment? No, I do not believe that. I think that is a mistake. I think what you need to do first is research it. Figure out what’s suitable for you, what models are suitable for you, what hardware is suitable for you. Most importantly, what you would do with that AI, which use cases you would do. I’m going to go into all that in a second of how to figure that out. Before you spend the tens of thousands of dollars, first figure out what you’re going to do with it. So when you set it up, you can just start getting cooking. I’m going to show you what I’m doing in a second. Actually, let’s just get straight into it. This is my local AI home lab platform I am building at the moment. This allows me to monitor all my devices. It also allows me to see which models I have up and running. And these models are going 24/7, 365. They’re doing security scans. They’re checking code. They are writing code at all times. They are constantly doing things around the clock for me, pushing my business forward, pushing Henry intelligent machines forward. And I am building on top of this home lab so I can do more and more things. I plan on training models, training lores, many different cool things like that. You want more information on that, let me know down below. Would you want me to like walk through how I’m building this home AI lab, the hardware I’m using, what I’m doing with it? Let me know down below in the comments. So, if you’re curious what you should be doing when it comes to local AI models, should I be doing Mac Studios, Mac Mini? Should I be buying a DJX Spark? I will spend a couple minutes here. So, lock in for this. You basically have three options. You have high-end Macs. You have AI computers like DGX Sparks and the new AMD computer coming out, as well as powerhouse chips like the 5090 I just built, like the 6000 Pro. I’ll just be adding on to it soon enough. What’s the difference in each? Which one should you go for? Well, couple things here. The advantage to Max are high unified memory. That means you get ton of memory to load models into. So, you can run the biggest models. I’m running GLM52 on one of my Mac Studios right now. It’s 250 gigs in my memory and I can only do that on my Mac because Nvidia chips don’t have that much VRAM. So, Mac Studios great for massive big models. It’s just low memory bandwidth which means it’s very slow. AI computers like DGX Sparks, which are very popular right now cuz they’re plug-andplay. You go to the store, you buy, you plug it in, you’re good to go. Those have medium unified memory, 128 gig, so you can load mediumsized models, like really good Quen 36 models, and they also have medium bandwidth, so they’re much faster than the Mac Studio. Not lightning fast, but faster. Then you have the Powerhouse chips, the 5090s, the 6000 Pros. These are lower VRAM. The 5090 can only store 32 gigs, so kind of the smaller Quen models. The 6000 is much bigger. It’s like a $12,000 chip. But their advantage is they have very high bandwidth. So you can run models lightning fast on them. I bought a computer in each class so I can take advantage of all the strengths and weaknesses. So it’s up to you. If you’re getting into local models, think about which one you want. Think about what suits your use cases. If you’re not sure what suits your use cases, go to chatjbt.com, go to claude.com. Go back and forth with your agent. Go to your Hermes agent. Say, “Hey, based on what you know about me, what would you do? What use cases can we do? What hardware should we get? What should we do with these local models? Which one should we load? Your agent should be able to help you out cuz it has a ton of context around you. So, make sure to be reverse prompting as much as you can before you go out and spend tens of thousands of dollars on computers. This is the news of the moment. It quite honestly pisses me off, but I think brighter days ahead. I hate that this is the new normal. I hate that this is the world we live in at the moment where you no longer have access to frontier intelligence. You need to get permission first. I’m sure this will only continue and as hardware prices get more and more expensive, it’s going to be harder to become sovereign and run things on your own. So, all options are starting to become more constricted unfortunately. This is what’s going on. More videos coming in the next couple days on Hermes use cases, claude code best practices, things like that. So, make sure to lock it in, leave a like, subscribe, turn notifications, hit all the buttons you see on your screen. So grateful you’d watch. Hope this was helpful. See you in the next video.

  • AI Agents run my business and life – Andrew Wilkinson

    Today’s episode is an inside look to how Andrew Wilkinson is using AI agents to run his personal and business life. This is a guy who has a great setup. He shows us exactly how he’s using things like OpenClaw and AI agents to be more productive and to make more money. How he uses it with his family office. How he’s using it to start a startup. How he’s using it to think about where the next generation business is and where he should be putting his money. This is an inside look, and I don’t think he shared this anywhere with how he’s using AI agents to run his life and his businesses. By the end of this episode, you’re going to have your creative juices flowing. I certainly did, and I can’t wait to see you in there.

    Andrew Wilkinson, I think third time on the pod. Welcome back. Good to have you, Andrew. By the end of this episode, what are people going to learn? Oh man. Um, they’re going to learn that Open Claw is uh hard, um, but amazing when it works. Um, they’re going to learn, uh, whether they have ADHD or OCD. Uh, they’re going to learn how to build a crazy vector database about their complex company. Um, and they’re going to learn a few prompt tricks, uh, and whatever random other stuff we end up stumbling into. Okay. So, for those of you who don’t know, Andrew is a very curious guy and he gets deep into rabbit holes. So, it sounds like what we’re going to learn is a lot about how you’re using AI in your day-to-day, the the good, the bad, the ugly, uh, and everything in between. Yeah, let’s do it. All right, let’s get into it. I would say I had this crazy moment like so many other people in December of last year where I played with cloud code and all the AI tools like Replet and stuff and they could kind of do stuff. It was interesting but it wasn’t uh it wasn’t there yet. And in December of 2025 I just literally like I I feel like I started shooting heroin. Um, I started waking up at 3:00 or 4 in the morning, rolling out of bed with a big smile on my face and literally just sitting in terminal in cloud code with 10 tabs open. Uh, and I’ve been doing that ever since. And my goal, um, you know, I’ve had a bunch of different things I’ve been trying to do uh, on the productivity side. Like I was basically trying to build an OpenClaw agent uh, before OpenClaw came out and doing a very poor job of it. So, I was excited um when I was able to do that. But I mostly have been excited as a business person. Um for those of you the listeners that don’t know, I basically buy and start businesses. I mostly start businesses as a hobby for for fun. Um but I buy a lot of businesses and I’m always astounded by the amount of administrative burden in uh you know a SAS company. If you think about how it scales um you know support accounting there’s all these like very boring wrote um types of tasks that are now able to be automated and so as a test before I started doing this in our operating businesses I basically built a business um a SAS business and then I’ve been running it entirely autonomously using OpenClaw um so that’s probably a cool place to start and I just want to say like with OpenClaw. Um I basically have been we we referenced heroin a moment ago. Um you know I have never done heroin just in case anyone’s concerned about me. But um apparently when you do heroin the first time is the best time and they call it chasing the dragon. You’re trying to get back to that special moment. And I had this special moment. I was traveling. I went to Arizona on a trip and I forgot to bring my laptop. Um, but I’d set up an OpenClaw agent on my computer and I basically was able to run my entire business using OpenClaw in the back of Ubers. Like I was going to this conference. It was super super busy and I was astounded by how competent it was able to be. Um, and that nobody picked up on the fact that, you know, every single email that I wrote was being written by OpenClaw. And so I’ve been chasing that moment ever since. Uh, and the problem is that I feel like I’m spending 50% of my time debugging it and 50% of my time maybe 30% of my time making it better and then 20% of my time being productive. So, it’s like the classic productivity treadmill. Um, but we have been able to build some pretty interesting stuff. Um, so let me let me screen share with you and I will show you this app that I built. Um, so this all started because I uh I wanted to build a custom GPT uh or chat GBT project for me and my girlfriend’s relationship, the idea would be that we would be able to query it. Hey, we’re having a fight about XYZ um which we do. And I asked it, I said, um, hey, if I was to do a bunch of psychological tests, which ones would you want to see? And it gave me this list of like 15 different screens that it wanted me to do. And so I went to Cloud Code and I said, “Hey, can you just put all these into a multiple choice test, set up scoring, and then put them in a JSON file.” And so both of us did that. It took about 40 minutes. And we put the JSON files into Chat GBT. And we said without knowing anything about this this couple, um, tell us about their relationship. And we read it line by line and like our jaws just like dropped. Like it nailed every single fight that we have, every single issue at home. Um, and so I I saw the power of these multiple choice personality tests. And so I, you know, saw the product opportunity and I was like, I’m going to build a business out of this. And so I started this thing called deep personality. Let me just share my screen here. Quick break in the pod to let you know about a free workshop I’m doing that answers some of your biggest questions. The first is in the AI age. What are some categories that are ripe for startup ideas? I’m going to outline a bunch of those different categories, the ones that I think the most opportunity is. Second is there’s a million AI tools out there. Which are the ones that matter when I’m trying to build a business? I’ll walk you through that. And lastly, how do you actually build a business with some of these AI tools? So, I’m actually going to show you live how I do this with my ideabrowser.com team. And I can’t wait to see you there. It’s this Thursday at 12:00 p.m. Eastern. And if you go to the show notes, if you go to the description, you can click a link, RSVP, and learn a few things. I hope it’ll get your creative juices flowing and I’ll see you back at the pod. And you know, you could have, you know, you you you own an agency called Metalab. You could have called out Metal Lab to go and build this for you, but you decided I’m going to do this all myself. I’m going to actually productize this myself. I’m going to design it myself. I’m going to build it myself. Why did you make that decision? Well, I think um I love people. Like I’m very extroverted, but the worst part about business is people. Um you know, if you think about using a let’s use a screenwriting analogy. So in Hollywood, there’s all these brilliant screenwriters and they write these incredible scripts and so they have this idea and they know where they want it to go, right? So let’s say they start here and they want it to go here. They want to make an incredible feature film. In between all in between the script and the feature film are 100 people that they have to convince, $50 million they have to raise, uh a million middlemen and all that. And I think that creativity is just um compromised based on how the number of people between your vision uh and execution. And so um I think like writing for me has been a very like pure pursuit where I can think about it and I can write it and I can work with AI to make it better if I need to. Um but it feels it feels like so such a clear um execution of your vision and I feel like vibe coding is that um like finally I can do absolutely every part of it and I can do it at my own pace. You know if I was using employees um they’re unreliable. They don’t see my vision. They don’t understand every aspect of um design. So you can have a great designer who sucks at front end or you can have um or doesn’t know how to design something that’ll work in a front end. You can have a great designer who doesn’t know how to write copy. So there’s just all these pieces that come together with vibe coding. And basically like in a few manic days I was able to build this pretty crazy app. So let me let me show you um how it works. So basically you do a personality test and it takes about 40 minutes. you’re just clicking multiple choice answers and stuff and then you get this report and so here’s my archetypes. It’ll be like you’re the blazing architect. Um here’s your superpowers. Here’s your kryptonite. Uh this is just like the basic and then um as you scroll you can see the AI has taken all of your answers and it’s written like a 100page report. So this report literally goes on and on and on and on and it’s written like Robert Green. So, it’s like super impactful and deep and hits you. Um, and it basically walks you through what you’re great at and what you’re terrible at, what job you should have. Um, is your relationship working for you? Do you have ADHD, OCD, are you on the spectrum? Like all these different things. And so you can see, let me get Oh my god, it’s so big. All the way to the bottom. Um, so you can see like these are my kind of personality traits, my attachment style, um, my internal family systems, like how much I people please, all this stuff. So I built this thing and usually what happens for me is I start something and then I don’t want to finish it because I don’t want to hire the people and deal with it. And so what I ended up doing is in this case um just building agents to do everything. And so I can show you we’re we were using OpenCloud. We’re currently using this thing called Harbor that a friend of mine built. Um and it’s basically a harness for agents. So you can see all the different agents that are running here. So we have a dev, we have marketing agents, and then we have a support agent. And basically the way it works is um somebody emails support and uh either support just tackles the ticket uh or it will actually fix the ticket. So it’ll send it to the dev agent. If it’s a P 0, so like a super scary security breach, it’ll just immediately fix it and merge the PR. Otherwise, it’ll uh we just wake up and have a bunch of PRs. Um and then it’ll email the person back and be like, “Hey, I fixed your issue.” Or whatever it is. that works basically perfectly. Like it’s shocking like support to me is not a job very very soon. Um the one that’s really exciting is the marketing agent. So we basically have it uh it’s hooked into Post Hog. So it has all the data for the app and it actually manages a meta and Reddit ads account. And so it’ll um do multivaried testing. It’ll create ad creative. It will set budgets. and we basically just message it and we’ll say um you know, hey, can you increase the budget by $1,000 or we approve like a big SEO project or something like that. So, where we’re at with it is like we’ve done maybe like $20,000 of revenue. Like, it’s still small. And where I’m really excited um to go next is like what happens when we give it like a $100,000 a month ad budget and we find ads and creative that actually work. Um so that’s been that’s been insane. Um and I think that we’re probably 3 to 6 months out from being able to just hand businesses off to AI to run at least basic businesses like this. Harbor I’ve never heard of and I see I see a lot of stuff. Let me um let me just ask so it’s my friend Gavin made it. Yeah. You link me to the Harbor website. Um yeah, it’s Harbor. It reminds me a little bit of paperclip. Have you seen Paperclip? Yeah, I have. So this is it. It’s GitHub/Geek forbrains/harbor. Um, and uh, he’s he’s a friend of mine that I’ve been working on this with, and uh, it’s it’s working really well. We just found that OpenClaw wasn’t quite deterministic enough. And the other issue with OpenClaw is because it’s a textbased interface, it was a little bit hard to keep track of all the agents and what’s actually happening. Um, so it’s worked really well for us. Yeah. I mean, I think what’s cool about it is like if you’re starting a company and you’re thinking about org charts, roles, responsibilities, you know, you don’t think about it within within text, you know, back and forth, right? You think about it as like, okay, I’m going to spin up this agent or employee to do XYZ and then how can I monitor what that XYZ employee is doing? Yeah. Like so basically like it’s just a this is just a guey basically for something like open cloud and it’s still running on cloud um but you know you have all these documents with uh kind of like a knowledge base you’ve got databases you have all your environmental variables etc. It’s like it’s very similar to paperclip. Um I think the problem it reminds me a little bit of crypto where crypto is not crypto is built by nerds so they make it nerdy. And when I saw paperclip, I got so excited because I was like, “Oh my god, I can this makes sense to me visually. You like have this org chart, but it’s clearly built by nerds because it’s very confusing.” And so my I mean my kind of belief is like pretty soon Anthropic and uh OpenAI are going to launch like basically like CEOs. So you just be like, I’m just going to hire a CEO for my company. Give me your data. I’ll figure it out. I’ll run it. I’ll run the whole business. And right now the problem I I feel like um you know 2 years ago it was like uh we’re you get you get 5 minutes with a super genius who has Alzheimer’s like the context window is so small that you just have these brief moments. Now I feel like with the the 1 million context window um they can like maybe remember a day but it’s like momento right. Um, and I feel like once the context window is like 5 million, 10 million, then we’ll be able to run entire companies with this. Yeah, there’s some people now selling autonomous companies. I don’t know if you’ve seen this. Pulsia is one of those companies. I think Pulsia P work like I I saw that New York Times story about that guy who like started the autonomous uh, you know, what is it like billion dollar business or whatever. But and obviously that’s real. the New York Times is writing about it, but I I can’t parse what’s real versus [  ] I think, you know, we’re recording this April 29th, 2026. You cannot run an fully autonomous company in right now that Yeah. that is going to get better that you can just like, you know, go hang out on the beach 24/7. That being said, I think there’s parts of the business that can be autonomous. Like support is like a good part, you know, area, but like you’re not going to outsource like product at this point in my opinion autonomously to to something like Pulsia today. You know, maybe that changes in 6 months, 12 months, whatever. But like my take is the people that are selling autonomous companies today are just selling a dream. Yeah, I kind of agree. Like I think um openclaw agents are still like zap. They’re basically like zap your zaps but that can make basic decisions and have intelligence but you still have to tell them step by step this is how I want you to think. This is how I want you to operate. Like let’s say you hired an intern and you gave them an email address. You would never have to say you should check your email every 15 minutes and you should reply. And when you do reply, you should, you know, think about the following things. Like it feels very, it’s like you’re dealing with a baby, a a genius baby, but you have to teach them how to do every single thing. Where I’m excited is when I can just have a model that’s just like a CEO model or or and just like delegate to them and they’ll just figure it out, which I think is kind of what everyone acted like OpenClaw was, but it’s totally not. Yeah. I want to go back to go to the deep personality test. Can I give you unprompted feedback? For sure. So when you were going through this, I was like like the content looked exceptional. my my you know my issue in general with like vibecoded projects is that because anyone could you know create apps and products like this it’s almost like you need to have some credibility layer in order to listen to the content you know what I mean so like um my you know if I was like the you know PM or CEO on this I would be like how can I partner with, you know, someone who’s credible in the space such that when I get this, you know, output, this report, I’m going to take this seriously. I think part of the problem is it’s anyone who is a psychologist or um someone who would be like legit on this would never do it because it’s a bit cheeky. like I’m using um psychological screens that are supposed to be interpreted by a psychologist, but I’m not a psychologist. I’m using AI to do it. And I think it’s incredibly accurate. Like I’ve I’ve hammered it on a million different models and I’ve looked at um example tests and stuff, but that is definitely an issue. If there’s someone listening who’s connected to like a J Shetty type person, definitely let me know because I think it’s perfect for that. Um, it really is one of those like 1 plus 1 equals 5 kind of things. But yeah, right now it’s what I realized is like I can when I post this in my newsletter, it goes crazy viral um for a bit, but I don’t have enough pull in that space where my audience is a bunch of like tech bros. They’re not going to, you know, they’re not going to share this with all their friends and stuff. It does definitely need something like that. Yeah. And I I I also wonder like you know I think about like who like what are influencers, celebrities, micro celebrities that people look up to like a couple like even just a couple that like has gone through this publicly maybe and have come out of the other side and they’re just happier and when people think of like you know a couple that’s you know a dream couple like this is their you know they’re involved in this in some capacity. That’s smart. So, you and your wife, you want to do it? Should we do it? Yeah. Yeah. I mean, my wife is like very like uh private, you know? So, I’m more of the public one. Uh but I’ll see what I can do. Same as my girlfriend. She hates hates publicity and stuff. Um let’s see what else can I show you. Um I mean, another big piece is just data. So I, you know, I feel really frustrated because at different times I’ve kind of standardized on different LLMs. Like I’ll get into the cloud ecosystem and I’ll use the desktop app. I’ll use Jazz GBT and I’ll build out a bunch of projects. I’ve basically just accepted that I’m going to live in cloud code until somebody builds her. Um, which I’m sure is coming in the next couple years. Um, and so my strategy has basically been um to take all the different data pipelines that I have and put them into a centralized place. And so I have um Fireflies record all my meetings. Um, every night a cron goes in to the API, builds an M markdown file, puts it into Gbrain. Um, I’ve built out vector databases um for my businesses. This is a really cool um thing. So, you know, a vector database can store um you know, millions and millions and millions of tokens and you can basically um you can basically have like a service like pine cone go and crunch through a large amount of data and it basically makes it highly searchable for an LLM. And so I can show you an example of that. Let me just switch the screen sharing. So, okay. So, here’s an example. So like I did um I trained a vector database on my family office Folly Partners which is basically just my like personal holding company. And here I just asked it uh what did I say? Um break down how many minority venture investments I’ve made and how many are in the money bankrupt or declined. And basically it went off and did this query and then boom I can see that I’ve made 132 direct investments. I invested 16 million, it’s now worth 36 million. And then it can break down all the different write offs, everything. And so this has been um really really powerful. So like if you think about I did it for tiny as well. And in tiny I have uh man 24 businesses or something like that, tons of historical data. And the challenge when you run a conglomerate is like I don’t know it like are any of the companies spending too much money? Are any of the CEOs full of [  ] Um are any of the businesses trending up down? Expenses are going up. It’s just too much data for one person to understand. And so I can’t show it because it’s all public company data. But basically what I can do in tiny now is I can say hey review the last quarter and I want you to give me any icebergs or issues. or I can ask a simple question like how many accounting staff do we have in head office um or whatever. And I’ve found this so useful. It’s not perfect like it’ll it’ll often like say the wrong person is CEO of a business or the numbers are a bit off but in terms of being able to like be the eye of Sauron inside your company, I think it’s like incredibly powerful. Mhm. and and curious like within Tiny like I see how you’re using it to interface with Tiny and and to you know be a better chairperson and give advice but within Tiny I imagine that there’s like some efforts to make the company’s AI first and stuff like that right yeah and that’s one of those challenges that I think everyone can relate to where what is the saying it’s um never expan expect someone to understand something that their paycheck depends on them not understanding. So you have a lot of people that are living in the old world and need to be upgraded um in their understanding and often they’re very attached to the old way of doing things. And so to be honest like the challenge in tiny is that we are generally pretty handsoff and where we’re really leaning in is in a lot of the software businesses because those are the ones that are at the most risk. I think we’ve talked about this before, but it’s not like software is dead. If anything, software is going to thrive way more, but it used to be like the newspaper industry where it’s like in order to compete, you have to assemble this incredibly expensive group of people that’s very rare to find, right? You need like great programmers, great designers, etc. And that that was like a very finite resource. So, it’s kind of like the newspaper industry where you had to be rich, you had to buy like $2 million printing press and then once you have it, you actually have a competitive advantage. Now, I just think software is free. Anyone can make it. Anyone can rip it off. Like my personality app, it’s cool. Does it have a moat? Absolutely not. Like maybe if to your point, I had John Legend and Chrissy Tegan backing it or something. Maybe there would be something there. But um I think pricing pressure is just going to go crazy because it’s like the restaurant industry. Like you know restaurants are not a bad business. They’re bad because there’s too much competition. So if you’re listening to this and and you know someone’s listening to this, they’re watching this actually and they’re saying like okay I like what Andrew is doing here with like you know this Foley advisory thing. I like what he’s doing with personality test. I feel like he has a good sense to where the world’s going. you know where what what you know what would you be building now if you’re you know if you’re you want to be building something right I think we talked about this a year ago and if anything I’ve become more concerned um when I look around I’m don’t get me wrong I’m not not concerned I’d just say it’s getting harder and harder and harder like I think we’ve all been astounded seeing um how good Claude has gotten and how much it can do um and how quickly it can do it. And from my perspective, I think that if I was somebody who’s obsessed with vibe coding and is 20 and let I would say the goal should be like make1 to2 million by building a product like deep personality or something like that, which is pretty straightforward. Try and make a million or two million bucks. And this is such a sad answer, but I’d be like invested in data center stocks or invested in TSMC because to be honest, that’s what I’m doing. Like I am I’m either buying like something with a moat, which is very very hard to find certainly in technology right now. Uh home services businesses, like very very brickandmortar kind of stuff. Um but even that I think is at risk with robotics over the next 10, 20 years. Um but I honestly I all I can really recommend someone does is like buy Iron and TSMC. Yeah. I think uh with you know with respect to like the guey the graphical user interface like it just feels like we’re that you know I always I think about it as like the arrow of progress like the hour of progress or you know deep progress is that the UI is going away and like I don’t know about you but I’m spending more and more of my time in codecs I’m spending more and more my time in claude code like those have become my operating systems so I’m spending less and less time in apps and it’s easier than ever to create apps. Therefore, like yeah, it’s pricing pressure, competition, harder to get mind share. Well, I mean, it’s an interesting like um someone asked me like is Adobe [  ] and that’s an interesting one because like I’m a pretty avid user of Lightroom and I love I’ve got a Leica. I love editing photos and stuff and while I do put my photos into Gemini sometimes for like recoloring or retouching or something, I still really enjoy the process of like moving the sliders and making it exactly the way I want it. And so I think, you know, it’s a question of like does this being the standard matter or will someone just vibe code an even better Lightroom and everyone will switch to that because they’re, you know, a big slow incumbent and someone else will do it faster. I can’t answer that question very well. All I can say is software is a worse business now than it was 5 years ago. I mean, look at Constellation Software. Their stock has been cut in half. Like that that’s crazy. like I and I don’t know if that’s correct because they own like the most boring software businesses ever, but um yeah, dude, it’s like a brave new world and it’s so depress I I hate to give such a depressing answer cuz your show is all about entrepreneurship and like I just want to say like I’m more excited than ever. There’s never been a better time to be an entrepreneur and build stuff. It’s just you are picking up pennies in front of the steamroller in most industries. It’s also hard to predict what’s going to happen in 12 months from now cuz you know uh or 18 months from now or 24 24 months from now. So like my advice to people is just build now knowing that um you know you’re a big Buffett guy, right? So like you know what does he say? Uh you know there’s only so many puffs you get on the cigarette or whatever. What is it? Yeah, you can um get Well, he’s he’s more talking about cigar butts, right? cigar butt out of it for free. And I think that would be like a gourmet cigar from a cigar shop now cigar butts. Yeah. So my take my my you know glass half full take is you you can get some puffs out of it and and it might turn in like your personality test might be like oh a$1 to2 million a year business for 3 years or it might turn into like a media conglomerate somehow. I also built it I built it for, you know, I was pretty irresponsible cuz I’m like using fast mode and going all out with all the cost, but I could probably build it for 10 grand, 20 grand of tokens or whatever to get to where we got to. I probably spent like 80 or 100 honestly cuz I’ve been So, Dude, I’m I’m spending like our family office. Um, so basically like I have tiny and then I have my personal holding company. Um, and you know, family office, the just the rich person word for uh personal holding company. So, I I’m sorry for being a douche, but um but basically like we have been instead of scaling employees um we’ve literally just been scaling Claude and so I’m so lucky like my CFO and president have both become obsessed with cloud code, but they’re actually just um scaling the API cost. So instead of a payroll, we just have a $40,000 a month claude bill and it’s doing it’s doing everything. Like I’d love to show you some of the stuff that they’ve built. It’s just crazy. Yeah. I I would love to see it. Here’s here’s an example of like software being completely [  ] So there’s this product called Adapar. Have you ever heard of it? Nope. So, Adapar is like um basically like software for rich people to track their portfolios and they charge $50 to $100,000 a year. Um and basically what it is is like it pipes into your bank. It pipes into your accounting. It pipes into the public market data and it just tells you like here’s how much um here’s how much money you have. Here’s your personal net worth. Here’s all your assets. Here’s your balance sheet, etc. And so what we did is my CFO just said, “Fuck that. I don’t want to pay um those guys all that money and we can actually build something that is way more customized to us and um integrate it into all of our data. And so he said that and like the you know the you remember like 5 years ago when one of your engineers would be like why are we paying Slack all this money? Let’s just build it ourselves. We all know that’s like a fool’s errand, right? Like that’s insane. And so when he told me he was just going to build it, I was like first of all you’re a CFO. Like I’m a little skeptical. Um but two I was like look do we really you know is that actually going to work in like 2 weeks he built this as this AI assistant. So this I can query um let’s see like what’s um stress test what is this? So basically it’s like the basically like a um anthropic API but it has access to all of our data. Um so like okay here’s one I screwed it up. Bad demo. Steve Jobs would be yelling at me right now. Yeah. So, this is going to go off and query this. Let’s see what it does. Um, but anyway, this was built by my CFO. He’s never coded in his life. Like, when I told him about Cloud Code and that he should check it out, he’s like, I don’t know how to code. Like, I’m not technical. And literally within like a week, I’m so lucky that he’s the kind of person that would do this, but he built this. And it’s just it’s insane. Going back to the glass of half full of entrepreneurship, you know, I’ve been seeing a lot on Twitter lately of like services is the new software. So, I can imagine I know this is you built this for yourself, but I can imagine a product like this uh and then that you you sell services on top of this, right? like if if you actually wanted to sell this to other family offices and stuff like that whereas like right like a weekly call or maybe it’s like I’ll you know add skills every single week or help you do XYZ. Yeah. I mean I think it the way I look at it is I always give the example of funeral homes. So funeral homes are a very unsexy industry that nobody wants to work in and so um you don’t have that much competition. And so if you build software for let’s say like some guy who owns a funeral home has like a web whiz nephew like you or me in like 2010 and he’s like hey can you build software that’s custom for funeral homes for me to manage mine and then you start the software business and you’re the only game in town like no other no other person owns a funeral home and has a web whiz nephew who’s going to do that and so you have a monopoly and you become the default and I think the new world is, you know, if 400 people in the United States own funeral homes, let’s say like 20 of them are smart and know AI, they’re all going to build their own software. And so what does that do? That means it’s great for the consumer. There’s now 20 different software choices that they can use. Someone can build their own custom thing if they want to, but pricing comes down big time. So like, you know, Adapar, the company I mentioned before, they’re charging $50 to $100,000 a month. I don’t think that they’re going to be able to do that for too much longer because there’s going to be a lot of competition that comes out. Hopefully somebody watches my video and says I’m going to build this too and then go crush Adapar cuz like it’s not particularly good software in my opinion. Mhm. So you can see okay so for some reason I can’t scroll still vibe coded but you can see it’s like given me an analysis of like how I could rebalance my portfolio. Um, it can do all sorts of stuff like it can track risks and be like, “Oh, hey, you have XYZ risk in your portfolio.” Um, it’s very cool. Awesome. Um, we only have a few minutes left. What uh anything? Well, I actually have a question. You mentioned uh Gbrain before and I haven’t gotten around to using it. Um, how have you found it? And and for you know, can you explain what GBrain is for for people who don’t know? Yeah. Well, so Gary Tan is a friend of mine and he basically built this um vibecoded project where he wanted a vector database um for personal kind of knowledge base. So really quick um ability to draw from a large base of markdown files on your computer. So basically trying to solve the problem of memory. And because he’s a friend, I was like I’ll install this and try it out. And actually it’s really really awesome. Um there’s a few different people kind of competing in the open source world for this. Um but I’ve been really impressed with it. Um I don’t I don’t want to do a demo because it’s like actually a really boring demo. But basically what I did is I ingested all of my email and I said, “Hey, I want you to um go through my email a thousand at a time and I want you to draw connections and I want you to build pages for everybody that I know.” So, I basically have a page on every person that I know. And then I can say something like, um, hey, I’m raising money for our Yerba Mate business. Who do I know that would be good for that round? And then I can say, okay, now go and draft a powerful email to them and make a deck and send it to them. Um, and so I just find that, oh, what what is what this has enabled me to do is like have a task that would otherwise take like eight hours. Like I I do these like men’s groups and we rent boardrooms and I need to charge everyone because I pay I end up paying for dinner in the boardroom. And so I was like, “Okay, I gotta I got to send everyone Stripe links. I have to get everyone on a subscription. I have to send all the emails. I have to Hector them.” And I just had that as a single task to my OpenCL agent and it went out went in the Stripe API, sent the emails, did everything. So like there are these magic moments using stuff like Gbrain and um and OpenClaw. I want to I want to show you two really cool actually three really cool things before I go. So one so I mentioned this guy Gavin Vicky who built Harbor. So we were doing a vibe coding retreat at my um my cabin and I was talking about how sad I was that um the Limitless pendant sold to Meta. So it was like this little pendant. I think I showed it last time I was on. You just wear it and it would record your entire day and build transcripts of it. And I was saying, “I’m so annoyed because the iPhone has a microphone on it.” Like, why can’t the iPhone just record all the time? And he just went, “Well, I can build that.” And 24 hours later, he had this app called Hearsay. And basically, can’t really see it, but what you do is you say what times of day you want to trigger it. And so, you can be like, “Oh, I’m I’m in meetings in the afternoon,” or or, you know, I wanted to record all day. And then it literally just records your entire day and builds transcripts and then sends them to your iCloud. And so you just have context on your life. And so I record my entire day and then Gbrain ingests it and it just knows context and then my OpenClaw agents have full context. Um, let me show you also a couple cool things I’ve been doing with OpenClaw. You’ve been busy, Andrew. I have been very busy. I mean, this is all all I do. Like, this is just like a complete obsession. And it is um kind of sad because I’m like, let’s see, cuz I’m always spending my time um I’m always spending my time uh tweaking my stuff versus doing actual work. So, um, basically like it does it reads all my email, triages all my email, and then it figures out automatically what projects I have going on. We might have to blur some of this. Um, but here, so it’s, you know, I’m on your podcast, and it’s telling me, oh, you need to, um, prepare for it. Uh, you know, it randomly was like, oh, your Air Table account’s going to go out. It’s my brother’s birthday. I’m bidding on a building. like it just figures out all of those things. And so every day I get this report and then you can see that it um gives me next steps. So I can say like don’t worry about it or I can say hey send an email to my um my admin asking her to um remind this person that. So that’s pretty cool. I also get um emails. So this is like it’s identified a high priority email. Again, we’re gonna have to blur this because this is someone’s comp, but this is somebody saying, “Oh, hey, I’m owed a bonus.” Right? So, and then it drafts in my voice different response options. So, I can just respond in line in Telegram and say 1B. Um, and so it turns your entire business into a multiple choice um quiz basically. So, every day I just get like 20 different messages. there are emails or it goes in my iMessage and identifies things I need to respond to and I can just say like 1 A, 2 B, 3 C and um and that’s saved me a shitload of time. Another cool thing I’m doing, I’ve built a brief. So basically this goes into my Read Wise reader and my email and it looks at which newsletters came in and then it based on what it knows about me. So I prompted it. I kind of said like I’m interested in AI and health and certain things. Um and then it chooses a few stories and then check this out. Did you ever listen to the daily on New York Times? Yeah. So listen to this. Here’s what landed in the inbox and reader today, Tuesday, April 28th. We have a special forces soldier who bet on an operation. So it basically makes a custom podcast using Gemini Voice. And I just listen to that every day in the shower. And it’s so cool because one of the reasons I stopped listening to podcasts like that was because they would be depressing or I, you know, it’s just stuff I don’t care about. Um, so I have it prompted to like only tell me things that are going to make my day better or are relevant to to my own life or my city or my businesses. And then I also have it do a countdown. So it says you have um this many more summers with your kids. You have this many more days to live. Here’s a quote from Senica, you know, to give you like a sense of purpose today. So, it’s just incredibly cool how you can basically make your media diet whatever you want in a custom way with this. I mean, that’s a product in itself, right? Like, honestly, the until OpenAI does it. You think well you think they would do it like the seven minute podcast like I would subscribe like if you if it was $10 a month to the 7 minute podcast that’s going to make you more productive, happier, and healthier. Uh and that is personalized to me. Like I would pay for that. Yeah. I think I think it’s kind of like um the other day I taught my OpenClaw agent I said whenever I tweet I want you to create an Instagram story. So it creates an image that’s perfectly scaled for Instagram and I want you to um put it into the um Instagram uh creator thing, right? So basically schedule it. And that was a product before. So there’s this company called Tweet Shot and they basically automate that. It’s just dead, you know? It’s like anything that could be an API call is just cooked. So to me that’s like an API call business, that’s like the first thing to get run over. But for like normies, I agree. Like if I told my dad about it and I could be like, “Hey, what topics are you interested in? Create me a daily podcast and text it to me.” Like I I do agree that is a cool idea. Someone should build that by the way and me and Greg will back you. Yeah. Um so here’s another one. So, so I have two OpenClaw agents running on a VPS and um Ava is kind of my personal assistant that I just showed you. This is Mara. This is my um my doctor um doctor agent. It also helps. I’ve made them very attractive women, so I always want to talk to them. Um and I’m always flattered when they message me. Um but this this is really cool. So, I have it um I have all my Apple Health data from my Apple Watch, my sleep, etc. and it uploads into a Google Drive. So I have a JSON file of all my um health metrics and then every morning it sends me a health summary. So, it looks at my HRV, resting heart rate, respiratory rate, tells me about my sleep, and then I have this weird um viral nerve pain that I get. And it looked through my data over the last 5 years and said, “Oh, I’ve correlated it and I see that every time you get that flare, your wrist temperature changes for 3 days before.” And so, it tells me in advance that. Um, and then it also tracks like my medication adherence and all that kind of stuff. So, it’s just stuff like I And then the other thing is like if I ask it a question, it’s prompted to use max intelligence. So, let’s say I said um, hey, should I take this medication? It will spin up a uh rheumatologist, a um you know uh internist like every type of doctor as a claude expert with extra high thinking and it will do a team of experts for like 10 minutes across my GBrain and all my medical data and it’ll give me a really informed answer. So I’m like just blown away by some of this stuff. Andrew, we covered a lot of territory, like way more territory than I even thought was remotely possible, but uh that’s why I love having you on. I appreciate it. We did we did pretty much everything. We did agents, we did running your business, we did family office, we did health, we did personalized health, we did living happier and healthier. So, I want to thank you for coming on. I’ll include links on where to find and follow Andrew on the internet, where to take uh the deep personality test, where to find Tiny if you’re ever interested in selling a company, and uh Andrew, is there anything you want to leave people with? Yeah, I have one prompting tip I want to give people um that’s changed my use of Claude a lot. So, I will say um this is my goal. So, let’s say uh real estate example. I’m thinking about buying this building. I want you to interview me. Ask me I’ll literally write ask me a shitload of questions to determine your prompt and use question tool. So, it’ll pull up multiple choice questions. It’ll interview me for sometimes five or 10 minutes. And what I found that it does is just give me like an incredible breadth of basically building perfect prompts. And I think this is like the thing that everyone misses cuz people are always like, “Oh, like um you know, there’s always going to be jobs because someone needs to build the prompts.” And it’s like, no, nobody needs to build the prompts. The AI should just interview you. Open AI just doesn’t want to spend all the compute at this point. But it is fully capable of just interviewing you to figure out what you need. Um so I love that. I also highly recommend um using agent teams. So I’ll say always use a team of agents of eight sub agents. And I find the answers are just incredible. I like that. Good tips. Andrew Wilkinson, thanks for coming back on the pod. Of course, dude. Always fun.

  • AI Agents are the new SaaS

    Okay, I’ll say it. Building agents is the new SAS. I mean, we saw billions of dollars of value creation during the SAS era of people, founders, 21 years old, 24 years old, you name it, come up with SAS ideas that changed their lives. Of course, not everyone was successful, but this is a new wave that’s happening. And I want you to understand what this wave is, how you can take advantage of it, how you can build startups in this space. And in this episode, I’m basically going to clearly explain this entire agents is the new SAS opportunity. By the end of this, you’re going to understand the playbook. You’re going to understand how to find the niche. You’re going to understand how to pick the workflow, how to, you know, build your first agent, how to prove it works, how you can package it like SAS, and how you can basically sell these agents as labor. And it’s really important because that that labor point because labor is a multi- trillion dollar market, right? So I think why people say agents is bigger than SAS is because the total addressable market for agents is just way bigger. You know it’s human capital. And I wanted to just do an episode where I explain everything step by step just clearly for people who are interested in building agents who are who are interested in selling agents and who are you know just want their creative juices flowing around this. This is for anyone who wants to build a business or who just want wants to be more productive. This episode is for you.

    So the first thing you need to understand is the product is the job. So, you know, the mental model I have for this is SAS sells software, agent SAS sells work. A normal SAS product says here is a tool a team could use basically. Um, but an agent SAS product will say here is a job your team no longer has to do by hand and then you’re selling that service. So, it sounds like a a small change, but it’s a it’s a really big mindset change for the customer and for you, the person who’s going to bu be building it. So, take uh restaurants for example. You know, a restaurant wakes up thinking our phone is ringing during, you know, dinner time. Um and the host is busy, right? Dealing with, you know, seating people. People are asking the same questions. We’re missing reservations and private dining calls are getting lost. So, they’re basically missing out on lost revenue. This is why a company like, you know, Slang AI is interesting. Basically, it’s an AI superhost for restaurants. I’m not affiliated. I just think it’s an interesting, you know, example. Uh, it answers inbound calls. It handles guest questions. It manages reservations. It routes VIPs. It alerts staff about high priority topics like private dining or guest complaints. And it integrates with systems like Open Table and Yelp and stuff like that. I’ll give you another example. home services, a plumbing company, HVAC company, a roofing company, pest control company, miss calls, you know, jobs are booked, customers followed up with, dispatches are less overwhelmed, more revenue from the same demand if they integrate something that picks up their phone 24/7. You know, an example of a startup that’s doing this is same day. So they focus on home services and then they basically sell these AI, you know, dispatchers, sales agents, receptionists that answer calls, respond to texts, books jobs, reschedule. Again, the product is the job. These examples matter because they’re just understandable. And so when you’re thinking about coming up with an idea for a startup here, think about I handle this one annoying job better than a junior employee, faster than an agency, and it’s cheaper than adding headcount. That’s the mental model I think that you should be thinking about. The second step I have here is pick a workflow with a paycheck attached. So you know, how do you find the right agent idea? You want to start with the paycheck, right? If people are already paying for the work, they’re paying an employee, they’re paying an agency, a receptionist, a coordinator, dispatcher, they there’s an opportunity to sell that service cheaper and then unload some of that work that that person is doing to do more high highly creative creative work. So a good agent workflow has five traits. Um the first is it happens all the time. So daily is good but hourly is better. Uh you know every inbound lead uh every call, every tech ticket, every quote request, every appointment, every order, every maintenance request. Second, it has to have a clear finish line. Uh the job got booked, uh the ticket got categorized, uh the refund got approved, uh the vendor got scheduled. Um the customer got a useful answer. Uh third uh if it touches already software. So if it touches Gmail or Slack or Shopify, HubSpot, Zenes, Stripe, um agents need these tools so they can use it and they also need the context that they can read. The fourth is the edge cases are actually really annoying um but they’re learnable. So if a workflow is too basic um basically the problem is basic automation you know zaps and stuff like that can do it um if it’s pure human judgment uh the first version will break. So the sweet spot is repetitive work with enough judgment that AI can help. Uh the fifth is the buyer can feel the loss. missed calls, slow replies, drop leads, uh empty calendar slots, uh expensive humans doing low value uh coordination. So, if this is, you know, you know, if you want to start a business here, here, what’s a first rep to get started? Well, pick one niche and write down 20 jobs people complain about. Um, if it’s roofers, you know, maybe it’s missed calls, uh, financing questions, insurance paperwork, appointment reminders. If it’s med spas, it’s maybe lead qualifications or no-show recovery, membership upselles. Um, if it’s Shopify brands, maybe it’s uh returns, uh, exchanges, uh, wholesale lead follow-ups. And then you want to score each job on five things. Um, how often does it happen? How expensive is the pain? How easy it how easy is it to know when the job is done? Uh what tools does it need access to? And who already owns the budget? And that is where agent SAS starts. So you want to start with the job that has a paycheck attached. Super super key point here. Um once you’ve done that you actually and this is this is the thing that a lot of people miss you you actually want to shadow the human before you build. So once you find the job right you you you’ve identify what the job is before you like prompt before you start coding just shadow a human being who does the job. Uh, I know a lot of founders want to skip this. Um, but it’s usually what’s going to help you get, you know, an unfair advantage, an insight into building an agent that is high quality. So, just watch someone do the job 10 to 20 jobs. Ask them to screen record it. Um, ask them to narrate what they’re doing. Uh, ask them what makes a case easy. Uh, ask them what makes a case weird. Um, what did they check before they make a decision? and ask them, you know, where the mistakes happen. Basically, you’re looking for the real workflow. Um, and even if you’ve done these tasks before, having having it, you know, fresh in your memory, is just going to be super super helpful when you’re building out this. So, you know, for example, a restaurant host, if they answer, “What time are you open?” Uh, the real workflow is actually deeper than that. um they know when the kitchen closes, which tables are good for strollers, uh when the patio is closed, how to handle a VIP, uh and you know when to route to a priv inquiry. So the detail is the product. Um and when you’re specking out your your agent, you know, I think it should have seven key parts. What wakes the agent up? What context does it need? What tools can it use? What is it allowed to do itself? Where does it need approval? When should it escalate and and bring a human in the loop there? And what does success look like? And if you understand all those things, um you’re, you know, you’re not just going to build an agent slop, right? We want to build agents that are high quality, that are exceptional, that do the work as well, if not better than humans, and way more consistently, and that’s what people are going to pay for. So, uh, really helpful to just sort of internalize that. Now, you’re going to want, uh, step four is you’re going to want to build the smallest useful agent. You know, I call it the minimal useful agent, the MUA. Most people hear agent and imagine a fully autonomous employee. Um, and that’s how you you get these demos that you see on Twitter. Uh, and they don’t really work and it ends up being a bad business. Um, you want to start smaller actually. So, there are four good first versions. The first is a draft and approve agent. So, it reads context. It drafts the reply, the quote, the summary or the next step. A human approves it. Uh so this is great when there’s workflow risk um maybe there’s creativity involved uh approval processes that that sort of thing. The second is a triage agent. So it classifies inbound work and routes it to the right place maintenance requests uh billing issue or you know refund that sort of thing. The third is a coordinator agent. So this goes between systems and people. So, it’ll check availability, it’ll send reminders, it asks for missing info, um, and it keeps the work moving basically. Um, and the fourth the fourth is the bounded action agent. So, it can do a specific thing under clear rules. You know, book an appointment, send a follow-up, you know, process a refund under $50. These are the sorts of things you’ll you’ll now see you’ll notice it in the wild. Like for example, with Uber Eats, you order something and your salad doesn’t arrive, automatically you’ll get the refund um based on an agent that will do it. So that’s basically the the ladder here. Uh when you’re building the the minimum useful agent, uh draft, triage, uh coordinate, and act. I was looking at Anthropic’s agent guidance uh recently and they made a really uh important point a really important simple point. They said many agent problems should start actually as workflows. So a workflow follows a predictable path. An agent decides more dynamically. Founders should earn autonomy by starting with a predictable path and adding judgment only when it creates value. So if I were building this, I would start with one workflow and one promise. For example, like we answered miss we answer missed calls for roofers uh and book qualified jobs or we triage maintenance requests for property managers and schedule the right vendor. We handle reservation calls for restaurants and alert staff when a human should jump in. Um that’s enough. That’s really enough. And one workflow that works enough is is good enough for day one. And it’s going to help just like build confidence not just in you that it’s working, but also in this customer cuz keep in mind people are buying agents for the first time ever. So they they want to they don’t want all of it at the same time, especially if you’re not Microsoft or you’re not Salesforce. So step five in building an agent is the product wrapper is what makes it a SAS. So you don’t want to just build a cool automation. And I think what separates a cool automation from a real agent first SAS product is the agent does the work but the rapper creates the trust. So customers actually need to see what happened. They need to see logs. Uh they need approvals, um controls, handoff rules, that sort of thing. And uh they need a way to test the agent before it goes live. They need to know basically why the agent did what it did. So that wrapper is the SAS and the agent actually lives in the phone system, the inbox, the Slack channel, CRM. So the dashboard can be really simple. Um but the customer customer actually still needs the control room. Um at least that’s what I’m noticing is working right now. So, for a restaurant phone agent, the control room might be, you know, call summaries or uh reservation outcomes, missed human handoffs, that sort of thing. Um, for a property maintenance agent, maybe it’s uh, you know, tickets that have been created, vendor routes or tenant updates, owner approvals, that sort of thing. Um, and that’s really why eval matter a lot when you’re building an agent first uh, business. Um because before you promise autonomy, you want to create a basically a small test uh a test set is the best way to think about it. So you know take 50 real examples of the job and then mark the right answers like 50 calls you know 50 leads uh maybe you know 50 maintenance requests depending on what it is and then you want to run the agent system against them. So, did it classify the problem correctly? Did it ask for the right missing information? Did it use the right policy? This is what’s called an eval, right? Your eval set is, you know, it’s basically like the gym. You know, every time you change the prompt, the model, the tools, the workflow, the agent goes back through the gym and and is able to, you know, basically know what’s good and know what’s bad. It’s also like low-key a really good sales asset because imagine telling a property manager, you know, we tested this on, you know, 50 of your old maintenance requests. It routed 42 correctly, flagged six of them for human review and made two mistakes. Here are the two mistakes and here’s how we fix them. So it it just helps you actually build trust uh especially with people who are like who own boring businesses but who can actually really use some of these agents. When you when you just are transparent and open about these sorts of things, you’re going to build a lot of trust with them. So uh the sixth step uh on building an agent is you’re going to want to sell the pilot like labor and then you’re going to want to productize it. So the fastest path is usually a pilot where you manually do the work with AI and then you productize the repeated parts. I’ll explain what I mean by by that. But you know basically I would start with three customers in one niche. So the same niche, same workflow, same pain and then you sell the outcome. You actually want to be like very very uh constrained on this or else you’re going to get bad results. So, if you’re selling the outcome, it’s we will answer and qualify your missed calls. We will triage your maintenance request and then you charge uh a setup fee and a simple like monthly fee. Um you can keep the pricing just like easy to understand and then you can add usage or outcome pricing once you understand the value. I’m a huge believer if you’re, you know, listen to the startup ideas podcast here and, you know, you’re a subscriber here, you know, I I I really believe that outcome pricing is the future of how a lot of these agent first businesses and software is going to be priced because, you know, it just makes sense like, you know, the customer only wants doesn’t want to pay for another seat for something. So, uh, but don’t just jump there uh initially. Um, so you’ll get there and you have to have patience with it a little bit. You know, the the pricing model, like how do you think about pricing uh something like this? You know, maybe it’s like a $1,500 setup, $1,500 setup, and then like $1,000 a month for one workflow. Or maybe it’s like $2,000 setup plus $30 per qualified appointment. So that’s more the outcome base eventually. Or $3,000 a month up to 500 handled tickets. So the exact price actually matters less than the learning. Uh you basically want to find out what the customer values and then uh where the agent breaks uh what needs approval and what would they miss if you took it away. Pretty much the most important question there is uh and then you build the product around the repeated pattern. So, if every roofer needs the same emergency call script, service area check, financing question, an estimate follow-up, boom, you have a product. Um, if every med spa needs lead scoring, consultation booking, no show recovery, um, post treatment follow-up, boom, you have a product. So, this is agents ass. You know, you earn the software by doing the work first. Step seven is distribution. You know, you’re going to want to get you need obviously you need people to hear about the thing you’re building, hear about the agent, see it, and be like, I need this. And how can you do it? What are some tips to to be thinking about this? Workflow tearowns is what I’m seeing in real time that’s working really, really well. So, show the old way of doing a process, right? A call comes in, nobody answers. The customer calls the next company or or the CSR answers, a asks five questions, checks the calendar, checks the service area, books the job, you know, you know, writes the notes, sends a reminder, and then forgets to follow up. And then the heart of the owner, of the manager just absolutely breaks. And then you show the agent way. A call comes in, an agent answers, it asks the right questions, it checks the service area, it checks the urgency, it books the appointment, it updates the CRM, it sends the confirmation, it flags edge cases for a human. That’s the type of content that works because the manager, the executive, the owner feels that pain. And you know, you want to be in the business of selling painkillers, not vitamins. And that’s why I love these building agent businesses because you are, you know, if you do this right and you go through some of these steps and and these frameworks and this playbook for coming up with an idea, building an idea, you’re building something that’s really really helping people. Like it is very very valuable to them. And the only way to really really get them to book a call or do something is to show them sort of make fun of the old way and then show them the new way. Pick one workflow, make the internet associate you with it. And you know, the way I think about it is you want to make the checklist, you want to make the B benchmark, make the tear down, make like 50 examples of this workflow post, and you’re going to be in the content game. You know, a lot of people listen to this, you know, don’t want to create content, and I totally understand, but, you know, you have to create content around this because it’s just the, you know, there’s just a opportunity in creating content. Um, and then you can use some of those assets that are starting to work and then put paid uh paid ads uh around it. So, you know, distribution, think about these these tearowns, think about poking fun of the old way, think about creating memes around it, uh, and then creating content, picking the winners, putting paid ads against it. I would suggest focusing on one platform to start. Um, and uh, you know, I’m going to be doing more episodes on just how do you how do you get how do you get customers to your your vibe coded apps and stuff like that in the future. So stay tuned for that. Um, but just you know how I’d be thinking about it. The last step you know the 0 to 100 plan like if I was starting this from zero you know I feel like people would want to know what would be my plan. Um so I’ll give you my you know call it week four-week plan. Um my first day what I would do like how to build a business. How do you build an agent business in 30 days? Okay. Day one we pick a niche where missed work cost money. We talked about this. Home services, property management, you know, insurance agencies. Day two, I would interview 10 operators, ask them to screen share the workflow, keep the calls as research, and just watch them. You can pay them for this, by the way. Day three, pick one workflow with frequency, pain, software access, and a clear success metric. Day four, write the agent spec, trigger, context, tools, rules, handoffs, eval. Uh day five, run it manually with AI. you know, use claude or chatbt and copy and paste the context, draft the output, uh, ask the human to approve and you are testing whether the AI helps before you build the software. Day six, build that smallest useful version. Uh, draft and approve or triage is usually enough here. Day seven, create the eval set from 50 real examples. Week two, sell two pilots in the same niche. Week three, add the product wrapper, right? The logs, the approvals, the settings, the analytics, the handoffs, and use AI to actually build that, you know, software. I’d probably using something like claw design and, you know, assuming that Fable is live, using Fable to actually code it up. Week four, I’m publishing workflow tearowns. I’m turning the pilots into proof and I’m doubling down on my content strategy. So, you know, while, you know, I I should have mentioned this, but while I’m doing all this, while I’m thinking about building this business, I’m building an audience all the way throughout. And by the end of week four four, I have formats that are working. I know where to double down. I know where I can spend money, pay paid money to acquire customers. And that’s when I, you know, my second and third month, I’m trying to understand what my LTV is. you know, what are the channels that are working? Where can I double down on it? And I keep going. I think that’s the episode. You know, basically where I’m at is I think agents are the new SAS because software is moving from help me do the work to do the work with me. And I think that a lot of people are just they’re not partaking in the shift. They see the shift. They understand the shift. You’re listening to me and you’re like, “Yeah, of course.” But they’re not building they’re not building agent first businesses. Um, I think the opportunity is basically to find the smallest painful workflow that repeats all day. Uh, in a niche that you understand and make it disappear, you know, answering a phone, booking a job, triaging the ticket, uh, updating the system. Um, escalating that weird case. Um, and I think there’s a ton of money to be made here and a ton of value to be created. So, if you’re watching this, you’re listening to this and you’re thinking, I want to build with AI, well, start start with the job. You know, find the job, shadow it, spec it, run it manually, build the smallest useful agent, sell the pilot, then productize the repeatable parts. This is how you build an agent that people will pay for. And this is why I think building agents is the new SAS. Hope this is helpful. Hope this got the creative juices flowing. People charge thousands of dollars for this type of thing, but it is free like always on the Startup Ideas podcast. Let’s I’ll see you in the comment section. I’ll see you uh let’s talk and let me know what you want me to cover next. If this is helpful and I read every single comment on YouTube, I appreciate every single like and subscribe if you want more of this stuff in your feed. Thank you and I’ll see you next

  • Build API Powered Dashboards – MongoDB, Discord and Mail API

    Hello everyone here on the free co camp channel. Today I’m going to be showing you how to build every tool that a startup needs thanks to this amazing low code approach. We are going to be using this low code approach to build a marketing dashboard in which you can view all your users on a certain page and then on another page you can choose which users which are associated with different marketing lists should be emailed or sent messages to on discord. We will also have the option of adding new customers directly from this dashboard, editing them as well as deleting them as well as adding new marketing lists too. Okay, so a lot to cover in this tutorial. We will be using MongoDB. We will also be using the SMTP API as well as the Discord web hook. So, a lot to cover. For those of you who don’t know me, my name is Anna Kuba and I’m a software developer as well as content creator online. You can find me on my channel or just here on free code camp. Now before we get going, low code solutions are not to be confused with no code solutions in which no coding is required. We will be using this platform right here, AppSmith, in order to drag and drop UI components have been pre-made for us and all we’re going to be doing is hooking up the back end. Okay, so as you can see here, a basic understanding of HTTP requests such as get, post, put, delete are required as well as some basic JavaScript too. This course is made possible thanks to a grant from AppSmith, the low code solution platform. Okay, so first things first, I’m just going to head over to the AppSmith platform, which we will be using to build our low code app. So if you sign in, this is what your dashboard should look like. As you can see here, I already have some previous projects that I have built using this platform. We of course are just going to create a new one. So I’m just going to go ahead and click the new button like so. And this will generate this new landing page for me. Now I’m just going to rename this so that we can keep track of this on our dashboard. I’m going to call this communications dashboard just like so and click off it. So that is saved and once we have finished that we will have the option to build with drag and drop or generate from a data table. So I’m going to choose to build from drag and drop. So just go ahead and select that option so that we can start completely from scratch on a blank canvas just like so. Once we are here, the first thing I’m going to do is just get the UI for our dashboard down. So, our dashboard is actually going to have two pages. Let’s start off with creating our first page. This is going to be called customer data. And it’s going to, you guessed it, hold our customer data because we’re going to want to have our customer data on one page and then options to send messages to our customers based on the mailing list they are on on the second page. So let’s go ahead and call this customer data. So our page is now called customer data. And like I said, let’s get to building the UI first. So to build the UI, we have some widgets to our disposal that are pre-built and pre-made, styled up, ready for our use. So if we click on the widgets here, and all I’m going to do is just simply search for a container widget and just drag and drop it. We can use the outline on this widget to essentially resize it just like so. And if we click on it, we can drag it around. So there we go. There’s our first widget that we have used. We can also customize it thanks to the tab on the right. So here are the options for personalization on this particular widget. And I’m simply going to choose to change the color on this. So, I’m going to change the background color to this lovely green like so. And we can do other things such as change the border radius as well. Okay. So, there we go. That is now a customized container. We can actually also rename these widgets. So, I can choose to name this header if I wish. This is useful especially when it comes to picking them out later when we add functionality to some of these widgets. Okay. So that is what you can do. It is optional. You don’t have to. So once that is done, I’m just going to show you how to add text to this header. So we’re simply going to search for text in the widgets and drag and drop some text. So once again, if we now click on this, you will see all the options for customization on this particular widget. So let’s change the text in this to be customer communications portal. So all I’ve done is just change the text in here. Okay. And then once that is done, we can also of course resize it by grabbing the border like so. The other things we can do are change the color of the text. So I’m simply going to select from the options here. And then we can also change the text size. So we have some standard ones here. I’m going to choose to use the heading one for this particular text. Okay. So great, this is looking good. And of course I can just center it by using the dragging functionality on the widget like so. Wonderful. So that is done. And the last thing I’m going to do is just put in an image. So once again, let’s go to our widgets and I’m just going to drag in a image widget like so. This is a little bit too big. So once again, we can resize it using the borders and then just drag it to where we need so that it clicks in place. Now once here, we can simply just use an image that is hosted on the internet. So this is a great library that I use or I’m going to use for this project that has loads of free icons for us to use. This particular one is just going to be a folder like so. So there we go. That is the URL that I’m going to need. You can of course use any URL you wish. And wonderful. So our header is looking good. I’m just going to resize this a tiny bit and move on. The next thing I’m going to do is actually use a another container because in this container I’m going to store our table of all our customers. So once again, let’s just drag in a container. I’m just going to drag it over here and give it the border radius again of 30. So there we go. That translates to 30 pixels. And once that is done, I’m going to now put some text in here so that our user knows what this container is for. And this is of course going to be for our customer data like I said. So let’s go ahead and change that text to customer data and select this to be a heading two so that it’s a little bit smaller than our main heading. So that was super easy. The next thing I want to do is just add in two inputs that will let us order the table that we’re going to input in later by whatever column we wish and then by ascending or descending order. And to do this, I’m going to use the text. So, I’m going to put in some text to say order by like so. So, just drag in the text and just change this to be order by. And the next thing I’m going to do is use the select widget. So let’s go back to our widgets and find the select widget and once again just drop it where we need just like so. So the select widget simply looks like this. If you click on it, it will show you all the options we have. All the options are represented by the options on the right with a label and a value. Okay, as well as a little search bar. So that’s what it looks like. We will come back to this later when we get to putting in the values that we essentially want because we don’t want blue, green, red. We want to order by the table columns. Okay, so this is looking good. Let’s just stretch this out so we can add a few more things. And I’m just going to move this around like so. So that we can put in essentially another select and another text widget. While we are here, however, I’m just going to rename this as this is something that I will probably want to pick out later. So, I’m going to rename this to key select just like so. And wonderful. Now, in AppSmith, an easy way to essentially duplicate what we have just done is to literally copy and paste the widget. So, that’s what I’ve done here. And now I can just use the same widget with the same sizing, the same inputs and everything and just move it along to here. And of course we need to rename this because as default this has been renamed to whatever the previous widget was with the word copy. I want this to be the order select. Okay, so there we go. We’ve got the two selects. Let’s now carry on before we get to changing these inputs later. Now, finally, for our table. So, to do this, I’m just going to actually go to our widgets, search for a table, drag it in here, just like what we’ve been doing, and a table will be generated for us with some dummy data. However, we don’t want this dummy data. We want data from an actual database. And this is going to be a MongoDB database. So, this is definitely something I’m going to want to pick out later when we get to writing queries and writing some JavaScript. So, let’s rename this. Let’s rename this to data table. Again, we don’t have to do this. You can, of course, pick it out by the existing name. This is just for readability more than anything for this tutorial. So, just keep that in mind. Okay. So, I’ve just renamed this to data table. And this means that instead of having all of this generic data that has been added for us by AppSmith, I want to get some real data from my database. So to do this, let’s connect to MongoDB. So all I’m going to do is head over to our data sources and then once here, well, we actually need to make our database first. So let’s head over to MongoDB and just sign up for free. Let’s go to MongoDB Atlas. And I’m just simply going to sign up. Now, I’ve already done the sign up process for this. If you haven’t, please pause here and do the sign up process as if you, you know, have never used this before if that is the case or just sign in if you have already used MongoDB. I’m going to choose to log in with my account that I use for MongoDB tutorials. And amazing. So this is what my dashboard looks like. As you can see, there are a few projects that I have previously done. But we are going to have to create a new project. So what should we call this project? I’m just going to call it communications as that is the app that we are working on. It’s a communications dashboard. And once we have named this whatever we wish, I’m just going to go ahead and click here. And this will take me to the next step in which we add members and set permissions. Well, this is easy. I’m just going to add myself really. So, let’s go ahead and create our project. Okay. And wonderful. Now, let’s build a database. We are of course going to use the free option for this. Of course, you don’t have to. This is just for the sake of tutorial. So, I’m going to click on the shared option right here. And now let’s go ahead and select some of these options. So the shared option, well this means that we can only use some of these. I’m going to go ahead and stick with the one they are suggested for me and create a cluster. Once this cluster has started to make, let’s just fill out these security quick start questions. Let’s give our database a username and password. I’m just going to go ahead and make my username and your kubo. And the password I’m going to use is 1 2 3. And I’m just going to create my user. Of course, please choose something more secure. Again, this is just for tutorial purposes, so I’m fine with that. And wonderful. Let’s also add my current IP address. This just means that I will only be able to access this from my current IP address. Okay? So, that will be the same for you. If you try to access your database from another IP address, it won’t work thanks to this. And let’s finish this out. And wonderful. So now our cluster is being created. Once that has done, you should see something that looks like this. Okay. And now we are ready to start our first collection. So let’s just click on cluster zero right here. And on the collections, let’s create our first collection. Let’s add my own data and call our database something. I’m just going to call it data for now. And our collection name. Well, we’re going to have a few things in here. We’re going to have a customers collection in which we’re going to store all our customer data. Okay. So, let’s just go ahead and call this customers and click create. So now you will see that we have data and then a collection called customers. And if we want to add another collection, just go ahead and click the plus sign right here. And checking that you’re under the database name data, just go ahead and add a collection name of mailing list in which we’re going to store all our mailing lists for our app. And just click confirm again. And once again, our third collection. I’m going to have three collections for this project. It’s going to be a marketing list. So once that is done, just go ahead and click create. And wonderful. So there we have our three collections in the database called data. Now I’m going to just add some customers in here manually to get started. Okay. We are going to be able to add customers from the dashboard itself, but just to get going, we’re going to create some and add them in manually just so we have something to work with. So to do this, I’m going to insert this first customer into the customer collection. As you can see, an ID has already been generated for me thanks to MongoDB. And I’m just going to choose this JSON option just because I prefer working this way. You can choose the other option but for me this is slightly easier as it will allow us to copy and paste and just really kind of you know create these customers quickly as we are going to create 10. So don’t forget the comma and what is our customer object going to look like? Well, we are going to have a user do not disturb and this just means that the user has chosen to not be disturbed. Okay, so that is an option that we’re going to have for our app. The next thing we’re going to have is a customer email ID, which is simply just going to be an email address for that customer. So, let’s go ahead and do that. Now, email ID and just fill it out. Again, this is all just random data. Of course, these emails, you know, I don’t know if they exist, maybe they do, but they are just dummy data. The next thing I’m going to do is just have a customer ID that is separate to the document ID above. This is a customer ID that I have chosen for the customer. Let’s start off with one 01. And then we’re also going to have a customer name. And this is what the name of the customer is that the customer has chosen to be represented by. Okay. So there we go. This is our essential customer object. Now I’m going to copy this so that we can use it to create way more customers. And I’m just going to insert this into the collection just like so. So there we go. There we have our first customer. Let’s create some more. So I’m simply just going to insert a new document. Click on the JSON option. Put in the comma. Paste away. And then I’m just going to format this a little bit. Change the customer ID. change the email ID. So, I’m just going to make something up once again. Just like so. Change the customer name. So, once again, I am just making this up and click insert. So, there is a few of these to go. I’m just going to do one more and then I’m just going to fast forward them for you because, you know, you should probably get the gist by now and there should be 10. So, once again, I’m just going to insert into the collection. choose the JSON option. Format this a little bit better. And then I’m just going to change the customer ID and of course the customer name to once again something that I am making up and click insert.

    Okay, so there we go. Like I said, I’m not going to put you through all of this. So I’m just going to fast forward and cut this bit out until we have 10 customers in our database.

    And wonderful. So there we have 10 customers in our database right now. There are 10 in here. So there we go. And now we can use this in order to populate the table in our app. So great. So first off, we’re going to have to get the URL that we’re going to need to connect to our database. So to do this I’m actually going to go to the overview of this cluster zero and just click on the connect. Once here we are going to choose the connect our application option and let’s go ahead and just get this whole connection string right here. So, just go ahead and copy all of this. Take it and we’re going to go back into our AppSmith portal. And then under the data sources, I’m going to create a new data source. And we already have MongoDB configured in here to make our lives a lot easier. So, select the MongoDB database option. And then right under here, let’s go ahead and choose the connection string option and then paste our connection string in here. Making sure to remove my first database and change it to data. And then also change the password to 1 2 3 or whatever you chose to save as your password. Okay, great. Now, we also have to whitelist these IP addresses. So, just where we added our own IP address, we can add these two right here. So, let’s go back to MongoDB now and just close this. And under network access, I’m going to add an IP address. So, all I’m going to do is just paste in one of the IP addresses from the AppSmith page and click confirm. And let’s now go back to AppSmith, grab the other one, and then once again go back into MongoDB and add that IP address. And I’m simply going to paste it once again and click confirm. So super easy. That is currently pending. But once that is done, we can go back to AppSmith and we can of course test the connection. So let’s go back in there now. And then of the three buttons, just select the third button. And great, this data source is valid. Let’s go ahead and rename that once again just for readability. I’m going to choose to call this communications data just so that we know what we need to find and it’s just a lot more easier for us to work with. So great. So once that is saved, let’s carry on. So now let’s go back to our customer data page and click on the table just like so and get rid of all this dummy data and instead we are going to write a query. So let’s go ahead and click on the queries.js right here on the left and create new. or we’re going to select the communications data option that we just made as a data source. So let’s scroll down and find that one right here. And then you should see this page pop up. So now we are writing our first query. Okay. So to recap, what we first did is created a data source and now we’re writing a query. Okay, that will use that data source. So our query, let’s go ahead and call this something. I’m going to choose to call this find query because we are going to find all the customers. Okay. And just return them. So making sure that is connected to the communications data. I am now going to choose the command find documents and look in the collection customers. Okay, because that is what collection we want from our database called data. And you’re just going to click run. And there we go. You will see all the customers that we created in the previous step when we manually added them on MongoDB. Easy, right? Okay, great. So, this is looking good. Now, let’s go back to our customer cumulations portal and once again just get rid of all the dummy data. Once we’ve selected the table data widget and then I’m going to use these two curly braces. So these two curly braces are an appsmith thing. It will just allow us to use the queries and not confuse the app by thinking it’s text. You can use JavaScript inside any widget to control things like its data source behavior and formatting. Just wrap the JavaScript in double brackets to separate it from regular text. Similar to mustache or handlebar syntax. This allows you to link widgets to APIs, queries, and JavaScript functions and is known as binding the widget. So, I’m just going to use find query. data. And tada, that has brought back all our customers. It has arranged it in columns for us. It’s got all the data. Is very intuitive. This is wonderful. Okay, so this is looking good. The next thing I’m going to do is just customize this table a little bit more. So, what I can do is make some of these columns not visible as we don’t need some of this information visible to the user using the app. One of these things is not making the ID visible. And the other thing is just making a new column called a delete column. So, to make a new column, I’m just going to go ahead and add a new column. And let’s just change this to say delete just like so. And instead of having text in this delete column, I actually want to have an icon. Okay. So, I’m going to show you how to do that now. So, to do this, just go ahead and click on the little cog and it will show you all the options that we can have for this column. So, the column type, well, we don’t want plain text, we want an icon. So let’s just go ahead and select icon from this dropdown right here. And great, an icon button has been generated for us. Now we can customize this further. For example, I want the icon to be a trash can. So let’s go ahead and select trash. And great. Now because this is more severe, I also want to change the color. So let’s go ahead and change the color of this trash can. So, I’m simply going to change the button color to be this red, like so. And great. And then let’s just round it off a little bit, too. So, of course, this has no functioning anality at the moment, but I really wanted to show you what it’s like to not have text in the columns. You can have icons, you can have buttons, you can have whatever you wish. We will be hooking this up later, so just bear with me for now. So now that we have that, I’m just going to actually add a modal that will pop up when the delete button is clicked. So again, we are just doing the UI for now. We will do the delete query a little bit later. So to do this, I’m just going to go back into the widgets

    and just search for the modal widget and just simply drag it over and place it under here like so. So once we have the modal here, I’m just going to change the text. I’m going to change the text to say delete row as that is what the model is going to be for. We’re going to confirm that we definitely want to delete this line. So once that has been changed, we can also do some other personalization. Let’s also rename this to delete modal. Okay. So, for example, I’m going to add some more text in here. So, let’s go back to the widget and search for the text widget and just paste it in here like so. And then we’re going to have a warning message that says, “Are you sure that you want to delete this item?” Because I want to make sure that people are definitely sure that they want to delete it. And we’re just not deleting the line if someone clicks on it by mistake. So, great. The next thing I want to do is just change the text of these buttons. So let’s go ahead and change this from close to cancel because you can change the text of these buttons quite simply like this. And by default this already has an event. The event is to close the modal that we have renamed delete modal. Okay. So that is in there by default. And next, I’m just going to change this to be a primary button. And I’m just going to change the color of the second button to be this red. Just like so. And on this click, when we confirm we want to delete the row, we’re actually going to execute a query. Okay, we’re going to execute. So, this is where we get to writing the delete query. We want to execute the delete query. So let’s on the on click event select well this time I’m actually not going to choose to just execute a query I’m going to chain some queries together which is why I am going to just choose the JavaScript option so I can write my own JavaScript in here. So to do this just click on the JS button until it’s turned blank and we are going to run the query delete query which as I said we are yet to write. So we would do delete query run and then this function. So we’re essentially chaining functions in here. So once with the delete query runs, we’re going to run the find query. The find query is the one that will bring back all the customers again once the customer has been deleted. So essentially refreshing our data to truly represent what is in there. Okay. And then we are also going to close the modal. So we’re going to write close modal. And the modal we want to close is the delete modal that we have just created. So that is how you would do that. Chaining all of these things together so that they happen in the right order. Okay, great. So of course delete query does have some little red squiggies under it because we don’t have that query yet. So AppSmith is telling us that this is the case and this will be an error. So why don’t we get to writing that query? Okay, now we’re going to actually hook up the button to open the modal so that we can open it. So I’m just going to do that now quickly just on click event and change that. While I’m here, I’m also going to delete this icon. We’ve done it. This is looking so so good. So, all I’m going to do is just under here, go to add query, create new, making sure to select the communications data. And this query is going to be a delete query. So, let’s just name this delete query for readability. And the collection we want to work with is the customer collection. And the command we want to do is delete document. And how we going to delete the document? where we’re going to search for it by the ID. Okay, the object ID. So let’s go ahead and choose the object ID that we are deleting. So this is the syntax for working with MongoDB. We’re going to have the ID and then we are going to get the object ID of the table data of the data table. So essentially the table we called data table on our dashboard and then we’re going to get the triggered row ID. Okay. So that is how we know that we’re going to delete the correct row. We’re going to select it from the table of the triggered row and then pass it through into here so that it gets sent off to MongoDB and deletes the correct one by the object ID. Okay. So hopefully that makes sense. Just to make sure this is working, let’s click run that. And now let’s check if it works. So let’s go ahead and choose one of these. I’m going to choose the first one and click on the delete icon. Click confirm. And then tada, that has now been deleted from our database. So that has worked. Okay, the delete functionality of this app is now working. So, let’s move on. So, this is all great. And of course, this table does actually come with some cool stuff that will allow us to search for things with the search bar. It will also allow us to filter. So, for example, we can filter by any one of these columns. Okay? Like this. And we can do, you know, users do not disturb is exactly zero, for example, which of course will bring back all of them because I believe they are all zero at the moment. But it’s just going to show all the options that you have available to you just by using this table widget like this. Okay, wonderful. So now that we have that done, I actually also want to do my own custom ordering. So let’s go ahead and use these inputs, these select dropdowns that I have made. The first thing I’m going to do is just delete all of this. Actually, we can just use this as a template. And let’s change out the labels and the values. So, I want to be able to sort by three things, I believe. I want to be able to sort by the users do not disturb. So, let’s just make the value the same like so. And then let’s also set And then let’s also order by the customer name. In fact, there is one more thing we can choose to order by and that is the customer ID. So let’s just go ahead and put the label as customer ID and the value as customer ID 2. Great. And let’s also have a default value. And I’m going to choose for this to be customer ID. Okay. So this is looking good. Uh as the visible here, I’m just going to actually put in some JS. And that is just going to say that only make this visible if the find query data length is bigger than zero.

    Okay. Otherwise I don’t want this to be visible. Wonderful. Now do we need any actions? Well yes on change. So on change, I actually want to run the find query uh query again because I want to essentially just bring back certain values in a correct order in this table. So we’re actually going to have to go back to our find query uh and add some stuff in there for this to work. But just for now on the onchange event or action, we’re going to run the find query uh query again. Okay. So, at the moment, this won’t do much. Uh, but we will be fixing that a little bit later. For now, let’s do the ascending or descending option, too. So, let’s go ahead and select this second dropdown. And once again, let’s change the label to be as c for ascending. And I’m going to get this value of one and the label to be dc for descending. And change the value of this to minus one. and delete the other options because I only want two options here. And just like before, visible is only going to be visible if the find query data length is bigger than zero. So essentially saying there’s, you know, more data in there than zero when we run the find query. And then I’m also going to change the default value to be one. So we’re getting the value to be one, but the label for that is ascending. Great. So this is looking wonderful. And on this we’re also going to have to change the onchange action. And that is just going to be to run the query find query again. Okay, great. So, like I said, this won’t do anything now because we have still a bunch of stuff to do. And that is be able to run a query based on the two selects that I have written, which is why we actually chose to rename these selects as key selects and order select. So, let’s go back into our find query. And as the query up here, I just want to be able to sort the data. So under the sort once again the syntax for MongoDB used to have these two curly braces and then I’m going to use the appsmith two curly braces so that the platform essentially recognizes that this is not text and get the key select selected option value. Okay. and then also the order select selected option value so that things are sorted by the option and whether it’s ascended or descending thanks to the order select dropdown. Okay, great. So this is looking good and of course if we run this it will bring back the data in the correct order. And now if we go back into our app, let’s test it out.

    Okay, so let’s go back in here. I’m just going to select the table. And actually on page change, I’m also going to execute the find query uh query. Okay. And also on the search text change, I’m also going to run it just as a backup. I just want to make sure that this query is being run. if we change anything in here so that we’re always going to get the correct data coming back. I’m just going to refresh this page to make sure. Amazing. So, this is now working. This is looking good. Let’s go ahead and switch some of these out again. So, great. This is all being sorted by ascending and descending order. Okay, wonderful. So, another part done. We have now finished making this table sort by our customized sort functions. Let’s carry on. Now the next thing I want to do, so we’ve deleted stuff from the table. We’ve got all the data from the table. The next thing I want to do is actually add customers directly from the platform to this table. So to do this, I am going to choose another widget. It’s going to be a button. So, let’s go to the widgets right here and just search for the button widget. I’m just going to drag over so that we can essentially connect it to a another modal. So, for now, I’m just going to rename whatever the label is for this button to be new customer. And we can actually add icons as well to these buttons. So, if we scroll down to all the options for a button, you will see the option to add an icon. I’m just going to put in a plus sign like so. And you can align it to the left or right, but I’m going to keep it here. I quite like that. Now that we have that done, let’s go ahead and find another modal in our widgets. So, once again, let’s search for the modal and then let’s just drag it down here, wherever. It doesn’t really matter. And there we have our modal. So this modal, well, I’m going to rename this like we did before. I’m going to call this insert modal as that’s what it’s for. We’re going to use it to insert a new customer to our database. Okay. So there we go. And now let’s go ahead and connect this button so that if we click on the button, so let’s get the on click event. I’m going to use it to open a modal. So just select the open modal option and then the model we want to open is the insert modal. Great. So now if I click on the button, it opens up the insert modal. This is looking wonderful. It’s exactly what I wanted. So first things off, let’s just change the text of this just like we did before to insert row. And now that we have that, I’m actually going to put in some inputs here. As to create a customer, we’re going to have to have a lot of inputs, right? So, let’s go ahead back to the widgets and search for the input widget. And let’s change the name of this to insert call input one. Again, just for readability, so that we know what we need to pick out when the time comes to it. So, in here, let’s get this some default text. At the moment, I’m just going to put in this uh hardcoded customer number, but we actually want to generate this randomly. I’m going to show you how to do that in a bit. And the label for this is going to be customer ID. So, this is looking good. And now, let’s just space that out a little bit, too. And great. So, there we have our first input. That’s what it looks like. And we’ve hardcoded a number in here. This is not a placeholder. It is a hardcoded number. And I’m just going to make this a little bit longer just so that it looks like this. Now, while we are here, I’m also going to make this feel required. We don’t need this visible toggle on. And great, this is looking good. One last thing I’m going do is just make this bold. Now, with the same technique we used before, I’m actually going to copy and paste this input again. So, let’s just copy and paste it and then just drag it underneath like so. And I’m actually going to do this a third time, too, so that we have three inputs just stacked over each other. And just move some things around so that it looks a little bit neater and better. So, I’m just going to move these buttons. I’m going to move them down here and space them out equally at the bottom of our modal. Great.

    Okay. So, now that that has been copied, I’m just going to rename some of these. So, we don’t need this copy here. Let’s go ahead and change this to insert column input 2. And I’m simply going to change the label as well to customer email ID. Okay. And the default text for this, well, we the default text, we don’t actually want any default text. We just want a placeholder this time. So, I’m just going to put in a placeholder. [email protected]. Okay. And same for the third one. I’m just going to rename this to insert column input three. And the placeholder text is just going to be Jane do. And we’re of course going to change the label too to be customer name. Okay. And let’s just rejiggle this a little bit better so that it looks nicer. And wonderful. Now, as promised, the default text, well, I want to randomly generate a customer ID. So let’s keep it the same format that we have been giving. So with a little C and then a number which I’m going to generate randomly. Okay. So we’re going to use the JavaScript uh object math floor to round down a random number. Okay. From essentially anywhere up to 10,000. So math random multiply by 10,000 will do that for us. So if you use this and again using the kali braces so that appsmith knows not to treat it like text. Tada. We will get a random number. In this case it is 1,720. Amazing. Now of course this isn’t foolproof. There is a chance that someone going to have the same customer ID but this is just for tutorial purposes. So I’m going to say that it’s fine for now. Now let’s move on. I am going to now use a switch so that we can switch if the user wants to be disturbed or not. So, let’s go back to the widgets and I’m just going to search for the switch widget and just pop it in right here and then change the label to be do not disturb. Okay, so there we go. We have the do not disturb label and okay, so now what do we want to happen? Well, on the close, nothing needs to change on this. We’re just going to close the modal. And on the confirm button, let’s go ahead and change this to insert button cuz we might want to pick this out later. And I just want to make sure that we are picking out the correct button, which is why I’ve called this insert button. And now on the confirm button, well, what do I want to happen? Well, I want a few things to happen. I actually want to run a query that will insert this user. which way yet to write. Uh but let’s go ahead and do that because we want a few things. And again, we want to chain them. So on the on click, just choose the JavaScript option. So we can write our own JavaScript. And let’s get up our two curly braces. And I’m just going to write insert query run. Again, we have not written this yet. And inside I am going to put a callback function that will run the find query after we’ve inserted our new user. So after the insert query runs, we then want to run the find query. So it’ll find all our customers again. And then we want to close the modal. So once again, we’re going to use close modal. And we are going to close the insert modal. Okay. So while I’m here, I’m just going to rename this button to reset button. And let’s carry on. So now let’s get to writing our insert query. Once again, I’m just going to click on the add query.js, create new, new communications data, and call this insert query. Now, what does our insert query look like? Well, we are going to want to, of course, the command we’re going to use for this is not going to be find documents. It’s going to be insert documents. The collection we’re going to work with is our customers collection. And the syntax we’re going to use, well, this is MongoDB syntax. We’re going to insert the object essentially into our customer collection. So for this, we’re going to get our curly braces out to create an object and we’re going to get the customer ID. Now as the value we are going to go into okay we’re going to go into the input which we called insert column input one and we’re going to get the text whatever’s in there. Okay, so that’s what we have done. And then the next thing we’re going to do is get the c let’s call this customer email ID just like we did in MongoDP. And once again as the value we’re going to get our two curly braces up so it knows not to treat this as text. I’m going to go into the insert column input two and get the text. Okay, just make sure that this is all spelled correctly just like we did in the collection. Okay. So, maybe it’s safer just to copy this and just paste it like so to prevent any spelling mistakes. And then again, let’s get our curly braces up and get the insert column input three text. Okay, so there we go. And now we also need the users do not disturb. So, let’s go ahead and get that one. And wonderful. And of course, we need the curly braces. And this time we’re going to get the switch one. And then we’re going to get the is switched on and if it is we’re going to return a one and if it’s not we’re going to return a zero. Cool. So that is how we are going to control if a label is switched on or not. Okay. So if it is it will assign the value uh one and if it’s not it’s going to assign the value of zero. Great. So I believe that is it. Let’s just have a quick check to see if this is working. So, let’s go back. Of course, don’t forget to run this first and let’s go back to here. Let’s click on the new customer. Okay. And then a random ID has been generated for us. Let’s put in a customer email. I’m just going to put test.com. The customer name, of course, uh let’s again just put in something in here. I’m going to put in test user and do not disturb. I’m just going to keep that as it is and click submit. And now if we search in here. Amazing. Our test user has been added. This is looking so good. Everything is working. Our insert query is working and we have successfully added a new user to our database from the dashboard itself. Great. So now let’s carry on. The last thing I want to do, so once again, we’ve got all the data. We’ve learned how to delete a customer from our database. We’ve learned to add a new customer from our database. I now want to edit a new customer in our database. So I’m just going to do this to the right of what we have built so far. So I’m going to get a container. So once again, let’s search for container. Let’s make this a little bit smaller so that it fits. And then I’m just going to drag that in here. Once again, I’m just going to customize this a little bit thanks to the options that we have. And I’m just going to give this a border radius of 30. Okay, so that’s what it will look like. And now I’m just going to drag in some text. So under the widgets, I’m going to find the text widget. And I’m simply just going to drag it in here like so. And call this update selected row. Okay. So, I’m just changing the text just so that it represents what we want to say. And then, of course, I can, you know, customize this further. I can give this a heading, too, just to make it a little bit bigger. And great. Now, once we have that, the next thing I’m going to do is just put in some inputs because we are going to want to change some of the inputs that we have. So, to do that, we’re going to populate the input with the selected row that we have chosen. And then we also have the option to change it. So again, under the widgets, let’s just go ahead and find well actually I’m just going to put in some Yeah, let’s put in the input. So let’s just drag in the input like so. This input I’m going to name this update column one. And the default text, well, it’s going to be the data table selected row customer ID. Okay. So, I’m just going to use whatever row we selected on the left to essentially populate this uh this uh input right here. Valid I’m going to keep as true. And the label for this is going to be the customer ID. Okay. And I can choose to make the customer ID bold, the label bold if we just click this button right here. And wonderful. So there we have it. Of course, I need more of these. So let’s use the same technique we did before and copy and paste this widget to create some more widgets. So once again, let’s rename this to update column 2. This time make the default text the selected row customer email ID. And of course, this means we need to change the label to customer email ID as well. Okay. And once again, I’m just going to copy the third one. Change this to update column 3. Change the default text to be the customer name. And then just change the label to be the customer name as well. Great. So now let’s check if this works. Let’s select a different row. And amazing. So that is changing. Everything is looking good. Now, of course, we also need the switch. So, let’s search in the widgets. And I’m just going to search for the switch widget. And I’m going to paste it in here. And then, of course, change the label of this. I’m going to change it to users do not disturb. And then we can change the alignment, but I’m going to keep it as it is. Okay. So, this is looking good. And as the default selected, well, once again, we’re going to get up our two curly braces, go into the data table, get the selected row, and get the users do not disturb. And if it equals one, this is going to be true. Okay, so as none of these really apart from I think one equal one, that should be false. The switch should not be clicked. And actually, let’s just go ahead and change alignment. Why not? And great. So amazing. This is looking good. I am liking this so far. Now, of course, we need a button to confirm that these are the changes we want to make to the selected row. So, let’s go ahead and go back to the widgets. Search for a button widget and just drag it in here. I’m just going to rename this to update button so that we know what we are working with. The label of this uh I’m going to change it from submit to update so that it’s makes more sense. And then on click we’re going to execute a query. This is going to be a new query, one that we haven’t written yet called update query. So let’s go ahead and rename this to be update query. And this time we’re going to update a document. We’re going to do this in the customer collection. So let’s just change that to say customer. And we’re going to just kind of like we did before. So the query we need for this. Well, we’re going to go and look for the object ID. So ID and that’s going to be the object ID of our data table selected row ID. So just to make sure that we are actually updating the correct document and then what are we going to update? Well, we’re actually just going to have to write the same object again with the new values. So we’re going to update we’re going to get up our curly braces. We’re going to get the customer ID and then of course we are going to well in fact we can actually copy this from the insert query as it’s just the same. So let’s go back to our insert query and I’m just going to copy all of this and on the update query just paste it. However, we are going to change the widget that this is reading from. Right? So instead of insert column, I’m going to change this to update column one just like this. And of course update column 2 as that is the column that we want to read from or that is the input sorry that we want to read from. and update column three as well as well as switch two. Okay, so just make sure to change those out as well or change them out to whatever you called your own widgets. Great. So let’s click run and let’s test this out. So if I go ahead and just make sure you’re selected on one of the rows. If I go ahead and just change some of this. So first off, let’s just make sure that the button is actually going to run the query. So on click update query run and then on success once again I’m going to find run the query find query. Okay. And also on error I’m just going to show the alert so that we know that an errors has happened and the alert is going to say error while updating resource. Okay. So this essentially is going to show up if there is an error in our uh update query running. Okay, great. So cool. Shall we check this out? First off, actually, let’s just make sure that we can read this. So to make sure that the label appears on top, all you have to do is just stretch out this widget just like so. I’m just reformatting it so that we can see things a little bit better and just in general making sure that it looks a little bit nicer for us. Okay, so we are now officially done with this page. Everything’s working. We have essentially we have essentially learned how to get data from our database, delete data from our portal, add a new customer from our portal, and update an existing customer from our portal, too. Now, the next thing we want to do is be able to send messages to these customers based on their options and what mailing list they are associated with. So, to do this, let’s just go ahead and create a new page. So to do this, let’s just go over here to the left and all I’m going to do is just press on the plus button next to pages and a new page will be created for me. Once again, we have the two options. I’m going to choose to build with drag and drop. And let’s rename the page while we are here. I’m going to choose to call this the send messages page so that we know what is happening on this page. And now let’s get to selecting our first widget. In fact, we can actually copy how the customer data page looks like. I’m just going to select the header and just paste it in here like so, which makes our life a lot easier. And let’s rename this to be the marketing portal. Okay, just like so. Just so that it’s very clear that this is separate to the other page. And let’s go ahead and change this image too. So once again, this is one I found on the internet before. So you can use it as well or you can use your own. It is completely up to you. Okay. So it’s a loudspeaker here as I feel that kind of symbolizes what this page is going to be about. So next up, I’m just going to start, you know, creating what the layout of this page should look like. So I’m going to go into my widgets. I’m going to search for the container. Okay. And then I am simply going to drag in a container just like this. And then I want to put some text into this container. This text is going to be here. And it’s just going to show us essentially how many customers we have to work with. So let’s change the label of this to total customers. So go ahead and change the text widget like so. And we can also change the text color. Now, if I don’t like any of these colors, I can choose my own. So, I’m simply going to change the hex value of this. Just like that, so that it’s a lighter gray. Once that is done, I’m just going to drag in another text. This time, the text of this is going to I’m just going to hardcode it to be 0 0 for now. We are going to change this later. This will be dynamic based on our database and the amount of customers we have in there. But for now, just leave it as this. Okay. And I’m just going to change this to be a heading one. Actually, let’s make it a heading one. Wonderful. So, once we are happy with what this looks like, I’m just going to shift these things around a little bit. Okay. Just like so. And I’m just going to put in an icon. So, I’m going to search for the widgets once again. And I’m going to put in a icon button. So, just paste that in here like this. And this is just going to symbolize visually what this section is all about. So I’m going to search for people. So there we have our people icon. And I can also change this to be a secondary button just like this. And we can also make it more of a uh rounded square if we want. I’m not going to give this any functionality. I just wanted to kind of show what this section is all about. Okay, great. And let’s also give a border radius to the container itself. So make sure you’re actually on the container when you do this. Wonderful. Now again, we want to show a lot of other statistics too, not just how many customers we have. So I’m going to copy this whole container and everything in it using the copy face functionality. And I’m just going to drag in wherever I want these other containers. So there we go. I do want four. This is going to store our major analytics if you will. So let’s change the name of this. The first one I want to say reachable customers as this is going to hold the statistics for our reachable customers which is essentially all the ones with do not disturb not on. And let’s also change the icon for this. So I’m going to make this an icon that symbolizes reachable customers just like so. So, I’m going to choose this one right here. Now, let’s move on to the third analytic provider. This is going to say do not disturb customers. Okay, so essentially we want to show how many customers have the do not disturb on. And let’s change the icon of this to symbolize that too with the blocked person icon. And finally, on the third one, we’re just going to have mailing list count. And this will just be how many mailing lists we have on our dashboard. And of course, let’s change this to be some kind of list, too. Great. So, this is looking good. Now, let’s get to displaying the mailing list we have and adding the option to add a new mailing list if we wish, as well as show exactly who’s on these mailing lists and then add the option to message these people as well. So, let’s do it. So once again, let’s go into our widgets and I’m going to choose the container. Just drag it in here like so. And then I’m also going to choose a second one too. So once again, let’s give the container the border radius this time of 15. And just do the same for the other one as well. Okay. So on the left, we’re going to have our marketing list. And on the right, we’re going to have all the people that are associated with that marketing list. So to do this, well, let’s actually just put in some text to visually show what these two sections are about. So let’s just drag in some text. And I’m just going to rename this to marketing lists. Okay, just like so. And make sure this is a heading, too, just so that it’s a little bit bigger and we can read it. Great. And once again, for the other side, just drag in some text. And this time let’s give it the text of please select a marketing list to view the users. Okay. And once again let’s make this a heading too. Just make sure that it kind of fits in a nice way. Now we are going to use a cool widget and this is going to be a list widget which allows to map on different things from our database directly onto a list. So if I search for list and then I just drag it in here like so. Okay, there we go. At the moment it just has some default values from the default values on the right. We want to replace this with our data from our database. Okay. But to do this, of course, we’re going to have to put in that data. So, we will do this in a bit. I’m just going to finish off styling this section first because we want to also add a button to actually create a new marketing list as well. So, in the widgets, let’s search for button. And let’s just drag in the button. And on the label, I’m just going to select new because we want to be able to add a new marketing list. And of course, we also want an icon to, you know, symbolize that we’re adding a new list as well. Great. So now I think I’m ready to start using our data source, which is the communications data to write another query. So first off however let’s go back to MongoDB because we need to add some dummy data for us to start working with. So back in MongoDB under the marketing lists I am going to insert our first marketing list. So go ahead and just make sure marketing list is selected as a collection and insert document. And once again I prefer to work with the JSON. So just go ahead and select that JSON option.

    So once again, don’t forget that comma. And what is going to make up our marketing list? Well, each marketing list is going to have a Discord web hook because we are going to want to direct anyone from this marketing list to a channel on our Discord. So as an option, you can have So let’s go ahead and put Discord web hook right here. And now I’m going to leave this blank because I will be showing you how to do this later when we start working with the Discord uh web hooks. So just leave that blank for now. I will come back to it in a bit. The next thing we want to do is also add a creation date. So the creation date uh well I’m just going to put in a creation date that I have pre-written for you in the ISO format. Okay. So this is the format that we are going to use for the creation date. Okay. So there we go. And the next thing I’m going to do is put a mailing list. And this mailing list is essentially just going to be the name of the mailing list itself. So on this occasion, it’s going to be bugs because we have a mailing list about people who want to know about bugs. Okay. The next thing we’re going to do is just have the mailing list ID, which once again is different from the document ID. So, let’s go ahead and put in a random mailing list ID like so. And finally, we’re also going to have an icon. Okay, so once again, this is just an icon that I have taken off the internet of a lock. You feel free to use this for tutorial purposes or please feel free to use your own. And finally, we’re going to have the users associated with this marketing list. Okay, so here we are. Here is the users associated with this marketing list. This is going to be an array of users based on their user ID that we have written. So I’m just going to put in some users in here. Again, this is like kind of random. It doesn’t really matter which ones you want to use. Please feel free to use whichever ones you wish. Okay, so I believe we only have up to 10. So I think this is fine for now. Let’s just have these three. Wonderful. So there is our first marketing list. I’m just going to copy all of this to make our lives easier when it comes to making the next one and insert this one into our marketing list collection. Great. So this is now done. Let’s go ahead and create a new one. Once again, don’t forget the comma. And I’m just going to paste this in here, right? So, and reformat it a little bit. And I’m just going to change the uh a few things. Let’s just change the creation date. Let’s change the mailing list name. This time it’s going to be products. Let’s change the ID as well. Let’s change the icon, too. So, once again, this is one I found on the internet earlier. This is uh one of a loudspeaker which we used before as well. So, I’m just going to use the same one for this. And the users associated with it. Well, I’m just going to add a few in here. In fact, perhaps maybe let’s add all of them. Let’s just pretend that everyone wants to know about the product updates. Everyone wants to be on the product mailing list. Great. So, there we have it. I’m just going to do a few more. So, let’s go ahead and insert another document. Don’t forget the comma format. Change the creation date name. Change this mailing list name to be something else. So this time it’s going to be feedback. Change the ID as well. And I’m also going to change the icon. This time it’s going to just be a heart. So let’s just go ahead and change that. Once again, you don’t have to use this one. Please feel free to use whatever you wish. And sure, let’s just change some of these users around and insert. Okay. So just one final one now to insert. I’m just going to again use the comma, reformat, change the creation date, change the mailing list uh to be all about

    the welcome mailing list. Change the ID and I’m going to change this again. So once again, just change the icon. Just changing these few digits around and just adding a cake. Okay, so again, I’m not making this up. This is one that exists and is hosted on the internet. And the users, well, we should probably have all the users. As you know, everyone should be on the welcome list, mailing list. So, I’m just going to add all my users in here like so. And just click insert. Great. So, wonderful. Now that we have our mailing list, what we can do is of course go back to writing our query. So, I’m going to use the communications data once again. And the query we’re going to write is get marketing lists. Okay. And we’re going to find documents. And then of course the collection this time is not going to be the customer collection. It’s going to be the marketing list collection that we just added some documents to. So if we click run, you will see exactly that. You’ll see all the objects that we made that will represent our mailing lists. Wonderful. So there we have it. So now if I click on the lists, I’m going to just get rid of this data and we’re going to use our query that we have just written. So the get marketing list query and get the data from it. Okay, so it really is that easy. And now we’re going to use that data to essentially map out things onto our widgets in here. So if I click on the image and get the current items icon, it will replace it with a icon from the object that we wrote. Okay, so the current item is a list item thing that will use the data that is coming back to us and then it will just use whatever we call this uh we call the icon with a capital I. So that’s what we need to get. And we can also just edit this text right here. So if I select this text and this time let’s get the mailing list itself. So I’m just going to copy that and change this to be current item mailing list. It will change it to the title of the mailing list. How good and how easy is that? So now I’m just going to delete this second text. I’m just going to reshuffle some things just to make this a little bit nicer and just so that we can perhaps see more of these on the marketing list first page. And there we go. That is immediately looking better. I can see three at least. And this is looking wonderful. It’s doing its job. We are seeing all the marketing lists to our disposal. Wonderful. So, now that we’ve done that, let’s actually get to adding a mailing list from the platform itself. similar like we did on the customer data page. So to do this, we’re of course going to need a, you guessed it, a modal. So let’s go back to our widgets and I’m just going to search for a modal. So once the modal has been added, again, you could just drop it anywhere. We’re of course going to just change the text in here. I’m going to change this to create new mailing list. And I’m actually just going to make this a whole lot bigger as we’re going to need a few things in here. So, what do we need in here?

    Well, the first thing we’re going to need is a input. We’re going to need a few inputs because we’re going to have to essentially replicate the objects that we just made from the dashboard. So, let’s drag in our first input. And this input uh well let’s change the name of this to list ID as that is what it’s going to show. And the default text for this again we’re going to randomly generate a uh list ID for this using an M to start with and then the curly braces so that it knows not to treat these JavaScript as text. We’re going to use math floor to round down the random number that is generated thanks to the math JavaScript object and random method when it’s multiplied by 10,000. Okay. And valid. Well, we’re going to only make this valid if the list ID text length is larger than zero. Great. So, that is how we do that. And then the label itself is going to just say list ID so that it’s very clear to the user that the list ID goes here. And let’s just make that bold as well. Okay. So once that is done, I’m simply going to copy this. Okay, copy that whole widget. Let’s change this. I don’t want any default text. And I’m going to change the label to be icon URL so that people can put the icon in here from the internet too. And let’s just rename this to icon. Okay. So there we go. And I’m just going to put that up here. And then just maybe make it a little bit longer as well cuz URLs tend to be quite long. Great. So now let’s go ahead and copy this once more and drag it up here. And this time I’m going to name this list name. And the default text I’m going to delete as well. And the label is just going to say well list name cuz this is where we’re going to store the name of our new mailing list. Great. So this is looking good. Of course we are not yet done. There’s still a lot of things to do. Now once again we need another input. This time for the web hook. So, let’s just go ahead and I’m just going to remove this valid and change the label of this to say Discord web hook URL just like so. And of course, rename this to say web hook. Okay, so there we go. Now, I’m just going to move these buttons down. We can actually select both of them at the same time. So, that’s what I’m going to do. And I’m just going to move them down here. Okay. So, there we go. I’ve moved them down to the bottom. And now I’m just going to use a divider just to space things out a little bit. So that is another widget that you can use. And of course just make sure that it looks exactly how you want thanks to the drag and drop functionality that AppSmith gives us. Great. Now I am also going to add an image so that we can essentially preview the image URL that we want to use. So for this I’m just using the image widget that I am resizing and that will essentially show the image URL that we put in the icon URL input. Great. So we can do this by simply selecting the image and on the image I’m going to get the icon as that is what we call the icon input text. Okay, so that should now work. And the last thing we want to do is just select which customers from our customer database we want to put into this new mailing list we are creating. So to do this, I’m going to select the table widget. I’m just going to grab the table widget and just paste it in like so by dragging it down. And of course, we are going to get rid of all the generic data that we have here. And we are going to essentially use a query in order to get all of our customers again. So I’m going to call this something different. I’m going to call it get all mailing list customers. Okay. Uh and this just means that we need to write a new query based on the communications data. So I’m just going to paste that in here like so. And I’m going to find the documents. And what I’m going to do is look in the customers collection. just click run to essentially get all our customers back. Okay. So again, it’s the same query we wrote in the first page we’ve just written again and called it something else. So now let’s just get the modal up again. I’m just going to do so this time by just selecting the modal. So just here. Okay. So there’s our modal again and just click on the table. And I’m just going to make sure to get the data from this query. And I’m also going to filter out each customer by the customer user do not disturb equals zero. Okay. So that is what I have done right here. And I am also now wanting to add a way to select multiple customers. Right? So before we do this, I’m actually going to make the user do not disturb not visible as well as the ID. And down here on the options, I’m going to enable multi row selection. So there we have it. Now we can select multiple rows essentially. I’m also going to just make sure that sortable is not true and enable client side search is also not true as we don’t need this. Great. So this is looking good. I’m selecting loads of different rows. And on the close button, I’m just making sure that the event to close does actually close the modal modal one. So, this is looking good. And on the second button, let’s actually rename this to form button one. I’m actually going to add a label. And the label is actually going to show us how many customers we want to add to our uh mailing list. So, I’m going to use the word add. And then I’m going to use our curly braces to go into table one selected row length. Okay. So if we selected three from table one, it will show me the number three. And then I’m going to use the words user to list. And I’m just going to show the list name that we have chosen to call this mailing list. At the moment, of course, it’s just nothing because we haven’t chose a list name to put in the list name input. Great. So, this is looking wonderful. And now on click, we of course want to execute a query. And this is going to be a new query. And this query is essentially going to let us add a new list to our mailing list. So, add new list. Uh we want to insert a document. The collection of this is going to be the marketing list and the document. Well, we can actually go ahead and copy all of this because that is what we want our object to look like. So, just go ahead and make sure to format this correctly. So, I’m just getting rid of all the spaces. And of course, the web hook, we’re going to leave this as blank for now. And we need to add the double quotes in all the right places, too. So, I’m just formatting this all a little bit just like so. For now, I’m just going to keep all of this hardcoded until we finish formatting because I’m going to have to replace some of these a little bit. So, now that we have all of that formatted, well, the Discord web hook, we want to get the value from the web hook input or the input that we called web hook and we want to get the text. So, making sure that’s in curly braces so that the platform knows that this is not text. Okay. And again, we’re going to do so for the creation date. This time, we’re actually just going to use today’s date. And we’re going to use moment for this. Moment is a dependency, an npm dependency that we can use that has been already put into AppSmith for us. And to get the correct date, we are just going to format it correctly like so. So saying that we want the year, the month, the day and the format that we used in when we were adding the documents manually in MongoDB. Okay, so there we go. And the mailing list name, well, this is just going to be the list name text. Again, we are grabbing the input which we have called list name and getting the text that we put in that input. And same for the mailing list ID. Once again, we’re getting the list ID and its text just like we did before. And finally, we’re going to get the icon. And this is simply going to be from the input that we called icon. And we’re going to grab its text. And great. So now, let’s check if this works. Let’s go ahead and just select the modal. So up here, because we haven’t actually connected the button to the model yet. And we also need to add the users. And the users is essentially going to be an array of the users from the table that we have selected. So let’s go ahead and do that. I’m going to call this users and I’m going to go into table one. I’m going to get the selected row. I’m going to map for each element the customer ID. So we’re just going to return back the customer ID from each of the objects. Okay. So great. So now let’s test it out. I’m going to go and find my modal because we haven’t hooked up the modal quite yet. We’re going to have to find it to get it up. And let’s put in a list name at the moment. I’m just going to put test. Let’s find a test icon that we can use and just whack it in here like so. So, the preview is working. That is good. And let’s just select some of these. So add three items to the list test list and just click the button. Now on click what do we want to happen? Well on click we want to essentially run the query add new list run and on success we’re just going to close the modal and the modal is called modal one. Perhaps we can change that later but for now I’m happy with that being modal one. So let’s run this and check if that has worked.

    And great. So there we have it. We can now see our new list, our new marketing list. This is all looking great. Okay. So now that we have managed to get our marketing list and add a new marketing list from the platform itself, let’s get to actually displaying the users associated with that marketing list when we click on it. So to do this, this is relatively simple. We’re just going to grab the table widget. So let’s go into our widgets and find the table widget and drop it in here like so. And we know what to do now. We of course need to get the correct data shown up here. So to do this, I’m going to write a new query. So just go ahead and click on the queries on the left. and we’re going to use our communications data. So let’s just click on that and let’s call this get customer list. Okay, so the get customer list well we’re going to find documents and we’re going to look in the customers collection and the query we’re going to write for this well we’re going to have to look if the customer ID is essentially in the marketing list we have chosen. So we can do so with this MongoDB syntax. Let’s get up our curly braces. Let’s get the customer ID and using the dollar sign and in we’re going to look and check if the list we selected. So the list widget selected item users. Okay. And if that exists then we’re going to return back the customer associated with that ID. First of all, of course, we do have to select one. So, select one from the list one and click run. Now, we aren’t getting anything back. However, let’s just try sort by customer ID. So, just put in this right here and just try click run again. And that has not worked. So, we’ve encountered our first issue. We need to debug. So, a quick way that I would do this is just simply look in MongoDB and check why the customer ID is not matching the marketing list ID. And you will quickly see it’s because we used a capital C on the customer ID and we used a small C on the marketing list. So, let’s go ahead and quickly change that. I’m just going to change these to small C’s right here as that will be the easier option. So I’m just changing all of these to small C’s just like so. So there is tend to update. I’m just going to quickly go ahead and do that. But that is how it would quickly debug if some data issues are happening. I’d always go to the source. I’d always go to MongoDB to check what that data is looking at. Perhaps it’s a string or and you’ve said that it should be a number. It could be a variety of different things. On this occasion, it’s quite a simple fix. So I’m just making sure that the ID is exactly the same as what we wrote in our marketing list. Great. So now if you run this, tada, we will get the data coming back to us. Okay. So these are all the users associated with the marketing list I selected on the dashboard itself. So that was the bugs. And if I now connect this, so instead of using this data for the table, I’m going to get rid of this. I’m going to get up our curly braces. I’m going to use the get customers list data. And tada. So now if I click on a marketing list, it will show me all the users associated with that marketing list. This is looking so good. How easy was that? Now, another cool thing we can do is actually change the text in here to show exactly what list we are looking at. So, if I select this text, I’m going to say that I want it to say I’m just going to cut all that because we’re going to use that later. Get up our two curly braces. I’m going to get the list one selected row. I’m just going to get the mailing list so that it shows the name of the mailing list we have selected. And if the length is bigger than zero, I want it to show the list one select a row mailing list name essentially. So just what we saw otherwise I just wanted to show please select a marketing list to view users. And we can actually get rid of this word users here because this users can be used for either one of these. So I’m just going to get rid of here and put it there. So now if you select on any marketing list, it should show the right title in the container on the right. Great. So this is looking wonderful. Let’s carry on. Okay. So now back on the table just here, I’m going to hide some of these columns. So I’m just going to hide the users do not disturb and the ID as we do not need these things. And I’m also going to choose to have the primary key column as the customer ID. I’m also going to choose to write some JavaScript to where this is visible or not. And this is going to be visible based on if the list one selected item ID is essentially larger than zero. Okay. So essentially if it exists. Great. And one last thing I’m going to do is actually add a uh enable multiple row selection so that we can choose who we want to email from this list as well. We can choose to email everyone but also we have the option to not email them if we wish. Wonderful. So now that we have that done, we actually need an option to email the users. So for this I’m going to use another button. So let’s go ahead and select a button widget so that this brings up a model for us. So this button right here. And let’s just go ahead and change the text to say connect with. And then we’re going to have the table to selected rows length. So make sure that’s rows multiple length users. So it will show us exactly how many users we have selected. At the moment it is one. So it will say connect with one users. And if we select more that will update to show us how many users we have selected. Okay. So great. And I’m just going to change this visible and put in some JavaScript to only make this visible if list one selected item ID length is larger than zero. So essentially if it exists and we’re also going to make this disabled. So again let’s enable the JavaScript if table 2 selected rows length equals zero. So if there is zero selected this button will be disabled. Okay great. So as you will see if I don’t select any that button is now disabled. Wonderful. And there we go. We have now enabled it again. So great. And now of course we need some events to add to this button. So on click what do we want to happen? Well on click we actually just want to open a modal. This modal we are yet to create. So let’s go ahead and create that modal now. So I’m going to go in here and I’m just going to create a new modal. And let’s call this the message modal as that is what this will be. It will be a message modal that will essentially send a email or a discord message or both to the users we have selected. First things first, let’s go ahead and change the text of this. I’m going to change the text of this to say send message just like we were doing previously. And the message we want to send, well perhaps let’s actually make some options. So, I can do this with a tabs widget. So, if you search for tab widgets and just place it in here, this is what it should look like. I’m also just going to move these buttons around. So, once again, I’m going to select both buttons and move them to the bottom of my modal. And this is to make the tabs stretch all the way out. And I’m just going to move some things around in here just to make things look a little bit better. Once we are happy with the layout, I’m going to select the tabs and I’m just going to change the tabs name. The first one is going to be the base text. That’s going to apply text to both the email and the Discord. And then I’m going to have a separate tab for the email as well in case we want to alter that text. And of course again for the Discord in case we want that text to be different as well. So there we have our three tabs. The next thing I want to do is just actually put in a rich text editor into all of these. So, I’m just going to search for that and I’m going to drop it in here. Uh, and first off, actually, let’s just put in some normal text. So, this text is to show what exactly we want to happen here. And I’m going to say I’m going to use actually some HTML to make this bold. Enter your base text. And then just a normal text. I’m just going to put you can edit this message uh for your email and Discord from those separate tabs. Okay. So, that’s just a little bit of an explainer. And the next thing we’re going to do is actually grab that rich text editor and just put it at the bottom like this. Okay. And of course, we can have some default text, but I don’t want to. I’m just going to leave it blank. And I’m actually going to grab all of this and copy it and paste it in the email section too. And just change the text of this a little bit so that it better represents what is happening here. And that is just going to say write your email. And this is really all I want in this section. Uh I’m also going to have an input perhaps for the subject too. So let’s go ahead and put in an input. And let’s put the label as subject. And this is of course going to be for the subject of the email. And also the one thing I want to do before we move on is actually change this to say email text so that we can pick out whatever’s in the text editor and that we know this is coming from the email tab. So let’s change this to email text. And back on the base text, let’s also change this to base text. Okay. And finally, on the Discord tab, once again, I’m just going to paste everything I did before and just change this text around just so it better represents what is happening here. And of course, we also need to change this to say Discord text so that people know where this has come from when it comes to picking it out later in this tutorial. Now, one other cool thing we can do, I’m just going to move this up to show you. You can put this on all the tabs or you can just have it here. Is actually to show a count of the characters. So I’m just going to do this simply by grabbing the text component or widget and dropping it in here. And instead of having some text, I’m going to use the Kylie braces so that this is is not text and get the Discord text length. Okay. And then I’m just going to put characters. So now we will know how many characters are used in this Discord text widget. Okay, great. So now I did say that I would want whoever is using this to choose if we want a message on Discord or email or both. So I think the perfect example for a switch is this use case. Let’s go ahead and grab these switches and I’m just going to drag one in below the tabs. Okay, I want this to be applied to the modal and not the tabs. And let’s change the label of this to say Discord switch. And just put in another one that will say email switch. And we’re going to link this up later. And while we are here, I’m just going to make the buttons a bit bigger just so they look a little bit nicer and just make sure that they are looking good. And on the confirm button, we’re going to execute a query that will essentially send messages. So what we’re going to do is actually write a JavaScript object for this. So this is going to be a JavaScript object as we’re not simply just going to run one query. We’re going to want to do a lot of things in here which is why we’re writing a JavaScript object. So let’s create a new JavaScript object. And I’m just going to call this object utils just to make it more clear what this is. uh and let’s just go ahead and delete all of this code right here as it is not really needed. So now the function that we want to write and essentially the JavaScript we want to call when clicking that button is something called send messages or as we are going to choose to call send messages. And what we want to happen is so if the discord switch or the widget that we call discord switch is switched on we want to essentially get the discord API to run. So we are yet to write to the discord API. So for now we will come back to that. And we also want to show a success message. So let’s define our success message. I’m going to call this success message one as we will have two. And the message we’re going to have is Discord message sent to. And I’m just going to concatenate the list ones selected items mailing list. So whatever item we have selected from the list, I’m going to get the entire mailing list and I’m going to concat server. So it’s going to show us all the uh mailing list that we have sent messages to, Discord messages to. And we’re just going to put this in alert. So show alert. And I’m going to put the success message one in here just like so. Okay. So, this is great. But also, what happens if the uh email switch is on, right? So, I’m just going to copy all of this and change this out. So, if email switch is switched on, well, we also want the send email query to run, which again we are yet to write. And let’s just change the success message. I’m just going to name it two just to differentiate from the other one. And I’m going to say email sent to and to use this on. And I’m just going to again concatenate it and just use the word list at the end and show the alert. Okay. And then I’m going to reset the widget. And the widget I want to reset is the message modal. And I want to close the modal of message modal. So we’re resetting it. So we’re emptying out all the fields and we’re closing that modal. Okay. So that will run after both of those if statements have been checked. Great. So this is looking good. Let’s carry on. So now I think we’ve come to the point where we should write our Discord API. So let’s go ahead and add a new query. I’m going to create a blank API and I’m going to call this Discord API. And we’re going to have to grab a web hook. Of course, we don’t have any web hooks yet, but we can actually just get the value of the web hook. So, I can do so easily by getting into the list and getting the select rows Discord web hook. At the moment, they’re all blank, but that is fine. As soon as we populate them, this will work. And as the key and value here, I’m just going to put the content type. And I’m going to fill this out with application JSON. So, make sure to do this like so. And of course, let’s also not forget to get the body because the body is going to be that of the Discord uh the one Discord text that we have associated with the rich text editor on the Discord tab. So make sure all that is done and make sure that this is a post request and just click run. Okay. So now that is done, let’s carry on. The next thing we need to do is be able to send emails. So again, let’s write our send email query. So to do this, I’m actually going to have to create a new resource and just click on the SMTP resource right here. and let’s call this send email. So just go ahead and do that. And now let’s do some configuration for your Gmail account. So if you have a Gmail account, I would suggest if you don’t have a Gmail account, I would suggest you get one because this is going to work with a Gmail SMTP. So the host address for this, well, the host address for this is going to be smtp.gmail.com. And the port there is a few. So I’m just going to put in two to be sure. So the port that we are going to use is the port five 587. And I’m going to put in the other one too because you never know. The second port is going to be 465. Making sure to of course put the host address as the same. And we are going to use authentication. So authentication is just simply the credentials you use to log into your Gmail account because we’re going to essentially be using your Gmail account to send out these emails. So I’m just going to put Anna at freecode.org and the password associated with that account so that I can log in to Gmail. Now you would think this would be it, but we are not yet done. Gmail uses some extra security that we’re going to have to configure. So I would suggest clicking run and you will get an error message. This is good as it will show up in your email address that some funky activity has gone on. So you will see sign in attempt was blocked which is great but it also means we need to unblock this attempt. So less secure app blocked. Let’s just go ahead and click and get more information on this. And then I’m simply going to scroll down in here. Click on this button right here. I’m just going to verify that this is me and I’m going to allow less secure apps off be on. Okay, so this will allow me to give access to essentially all less secure apps including this one. So this means that if I now click test, that should now work. So don’t forget to do that. If you have any issues, that could be why. And let’s carry on. So now that we have added our resource send email, I’m actually going to also have to write a query. So we’ve got the data source, let’s write the query. Now I have named this to be send email. So let’s just name the query send email again. So let’s write a new query using the send email data source and I’m just going to call this send email again. Now the command we want to do is send an email. That is correct. and from the email address. Well, that is just going to be from my email address. So, I’m just going to put in that in here just like so. And the two emails, well, we’re going to have to get the emails from the mailing list that have been selected. So, once again, let’s get our curly braces and I’m going to go into the utils and we’re going to actually write our own JavaScript for this. Okay, instead of writing everything in here, I’m just going to put in the retails as that is easier. So let’s call this get emails and let’s have the subject of this be communications sent via communications dashboard as that is what this dashboard is called and the body of our email is just going to be whatever the email text is text. Okay. So whatever we have in the email text rich text editor text is going to be body of our email and the subject will never really change unless we want it to. Okay. So if you want you can connect the input that we have chosen for the subject here but that is optional too. And oops this should say get emails. So let’s just change that to get emails. And let’s write this in our utos file. So once again, let’s actually describe this. Let’s actually write this out here. So I’m just going to use get emails. And what do we want to happen? Well, what we want to happen is we want to first define the name array. And that is going to be the table to selected row. And for each row, we’re going to get the customer email ID. So each customer email ID or essentially each email will be be mapped or essentially each email will be stored to this name array and we’re just going to return the name array to string. Okay. So now we have essentially got all the customer emails associated with the selected row of the table and this means that we can now use get emails. So get emails and just call it. Okay. So, let’s check if that has worked. So, I’m just going to go ahead and try send a message. So, let’s get up our modal. Let’s click on the email tab. I’m actually going to put the default text of this as the base text text. And then we can change it if we want. And I’m also going to actually do this for the Discord rich text editor, too. So, make sure to click on that. And under the default text, we’re going to go into the base text and just grab the text like so. And of course, we can edit this if we wish. Okay, so wonderful. Let’s just check this works. Of course, perhaps we should put our own email in here to email ourselves to. So, let’s just go back to the query. And I’m just going to put in my own email address. Okay. And just click run. So, that says that that has been sent successfully. Let’s check it out. And great. So I have indeed received that email. This is looking wonderful. This has worked. And let’s check if it works from the dashboard itself. So once again, let’s just get up the model and click confirm. And let’s make sure that this actually runs the query runs the thing that it needs to run. So let’s click on utils and then let’s click on the send messages util. Why is this red? Uh, we need a default tab. So, let’s change this to be base text. Okay, great. So, we’re sending emails. Everything is working. Everything is looking good. There’s the last few things we need to do and that is actually just hook up the analytics on the analytics tabs and then actually link up the Discord web hook to Discord. So, first let’s do the analytics uh as that should be relatively easy. So let’s go ahead and select this first analytic and I’m going to write a new query. So let’s go ahead and create a new query using the communications data and call this get all customers list. And this is just going to find documents and it’s just going to look in the customers collection just as we’ve been doing previously. And I’m just going to run it. And now this means that if I get the curly braces up and use that query and just get data length, it will show me exactly how many customers we have in that list which is 10. That sounds and now we’re just going to get the mailing list count. This is easy as we’ve already written this query. So just get the query to get the marketing lists, get the data length, and that’s it. Great. Next one. So for this one, we just want to show the users that are reachable. I’m going to write a new query for this. In fact, let’s actually write this in the utils file. So let’s get up our utils file again. And I’m just going to not forget the comma and write a function that will essentially show us everyone on the do not disturb list. So let’s call this dnd list. And I’m going to save the dnd count. And as default, it’s going to be zero. I’m also going to say the reachable and also make that zero. Now what we are going to do is get all customer lists. So the query we just wrote, I’m going to get the data and for each uh I guess user coming back to us, I’m going to get the user do not disturb and if it equals zero, I want to add to the DND count. However, if it uh does not equal zero, I’m going to add it to the breachable count. Okay. So, great. And then I’m just going to return. So, let’s define what I’m going to return. And I’m going to return an array. The first object is going to be for my reachable. So, I’m just going to make an object that has X as the string reachable and Y as the DND count. And X and the second object is going to be for my do not disturb and Y is going to be the reachable count. Great. And I’m just going to return this. So now I can use the util. I have wrote the dnd list. Of course, we need to use utils dot. That is the correct syntax. And I’m just going to get the go to the second item in my array and get y to show the reachable customers. And then I’m also going to use the do not disturb. And the same thing. So I’m just going to copy and paste all that. But this time I’m going to go to first item from my array and get the y value for that. Okay, so seven reachable customers and three on the do not disturb. This is looking correct and great. So we’re nearly there. The last thing we need to do is I’m just going to show you how to use the Discord web hook. So for this you need to actually have a Discord account. Okay, so get up your Discord account and if you haven’t already, I want you to go ahead and start a new server. Okay, because we’re assuming that you own a server and you want to message everyone on your server on a certain channel about a certain thing. So, for example, uh if I have a server and I have a channel all about bugs, I want to email everyone on the bugs channel about the bugs. So, to do this, let’s create a new server. I’m just going to put for me and my friends and I’m going to create it. And now once I have done that, uh let’s just I’m going to show you how to do this on the general channel. Okay, of course once you know how to do this, you can connect the correct Discord web hook to the correct channel, but this is a tutorial. So I’m just going to show you how to do it and you can do it yourself. Now on general, I want you to go ahead and just click on the cog. And once you’re on here, I want you to get integration and just essentially create web hook and copy the web hook link. And once we have that, I’m just going to go on the first marketing list and I’m going to get the first object and in here I’m just going to paste it in. Okay, so on the mailing list of bugs that now has a Discord web hub link, which will essentially just post to my general channel on my Discord, but you get the drift. So now, let’s check it out. So, if I go back in here and make sure that Bugs is selected on the mailing lists and click connect with two users, I’m just going to go ahead and click confirm

    and great. So, that has now been sent. Amazing. We’ve done it. We’ve got the whole app working. This is looking fantastic. I hope you’ve enjoyed this lesson. We have a few more things to do, and that is just deploy this. So, just bear with me. Let’s do it. But I hope you’ve learned a lot so far, and I hope you know now how to add your own Discord web hook links, too. So to do this, all I’m going to do is just press on this button right here to connect to Git. And once done, I need to get a remote URL to a repository. Well, we need to make a repository first. So all I’m going to do is click new right here and create that repository. I’m just going to choose to add a readme and create.

    Now once that is done, I’m just going to grab this URL like so and paste it in here.

    I’m also going to have to give Appsmith access to my repository. So, let’s copy this SSH key and go back to GitHub. And now under settings, I’m just going to click deploy keys and add a deploy key and add that key in there and name it and click add key. And that’s done. Let’s just connect commit and push. And tada. Let’s preview what we committed. And there is our app and it is saved on our GitHub. Okay, so there we have it. There’s our wonderful app. As you can see here, we’ve got two tabs. We can send messages. We can also filter through bugs and all our marketing channels. And of course, we can see all our bug users and all our mailing lists and everything like that. Thanks so much again for watching. I really hope you’ve enjoyed this tutorial and I hope you love your new app.

  • Code a Minecraft Clone with JavaScript, React, Three js – Tutorial

    In this course, Daniel Bark will teach you how to code a fully functional Minecraft clone using React, JavaScript, and 3JS. Daniel is a senior software engineer from Sweden. You will create a game that supports five Minecraft block types. It will include moving, jumping, switching and placing blocks, saving, and more. You will learn about many React concepts such as use state, use effect, use ref, and custom hooks for state management. and you’ll be able to apply the principles to create other 3D games in JavaScript. All right, so let’s get on with the tutorial. And to begin with, let’s have an overview of the steps we’re going to take in this tutorial to build a Minecraft clone. So, first we’ll look through the code that we’re starting out with and the packages that we’re going to use. Then we’ll add our first 3D element, which is a skybox that will wrap the entire world. We need some images that will be used as textures on the ground and on the cubes. Uh next up, we’ll use a plane as the ground and our player is going to interact with that ground. Um so the player is going to get a firsterson view. We’ll mount a camera to a sphere and that will feel like a firsterson game. Then we need to have some gravity. We need to make sure that the player cannot fall through the ground and when you jump you should fall back to the ground and so on. We need some movement to go back and forward and to the sides. And then we need some state management because we need to keep track of all the cubes in the world. So you need to be able to add and remove cubes in a global state. So we need to keep track of that. And then we also need to keep track of what type of cube the player want to add to the world. So we also need some type of UI that indicates what cube texture is active. It would also be nice if we can save our world so we don’t have to start from scratch every time we come to the app. So we’ll implement a button to store the world in the local storage and also to u reset the world if we want to start over. We’ll have a reset button for that. And in the end we should build ourselves something fun like a house or we’ll see what we come up with. All right. So let’s look through the code that we’re starting with. So we have a package JSON. So we have react 3 fiber the the main package and then we’re going to use some nice functions from canon and dry we have react we have three we have a way to generate ids and we have the state manager sustand now let’s jump to the components folder is empty right now but we’ll we’ll populate it inside images we have small images like this we have dirt glass grass logs and wood. And I already created a JavaScript file that just imports these images and then exports them in an object like this. Let’s go to the index. So here, not much is going on. Quite standard. We have an index.css file with not much in it. I just added some helper classes and we’ll probably add some more later on. And inside the app here we have just a div that says outside canvas and then we have canvas from reactory fiber and we have nothing inside the canvas right now. So we see a text here that is outside the canvas and the rest of the screen is covered by the canvas. All right. So we are done with looking through the boiler plate. So onwards towards the sky. So the sky we will import from let’s see if we get some help here. Sky from React 3 dry and let’s see if something happened. Yes, we got a sky. So for now we can remove this div that says outside canvas. What I wanted to show with that is that you can add normal HTML as long as it’s outside of the canvas. Because if I move this into the canvas, we get some errors because React 3 fiber doesn’t know what to do with the div. It has all kinds of other primitives. It can render like meshes and geometries and so on, but it cannot handle divs. But we can place them outside and then we can mix the 3D stuff and the normal HTML stuff. So I’ll remove outside canvas for now. So we get a full view of the 3D content here. For on the sky we can set sun position and that takes uh an array of XY Z. So I’ll do 100 and 20 or something. It doesn’t matter too much. But now we see that the sky got a bit brighter and I cannot really look at the any other part of the sky because the camera is now static. Um, so we can adjust the sun position later if we’re not happy with it. But at least now we have a sky in the day and not an evening sky like it was before. So I think we’ll leave the sky like this for now and jump onwards to the next step. All right. So let’s prepare our images and turn them into 3JS textures. So first I’m going to change actually this images file so that we can destructure them when we import them directly. So I will clean it up like this. Let’s create a new file

    and call it textures.

    So then we can import from images. So what we need to do here is create textures. So let’s start with the dirt texture. So we need to import from 3JS

    the texture loader.

    So we say new texture loader and we give it the dirt image. So we just repeat this. There we go. And we create a separate texture also for the ground. Uh even though we’re going to use the same image.

    So we’ll call that ground texture and uses the grass image. So now we want to export these.

    There we go. So now we have a file that exports the textures. So I think we can cross off textures and images. So our next step in the list is to work with the ground. So let’s before we create the ground, let’s add a few things in here. Let’s add an ambient light. So that is a light that will uh light up every 3D surface. Uh, and that one takes a prop intensity. So, let’s do one 0.5. And before we include the ground, uh, we need to add a physics container because we’re going to use a hook from Canon to create our plane that will be the ground. And that needs to be within a physics boundary. So, we’ll do physics from cannon. And inside here is where we can create the ground. So let’s create that component now.

    Ground.

    Okay. So here to create our ground plane, we’re going to use a hook from Canon called use plane.

    So this plane will give us an array where the reference comes first and that is a reference that we will place on the mesh that we let Canon control. So use plane. So it takes a callback function that returns an object. So here we can set some properties of this plane like rotation and position and so on. So we’ll do rotation and here we have an array of three and position also an array of three.

    So now we’re going to return some elements here. So we will take a mesh. We first we will reference this mesh. So we’ll set ref is ref. And then we have the geometry. So we’ll have u a plane buffer geometry and we’ll attach

    this as a geometry. And here we can set the size of the plane with the orgs prop. So since it since it is a plane, it has two dimensions. So we’ll set it 100 by 100. And we also need to add a material here. So we’ll do a mesh standard material.

    And this should attach as a material. And here is where we want to add a texture. But first, we can just set a color. Let’s do hot pink. All right. So, if we look at the browser now, we have something hot pink that is covering the entire uh screen. So, we don’t want to have color hot pink here. We want to attach the ground texture. So let’s import the ground texture. So we just say map is ground texture. Okay. So we got an error uh because we forgot one step in the texture loader. We need to call it and then call the load function.

    Okay, so we instantiate a texture loader and on that we call the load function for each image. That’s important to remember.

    So now we can continue debugging this.

    Okay, so now we have a new texture here. So we as we can see it doesn’t really look like uh the the grass image which has these small pixels on it. So what I suspect is happening now is that the image is being stretched out. So we want this texture to be repeating. We want this small image to repeat over and over. So we can do ground texture dot wrap s and we’ll do repeat wrapping and import that from three. And the same for T. And then we’ll do repeat dot set. And we’ll set this to the same as our size 100 100.

    There we go. So now we have it repeating. But as we can see the it looks very blurry and that has to do with how the texture is being stretched and how essentially how the rendering engine figures out how to display these colors. So with this setting it’s like smearing them. And we can change that if we do ground texture dot mag filter

    nearest filter instead. So let’s see what happens now. That looks much better. Now it looks pixelated as it should. So our next step would be to flatten or lay down the ground because right now the ground is standing up. So we can play with this rotation here. So I will rotate the xaxis and we want to rotate it 90° but in radians. So 2 pi would be 360° which means that one pi is 180° and half of a pi is 90°. So I will do math dot pi / 2 to rotate it 90°.

    And it might be that we’re seeing it from behind now. So I will flip it n 180°.

    So it folded over maybe so that we can no longer see it with the camera. So let’s do it a little bit less. Okay, there we go. So now we can see that it lays down but not completely 90°. But for now, we can keep it like this for a while. We can see that it’s almost correct. Uh because once we can move the camera around, it’s going to be easier for us to to flip it back then because then we will add gravity and we will fall down onto the ground. But let’s keep it like this just that we at least can see that we have the ground there. All right. So, we have the ground. Let’s start to work on the player.

    So our player needs to have a camera. So we can destructure camera from a hook

    called use three. So that hook is from Reactory Fiber. So we also need some type of geometry to represent the player the geometry that can collide with other geometries and so on. So for that we can use a a sphere. So this will be similar to what we did to the plane for the ground. So we’ll do use sphere

    and we call we call use sphere and it takes a function that returns back an object.

    So here we can set mass. We’ll set that to one. We’ll set type to be dynamic and we’ll return a mesh

    and attach the ref.

    And then let’s add our player.

    All right.

    So we we should have a player now. So the next thing, so we won’t see that anything change yet. So we need somewhere to store the position of our player.

    So let’s create a variable called position and we’ll do a reference

    and it has XY Z coordinates. So we’ll do 0 0 0 to begin with. Now we will call the use frame hook. So this hook will run on every frame. So what we want to do now is attach the camera to this position that we’re going to connect to our player.

    So what we can do is that we can take the camera which is from use three and we take the position and we copy

    and we pass in a new vector three

    and this vector we give position current

    and we give it the X. And then we do the same for Y and Z. position dot current dot one which is Y and position.curren

    two.

    So now we should have a camera that follows this reference to a position here. Okay, we can set the console log here just to see that our frame is running. Okay, so we see that we no longer see the ground and we have frame console login here. So we can see that it runs on every frame. So let’s remove this. So we did something to the camera at least that is good. So if we uncomment this line, we should see the ground again. And we do. So that’s good. So we were able to move the camera. We copy it to this position every frame. So our next step is to have this position follow the position of this sphere because this sphere will be affected by physics and gravity. So we can do a use effect

    and this use effect will need to rerun every time the sphere changes position. So we can take out element number two here from usphere which is the API an API towards the sphere. So we’ll say that rerun this effect every time the sphere API position changes. And what do we want to do when the position changes? We want API.positionscribe position dots subscribe and subscribe takes a call back where we get call it P and we’ll say position dot current is equal to P.

    So P is a triplet. So it will look like this. So now we have a sphere that is connected to this reference or let’s say this reference follows the sphere and we can get the camera to follow this reference. So our goal is to get this camera to follow the sphere.

    Okay. So now I added back the camera so we can see that something happens. We get ejected. I don’t know if we may be colliding with the ground and then to handle that collision we just get ejected. If I change the set value here. So if I do 10 and I reload, I land on the ground. But because remember what what technical depth we had from the ground, we didn’t flatten it to 90° properly. So now would be a good time to fix that. So like I said to to rotate 90° that is half of a pie. So now we flatten the ground out.

    So we fly up and then we land on the ground. We have taken the camera. We glue the camera to our position reference and then we subscribe to API position changes of the sphere. So we have a riff that tracks the sphere and then we glue the camera to our reference. Hopefully that makes sense. So we need to do similar things to the velocity. So let’s copy this position code here and we’ll call it call this val and here we track API velocity

    API velocity.

    So here we get V and we’ll set val.curren to V. So now we have a reference of the velocity that subscribes to the velocity of the sphere. Okay. So let’s fix this catapult effect thing. So what I suspect happens is that when the sphere is inside of the ground plane they that state cannot exist. So we just get flung out so that there’s no collision anymore. So we need to lift up the sphere a bit. So let’s try five.

    So now we start from above the plane and then we fall down to it. So let’s see how close we can get.

    So if we put one, we seem to be standing on the ground as we start. So that’s great. Let’s see if we can actually trigger some movement on the sphere. So we have the API. So we can do API dot velocity dot set. So here we can give it the X Y and Z velocities. So we can do 0 1 0. Then we should be constantly lifted upwards. So we’ll do something similar to this when we implement jumping because then we want to set velocity upwards but just for a short while so it so you fall back down so it’s a normal jump. All right. So I think before we can move before we can move forward, pun intended, uh with the player, uh we should make a hook for the keyboard inputs so that we can register different key presses uh that we’re going to use to control this sphere that is the player. So let’s add this to our to-do list. Keyboard input.

    So the player is not yet done. We’ll move to the keyboard inputs first.

    So the keyboard input is actually a hook. So let’s do a hooks folder and we’ll call it use keyboard. Export con use use keyboard. So we’ll need to have some state here to keep track of what keys are pressed. So we’ll do we’ll call it movement

    set movement

    use state. So let’s set up this initial state. All right. So we need to map out all the keys and call them things that we understand. Uh so one action is move forward, move backward. We also have move left and move right. We have jump and then we have texture one, two, three, four, five. I think that should be all the now that we have textures, we should maybe call it actions. So now we need to have a use effect and inside here we do document dot add event listener listen for key down.

    Then

    we need to create some functions to handle this key up. And since we’re adding event listeners, we also need to return a function that removes them. Otherwise, we will add endless event listeners. Handle key down. We wrap this in the use call back. So inside here we get the key down event. So let’s create some helper function to determine what key maps to what. So we’ll do function action by key. So here we get a key key map key action map. So here we say key here we need to type it as they as they are called in the key event. So key W like this. We’ll call it move forward and we have space for jump. And then we have digit one. And now we can say what texture it corresponds to. We’ll say it’s dirt and grass.

    And the last one is log. So now we mapped out what keys belongs to what actions and then we just return key action map with key. Of course we need to check uh so that only we only react to the keys that we are listening for.

    action by key e docode.

    So now we can do set movement and of course we need to preserve the previous state.

    So we we we spread the previous state and then we set

    We can do action equals action by key.

    Now we can just say

    if action

    action is true and this is now called set action actions. Okay. So it will be very similar for a handle key up

    just that we set this to false. So here we need to do handle key down and handle key up and then we just return the actions.

    Let’s try this hook from the player component. I’ll do like this. So we’ll just see those that are true

    key and value and we return those that have true. All right. So now we should be able to see in the console log when we press these different keys that we are looking for. Okay. So we have no actions when we start. That’s good. So now I press W. Okay. So I’m not getting anything. So let’s debug. Let’s see if we are here.

    Yes, we get the keyboard event action by key. Action by key is a function, not a map. So, this should fix that. And same thing here.

    So I’m pressing W S A D jump spacebar and the digits one 2 3 4 5. Okay, so we have everything working. So now we can react to these actions and control the movement of the sphere by looking at what key presses we’re doing. So we can cross off the keyboard inputs. All right. So, let’s control the player using the keyboard inputs. And I think an easy one to start with is the jumping because this requires some vector math. So, it will be a little bit tricky, but I think we’ll manage it. So first we can look at

    if actions do jump.

    That means that we are jumping. Uh we can reuse this code

    here. We can for the x we’ll just keep the value and for zed we’ll just keep the value

    and here this is a constant that we’ll use for the jumping. So let’s store it jump

    force. Let’s try 10

    jump force.

    Okay, let’s try it out. Spacebar. All right, so we achieved the jump. It felt a little bit too high. And also we can jump indefinitely, which is wrong. Uh, so first let’s fix the jump height. Let’s try three.

    Yeah, that’s better. We’ll try four for now. Uh so we need to do another if check here if we can jump again. And one easy way of uh eliminating all these extra jumps is that we make sure that our y velocity is zero. Make sure that we’re not moving up and down because whenever we are moving up and down it means that we are falling through the sky or already jumped and we’re on our way up. So we need to make sure that the velocity in the y direction is really close to zero. So let’s do since we we care about positive and negative we can do absolute value and we have it on velocity dot

    current.

    It’s val right.

    Current one should be smaller than 0.

    Let’s do 0.05 maybe. Okay. So, let’s try. Good. We can still jump. I’m pressing it continuously, but we we’re only allowed to jump once we’ve landed. Oh, there’s one bug that we should fix and that is that we can we can jump if we hit right in the moment when we’re actually slowing down from going up to going down again. So, it’s um the the velocity there becomes almost zero at a certain frame. So, if I can time that frame, you can see that I can jump two times in a row. But we’ll leave it like that for now. So we can start to think about how we move in a direction. And the tricky part about it is that later on we will be able to turn around. So W will always take us in the camera direction. So we need one vector to represent what direction we are facing, another vector for the forwards and backwards speed and the other one for the side speed. So let’s create those vectors. one direction vector

    vector 3

    and uh we’ll call it front vector

    also a vector 3 and a side vector. So the front vector it’s this Z axis here that will determine uh us going forwards and backwards. So both the move forward and move backwards should affect this force here. So one way of doing it is we check actions domove backwards and we set it to one if we’re moving backwards or zero. And then we subtract the same thing but we’re moving forward.

    So if we press them at the same time they cancel out. We could actually destructure here. Move forward, backwards, move forwards, move right, move left, jump. Then we can clean this up.

    Like this. And like this. All right. So, we have this one one or zero. And this one one or zero. And if they are both one they cancel out which is a good thing because if you go forward and then you start to hold backwards also then uh you should stop right that’s what we see in games. So then we’ve taken care of the front vector. So let’s do something similar for the side vector. So we’ll copy these. So now we’re not moving in the Z direction anymore. I think this should be the X direction.

    And here it’s move left and here it’s move right. So we get the same behavior there. If you’re holding both at the same time, you should go nowhere.

    There we go. So now we’re going to do some calculations and we’ll we will originate from the direction vector. So we’ll do direction dot subtubract vectors uh and those vectors are the front vector and the side vector. And then we’ll chain on some more operations. We normalize and then we multiply scalar. And here we need to determine how fast we want to go. So let’s also make a variable for that or a constant. We’ll try four for speed as well. So we’ll multiply the speed and then finally we apply uler

    and this is where we get the correct facing direction from the camera. So we have a reference to the camera and its rotation. So this is where we make sure that the front and side vectors are correct in relation to the camera. So now we can take this direction vector and apply it to the sphere. So API dot velocity

    dot set and then we do the direction.x X direction doy and direction dot zed. But that’s not completely true because the yaxis is not controlled by these front and side vectors. This is just for moving backwards and forwards and to the sides. So the y should actually stay the same. So we’ll do well. one. So that should be enough. In the best of worlds, we would be able to move at this point.

    See if we need to refresh.

    All right. I think we’re missing the new keyword here for the vectors. There we go. All right. So, we have a typo here. Okay. So, let’s try. I’m pressing forward. All right. So, forward is working. Backward is working. Now, we’ll try backwards and forwards at the same time. And it stops. That’s great. Let’s try left and right at the same time. And I let go of left. All right. So, that seems to be working. So, we cannot yet test that it will be still correct when we turn the camera. That we will do once we once we build out the the pointer lock controls uh where we can control the camera with the mouse. All right. So, I think we are done with the player for now. Let’s move forwards with the firsterson view. So we’ll create a component FPV

    and this one is actually quite simple because we get a lot of help from uh react fiber here. Okay. So we need of course to connect this to the camera. So we need use three

    where we can get the camera.

    Okay. So we return

    pointer lock controls

    args is camera destruction GL here passing that as GL dom element FPV from FPV

    and just render it.

    All right. So, uh when I click here now, it should lock the camera to how I move the mouse. So, now I can look around. So, now we can see that if I’m facing left, I can move straight ahead. And if I turn a bit, I can still move straight ahead. So, our player movement seemed to work fine. and the pointer lock controls seem to work as well. There’s one thing we should do with the firsterson view is that we should add a small cursor to uh the middle of the screen. So outside of the canvas, let’s add a div class name cursor and let’s put just a plus there. and let’s position it absolute. And we’re going to center this on the screen. So let’s make a class called centered. So this is positioned absolute. So we do top 50%, left 50%. We need to add a transform translate

    minus 50% and minus 50%. So that is just because if we if we center it 5050% without doing this transform translate then it will not actually be in the middle because I think I can show you this background hot pink. If we make this bigger we see that it is in fact centered. But if we don’t have this translate, this is what will happen. The top left corner of the square will be in the center. So what we’re adjusting for with 50% is 50% of the width and height of the square. So then it will move to the middle. But this one doesn’t need to be big at all. So we’ll remove these two. That looks good. And then remove the background.

    So move the the color styling to cursor.

    There we go. Now we have a marker to indicate the center of where we are watching. Great. I think we are done with uh the player for now. So we will cross out firsterson view. We’re also done with gravity and we are done with the movement. Our next item on the agenda is to add a state manager. We can add a hook called use store that keeps track of the game state. So let’s create our hook. Use store. So we’ll need create from sustand use store.

    We can wrap this in create and we get a setter method here as an input parameter. So we will return an object. So we call create. We pass it a function that returns an object. So in this object we can declare our state. So, we need to keep track of a texture. And we can default the texture to dirt. We need to keep track of the cubes that the player is going to be able to place. So, we can just default that to an array. And now, we’re going to declare our methods that you can use to interact with the state. So, we’ll of course have add cube, remove cube. You need to be able to set the texture and for later we want to be able to save the world. Reset world. These are all the operations that we need to support in our store. So when we add a cube, all we need to know is where to place it because the texture we already know since we are in the store. So when when someone calls add cube we need to call set and in set we pass it a callback function and we get back the previous state. So here we can return an object. So here we just want to affect the cubes which is an array. So we spread in the previous cubes

    and then at the end we add our new cube. And every cube needs to have a key and then we can use nano ID for that.

    We have a position that we get from XY Z that’s being passed in. And then we have the texture which we can get from pre.

    So that should be all it takes for us to add a cube. But before we do that, we need a way to render cubes. So I suggest that we leave the store like this for now with just a method of adding cubes and then we create the component to render a cube and then we can start to render them out. We can actually initialize the state with one cube just for debugging. Let’s do 111. So now we always have one cube initially that we can quickly see if when we start to rendering the cubes if they come out. So I s I suggest that we leave the store like this before we finish the rest of the store functions and then start to working on rendering our first cube. So let’s add a new component. Before we create the cube, we should have a a component that is taking care of rendering all the cubes essentially consuming the store and mapping out the cubes. So we’ll make a component called cubes. So we need definitely to have used the use store

    from hooks.

    So our use store hook we can we get the state back and then we can return an array where we can place different things from the state in whatever order we want. So we want state cubes.

    So then the first element here will be the cubes. So if we do console log cubes, we can return nothing here. Let’s add cubes. Cubes.

    So since the player needs to be able to stand on the cubes, the cubes needs to be within the physics.

    So add it like that. Okay. So we consoled out the cubes and this is our debugging cube that we added a dirt cube on position 111. So now we can start working on mapping out those cubes. So we return.

    Here we’re going to use the cube component. So let’s create that one first.

    Since we’re doing a mapping, we need to use the key which is something that we have on the cube already. We have key, we have XY Z texture. So here we can use the key. This is actually position.

    So we receive position and texture. So to create the cube, we’re going to use the the canon use box hook.

    So we’ll set type is static and we have the position from the incoming prop.

    So here we return a mesh and to the mesh we connect the ref. Here we need a box buffer geometry and we also need a mesh standard material

    attach as geometry

    color is hot pink. Do we have a cube anywhere? Okay. So I see we called it position in the store and here we’re destructuring position.

    So we need to call it push here.

    Oh, okay. So, the reason I couldn’t find the cube was because I was standing on it. I feel very stupid now.

    That’s good. So, let’s play around with these values. See if we can get get it up in the air.

    All right. So, there we have our first cube. All

    right. So, we have the cube standing on the ground. So now let’s fix the texture of the cube.

    So let’s pass in the texture.

    In the store we just call it dirt and in textures we call it dirt texture. So let’s do texture plus texture. So we import all the textures as textures and then we map it by the texture in the store plus texture and then we get our active texture. Then we can do map active texture

    and remove the color. There we go. We get the dirt texture on the cube. Let’s move it a bit closer to us.

    So, as we can see, it doesn’t look so good. So, we need to do the same treatment we did to the grass to every cube texture. So, we’ll test it with dirt. dirt texture

    mag filter

    nearest filter. Let’s see if that helped. Yeah, now it looks good and pixelated and not smooshed.

    Let’s do it to ground texture in here as well since we are already here. And then we don’t have to do it in here. Let’s move these out as well. There we go. So now we fixed it for all the textures inside of the texture file instead to keep our components more clean. I was thinking to maybe keep this in ground because it correlates to the size of it. So, we’ll keep it here. So, now we should be able to add a second cube with another texture.

    And we’ll pick another position texture

    wood.

    All right. So now we can render cubes with different textures. And this one looks nice as well since it’s been fixed. All right. So now we have a way of rendering cubes once they are added to the store. All right. So we have the basics of the state management and we have the cubes basics as well.

    Something that is missing in this list is adding cubes. So one way of adding a cube is to click the ground. So let’s open the ground. So we need to get the add cube method from use store.

    add cube

    and we return an array with state add cube. All right. So we had have the add cube method. Uh but we need to figure out the x y and z coordinates to uh to pass to this function. So let’s add an on click to this mesh.

    Let’s do E do. Stop propagation so that the click cannot be passed through the ground. So on the event we have something called E.point.

    So we want to get X Y and Z. So we can do object dot values from E dot point. So let’s stop here to check out what happens when we click the ground. So we have E.

    Let’s look at point.

    So we have a vector three. So we just want to get the values of this vector. We don’t want to pass the whole object. So if we do object valvalues, we just get these three values and we structure them out here. So if we hover the x, y, and zed, we see that we do in fact get the values here. As you saw, there are a lot of decimals here. We want the cubes to end up on fixed location according to this grid that we can see here in full numbers. So we need to round this. So we need to do a mapping of these values and return math seal of the value and then we should be able to call add cube with x y and zed. Right? So let’s try this out. Let’s reload. And we click the ground and we do get a cube.

    So as we can see the seal function made it round up. So let’s try with floor instead. So, as we can see, I think we should try moving the ground down by half a unit and see if that will make the cubes lay flat on the ground. So, let’s try that. So, now that we fixed the ground, we can go back to seal here.

    Math seal. And when I click the ground, we actually get cubes added. Pretty cool. So now let’s lower these default cubes or we can actually remove these default cubes cubes now that we have a way of adding cubes for real. Okay, so we handle the case where you click the ground and you want to add a cube. But what about when you click the surface of a cube to add a cube next to it? Okay. So let’s handle the clicking of cubes. So we can copy this state call here because we want to do the same inside of cube.

    But we also want to have remove cube later on. So let’s add that straight away.

    So my plan is that if you hold in a modifier key and click then you can remove cubes as well.

    So let’s add an on click.

    We stop propagation. So here we need to handle a few things. A cube has six sides and the side that you actually click needs to get another cube next to it. So we’ll create a variable clicked face.

    And a face of a cube actually has two triangular shapes that covers the face. So it’s not a full square, it’s two triangles that together cover the square face. So instead of six faces, it has 12 faces. But that is pretty easy to fix. So we can just take take e dophase index and divide this by two and then we will be in the range between zero and five instead of zero and 11 and we of course need to math do floor it because there’s no 0.5 face index. So now clicked face should be between zero and five. So let’s console log face clicked face. So let’s add a cube here. Phase four, face one, face five, face zero, top is phase two, and the bottom should be phase three then. So now we just need to write if statement to cover all these clicked faces. So if it’s zero add cube. So we have a ref to the box that has a position. So we can do xyz from ref current position. So we can pass in xy z. And then we need to on one of them maybe subtract one to the x. And for another face, we need to do x + one. But it’s a little bit of guesswork to figure out what phase is what direction, if you understand what I mean. 1 2 3 4 5 6.

    So something like that. This will most likely be wrong. All right. So we add a cube. We click one face. So here we see that it was the opposite.

    All right. So now we have logging as well. So if I click this face, we see that it was four and the cube was added on the other side. So clicked face four just needs to flip. And then let’s flip this one. If I click this face, that was face one and that was also flipped. So this should probably minus one and maybe plus one here. Let’s try the top.

    So phase two, nothing happened. So I’m suspecting that there’s a cube underneath. So this should probably be + one and this should be minus one. So let’s try again to click the top. Yeah, now that was correct.

    So I think we might have it. Nice. Now we can click a cube to add another cube next to it. So now now it starts to become fun. So we can return if we are done with the operation.

    So now we can handle the removal of cubes. If E. Altkey key remove cube X Y Z and return. And of course we haven’t implemented the remove cube function yet.

    So what we can do just to try it quickly is to just console log here

    xyz

    xyz

    remove. All right. So I’m holding down the alt key and I’m clicking it and we get a call to remove cube with xyz. So that’s great. So now we can implement the remove cube function.

    So we can borrow some code from add cube. We will still call set but instead of adding to this array we can take pre dot cubes dot filter cube or we keep all the cubes where x y and z are not equal to the xy z being passed in. So we destructure

    x, y and z from the cube. Then we return x not equal to x,

    y not equal to y, and z not equal to set. So let’s see if we can filter out the cube that we’re clicking on. Let’s add a few.

    So here we need to say cube cube. Pulse. All right, let’s try again. So add a few cubes and then alt key and they were all removed. I think the issue is that this should be or because if any coordinate is not correct, it’s not the the right box to filter out. So let’s try again.

    There we go. One cube being removed at a time. Great. Now we can remove cubes. Great progress. All right. So we are done with adding cubes and removing cubes. So let’s continue with the cube type selector. So we should create some UI that indicates what selections there are and what is currently active. So let’s create a component texture selector.

    And this one will not be a three component. This will just be HTML. And this one should just be visible when we’re actually changing the texture. So we need some state here.

    So determine if it’s visible right now or not. We’ll default it to false. We need to get the texture from u from the store. active texture

    state and we get an array back where we take state dot. We just call it texture

    texture.

    So, let’s call create a use effect that runs whenever the active texture changes.

    Active texture. So, if the active texture changes, we want to have this texture selector visible for like 2 seconds and then we want it to disappear. So we need a visibility timeout that is set timeout

    for 2 seconds. So after 2 seconds we want to set visible false and immediately we want to set visible true and then we need to clear the timeout.

    Clear timeout visibility

    like this.

    So we only want to show something is if visible is true.

    So let’s do class name absolute and centered. So now we we also need to handle so that the texture is actually changed when we press the digits actions from use keyboard.

    So in the store we have a set texture method. So let’s finish that. We take a texture called set.

    We don’t care about the previous. We just want to set texture based on the incoming texture. So let’s look at use keyboard. We have texture one to five. This is what we want to dig out here.

    So let’s do a use effect again that will run for texture one texture two

    if texture one. So now we need the set texture from the store.

    Set texture dirt. Okay, we’ll call this dirt,

    grass,

    glass, wood, and log. So, the actions will now contain props that are the actual names of the textures.

    So we’ll call it pressed texture.

    So if any of these textures are true then that texture will be the pressed texture and then we can do if pressed texture set texture to pressed texture. Let’s see. Pressed pressed texture. So, let’s see if it works.

    If I press one. All right, let’s debug.

    So, if I press one, there to be true. So, that’s great. So, it works correctly in use keyboard and in the texture selector. Let’s console log dirt. Let’s see if we can get dirt to be one. So, one thing what we’ve must do is add the texture selector to our app before we start to looking for console logs in it. So, let’s add it here. Texture.

    All right. So, we get dirt false. We saw it there. And as I press one, we got dirt true and texture selector appears for two seconds and then gets removed. So it looks very promising active texture. All right. So here we have our textures as booleans. So let’s create a mapping that will set the prop which is the name of the texture that will map from the name to the booleans. So then we can do object entries

    find

    key value. So we want to find a texture where the value is true. If we have such a pressed texture, we’ll take the value from that. All right. So we get five booleans here and we put them in a mapping. So we’ll get dirt falls, grass falls, maybe glass true and if glass is true we will find the true texture store that in press texture. So if we found a press texture, we get the key of that by taking the first uh element in that tupil. So let’s see if it actually worked. Grass, pressed dirt, pressed wood, and pressed log. So now I pressed glass. So this is the glass cube. Pressing dirt and I get a dirt cube. So cool. We have a way of selecting different textures just using the keyboard. I don’t know what happened with this cube. But let’s continue building the UI to show the actual selections.

    So we already have a list of images with these. So let’s import those images.

    Okay. So let’s create a mapping here images.

    So we keep the name that they are called in the store to the actual image. That’s

    so we need to loop these in a map here. Images and we’ll do object dot entries images. So here we get key and source image. So we can return an image image tag source is source key is K

    and now we need to check which one is the active one and that we can do by adding a class name. So here we can do K equals active texture. If that is true, if that is true, we add active. Otherwise, nothing. And let’s have an alt prop the uh the name of the texture. All right. So let’s see if anything happened. So when I change the texture now, here we have an error. This should be an array. So now let’s see what Oh, we we got it. So when I change texture, the texture selector appears. So we should just make it bigger.

    Let’s add a class

    texture select.

    So we can do transform scale 10. It should be select.

    There we go. That’s bigger.

    Let’s do maybe five. And then let’s handle the active also. So if we have an imageactive there, let’s do a border. of two pixel solid red. So let’s see if we can see which one is active. Yes, we can.

    Okay, so we between the four and the five we have the wrong digits. So that is probably because I typed them in the wrong order here.

    All right, now they work correctly. All right, let’s see all our cubes. We have wood or log, we have wood, we have glass, we have grass, and we have dirt. Really nice. Let’s remove this console log. All right, so our cube type selector is done. The next thing on the agenda would be to save the world in local storage. So that is something that we can do inside of our store. So let’s create some helper functions to talk to the local storage. So what we want to store in the local storage is an array. So we need to do JSON parse and JSON stringify to talk to the local storage. So let’s call create a helper function get local storage.

    So we we take in a key and we return JSON.par

    window local storage get item of key. So all we’re doing is JSON parsing what we get from local storage. And let’s do a similar function with set local storage. We take in a key and of course the value that we want to set. And then we do JSON stringify

    set item and then we set we pass the key. Actually this JSON string if I should be just wrapping the value

    value right now we have our helper functions. So when we first create the state we want to do get local storage and we can just make up a key here. We’ll call it cubes. So we’ll either get something or it will be empty. So we’ll fall back to the empty array. So now we can implement these two functions. Let’s start with just resetting the world. That would just be set

    and then we just set the cubes to be empty array like that. That should reset the world. And then we have say world. So we call set just to get the current state. And inside here we just call set local storage. The key was cubes. And we store prev. cubes. So we don’t need a load world function because that happens when we just reload the page. But we we also need to create some buttons on the UI for this. Let’s create a component called menu.

    So we want to access save world and reset world from use store.

    So state

    reset world. All right.

    So, let’s create some UI

    class name of menu and absolute.

    We need save and we need reset

    on click.

    Save world.

    Reset world. All right, let’s import menu.

    So, let’s see where we have our menu. We have it, but it’s down there. So, we need to style it so it becomes in the top.

    So, we’ll do top 10 pixels, left 10 pixels. There we have them.

    All right. So, let’s try them out. We’ll place a few cubes of different types.

    All right. We have a nice line here. Let’s save it. So now it should be in local storage. We can verify that application local storage. We have cubes and there we have the cubes. So now when I reload the page, do we have any cubes? Oh, here they are. Really cool. So now we can persist it. Of course, we can also reset, but they are still in local storage. So if I just reload the cubes will be there. All right, we are done with saving the world in local storage. But we have one more thing that would be nice to have hover state on cubes. I think it would be nice if when the cursor hovers a cube that they become a bit darker so that you indicate what cube you’re actually hovering on. All right, let’s keep track if a uh cube is hovered.

    Set is hovered. Use state from react false. Now we can add some pointer events here on pointer move

    and we take the event stop propagation set is hovered true.

    And then we just do the same for

    on pointer out.

    And now we need to adjust the appearance based on the hover. So let’s add color here is hovered.

    Let’s make it gray. If they’re hovered, we make them gray. Otherwise, we keep them white.

    But one thing that would be nice is if the glass cube would actually be a bit transparent. So we add transparent true to all the cubes. And then we do opacity active texture equals glass. Then we do 0.5

    otherwise we do one and this should be just texture.

    All right. So there we have transparent glass. And maybe it’s a bit too transparent. Let’s do 0.6.

    Really nice. Very cool.

    Right. So, we’re getting close to being able to build that house. And of course, transparent glass is a must for building houses

    so you can watch outside.

    All right, I will quickly finish this house just to check it off the list.

    should probably have a door.

    All right, we’re inside the house.

    I think we can check it off the list. All right, we can say actually right now that we have fixed everything on our to-do list and even some more things that we had to add as we went on. For those of you that got this far, kudos to you. It’s quite a long project. If you want to submit pull requests to this uh project, feel free. I will look at them and probably pull in many of them. So, thank you so much everyone that watched. I hope you learned a thing or two about uh building 3D things on the web and I hope you got inspired to try out to build something on your own. So please keep watching free code camp, continue to learn and also you can check out uh my channel if you should want to. Bye now. Thanks a lot for watching.

  • Code a 2D Game Using JavaScript, HTML, and CSS w⧸ Free Game Assets – Tutorial

    Frank Dvorak teaches this JavaScript game development crash course. You will learn how to create a 2D game using JavaScript, HTML, CSS, and object-oriented programming. And Frank provides a lot of free sprites and game art assets so you can follow along. Frank is a popular teacher who creates super creative courses. What a strange planet. It’s completely covered in a thick layer of smoke. Initial scans indicate there are no organic life forms present, but I register a lot of movement. Coders, hope you like making games. Let’s make a 2D steampunk game completely from scratch with HTML, CSS, and JavaScript. No frameworks, and no libraries. I will give you a lot of premium art assets for characters, environments, and props, and you can do whatever you want with them. You can use them in your projects, and you can modify them. I will show you how to create gameplay variety by giving different enemy types different mechanics that the player can interact with or has to deal with. For example, if you destroy a hive well, a bunch of small drones will come after you. Let me show you how to give your games beautiful visuals and how to apply many special features I came up with specifically for this class. Let’s go. These creatures have very similar physiology to the Earth’s seahorses. Body shape like this can cut easily through the thick atmosphere of this planet. They can move very fast. Seahorse hive is being attacked by something. This one has been damaged. I wonder if we can hack this creature’s central computer to control it for a while. It is surprisingly easy to override its circuits. Seems like these machines are not used to our technology. I’m getting a lot of new data. Okay, explorers. We are getting a stream of data about multiple different species. We will convert their source code into HTML, CSS, and JavaScript. Let’s analyze it line by line and see how it works. We have a lot to learn. I will answer all your questions as we discover more about their movement, special abilities, and how they interact with their planet’s environment. Let’s look under the hood of this alien ecosystem. The atmosphere is thick enough to allow heavy siliconbased life forms to float, but smoke is blocking most of the sunlight. Many creatures developed artificial lights and glowing appendages to see through the heavy clouds. Seahorse Sentinel has a basic attack that’s powerful against weak enemies. But if it absorbs energy from one of the overcharged creatures, it gets additional firepower for a short period of time, and it instantly replenishes its ammo. Ammo also automatically recharges over time. It seems we just need to help it to get through these aggressive swarms in time so it can join its hive. If this is your first time discovering JavaScript, you should try some beginner classes first. Today’s coding will be beginner friendly, but I expect some basic knowledge of JavaScript. when you get more comfortable with objects, arrays and for loops, come join me in this class.

    So after a simple basic setup inside index html and style CSS, we move into script.js. All JavaScript logic for this game will be written here inside this file. I create an event listener for load event. Notice that we call it on built-in JavaScript window object which represents the browser’s window. load event fires when the whole page has been loaded, including all dependent resources such as stylesheets and images. We need to do this because we will use a lot of graphics in this project and they can take some time to load. If you’re trying to draw an image with JavaScript, remember that you always have to wait for that image to be fully loaded before you run the JavaScript code that depends on that image. I usually like to do HTML canvas setup like this. Custom variable I call, for example, canvas will store the reference to canvas element. I point it towards that element using get element by ID. I give it an ID of canvas one. Now I need so-called drawing context. It is a built-in object that contains all methods and properties that allow us to draw and animate colors, shapes, and other graphics on HTML canvas. To create it, we need to call a special built-in get context method on a variable that holds a reference to canvas element. So I say canvas dot get context. And then I need to pass it identifier. Sometimes we call this argument a context type. We can pass it 2D or WebGL here. WebGL represents three-dimensional rendering context. Today we will work with 2D. Now I access width property on canvas from line 3 and I set it to 500 pixels. Height will be 500 as well. As you can see 500 pixels is wider than my current browser size. For that reason, I also like to declare max width property and I set it to 100%. That way, the element will scale down until it’s fully visible in the available browser area. I also declare max height in case the restricted factor is the height of browser window. Doing this will make sure we can always see the entire canvas element even when the browser window is too small. I will zoom out a bit to adjust my workplace. For this tutorial, I set canvas width to a larger value and keep my browser window small. Canvas element will scale down to make sure it’s fully visible.

    To build our game today, we will use object-oriented programming, which means we will wrap variables and functions in objects. JavaScript is a prototype-based object-oriented language, which means it doesn’t have classes. It has prototypes. But we can use modern JavaScript syntax that introduced classes as so-called syntactical sugar simplified clean syntax that mimics classes from other programming languages. Still under the hood, it’s just working with prototype based inheritance. One of the four main principles of object-oriented programming is encapsulation. Encapsulation is the bundling of data and the methods that act on that data in objects. Access to that data can be restricted from outside the bundle. In this project, I will encapsulate our data into multiple classes. Each class will have its special purpose. The challenge for beginners will be to keep track of how these classes communicate with each other. I will explain everything step by step as we write the code to help you understand. We need to declare our classes in a specific order. Class declarations are hoisted in JavaScript, but they stay uninitialized when hoisted. That means while JavaScript will be able to find the reference for a class name we create, it cannot use the class before it is defined in the code. This means that I need to declare input handler class first because I will need to use it inside player class and so on. Input handle class will keep track of specified user inputs. For example, arrow keys. Projectile class will handle player lasers. Particle class will deal with falling screws, [ __ ] and bolts that come from damaged enemies. Player class will control the main character. It will animate player sprite sheet and so on. Enemy class will be the main blueprint handling many different enemy types. Layer class will handle individual background layers in our parallax seamlessly scrolling multi-layered background. And background class will pull all layer objects together to animate the entire game world. UI class will draw score, timer, and other information that needs to be displayed for the user. and the main game class will come last. Inside this game class, all logic will come together. This will be the brain of our project. I hope this gives you a map of what we need to do to complete our game. Let’s write JavaScript logic inside individual classes and connect them together. I will explain everything step by step as we go along.

    Constructor is a special method on JavaScript class. When I call this JavaScript class later using the new keyword constructor will create one new blank JavaScript object and it will assign it properties and values based on the blueprint inside. Player will need access to game width and height and other properties that will be stored on the main game object. So I will pass it the main game object as an argument like this. I convert that game object into class property on player class like this. I’m saying take this game object that was passed as an argument to the class constructor and turn it into class property called this.game. Keep in mind that by doing this I’m not creating a copy of the main game object and placing it on player. Objects in JavaScript are so-called reference data types which means that unlike primitive data types, objects are dynamic in nature. I am just creating a reference that is pointing to the place in memory that stores the main game object. So when the values and properties on the main game object get updated, those changes will be immediately visible from this.ame reference inside this player class. I made the size of player spreadsheet the same size as we will draw them in game. It’s a good practice. I know that the width of a single frame in my spreadsheet is 120 pixels and height is 190. If you are a beginner, it’s best if you use the same sprites and images I’m using. It will make the debugging easier in case you run into problems. You can always check my code to find the problem. All art assets I’m using are linked below. You can download them from the project section. Start in horizontal X coordinate on the player will be 20 pixels and vertical Y position is 100. Player will also need an update method to move it around and draw method that will draw graphics representing the player. For now, let’s start by increasing vertical Y position on the player by speed Y. I need to declare that property here. It will be zero at first, so no vertical movement. Draw method will take context as an argument. This will specify which canvas element we want to draw on. In case our game has multiple layers with multiple canvas elements, it’s also a good practice to use context argument like this rather than pulling ctx variable from the outside directly into our objects. At first, I will just draw a simple black rectangle representing the player. So, built-in canvas fill rectangle method and I want to draw the rectangle at player’s current X and Y position and it will have players width and height. So, we have our player object. How do we include it inside game logic and draw it on canvas? As I said, the main game class from line 45 will be the brain of our entire project. All the logic will somehow go through it. Again, I will give it a constructor. Constructor will need width and height of canvas as arguments and inside we convert them into class properties. This will make sure that the width and height of the game matches the size of canvas element. Constructor on JavaScript class is a special type of method that will run once when we instantiate the class using the new keyword. It will create one new blank object and it will give it values and properties as defined inside the blueprint. Here I can take an advantage of the fact that all the code inside the constructor gets automatically executed like this and any code I put inside the constructor on game class will automatically run when I instantiate my game in a minute. So when I instantiate game class I want it to automatically create an instance of player class and I want that instance to become class property on game class called this dot player. So this player is equal to new player like this. The new keyword is a special command in JavaScript. It will look for class with this name in this case player and it will run its constructor method to create one instance of it based on the blueprint inside. So by calling new player on line 49, JavaScript will find player class up here on line 17 and it will run all the code inside its constructor. I can see that constructor method on player class needs game as an argument. Down here we are inside that game class. So I pass it this keyword. This keyword used inside this class refers to this entire game object. Our game will also need update and draw methods. Update method will take this player property from line 49 which holds an instance of player object and it will call its update method we defined on line 26. Inside draw method we will render the player on canvas by calling draw method from line 29. I can see that it expects context as an argument. So I pass it context like this and that value will be passed along here. Now I create an instance of this new game class we just wrote and I save it in a variable I call for example game. It’s equal to new game like this. Again new keyword will look for class with that name. It will find it on line 45 and it will run its constructor method to create one new blank JavaScript object and assign it values and properties based on the blueprint. Here on line 46, I can see that game class constructor expects width and height as arguments. So I pass it canvas width from line five and canvas height from line six.

    So the new keyword triggers a class constructor. As the constructor gets executed, we hit this line which will automatically create an instance of player class from line 17. So this is how by creating the main game object, we also automatically create player object and now it sits as a property on the game class on line 49. Perfect.

    We will also need animation loop that will run update and draw methods over and over 60 times per second. updating positions and redrawing our game. I create a custom function I call for example animate. Inside I take the instance of game class from line 59 and I call its associated update method we declared on line 51. I will also call draw method from line 54 like this. I can see it expects context as an argument to specify which canvas element we are drawing on. So I pass it ctx from line 4. This means that this ctx variable will be passed here and it will get passed along to draw method on player object here. Now the player knows where we want to draw it. After we called update and draw, we want to trigger the next animation frame. So I call built-in request animation frame. Request animation frame method sits on the window object. But we can also call it just like this. It tells the browser that we wish to perform an animation and it requests that the browser calls a specified function to update an animation before the next repaint. So we need to pass it one argument and it will be the method we want to call before the repaint before browser window gets updated and redrawn on screen. I pass it animate the name of its parent function to create an endless animation loop. Request animation frame has two special features. It adjusts the user’s screen refresh rate. For most of us, it will be 60 frames per second. It also autogenerates a timestamp argument and passes that as an argument to its callback function. A little bit later, I will show you how to use this feature to create periodic events in our project. Events that repeat in a certain interval. I get an error because I misspelled the word constructor. Here, I’m using VS Code editor. It highlights syntax in different colors which makes it easier to notice typos like this. We have our main game logic and we are drawing this black rectangle representing our player. It looks static but it’s actually animating. We can test that by giving player some value here in speedy property. The reason the rectangle gets longer now is because we can see old paint. We can see old black rectangles that were drawn in the previous animation loops. I can fix that by deleting all canvas drawings between each animation frame. Between every animation loop, I call built-in clear rectangle method. And I want to clear canvas from coordinates 000 to canvas with canvas height like this. Now you can see that because player speed Y property is set to + one, the player moves by one pixel per frame in positive direction on vertical Y-axis. If speed Y is minus one, player will move upwards. If speed Y is zero, the player will not move at all. It’s all because for every animation frame, we are adding speed Y property to player’s vertical Y-coordinate here on line 27. We know that everything is working well. It’s good to test your code as you go step by step to discover potential problems. I want the player to be controlled by keyboard. When I press up arrow, we set speed Y to minus one and player will move up. When I press down arrow, we set speed Y to plus one and player will move down.

    We will handle all player input up here inside input handler class. Constructor will take a game as an argument. Same as we did with the player. I convert it into this.ame class property. As we said before, when we create an instance of a class, all the code inside class constructor gets executed. We can take advantage of that. And I can even apply event listeners from here. I simply just apply event listener like this. We will listen for key down event. Callback function on event listener has a special autogenerated argument that contains all kinds of additional details about the event that just happened. If I want more details about the key down event, I just need to pick a variable name and I pass it as an argument to the call back. Usually we use letter E or the word event, but you can also type ABC. Whatever you put here will become a custom variable name containing a special object with additional information about the key down event that just happened. I will save it in a variable I call E and I will console log it. If you just console lock E, you will get the full event object with many properties. I’ve done this before. So I know I want a specific property called key. So I console lock E.Key. This will contain a string with the name of the key that was pressed. Let me show you. I need to create an instance of input handle class. So as we did with the player, I want my input class to be instantiated automatically as I create my main game class. So here inside the game class constructor, I create a property. I call for example this.input. I set it to new input handler and I know its constructor expects game as an argument. So same as we did with the player, I pass it this referring to this entire game class. So now as I create game object down here, it automatically creates player object on line 54 and input object on line 55. As we call the new keyword on line 55, JavaScript will jump to line 9 and it will run input handler class constructor which will among other things apply this key down event listener that’s console login the current key that is pressed. I open browser console. I click on canvas element so it starts registering events. And now when I press keys on my keyboard, you can see we are console login the key property

    inside key down event listener I say if e.key is arrow up take keys array on the game object.

    We will create that array in a second and push that key into the array.

    I create that array here on line 59 inside game class constructor. Its job will be to keep track of all keys that are currently active that are currently being pressed down. I will console log this.game.keys from here to check if arrow up key is being correctly added. I get a console error that is saying that the variable name I’m calling keys from is undefined. By the time this callback function is executed, JavaScript forgot what this.game game stands for which object it points towards. We want JavaScript to remember that this code initially sits inside this object so that it can see and remember this.game property even when we call it later as we play our game. If you are a beginner, don’t worry about fully understanding this yet. All you need to know here is that if JavaScript forgets what this keyword stands for, we need to bind that code to the surrounding codes context. We can use built-in JavaScript bind method or even simpler, we can use ES6 arrow function syntax here. A special feature of arrow function is that this keyword inside arrow function always represents the object in which the arrow function is defined. Arrow function will never forget that it was originally defined inside constructor on input handle class and it will always see this reference for this.game from line 10. Therefore, it will be able to access this.game.keys keys and push keys inside. Now everything is working. When I press up arrow key, it gets added into this.game.keys. And if I press it multiple times, it keeps adding more and more. So I create another event listener.

    This time for key up event. When we release the key, I want to remove it from the array. I do that by checking if the array contains that key. So built-in index of array method. The index of method returns the first index at which a given element can be found in the array or it returns minus one if the element is not present. So if this.game keys index of is more than minus one meaning if keys array contains the key that is currently being released in this key up event take this.game.keys array and remove that element from the array using splice method. The splice method changes the contents of an array by removing or replacing existing elements. Splice method needs at least two arguments. The first argument is the index at which we want to start changing the array. So it will be the index of that key we want to remove like this. And the second argument is delete count an integer indicating the number of elements in the array we want to remove from that starting index. So I call splice. I want to remove elements starting from this index and I want to remove only one element at that index. I put the same console lock inside key up event. You can see that it works well. When I press up arrow, it gets added. When I release it, it gets removed. Added removed. Nice. The problem is when I hold up arrow key down for too long. Key down event will start firing over and over but key up event doesn’t fire. So we are not removing those keys. We are adding multiple keys. we are adding the same key over and over increasing the size of the array. This can also be fixed easily. I only want to add that key into this keys array if it’s not already present in there. So additional condition here if this keys index of the key that was just pressed is minus one. Now when I press and hold the key gets added only once. When I release the button the key gets removed. Perfect. On key down event, I check if key that was pressed is arrow up. And at the same time, I check if arrow up is not yet in the array. Only then I push arrow up into this. Keys array. On key up event, I check if the key that we are releasing is present in the array. If it is, I remove it using splice method. We have the main logic now. And adding more keys is easy. Just be careful about brackets here. It’s easy to miss something and get an error. I wrap this part in another set of brackets and I check if key that is pressed is arrow up or arrow down like this.

    Now keys array on the main object can contain nothing and can be empty or it can contain up arrow key or arrow down key and it can even contain multiple keys at the same time. In our case both arrow up and arrow down. So now keys property on the main game object is an array that always keeps track of presses and releases of up and down arrow keys. I store this array on the main game object on line 67. So the information of what keys are currently pressed is available all over our code base. It’s also available inside our player class because player has this.game property here on line 35 pointing towards the main game object. I can simply check if this.game.keys keys includes a specific key and I can change player behavior from here. I check if this.game.keys includes arrow up. Notice that before I use index of method to check if element can be found in the array. I can also alternatively use built-in JavaScript includes method to do the same thing. The includes method determines whether an array includes a certain value among its entries returning true or false as appropriate. If this line returns true, we want player to move up. So we set speed Y from line 40 to minus one. Else if keys array includes arrow down, we set speed Y to + one. I save changes and click canvas. And now I can move player up and down by pressing up and down arrow keys. The only problem is that player will never stop moving. We need to add one more small condition. So else meaning this.game.keys keys array doesn’t include arrow up or arrow down. We set speed Y to zero. Instead of hard coding minus one and plus one here, maybe player speed is dynamic and player can speed up during a power up. For that purpose, it’s better to save max speed in a variable like this. So, we have current player speed on line 40 and maximum player speed on line 41. Let’s try two pixels per frame. And I replace hard-coded values with variables on lines 44 and 45. If we press arrow up, speed Y is minus max speed. If we press arrow down, speed Y is plus max speed like this. Now we can change player movement speed if we need to by changing max speed value on line 41. And this is one of the techniques I like to use to handle keyboard inputs in my games. If you have any questions or any suggestions how to improve this code, let me know by leaving a comment.

    player will be shooting lasers at enemies. We will create them by using a class I call projectile. Constructor will need three arguments. The main game object so that this class has access to game properties when it needs them and start in X and Y coordinates. Those need to be dynamic passed as arguments from here because starting coordinates of each projectile will depend on player’s current position. As usual, I convert the arguments passed to class constructor into class properties. Width will be 10 pixels.

    Height will be 3 pixels.

    Speed will be 3 pixels per frame. Update method will also increase horizontal xcoordinate from line 30 by speed from line 34. I will also need marked for deletion property which will be initially set to false. And if horizontal xcoordinate of this projectile object is more than width of the game meaning it has moved across the game area this object can be deleted. I will actually set it to 80% of the game area. uccessful projectiles will be coming from player here to somewhere around here because I don’t want enemies to be hit and destroyed off screen. Let’s say that the lasers have limited range. So if horizontal coordinate of the projectile is more than 80% of width of the main game area, set their marked for deletion property from line 35 to true. This will flag that projectile as ready to be deleted and removed from the game. We will remove them in a moment. Before we do that, we will also have a simple draw method that will take context as an argument and I call built-in fill rectangle method that will represent the projectile. I want to draw that rectangle at coordinates this do.x this doy and I pass it this dowidth this dot height from lines 32 and 33. We will use images and animations for everything soon. But first, let’s set fill style to yellow and draw yellow rectangles for our lasers.

    I will also have to define fill style here on the player otherwise that yellow color will apply on it as well. I can set it to green or black like this. So we have our projectile class ready. How do we add them into our game? One way to do it is by creating a special custom method on player class. Player will have two different attack modes. So I will call the basic one shoot top. In this mode, the lasers will be coming out from the mouth of our mechanical seahorse. When shoot top method is triggered, I take this projectiles array I will create in a minute and I will push new projectile inside using the class we just defined on line 27. I create this projectiles array on player class. This will hold all currently active projectile objects. Up here I can see that class constructor expects game X and Y as arguments. So I pass it this.game game from line 51 and the current player coordinates. So this dox from line 54 and this doy from line 55. I want player to shoot when we press a key. So I go up to input handler class. And here I will make it very simple. I go inside key down event and I say else if key is spacebar. So just space like this. You can also use enter or any other key if you want. When we press spacebar, use this.ame reference from line 10 and navigate to its player property and from there call shoot top method we just defined. Since I’m holding all projectiles here on line 60 on player class, I will handle projectiles here inside update method. I take this projectiles array and for each element in that array, I call update method we defined on line 39.

    Inside that method, I have this check. If the projectile moves across the screen, we set its marked for deletion property to true. I want to remove those elements from projectiles array. I will do it using JavaScript filter method like this. The filter method creates a new array with all elements that pass the test implemented by the provided function. So here I’m taking projectiles array. I call filter on it and the test is that I want all elements to have marked for deletion properties set to false. So exclamation mark here. This will filter out and remove all elements with marked for deletion properties set to true. And since we just said that filter creates a new array, we want to override the original array with the new one that was filtered here. With this line of code in place, every time we set marked for deletion property to true on any projectile object, it will get removed from projectiles array. I will check if it works by console login this. projectiles from inside shoot top method. I will also call for each on all projectiles from inside draw method and I trigger draw method from line 43 on each one. I remember that I need to pass it context. So I pass it along the value from here like this. I save changes and run my code. And I can see we have an error on line 45. I go up to line 45 and I forgot to call fill rectangle from context. So JavaScript doesn’t know what to do with it. I fix it like this. Now I click on canvas and I can move up and down using keyboard arrow keys and I can shoot using spacebar. In browser console I can see that projectile objects are being correctly added and removed from projectiles array. Perfect. Let’s remove these two console locks to clean up our code. Now the console is cleaner and it’s easier to see how projectile array adds and removes objects. Nice. Right now we can shoot without limits. I want the player to have limited ammo that slowly recharges over time. It will also get completely refilled when we collect a special power up fish. Down here I say if this.gamemo, game.mmo which we will create in a minute is more than zero only. Then create new projectile object.

    I go down here to line 104 and I create this new ammo property. Initially we will start with 20 ammo for example.

    Every time we create a new projectile we decrease that value by one. Now I can do it 20 times and then it stops. Even if I keep pressing spacebar, we run out of ammo. Here on line 80, I can change which coordinates the projectiles start from in relation to the current player position. We will match it even better when we apply player sprite sheet a bit later to make sure it comes out from the mouth of our steampunk seahorse. We will get back to this. I can offset it here or I can also do it inside projectile class itself.

    When we use all 20 projectiles, we completely run out of ammo. I want it to slowly recharge over time. To do that, I want to run a periodic event in our codebase. And I want to be able to measure time in milliseconds and say, for example, every 500 milliseconds, every half second, automatically recharge one ammo. To do that is easy. If you know this technique with timestamps and delta time, let me quickly explain how it works. Here on line 116, I create a variable. I call for example last time. Its job will be to store a value of time stamp from the previous animation loop so that we can compare it against the value of time stamp from this animation loop. This difference will give us delta time, the difference in milliseconds between the time stamp from this loop and the time stamp from the previous loop. Like this. Where does this time stamp value come from? Request animation frame method has a special feature. It automatically passes a timestamp as an argument to the function it calls. In our case, animate. I can use it simply by giving it a variable name here. You can call it whatever you want as long as you keep referring to that value using the same variable name. I will call it timestamp spelled like this. And I will use it to calculate delta time here on line 119. After we used last time to calculate delta time for this animation loop, we reassign last time to the time stamp from the current loop so that it can be used to calculate delta time in the next loop. So request animation frame autogenerates a timestamp value which is a number in milliseconds since this loop started. We access it here in animate. Assign it a variable name for example time stamp like this. We calculate the delta time which is the difference in milliseconds between the time stamp from this animation loop and the time stamp from the previous animation loop. And then we set last time to time stamp from this loop so that it can be used to calculate delta time in the next loop. Don’t worry if this is a bit complicated to understand at first. It’s a very common technique and it will become more intuitive as you use it in multiple projects.

    I can console log delta time to check if it’s working. My delta time is around 16.6 milliseconds. 1,000 milliseconds 1 second divided by 16.6 is around 60. So I can see that my game is animating at 60 frames per second. Let me know if you get the same value or something else. If you had an old computer, delta time value might be higher because it takes your computer more milliseconds to render animation frame. If you have high refresh gaming screen, delta time value could be lower for you. I wonder if we have any coders here who use that type of screen. Remember to remove your console locks when you don’t need them, especially this one that runs 60 times per second. It could affect the performance of our game if I just leave it here. So, we calculated delta time. We know how many milliseconds it takes for our computer to render one animation frame to run one animation loop. I will pass it to update method here. And we can use that value to run periodic events in our game or to measure game time. The advantage of this technique is that it doesn’t matter if you have strong supercomput or a very old slow one. Delta time measures actual milliseconds in real time. So periodic events will happen roughly at the same time on slow and fast machines regardless of their ability to animate our game slow or fast. To trigger periodic events in our game, I need two helper variables. one will be timer that will go between zero and some kind of predefined limit. Each time it reaches that limit, it will trigger some kind of event and it will reset back to zero to count again for the next loop. The second helper variable will be that limit that interval value that timer needs to reach. So I want to replenish some ammo every half second 500 milliseconds. I will also introduce some hard limit. I want the ammo to automatically replenish only up to this value not endlessly. So starting ammo will be 20. Maximum ammo will be 50. For example, inside update method on game class, I will use ammo timer and ammo interval helper variables and also delta time to trigger this periodic event that replenishes ammo every 500 milliseconds. I say if ammo timer from line 107 is more than ammo interval, so 500 milliseconds. Inside I will also check if ammo is less than max ammo like this

    only. Then I will increase ammo by one. Then I reset ammo timer back to zero so that it can count again. Else keep increasing ammo timer by delta time.

    I am calculating delta time on line 128 and I’m passing it to update method on game class on line 131. I make sure update method expects that value here on line 110 and that delta time value will get passed along here.

    Our ammo is already recharging but it’s not easy to check and see. I can console log these values but it would be nice to have some visual representation of our available projectiles as part of our game screen. I have user interface class here on line 95. I will use it to draw messages and game statuses that player needs to be aware of. This class will be very simple. A constructor will take a game as an argument. So we convert it to a class property as usual. We will define font size and font family. We will need it later to draw some score and game timers.

    I will also define color and I set it to white for example. It doesn’t need update method. It just needs a draw method. It will expect context as an argument and here I will draw a small bar for each available projectile. I create a for loop. It will run as many times depending on the amount of ammo we currently have.

    I will set fill style to this dot color.

    This should actually be outside the for loop like this. For each available projectile, I will draw a small rectangle. So, fill rectangle method. Add coordinates 2050. Width 3 pixels and height 20 pixels. Let’s draw what we have so far and then we can finish it once we can see what we are doing. Same as we did with player and input handle classes, I create an instance of user interface class here on line 116 inside game class constructor. It expects game as an argument. So I pass it this keyword. Now I use this UI property and I call its associated draw method we defined on line 102 and I pass it context. Nice. Right now we are drawing all 20 available projectiles on top of each other here. To make them align next to each other, I just multiply them by the index from the for loop like this. 20 pixels spacing is too much. How about a spacing of 5 pixels

    plus 20 pixels left margin like this. That’s better. Now we can see how our ammo is slowly recharging.

    I can change the color here on line 100. I can test it and it’s working really well.

    It will keep recharging until it reaches max ammo value of 50 and then it should stop.

    Yes, we will apply better visuals to our game in a moment. I just want to have a complete functional game skeleton first.

    We are missing one last important element in our main game loop, enemies. And some enemies will also work as powerups in this game. We will have multiple enemy types in our game with different visuals and behaviors. Let’s take it step by step to make sure we understand how everything works and how the player projectiles, enemies, and power-ups interact with each other. Enemy class will just contain the main blueprint, the properties and methods shared between all enemy types. We will then extend this class into multiple small subclasses. Each enemy type will have a separate child class that inherits from this main enemy parent class. All enemies will need access to the main game object. So I do this as usual. All enemies will also have the same starting horizontal X coordinate. They will go from right to left starting just behind the right edge of game area. So this gamewith horizontal speed of each enemy will be a random number between minus0.5 and minus2 pixels because I want them to move in minus direction to the left on horizontal xaxis. Marked for deletion will be set to false initially.

    Update method will adjust horizontal x coordinate by the amount of speed x value for each animation frame moving enemies from right to left. I check if enemy moved completely off screen all the way behind the left edge of game area. So if xcoordinate of the enemy plus its width is less than zero, we will set its marked for deletion property to true. Draw method will take context as an argument. At first I will just draw red rectangles representing enemies. So fill style red and fill rectangle at enemies x and y coordinates and its width and height like this.

    We will have multiple enemy types. Let’s start with the basic simple enemy angler fish. I call that class for example angler one and it extends enemy class from line 86. In this scenario we have a parent enemy class also called a superass and we have child angular class also called a subclass. This is a good example of the second principle of object-oriented programming called inheritance. Angler is a child of parent enemy class and it has access to its methods such as this update and draw as well as these properties. If I call a property or a method on angle class and JavaScript can’t find it on angular, it will automatically travel to the parent enemy class and it will look for it there. Inheritance is used to reduce code repetition. Instead of redeclaring the same methods and properties on each class, I can just declare them once on parent class and all child classes will inherit them automatically. We can also do other things here using a special super keyword. I will show you as we write the code. Angle class will have its own constructor because some properties will be specific only to anglerfish enemies in our game. If I don’t declare constructor on angler class at all, it will automatically use constructor from enemy class from line 87. In this case, I want the code from parent class constructor on line 87 to run. And I want to add some additional properties here. If I just declare constructor on angular, it will completely override parent class constructor. And this code would be ignored. So I have to use a special syntax to kind of merge them. I want first this code to run and I want to add little bit of it here. I do it by calling super which refers to superass parent class constructor. This line of code will make sure that the constructor on the parent gets executed. Now I can add some more properties that will be specific only for angular. Remember that if you want to combine constructors like this, you have to call super first before you use this keyword. Doing it the other way around will give you an error. I have specific sprite sheets ready for our project. So I know that width of a single frame in our angular sprite sheet is 228 pixels and height is 169 pixels. I want vertical y position to start from here and go 90% from the top because we will have some ground graphics in our game environment layer. These are flying fish machines. They need to be above ground. Rectangles and images on canvas are drawn from the top left corner. So, I want the starting vertical position on each enemy to be between zero here and 90% of game height here. But I need to offset it by the actual height of the enemy. Otherwise, they will be drawn too low down here. That’s why I define x coordinate on the parent enemy class on line 89. But I had to wait declaring vertical y-coordinate until I had height of that specific enemy type. It will all work together well. Now you’ll see inside update method on the main game class I will cycle through all enemies and for each enemy object inside enemies array I will call their update method. I also need to define this enene array here. It will hold all currently active enemy objects. I will again use filter method to filter out all enemy objects that have marked for deletion property set to true. The same thing we did with projectiles.

    And I will cycle through all enemy objects here. Call their draw method and pass it context. So we have enemy class. We are updating, drawing, and removing old ones. We need to figure out how to add new enemies into our game. I will have a special method on the game class called add enemy. Every time this method is called, it will push one new enemy object inside this enemies array. Notice that I’m not calling the parent enemy class. I’m calling the child angler one class here on line 103. I can see it expects game as an argument. So I pass it this keyword because we are inside that game class.

    Now I want to call add enemy in a specific interval. We will use the same technique we used to periodically recharge ammo and it will be much easier because we are already calculating delta time. I will need two helper variables. Enemy timer that will count between zero and enemy interval. I want to add new enemy into our game every 1 second every thousand milliseconds.

    Same as we did with recharging projectiles. I say if this enemy timer which starts from zero is more than enemy interval. H let’s go up here and also declare game over property and initially set it to false.

    Back here on line 162 I say and at the same time this game over is false because I don’t want to be adding new enemies when the game ended. And we call add enemy method from here. We will also reset enemy timer back to zero so that it can count again. Else meaning enemy timer is less than enemy interval. We will keep increasing enemy timer by delta time which is already being passed to update method here. Nice. We are adding big red enemies to our game. I go up to line 105 and I make the width and also height smaller just for now before we start animating sprites. I will make the entire game wider when we get to later stages. For now, we are just building the main logic loop. We have player that can move and shoot projectiles. We have recharging ammo and there are swarms of enemies coming at us. Nice work if you are following along. As usual, I want to check if enemies are being correctly added and removed from the array. So, I console log this enemies array here. I want to make sure that filter method on line 161 does its job and we don’t have endlessly growing array. It works well. Enemies that moved off screen to the left are being removed. Perfect.

    It’s time to add some interactions. I need to check if enemies collide with player and also if projectiles collide with enemies. To save ourselves code repetition, I will create a reusable collision detection method on the main game object. I call for example check collisions. This method will take two arguments, two objects. I will call them rectangle one and rectangle two. And it will return true if they collide and false if they don’t. It will be a reusable function. So we can use it later and pass it player and enemy as rectangle one and two. And we can also pass it enemy and projectile to check if they collide. Let me show you exactly how to do that right now. When checking if two rectangles collide, we compare their X Y width and height in a specific way. So all objects we are comparing need to have X Y width and height properties for this to work. I will return a statement in brackets like this. So if the code in brackets evaluates true or false, it will immediately be returned by this function. Quick and easy to check if two rectangles collide. We need to run four checks. We need to check if horizontal x position of rectangle one is less than horizontal position of rectangle 2 plus its width. If this side is to the left of this side, I will comment out line 196 just for a moment so the movement doesn’t distract us. At the same time, we need to check if horizontal position of rectangle one plus the width of rectangle one is more than horizontal position of rectangle 2. If this side is to the right of this side, if both of these statements are true, we know they’re in the same space on horizontal x-axis, but it still doesn’t mean they collide. They can be far away vertically. Because of that, we need two more checks. We need to check if vertical position of rectangle one is less than vertical position of rectangle two plus the height of rectangle two if this side is above this side. And finally we check if the height of rectangle one plus its y position is more than vertical y position of rectangle two if this side is below this side. If all four of these checks are true, this entire statement will evaluate to true and check collision function will return true. If at least one of these is false, the entire statement will be false. And we know these two rectangles don’t collide. We stay inside the main game class and go to its update method. In this for each call, we cycle through every object inside enemies array from line 141 and we call their update method. As we go through that array one enemy object at a time, we will check collision between player object from line 137

    and that particular enemy rectangle. I do this by calling our custom check collision method we just wrote and I pass it player as rectangle one and enemy as rectangle two. If this message returns true, we know we are colliding and I will set marked for deletion on that animator true. I go down to line 200 and I unccomment request animation frame again so that we can test it.

    I can see that whenever player collides with an enemy that enemy gets deleted. Perfect. We have some interactions in the same for each method. I will also check each enemy against all currently active projectiles. They are stored inside this. Player.p projectiles and I call for each on that array as well like this. For each enemy inside enemies array, we check against every single projectile in projectiles array. I say if this check collision between projectile from this iteration of this for each and enemy from this iteration from this for each if check collision is true decrease enemy lives by one at the same time set marked for deletion on that projectile that collided to true so it gets deleted then I check if enemy lives are less or equal to zero

    And if they are set marked for deletion on that enemy to true as well. And lastly, I will increase score by plus one. Actually, I want each enemy to give different amount of score points when defeated. So, we will increase game score by score property on that enemy. Now, I used three properties that don’t exist yet. I go up to parent enemy class and I declare them here. I set lives to five and score that this enemy rewards will be equal to the number of its lives like this. I will also draw that number on top of each enemy for debugging purposes by calling fill text. Here I pass it this lives from line 92 and X and Y coordinates of that enemy. It’s very small. So I will set fill style to black and font property will be set to 20 pixels Helvetica for now.

    I need to define score on the main game class here on line 154. And I will also define winning score. Let’s set it to 10 points for now so it’s easy to test. Every time we increase score here, we check if the current score is more than winning score. And if it is, game over from line 153 is true. I go up to line 130 inside draw method on UI class. In this area, I will write code to display the current score to the user. I call built-in fill text method again and I pass it the text I want to draw. So this.game.score score and I want to draw it at coordinates 2040. I set font property to this do font size from line 126 plus pixels space plus this do font family from line 127. I put a string that says score colon space here plus we will concatenate this.game.score. Let’s see if everything works. All seems to be fine except for the text colors jumping around. I will move this fill style declaration up here and I set this dot color to white.

    I can also do other adjustments to the text. For example, shadows. If I want the shadows to apply only to the text and not all the shapes on canvas, I will put it between built-in save and restore canvas methods. Save method of canvas 2D API saves the entire state of canvas at that point in time. That includes settings like stroke style, fill style, line width, global alpha, all shadow settings we will use in a minute as well as other things like cliin region or the current transformation matrix. So whatever we do with scale, translate and rotate canvas methods. Then we can change the state of canvas however we want and we call restore. Canvas restore method restores the most recently saved canvas state. If there is no saved state, this method does nothing. So save and restore only work when used together. I will start applying canvas shadows. If I did that outside save and restore, shadows would get applied to everything including player and enemies. But in our case, these shadows will only affect shapes and text we draw in this area between this safe and this restore. Shadow offset X defines the distance that shadow will be offset horizontally. It can be positive or negative depending on if you want the shadow to be to the left or to the right from the source element. Shadow offset Y defines vertical distance of the shadow. I set shadow color to black. I could also set shadow blur, but I don’t need it at this time. So by wrapping code in save and restore, I make sure that canvas shadows and this fill style property affect only this drawing code and not other shapes and graphics we are drawing on the same canvas element. This is a pretty solid code base. You can use this as a base boiler plate for many different games. Maybe some of you want to make a copy of this project at this state and save it in a different folder so you can experiment with it later and use it as a starting point of a different game project.

    Win and lose condition in our game will depend on how many score points can the player get in a specific time window. We are going to handle those game over messages here before we call restore. So if game over property on the main game object is true, we set text align to center. We are going to display message one in larger letters and under that there will be message two and smaller font. What these two messages say will depend on how many score points we manage to get in a specified game time. I check if game score is more than winning score. Message one will say you win

    and message two will say well done. So that’s our winning message. Else we display the losing message. So message one is you lost.

    Message two is try again next time. Now we actually need to draw these messages on canvas. So font for the first message will be 50 pixels space plus font family. Then I call fill text and we draw message one in the center of the screen. So x coordinate will be game width time 0.5. Vertical y-coordinate will be game height time 0.5.

    I copy these two lines of code and I change some things to draw message 2 in smaller letters. 25 pixels here and message two here.

    I try to play the game and win. Nice. We get a winning message. I need to create some space between the lines. So, first message will be minus 40 pixels vertically and the second message plus 40 pixels vertically. Let’s see.

    Yeah, this is fine for now.

    We need a time limit for our game. On the main game object, I create two helper variables. I call them, for example, game time, which will start at 0 milliseconds, and time limit. For testing purposes, time limit will be 5,000 milliseconds, 5 seconds. After 5 seconds, the game will end. And depending on how many score points we manage to get, we will display winning or losing message. In update method, I say if game over is false, take game time from line 181 and increase it by delta time. Delta time is the difference in milliseconds between time stamp from this animation loop and the time stamp from the previous loop. So, it’s the amount of milliseconds between frames. By adding delta time to game time every time we draw a new frame, we are keeping track of how many milliseconds passed since the game started. Game time variable is simply just accumulating milliseconds since the game started. If game time is more than time limit from line 182. So when the game has been running for 5,000 milliseconds, we set game over to true. The final game will run longer. I just use 5 seconds time limit here so it’s easy to test. Up inside UI class, we want to draw game timer on screen. Let’s do it in this area on line 143. I call fill text and the text will say timer colon plus this.game time add coordinates 20 100. Actually the variable we just created was called game time like this. And I need to add space here.

    Nice. So we can see game timer. I want to format that value so it looks a bit cleaner. I create a temporary helper variable called formatted time. I want to move the decimal point to show seconds. So this game.game times 0.001.

    That works. I also want to display only one digit after the decimal point. So I use built-in two fixed method and I pass it one. Two fixed method formats a number using fixed point notation. We can use it to define the number of digits we want to appear after the decimal point. Perfect. We have game time functionality. I’m getting a back when I get a losing message and then I defeat a couple of remaining enemies and that message switches to the winning message. I want to make sure that after game over message appears, we are no longer able to gain more score points. Down here inside update method on game class, I only want to increase score if game over is false.

    I get an error. It’s supposed to be this.ame game over like this. This will fix the bug. We have the base game. We have player, enemies, and projectiles. We have recharging ammo, score, timer, and win and lose condition. You can save this code in a separate folder and use it as a base skeleton for many different games if you want. From this point, I will start adding graphics and features that will be specific to our steampunk alien game. This will be the fun part. Let’s go.

    We will be using large detailed images and graphics today. I will put all of them here inside index html. And because all the code in script js is inside event listener for load event, JavaScript will only run after all our images have been fully loaded. This will prevent errors. I will separate our assets in this project into three different categories. Characters, which will include player and enemies. props, which will include things like mechanical parts that fall from enemies when we damage them, and game environment. Let’s start by creating the game world. First, img element with an ID of layer 1, and source will point towards that.png file. You can download all project images in the description. I will put all my images into a project folder I call assets. Our game world will be made out of four separate layers for parallax scrolling effect. layer one, two, three, and four like this. I don’t really want to draw these images on the web page like this. I only want to draw them on canvas with the JavaScript. So, inside style CSS, I set all of them to display none.

    In script JS on line 116, we have a custom class I called layer. Its job will be to set up each individual layer object. constructor will expect three arguments coming from the outside game, image and speed modifier. I convert those arguments into class properties like this.

    The width of the images we are using is 1,768 pixels and the height is 500 pixels. horizontal x coordinate will start at zero and y will also be zero.

    We will need update method to move the background layers from right to left as the game scrolls. If horizontal xcoordinate is less or equal to minus width from line 121, meaning the background image has moved across the screen and is now fully hidden behind the left edge of canvas. We set x back to zero so that it can scroll again. else decrease X by game speed times speed modifier. Each layer object will have different speed modifier to create parallax but all will depend on the main game speed variable so that all four layers can be controlled from one place. Game speed variable doesn’t exist yet. So I create it on the main game class here. Initially I set it to one. Layer class will also need a draw method. It will take context as an argument. I call built-in draw image method. This method needs at least three arguments. Image we want to draw. So this do image from line 119. And where on canvas we want to draw it. So I want to draw it at this.x this.y from lines 123 and 124. So we have our layer class which will handle individual background layers. We will also need background class that will put all four layer objects together to create the game world. Constructor will take the main game object as an argument. I convert it into a class property like this. Here we will grab all four images for each layer with JavaScript. So this image one will be document getelement by id and I pass it layer 1. The ID I give it in index html. This layer 1 property will be an object that holds an instance of layer class from line 116. So new layer like this. On line 117 I can see that layer class constructor expects game. image and speed modifier arguments. So I pass it this game from line 137. This do image one from line 138 and speed modifier will be one for now. Update method will move all layer objects

    and draw method will draw all of them. We will hold all layer objects inside this dot layers property. It will be an array. Let’s start with just layer one.

    Inside update method, I take this layers and I call for each method. For each layer object call their associated update method we declared on line 126. Draw method will expect context as an argument to specify which canvas we want to draw on. Inside we will do the same thing. call for each on layers array and for each layer object trigger its draw method and pass it that context value because we know that the draw method on line 130 expects that argument. So background will handle all layers to create the game world. Layer class will handle logic for each individual background layer object separately. Now to animate the background I just need to create an instance of background class inside game class constructor. Same as we did before with player and input handler classes. Background class expects game as an argument. So I pass it this keyword because I’m inside that game class. Right now inside update method on game class, I take this new background property and I call its update method. Inside the draw method on game class, I call draw method on the background object and I pass it context along here. Notice that I am drawing background first, then the player. This will make sure that the background is behind the player and doesn’t cover it. I’m getting an error. I go back to my background class and I want to put this layer 1 object into the array. So, I have to use this keyword.

    Nice. We are animating layer one of our background. I can change scrolling speed by changing the value I pass as a speed modifier. If I pass it five, the game speed is one because I’m multiplying game speed times speed modifier. 1 * 5 is five. So background will scroll at the speed of five pixels per frame. I will bring all other layers into the project. I bring their images first. Then for each one, I create an instance of layer class

    and I put all of them inside this dot layers array.

    Okay, now we see all four layers. I give each layer a different speed modifier. These values are passed as speed modifier and they will be multiplied by the current game speed. You can control scrolling speed of each layer individually like this. For now, I will set speed modifier to one on all four layers. You can see that because of line 128, as soon as the layer images slide completely off screen, they reset back to X position of zero so that they can slide again. We are getting this gap. To get a seamless scrolling background effect, we can use a simple trick. We can place a second identical image next to the first one. So at the point where the first image doesn’t fill the entire game area, the second image comes in to fill the gap. The second image will never be fully visible. It will be filling in just for that short period of time before the first image can reset to its starting position again. Reset to the original position happens in one frame. So it’s not visible by naked eye. It will create an illusion that we have one endless seamless background. How do I apply that in code? I simply draw a second identical image. But I need to make sure it is next to the first one. The second image will start where the first image ends. So its horizontal x position will be this. X plus this dowith like this. And that’s it. We have endless parallax background implemented in our game. I can change its scrolling speed by adjusting speed property on the main game object. Or I can change speed modifier values I pass as arguments when I create individual layer objects. I’m getting a small stutter when the background images reset back to position zero. I fix that by removing this else statement here.

    Now the reset should be smooth and not noticeable. I can also use small values as speed modifiers. I want the back layer to scroll very slowly. If I use speed modifier 0.2 and base game speed is one, that layer will scroll by 0.2 pixels per frame because we are multiplying game speed by speed modifier. I will try 0.2 0.4 four one because layer three is this ground image so that it should scroll the same speed as the rest of the main game objects and layer four are these items in the foreground so I will make them scroll at 1.5 base game speed the issue we have right now is at layer four these foreground objects should be in front of the player but right now they are behind because in the main animation loop I’m drawing all four background layers before I draw the player there are multiple ways to solve this I’ll use the simplest possible ible solution. I will draw only layer 1, two, and three here as part of the background class and remove layer four to draw it separately later. Because I removed layer 4 from the array, I need to call its update method first. From inside update method on the main game class here on line 226, I’m calling background.update which updates layers 1, 2, and three. And I will also call update on layer four like this. Inside draw method, we are redrawing all elements that make up our game for every animation frame. First, we draw the background which now contains only layer one, two, and three. Then, we draw the player on top of that. Then, we draw UI, then enemies, and on top of everything, we will draw background layer four to make it appear in front of all other game objects. The thing to understand is that since we are drawing everything on the same canvas element, what is drawn first will be drawn behind the thing that is drawn after. Background will be behind the player.

    Time to draw the player. We start by bringing player image into the project here in index html. I created this seahorse sprite sheet that you can download and use. We will have basic swimming animation and we will have power up animation row because when the player collects a special overcharged fish, it will absorb its energy. The player’s eyes and chest will light up and player will shoot two lasers instead of one. In script js, I go to line 59 inside player class constructor and I bring the image into the project using get element by ID. Same as we did with background images. In style CSS, I give player image display none.

    We are bringing the image into JavaScript project here on line 59. inside the draw method. Currently, we are drawing a black rectangle representing the player. To draw the sprite sheet, I will use built-in canvas draw image method. I pass it the image I want to draw. So, this image from line 59 and X and Y coordinates where I want to draw it. I want to draw it at player’s current X and Y position from lines 54 and 55. You can see we are drawing the entire sprite sheet with all its frames and rows. Draw image method can accept three arguments like this. We can also give it five arguments by adding width and height. In case of a spreadsheet like this, it will just squeeze all frames into an area of one frame. We don’t really want that. What we need is the longest version of draw image method that expects nine arguments and it gives us the most control over the image we want to draw on canvas. Those nine arguments are image we want to draw, source X, source Y, source width, and source height of the area we want to crop out from the source image, and destination X, destination Y, destination width, and destination height to specify where we want to draw that cropped out piece of image on destination canvas. We will need some helper variables as well. Frame X will cycle through the sprite sheet horizontally. Frame Y will determine row of the sprite sheet. In this case, row zero or row one. I need to crop out just one frame from the source spreadsheet image. So source X will be frame X times width of a single frame, which in our case is the width of player. Because I like to size my images to the same size we will draw them in game. When frame X is zero, we display this frame. When frame X is one, 1 * width of 120 pixels is 120. So we will draw this frame. Frame x2 will be 2 * 120, so 240 pixels, this frame, and so on. It will work the same with frame Y vertically. Frame Y times height of the player, which is identical to the height of the sprite sheet frame. Source width is width of a single frame. Source height is height of a single frame. Now we are cropping out just one frame. Perfect. I will animate the sprite sheet by cycling between frames horizontally from zero to max frame. In the case of player sprite sheet, max frame is 37, we count from zero. I will handle sprite animation logic down here. It’s simple. If frame X from line 56 is less than max frame from line 58, increase frame X by one. Else reset frame X back to zero. If you prepare your sprite sheets well in graphics editor, the way I prepared the seahorse for you, you only need very little code to get the animation. If I set frame Y to one, we will see the second row in the sprite sheet. We will use that for power up state. For now, I set it back to zero.

    At this point, I no longer need the black rectangle that represents the player. But it is still useful to keep track of that area because it will be player’s hitbox used for collision detection. I replace fill rectangle with stroke rectangle. I remove this fill style declaration. Stroke style will be black by default unless we set it to a different color. I want to have a debug mode in my game. When I press letter D, the game will show hitboxes and maybe other things like enemy hit points. player hitbox is this black rectangle we are outlining. So I only want to draw that if gamedebug is true.

    I need to create that property. So down here inside game class constructor I say this debug is true. The last thing I need is to create a switch that will allow the user to toggle debug mode on and off by pressing letter D. To create a toggle with JavaScript is simple. I go up inside our input handler class. And inside key down event listener, I create an else if statement and I check if the key that was pressed is letter D. If it is, I set the new debug property we just created on the game object to its opposite value. So if it’s true, I set it to false. If it’s false, I set it to true. Now when I play my game, I can toggle debug mode on and off by pressing the letter D. At this point, debug mode only shows and hides player hitbox. But we will attach more functionality to it a bit later.

    Nice. We are making a lot of progress. Let’s add more characters to the game. The base game loop will have three enemy types. I created multiple animations for each enemy type to give our game more variety, and I will show you how easy it is to swap between them. You can download all art assets in the project files in the section below. I made these character spreadsheets for you, so feel free to keep them for your personal projects. You can modify them and do whatever you want with them. You can credit me if you use it for your personal projects, but only if you want. Also, if you want the base Photoshop files or separate pieces in PNG format for all these characters so that you can animate them and turn them into spreadsheets yourself, let me know. The best free software to create custom sprite animations is Dragon Bones. If you want more advanced features, there is also a paid software called Spine. You don’t need any of that because I’m already giving you complete readytouse sprite sheets. This is just for those of you who want to learn more and create custom animations or different animations than the ones I created for you. So, I’m bringing three new images into the project. Angler one will be the most basic anglerfish enemy type. The sprite sheet has multiple different animations for the same character model, and we will use all of them in a minute. The second character is a different type of angler fish with more gears and chimney. These are steampunk machines that come to life. I gave them a lot of mechanical parts. These two anglerfish enemies will be just a simple basic enemy type that comes at the player trying to eat it. They are not very resistant and they are easy to deal with using our seahorse sentinel lasers. The only advantage they have is that they can come in big numbers sometimes. To deal with that, we have to be smart and use our slowly recharging ammo wisely. We can use the third enemy type to help us. I call this third enemy type lucky fish because it will be an enemy but also a power up at the same time. It will have two different models, different skins that we will use randomly when we create a new one. And the way we use this enemy type to make gameplay more interesting is that the player can do two things when this enemy appears. We can shoot it for a lot of score points or we can collide with it to collect it as a power up. It doesn’t have many lives. So players also have to be careful not to destroy it accidentally before they can collect it and activate the power up. The story is that this is an overcharged fish and when the sentinel seahorse collides with it, it absorbs its light and power to activate its ultimate offensive mode for a short period of time. It will all be represented by graphics to make it clear to the user what’s happening. So here is the parent enemy class and here we have a child angle one class that extends it and inherits from it. I will add this image property and I point it towards the spreadsheet we just included in index. HTML like this. We have three different animations that loop and when we create a new angular fish, we will assign it one of these three randomly by setting this frame Y property to a random number between zero or one or two. So math at random times three wrapped in math floor

    like this. Right now we have these small red rectangles representing each anglerfish enemy. Same as I did with player, I replace fill rectangle with stroke rectangle and I remove this fill style declaration.

    And also this one to draw enemy sprite sheet. Same as we did with player sprite sheet. I use built-in canvas draw image method. I pass it image I want to draw. So this dot image from line 124. If I just pass it X and Y coordinates, it will draw the entire big spreadsheet with all frames and all rows. I declare frame X that will help us to navigate in the spreadsheet horizontally. Frame Y will navigate vertically.

    Max frame will be the maximum horizontal frame which is 37 for this particular sprite sheet. I only want to draw enemy hitboxes when debug mode is active. So this line will run only if this.game.debug is true. I want to draw them at the original full size. So I remove this temporary size modifier we created earlier. If I pass a draw image method additional width and height, we will squeeze all frames into an area of one frame. So I will add four more to define an area I want to crop out. Same as we did with the player. So source X, source Y, source width, and source height. So image I want to draw, four arguments for the area I want to crop out from the source image and four arguments for where to place that cropped out image on destination canvas. Source X will handle horizontal cycling through the sprite sheet and it will be frame X from line 106 times width from line 124. We keep width property on a subclass because it will be different for each enemy type. Source Y will be frame Y from line 107 times height from line 125. Source width will be this dowidth. Source height is this doheight. I’m giving you spreadsheets that are already sized exactly as they will be drawn in the game. So, we don’t have to do any scaling with code here. It’s simpler and it’s more performance efficient to do it this way. The sprite animation itself will be simply going between frame x0 and max frame over and over. We will handle it here inside update method. If frame x from line 106 is less than max frame from line 108, increase frame x by one. else reset frame X back to zero and we are animating our first enemy type. The final game will be wider. I just keep the game area smaller so that I can show you everything on one screen. In style CSS, I hide images with ID angler one, angler two and lucky. I can set the game width to 700 pixels so that the large enemies fit better. You can see that each enemy fish has been randomly assigned one of the three possible animations I prepared for you. It gives our game a nice variety. I needs to account for game scrolling speed when calculating enemy positions. So down here inside update method on enemy class, I say this.x plus equals this. Speedx minus this.game.speed. This way we can have dynamic events that change game speed and enemies will always be correctly positioned in relation to our scrolling game world.

    Let’s add the second type of angler fish I created for you. I copy this child class that extends the parent enemy class and I call it angr 2. Width of a single frame is 213 pixels and height is 165 pixels.

    For this anime model, I created two different animations. So frame Y can be row zero or row one. So now we have two different enemy types. I want to have a simple functionality where I say something like when you create a new enemy in the game in 50% of cases make that enemy angler one. Otherwise make it anglr 2. We will handle that logic inside add enemy method. We will do it by rolling dice once every time we create a new enemy. So helper variable I call randomize is math.random. math.random declared like this will generate a random number between zero and one. If that random number is less than 0.5, create angler one enemy type.

    Else create angler 2.

    Up here on line 249, I increase game limit to 15 seconds. So we have some more time to test everything before game over is triggered. Immediately I can see the new angler 2 enemy type and I can see we are playing both animations. Perfect. Giving graphics like this for your game will go a long way to help you create unique stories and adventures for your players. If you are interested how to take drawings of static characters and turn them into animated sprite sheets with free dragon bones software like I did with this seahorse and angler for this class, let me know and I might make a course on that. On enemy class, I have this lives and this score properties. I want each enemy to have different values here. So, I cut it here and I paste it on each enemy type individually. Angler one will have two lives and when we defeat it, we will get two score points. Angler 2 will have three lives and it will give three score points. Quick test to see if everything works. I can see enemy lives and it gives the correct amount of score points. Don’t worry about the color of the numbers right now. We will fix that later.

    Let’s create a third enemy type. I copy this code block and I will call this subclass lucky fish for example.

    Width will be 99 pixels and height 95.

    This fish will have three lives and if destroyed it will award 15 score points. I will give it a property I call type and I will set it to lucky. We will use this to check which enemy type player collided with. Down on line 314 inside add enemy method. I add another else if statement like this. If random number is less than 0.3, we create angular one. Else if it’s less than 0.6, we create angler 2. When the random value is between 0.6 and 1, we create lucky fish using the new class we just wrote. There’s something strange happening with the animation. I go up to lucky fish class to see what’s wrong. I can see that on line 153 I need to point this image property to the correct sprite sheet. And we are animating our special lucky fish power up. There are two models because the sprite sheet has two rows and we are randomizing vertical coordinate with frame Y here on line 154.

    When the player collides with one of these special overcharged fish, it enters a power up mode. Let’s write that code now. We start by declaring this. Power up property on the player up here on line 65. Initially, I set it to false. Power up will last for a while and then the player will go back to the normal state. So, we will need another timer. We can use delta time for it. We will have two helper variables called power up timer and power up limit. Power up timer will be counted milliseconds. When it reaches power up limit of 10,000 milliseconds, 10 seconds power up state will end. We will handle that logic here in update method on player class. I say if this power up from line 65 is true, we enter this code block. Inside we check if power up timer is more than power up limit

    and if it is we set power up timer back to zero and power up to false. We will also set player sprite sheet to frame Y0. So normal default animation else mean and power up is true and power up timer is not yet higher than power up limit. The player is in power up mode and power up timer is counting milliseconds by adding delta time. We calculated delta time before inside the main animation loop. It’s the difference in milliseconds between time stamp from previous and the current loop. We need to make sure update method expects delta time as an argument on line 69.

    And we pass it to this method inside update method on the main game class here on line 286.

    So we are counting timer and frame Y is on the second row. So value is one. We count from zero. That will give us a special animation with light coming from chest and eyes. And also tail will animate differently because while in this state we will shoot two lasers, one from the nose and one from the tail at the same time. Two lasers for the price of one ammo. At the same time, we will be recharging ammo by 0.1 per frame. And this will be on top of the regular recharging speed. So ammo will be recharging very fast while in power up mode. So when power up is set to true, we enter this code block. Power up timer is increasing by delta time, counting how many milliseconds we are in power up mode. Frame Y is animating special overcharged animation and ammo is recharging fast. As soon as power up timer increases over the value in power up limit which will happen after 10 seconds 10,000 milliseconds we set power up timer back to zero. We set power up to false and we set animation row back to normal regular floating animation.

    Inside update method on game class in this area where we check for collision between player and enemies. We check if type property on that enemy is set to lucky.

    If it is, we call a special method on the player object called enter power up. We will write it in a minute. Else if we collided with another enemy that is not lucky fish, we decrease score by one as a penalty to the player. This will encourage player to collide with power up fish and avoid regular enemies to get maximum possible score.

    I go up to player class here on line 111. I create that method. So enter power up. Its job will be to set everything up when player enters power up state. I could have used state design pattern, but we don’t have that many player states. So, we can do it simply like this. When we enter power up, we set power up timer back to zero in case we collided with power up fish while we are already in power up state. This will make sure the timer resets and we get full 10 seconds from that second collision. Reset power up property on player object to true. We will also recharge ammo to its maximum possible value.

    I test it. I collide with our special overcharged fish and player gets overcharged. We are in power up mode and ammo is instantly refilled and it’s recharging very fast. Perfect. After 10 seconds, power up ends. Ammo stops recharging because we are well over max ammo value and player sprite sheet switched to the basic floating animation. Great. So when we are in power up mode, our sentinel seahorse will shoot defensive lasers from mouth and tail at the same time. It’s overflowing with energy and it can shoot extra free projectiles from tail every time it shoots one from the mouth. We can handle that functionality with JavaScript very easily by declaring additional method I call shoot bottom. In shoot top we handle shooting from the mouth. In shoot bottom we will handle logic for tail lasers. So inside I check if ammo is more than zero and we just push new projectile into projectiles array.

    I adjust its horizontal and vertical starting position because I want it to be coming out from the tail. I will call this method from inside shoot top like this. While we are running the code in shoot top, we check if we are in power up mode. And if we are, we execute shoot bottom method as well to add that extra free projectile. I tested lasers are just coming out from Seahorse’s mouth in basic floating state. If we collect the power up fish, we enter power up mode and both shoot top and shoot bottom methods are running. We are shooting two projectiles, but it costs only one ammo. Getting overcharged makes the player very powerful. Maybe we need some bigger bulkier enemies so we get more challenge. I made two types of mechanical whales for player to defeat. Probably you will need these powerups to do so. I want the projectiles to come from behind the player. We are drawing projectiles inside the draw method on player class. If I want them to be drawn behind, I need to make sure we draw projectiles first and the player second. Like this. I want to make it even more visually clear when powerup mode is active. For example, I can make this ammo display up here different color while in power up. We draw all these UI elements in our custom UI class on line 243. Before I draw all these small rectangles representing ammo, I check if power up property on player class is true. If it is, I set fill style to a different color. I want that color to be similar to the glow effect we have on our spreadsheets. So maybe this

    it works. The problem is that it also recolors the timer text because we define fill style here. We draw ammo and then we draw the timer. I can keep drawing ammo at the same coordinates in our game and I can move this entire code block further down.

    That way this white fill style will apply to timer and the other color will apply only to ammo like this.

    Instead of drawing a rectangle representing a laser projectile, we can also use an image. I bring it into the project here in props section in index html. You can download it in the video description or you can use your own image. I give it an ID of projectile. I bring it into the project here on line 38 inside projectile class constructor. This do image equals to document.getelement by ID and I use the ID I just gave it. So right now we are drawing yellow rectangles representing our projectiles. I delete that and instead I will use draw image method. This time it’s simple because the image is already the right size. I just give it three arguments. The image I want to draw and X and Y coordinates where to draw it on canvas.

    Nice. We are drawing images. These projectiles can also be animated either using a special sprite sheet or all different kinds of particle effects. We will use spreadsheet to animate projectiles in a bonus section of this course.

    Let’s add a web font to make the text look better. Adding a font to a canvas game is very simple. I go to Google fonts and I search for bangers. I like this comic book style. When you have your font, you click select your style here. You can select multiple different fonts like this if you want. Then we go up here to view selected families. If you choose more than one, this code will be adjusted to contain all of them as part of a single declaration. All we need to do to bring the font to our project is to copy these link tags and paste them up here in index html, ideally above the main CSS stylesheet to make sure the fonts are available from there as the code gets executed line by line from top to bottom. I go back to Google fonts website and here it also gives us a readym made CSS font family declaration. I copy it and I put it inside our style CSS file here on canvas element. Now my font is available. So I go to script js. Inside UI class I set this custom font family property we wrote before to bangers. And now all the text drawn by UI class. So score timer and game over messages will use the new font. Let’s adjust the winning text to something less boring. I want to keep the Victorian steampunk explorer theme going for this game. So, winning message will say most wondrous in big letters and with an exclamation mark. Secondary smaller message, we’ll say well done explorer. For the losing message, let’s use another old phrase. I will say blazes with an exclamation mark. It’s a word for when something goes wrong in old English.

    Secondary small message will say hm get my repair kit and try again for example. You can come up with your own messages here if you want. Now I have my messages in a new font so I can adjust the sizing and spacing. I want the main message one to be much bigger. I try 150 pixels. Well, that’s way too big. We could also adjust the text size to match the width of canvas, but let’s keep it simple for now and set it to 100 pixels.

    H I think I will go with 70 pixels.

    I want the messages to be closer together. So instead of 40 pixels offset, I tried 20 for both of them.

    I’m happy with the spacing and font size for now.

    I can see that we still have the projectile image visible in the top left corner of the browser window. So in style CSS I set it to display none. We can also see the spacing of the loin message. Now looks good. I would also like the little numbers above each enemy that represent their lives to be only visible when debug mode is active. To do that, I go up to enemy class and inside draw method, I only want to call that fill text method if debug mode is active. If debug property on the main game object is true.

    Let’s test it.

    Yes, I can only see hitboxes and enemy lives when in debug mode. Perfect.

    I want to make sure that player cannot leave the screen. Right now, if you press up or down arrow for long enough, player will move completely off screen. Inside update method on player class, we will handle vertical boundaries. Let’s start with the bottom boundary. If this doy vertical position of the player is more than the height of the game minus the height of the player, meaning that the bottom edge of the player is touching the bottom edge of the game area. Make sure we cannot move past this point like this. I actually want the player to disappear halfway so that it can avoid very big dangerous enemies we will add soon. I will do that by multiplying player height times 0.5 here and here. Now we can move half the seahorse’s body outside the screen and then we hit the boundary we just defined. I will do the same thing for the top boundary. Else, if player’s current vertical y-coordinate is less than minus player height time 0.5, meaning that the top half of the seahorse is offcreen, make sure it cannot move any further up like this. I test it. Top boundary works. Bottom boundary works. Perfect.

    Up on line 48, we have a particle class. I will use it to create broken parts fallen from enemies every time we hit them and for a big spray of spare parts when we completely destroy an enemy. We will also make those parts bounce from the floor for a specific number of times before they fall off screen. Particle class constructor will need a reference to the main game object. Start in horizontal x coordinate and start in vertical ycoordinate. I convert those arguments into class properties. As usual, we will use a spreadsheet with nine images in a grid. Each particle object will randomly choose one of these images so that we have some variety. This image is document.getelement by ID and ID will be gears. In index html, I bring it into the project here in the props section. ID is gears and file name is gears.png. You can download it in the project section as usual.

    In style CSS, I hide it by giving it display none.

    Here we are referencing that image with JavaScript. I will need some helper variables to navigate around the sprite sheet. Each particle object, each spare part flying from the enemy will have a random image assigned from these nine available options. Frame X will be a random number between zero and two. So column zero or one or two. Frame Y will be the same. So row zero or one or two. Combination of frame X and frame Y value for each particle object will point to a specific image in the grid. For example, frame X 2, frame Y1 will be here. Sprite size will be the size of individual frame. In this case, frames are squares 50 * 50 pixels. I want each particle to have a different size when drawn on canvas. So we will create size modifier and we will set it to be a random number between 0.5 and one. I will set it to one number after decimal point to reduce artifacts. So particle size will be sprite size multiplied by size modifier to make sure every particle is a different random size when drawn on canvas. I want particles to fall in both directions horizontally from the enemy. So speed x will be a random number between minus3 and + three. If it’s minus, it will move to the left. If it’s plus value, it will move to the right on the positive direction on horizontal x-axis.

    Speed y vertical speed will be a random number between zero and minus15. So particles will always start moving upwards on the negative direction on the vertical y-axis before they start being pulled down towards the ground by gravity. I set gravity to 0.5. Let’s see what kind of curved movement we get. We can adjust it later. Marked for deletion will initially be false. I want the [ __ ] wheels and spare parts to rotate as they fall. So I will have an angle property storing rotation angle for each particle separately starting at zero. And the speed of that rotation will also be randomized in this. VA property velocity of angle. Rotation speed will be a random value between minus0.1 and plus0.1 radians per animation frame.

    In update method, we will increase the rotation angle by VA. Speed Y will increase by gravity which will give it a nice curve. Let’s say the particle will start moving upwards because starting speed Y is -15. As we increase speed Y by gravity from line 6 to1, that minus5 value goes closer to zero. At that point, when it reaches zero, it will stop moving and it will be at its peak height. As speed Y further increases by gravity value into positive numbers, it increases by 0.5 per animation frame. That particle will start falling down faster and faster until it disappears below the bottom edge of canvas. This dox minus equals speed X to move particles horizontally. this do y plus equals speed y to actually apply that speed y value affected by gravity to the vertical coordinate of each particle. If the particle fell off screen vertically, so its y-coordinate is more than game height plus size of the particle. Or if the game scrolled past the particle, so its x position is less than zero minus particle size. Set its mark for deletion property to true.

    Draw method will take context as an argument. We call draw image method. pass it the image we want to draw and XY width and height where to draw it on canvas. Since the particle image is a grid of frames, it’s a sprite sheet. We only want to crop out one individual frame for each particle object. I will also need to specify cropping position. So source X, source Y, source width, and source height. Source X is this frame X from line 54 times this. sprite size from line 56. Source Y is frame Y time sprite size.

    Source width and source height will be this dot sprite size like this. We want to crop out a frame 50 * 50 pixels from the source sprite sheet. Then we multiply that by size modifier and we draw it at that scaled size. We will need an array that holds all active particle objects. I will create it here as this particles property on the main game object.

    For each particle in that array, we call their update method like this. Use an ES6 arrow function syntax to keep the code cleaner.

    After that, I call built-in filter method on that array and I replace that original array with a different one that contains only particles that have marked for deletion property set to false. All the particles with mark for deletion property set to true will be removed.

    Inside the draw method, again we call for each on each particle object. We call its draw method and we pass it context as an argument as it expects up here on line 73.

    We have our particle class ready. We just need to find a good place in our code to add these particles. I go down to update method on game class. And here where we check for collisions between projectiles and enemies, I create a for loop. This for loop will run 10 times.

    And each time it runs it takes this particles array and it will push new particle object inside. I know that particle class constructor expects a reference to the main game object as the first argument. So I pass it this because right now in our code we are inside that game object. Each particle also needs starting X and Y coordinates. So I pass it X and Y of the enemy that just collided with a projectile. I don’t want the particles to come from the top left corner of each enemy. I want them to come from the middle. So, I add enemy width time 0.5 horizontally and enemy height time 0.5 vertically.

    I copy this for loop. I actually want 10 particle spare parts to fall from the enemy when it collides with the player and gets destroyed.

    down here. I remove the for loop and just push one particle. I test it.

    Nice. We have a splash of spare parts coming out of enemy when they are destroyed by colliding with the player. Player in this game is indestructible. We will make that clear by giving it a special animated shield later in the bonus section. I copy this code that adds just one particle. And I actually want to put it here. So that every time projectile collides with enemy, one particle falls out. Nice. So now every time enemy gets hit by a projectile, one particles per part falls. If enemy is destroyed by colliding with the player, 10 particles come out in all directions. I want the particles to bounce off the floor for a specific number of times before they fall off screen. To make this effect even more intense, I go up to our particle class. And here on line 65, I create a helper variable. I call it bounced. And initially I set it to false. I also want to define a margin from the bottom end of canvas from which point the particles will bounce. So I call it for example bottom bounce boundary like this. And I set it to 100 pixels. If particle reaches this point, I want it to bounce. So I will switch its speed Y value to its opposite. If vertical position of the particle is more than game height minus bottom bounce boundary. So somewhere around this point. And at the same time if this dobbounce from line 65 is false. Set bounced to true so that it doesn’t bounce again after this. And set speed Y to its opposite value by multiplying it times 0.5.

    So particle is falling. It reaches this point and its current speed is for example + 5. We switch it to minus 2.5 making it bounce moving upwards again. Still line 70 keeps applying gravity. So eventually we reach zero and go into positive numbers making the particle curve towards the ground again and eventually fall off screen. It bounces once sets bounced to true. So this if statement check will fail for the second bounce and particle will just fall off screen.

    Maybe I don’t want particles to all bounce from the same vertical point on the ground. How about they bounce from a range between this and this point roughly to match our ground level image. So bottom bounce boundary will be a random value between 60 and 160 pixels from the bottom edge of canvas area. What about if we want to specify how many times each spare part bounces from the ground rather than having them bounce just once? On line 65, I set the initial bounced property to zero. In this check on line 74, I check if bounced is less than two. And each time we bounce, I increase bounced by one. Here on line 75, now each particle bounces twice before it falls off screen.

    down here where we create particles. I copy this for loop that creates 10 particles. We create one particle when enemy collides with the projectile. I paste that for loop here to create 10 particles when enemy is destroyed by a projectile. So particles will come out of enemies after three different events. When enemy collides with a player and is destroyed, we get 10 particles. When projectile collides with an enemy, we get one particle. When enemy is destroyed by a projectile, we get 10 particles. So, we know how to create particles when certain events happen in our game. We know how to bounce them off floor and we know how to control how many times they bounce.

    We also have this angle property that is increasing by VA on line 69. If you never done rotation on canvas, this part might be a little bit challenging, but I will try to explain. Each particle has a different angle value that’s increasing by VA value that’s also randomized for each particle object. It means that at any point each particle is at different rotation. Their angles have different values. To make sure that rotation angle only affects one specific particle and doesn’t spill out and affect other objects we draw on canvas, I will wrap the entire drawing code between save and restore. Save method takes note of the current canvas state. When we call restore later that restore will look for its associated save method and it will reset all canvas settings back to that point in time. Anything done between save and restore will just affect the code the drawing code in between. After we call restore, everything will be reset to its original state. To rotate something on canvas, we first have to move a rotation center point, the point that is normally considered coordinates 0 on canvas. So the top left corner, we have to translate that point over the object we are rotating. So translate to the current x and y position of the particle. Calling translate like this moved rotation center point from top left corner to this dox this doycoordinates of this particle. Then we call built-in rotate method that takes angle value in radians. I pass it the angle property that is increasing for every animation frame by va here on line 69. Not sure if you can see but particles are currently making very large circles around their x and y coordinates. It is because we are going to another distance of X and Y from these coordinates because of the fact that we translated 0 0 and rotation center point to these coordinates. For all intents and purposes, this dox and this doy between this save and restore in this area of our code is considered point 0 on canvas. And then I’m drawing this particle at this dox this doy from that translated point further and I’m rotating it making it go in larger circles around that center point. I fix it by changing x and y to zero here because position of that particle is already defined on line 81 in translate call.

    Now the particles are rotating from their top left corner. So I shift them a little bit by half of their width and half of their height to rotate around the center point of each particle.

    I have other classes about rotation. For now, let’s just move on. If you don’t fully understand some things about rotation, don’t worry. It will become more clear as you use these techniques more often in the future. We are getting a lot of particles now. If you are on a very old computer, you can reduce the amounts of particles to get better performance. I don’t have any performance issues on my computer. Let me know if it runs smoothly for you or if you had to decrease the number of particles to get a good frame rate.

    The particles don’t move correctly in relation to the ground artwork. I need to go here and include the game scrolling speed in the horizontal position calculation.

    H. So, this actually has to be plus

    Yes, now it works. Awesome.

    Time for a small cleanup. First of all, I want the debug mode to be disabled by default. We can still press letter D on keyboard to toggle it on and off, but when the game first loads, I want player and enemy hitboxes and enemy lives to be hidden by default. We have a bug in our game. When the player collides with any enemy type, it goes into a power up mode. That would make the game too easy. We only want the player to enter power up when it collides with power up fish. And later in the bonus section, there will be another way to enter power up for skilled and fast players who can shoot fast and big moonfish before it comes too close. To make sure the power up works correctly, I just need to fix this comparison operator on line 357. Like this. Now, our Sentinel Seahorse only enters power up if it collides with Lucky Fish. Another bug is when we enter power up, players ammo gets automatically assigned to max ammo. This is meant to refill the ammo. But if the player saved up and has current ammo higher than maximum ammo, entering power up will actually reduce the total amount of ammo they have. I fix it here on line 159 inside enter power up method on the player class. We only refill ammo to max ammo if the current ammo is less than max ammo.

    Like this.

    That works. I’m using VS Code editor. When I press Ctrl + F, I can look for all console locks. I want to delete them. Let’s keep our code and console clean. Particle spare parts falling from the enemies are not bouncing from the correct area. I want the bounce area range to match the ground artwork a bit closer. Here on line 66 inside particle class constructor, I set bottom bounce boundary to a range between 60 and 140 pixels.

    I want to change the order in which we draw our game elements. Because we are drawing everything on a single canvas element, the order in which we call draw methods will determine what is behind and what’s on top. I go down here inside the main draw method on game class. And I want to draw the background first, then UI elements. So score, ammo, timer, and game over messages. Then we draw player, projectiles, particles, and enemies. On top of that, you can play with the draw order here if you want. If you want UI to be on top of everything, for example, just draw it last. I think it looks better like this because it’s a bit 3D or 2 and 1/2D when it’s slotted between the game world and game characters like this. We can do many other things to make the UI feel like a part of the game world. I have lots of ideas. Maybe in the next class I’ll show you more. Game text can be floating, moving, changing colors. It’s easy to do it if you follow my other coding tutorials and you understand canvas animation well.

    We have a power up mode. So the game currently is very easy. When we are in power up enemies have no chance. Let’s add a massive enemy type that when defeated splits into five smaller enemies. That should give the player some challenge. Hope you like teeth and tentacles. It will also introduce some tactical decisions into the game. Maybe sometimes it’s better to avoid the enemy altogether if we are low on ammo when we know we can’t deal with the little enemies that come out of it when we destroy the big one. I copy lucky fish class that extends the main parent enemy class. And I renamed that copy hive whale. This is a massive mechanical whale that serves the enemy swarm as a hive vessel containing a lot of aggressive and fast drones. Width is 400 pixels and height is 227 pixels. This image will be looking for an ID of hive whale. I need to go to index html to bring that spreadsheet into the project. You can download it in the project files section. I made just one animation rule for this enemy type. It’s a lot of work animating all these tentacles and creating this spreadsheet. And also it’s already a big image file. image with an ID of hive whale and source is assets/hive whalepng. In style CSS, I give that image display none. Frame Y will be zero because this sprite sheet only has one animation row. It will have 15 lives. It can take a lot of damage. When defeated, it will give player 15 score points. Type is hive like this and it will move very slow. So here I will override the default speed X property from the parent enemy class and I set it to a random number between minus0.2 and minus 1.4 pixels per frame. I want the enemies to be spread a bit more down, not all the way to the bottom of the game area, but maybe 95% of the game height. I do it by replacing this vertical position calculation on angler one, angler 2, lucky fish and hive whale with 0.95 position where enemies can spawn in the game can be anywhere between zero and 95% of game height. We need this extra space. There are some large enemies incoming. We add hive whale into the project down here inside add enemy method on the main game class. I copy this line and I say if randomize is between 0.6 and 0.8 add new hive whale enemy type.

    And here they come. I can enable debug mode by pressing letter D to see its massive hitbox and its current lives. We need to hit the whale with 15 projectiles to destroy it. But that’s not all. When destroyed, five smaller, fast, and aggressive drones come out of it, and they will go straight for our Sentinel Seahorse character. Let’s create that enemy type.

    Drones are small, fast, and aggressive creatures. They live inside hive wells where they collect resources and feed on whatever the hive will swallows. Let’s make sure that Sentinel Seahorse is not their next meal. I copy this code block and I will name it drone.

    This enemy type is different. They are ambush predators and they always hide inside the hive whale ready to jump out and attack their prey. They will not be coming at player from the right side of the screen like the other enemy types do. We will only see them when we destroy a hive whale. For that reason, when we create a new drone using this class, we need to pass it game object as usual, but also we need to pass it the current X and Y position. It will be the current position of the hive while we just destroyed. I convert X and Y into class properties as we always do.

    Image will be looking for an element with an ID of a drone.

    I bring it into the project here in index html. ID is a drone, source is assets/ dronepng. I created two different animation rows. Each one will be moving differently so we get some variety. Frame Y will be a random number, either row zero or row one. Each drone will have three lives and will award player with three score points if destroyed. I will give it type drone. I’m not sure if I will use this type property for something, but might as well declare it. We might need it later. This enemy can move very fast if it wants to. It will have a random speed range from a minus0.5 to -4.7 pixels per frame.

    The way I want this to work is when we destroy hive whale with projectiles, it will spawn five drones. In star CSS, I give the drone image display none. If the hive whale gets destroyed by colliding with the player, there will be no drones because the drones would spawn too close to the player and there will be no time to try and aim and target them properly. It would not be a good gameplay experience having enemies spawn so close to the player. If projectile collides with an enemy and if lives of that enemy are less or equal to zero, that enemy is destroyed. We check if the enemy that was just destroyed has type property set to hive. If it is a hive whale, we take enemies array and push one new drone enemy object inside. If you remember drone class expects game and X and Y position were to appear in the game world. I want it to appear under the destroyed hive whale. So I pass it X and Y of that destroyed enemy. Let’s test it. I destroy a hive whale and we have one drone coming out of it. Nice. Let’s put this code into a for loop that runs five times to create five drones.

    We have five drones, but they all appear on top of each other in the top left corner of the hive whale. That’s not ideal. Let’s spread them around a bit. Starting position of the drone will be horizontal X position of the hive whale that was just destroyed plus a random number between zero and the width of the hive whale enemy. Starting vertical position of each drone will be vertical Y position of the hive whale plus a random number between zero and height of the hive whale like this.

    Maybe just height time 0.5.

    Nice. Now the drones are more spread out. Some move very fast, some move slower. This is good. We get too many particles. I don’t want each drone to burst into 10 particles when destroyed. What if we make the number of particles per parts that fall from enemies when destroyed to be equal to the score that enemy gives?

    I also make the same change here on line 383 when enemies get destroyed by colliding with the player. Now, hive whale should burst into 15 particles because when defeated, it gives 15 score points. Each drone will turn into three spare parts. That way, we won’t get a massive flood of 50 [ __ ] and wheels when we destroy five drones.

    I want the game to feel good when we score some points and destroy an enemy. I want that enemy to really pop. So, not only we will turn it into spare parts that bounce around, we will also play a dust or fire explosion from a sprite sheet. I have two special sprite sheets for this purpose. You can take them and use them in your other projects as well if you want. Many games need dust and fire effects like this. All art assets for this episode were custom made by me or artists I hired. So there is no copyright. You can use them however you want. Enjoy. We will have the parent explosion class and we will extend it into two child classes. Dust explosion and fire explosion. Parent explosion class will contain methods and properties shared for all explosion types. It will expect game X and Y as arguments because I want the animation to play over the enemy that was just destroyed. So that X and Y position will be passed from the outside each time we create a new explosion object. Both fire and smoke explosion will be single row sprite sheets. I could also have placed them into a single image. We will cover compact sprite sheet animation in a later class, not today. I will cycle through them from left to right from frame x0 to max frame. Sprite height is the height of a single animation frame in the sprite sheet and it will be the same for both explosion types. I made both sprite sheets the same height of 200 pixels. So that property can be on the parent class. It’s a property shared between all explosion types. Sprite width. The width of a single animation frame in the sprite sheet will be different for each type. Because of that, it will sit on each subclass separately. We will define that in a minute. The sprite sheets have only eight frames, so they will animate very fast. I want us to be able to control FPS, frames per second on this animation. And I want that FPS to be independent of animation speed of the rest of the game. We will do that using delta time again. And we will need two helper variables. Timer that will count from zero adding delta time over and over until it reaches interval value. When we reach it, we will serve the next animation frame in the sprite sheet. Interval will be th00and milliseconds, 1 second divided by 15. So the animation will run at 15 fps. I can also put frames per second in a separate property if I want to. We can control FPS by adjusting that property instead. Marked for deletion will be initially set to false. As usual, we will need update method and it will expect delta time value as an argument. We calculate delta time in the main animation loop. Draw method will expect context as an argument to specify which canvas element we want to draw on. Update method will simply animate the sprite sheet by increasing frame X property from line 302. Draw method will draw currently active animation frame cropped out from the sprite sheet. Let’s start by just giving it image we want to draw and X and Y coordinates where to draw it. So this is the parent explosion class. It contains properties and methods shared between all explosion types. We will have two child classes. Smoke explosion and fire explosion. I say class smoke explosion extends explosion. That extends keyword creates a relationship between these two classes and it sets up prototype based inheritance behind the scenes for us. Smoke explosion subclass now has access to properties and methods that sit on explosion superclass. We will also have fire explosion subclass. Constructor will expect game and x and y coordinates. In index html I bring the sprite sheets into the project here in the props section.

    IDs will be smoke explosion

    and fire explosion.

    In style CSS we give both of them display none.

    I point the subclass towards that image using get element by ID. I’m placing this image property on the subclass because that image is specific only for this subclass. Parent superclass contains only properties and methods that are shared between all subasses. Sprite width. The width of a single frame will be 200 pixels. Both sprite sheets have eight frames. So max frame will be eight. Rectangles on canvas are drawn from the top left corner. I want the explosion animation rectangle to be coming from the exact center of the enemy rectangle. I can do it like this. I’m going to give it width and height property and I set it to be equal to sprite width and sprite height. I take X and Y properties from the parent class and I place them on the child class. Once we have a width property here, I offset X position by half of its width, moving its center point to the middle of the image horizontally. I will also move the vertical Y position into the middle of the image vertically like this. Down here inside game class constructor, I create an array that will hold all currently active explosion objects. Inside update method, same as we do for particles, I will call for each

    and for each explosion object in explosions array. I call its update method. We will also use filter method to remove all explosion objects that have marked for deletion property set to true.

    Inside the draw method, I call for each on each explosion object again and I draw them passing it context. Notice I draw explosions after I draw enemies. So they will be drawn on top of enemies. The order in which we call draw methods here matters. We will have two different explosion types. So same as we did with adding different types of enemies to the game. On the main game class, I define a custom method I call add explosion. We will have a variable that will randomize a number between zero and one like this. If that random number is less than one for now

    take this explosions array and push new smoke explosion inside I pass it game. So this keyword it will also need a position. So we will take it from the enemy we just collided with. We will add a reference pointing to that entire enemy object here as an argument. X and Y of this explosion will be X and Y properties from that enemy object that is passed here. Let’s try to add it into the game and see what we’ve got so far. Up here on line 419, we check if player collided with an enemy. That enemy will be destroyed and we want to animate an explosion at that position. So I will call this add explosion like this. I pass it the enemy player just collided with and destroyed as an argument. I also want the explosion animation to play when we destroy enemy with projectiles. So here we check if projectile collided with an enemy. If that enemy’s lives are less or equal to zero, it will be destroyed. And we animate a splash of spare parts. We set marked for deletion on that enemy to true. And we will add explosion here as well like this. I test it and we are getting no explosion animations. I don’t see any console errors. Let’s debug it by console logining explosions array from inside add explosions method. Every time we add one, we console log the entire array. I can see that add explosion method runs and creates the console lock for us. But the array remains empty. Let’s see what I did wrong. Probably I made a typo somewhere.

    Oh, I see this if statement never runs because there is no this.randomize property. Easy fix. We need to refer to this temporary helper variable like this.

    Now I’m getting a console error which is better because this error will guide us to where the problem is. The error says we must call constructor in derived class before accessing this. Now I know the problem is inside smoke explosion class constructor. This is a so-called derived class. When I create a new smoke explosion object, I want the parent class constructor to run first, creating properties and values shared for all child classes. And then I want to add this little bit of code that’s specific only for smoke explosion class. To do that, I have to call the parent class constructor using a special super keyword. I know that parent class constructor expects game X and Y. So, I pass these arguments along. It’s a good lesson for me to remember on a child class we must always call superclass constructor before using this keyword otherwise we will get a reference error. Now when I create a new smoke explosion we create one new blank object. This constructor will run first creating these properties and then these properties will be added on top of that. Smoke explosion will also have access to update and draw methods because of the inheritance that was set up behind the scenes by the special extent keyword we used. We fixed all the bugs and typos. When I test it, I can see that everything works and we are adding smoke explosion into the explosions array and we are drawing the entire sprite sheet at that position. Perfect. Let’s clean it up and make it into a proper sprite animation. Now this dust cloud is a sprite sheet. We are drawing it using built-in draw image method on line 312. As we already did multiple times in this class, we know that to animate a sprite sheet, we need to crop out individual frames and swap through them one by one. We do it by passing draw image method nine arguments. Image we want to draw source X, source Y, source width, and source height to specify area we want to crop out. We want to crop out one spreadsheet frame at a time and destination X, destination Y, destination width, and destination height to tell JavaScript where we want to draw that cropped out image on destination canvas. We already have the values for destination. We just need to specify the crop area. Source X will be frame X from line 300 times sprite width from line 320. Source Y will always be zero because this sprite sheet has only one row of frames. Width of the cropped area will be sprite width. Height will be sprite height. So now because frame X times sprite width determines horizontal cropping coordinate as we increase frame X inside update method the frames will cycle and animate. Now it works but the animation is coming from the top left corner of each enemy and it plays very fast. Also, we are not removing all the explosion objects that already animated and we have an everinccreasing array. I will check if frame X is more than max frame. And if it is, I know that entire animation played. At that point, it’s safe to set marked for deletion property to true. And that explosion object will be removed by filter method we already defined earlier. In the browser console, I can see that the old explosion objects are being correctly removed. Nice. I want the animation to run at 15 frames per second. I do it by creating a periodic event again. Timer will be counting from zero to the value of milliseconds defined in interval. Whenever it reaches that value, it will trigger next frame in the spreadsheet and resets back to zero so that it can count again. So if this timer from line 303 is more than this interval from line 304, increase frame X by one. else keep increasing timer by delta time accumulate in milliseconds until it reaches the interval.

    This will serve only the first frame. It’s because after timer reaches interval, it needs to be reset back to zero so that it can count again for the next animation frame. It still doesn’t work. I can see that update method expects delta time as an argument to be used to increase timer value on line 313. I have a feeling I’m not passing it that value when I call it. I go down to line 422

    and I pass update method on explosion object delta time. Now we are animating the explosions at 15 frames per second. Structuring your code like this will allow you to set different FPS for different objects in your game. In this case, we did it because player and enemy sprite sheets are optimized for high frame rate, but explosion animation has only eight frames. So, it looks better if we stagger the animation speed. If you want to turn this into a mobile game, you would have to do this for all objects, player and enemies. You would have to delete some frames and stagger their animation because current mobile phones will struggle to serve sprite sheets with so many frames we are using for our characters. If you want lower frame rate spreadsheets for these characters, let me know. so I can easily make them for you. The explosions are animating in the top left corner of each enemy. I want them to be in the middle. So I adjust the initial X coordinate we pass it by half of enemy width

    and the vertical coordinate will be adjusted by a half of enemy height like this. This looks good. I’m noticing that we are not showing the first animation frame of our smoke explosion sprite sheet. It’s because we first call the update method that increases frame X by one and then we draw it. I can fix it by calling draw first and then I call update like this.

    Now we can see the first sprite frame as well and it stays long enough so we can actually notice it. Nice.

    Let’s delete this console lock. We don’t need it anymore. I can change the animation speed of dust clouds by changing the value here in FPS property. When I set it to a very low value, like five frames per second, it becomes obvious that they are not being correctly placed within the game world. They are static, but they should be scrolling along with the game world for the positioning to look right. I fix it by accounting for the current game speed in their horizontal coordinate calculation like this. Now they scroll with the game world and it looks as it should.

    I think a good FPS for this sprite sheet is around 30 frames per second.

    Yes, I’m happy with this for now.

    Let’s create a fire explosion. This time it will be very simple. I copy all the code inside the constructor into the other child class. Image will have ID of fire explosion like this. I actually decided to refactor the fire sprite sheet. And now both smoke and fire sprite sheets have frames 200 * 200 pixels. In that case I can remove sprite wave on child class and I can place it on the parent explosion class because now it’s shared for both explosion types. H in that case I can actually take all these properties and add them on the parent class as well.

    I remove them here since they will be automatically inherited. Nice. That’s cleaner. So only the images are specific for each class. All other properties and methods will be shared and inherited from the parent class.

    Down here inside add explosion method I say if randomize is less than 0.5 create smoke explosion. Else careful about the brackets and syntax here. else create fire explosion.

    Nice work. Now, sometimes we get a fire effect, sometimes we get a smoke effect.

    Inside game class constructor, I adjust time limit to 30 seconds. Winning score will be 100. So, the player needs to get at least 100 score points in 30 seconds to see the winning message. I set ammo interval to 350 milliseconds so that ammo recharges a bit faster. And I set enemy interval to 2 seconds. Let’s test it.

    We have a bug. I got a winning message and there were some leftover enemies and colliding with them reduced my score below 100 and losing message was displayed instead. I need to make sure that after the winning or losing message appears, colliding with enemies doesn’t affect the score.

    I do it here on line 437. Only decrease score when we collide with an enemy if game over is false.

    Let’s tune the game into a more playable and challenging state. I make hive whale less likely to appear in our game and lucky fish more likely like this. I give hive whale 20 lives.

    Lucky fish will have five lives. Angler 2 will have six lives. Angler one will have five lives. For example, I set game width to,000 pixels. This will make the game easier as we can see enemies coming sooner and we can plan and manage our moves and ammo better. I try to play to get a better idea of how much score I can get in 30 seconds. Okay, the game ended because we reached winning score 100 in 25.1 seconds. Let’s set winning score to 80.

    I can strategize now. I can see there is a lucky fish coming that will replenish my ammo. So, I will use as much as my ammo as possible before I get the refill. Now, I get a refill and I can go crazy with my lasers. I will be careful not to hit the lucky fish coming at the bottom so that I can collect it and make my power up state longer.

    Okay, it took 24 seconds to get the score over 80. game has a time limit of 30,000 milliseconds. 30 seconds. If the game runs for that amount of time, it will end. We need to get enough score points in that time period. This is just my choice. You don’t have to do this, but I want the game to always run for 30 seconds. I don’t want it to end as soon as we get over the winning score. So, I will comment out line 456. Game will only end when time limit is over 30 seconds. And based on how much score we manage to get, we will see a winning or losing message. There is an element of luck in the game we designed because it is very dependent on which type of enemy spawns. If we get just lucky fish and hive whales, we will get a lot of score points fast. If we get only anglers, it will be very hard to win the game. I gave you all the tools and techniques you need to understand. You can now adjust the game time, enemy health, and winning score yourself to make the game as easy or as difficult as you want it to be.

    The game runs well on my gaming PC, but if you have a Chromebook or some very old laptop, you might be experiencing performance issues. I focused this class mostly on handling graphics and animation. There is a whole other set of optimizations we can do to make this run even on the oldest machines, but that’s beyond the scope of this class. Notable optimizations would be for example to draw on multiple canvas elements and only clear parts of canvas that actually update it. Object pooling technique would also have a massive positive effect on the performance. It means that we create a pool of particle and projectile objects and we just reuse them over and over rather than creating new ones and discarding them after one use. For this project, the quick changes you can make to improve performance would be to increase enemy interval property to make enemies spawn slower. If your computer is not keeping up, you can also remove all shadow properties inside UI class. Canvas shadows are still not well supported and optimized in some browsers, especially in Firefox. We can reduce the number of particle spare parts that fall from enemies when damaged. And we can also make sure they only bounce off the floor once or that they don’t bounce at all. If you are still getting performance issues, you can also merge all background layers into one image and just animate that one layer. That will increase performance. massively. Same goes for our spreadsheets. I gave you sprite sheets with 37 animation frames, which looks really good and smooth in motion. But if you struggle to get 60 fps, reducing the number of frames and have each animation to be just around 15 frames, let’s say, and staggering animation speed with delta time like we did with animated explosions would make the performance better as well. I will probably release a version of sprite sheets with lower frame rate for each character so you don’t have to do it manually yourself. Bonus extended lesson where I add more enemy types, animated projectiles, shield, and simple sound design is linked in the video description, but feel free to play with the code and add your own features with the techniques we learned today. Let me know if you finish this project by typing I did it in the comments. If you want more vanilla JavaScript game death, come and build this game with me. I will show you how to use state design pattern for more complex player controls and movement and how to split our code into individual modules. Click like, please. I’ll see you there.

  • 5 Cinematic Motion Graphics You Should Know in After Effects

    Here are five motion graphic tricks to make anything cinematic in After Effects. As you know, we’ll be using a handful of buffoonery effects to create light and shadow, which will allow us to produce an infinite amount of motion graphics. All right, my first and favorite motion design trick is turning random shapes into gradient masterpieces. So, firstly, create any shape of your choice with the shape tools. Though you could use the rectangle tool to create a large shape in the corner, maybe rotate it or even use the ellipse tool to create a basic circle or stretch it all out to create an oval for some variation. Now for some quick animation right off the bat, we can use the wiggle paths property inside the shape layer. This is a very simple effect if you will, as you only need to increase the size, lower the detail, set the points to smooth, and maybe use a low wiggles per second. And this can also be copied and paste to your other shape layers as well to create that $1 million animation. But to give this scene some life, go ahead and add the four color gradient effect and move the points to the edges or the sides of your graphic. And finally, you’re going to want to use two colors of the similar tonality to create a very nice blend. Now, to help blend this into the background, let’s use the gaj and blur effect and set the amount to, I don’t know, around 10. And most importantly, let’s use a CC radial blur effect to set this to a fading zoom. This effect is going to allow you to move the center origin of the blur with the anchor point right here, which should be placed on the side of the shape. Then all we need to do is increase the amount to make the side scatter with a blur. Awesome. We can also alt click the stopwatch here to use the wiggle 0.520 expression to add a little bit more animation. And of course, you can copy and paste these effects to your other independent shape layers. But now let’s go ahead and add some character with our cinematic effects by creating an adjustment layer. The first effect to add is noise, which we’ll set to 12%. The second effect is glow, which all we need to do is nearly max out the glow radius and maybe adjust the threshold if needed. And finally, try the posterize effect to create some grit. And if you like, use the curves effect to add some extra contrast. And most importantly, to make sure that these effects actually work, you’re going to need a very dark background underneath your cinematic gradient shapes. Now, go ahead and make those millions. The next cinematic motion graphic is creating pockets of light and shadow with a single effect. Looks great on almost anything. And that effect is CC spotlight when you apply it to a white, maybe bluish solid layer. The color doesn’t really matter. Now, wasting no time, we should set the blend mode of the layer to either add screen or lighten. and set the intensity of the effect to 100. Doing this will allow us to visualize the spotlight correctly. And all we need to do is move the anchor points of the spotlight effect to help angle this in the direction that you want. Then make sure that the height is set to zero, allowing you to accurately adjust the cone angle and the edge softness. Now, we could add the wiggle expression to the cone angle to add, you know, a little flickering animation. Very cute. Now, to help fade the light beam into the background, let’s go ahead and use the linear white transition effect and set the angle to match your current beam direction and then adjust the completion and then truly go crazy on the feather. Awesome. But to boost the darkness of the scene, let’s go ahead and duplicate this spotlight layer and then set the bottom blend mode to darken. Cool. But to take this even further, we can use the same adjustment layer effects from that previous technique without maybe the posterize effect. And awesome, you can also add some new spotlights by duplicating the top layer and moving it around. Also, you can animate the from and two values to actually move the beams of light to create something cinematic. A quick technique to add a simple refraction effect to anything is by drawing out a thin straight line horizontally or vertically in an empty composition. Then, right click this layer, go to layer styles, and add a gradient. Just make sure that the black and white colors will stretch from side to side like this. And finally, create a lot of duplicates. And I mean a lot lot. And when that’s all done, from here, just select everything and hit P on your keyboard for position. Then hold control and alt or option and command on your keyboard to proportionally spread this across the entire composition. Like so. You know, this won’t look great or anything, but now we can take this composition and place it over any body of work that you have in another comp and turn it off. Now all we need to do is create an adjustment layer and add the displacement map effect. We’ll set the map layer to that you know composition that we created and adjust the displacement values to create a glassesque refraction effect. And remember you can create this vertically as well. So it can be horizontally and vertically. With that said, my next favorite motion graphic is creating curved light streaks like this. So we can start off by creating a very large white stroke only circle with the ellipse tool. Then we can contain the line with trim paths. As you may have guessed, all we need to do is adjust the end and the offset. You can even key frame the offset to rotate the line by a bit. Now to smooth out those hard edges, go to taper and max out the start and end length just like so. Perfect. Now for the effects, use the gaj and blur effect and set it to 10. And then use the CC radial fast blur effect. increase the amount and set this to brightest. Now use the glow effect and increase the radius. And for a stacking, you know, technique, duplicate the glow effect and increase the radius even further. Now, finally, to give this some color, go ahead and create an adjustment layer and use the trionee effect. And just set that midtone color to any color that you want. And again, use the noise effect at 12%. Pretty recurring theme in this video. And then use the glow effect once again for some good measure at around 300 points or so. Then of course make sure that you have a background and you can animate the streak however you want. Maybe cough cough. Use the trim paths to bring in your glowing cinematic streak. Just awesome. But okay, the next and final technique is creating colorful motion graphics in moments with the techniques that we’ve already used in this video. You know, kind of tying everything together to Aura Farm. So, for instance, you can create any shape that you like. And I’ll set this to a, you know, radial gradient for this specific shape. You’ll typically want to set your points for the gradient off the bat so that we can actually see the colors as we edit the gradient with a bunch of different, you know, tones like so. Now, if you have a stroke object, we can animate it in with trim paths, right? But back to the basics again with an adjustment layer, we can use the noise and the glow effect several times to compound the overall glowability of everything. And of course, you can use posterize to add some grit to your object. Also, since the blur effect is a massive key to this cinematic theme, try the camera lens blur effect on your actual shape. And then use the wiggle expression again to pop this in and out of focus. But now you have the tools to create cinematic motion graphics. Subscribe to be the best and always be creative.