<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>Sam McBroom</title>
    <subtitle>Projects, devlogs, art, and thoughts</subtitle>
    <link rel="self" type="application/atom+xml" href="https://sammcb.com/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://sammcb.com"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-04-04T00:00:00+00:00</updated>
    <id>https://sammcb.com/atom.xml</id>
    <entry xml:lang="en">
        <title>Configure it? I barely node it!</title>
        <published>2026-04-04T00:00:00+00:00</published>
        <updated>2026-04-04T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Sam McBroom
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://sammcb.com/blog/homelab-first-node-setup/"/>
        <id>https://sammcb.com/blog/homelab-first-node-setup/</id>
        
        <content type="html" xml:base="https://sammcb.com/blog/homelab-first-node-setup/">&lt;h2 id=&quot;it-works-on-my-machine&quot;&gt;It works on my machine&lt;&#x2F;h2&gt;
&lt;p&gt;For a while now, I&#x27;ve wanted to set up a small &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Home_server&quot;&gt;home server&lt;&#x2F;a&gt; (more commonly referred to as homelabs) to run some basic services and give me a place to play around with a personal &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;kubernetes.io&quot;&gt;Kubernetes&lt;&#x2F;a&gt; cluster. I decided to start by setting up a simple single-node cluster using a &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Virtual_machine&quot;&gt;VM&lt;&#x2F;a&gt; running on one machine. I&#x27;ve flip-flopped back-and-forth on getting a machine, because I really only wanted to host some Minecraft servers and maybe my website instead of using GitHub pages. However, recently I learned about &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;codeberg.org&quot;&gt;Codeberg&lt;&#x2F;a&gt; and love their mission. I decided to migrate my repos from GitHub to Codeberg, but ran into some issues with their provided runner sizes for CI jobs. I use &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;nixos.org&quot;&gt;Nix&lt;&#x2F;a&gt; for my projects, and while I love many aspects about Nix, it can lead to heavy&#x2F;slow initial installations when using &lt;code&gt;flake&lt;&#x2F;code&gt; dependencies. Codeberg urges users to use their provided runners responsibly, and in that spirit I decided this would be a great time to finally set up a homelab and also use it as a self-hosted runner. So I purchased a machine and finally committed to the project!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;network-configuration&quot;&gt;Network configuration&lt;&#x2F;h2&gt;
&lt;p&gt;I wanted to provide some basic network security for my home network. &lt;strong&gt;Disclaimer: I am &lt;em&gt;not&lt;&#x2F;em&gt; a network security professional and am still learning more about best practices, so this isn&#x27;t meant to be a definitive guide!&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;First, I created a separate &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;VLAN&quot;&gt;VLAN&lt;&#x2F;a&gt; for future homelab nodes. I set up the homelab VLAN to be isolated from any other VLAN networks using firewall rules to block network traffic from crossing VLAN boundaries. I then created a new Wi-Fi SSID for machines on the network (for now, I plan to have machines use Wi-Fi instead of Ethernet).&lt;&#x2F;p&gt;
&lt;p&gt;Because I wanted to manage my machines remotely from devices on my main VLAN, I needed to allow some traffic communication between the VLANs. I was able to add a firewall rule that would allow devices on the homelab VLAN to respond to TCP requests initiated from the main VLAN. This allowed connectivity for VNC, SSH, etc., without allowing devices on the homelab VLAN to initiate connections to devices in other VLANs.&lt;&#x2F;p&gt;
&lt;p&gt;With these basic security firewalls in place, I was ready to set up my first (and for now, only) node!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;conditioning&quot;&gt;Conditioning&lt;&#x2F;h2&gt;
&lt;p&gt;Next, it was time to set up my machine so that I could manage it remotely and reduce the amount of processes running to a bare minimum to minimize idle energy usage. I purchased a refurbished Mac mini due to the hardware offering a good balance of power, energy efficiency, and cost. Unfortunately, the default macOS software isn&#x27;t designed to run headless&#x2F;as a dedicated server, so there were a lot of settings I needed to configure to turn off unnecessary features. Once M4 chips are supported, I would love to install &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;asahilinux.org&quot;&gt;Asahi Linux&lt;&#x2F;a&gt; instead of macOS.&lt;&#x2F;p&gt;
&lt;p&gt;The first step was to boot the machine, create a user, connect the device to the homelab VLAN, and enable Screen Sharing. Setting up the Mac mini required using an external display and keyboard initially, so I wanted to do as little as possible and just get the machine to a point where I could manage it via the Screen Sharing app from my macOS laptop. While I expected that just using a keyboard would be sufficient to get through the initial setup, I was annoyed to find that tabbing through fields in the setup forms did not always work as expected. Notably, on the form prompting to sign in with an Apple Account, I was unable to skip the sign in by tabbing through. I ended up needing to bring up the accessibility options and enable &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;support.apple.com&#x2F;guide&#x2F;mac-help&#x2F;use-your-keyboard-like-a-mouse-mh27469&#x2F;mac&quot;&gt;Mouse Keys&lt;&#x2F;a&gt; on the keyboard.&lt;&#x2F;p&gt;
&lt;p&gt;Aside: I do not normally interact with macOS this way, so maybe I was just unaware of other ways to do keyboard-only navigation, but overall I was really disappointed in the default keyboard-only accessibility on the system. Trying to navigate through System Settings without Mouse Keys almost always had issues, where I just couldn&#x27;t navigate to some fields and others wouldn&#x27;t let me tab out.&lt;&#x2F;p&gt;
&lt;p&gt;Anyways, I finally enabled Screen Sharing with the following configuration:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;General &amp;gt; Sharing &amp;gt; Screen Sharing (i)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Screen Sharing: Enabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Anyone may request permission to control screen: disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- VNC viewers may control screen with password: disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Allow access for: Only these users&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	- &amp;lt;List only contains user created during setup&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;It was difficult to find information about what some of the options would do if enabled or disabled. I discovered that &lt;code&gt;Anyone may request permission to control screen&lt;&#x2F;code&gt; being enabled would allow someone to use the credentials of any Mac mini user to log in, but would also require approving requests from the Mac mini. Neither of these things are desirable to me, so I left that disabled. Enabling the &lt;code&gt;VNC viewers may control screen with password&lt;&#x2F;code&gt; would effectively allow logins through a &quot;guest&quot; account with the password specified. However, logging in using the credentials of the allowed users would also work. Again, I left this disabled as I just planned to log in with the user credentials.&lt;&#x2F;p&gt;
&lt;p&gt;Before continuing Mac mini configuration remotely, I configured my router to give the Mac mini &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;MAC_address&quot;&gt;MAC address&lt;&#x2F;a&gt; a fixed &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;IP_address&quot;&gt;IP&lt;&#x2F;a&gt; so I could consistently connect to it in the future. I added a connection using the fixed IP in the Screen Sharing app on my laptop. Finally, I logged in as the user I created, unplugged the device from the keyboard and monitor, and finished setting up all the options.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;lightning-round-settings&quot;&gt;Lightning round: settings!&lt;&#x2F;h2&gt;
&lt;p&gt;To be honest, the rest of this post is not super interesting and I&#x27;m mostly including the full-ish (I might have missed some) list of options I changed as a reference in case I need to wipe the machine and set it up again. Generally, the options I set focused on a few goals: making sure I could log back in remotely even after the machine restarted (which required disabling FileVault and setting some other options) and minimizing unnecessary background processes to improve power efficiency and performance. Thank you so much for reading!&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Sign in with your Apple Account&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- &amp;lt;Not signed in&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Wi-Fi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Wi-Fi: enabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- &amp;lt;Connected to homelab SSID&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Bluetooth&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Bluetooth: disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Network &amp;gt; Firewall&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Firewall: enabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt; Options...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Block all incoming connections: disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Automatically allow built-in software to receive incoming connections: enabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Automatically allow downloaded signed software to receive incoming connections: enabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Enable stealth mode: enabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Process list&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	- screensharingd.bundle: Allow incoming connections&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	- QEMULauncher: Allow incoming connections&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Energy&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Prevent automatic sleeping when the display is off: enabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Wake for network access: enabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Start up automatically after a power failure: enabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;General &amp;gt; AirDrop &amp;amp; Handoff&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Allow Handoff between this Mac and your iCloud devices: disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- AirDrop: No One&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- AirPlay Receiver: disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;General &amp;gt; AutoFill &amp;amp; Passwords&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- AutoFill Passwords and Passkeys: disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Verification codes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Delete after use: enabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;General &amp;gt; Date &amp;amp; Time&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Set time and date automatically: enabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Set time zone automatically using your current location: true&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;General &amp;gt; Language &amp;amp; Region&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Live Text: disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;General &amp;gt; Login Items &amp;amp; Extensions&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Open at Login: &amp;lt;empty list&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Extensions&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- &amp;lt;All extensions for all apps disabled&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Appearance&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Appearance: Auto&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Icon &amp;amp; widget style: Dark (Auto)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Apple Intelligence &amp;amp; Siri&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Apple Intelligence: disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Siri Requests&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Siri: disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Desktop &amp;amp; Dock&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Dock&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Show suggested and recent apps in Dock: disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Widgets&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Show Widgets: &amp;lt;disabled for all options&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- iPhone Widgets: disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Windows&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Drag windows to left or right edge of screen to tile: disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Drag windows to menu bar to fill screen: disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Hold ⌥ key while dragging windows to tile: disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Tiled windows have margins: disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Mission Control&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Automatically rearrange Spaces based on most recent use: disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- When switching to an application, switch to a Space with open windows for the application: disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Group windows by application: disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Displays have separate Spaces: disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Drag windows to top of screen to enter Mission Control: disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Displays&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Color profile: Screen Sharing Virtual Display&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt; Advanced...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Link to Mac or iPad&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Allow your pointer and keyboard to move between any nearby Mac or iPad: disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt; Night Shift...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Schedule: Sunset to Sunrise&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Menu Bar&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Recent documents, applications, and servers: None&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Menu Bar Controls&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- &amp;lt;Only Wi-Fi enabled&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Allow in the Menu Bar&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- SSMenuAgent: enabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- &amp;lt;All other apps disabled&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Spotlight&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Show related content: disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Help Apple improve Search: disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Results from Apps&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- &amp;lt;All disabled&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Results from System&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- &amp;lt;All disabled&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Results from Clipboard: disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Wallpaper&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Black&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Show on all Spaces: enabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt; Screen Saver...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Start Screen Saver...: Never&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Notifications&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Notification Center&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Show previews: Never&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Show notifications&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	- when display is sleeping: disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	- when screen is locked: disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	- when mirroring or sharing the display: Notifications Off&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Application Notifications&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- &amp;lt;All Off&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Sound&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Sound Effects&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Play sound on startup: disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Play user interface sound effects: disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Play feedback when volume is changed: disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Output &amp;amp; Input&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Output volume: Mute&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Lock Screen&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Turn display off when inactive: For 10 minutes&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Require password after screen saver begins or display is turned off: Never&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Privacy &amp;amp; Security&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt; Location Services&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Location Services: enabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Siri: disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- &amp;gt; System Services &amp;gt; Details...&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	- Alerts &amp;amp; Shortcuts Automations: disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	- Suggestions &amp;amp; Search: disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	- Setting time zone: enabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	- System customization: enabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	- Signification locations &amp;amp; routes: disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	- Find My Mac: enabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	- Home: disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	- Networking and wireless: enabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	- Mac Analytics: disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;	- Show location in Control Center when System Services request your location: disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt; &amp;lt;Data, like Calendars, Contacts, etc.&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- &amp;lt;All set to None&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt; &amp;lt;System capabilities, like Accessibility, App Management, etc.&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- &amp;lt;All set to 0&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt; Analytics &amp;amp; Improvements&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Share Mac Analytics: disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Improve Siri &amp;amp; Dictation: disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Improve Assistive Voice Features: disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Share with app developers: disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt; Apple Intelligence Report&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Report duration: Off&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Security&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Allow applications from: App Store &amp;amp; Known Developers&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt; FileVault&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- FileValut: disabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Login Password&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Automatically log in after a restart: enabled&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Users &amp;amp; Groups&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;- Automatically log in as: &amp;lt;user created during setup&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Wow, you made it all the way down here!? I guess you should get some kind of reward. How about a fun fact! Did you know, back in 2012 &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Voyager_1&quot;&gt;Voyager I&lt;&#x2F;a&gt; crossed the heliopause and became the first human-made object to leave the solar system and enter interstellar space? Pretty neat stuff!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>ASCII art and single sources of truth</title>
        <published>2026-02-08T00:00:00+00:00</published>
        <updated>2026-02-08T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Sam McBroom
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://sammcb.com/blog/ascii-art-and-single-sources-of-truth/"/>
        <id>https://sammcb.com/blog/ascii-art-and-single-sources-of-truth/</id>
        
        <content type="html" xml:base="https://sammcb.com/blog/ascii-art-and-single-sources-of-truth/">&lt;h2 id=&quot;tiny-art&quot;&gt;Tiny art&lt;&#x2F;h2&gt;
