<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Andrés Villarreal</title>
    <description>The latest articles on DEV Community by Andrés Villarreal (@kaeruct).</description>
    <link>https://dev.to/kaeruct</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F386854%2Fb257dac5-29dd-4876-9247-ffe1579df236.jpeg</url>
      <title>DEV Community: Andrés Villarreal</title>
      <link>https://dev.to/kaeruct</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kaeruct"/>
    <language>en</language>
    <item>
      <title>LocalStack License Changed, CI First to Know</title>
      <dc:creator>Andrés Villarreal</dc:creator>
      <pubDate>Sat, 28 Mar 2026 15:09:45 +0000</pubDate>
      <link>https://dev.to/kaeruct/localstack-license-changed-ci-first-to-know-4bkd</link>
      <guid>https://dev.to/kaeruct/localstack-license-changed-ci-first-to-know-4bkd</guid>
      <description>&lt;p&gt;&lt;a href="https://www.localstack.cloud/" rel="noopener noreferrer"&gt;LocalStack&lt;/a&gt; is a great product. It’s basically an emulator for the AWS cloud that you can run locally. We rely on it for development and automated testing. However, nothing comes for free. Understandably, the company behind this amazing piece of software has some bills to pay. They changed the license to require a subscription to run their provided Docker images. If the license is not provided as an environment variable, the image simply fails to start. Normally, this would not be a problem if we pinned our versions properly. But surprise, we don’t!&lt;/p&gt;

&lt;p&gt;CI started “randomly” failing in the middle of the day and annoying all the engineers. I consider myself the self-appointed CI shepherd, so it was my responsibility to find out what was going on. Initially I thought this was just a couple of flaky tests, but after it started failing constantly, it became obvious we had a real problem. We use &lt;a href="https://testcontainers.com/" rel="noopener noreferrer"&gt;testcontainers&lt;/a&gt; with the S3 LocalStack image, and all tests which used this setup were consistently failing.&lt;/p&gt;

&lt;p&gt;The nice thing is that I was able to reproduce the problem locally, so then I just bumped the log levels to the max and looked for funny stuff. After some log spelunking, I noticed the failing image was &lt;code&gt;localstack/localstack:s3-latest&lt;/code&gt;. From there it was easy to find out &lt;a href="https://blog.localstack.cloud/localstack-for-aws-release-2026-03-0/#setting-your-auth-token" rel="noopener noreferrer"&gt;LocalStack’s latest blog post&lt;/a&gt; explaining their licensing changes.&lt;/p&gt;

&lt;p&gt;The immediate fix was to pin the image to version &lt;code&gt;4.4.0&lt;/code&gt;. For example: change &lt;code&gt;localstack/localstack:s3-latest&lt;/code&gt; to &lt;code&gt;localstack/localstack:4.4.0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I would say the main takeaway from all of this is to pin your versions. Then you always know what you get. Package manager dependencies, docker images, Github actions, anything! Always specify a deterministic version. Never use &lt;code&gt;latest&lt;/code&gt; or similar. Oh, how I wish &lt;a href="https://reproducible-builds.org/" rel="noopener noreferrer"&gt;reproducible builds&lt;/a&gt; were more widespread in the software industry!&lt;/p&gt;

&lt;p&gt;Back to the LocalStack topic, now I am actively on the lookout for a proper replacement. I only need a local S3-compatible emulator. I have tried MinIO but for some reason it doesn’t seem to be a drop-in replacement and also has some funny business going on with the licensing. &lt;a href="https://github.com/hectorvent/floci" rel="noopener noreferrer"&gt;floci&lt;/a&gt; also seems promising although it’s quite new. Please reach out if you have any recommendations!&lt;/p&gt;

</description>
      <category>testing</category>
      <category>localstack</category>
      <category>ci</category>
    </item>
    <item>
      <title>Our CI Doesn't Do Weekends</title>
      <dc:creator>Andrés Villarreal</dc:creator>
      <pubDate>Sat, 24 Jan 2026 09:34:06 +0000</pubDate>
      <link>https://dev.to/kaeruct/our-ci-doesnt-do-weekends-4og1</link>
      <guid>https://dev.to/kaeruct/our-ci-doesnt-do-weekends-4og1</guid>
      <description>&lt;p&gt;I think a codebase can tell you a lot about the people that work on it. From this specific example in particular, I felt very reassured that the team takes work-life balance seriously and never works on weekends.&lt;/p&gt;

&lt;p&gt;For context, the software interfaces with old-school banking systems that famously do not run certain processes on holidays or weekends.&lt;/p&gt;

&lt;p&gt;We had some logic to to an early return to avoid running a process on bank holidays, imagine something like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;if (isBankHoliday(new Date())) {
  logger.info("Skipping process on bank holiday");
  return;
}
// ... continue business logic below
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This logic was not covered by any tests! Not to say that there were no tests, but they were more focused on what would happen on work days and not the fact that the code should not run on bank holidays.&lt;/p&gt;

&lt;p&gt;This worked quite well, until somebody &lt;strong&gt;pushed changes on a weekend&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Weekends are considered bank holidays, so the check to avoid running on bank holidays was triggered and the tests failed. Fortunately, the changes being pushed on the weekend were not urgent and nobody was blocked by this.&lt;/p&gt;

&lt;p&gt;The lesson we learned from this is that you should &lt;strong&gt;not work on weekends!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Although in all seriousness, the tests should have faked the date from the start to avoid this. Even if people are not working on weekends, it could be that they work in a different timezone, or the team needs to push an urgent hotfix during the weekend.&lt;/p&gt;