&lt;p&gt;Recently, I was inspired to try and make a new homepage artwork for my website. I aim for my site to be lightweight, but I was loading in a pretty large image for my homepage. I do use optimizations like &lt;code&gt;decoding=&quot;async&quot;&lt;&#x2F;code&gt; to load images asynchronously and &lt;code&gt;loading=&quot;lazy&quot;&lt;&#x2F;code&gt; to ensure images are only loaded when they need to be viewed, but it still felt like the image was adding a lot of weight to my landing page without adding much value.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;ve known about sites like &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;512kb.club&quot;&gt;The 512KB Club&lt;&#x2F;a&gt;, which encourage web developers to focus on cutting bloat and improving performance, and wanted to see if I could create a cool piece of art while also keeping its size as small as possible. Originally, I planned to create some pixel art as it&#x27;s one of my favorite art styles, but while thinking about what to make I had another idea: I could make some &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;ASCII_art&quot;&gt;ASCII art&lt;&#x2F;a&gt;!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;ascii-use-me&quot;&gt;ASCII-use me?&lt;&#x2F;h2&gt;
&lt;p&gt;Broadly, ASCII art is a term used to refer to art made with text. Technically, &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;ASCII&quot;&gt;ASCII&lt;&#x2F;a&gt; only includes a specific set of printable characters, but nowadays I would label any text-based art as ASCII art. ASCII art is pretty similar to pixel art. It usually uses a small canvas with a limited &quot;pallet&quot; of characters, and commonly resembles 1-bit (2 color) pixel art due to a lack of color (though depending on the program displaying the art, it can be colored as well). Because it can just be text, an ASCII artwork would also be one of the smallest visuals I could load on my homepage.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;d never attempted to create any ASCII art beyond simple emoticons and a few small animations for some text-based games. I love mountain scapes. My favorite mountain (for all time and forever &lt;code&gt;&amp;lt;3&lt;&#x2F;code&gt;) is Mt. Hood, so of course I had to draw? (paint? type?) it! I started by finding some reference images to use. Personally, I found it easiest to begin by making the outline and then filling in with shading. I chose to stick with the traditional ASCII pallet, mainly because larger character sets felt overwhelming and were hard to type due to not having dedicated keyboard keys. Overall, I was really happy with how it turned out!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;probably-overthinking-things&quot;&gt;Probably overthinking things&lt;&#x2F;h2&gt;
&lt;p&gt;My main concern with using ASCII art for my homepage was the potential for text wrapping on small width displays. This got me thinking about what fundamentally &quot;defined&quot; my ASCII art. As a software engineer, this issue felt very similar to &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Single_source_of_truth&quot;&gt;single source of truth (SSOT)&lt;&#x2F;a&gt; problems I encounter when architecting systems. Should I accept that the ASCII art might not look correct if a display is too thin and just treat the SSOT as text, or should the SSOT be the way the art looked to me, using a particular monospaced font on my display?&lt;&#x2F;p&gt;
&lt;p&gt;I gave this some thought, and decided that one of the aspects I love about ASCII art &lt;em&gt;is&lt;&#x2F;em&gt; that it is just text and can be easily copied and displayed anywhere text input is supported. However, for my homepage I really wanted to prevent the art from &quot;breaking&quot; as that could be confusing to visitors. Unfortunately, there is no way currently to scale text fonts dynamically to fit their container using just CSS, though hopefully this will change soon. I could have a number of pre-defined CSS media queries to change the font size or use JavaScript to dynamically recalculate the font size based on the window width, but neither of these options felt &quot;clean&quot; to me (and I want to avoid requiring JavaScript for my website). I tried using &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.w3.org&#x2F;TR&#x2F;SVG2&#x2F;text.html&quot;&gt;SVG text elements&lt;&#x2F;a&gt;, which did scale with the SVG (yay! &lt;code&gt;:)&lt;&#x2F;code&gt;), but required hardcoding vertical spacing between lines (boo &lt;code&gt;:(&lt;&#x2F;code&gt;). Because I had to manually set the pixel spacing between lines, I was concerned this might break the look of the art depending on which monospace font was used to render the text. My website does not include or require a specific font, and instead simply directs the browser to use the system monospace font.&lt;&#x2F;p&gt;
&lt;p&gt;Ultimately, I decided to sacrifice the extremely small size and convert the text to SVG paths and simply treat the artwork as an SVG. This ensures the artwork will look consistent regardless of rendering variables like screen width or font. The only downside was that users wouldn&#x27;t be able to copy the text to use it elsewhere. I mitigated this by sharing both the plaintext and SVG versions on my Art page. The best of both worlds! I still consider the plaintext version to be the &quot;real&quot; source of truth, but making both available is a nice convenience.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;final-thoughts&quot;&gt;Final thoughts&lt;&#x2F;h2&gt;
&lt;p&gt;I hope you enjoyed reading this! While maybe not the most riveting of posts, I found the question about what fundamentally defines an ASCII art piece (and digital art in general) interesting to mull over. I&#x27;m sure every artist has their own thoughts, and I believe the answer is unique to each individual. ASCII was definitely a fun style to work with and I encourage everyone to give it a try, even if it&#x27;s just making some fun emoticons &lt;code&gt;\o&#x2F;&lt;&#x2F;code&gt;!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Look at that view!</title>
        <published>2022-05-03T00:00:00+00:00</published>
        <updated>2022-05-03T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Sam McBroom
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://sammcb.com/blog/mountainscape-look-at-that-view/"/>
        <id>https://sammcb.com/blog/mountainscape-look-at-that-view/</id>
        
        <content type="html" xml:base="https://sammcb.com/blog/mountainscape-look-at-that-view/">&lt;h2 id=&quot;color-me-impressed&quot;&gt;Color me impressed&lt;&#x2F;h2&gt;
&lt;p&gt;After the last devlog, all I needed to do to finish up an initial version of the mountain scape generator was to tweak the generation parameters and add a coloring system. I looked at some vector art and loved the look of a bluish haze over the layers of mountains. I wanted to make a flexible system that would allow me to choose between using solid colors or gradients.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; mountains.js&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;if&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;gradient&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;	const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-js&quot;&gt; gradient&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;createLinearGradient&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; height&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;	gradient&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;addColorStop&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; colors&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;	gradient&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;addColorStop&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; colors&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;	context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-js&quot;&gt;fillStyle&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; gradient&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt; else&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;	context&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-property z-js&quot;&gt;fillStyle&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; colors&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After adding this, I spent a little time tweaking generation parameters and color values and ended up with some pretty nice views 🏔️!&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a class=&quot;resize-image-source&quot; href=&quot;&amp;#x2F;blog&amp;#x2F;mountainscape-look-at-that-view&amp;#x2F;mountainscape.png&quot;&gt;&lt;img alt=&quot;Final mountain scape&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; src=&quot;https:&amp;#x2F;&amp;#x2F;sammcb.com&amp;#x2F;processed_images&amp;#x2F;mountainscape.53ae14121a51b85c.webp&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Feel free to check out the &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Sammcb&#x2F;MountainScape&quot;&gt;code&lt;&#x2F;a&gt; or play around with the &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;sammcb.com&#x2F;MountainScape&quot;&gt;generator&lt;&#x2F;a&gt; and find your favorite mountain scape!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Rough around the edges</title>
        <published>2022-05-02T00:00:00+00:00</published>
        <updated>2022-05-02T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Sam McBroom
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://sammcb.com/blog/mountainscape-rough-around-the-edges/"/>
        <id>https://sammcb.com/blog/mountainscape-rough-around-the-edges/</id>
        
        <content type="html" xml:base="https://sammcb.com/blog/mountainscape-rough-around-the-edges/">&lt;h2 id=&quot;fractals-all-around&quot;&gt;Fractals all around&lt;&#x2F;h2&gt;