&lt;p&gt;The way to do this using &lt;code&gt;vitest&lt;/code&gt; is very simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Pick a date that is definitely not a bank holiday!
vi.useFakeTimers({
  now: new Date("2025-03-03"),
  toFake: ["Date"]
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By the way, &lt;a href="https://vitest.dev/" rel="noopener noreferrer"&gt;vitest&lt;/a&gt; is very fast and &lt;a href="https://vitest.dev/guide/migration.html#jest" rel="noopener noreferrer"&gt;very easy to migrate to from jest&lt;/a&gt;! Make the switch if you haven’t already!&lt;/p&gt;

</description>
      <category>testing</category>
      <category>node</category>
      <category>vitest</category>
    </item>
    <item>
      <title>fzf + SSH Config Hosts</title>
      <dc:creator>Andrés Villarreal</dc:creator>
      <pubDate>Thu, 10 Oct 2024 18:42:48 +0000</pubDate>
      <link>https://dev.to/kaeruct/fzf-ssh-config-hosts-23dj</link>
      <guid>https://dev.to/kaeruct/fzf-ssh-config-hosts-23dj</guid>
      <description>&lt;p&gt;SSH has a nice feature in which you can store aliases for frequently accessed hosts.&lt;/p&gt;

&lt;p&gt;Combining this with &lt;a href="https://github.com/junegunn/fzf" rel="noopener noreferrer"&gt;&lt;code&gt;fzf&lt;/code&gt;&lt;/a&gt;, you can have a nice quick shortcut to quickly pick a server to connect to into.&lt;/p&gt;

&lt;p&gt;This comes in very handy if you need to ssh into different servers and forget their IP or hostname often.&lt;/p&gt;

&lt;p&gt;Here’s a sample ssh config file (normally located at &lt;code&gt;~/.ssh/config&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# see https://man.openbsd.org/ssh_config.5 for all the available configuration settings
Host runner-staging
    HostName 10.0.0.8
    User alpha

Host runner-production
    HostName 10.0.0.9
    User beta

Host mainframe
    HostName mainframe.computer.world
    User hackerman

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here’s a small shell function which calls fzf with the hostnames configured and allows you to pick one to connect to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;s () {
  local server
  server=$(grep -E '^Host ' ~/.ssh/config | awk '{print $2}' | fzf)
  if [[ -n $server ]]; then
    ssh $server
  fi
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add this function to your &lt;code&gt;.bashrc&lt;/code&gt; (or &lt;code&gt;.zshrc&lt;/code&gt;, or whichever config file for your shell) and reload the configuration.&lt;/p&gt;

&lt;p&gt;Now, you can quickly ssh into &lt;code&gt;mainframe&lt;/code&gt; by typing &lt;code&gt;s&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ s

# fzf will allow to quickly search and pick your server
&amp;gt; runner-staging
  runner-production
  mainframe
  3/3 ──────────

# press enter and you will be connected!
[hackerman@mainframe.computer.world ~]$ 

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>linux</category>
      <category>ssh</category>
      <category>tips</category>
    </item>
    <item>
      <title>Using AsyncLocalStorage for Better Traceability in NodeJS Applications</title>
      <dc:creator>Andrés Villarreal</dc:creator>
      <pubDate>Sun, 29 Sep 2024 08:45:54 +0000</pubDate>
      <link>https://dev.to/kaeruct/using-asynclocalstorage-for-better-traceability-in-nodejs-applications-322o</link>
      <guid>https://dev.to/kaeruct/using-asynclocalstorage-for-better-traceability-in-nodejs-applications-322o</guid>
      <description>&lt;p&gt;NodeJS has a neat API called &lt;code&gt;AsyncLocalStorage&lt;/code&gt;. It’s used to share information across callbacks and promise chains.&lt;/p&gt;

&lt;p&gt;For example, it is useful to share information for all the code executed when serving a web request. I also found it very useful to keep trace information to easily keep track of which item was being processed during a batch process.&lt;/p&gt;

&lt;p&gt;The only caveat in my opinion, is that you need to wrap your code in yet another callback.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to use &lt;code&gt;AsyncLocalStorage&lt;/code&gt;:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;First, create an instance of &lt;code&gt;AsyncLocalStorage&lt;/code&gt;:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Then, use the &lt;code&gt;run&lt;/code&gt; method to wrap your code:&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Finally, use the &lt;code&gt;getStore&lt;/code&gt; method to retrieve the shared state:&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Real-world example
&lt;/h2&gt;

&lt;p&gt;The previous example is very simple because it only shows how to use it.&lt;/p&gt;

&lt;p&gt;Here’s a more elaborate example that will hopefully show why this feature is so useful:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { AsyncLocalStorage } = from "node:async_hooks";

async function process() {
  try {
    await Promise.all([foo(), bar()]);
  } catch (err) {
    handleError(err);
  }
}

async function foo() {
  const { index } = asyncLocalStorage.getStore();
  console.log(`processing foo ${index}`);
}

async function bar() {
  const { index } = asyncLocalStorage.getStore();
  console.log(`processing bar ${index}`);

  if (Math.random() &amp;lt; 0.1) {
    // simulate a random failure
    throw new Error("A random failure happened");
  }
}

async function handleError(err) {
  const { index } = asyncLocalStorage.getStore();
  console.log(`Handling error when processing ${index}: ${err}`);
}

const asyncLocalStorage = new AsyncLocalStorage();

// process 20 things, asynchronously
const tasks = [];
for (let i = 0; i &amp;lt; 20; i++) {
  tasks.push(
    asyncLocalStorage.run({ index: i }, process)
  );
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you execute this code, it will clearly log for which items the failures occured, because the required information is available in the shared state exposed by &lt;code&gt;AsyncLocalStorage&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Example of the output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;processing foo 0
processing bar 0
processing foo 1
processing bar 1
...
Handling error when processing 3: Error: A random failure happened
Handling error when processing 8: Error: A random failure happened
Handling error when processing 14: Error: A random failure happened

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>node</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Starfield visualization in JavaScript</title>
      <dc:creator>Andrés Villarreal</dc:creator>
      <pubDate>Sat, 31 Aug 2024 18:18:07 +0000</pubDate>
      <link>https://dev.to/kaeruct/starfield-visualization-in-javascript-3cnm</link>
      <guid>https://dev.to/kaeruct/starfield-visualization-in-javascript-3cnm</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgj4iktlpunre4ptkanno.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgj4iktlpunre4ptkanno.png" alt="Starfield Visualization" width="800" height="650"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a simple, straightforward implementation of a visualization reminiscent of the classic Windows 95 starfield screensaver.&lt;/p&gt;

&lt;p&gt;It is also interactive: you can touch the screen or use the accelerometer to influence the direction of the movement.&lt;/p&gt;

&lt;p&gt;This is how it works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a bunch of particles (100), each in a random position.&lt;/li&gt;
&lt;li&gt;Every frame, move each particle further away from &lt;em&gt;the center&lt;/em&gt;*. The further the particle is from the center, the more visible it will become. This gives the illusion that the particles are moving closer to the viewer, or that the viewer is going further into space.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;The center&lt;/em&gt; is not really the center of the screen, but a variable point which can be influenced by the user by moving their cursor or tilting their device.&lt;/li&gt;
&lt;li&gt;When the particles go outside of the view, put them near the center again, this keeps the visualization going on in perpetuity.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this blog post, I want to share the heavily-commented source code to demonstrate how simple it is to create visually appealing animations with a few lines of code and basic math knowledge.&lt;/p&gt;

&lt;p&gt;Please &lt;a href="https://kaeruct.github.io/projects/starfield/" rel="noopener noreferrer"&gt;click here&lt;/a&gt; to see the visualization in action!&lt;/p&gt;

&lt;p&gt;The code is available in this Gist:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


</description>
      <category>tutorial</category>
      <category>javascript</category>
      <category>html</category>
      <category>canvas</category>
    </item>
    <item>
      <title>Migrating From DokuWiki to Obsidian</title>
      <dc:creator>Andrés Villarreal</dc:creator>
      <pubDate>Sun, 18 Aug 2024 19:37:56 +0000</pubDate>
      <link>https://dev.to/kaeruct/migrating-from-dokuwiki-to-obsidian-1n35</link>
      <guid>https://dev.to/kaeruct/migrating-from-dokuwiki-to-obsidian-1n35</guid>
      <description>&lt;p&gt;About a year ago, I decided to move all my personal notes from &lt;a href="https://www.dokuwiki.org" rel="noopener noreferrer"&gt;DokuWiki&lt;/a&gt; to &lt;a href="https://obsidian.md/" rel="noopener noreferrer"&gt;Obsidian&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;DokuWiki is great software and has served me well, but I never utilized it to its full capacity. It’s biggest strength is that it’s a… wiki, and I was the sole user.&lt;/p&gt;

&lt;p&gt;It made little sense for me to keep a service running when I could just have some Markdown files locally. And Obsidian provides a really nice UI on top of those Markdown files.&lt;/p&gt;

&lt;p&gt;One reason I chose DokuWiki in the first place, is that it doesn’t need a database. All the content is kept in plaintext files. So if I ever wanted to move my notes elsewhere, it would hopefully be a painless process. In the end, I think it was a good choice, because the migration was quite simple.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Migration Process
&lt;/h2&gt;

&lt;p&gt;These are the steps I followed:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Copying the data folder locally
&lt;/h3&gt;

&lt;p&gt;First, I needed to get the source text and image files from DokuWiki to my local machine. All of it is located at &lt;code&gt;/var/www/dokuwiki/data/&lt;/code&gt; for a common installation. This directory contains all the text files and images that comprise the wiki pages. &lt;a href="https://www.dokuwiki.org/config:savedir" rel="noopener noreferrer"&gt;This directory is configurable&lt;/a&gt;, so check your configuration if you’re unsure.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Convert all text files from DokuWiki Syntax to proper Markdown
&lt;/h3&gt;

&lt;p&gt;The next step was to locate all the &lt;code&gt;.txt&lt;/code&gt; files in &lt;code&gt;data/pages&lt;/code&gt;. These files needed to be renamed to &lt;code&gt;.md&lt;/code&gt;, and the content converted to proper Markdown.&lt;/p&gt;

&lt;p&gt;DokuWiki uses its own syntax, which is not really used anywhere else.&lt;/p&gt;

&lt;p&gt;I ended up writing a quick script to handle this, with some help from ChatGPT to speed up the process.&lt;/p&gt;

&lt;p&gt;Main points the script covers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Changing DokuWiki’s heading syntax to Markdown format.&lt;/li&gt;
&lt;li&gt;Adjusting link and image paths to work with Obsidian.&lt;/li&gt;
&lt;li&gt;Handling any quirks like list formatting.&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h3&gt;
  
  
  3. Moving Media Files
&lt;/h3&gt;

&lt;p&gt;After the text files were converted, I moved all the media files from &lt;code&gt;data/media&lt;/code&gt; to &lt;code&gt;data/pages&lt;/code&gt;. Obsidian can handle images and other media in the same directory as the Markdown files, which DokuWiki did not.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Final Touches
&lt;/h3&gt;

&lt;p&gt;The last step was to verify everything in Obsidian. I went through my notes to check formatting and that there were no broken links or images. A few minor tweaks were necessary, but the script got me 95% of the way there!&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;It’s been about a year since I did the migration, and using Obsidian is much smoother. I just need to make sure the directory with my notes is properly backed up / synchronized between my devices. Obsidian offers this as a paid feature, but I didn’t want to depend on yet another 3rd party service. I simply use a Git repository to keep my notes.&lt;/p&gt;

&lt;p&gt;For anyone looking to do the same or similar, I hope this post helps you out.&lt;/p&gt;

&lt;p&gt;Here is a small peek of my notes in Obsidian’s beautiful graph view:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqibg91z17xs1zf5zhmqr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqibg91z17xs1zf5zhmqr.png" alt="obsidian graph view" width="800" height="782"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>dokuwiki</category>
      <category>obsidian</category>
    </item>
    <item>
      <title>How to use Let's Encrypt certificates with Keycloak</title>
      <dc:creator>Andrés Villarreal</dc:creator>
      <pubDate>Wed, 04 Jan 2023 16:28:41 +0000</pubDate>
      <link>https://dev.to/kaeruct/how-to-use-lets-encrypt-certificates-with-keycloak-5h98</link>
      <guid>https://dev.to/kaeruct/how-to-use-lets-encrypt-certificates-with-keycloak-5h98</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/http%3A%2F%2Fkaeruct.github.io%2Fletsencrypt_keycloak.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/http%3A%2F%2Fkaeruct.github.io%2Fletsencrypt_keycloak.png" alt="Let's Encrypt + Keycloak" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Keycloak provides user federation, strong authentication, user management, fine-grained authorization, and more.&lt;/p&gt;

&lt;p&gt;Here is a guide to enable HTTPS access to your Keycloak server using a free Let's Encrypt SSL certificate. The beauty of Let's Encrypt is its ease of use and the fact that it's free!&lt;/p&gt;

&lt;p&gt;This guide assumes you have already installed Keycloak at &lt;code&gt;/opt/keycloak/&lt;/code&gt; using the &lt;a href="https://www.keycloak.org/getting-started/getting-started-zip" rel="noopener noreferrer"&gt;official guide for bare metal installs&lt;/a&gt;, and now you want to enable HTTPS access. You need to have version &lt;strong&gt;20&lt;/strong&gt; or higher.&lt;/p&gt;

&lt;p&gt;In all the instructions below, be sure to replace &lt;code&gt;&amp;lt;DOMAIN&amp;gt;&lt;/code&gt; with the actual domain you will be using. All commands in this guide must be run as root.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Install certbot
&lt;/h3&gt;

&lt;p&gt;First you will need to install &lt;code&gt;certbot&lt;/code&gt;. This depends on the Linux distro you are using.&lt;/p&gt;

&lt;p&gt;For example, for apt-based distros such as Debian or Ubuntu, you can just run the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apt install certbot

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Create HTTPS certificates
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Set up certificates:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ certbot certonly --standalone --preferred-challenges http -d &amp;lt;DOMAIN&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Configure Keycloak to use Let's Encrypt certificates
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Change configuration:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vi /opt/keycloak/conf/keycloak.conf

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Add or update the following lines in that file:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https-certificate-file=/etc/letsencrypt/live/&amp;lt;DOMAIN&amp;gt;/cert.pem
https-certificate-key-file=/etc/letsencrypt/live/&amp;lt;DOMAIN&amp;gt;/privkey.pem
hostname=&amp;lt;DOMAIN&amp;gt;

https-port=443
http-port=80

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Update keycloak config:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ /opt/keycloak/bin/kc.sh build

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;You're done! Now you can run the following command and Keycloak should now be accessible from the browser via HTTPS:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ /opt/keycloak/bin/kc.sh start

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Optional: Set up Keycloak as a systemd service
&lt;/h3&gt;

&lt;p&gt;The official guide purposely leaves this open-ended because there are many ways in which you might want to handle the lifecycle of the Keycloak server. However, I think a good approach is to just use &lt;a href="https://systemd.io/" rel="noopener noreferrer"&gt;systemd&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  4.1. Set up systemd service
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Create user and group:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ useradd -g keycloak keycloak

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Give access to certificates:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ chmod 0755 /etc/letsencrypt/{live,archive}
$ chgrp keycloak /etc/letsencrypt/{live,archive}
$ chgrp -h keycloak /etc/letsencrypt/live/&amp;lt;DOMAIN&amp;gt;/privkey.pem

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Give access to Keycloak directory:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ chown -R keycloak:keycloak /opt/keycloak/

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Create systemd service:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ vi /etc/systemd/system/keycloak.service

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Write the following contents into the file. You might need to add your chosen database service to the &lt;code&gt;After&lt;/code&gt; line, for example &lt;code&gt;postgresql.service&lt;/code&gt; or &lt;code&gt;mysql.service&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Unit]
Description=Keycloak Application Server
After=syslog.target network.target

[Service]
Type=idle
User=keycloak
Group=keycloak
LimitNOFILE=102642
ExecStart=/opt/keycloak/bin/kc.sh start --optimized
StandardOutput=append:/var/log/keycloak.log
StandardError=inherit
RestartSec=2s
Restart=always
AmbientCapabilities=CAP\_NET\_BIND\_SERVICE

[Install]
WantedBy=multi-user.target

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Reload systemd config and start service:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ systemctl daemon-reload
$ systemctl start keycloak.service

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  4.2. Automatic Keycloak server restart when certificates are updated
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Make certbot restart Keycloak after updating certificates:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cd /etc/letsencrypt/renewal-hooks/deploy
$ vi restart-keycloak.sh

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Write these contents:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/sh
systemctl restart keycloak

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Make the script executable:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ chmod +x restart-keycloak.sh

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You're done! Now Keycloak is set up as a systemd service and will start when your machine boots up.&lt;/p&gt;

</description>
      <category>keycloak</category>
      <category>letsencrypt</category>
      <category>linux</category>
    </item>
    <item>
      <title>Try Andy's Desk</title>
      <dc:creator>Andrés Villarreal</dc:creator>
      <pubDate>Sat, 15 Jan 2022 10:35:29 +0000</pubDate>
      <link>https://dev.to/kaeruct/try-andys-desk-5d17</link>
      <guid>https://dev.to/kaeruct/try-andys-desk-5d17</guid>
      <description>&lt;p&gt;LINK: &lt;a href="https://desk.glitchy.website/" rel="noopener noreferrer"&gt;https://desk.glitchy.website/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4vg8ahjrmlkbthyat6u7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4vg8ahjrmlkbthyat6u7.png" alt=" " width="800" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a nostalgic (and not very faithful) recreation of the Windows 7 desktop UI.&lt;/p&gt;

&lt;p&gt;The code is intentionally not too polished, as this is a project I work on for fun.&lt;/p&gt;

&lt;p&gt;Things might be buggy but that's part of the fun.&lt;/p&gt;

&lt;p&gt;You WILL find weird hacks and work-arounds and lots of inefficient stuff.&lt;/p&gt;

&lt;p&gt;One of my main goals with this project was to build it as fast as possible. I managed this by integrating as many existing projects/code as I could find. Of course, everything is credited if you open &lt;code&gt;CREDITS.txt&lt;/code&gt;. You can also take a look at the source code for more information!&lt;/p&gt;

&lt;p&gt;You can find the repo here: &lt;a href="https://github.com/KaeruCT/desk.glitchy.website" rel="noopener noreferrer"&gt;https://github.com/KaeruCT/desk.glitchy.website&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
      <category>desktop</category>
    </item>
    <item>
      <title>Free Static Web Hosts for Frontend Developers</title>
      <dc:creator>Andrés Villarreal</dc:creator>
      <pubDate>Sat, 15 Jan 2022 09:30:31 +0000</pubDate>
      <link>https://dev.to/kaeruct/free-static-web-hosts-for-frontend-developers-mjk</link>
      <guid>https://dev.to/kaeruct/free-static-web-hosts-for-frontend-developers-mjk</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/http%3A%2F%2Fkaeruct.github.io%2Fstatic-website-code.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/http%3A%2F%2Fkaeruct.github.io%2Fstatic-website-code.jpg" alt="F-Droid" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nowadays it's very easy to publish on the web for free.&lt;/p&gt;

&lt;p&gt;There are countless blogging platforms and website creators. But these platforms usually end up controlling your content. Sometimes you cannot even export your own data!&lt;/p&gt;

&lt;p&gt;The other extreme is to set up your own server by yourself. Buy a VPS (virtual private server) or a shared hosting somewhere, install a web server, and upload your files. This is a lot of work already! Specially if all you want is to publish a static website.&lt;/p&gt;

&lt;p&gt;You already know HTML and CSS, and maybe a bit of JavaScript. You just want a place where you can drop your files and see it on the web!&lt;/p&gt;

&lt;p&gt;Here is a list of services that allow you to do that, in no specific order:&lt;/p&gt;

&lt;h2&gt;
  
  
  Netlify
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.netlify.com/" rel="noopener noreferrer"&gt;Netlify&lt;/a&gt; allows you to drag &amp;amp; drop a zip with your files. You can also connect it to your project from Github, Gitlab or Bitbucket. I use Netlify for a lot of my projects, such as &lt;a href="https://desk.glitchy.website" rel="noopener noreferrer"&gt;desk.glitchy.website&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vercel
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://vercel.com/new" rel="noopener noreferrer"&gt;Vercel&lt;/a&gt; is very similar to Netlify. They are also the company behing Next.js, so they have many integrations with it. I use Vercel for my &lt;a href="https://andres.villarreal.co.cr" rel="noopener noreferrer"&gt;personal website&lt;/a&gt; and for &lt;a href="https://glitchy.website" rel="noopener noreferrer"&gt;glitchy.website&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Surge
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://surge.sh/" rel="noopener noreferrer"&gt;Surge&lt;/a&gt; allows you to easily publish your static website from the command line.&lt;/p&gt;

&lt;h2&gt;
  
  
  Github Pages
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://pages.github.com/" rel="noopener noreferrer"&gt;Github Pages&lt;/a&gt; allows you to directly from your GitHub repository. Just edit, push, and your changes are live. &lt;a href="https://kaeruct.github.io/" rel="noopener noreferrer"&gt;My blog&lt;/a&gt; is hosted on Github Pages.&lt;/p&gt;

&lt;h2&gt;
  
  
  GitLab Pages
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.gitlab.com/ee/user/project/pages/" rel="noopener noreferrer"&gt;GitLab Pages&lt;/a&gt; allows you to publish static websites directly from a repository in GitLab.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing Words
&lt;/h2&gt;

&lt;p&gt;With these services, you can host your own static website for free. If having your own domain is important, then you will have to buy one, but that's the only thing you need, as many of these services allow you to use your own custom domain as well.&lt;/p&gt;

&lt;p&gt;I recommend you familiarize yourself with the options and not to put all your eggs in one basket. The beauty of static website is that something happens to the provider, you can just copy your files to another one, and you're done! Keep it simple.&lt;/p&gt;

</description>
      <category>css</category>
      <category>html</category>
      <category>javascript</category>
      <category>tips</category>
    </item>
    <item>
      <title>Publishing an App on F-Droid</title>
      <dc:creator>Andrés Villarreal</dc:creator>
      <pubDate>Tue, 03 Aug 2021 15:29:13 +0000</pubDate>
      <link>https://dev.to/kaeruct/publishing-an-app-on-f-droid-93n</link>
      <guid>https://dev.to/kaeruct/publishing-an-app-on-f-droid-93n</guid>
      <description>&lt;p&gt;&lt;a href="https://f-droid.org/" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/http%3A%2F%2Fkaeruct.github.io%2Ffdroid.svg" alt="F-Droid" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I made &lt;a href="https://f-droid.org/packages/com.kaeruct.raumballer/" rel="noopener noreferrer"&gt;some&lt;/a&gt; &lt;a href="https://f-droid.org/packages/com.kaeruct.gotosleep/" rel="noopener noreferrer"&gt;small&lt;/a&gt; &lt;a href="https://f-droid.org/packages/com.kaeruct.glxy/" rel="noopener noreferrer"&gt;apps&lt;/a&gt; for Android and I wanted to distribute them. I also care a lot about software freedom, so F-Droid is the best place for me to publish my apps.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Disclaimer! You are not able to sell your app on F-Droid. If you want to make money with it, you would need to allow users to pay through another method. Please see this &lt;a href="https://opensource.stackexchange.com/questions/88/how-can-free-and-open-source-projects-be-monetized" rel="noopener noreferrer"&gt;StackExchange question&lt;/a&gt; if you're interested in monetization.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What's F-Droid?
&lt;/h2&gt;

&lt;p&gt;F-Droid is an alternative for the Play Store and other Android stores focused on software freedom and privacy.&lt;/p&gt;

&lt;p&gt;The biggest difference is that F-Droid only allows &lt;a href="https://www.gnu.org/philosophy/free-sw.en.html" rel="noopener noreferrer"&gt;Free and Open Source (FOSS) software&lt;/a&gt;. F-Droid also respects your privacy and discourages application which do not.&lt;/p&gt;

&lt;p&gt;In an age where privacy and software freedom matters most, F-Droid is the perfect replacement for other Android stores.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why publish on F-Droid?
&lt;/h2&gt;

&lt;p&gt;F-Droid is a great way of distributing your FOSS Android application. It makes it very easy for your users to install your app and keep it up to date, without requiring them to side-load it.&lt;/p&gt;

&lt;p&gt;There is also a higher level of trust since every apk published on F-Droid is built from source.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to submit your app to F-Droid
&lt;/h2&gt;

&lt;p&gt;I've broken this down into two big steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Preparing&lt;/strong&gt; your app&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Submitting&lt;/strong&gt; it to F-Droid&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Preparing your app's repo
&lt;/h3&gt;

&lt;p&gt;F-Droid needs some metadata about your app so it can show something to the users. For example: app name, description, screenshots, and the changelog.&lt;/p&gt;

&lt;p&gt;Makes sure you have good screenshots and good explanatory texts about your app. This makes people more interested in it, and speeds up the review process.&lt;/p&gt;

&lt;p&gt;The best way to get this metadata to F-Droid is to put it in your app's repo. You only need to create a few files, following either of these methods. I recommend Fastlane.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://gitlab.com/-/snippets/1895688" rel="noopener noreferrer"&gt;Fastlane&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gitlab.com/-/snippets/1901490" rel="noopener noreferrer"&gt;Triple-T&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Submitting your app's build metadata to F-Droid
&lt;/h3&gt;

&lt;p&gt;Getting your app on F-Droid is as easy as sending them a merge request to their &lt;a href="https://gitlab.com/fdroid/fdroiddata" rel="noopener noreferrer"&gt;data repo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To summarize, you need to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fork the repo on GitLab&lt;/li&gt;
&lt;li&gt;Create a new branch for your changes&lt;/li&gt;
&lt;li&gt;Create a metadata &lt;code&gt;.yml&lt;/code&gt; file for your app. You should name it using your app's id, for example: &lt;code&gt;com.kaeruct.raumballer.yml&lt;/code&gt;. There are some templates &lt;a href="https://gitlab.com/fdroid/wiki/-/wikis/Metadata/YAML-Metadata" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Submit the merge request to &lt;a href="https://gitlab.com/fdroid/fdroiddata" rel="noopener noreferrer"&gt;F-Droid's data repo&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Wait for the automated build to finish.&lt;/li&gt;
&lt;li&gt;Fix any errors in the build or feedback to your merge request.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There are details instructions in the repo's &lt;a href="https://gitlab.com/fdroid/fdroiddata/-/blob/master/CONTRIBUTING.md" rel="noopener noreferrer"&gt;CONTRIBUTING.md&lt;/a&gt; file.&lt;/p&gt;

&lt;p&gt;I highly recommend you also set up auto updates. This allows F-Droid to automatically know when you have released a new version. It will then update your app's metadata &lt;code&gt;.yml&lt;/code&gt; file automatically and publish the new version of your app on the store.&lt;/p&gt;

&lt;h3&gt;
  
  
  My experience
&lt;/h3&gt;

&lt;p&gt;Each of the apps I submitted were approved around 2 or 3 weeks, but this may vary depending on the complexity of your app. The contributors are very friendly and always give you helpful feedback to get your app on F-Droid as soon as possible.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gitlab.com/fdroid/fdroiddata/-/blob/master/metadata/com.kaeruct.raumballer.yml" rel="noopener noreferrer"&gt;Here is one of my app's metadata file on the F-Droid data repo&lt;/a&gt; and &lt;a href="https://github.com/KaeruCT/RaumBaller" rel="noopener noreferrer"&gt;the source code on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Closing words
&lt;/h3&gt;

&lt;p&gt;F-Droid is a very valuable resource for people who care about software freedom and privacy. It is also run by volunteers. Please &lt;a href="https://f-droid.org/en/donate/" rel="noopener noreferrer"&gt;donate&lt;/a&gt; if you are able to!&lt;/p&gt;

</description>
      <category>android</category>
      <category>fdroid</category>
      <category>tips</category>
      <category>tutorials</category>
    </item>
    <item>
      <title>Starry Sky in HTML5 Canvas - Part 2</title>
      <dc:creator>Andrés Villarreal</dc:creator>
      <pubDate>Sat, 16 May 2020 10:22:25 +0000</pubDate>
      <link>https://dev.to/kaeruct/starry-sky-in-html5-canvas-part-2-520k</link>
      <guid>https://dev.to/kaeruct/starry-sky-in-html5-canvas-part-2-520k</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This is part of a series! Please make sure you have read &lt;a href="https://dev.to/kaeruct/starry-sky-in-html5-canvas-4e3o"&gt;Part 1&lt;/a&gt; first!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IMPORTANT&lt;/strong&gt; -- you can try out the result of this tutorial by visiting this &lt;a href="https://codesandbox.io/s/z68y1012yl?fontsize=14" rel="noopener noreferrer"&gt;CodeSandbox&lt;/a&gt;.&lt;br&gt;
However, I encourage you to read the blog post and try to follow along to understand how and why it works.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Last time we left off with a very nice starry sky, but it's a bit dead. We need to add some animation to it!&lt;br&gt;
The way animation is done on HTML5 canvas is by drawing something else every frame.&lt;/p&gt;

&lt;p&gt;For our case, we can use the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame" rel="noopener noreferrer"&gt;&lt;code&gt;requestAnimationFrame() function&lt;/code&gt;&lt;/a&gt; to call our &lt;code&gt;render()&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;First, we will add a &lt;code&gt;counter&lt;/code&gt; variable. We will increment this every time we draw.&lt;br&gt;
This is useful because we will have a number that will change with every render.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, we will update our &lt;code&gt;render()&lt;/code&gt; function so it uses &lt;code&gt;requestAnimationFrame()&lt;/code&gt;. We will also make it increment the counter.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillStyle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fillRect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;stars&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;star&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;star&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;star&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;star&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;fillCircle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rgb(255, 255, 255)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nf"&gt;requestAnimationFrame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For now, this will look exactly the same as before, because we always render the same thing. But let's begin to change that now.&lt;/p&gt;

&lt;p&gt;We'll make a small change to make the stars look like they're flickering.&lt;/p&gt;

&lt;p&gt;First, let's add a function to generate an opacity value. This value will go from 0 to 1 and will determine the opacity of our star.&lt;/p&gt;

&lt;p&gt;The use of &lt;code&gt;Math.sin()&lt;/code&gt; in the function below is just to make sure we get a value that changes smoothly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;minStarOpacity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;maxStarOpacity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.7&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getOpacity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;factor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;opacityIncrement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;maxStarOpacity&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;minStarOpacity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;factor&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;opacity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;minStarOpacity&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;opacityIncrement&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, we will use this function when rendering our stars.&lt;br&gt;
Also notice how we change the color from &lt;code&gt;rgb(255, 255, 255)&lt;/code&gt; to &lt;code&gt;rgba(255, 255, 255, opacity)&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillStyle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fillRect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;stars&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;star&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// factor will be a different number for every star&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;factor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;star&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;star&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;opacity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getOpacity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;factor&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;fillCircle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;star&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`rgba(255, 255, 255, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nf"&gt;requestAnimationFrame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fkaeruct.github.io%2Fgalleries%2Fscreenshots%2Fstarry%2Fflicker.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fkaeruct.github.io%2Fgalleries%2Fscreenshots%2Fstarry%2Fflicker.gif" alt="Animated Starry Sky" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now the sky is looking really nice and animated. But it's still missing a nice big &lt;code&gt;moon&lt;/code&gt;. Let's add it next.&lt;/p&gt;

&lt;p&gt;We will create a function to render our moon, and call it from &lt;code&gt;render()&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;moon&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#fea&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;r&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;renderMoon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;blur&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;fillCircle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;moon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;moon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;moon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;moon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// render a smaller circle above the moon to give it that well-known moon-shape&lt;/span&gt;
  &lt;span class="nf"&gt;fillCircle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;moon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;moon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;moon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;moon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;moon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;backgroundColor&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And our updated &lt;code&gt;render()&lt;/code&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillStyle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fillRect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;stars&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;star&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;factor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;star&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;star&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;opacity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getOpacity&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;factor&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;fillCircle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;star&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;`rgba(255, 255, 255, &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nf"&gt;renderMoon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nf"&gt;requestAnimationFrame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That leaves us with the finished product:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fkaeruct.github.io%2Fgalleries%2Fscreenshots%2Fstarry%2Fmoon.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fkaeruct.github.io%2Fgalleries%2Fscreenshots%2Fstarry%2Fmoon.gif" alt="Animated Starry Sky with Moon" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks for following this tutorial to the end! Remember you can look at a working example in the &lt;a href="https://codesandbox.io/s/z68y1012yl?fontsize=14" rel="noopener noreferrer"&gt;CodeSandbox&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Have fun experimenting and tweaking the values used to render the stars and the moon.&lt;br&gt;
Some ideas you may want to try to learn more and improve your skills:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Make the stars more colorful.&lt;/li&gt;
&lt;li&gt;Make the moon move across the sky.&lt;/li&gt;
&lt;li&gt;Add shooting stars.&lt;/li&gt;
&lt;li&gt;Add a gradient background instead of a solid color.&lt;/li&gt;
&lt;li&gt;Add multiple moons.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Don't hesitate to contact me at &lt;a href="http://twitter.com/KaeruCT" rel="noopener noreferrer"&gt;@KaeruCT&lt;/a&gt; if you have any questions, suggestions, or improvements for this tutorial!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>tutorial</category>
      <category>canvas</category>
      <category>html</category>
    </item>
    <item>
      <title>Starry Sky in HTML5 Canvas - Part 1</title>
      <dc:creator>Andrés Villarreal</dc:creator>
      <pubDate>Sat, 16 May 2020 10:19:19 +0000</pubDate>
      <link>https://dev.to/kaeruct/starry-sky-in-html5-canvas-4e3o</link>
      <guid>https://dev.to/kaeruct/starry-sky-in-html5-canvas-4e3o</guid>
      <description>&lt;p&gt;In my spare time I often enjoy creating visualizations using HTML5 canvas.&lt;br&gt;
I'm planning to do a little presentation about this so I thought a good way to get started was to create a blog post explaining how to do a simple one.&lt;/p&gt;

&lt;p&gt;This tutorial will teach you how to create something like the image below from scratch!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fkaeruct.github.io%2F%2Fgalleries%2Fscreenshots%2Fstarry%2Fmoon.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fkaeruct.github.io%2F%2Fgalleries%2Fscreenshots%2Fstarry%2Fmoon.gif" alt="Animated Starry Sky with Moon" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;IMPORTANT&lt;/strong&gt; -- you can try out the result of &lt;strong&gt;this part&lt;/strong&gt; of the tutorial by visiting this &lt;a href="https://codesandbox.io/s/kmrx1z6wn7?fontsize=14" rel="noopener noreferrer"&gt;CodeSandbox&lt;/a&gt;.&lt;br&gt;
However, I encourage you to read the blog post and try to follow along to understand how and why it works.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;First, you will need an HTML file, let's name it &lt;code&gt;index.html&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Starry sky&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nt"&gt;html&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="nt"&gt;canvas&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;canvas&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"canvas"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/canvas&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing crazy so far, just some styles and a &lt;code&gt;canvas&lt;/code&gt; element.&lt;/p&gt;

&lt;p&gt;Next, let's create a JavaScript file. Let's name this &lt;code&gt;index.js&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;backgroundColor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#030318&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerWidth&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHeight&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;canvas&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#canvas&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2d&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;canvas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillStyle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fillRect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the code above, we set the canvas' width and height so it takes up the whole window.&lt;br&gt;
Then, in the &lt;code&gt;render()&lt;/code&gt; function, we fill the canvas with the background color.&lt;br&gt;
If you run it on your browser, it will look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fkaeruct.github.io%2Fgalleries%2Fscreenshots%2Fstarry%2Fstep1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fkaeruct.github.io%2Fgalleries%2Fscreenshots%2Fstarry%2Fstep1.png" alt="Step 1" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Yup. Not very interesting. Let's put something in there!&lt;br&gt;
Let's add some code to our &lt;code&gt;index.js&lt;/code&gt; file to draw some stars.&lt;/p&gt;

&lt;p&gt;First, let's have a function that creates the stars.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createStars&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;spacing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stars&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;spacing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;spacing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;star&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
      &lt;span class="nx"&gt;stars&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;star&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;stars&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stars&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createStars&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;spacing&lt;/code&gt; parameter will control the spacing between stars.&lt;/p&gt;

&lt;p&gt;Then, let's update our &lt;code&gt;render()&lt;/code&gt; function so it renders the stars.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillStyle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fillRect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;stars&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;star&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;star&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;star&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beginPath&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillStyle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rgb(255, 255, 255)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;arc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PI&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For our purposes, a star is a circle, so we can use the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/arc" rel="noopener noreferrer"&gt;&lt;code&gt;arc()&lt;/code&gt; function&lt;/a&gt; to draw our stars.&lt;br&gt;
An explanation of the parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; are used for the position.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;r&lt;/code&gt; is used for the radius of the circle.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;0&lt;/code&gt; and &lt;code&gt;Math.PI * 2&lt;/code&gt; are the start and end angle, respectively.
A full circle goes from &lt;code&gt;0&lt;/code&gt; to &lt;code&gt;2pi&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The line &lt;code&gt;ctx.fillStyle = "rgb(255, 255, 255)";&lt;/code&gt; is used to set the color of the circle to white.&lt;/p&gt;

&lt;p&gt;Let's see what we get now:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fkaeruct.github.io%2Fgalleries%2Fscreenshots%2Fstarry%2Fstep2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fkaeruct.github.io%2Fgalleries%2Fscreenshots%2Fstarry%2Fstep2.png" alt="Step 2" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's definitely a bit more interesting. But it doesn't look like a starry sky at all!&lt;br&gt;
Stars don't usually look so uniform and boring. We need to add some randomness.&lt;/p&gt;

&lt;p&gt;Let's create a function called &lt;code&gt;randomInt(max)&lt;/code&gt; that will return a random number:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;randomInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;max&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;floor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;max&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, let's use these random numbers when creating our stars:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createStars&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;spacing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stars&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;spacing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;spacing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;star&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;randomInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spacing&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;randomInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spacing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
      &lt;span class="nx"&gt;stars&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;star&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;stars&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fkaeruct.github.io%2Fgalleries%2Fscreenshots%2Fstarry%2Fstep3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fkaeruct.github.io%2Fgalleries%2Fscreenshots%2Fstarry%2Fstep3.png" alt="Step 3" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That looks already almost real! Now let's make it so the stars are different sizes.&lt;br&gt;
To do this, we will need a different radius for each star, so we will add it to the star objects.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;maxStarRadius&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;1.5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createStars&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;spacing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;stars&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;

  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;spacing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;spacing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;star&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;randomInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spacing&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;randomInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spacing&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="na"&gt;r&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;maxStarRadius&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
      &lt;span class="nx"&gt;stars&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;star&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;stars&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, we will update the &lt;code&gt;render()&lt;/code&gt; function so it uses the star's radius when drawing.&lt;br&gt;
While we're at it, let's extract the circle drawing logic to a new function as well.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fillCircle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fillStyle&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beginPath&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillStyle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fillStyle&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;arc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PI&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fill&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fillStyle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;backgroundColor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fillRect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;stars&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;star&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;star&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;star&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;star&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;fillCircle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;rgb(255, 255, 255)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fkaeruct.github.io%2Fgalleries%2Fscreenshots%2Fstarry%2Fstep4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fkaeruct.github.io%2Fgalleries%2Fscreenshots%2Fstarry%2Fstep4.png" alt="Step 4" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Much better! Now the stars are all different sizes!&lt;/p&gt;

&lt;p&gt;This is all for part 1. You can continue reading &lt;a href="https://dev.to/kaeruct/starry-sky-in-html5-canvas-part-2-520k"&gt;Part 2&lt;/a&gt;, where we will add a moon and make our stars flicker!&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>javascript</category>
      <category>html</category>
      <category>canvas</category>
    </item>
  </channel>
</rss>