&lt;p&gt;Yes, that&#x27;s a Frozen reference ❄️. While reading about different kinds of noise, I learned about a couple different options I could implement to achieve landscape-like images. The first was to add multiple &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Octave_(electronics)&quot;&gt;octaves&lt;&#x2F;a&gt; of Perlin noise to achieve rougher textures, creating a form of &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Pink_noise&quot;&gt;fractal noise&lt;&#x2F;a&gt;. Other options were to use &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Value_noise&quot;&gt;value noise&lt;&#x2F;a&gt; or &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Simplex_noise&quot;&gt;Simplex noise&lt;&#x2F;a&gt; instead of Perlin noise. I chose to implement the fractal noise first to see what the results would look like.&lt;&#x2F;p&gt;
&lt;p&gt;So at this point you&#x27;re probably wondering &quot;What the heck does fractal noise mean? How to octaves play into that? Where are the pretty pictures??&quot;. Basically, for each octave, the frequency we pass into our &lt;code&gt;perlin()&lt;&#x2F;code&gt; function is doubled and the amplitude of the result is halved. Luckily this requires zero changes to our originial Perlin noise generator, and we just have to add a wrapper function to generate Perlin nose for each octave and sum across all the values.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; mountains.js&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; fractal&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;octaves&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; wavelength&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; gradients&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;	let&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; noise&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; perlin&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;wavelength&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;	for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;let&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; i&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; i&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; octaves&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; i&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;++&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;		const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-js&quot;&gt; factor&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; Math&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;pow&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; i&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;		const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-js&quot;&gt; octaveNoise&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; perlin&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;wavelength&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; factor&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;		noise&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; noise&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;map&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;height&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; index&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; height&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; octaveNoise&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;index&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; factor&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;	return&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; noise&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Because each octave results in larger gradient arrays and smaller amplitudes, the more octaves I use the rougher the terrain generated. I found that 8 octaves produced some nice rocky terrain.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;scaling-the-mountain&quot;&gt;Scaling the mountain&lt;&#x2F;h2&gt;
&lt;p&gt;The values this new &lt;code&gt;fractal()&lt;&#x2F;code&gt; returns an array of noise with generally very small values, which I think scale later for plotting on my graph.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; mountains.js&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; scaleY&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;y&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; scale&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; shift&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;	return&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;y&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; *&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; scale&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; shift&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;After getting the fractal noise working, I adjusted the &lt;code&gt;scale&lt;&#x2F;code&gt; and &lt;code&gt;shift&lt;&#x2F;code&gt; values so they are both relative to the height of the canvas. I also adjusted the way the values were calculated to depend on easily understandable changes.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; mountains.js&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-js&quot;&gt; flatnessFactor&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt; &#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Larger is flatter&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-js&quot;&gt; scale&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; height&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; flatnessFactor&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-js&quot;&gt; heightSum&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; heights&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;reduce&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;first&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; second&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; first&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; second&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; heights&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;length&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-js&quot;&gt; averageHeight&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;  heightSum&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; heights&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;length&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; *&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; scale&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-js&quot;&gt; heightFactor&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;5&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt; &#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Between 0 and 1, represents where the average height of the noise will be relative to the height&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-js&quot;&gt; shift&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;height&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; *&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; heightFactor&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; averageHeight&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;This system will make it easy for me to adjust the verticality and position of the mountains.&lt;&#x2F;p&gt;
&lt;p&gt;The result were actual mountain-y looking mountains 🏔️!&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a class=&quot;resize-image-source&quot; href=&quot;&amp;#x2F;blog&amp;#x2F;mountainscape-rough-around-the-edges&amp;#x2F;mountain.png&quot;&gt;&lt;img alt=&quot;Layered perlin noise mountain&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; src=&quot;https:&amp;#x2F;&amp;#x2F;sammcb.com&amp;#x2F;processed_images&amp;#x2F;mountain.f5328fa66e956a45.webp&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;blooper-reel&quot;&gt;Blooper reel&lt;&#x2F;h2&gt;
&lt;p&gt;While working on this new algorithm, I accidentally implemented it improperly (by generating a larger gradients array once and using that for all octaves) and produced some very fractal-y looking mountains.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a class=&quot;resize-image-source&quot; href=&quot;&amp;#x2F;blog&amp;#x2F;mountainscape-rough-around-the-edges&amp;#x2F;fractal.png&quot;&gt;&lt;img alt=&quot;Fractal mountain&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; src=&quot;https:&amp;#x2F;&amp;#x2F;sammcb.com&amp;#x2F;processed_images&amp;#x2F;fractal.7bd6c37026c89fd7.webp&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Honestly though, I was really happy with how the fractal noise turned out and wanted to try move forward with making some artworks before adding in the erosion system (who knows, maybe it won&#x27;t be necessary?).&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Steep learning slope</title>
        <published>2022-05-01T00:00:00+00:00</published>
        <updated>2022-05-01T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Sam McBroom
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://sammcb.com/blog/mountainscape-steep-learning-slope/"/>
        <id>https://sammcb.com/blog/mountainscape-steep-learning-slope/</id>
        
        <content type="html" xml:base="https://sammcb.com/blog/mountainscape-steep-learning-slope/">&lt;h2 id=&quot;prologue&quot;&gt;Prologue&lt;&#x2F;h2&gt;
&lt;p&gt;Ever since I wrote my &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Sammcb&#x2F;DoublePendulum&quot;&gt;Double Pendulum&lt;&#x2F;a&gt; project, I&#x27;ve loved generative art. One idea I worked on a year ago was to generatively build 2D mountain scape art. I originally thought I could create realistic mountains from random combinations of various sine and cosine functions. I implemented some basic functions for generating foreground, mid ground, and background mountain ranges, but the result always ended up looking too smooth. I attempted to fix this by connecting spaced-out points along the generated curves with straight lines instead of drawing the continuous curve. This helped a little, but I wouldn&#x27;t go so far as to say the mountains looked &quot;realistic&quot;. I also created a basic &quot;Sun&quot;, sky, and lake generator, which all ended up looking very basic and cartoony. Here is an example of one of the super-realistic landscapes generated by my script:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a class=&quot;resize-image-source&quot; href=&quot;&amp;#x2F;blog&amp;#x2F;mountainscape-steep-learning-slope&amp;#x2F;old.png&quot;&gt;&lt;img alt=&quot;Old mountain scape attempt&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; src=&quot;https:&amp;#x2F;&amp;#x2F;sammcb.com&amp;#x2F;processed_images&amp;#x2F;old.a3df4e779ec73a23.webp&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;This is where I left the project, since I figured I would need to try another approach and didn&#x27;t want to start from scratch.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;base-camp&quot;&gt;Base camp&lt;&#x2F;h2&gt;
&lt;p&gt;A year later, and I think I&#x27;m ready to tackle the challenge! Earlier this year, I watched some videos by &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;channel&#x2F;UCmtyQOKKmrMVaKuRXz02jbQ&quot;&gt;Sebastian Lague&lt;&#x2F;a&gt; (love his Coding Adventure series btw) and in one of them, he created some realistic planet terrain by simulating rainfall and erosion. I thought it would be really cool to apply these concepts in a 2D context as a basis for my new mountain scape generator.&lt;&#x2F;p&gt;
&lt;p&gt;I began by implementing a random number generator. In JavaScript, I like to use &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Linear_congruential_generator&quot;&gt;linear congruential generators&lt;&#x2F;a&gt; (LCGs) because they allow for seed values and are fairly simple to write. Their output is also sufficiently random for most purposes.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; mountains.js&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;let&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; seed&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Returns a random float in the range [0, 1]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; randomFloat&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;	const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-js&quot;&gt; m&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 4294967296&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;	const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-js&quot;&gt; a&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1664525&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;	const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-js&quot;&gt; c&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;	seed&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; *&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; seed&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; c&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; %&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; m&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;	return&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; seed&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; m&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For convenience, I also wrote a function for generating a random number in a range of values utilizing my LCG.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; mountains.js&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; Returns a random float in the range [min, max]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; randomFloatInRange&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;min&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; max&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;	return&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; randomFloat&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; *&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;max&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; min&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; min&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;beginning-the-climb&quot;&gt;Beginning the climb&lt;&#x2F;h2&gt;
&lt;p&gt;To start, I needed to build a decent height map generator upon which my &quot;rain 💧&quot; would fall and shape. I decided to use &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Perlin_noise&quot;&gt;Perlin noise&lt;&#x2F;a&gt;, which took me down a very mathematical rabbit hole. Perlin noise can be generated in any dimensional space, but I needed a 1D implementation for my height map. Following the algorithm detail, I broke my implementation into 3 steps:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;Generate the gradient vectors&lt;&#x2F;li&gt;
&lt;li&gt;Find the dot products for each candidate point&lt;&#x2F;li&gt;
&lt;li&gt;Interpolate using those dot product values to find the height for a given candidate point on the x-axis&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;First, I needed to create an &lt;em&gt;n&lt;&#x2F;em&gt;-dimensional grid. In my 1D space, this mean effectively choosing spacing for tick marks along a line. This spacing, or &lt;code&gt;wavelength&lt;&#x2F;code&gt;, determines the frequency of potential peaks produced by the noise. In the 1D space, the process for generating the gradient vectors just requires choosing a random number in the range &lt;strong&gt;[-1, 1]&lt;&#x2F;strong&gt; for each tick mark.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; mountains.js&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; generateGradients&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;wavelength&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;	let&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; gradients&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;	for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;let&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; x&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; x&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; width&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; wavelength&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; x&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +=&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; wavelength&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;		gradients&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;push&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;randomFloatInRange&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;	return&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; gradients&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;onwards-and-upwards&quot;&gt;Onwards and upwards&lt;&#x2F;h2&gt;
&lt;p&gt;To find the dot products for a given candidate point (which in my 1D case is just a random &lt;code&gt;x&lt;&#x2F;code&gt; coordinate), I first, needed to find the &quot;cell&quot; that contains my candidate point. For my implementation, this meant finding which step contained my candidate point. Finding the cell then allowed me to easily fetch the two generated gradient values on the edges (or &quot;corners&quot; as I called them to stay consistent with the algorithm description) of the cell.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; mountains.js&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; getCornerGradients&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;x&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; wavelength&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; gradients&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;	const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-js&quot;&gt; cell&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; Math&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;floor&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;x&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; wavelength&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;	return&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;gradients&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;cell&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; gradients&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;cell&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Then to get the offset vectors, I just need to find the vector from my candidate point to the corners of the cell. The only thing I changed was normalizing &lt;code&gt;x&lt;&#x2F;code&gt; so it was in the range &lt;strong&gt;[0, 1]&lt;&#x2F;strong&gt;, which makes some later parts of the algorithm easier to compute.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; mountains.js&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; getOffsetVectors&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;x&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; wavelength&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;	const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-js&quot;&gt; normalizedX&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;x&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; %&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; wavelength&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; wavelength&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;	return&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;normalizedX&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; normalizedX&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Finally I was able to compute the dot products of the gradients and the offset vectors.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; mountains.js&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; getDotProducts&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;x&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; wavelength&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; gradients&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;	const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-js&quot;&gt; cornerGradients&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; getCornerGradients&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;x&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; wavelength&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; gradients&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;	const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-js&quot;&gt; offsetVectors&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; getOffsetVectors&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;x&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; wavelength&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;	return&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;cornerGradients&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; *&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; offsetVectors&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; cornerGradients&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; *&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; offsetVectors&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;reaching-the-summit&quot;&gt;Reaching the summit&lt;&#x2F;h2&gt;
&lt;p&gt;For the third and final step, I just needed to write a function to interpolate between the two dot products I computed above. I followed the algorithm on the Wikipedia page and used the &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Smoothstep&quot;&gt;smoothstep function&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; mountains.js&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; interpolate&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;x&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; wavelength&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt; dotProducts&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;	const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-js&quot;&gt; normalizedX&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;x&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; %&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; wavelength&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; wavelength&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;	return&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; dotProducts&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; smoothstep&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;normalizedX&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; *&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;dotProducts&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; -&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; dotProducts&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;]&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Putting it all together, I was able to calculate 1D Perlin noise!&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;&#x2F;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; mountains.js&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; perlin&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-parameter&quot;&gt;wavelength&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;	const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-js&quot;&gt; gradients&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; generateGradients&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;wavelength&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;	let&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; noise&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; [&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;]&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;	for&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; (&lt;&#x2F;span&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;let&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; x&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; x&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; &amp;lt;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; width&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;;&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; x&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;++&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;		const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-js&quot;&gt; cornerGradients&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; getCornerGradients&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;x&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; wavelength&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; gradients&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;		const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-js&quot;&gt; dotProducts&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; getDotProducts&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;x&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; wavelength&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; gradients&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-storage z-type&quot;&gt;		const&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-constant z-js&quot;&gt; interpolated&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; interpolate&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;x&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; wavelength&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;,&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; dotProducts&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;		noise&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-accessor&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;push&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt;interpolated&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;	}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;	return&lt;&#x2F;span&gt;&lt;span class=&quot;z-variable z-other z-readwrite&quot;&gt; noise&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To finish up with this initial step, I wrote a function to draw a line, where the y values would be determined using the generated Perlin noise and I got a decent-looking output!&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a class=&quot;resize-image-source&quot; href=&quot;&amp;#x2F;blog&amp;#x2F;mountainscape-steep-learning-slope&amp;#x2F;perlin.png&quot;&gt;&lt;img alt=&quot;Basic perlin noise image&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; src=&quot;https:&amp;#x2F;&amp;#x2F;sammcb.com&amp;#x2F;processed_images&amp;#x2F;perlin.9fd395e3009e7372.webp&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Whew, that was a lot of math! I promise the next devlog in the series will be better in every way: less math and more pretty pictures 😄.&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Happy anniversary, LÖVE Sam</title>
        <published>2021-03-25T00:00:00+00:00</published>
        <updated>2021-03-25T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Sam McBroom
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://sammcb.com/blog/anniversary-happy-anniversary-love-sam/"/>
        <id>https://sammcb.com/blog/anniversary-happy-anniversary-love-sam/</id>
        
        <content type="html" xml:base="https://sammcb.com/blog/anniversary-happy-anniversary-love-sam/">&lt;h2 id=&quot;endgame&quot;&gt;Endgame&lt;&#x2F;h2&gt;
&lt;p&gt;On the day of our anniversary, I tried to quickly wrap up the project in the morning.&lt;&#x2F;p&gt;
&lt;p&gt;First, I wanted to animate a fadeout for the game while having the ending cutscene text remain on screen. I tried setting the graphics draw color to black with a gradually increasing alpha value, then drawing a window-sized rectangle over the screen. I drew the rectangle after the game objects but before the text, to keep the text above the fade.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lua&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;--&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; main.lua&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; love&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;draw&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;	love&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;graphics&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;setColor&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;alpha&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;	love&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;graphics&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;rectangle&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;fill&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;love&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;graphics&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;getWidth&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(), &lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;love&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;graphics&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;getHeight&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;However, this approach was giving me a lot of visual issues.&lt;&#x2F;p&gt;
&lt;p&gt;I took a break and went for a walk and thought over some of the possible causes for the visual bugs. I realized it might be because I wasn&#x27;t resetting the draw color after rendering the rectangle. After getting back from my walk, I updated my code and the fadeout worked perfectly!&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lua&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;--&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; main.lua&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; love&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;draw&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;	local&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; r&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;g&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;b&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; love&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;graphics&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;getColor&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;	love&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;graphics&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;setColor&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;alpha&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;	love&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;graphics&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;rectangle&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;fill&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;love&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;graphics&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;getWidth&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(), &lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;love&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;graphics&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;getHeight&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;	love&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;graphics&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;setColor&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;r&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;g&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;b&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;a&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;With the fadeout and camera transformations, I felt the game had a pretty smooth looking end cutscene.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;music&quot;&gt;Music&lt;&#x2F;h2&gt;
&lt;p&gt;For the final part of the project, I wanted to add a couple background music tracks. Luckily for me, I had exactly 0 experience making music. I wanted the music to fit the retro feel of the game, and found this great website called &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.beepbox.co&#x2F;&quot;&gt;BeepBox&lt;&#x2F;a&gt;. First, I made a short background track, which I was pretty happy with given how quick I was able to create it. I exported the &lt;code&gt;.wav&lt;&#x2F;code&gt; file and loaded it into LÖVE. I also configured the music to loop once played.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lua&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;--&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; main.lua&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;local&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; music&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; love&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;audio&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;newSource&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;ambient.wav&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;stream&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; love&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;load&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-class&quot;&gt;	music&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;setLooping&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language&quot;&gt;true&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-class&quot;&gt;	music&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;play&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;For some reason, the looping appeared to have no effect. I looked around but couldn&#x27;t find any issues with the &lt;code&gt;setLoop()&lt;&#x2F;code&gt; function. I tried exporting the music to other file formates, but nothing seemed to work. Then, when exporting the music, I saw that there was a default option checked in BeepBox called &quot;outro&quot;. After unchecking this box, and reloading the music file, the looping finally worked as expected.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;final-touches&quot;&gt;Final touches&lt;&#x2F;h2&gt;
&lt;p&gt;With the gameplay mechanics, ending cutscene, and music done, I was almost done with the project. I felt the plain green background color needed improving, and I wanted to replace it with randomly generated grass tiles. Luckily, this was pretty easy to accomplish. I just copied the random grass terrain generation logic from my &lt;code&gt;world&lt;&#x2F;code&gt; object and set the program to fill an area slightly larger than the player&#x27;s viewport with the randomly generated grass. I also tweaked the grass generation so plain grass tiles were chosen more frequently than flowering grass tiles.&lt;&#x2F;p&gt;
&lt;p&gt;I had a little extra time before I wanted to present the game to my partner, so I decided to quickly extend my tile system and create some animated water tiles. I followed the same process for implementing a new tile type, but every second I had the &lt;code&gt;draw()&lt;&#x2F;code&gt; function switch which water tile was rendered in the water pools.&lt;&#x2F;p&gt;
&lt;p&gt;I also chose an retro, arcade-style font, but chose not to include that in the version on GitHub since I&#x27;m not quite sure about the licensing (one day I would love to learn enough to make my own font).&lt;&#x2F;p&gt;
&lt;p&gt;Finally, I wrapped up the project by designing a few more grass and wall tile variations. I was very happy with the final product and was excited to present it to my partner!&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a class=&quot;resize-image-source&quot; href=&quot;&amp;#x2F;blog&amp;#x2F;anniversary-happy-anniversary-love-sam&amp;#x2F;anniversary.png&quot;&gt;&lt;img alt=&quot;Final game cutscene&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; src=&quot;https:&amp;#x2F;&amp;#x2F;sammcb.com&amp;#x2F;processed_images&amp;#x2F;anniversary.14102501ab85d797.webp&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Apart from thinking she was walking through a small intestine, being confused by the heart-blob character, and generally not being a fan of pixel art graphics, she loved it!&lt;&#x2F;p&gt;
&lt;h2 id=&quot;closing-thoughts&quot;&gt;Closing thoughts&lt;&#x2F;h2&gt;
&lt;p&gt;Overall, I really liked working with LÖVE. I was impressed with how quickly I was able to create a working (albeit very simple) game. While I really enjoyed using it for this project, Lua&#x27;s lack of objects makes me unsure if the engine would work well with larger-scale games. Additionally, the lack of sprite z-positioning adds extra complexity to the draw function, and the absence of a built in camera object surprised me.&lt;&#x2F;p&gt;
&lt;p&gt;That being said, the engine was definitely easier to learn compared to a more full-featured engine like Unity. There was a lot of convenient default functionality provided, such as being able to play looping music or load in and draw a sprite in just a few lines. I definitely hope to experiment more with LÖVE and felt it was an execellent engine choice for this project.&lt;&#x2F;p&gt;
&lt;p&gt;I hope you enjoyed this devlog series. I&#x27;ll definitely write more in the future on projects to come! If you want to look more closely at the code or run&#x2F;build off of Anniversary yourself, make sure to check out the &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;Sammcb&#x2F;Anniversary&quot;&gt;repository&lt;&#x2F;a&gt;!&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Game day</title>
        <published>2021-03-24T00:00:00+00:00</published>
        <updated>2021-03-24T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Sam McBroom
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://sammcb.com/blog/anniversary-game-day/"/>
        <id>https://sammcb.com/blog/anniversary-game-day/</id>
        
        <content type="html" xml:base="https://sammcb.com/blog/anniversary-game-day/">&lt;h2 id=&quot;a-maze-ing-design&quot;&gt;A-maze-ing design&lt;&#x2F;h2&gt;
&lt;p&gt;Last night, I thought more about the design of the game. I began this project with some vague ideas, but no concrete game mechanics or story. After working on the tileset yesterday, I realized doing the artwork for the game was the most time-consuming task, and with only a couple days left to finish the game I would have to end up with a super simple product. I was inspired to try and make a maze that the player would wander through to find their missing half. I also decided, in the spirit of our anniversary, to change the character design so the player was half a heart and their goal was to search for their other half:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a class=&quot;resize-image-source&quot; href=&quot;&amp;#x2F;blog&amp;#x2F;anniversary-game-day&amp;#x2F;player.png&quot;&gt;&lt;img alt=&quot;Player character&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; src=&quot;https:&amp;#x2F;&amp;#x2F;sammcb.com&amp;#x2F;processed_images&amp;#x2F;player.8daf1309dff6a3e7.webp&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;(My partner thought it looked like a blob.)&lt;&#x2F;p&gt;
&lt;p&gt;I couldn&#x27;t help making the game a little cheesey, and decided that the plot and level design should be used to tie into the ending cutscene. To help speed up gameplay and development (and allow for alliteration in the ending cuscene), I chose to make a labyrinth rather than a maze, so there was only one path the player could follow. This helped me too, since I wouldn&#x27;t need to design branching paths and dead ends, or balance the complexity of the maze. This was the design I ended up creating:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a class=&quot;resize-image-source&quot; href=&quot;&amp;#x2F;blog&amp;#x2F;anniversary-game-day&amp;#x2F;labyrinth.png&quot;&gt;&lt;img alt=&quot;World map&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; src=&quot;https:&amp;#x2F;&amp;#x2F;sammcb.com&amp;#x2F;processed_images&amp;#x2F;labyrinth.a8d1c59ec2f96e13.webp&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;level-editor&quot;&gt;Level editor&lt;&#x2F;h2&gt;
&lt;p&gt;Originially, the image of the labyrinth I designed was just meant to help me quickly picture the game world. However, after looking at the scale of the labyrinth (each pixel represented a tile from my spritesheet), I realized it would be nearly impossible to build the level in code with my deadline (not to mention the difficulty of changing the design later). With my knowledge of &lt;code&gt;Quads&lt;&#x2F;code&gt;, I decided to design the &lt;code&gt;world&lt;&#x2F;code&gt; object to automatically generate the game world given an input image.&lt;&#x2F;p&gt;
&lt;p&gt;I wrote a function that would check each pixel of the input image, compare it to a list of colors I defined in code, and assign a tile based on the color of the pixel.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lua&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;--&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; world.lua&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;local&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; r&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;g&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;b&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-class&quot;&gt; input_image&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;getPixel&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;x&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;y&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;if&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt; colors_equal&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;r&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;g&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;b&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;grass_rgb&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;) &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword&quot;&gt;then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;	tiles&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;[&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;x&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;][&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;y&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;] &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;=&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; love&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;graphics&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;newQuad&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;8&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;8&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-class&quot;&gt;terrain&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;getDimensions&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I also extended this system so the world automatically chose a random grass or wall tile to give the game world a more natural feel. I had to make a 2D table of &lt;code&gt;Quads&lt;&#x2F;code&gt;&#x2F;tiles in &lt;code&gt;love.load()&lt;&#x2F;code&gt; to use since choosing a random &lt;code&gt;Quad&lt;&#x2F;code&gt; in &lt;code&gt;love.draw()&lt;&#x2F;code&gt; caused the world tiles to change every frame.&lt;&#x2F;p&gt;
&lt;p&gt;While this took a lot of code to get working, it allowed me to effectively use Aesprite as a level editor, which really helped me finalize the design of the labyrinth after playtesting the game.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;lights-camera-action&quot;&gt;Lights, camera, action&lt;&#x2F;h2&gt;
&lt;p&gt;With level generation working, to explore the generated labyrinth in-game, I needed to implement a basic camera. LÖVE doesn&#x27;t have a built-in camera, so I followed a set of &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;ebens.me&#x2F;post&#x2F;cameras-in-love2d-part-1-the-basics&quot;&gt;camera tutorials&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;While working on the camera, I discovered a bug with my terrain generation code. After figuring out how to zoom out the camera, I saw that the last column and row of my terrain image was not generating. After a little debugging, I learned that tables in Lua start indexing at 1 rather than 0 (🤢), resulting in off-by-one errors scattered throughout my level generation code. Luckily, these weren&#x27;t too difficult to fix.&lt;&#x2F;p&gt;
&lt;p&gt;After fixing those errors and some trial and error with the camera, I figured out how to translate and scale the camera using graphics transformations, and programmed it to center on and follow the player as they move around the world. To center the camera on the player, I used the following code:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lua&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;--&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; camera.lua&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;love&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;graphics&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;translate&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;camera&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;position&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;x&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; love&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;graphics&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;getWidth&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;() &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; *&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; camera&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;scale&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;x&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;-&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;camera&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;position&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;y&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; +&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; love&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;graphics&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;getHeight&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;() &lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt;&#x2F;&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 2&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; *&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; camera&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;scale&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;y&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;not-smooth-moves&quot;&gt;(Not) smooth moves&lt;&#x2F;h2&gt;
&lt;p&gt;My next task was to tackle the movement mechanics. I wanted the player to stay on the tile grid rather than having smooth movement. Choosing this approach both helped setup the ending scene and drastically reduced the remaining work on the project. I wouldn&#x27;t need to learn collision, and could instead limit the player&#x27;s movements based on what tile they were trying to move to.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;cutscene&quot;&gt;Cutscene&lt;&#x2F;h2&gt;
&lt;p&gt;With the terrain generation, camera, and movement working, I was nearing the end of the gameplay section of the project. To finish of the day&#x27;s work, I started coding the ending cutscene.&lt;&#x2F;p&gt;
&lt;p&gt;First, I set the window&#x27;s background color to match my plain grass color as a quick and dirty way to extend the world around the player.&lt;&#x2F;p&gt;
&lt;p&gt;Sadly, with very little time left to work on the project, my ending cutscene code was not as modular as I would have liked (spaghetti, anyone?). I added some code to the &lt;code&gt;love.update(dt)&lt;&#x2F;code&gt; to stop player control and begin applying transforms on the camera when they reach their missing half. Then I created some simple text objects to display (with time delays between them).&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lua&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;--&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; main.lua&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;local&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; font&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; love&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;graphics&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;getFont&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;local&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; cutscene_text&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; love&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;graphics&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;newText&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;font&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Happy anniversary&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Finally, I ended the day by animating the two heart halves leaving the labyrinth together.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a class=&quot;resize-image-source&quot; href=&quot;&amp;#x2F;blog&amp;#x2F;anniversary-game-day&amp;#x2F;heart.png&quot;&gt;&lt;img alt=&quot;Full heart character&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; src=&quot;https:&amp;#x2F;&amp;#x2F;sammcb.com&amp;#x2F;processed_images&amp;#x2F;heart.23951002be0e8b05.webp&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Learning to LÖVE</title>
        <published>2021-03-23T00:00:00+00:00</published>
        <updated>2021-03-23T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Sam McBroom
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://sammcb.com/blog/anniversary-learning-to-love/"/>
        <id>https://sammcb.com/blog/anniversary-learning-to-love/</id>
        
        <content type="html" xml:base="https://sammcb.com/blog/anniversary-learning-to-love/">&lt;h2 id=&quot;background&quot;&gt;Background&lt;&#x2F;h2&gt;
&lt;p&gt;With my partner and I&#x27;s one year anniversary coming up soon, I thought it would be a fun opportunity to make a short game for her. I love pixel art (unlike my &lt;strong&gt;objectively&lt;&#x2F;strong&gt; wrong partner), and while I&#x27;m not very good at making it, I thought designing a tileset for the game could be great practice. Next, I had to decide what engine to use to make the game. I had some experience with Unity, but a few weeks ago, I learned about the &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;love2d.org&quot;&gt;LÖVE&lt;&#x2F;a&gt; game engine.&lt;&#x2F;p&gt;
&lt;p&gt;LÖVE is a framework for making 2D games in Lua. With only a few days ahead of me to make the project, I was worried about finishing it in time. While I already knew how to use Unity, it seemed like a lot of overhead and extra setup for such a small project. LÖVE, on the other hand, appeared quick to prototype with, and being dedicated to 2D game development seemed much more convenient to use.&lt;&#x2F;p&gt;
&lt;p&gt;I had to consider the benefits of using a familiar engine that I knew would take a decent amount of work vs. learning a new game engine which might eventually allow for quicker development. I decided to dive into LÖVE, and chose to name my game &lt;em&gt;Anniversary&lt;&#x2F;em&gt;. I figured a small project like Anniversary would be a great opportunity to dip my toe into the waters of LÖVE and try out the engine without committing to a larger-scale project.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;0th-step&quot;&gt;0th step&lt;&#x2F;h2&gt;
&lt;p&gt;When working on coding projects, I like to create Docker containers to help manage different system install requirements, enhance the portability of my code, and reduce system debugging issues. Unfortunately, I have not yet figured out how to connect a Docker container application to my host computer&#x27;s graphical display (definitely something I want to explore in the future). For this reason, I decided not to make a container for this project.&lt;&#x2F;p&gt;
&lt;p&gt;Another part of my workflow is to create a &lt;code&gt;do.sh&lt;&#x2F;code&gt; script containing a bunch of important commands and build flows so I don&#x27;t have to remember or look up common actions.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;hello-world&quot;&gt;Hello, world&lt;&#x2F;h2&gt;
&lt;p&gt;The first step of my journey was to get LÖVE installed and working. I followed the &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;love2d.org&#x2F;wiki&#x2F;Getting_Started&quot;&gt;&quot;Getting Started&quot; guide&lt;&#x2F;a&gt; and created a &lt;code&gt;main.lua&lt;&#x2F;code&gt; file.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lua&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;--&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; main.lua&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; love&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;draw&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;	love&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;graphics&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;print&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;Hello, world!&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;400&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;300&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I then ran my game by typing &lt;code&gt;open -n -a love .&lt;&#x2F;code&gt; and was excited to see my super-exciting-definitely-original-game up and running in just a few minutes:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a class=&quot;resize-image-source&quot; href=&quot;&amp;#x2F;blog&amp;#x2F;anniversary-learning-to-love&amp;#x2F;helloWorld.png&quot;&gt;&lt;img alt=&quot;Hello world text&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; src=&quot;https:&amp;#x2F;&amp;#x2F;sammcb.com&amp;#x2F;processed_images&amp;#x2F;helloWorld.fc4472eaa52bedd0.webp&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;smart-debugging-print&quot;&gt;Smart debugging: &lt;code&gt;print()&lt;&#x2F;code&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Being new to LÖVE, and completely underestimating my familiarity with Lua (I had used it a bit when messing with the &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;http:&#x2F;&#x2F;www.computercraft.info&quot;&gt;ComputerCraft&lt;&#x2F;a&gt; Minecraft mod many years ago), I decided it would be important to figure out how to print debugging information to the console.&lt;&#x2F;p&gt;
&lt;p&gt;This took a bit of trial and error, but eventually I figured out that I had to launch my game using the direct path to the &lt;code&gt;love.app&lt;&#x2F;code&gt; application instead of using the macOS &lt;code&gt;open&lt;&#x2F;code&gt; command. During the process, however, I learned more about how to build a &lt;code&gt;.love&lt;&#x2F;code&gt; file and package an executable. I updated my &lt;code&gt;do.sh&lt;&#x2F;code&gt; script with these build paths, as they might be useful in the future.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;basic-player&quot;&gt;Basic player&lt;&#x2F;h2&gt;
&lt;p&gt;The next step was to create a player sprite and figure out how to move them around the game window. For pixel art, I recently purchased &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;www.aseprite.org&quot;&gt;Aesprite&lt;&#x2F;a&gt;, which is a wonderful drawing application dedicated to pixel art. While $20 seemed like a small price to pay to kickstart &lt;em&gt;very professional pixel artist career&lt;&#x2F;em&gt;, they also have a &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;aseprite&#x2F;aseprite&#x2F;&quot;&gt;GitHub page&lt;&#x2F;a&gt; with instructions on how to compile the application yourself for free.&lt;&#x2F;p&gt;
&lt;p&gt;Still being new to pixel art and under a time crunch (who knows what would happen if I didn&#x27;t finish the game in time for our anniversary 😱), I decided to go with 8x8 pixel tiles for the player and tileset. These would allow me to quickly make (hopefully) passable art for the game. At this point, I had very little idea of what the game would be. Originially, I was going to make the player a simple 8x8 dot, but this design reminded me of a game I played a few months back called &lt;a rel=&quot;noopener nofollow noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;store.steampowered.com&#x2F;app&#x2F;1179620&#x2F;Journey_of_the_Broken_Circle&#x2F;&quot;&gt;Journey of the Broken Circle&lt;&#x2F;a&gt;. I love the cartoonish-yet-romanic idea of a shape looking for its other piece.&lt;&#x2F;p&gt;
&lt;p&gt;Thus, I decided to make the player half a circle and have them search for their other half. I blocked out a simple player character:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a class=&quot;resize-image-source&quot; href=&quot;&amp;#x2F;blog&amp;#x2F;anniversary-learning-to-love&amp;#x2F;player_block.png&quot;&gt;&lt;img alt=&quot;Player character&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; src=&quot;https:&amp;#x2F;&amp;#x2F;sammcb.com&amp;#x2F;processed_images&amp;#x2F;player_block.5a8788573cd155a2.webp&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Using the following code, I was able to get the sprite to draw on screen (though there was no scaling so it was very tiny):&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lua&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;--&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; player.lua&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;local&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; sprite&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language&quot;&gt; nil&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; love&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;load&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;	sprite&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; love&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;graphics&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;newImage&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;player.png&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; love&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;draw&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;	love&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;graphics&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;draw&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;sprite&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;400&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;300&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Since I was working with very low-resolution pixel art, I needed to figure out how to scale up the sprites in LÖVE without generating blurring artifacts. I learned (after more confusion than I would like to admit about &lt;code&gt;object:method()&lt;&#x2F;code&gt; syntax in Lua replacing &lt;code&gt;object.method()&lt;&#x2F;code&gt; on other C-based languages, and enums in Lua, unlike in Swift or Python, being just strings), that I could set a filter on the image&#x27;s &lt;code&gt;Texture&lt;&#x2F;code&gt; object to adjust how it was scaled up and down.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lua&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;--&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; player.lua&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; love&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;load&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;	sprite&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; love&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;graphics&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;newImage&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;player.png&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-entity z-name z-class&quot;&gt;	sprite&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;setFilter&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;nearest&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;nearest&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;To actually scale up the sprite, I had to set the scale values when calling the draw function:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lua&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;--&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; player.lua&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;local&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; scale&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt; 5&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; love&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;draw&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;	love&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;graphics&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;draw&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;sprite&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;400&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;300&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;scale&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;scale&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;classic-lua&quot;&gt;Classic Lua&lt;&#x2F;h2&gt;
&lt;p&gt;When working with Unity, I primarily relied on classes and inheritance to contruct objects. I was surprised to learn that Lua, being a very lightweight scripting language, does not include native support for classes (or a bunch of other common data structures like arrays or hash tables). Lua&#x27;s approach is to provide a &lt;code&gt;table&lt;&#x2F;code&gt; data structure, which can then be used as an array, dictionary, set, and many other common data structures depending on how the programmer uses it. Thus, I was forced to rethink my traditional design pattern.&lt;&#x2F;p&gt;
&lt;p&gt;It took me awhile to figure out a design pattern I was happy with (and I&#x27;m still not sure if I&#x27;m completely happy with it, but it was fine for this small project). I chose to follow a factory design pattern, and created a &lt;code&gt;player_factory&lt;&#x2F;code&gt; module with a single function called &lt;code&gt;newPlayer()&lt;&#x2F;code&gt;. This function initialized a &lt;code&gt;player&lt;&#x2F;code&gt; table object, and assigned it instance methods. I then followed the same approach for creating a &lt;code&gt;player_controller&lt;&#x2F;code&gt; object to connect user inputs to player actions.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;basic-terrain&quot;&gt;Basic terrain&lt;&#x2F;h2&gt;
&lt;p&gt;I decided to wrap up progress for the day by designing a simple tileset and hopefully getting some tiles drawn to the screen. This is the tileset I whipped up:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a class=&quot;resize-image-source&quot; href=&quot;&amp;#x2F;blog&amp;#x2F;anniversary-learning-to-love&amp;#x2F;terrain.png&quot;&gt;&lt;img alt=&quot;Tileset&quot; decoding=&quot;async&quot; loading=&quot;lazy&quot; src=&quot;https:&amp;#x2F;&amp;#x2F;sammcb.com&amp;#x2F;processed_images&amp;#x2F;terrain.11cc7b7958fae134.webp&quot;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;I wrote out a &lt;code&gt;world_factory&lt;&#x2F;code&gt; module to generate the &lt;code&gt;world&lt;&#x2F;code&gt; object and began figuring out how to divide my spritesheet into individual tile images in LÖVE. I figured out the tool I needed was a &lt;code&gt;Quad&lt;&#x2F;code&gt;. I was then able to draw the selected portion of the spritesheet to the screen using a &lt;code&gt;draw()&lt;&#x2F;code&gt; call.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo z-code&quot;&gt;&lt;code data-lang=&quot;lua&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-punctuation z-definition z-comment&quot;&gt;--&lt;&#x2F;span&gt;&lt;span class=&quot;z-comment&quot;&gt; world.lua&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;local&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; terrain&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language&quot;&gt; nil&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;local&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; tile&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-language&quot;&gt; nil&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; love&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;load&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;	terrain&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; love&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;graphics&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;newImage&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-string&quot;&gt;terrain.png&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation z-definition z-string&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;	tile&lt;&#x2F;span&gt;&lt;span class=&quot;z-keyword z-operator&quot;&gt; =&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt; love&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;graphics&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;newQuad&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;0&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;8&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;8&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-class&quot;&gt;terrain&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;:&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;getDimensions&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;function&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt; love&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-entity z-name z-function&quot;&gt;draw&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-punctuation&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-source&quot;&gt;	love&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;graphics&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;.&lt;&#x2F;span&gt;&lt;span class=&quot;z-support z-function&quot;&gt;draw&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;(&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;terrain&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;tile&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;400&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;, &lt;&#x2F;span&gt;&lt;span class=&quot;z-constant z-numeric&quot;&gt;300&lt;&#x2F;span&gt;&lt;span class=&quot;z-source&quot;&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-keyword&quot;&gt;end&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;I was happy to see that the terrain was drawn to the screen, but I ran into an issue where the terrain was drawn over the player. It turns out LÖVE does not support sprite z positions, so I need to make sure I carefully manage the draw order by drawing the player after drawing the world.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;wrap-up&quot;&gt;Wrap up&lt;&#x2F;h2&gt;
&lt;p&gt;With that, I had some new knowledge of Lua and LÖVE, the ability to control a player and render tiles from a spritesheet, and was excited to continue working on my game another day!&lt;&#x2F;p&gt;
</content>
        
    </entry>
</feed>
