<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Jake Varness Blog</title><description>Welcome to my blog, where I routinely post about topics related to software development, coding, career development, and more!</description><link>https://jvarness.blog/</link><item><title>Can Local LLMs Replace Subscriptions?</title><link>https://jvarness.blog/local-llms-and-you/</link><guid isPermaLink="true">https://jvarness.blog/local-llms-and-you/</guid><description>Depends on how critical your mission is</description><pubDate>Sat, 10 Oct 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Happy Spoopy Season all!&lt;/p&gt;
&lt;p&gt;For about a year or so, I had been subscribed to the $20/month plan for either OpenAI or
Anthropic, depending on the month. There were so many cool things I was able to do with
those subscriptions, like building mobile apps with little to no experience with mobile
development, learning new skills rapidly, and playing around with Deep Research to see
if an idea I had was worth pursuing, or if others have tried and failed at ideas that
were similar.&lt;/p&gt;
&lt;p&gt;And don’t get me wrong: OpenAI and Anthropic models are very good: Sonnet is typically
my go-to model for most software engineering tasks, and OpenAI’s models have been really
great at generating photos and helping me with other non-engineering related work like
creating reports for me using MCP servers.&lt;/p&gt;
&lt;p&gt;OpenAI and Anthropic aren’t the only players in the LLM game though: there is a
menagerie of open-weight models in the market that, with the right local hardware,
could easily replace the proprietary models I’m used to using. When looking at
benchmarks that compare some of those models, like Qwen 3.8 or Muse Glimmer, to the
proprietary frontier models, it’s quite impressive what some of those models are able
to achieve.&lt;/p&gt;
&lt;p&gt;Do they stack up to Opus, Sol, Fable, or Astra levels in terms of quality or accuracy?
Probably not, but have I ever been able to use any of those models for a long enough
time to actually make anything? Not on a $20/month subscription, no. $20/month would
normally get me a solid hour of using Opus, at max, and then I’d have to wait until
my limits got reset to continue. So me personally, I’ve pretty much gotten used to
using the likes of Sonnet and Terra for most things.&lt;/p&gt;
&lt;p&gt;By the way, if your job gives you some kind of AI tooling, do you know how much
your usage is costing your organization? When I was working at Storable, I remember
we were using Anthropic models via AWS Bedrock as opposed to subscriptions. However,
in the instructions for the setup, they had originally recommended setting your
default up to be &lt;em&gt;Opus&lt;/em&gt;… Needless to say, we had to roll that &lt;em&gt;waaaaay&lt;/em&gt; back.&lt;/p&gt;
&lt;p&gt;Food for thought in case you really think you need Opus or Fable for everything. I’m
here to tell you that you don’t.&lt;/p&gt;
&lt;p&gt;Anyway, enough about subscriptions, let’s talk about local AI once again on this blog.&lt;/p&gt;
&lt;h2 id=&quot;making-local-ai-possible&quot;&gt;Making Local AI Possible&lt;/h2&gt;
&lt;p&gt;So if you’re a habitual reader of my blog, first of all thanks 😁😁😁, and you might
remember how in &lt;a href=&quot;https://jvarness.blog/my-primer-with-hermes/&quot;&gt;My Primer with Hermes&lt;/a&gt;
and in previous blog posts, I’ve been using so many different tools, and trying out a
lot of different models. I’ve also spoken about how running local models has, in recent
months/years, been difficult to achieve. And not only have I talked on this blog about
that, but I also have talked to my wife a lot about different computers that I thought
would be cool, and different deals that were around there…&lt;/p&gt;
&lt;p&gt;Well, when I told her about a deal for the Asus ROG Z13 Flow that Best Buy had, I think
she finally got tired of me talking her ear off about computers and LLMs and stuff and
she pulled the trigger.&lt;/p&gt;
&lt;p&gt;Bless her heart 🥲&lt;/p&gt;
&lt;p&gt;But anyways, I am now the proud owner of a Z13 Flow with an AMD Ryzen AI Max+ 395 chip,
and 64 GB of unified memory, and let me tell you something: as nice as this device is,
that is literally &lt;em&gt;the worst&lt;/em&gt; name you could come up with for any modern CPU.&lt;/p&gt;
&lt;p&gt;Poorly named wafers aside, let’s discuss why this model in particular. Apart from the
pricing being fantastic when this device was purchased, 64 GB of unified memory has
turned out to be a really great sweet spot for running LLMs locally. This device is
also perfect because of it’s portability: a desktop PC would have me tied to a desk
whenever I wanted to use it.&lt;/p&gt;
&lt;p&gt;But why this one and not a 128 GB model? Because they do have those, and that’s what
every mini PC marketed for running local models has in it nowadays &lt;em&gt;minimum&lt;/em&gt;. Honestly,
I feel pretty comfortable in saying that 64 GB in 2026 is the perfect balance of price and
performance: for what I’m experimenting with locally, 32 GB would not have nearly been
enough, and I’ll show some numbers to back that up here in a bit. 128 GB would have been
great, and I might have been able to run more powerful models, but there are really
great local models available in the ~30B parameter range that I think a lot of people
would be more than happy with using. 64 GB gives me enough space to run what I want
at a price point that doesn’t cause my back to spasm.&lt;/p&gt;
&lt;p&gt;While this might not be the most repairable device, like I’ve spoken about previously,
this is an unfortunate reality of computer hardware and Generative AI use-cases in 2026:
&lt;strong&gt;No VRAM? No local LLMs&lt;/strong&gt;. Unless you’re planning on running your models in system RAM,
you’re going to have a very poor user experience. It makes your definition of &lt;em&gt;possible&lt;/em&gt;
look really bleak compared to what that $20/month can typically get you.&lt;/p&gt;
&lt;p&gt;Speaking of &lt;em&gt;user experience&lt;/em&gt; and &lt;em&gt;possible&lt;/em&gt;:&lt;/p&gt;
&lt;h2 id=&quot;how-good-is-possible&quot;&gt;How Good is &lt;em&gt;Possible&lt;/em&gt;?&lt;/h2&gt;
&lt;p&gt;Recall, if you will, the Hermes blog post I made, where I had tried to use local LLMs for
coding and absolutely failed. The models weren’t large enough to know how to use tools,
context windows were tiny, &lt;em&gt;possible&lt;/em&gt; meant tiny models with short-term memory. &lt;em&gt;Possible&lt;/em&gt;
with 16 GB of unified memory, meant that I wasn’t able to achieve anything.&lt;/p&gt;
&lt;p&gt;Well folks, I’m here to tell you, that when you quadruple the amount of unified memory you
have, that your experience does, in fact, get much better using all these tools!&lt;/p&gt;
&lt;p&gt;But what tools, you ask, am I actually using? What models? And what have I actually done
with all that stuff anyway?&lt;/p&gt;
&lt;h2 id=&quot;what-is-the-sharpest-tool-in-the-shed&quot;&gt;What &lt;em&gt;is&lt;/em&gt; The Sharpest Tool in the Shed?&lt;/h2&gt;
&lt;p&gt;Well let’s talk about the tools first, then I can tell you what I’ve actually done with
them.&lt;/p&gt;
&lt;p&gt;So I first thought to myself: “Hey self! You like Ollama a lot right? Just use that and
use that for everything!”. And I did, and I tried using Claude Code as a harness using
Ollama, and uh… I’m not convinced at this time that Claude Code is all that good to use
for local LLMs… I tried using some models with it (admittedly I forget which ones), and
I was really struggling with actually using them.&lt;/p&gt;
&lt;p&gt;One thing that I also began realizing as well, was that Ollama’s model library was somewhat
limited. At the time of writing, &lt;a href=&quot;https://ollama.com/search&quot;&gt;Ollama’s models page&lt;/a&gt; had roughly
230 models available for local usage… Have you been to &lt;a href=&quot;https://huggingface.co/models&quot;&gt;HuggingFace&lt;/a&gt;
and seen the over 3.1 MILLION models they have? I rest my case.&lt;/p&gt;
&lt;p&gt;So I started hunting around, and two names kept coming up: LM Studio Bionic, and Unsloth.&lt;/p&gt;
&lt;p&gt;(LM Studio Bionic)[&lt;a href=&quot;https://lmstudio.ai/&quot;&gt;https://lmstudio.ai/&lt;/a&gt;] was ok: I really didn’t mind the chat functionality of
it, or how it can create entire projects within the agent window itself. However, I didn’t like
that it pretty much always wanted you to put all your chats into organized project folders, and,
if you can believe it, I also didn’t like how limited the model quantization options were for various
models.&lt;/p&gt;
&lt;p&gt;Quantization, for those who aren’t aware, is the process of quantizing the weights used by an LLM
down to specific precisions of bits, in order to make the model smaller to download and to fit into
VRAM. With quantized models, you lose precision, but you gain slightly faster processing and more
resource efficiency. Typically, 4-bit quantizations (or Q4 quants, as they are referred to) are
the sweet spot: good precision at a fraction of the VRAM and disk consumption.&lt;/p&gt;
&lt;p&gt;My problem with LM Studio, however, is their models page for, say, Qwen3.8-27B, provides me with
3 options: Q4_K_M, Q6_K, and Q8_0. All three are great, but that gives me no option to experiment
with any other options. Another example: Muse Glimmer, Meta’s latest 30B open weight model: comes
in &lt;em&gt;one quant&lt;/em&gt; in LM Studio and it’s the Q4_K_M quantization. Again, great option, but I want
&lt;em&gt;more&lt;/em&gt; because I know elsewhere I can &lt;em&gt;find&lt;/em&gt; more. I’m trying to experiment, not try the 5-10
models that LM Studio recommends.&lt;/p&gt;
&lt;p&gt;Another gripe that I had about LM Studio was the CLI. Desktop applications are not my favorite
way to use agentic coding tools: I &lt;em&gt;love&lt;/em&gt; my CLIs. LM Studio’s CLI doesn’t currently have easy
ways to start a coding tool like Claude Code or OpenCode easily. I was a little shocked at that,
because even tools like Ollama have CLIs that do that!&lt;/p&gt;
&lt;p&gt;But then I discovered &lt;a href=&quot;https://unsloth.ai/docs/desktop&quot;&gt;Unsloth&lt;/a&gt;, and it had pretty much all
the functionality I was looking for: varied model selections at varying quanitzations, an
easy-to-use desktop application that feels intuitive to use coming from ChatGPT or Claude,
and best of all, I’m an &lt;code&gt;unsloth start claude&lt;/code&gt; or &lt;code&gt;unsloth start opencode&lt;/code&gt; away from starting
an agent with one of the models I downloaded.&lt;/p&gt;
&lt;p&gt;The ability to start up an agent harness this easily is a &lt;em&gt;must&lt;/em&gt; for anyone who is wanting to
use their existing tools: Claude and Codex harnesses will typically have specific instructions
or files that exist in places that typically don’t work with other agent harnesses. Being able
to transition your models without having to uproot your entire workflow or configuration is
a &lt;em&gt;huge win&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;In addition to the CLI, Unsloth also felt very familiar with what I had come to expect from
other GenAI apps: Deep Research mode, Web Search tools, MCPs, but with the added benefits of
all my models running locally, not requiring an internet connection, and with a plethora of
free, open weight models available from some of the largest players like ChatGPT, Google, NVIDIA,
and Alibaba, all the way down to small-time fine-tuners, distillers, and obliterators.&lt;/p&gt;
&lt;p&gt;For me: Unsloth has been the sharpest tool in my local LLM shed.&lt;/p&gt;
&lt;h2 id=&quot;models--tools--success&quot;&gt;Models + Tools = Success?&lt;/h2&gt;
&lt;p&gt;So here’s a harsh reality of the local LLM ecosystem that I haven’t quite discussed yet that
I think is important to understand: getting into a groove with local models and tools, in a
manner in which you can be productive, comes with a lot of trial and error.&lt;/p&gt;
&lt;p&gt;If you have subscriptions to ChatGPT, Claude, Cursor, or another provider that offers some
kind of agent harness, you’re likely accustomed to logging into your tools on your machine,
sending over a prompt, and your agents producing the work you wanted it to produce in the
same day. It all &lt;em&gt;just works&lt;/em&gt;. You pay your subscription fee, you log in, and Opus one-shots
a todo app for you in less than 20 minutes. Simple, easy, fast.&lt;/p&gt;
&lt;p&gt;With local LLMs however, it’s a series of trial and errors, trying different combinations
of models and tools, and seeing what works best in what. Depending on the size of the model
as well, and how much computing power you have, it may not be nearly as fast as a subscription
that you might have.&lt;/p&gt;
&lt;p&gt;Let me give you a more practical example: you know that post I made about using ChatGPT
to edit a &lt;a href=&quot;https://jvarness.blog/nerdery/pokemon-gold-chatgpt-egglocke-1/&quot;&gt;Pokemon Gold save&lt;/a&gt;?
Well typically editing those files in Claude or ChatGPT was relatively fast. Ultimately
most of those saves had problems with them, but within about half an hour I would usually
have one.&lt;/p&gt;
&lt;p&gt;Care to guess how long it took Qwen3.8-27B to edit the save file? Well… I wasn’t able to
edit the file inside the Unsloth Desktop application, because apparently it doesn’t accept
&lt;code&gt;.sav&lt;/code&gt; files. Instead, I popped &lt;a href=&quot;https://opencode.ai/&quot;&gt;OpenCode&lt;/a&gt; up with Qwen3.8 to have it
edit the file. It took a whopping &lt;strong&gt;5 hours and 11 minutes&lt;/strong&gt; to edit the save file. I still
need to play the game to see if it worked, and I still have to finish my posts about trying
to get Claude to edit the saves that I’ve been lazy about getting out.&lt;/p&gt;
&lt;p&gt;Another example: I wanted to convert my blog from Gatsby to a different framework. I started
by having Muse Glimmer do Deep Research on good alternatives I could convert the blog to.
Based on the research it had done, I decided that &lt;a href=&quot;https://astro.build/&quot;&gt;Astro&lt;/a&gt; would be a
good choice! In terms of the Deep Research, I think local models do as good of a job as
you might expect Deep Research to work in Claude or ChatGPT, so for that local LLMs are
more of a toss-up.&lt;/p&gt;
&lt;p&gt;When I started the conversion, I had started by trying to see if this model called
&lt;a href=&quot;https://huggingface.co/empero-ai/Qwythos-9B-Claude-Mythos-5-1M&quot;&gt;Qwythos&lt;/a&gt;, a Qwen-based
model trained on Claude Fable traces. It’s one of the few models that I can run on this
machine that natively support a 1M context window. Now… Interestingly enough, this model
didn’t always perform very well in a non-Anthropic harness. In Unsloth, it didn’t always produce
the right syntax for tool calls within the desktop app. But in Claude Code, it performed very
well!&lt;/p&gt;
&lt;p&gt;Well enough to convert my blog in one shot? Ha, I wish 🫠&lt;/p&gt;
&lt;p&gt;I had tried starting out in Plan Mode like I normally would in Claude Code for larger
refactors like this, and Qwythos was able to, at the very least, come up with the plan.
Not bad. But when it came to all the coding effort it took to actually convert the
blog, that was a little more tricky: context window compaction was not as smooth
within Claude Code, and Claude Code sometimes timed out waiting for responses from
Unsloth during compaction, or even when I switched to the slower Qwen3.8-27B and waiting
for responses from it. This did not end up being the set-and-forget refactor that would have
been very capable for the likes of Opus or Sol.&lt;/p&gt;
&lt;p&gt;However, after a few days of switching between Claude and OpenCode, switching to Qwen3.8
to finish things up, and multiple sessions later, this blog was finally completely
re-written and migrated to Astro! No more Gatsby security issues and dependency hell for
me!&lt;/p&gt;
&lt;p&gt;So it just goes to show: your selection of the models and tools really does matter.
Some models work really great: Muse Glimmer and Qwen3.8 have been extremely capable
models, and I’ve even enjoyed the occassional use of Ornith and gpt-oss models as well! In
contrast, there are models that I thought I would be really great to use, like GLM-4.7,
that I have yet to find a harness where that model will work at all. Am I doing something
wrong? Probably, I’m very new to this, but it just goes to show that doing this all
locally doesn’t mean it’s &lt;em&gt;easy&lt;/em&gt; or &lt;em&gt;fast&lt;/em&gt;. What it &lt;em&gt;does&lt;/em&gt; mean though, is that I can still
delegate tasks to an agent &lt;em&gt;for free&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id=&quot;going-bigger&quot;&gt;Going Bigger?&lt;/h2&gt;
&lt;p&gt;So I mentioned earlier that I would maybe have some numbers detailing where my hardware
typically ends up sitting at and with which models. The factors are numerous here, and
as the technology around LLMs gets more advanced, I’m going to be excited to see how
far we can push our hardware! But for now, my setup and the numbers look a little bit
like this:&lt;/p&gt;
&lt;p&gt;So my machine is the Z13 Flow with 64 GB of unified memory, as I mentioned before. In
Armoury Crate (the (British?) tool the Z13 comes with for lower-level device management),
I have 32 GB allocated to the CPU, 32 GB allocated to the GPU, and approximately 16 GB of
the 32 GB of CPU RAM can be shared with the GPU. Not quite as seemless as managing RAM
on a Mac, but not horrible.&lt;/p&gt;
&lt;p&gt;Now: that 32 GB of GPU RAM is surprisingly very flexible when it comes to running any of
these LLMs locally. One of the nice things that Unsloth has (that Bionic doesn’t), is
that it has a little RAM estimator that can give you insight into how much RAM the model
is going to take up. Very convenient for when you may want to mutli-task and you want
to ensure that the model will fit within the dedicated GPU RAM.&lt;/p&gt;
&lt;p&gt;Where it gets slightly more complicated is when we start talking about models that
&lt;em&gt;don’t&lt;/em&gt; fit within 32 GB of RAM. Windows 11 takes, on startup, with most apps disabled
from opening on startup, approximately 9 GB to 11 GB of RAM, leaving about 20 GB in headroom
to do other things, providing the LLM itself doesn’t take up too much more room in the
system.&lt;/p&gt;
&lt;p&gt;If you are someone who has been interested in local AI development, and you aren’t sure
if a model could fit either into VRAM or system RAM, here is what Unsloth tells me about
the amount of RAM each of the following models can fit into, with the given parameter
counts, quantizations, and context windows:&lt;/p&gt;






















































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Model&lt;/th&gt;&lt;th&gt;Size&lt;/th&gt;&lt;th&gt;Quant&lt;/th&gt;&lt;th&gt;Context Window&lt;/th&gt;&lt;th&gt;Unsloth Estimated RAM&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Qwen 3.8&lt;/td&gt;&lt;td&gt;27B&lt;/td&gt;&lt;td&gt;Q4_K_M&lt;/td&gt;&lt;td&gt;262,144&lt;/td&gt;&lt;td&gt;37.3 GB&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;NVIDIA-Nemotron-3-Nano-Omni&lt;/td&gt;&lt;td&gt;30B-A3B&lt;/td&gt;&lt;td&gt;Q4_K_M&lt;/td&gt;&lt;td&gt;1,048,576&lt;/td&gt;&lt;td&gt;33.16 GB&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Muse Glimmer&lt;/td&gt;&lt;td&gt;30B&lt;/td&gt;&lt;td&gt;IQ3_M&lt;/td&gt;&lt;td&gt;131,072&lt;/td&gt;&lt;td&gt;18.75 GB&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Qwythos&lt;/td&gt;&lt;td&gt;9B&lt;/td&gt;&lt;td&gt;Q8_0&lt;/td&gt;&lt;td&gt;1,048,576&lt;/td&gt;&lt;td&gt;50.71 GB&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;gpt-oss&lt;/td&gt;&lt;td&gt;20B&lt;/td&gt;&lt;td&gt;MXFP4&lt;/td&gt;&lt;td&gt;131,072&lt;/td&gt;&lt;td&gt;14.93 GB&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Ornith 1.5&lt;/td&gt;&lt;td&gt;35B-A3B&lt;/td&gt;&lt;td&gt;Q4_K_M&lt;/td&gt;&lt;td&gt;262,144&lt;/td&gt;&lt;td&gt;29.84 GB&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;But what about larger models like GLM-5.3 and some of the flagship Deepseek models? Well
some of those are potentially trillions of parameters large, roughly 30x the size of the
larger models that I’ve listed here. Even at a Q1 quantization, which would basically
lobotomize the LLM, likely none of these models are capable of running on this machine.&lt;/p&gt;
&lt;p&gt;Ok but what about models smaller than 1T but bigger than 35B? Well… Two things about
that: first and foremost, those sizes of models rarely exist. Once you exhaust the
inventory of models that exist between the 9B and 35B range (which is most of them that
you would want to run to do any kind of coding or productivity task) the models basically
jump to 200B or larger.&lt;/p&gt;
&lt;p&gt;Second: those 200B models would never fit in this machine as LLMs currently exist, no
matter what format or quant they come in. Say for example DeepSeek-V4-Flash-0731. That
is a 284B model. On disk, the model at Q1 quantization is 83 GB. Most of the models that
fit on this machine are roughly 11-20 GB on disk, but you can tell between the context
window and the models sizes on disk that they take up a substantial amount of space in
RAM and VRAM. Unsloth even has a little icon that shows up whenever you’re looking at
the quantizations that tells you the likelihood of a model fitting on the machine. It’s
got Green for should fit, Yellow for might fit, and Red for highly unlikely to fit. I
can’t find any models that are 200B+ parameters in size that aren’t Red 🫠&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Overall, these local models are turning out to be incredibly capable and useful. Granted,
there are some quirks getting this all running, and it’s definitely not as smooth of an
experience as getting a subscription from some of the other players in the AI game.
But if you get the right mixture of capable tools, right-sized models, and you have
reasonable ambitions, you can delegate a lot of the things you want to do to local
models.&lt;/p&gt;
&lt;p&gt;If you read this blog and you had more questions for me, feel free to reach out to me on
some of the socials at the bottom of the screen! Have yourselves a great rest of the
weekend, and have fun LLM’ing!&lt;/p&gt;</content:encoded></item><item><title>My Primer with Hermes</title><link>https://jvarness.blog/my-primer-with-hermes/</link><guid isPermaLink="true">https://jvarness.blog/my-primer-with-hermes/</guid><description>Why and how I started playing around with Hermes Agent, and why it&apos;s my fun new AI-powered experiment</description><pubDate>Tue, 18 Aug 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In one of my previous blog posts, you may have read that &lt;a href=&quot;/the-trap-of-modern-computer-hardware&quot;&gt;I upgraded an older machine&lt;/a&gt;
that I had gotten from a previous employer. So far, the extra RAM has proven to be a lot more
useful than I had imagined! I’ve been able to offload a bunch of what I was trying to use my
M1 Pro Macbook for, and so far it’s been working great!&lt;/p&gt;
&lt;p&gt;One of the things I was really wanting to try out with this upgrade was using local LLMs with
Ollama. You might have seen some videos online about how models like Gemma 3 or 4 could run
on hardware as constrained as a Raspberry Pi. This made me very excited, initially, because
with all this additional headroom, I was thinking to myself that this is the perfect time to
play around with some local LLMs once again.&lt;/p&gt;
&lt;p&gt;Using local LLMs can be extremely beneficial to anyone using them:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Reducing one’s dependency on paid monthly subscriptions&lt;/li&gt;
&lt;li&gt;Privately hosting your own LLMs and data and not letting cloud-services scrape your data&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Never hitting another token limit&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That last one is a big deal: a lot of people want to allow agents to run uninhibited by limits,
only being constrained by context window sizes. Whenever you hit a limit, it can be frustrating,
regardless if you’re using Anthropic, OpenAI, or any other set of models. For people who are using
an agent like Hermes or OpenClaw, hitting a limit could mean your agent hits a wall for several
hours.&lt;/p&gt;
&lt;p&gt;That last point too is… Unfortunately, not something my 4th Generation Intel i7 machine’s
integrated graphics processor can really help me with. Really, none of those bullet points are
going to really be addressed for me soon. I’ve got a personal Claude subscription, but what
exacerbates this entire situation is that Anthropic has done everything under the sun they could
do to prevent agent harnesses like Hermes from using their models. Anthropic’s hostility towards
it’s models being used outside of their specific products has made their value really depreciate
over time for me…&lt;/p&gt;
&lt;p&gt;Until I can get my hands on something like an AMD AI Halo, a DGX Spark, or some other kind of
unified memory beast, I probably won’t be able to get through any of those bullets (or Anthropic’s
restrictive usage policies) easily. However, there are things I’m starting to learn how to use now
that I’m hoping I can take advantage of in a future where I won’t have to sell an arm or leg to
afford one of those.&lt;/p&gt;
&lt;p&gt;This blog originated from a desire to try out &lt;a href=&quot;https://hermes-agent.nousresearch.com/docs&quot;&gt;Hermes Agent&lt;/a&gt;,
the new agent that’s becoming increasingly more popular, and for good reason. It’s an agent that not
only performs tasks for you autonomously like one would expect from any agent, but it also creates and
refines it’s own skills over time as you continue to use it. It’s a brilliant piece of technology that
I’m very excited to continue using!&lt;/p&gt;
&lt;p&gt;But without all that sweet sweet VRAM, how exactly have I setup a Hermes Agent? Well, that’s what this
blog is all about.&lt;/p&gt;
&lt;h2 id=&quot;the-constraints&quot;&gt;The Constraints&lt;/h2&gt;
&lt;p&gt;VRAM, o VRAM, where art thou, thy VRAM? Look, I know the answer, I just don’t really like it. The
truth is: it’s all in graphics cards and unified memory SOCs that are all continuing to skyrocket
in price. How much VRAM do I have? Not nearly enough.&lt;/p&gt;
&lt;p&gt;See: I’m not really your typical computer nerd. Many of your other favorite nerds you interact with in
your life likely have a gaming PC, or some other kind of higher-end desktop computer. Maybe they
joined the PC Master Race a long time ago, and they’ve been working their way through computer upgrades
for several years of RTXs, Ti’s, 4090s, 3080s, 9600s, AM4s, AM5s, etc. The cold-hearted reality for
me is that I’ve only recently (and I’m talking as in the past month or so) what all those terms
actually mean. I use what the companies I work for give me, and occassionally I spend a little more
on myself to get a personal device. That’s roughly it.&lt;/p&gt;
&lt;p&gt;So no, sadly, I don’t have any desktop computers that I could really use for anything like this. I
also don’t have any laptops that have nearly the amount of hardware that I would need to achieve any
kind of useable agent context window. Ollama, in particular, which has been one of my preferred
means of accessing LLMs locally, &lt;a href=&quot;https://docs.ollama.com/context-length&quot;&gt;recommends having over 48GB of VRAM&lt;/a&gt;
in order to achieve a 256k context window.&lt;/p&gt;
&lt;p&gt;For your own context, in case you aren’t aware of what that means, an LLM’s context window is essentially
it’s short-term memory for that conversation. Sonnet 5 and Opus 4.8 are capable of context lengths up to
1 million tokens, and typically Codex context lengths (from what I remember when I used it), are typically
around 256k. Whenever your context window is reached, pretty much every model will go through and compact
the context down so that it can fit more, if it’s a longer-running session.&lt;/p&gt;
&lt;p&gt;But why is having a high context window important? Well, because if your LLM can’t use it’s brain, it gets
stuck:&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;#x22;src&amp;#x22;:&amp;#x22;./low-context-window.jpeg&amp;#x22;,&amp;#x22;alt&amp;#x22;:&amp;#x22;A screenshot of Cline running via a local LLM and restating the same statement multiple times&amp;#x22;,&amp;#x22;index&amp;#x22;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;If you opened that link to Ollama previously, you might notice what context windows are recommended depending
on how much VRAM your system has. In the screenshot above, this is Cline running &lt;code&gt;qwen3:4b&lt;/code&gt; hosted in LM Studio
locally. The context window in this screenshot was only about 4k. I couldn’t even &lt;em&gt;use Cline&lt;/em&gt; with a local LLM
because my local LLM had a real smol brain. The other issue is that between the actual models themselves, which
can take up significant amounts of that VRAM, and the context window your model is storing, your model isn’t
sipping resources at that point: it’s chugging them.&lt;/p&gt;
&lt;p&gt;And as it turns out: trying to use DDR3 RAM with a local LLM, even at a larger context window, doesn’t really
yield a usable setup. Was I able to run &lt;code&gt;gemma4:e4b&lt;/code&gt; on my W540? Sure, I was able to have one brief conversation
with it. Was I able to &lt;em&gt;use it&lt;/em&gt; though? Absolutely not.&lt;/p&gt;
&lt;p&gt;But why not? &lt;code&gt;gemma4:e4b&lt;/code&gt; was purpose-built to run on constrained hardware at the edge! Well, even if I expand
the context window, I couldn’t prompt the model outside of Ollama. If I tried to hook up Hermes Agent to Ollama
with that model, I couldn’t even get one prompt in before it started timing out. There was just too much context
that Hermes was trying to initialize Gemma4 with, and ultimately I gave up trying to load it locally.&lt;/p&gt;
&lt;p&gt;I also knew that Hermes wasn’t going to be able to use my Claude subscription either: everything Anthropic
enforces would have forced me to pay for token usage out-of-pocket if I wanted to use the models.&lt;/p&gt;
&lt;p&gt;And I’m a cheapskate: I want to pay my $20 per month and use those limits, not pay per token. If I wanted to
do pay per token, I would have just started using AWS Bedrock.&lt;/p&gt;
&lt;p&gt;I was giving up on the idea of using any local models, and giving up on the idea of experimenting with Hermes
until I either switched subscriptions or got a new computer…&lt;/p&gt;
&lt;p&gt;But then, I saw this:&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;#x22;src&amp;#x22;:&amp;#x22;./access-cloud-models.png&amp;#x22;,&amp;#x22;alt&amp;#x22;:&amp;#x22;Screenshot of Ollama&amp;#x27;s Free tier that includes cloud models&amp;#x22;,&amp;#x22;index&amp;#x22;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;“Access Cloud Models” you say? Usage only reflects the usage of Ollama’s GPU time and not based on token usage,
you say? You’ve got models like Gemma4, Qwen3 Coder, and GPT-OSS with 256k context windows, do you?&lt;/p&gt;
&lt;p&gt;😏😏😏&lt;/p&gt;
&lt;h2 id=&quot;ollama&quot;&gt;Ollama&lt;/h2&gt;
&lt;p&gt;So let’s start off with the obvious question: why? Why Ollama and why Hermes?&lt;/p&gt;
&lt;p&gt;When Lovable, OpenRouter, and many other model providers (some that are arguably better than) Ollama
exist, why use Ollama? When graphical tools like LM Studio exist, or potentially more powerful and
configurable tools like Llama.cpp exist, why use Ollama?&lt;/p&gt;
&lt;p&gt;Because it’s easy for me to use. That’s really the long and short of it. I started my local LLM journey using
Ollama, and while I haven’t had the hardware necessary to take full advantage of it a lot of the time, it has
a really simple CLI, it’s free to download, only requires an account if you want to use the cloud models,
it has most of the popular models you could want, it’s just so darn simple to use. It’s also got config
files you can run to customize the behavior of the models if you want to fine-tune some of the model’s
default parameters and supply a system prompt to it.&lt;/p&gt;
&lt;p&gt;How easy is it to interact with a model with Ollama though if the interface you’re using is primarily
CLI-based? Pretty easy. Just download Ollama, and if you want to interact with it, you just login:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;ollama&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt; signin&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then you can pick from a massive swath of &lt;a href=&quot;https://ollama.com/search?c=cloud&quot;&gt;cloud-based models&lt;/a&gt; hosted
by Ollama. Take &lt;code&gt;gemma4:cloud&lt;/code&gt; for example:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;ollama run gemma4:cloud&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Connecting to &apos;gemma4:31b&apos; on &apos;ollama.com&apos; ⚡&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&gt;&gt;&gt; say &quot;hello&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Thinking...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;The user wants me to say &quot;hello&quot;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;The request is straightforward: &quot;say &apos;hello&apos;&quot;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;The appropriate response is to say &quot;hello&quot;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;...done thinking.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;hello&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&gt;&gt;&gt; Send a message (/? for help)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now… Me personally? I could really do without ever seeing any thinking tokens. Watching the
model generate several paragraphs that all start with &lt;code&gt;But wait, ...&lt;/code&gt; seems like a complete waste of
effort and tokens in my opinion. Regardless: you can use Ollama to chat with models pretty easily
this way, and you can choose between a lot of open weight options. You can even create a
&lt;a href=&quot;https://docs.ollama.com/modelfile&quot;&gt;Modelfile&lt;/a&gt; that allows you to give a model a different name,
provide a system prompt, and override any of the default parameters like temperature and top K.&lt;/p&gt;
&lt;p&gt;The only issue here is that the CLI itself isn’t actually very useful. Ollama doesn’t provide
any extra tools or harnesses apart from allowing you to chat with the model. To demonstrate this,
if you aren’t famous like I am, you can ask it to look up information about you:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&gt;&gt;&gt; Can you search for Jake Varness and tell me what you know about him?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Thinking...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&amp;#x3C;it thought for a while&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;...done thinking.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;I was unable to find any widely known public figures, celebrities, or &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;historical personalities named **Jake Varness**. &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;It is possible that he is a private individual, a professional in a &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;specific niche, or someone with a smaller online presence. If you can &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;provide more context—such as his profession, where he is from, or why he &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;is notable—I may be able to help you find more specific information.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&gt;&gt;&gt; &lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can see here that not only was it apparently never trained on who I was, which tells me
&lt;strong&gt;exactly&lt;/strong&gt; how important I actually am, but it also never bothered to actually search the web.
This is part of why chatting with a model like this isn’t very reliable: it’s all based
on training data within the model. There’s no RAG or tool calls here to help it perform a web
search, do deep research, write code for you, etc. It’s about as useful as ChatGPT used to be
before they started adding tool calls to LLMs.&lt;/p&gt;
&lt;p&gt;In fact: some models out there cannot use tools at all. Fortunately, Ollama allows you to filter
by models that can &lt;a href=&quot;https://ollama.com/search?c=cloud&amp;#x26;c=tools&quot;&gt;use tools AND are cloud-deployed&lt;/a&gt;.
Since Ollama is simply providing a chat interface to test out a model, in order to use tools, it
needs some kind of agent harness.&lt;/p&gt;
&lt;p&gt;An agent harness is something like Codex, Claude, OpenClaw, or Hermes, that is able to use an
underlying model to process your prompts. So while using &lt;code&gt;gemma4:cloud&lt;/code&gt; in Ollama won’t allow
you to perform any agentic coding tasks, you could use &lt;code&gt;gemma4:cloud&lt;/code&gt; in a harness like Claude
Code, Codex, or OpenCode:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# Claude Code using Ollama&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;ollama&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt; launch&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt; claude&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt; --model&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt; gemma4:cloud&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# Codex using Ollama&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;ollama&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt; launch&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt; codex&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt; --model&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt; gemma4:cloud&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# OpenCode using Ollama&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;ollama&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt; launch&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt; opencode&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt; --model&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt; gemma4:cloud&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;# Hermes using Ollama&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;ollama&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt; launch&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt; hermes&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt; --model&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt; gemma4:cloud&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That last one is how we can start to take advantage of the power of an always-on agent like Hermes.&lt;/p&gt;
&lt;h2 id=&quot;hermes--ollama&quot;&gt;Hermes + Ollama&lt;/h2&gt;
&lt;p&gt;Hermes, like I mentioned before, is an autonomous, always-on agent, that is capable of continuously
executing tasks. As you prompt Hermes, it builds skills and memories and can teach itself how to do
it’s best possible work for you.&lt;/p&gt;
&lt;p&gt;Hermes is also nice in the sense that you don’t necessarily need to use any particular model vendor
to use it. Nous Research, the creators of Hermes, do have models specifically designed for Hermes
that you &lt;em&gt;could&lt;/em&gt; use, but Hermes doesn’t require their models, which is nice. If you have a
subscription that &lt;em&gt;isn’t&lt;/em&gt; a Claude subscription to a model provider, you could even use an existing
subscription!&lt;/p&gt;
&lt;p&gt;If you’ve already done some of the steps I’ve done to sign into Ollama, and if you’ve got an afternoon
to setup Telegram and Hermes, you can do so by running that last command I mentioned earlier:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;bash&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;ollama&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt; launch&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt; hermes&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt; --model&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt; gemma4:cloud&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Apart from the communication gateways, you can also setup different kinds of skills and tools that
Hermes can take advantage of! You can go to this &lt;a href=&quot;https://hermes-agent.nousresearch.com/docs/reference/tools-reference&quot;&gt;tools reference page&lt;/a&gt;
to check out some of the tools that are installed in Hermes by default and learn about how to browse
from a skills marketplace to get new skills and tools.&lt;/p&gt;
&lt;p&gt;So with a newfound agent, one would think I’m using it to build a business right? My use-cases
unfortunately are not that ambitious at the moment. Like most things in a programmer’s life, to
learn how to utilize them best, it’s good to start small and work your way up to more complicated
use cases over time. I guess the other good news about this though, is that you can still rest
assured that I’m not using AI to write blogs ^-^&lt;/p&gt;
&lt;p&gt;However, there was something that I was able to have Hermes do for me that I did think was really
cool. I have some compute-heavy workloads for an iOS game I’ve been using Codex and Claude to help
me develop over the past few months. Codex and Claude have refined a set of python scripts that I’ve
used to develop the levels of the game, and while I’m eternally grateful for their hard work, those
scripts take a long time to run, and a lot of memory as well.&lt;/p&gt;
&lt;p&gt;Normally, if I wanted to run those on my M1 Pro, my 16gb of RAM doesn’t afford a ton of headroom to
actually generate levels. Not only that, but I also have to make the Macbook sit there and run
continuously, and if I wanted an update of whether or not a pack of levels got generated, I’d have
to go check it myself. All compute and no play makes Jake’s Macbook a dull piece of aluminum.&lt;/p&gt;
&lt;p&gt;The upgraded Lenovo was actually a perfect little machine for performing these RAM-heavy tasks, and
even though the processor in it is a 12-year-old Intel i7, I don’t really care that it’s going
to be able to compute these levels super fast: &lt;em&gt;I just care that it eventually does it&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;While running some of these scripts manually myself, and while I was going down this journey of
setting up Hermes, I realized something: I might be able to just have Hermes watch these processes
for me!&lt;/p&gt;
&lt;h2 id=&quot;learning-hermes-by-leaning-on-hermes&quot;&gt;Learning Hermes by Leaning On Hermes&lt;/h2&gt;
&lt;p&gt;So I told Hermes (and I’m vastly paraphrasing here, it wasn’t the exact prompt): “hey dude, I have
3 python processes running that I’d like to refer to as “level generators”, and I want you to check
on them for me 3 times per day and let me know if any of them has completed”.&lt;/p&gt;
&lt;p&gt;Hermes basically said: “bet, lemme setup a watchdog”.&lt;/p&gt;
&lt;p&gt;And it did! I specified a few times per day to check: times where I thought if something finished
that I’d actually be able to do something about it around that time. But I really wanted it to
just… Let me know if any of them aren’t running anymore.&lt;/p&gt;
&lt;p&gt;What Hermes &lt;em&gt;actually&lt;/em&gt; did, was just notify me during each of the times of day and say “hey uh, these
are all still running”.&lt;/p&gt;
&lt;p&gt;So I had to tell Hermes: “hey dude, I just want you to notify me when one of them actually finishes,
and if any of them haven’t, you don’t need to notify me.”&lt;/p&gt;
&lt;p&gt;And Hermes was all like: “oooooh ok I get it now” “cronjob: edit” “ok we gucci”&lt;/p&gt;
&lt;p&gt;I didn’t hear from it again for a couple weeks. I wasn’t expecting to, really: those scripts take
a long time to run. However, to my surprise, while I was out of town and the computer was still
up and running and plugging away, I got a notification from Hermes! One of my scripts had ran
successfully and generated some levels!&lt;/p&gt;
&lt;p&gt;I was pretty excited! I was also excited when a couple hours later it notified me &lt;em&gt;again&lt;/em&gt; about
the same process that had stopped… And &lt;em&gt;again&lt;/em&gt; later that day when it updated me about
&lt;em&gt;the same process&lt;/em&gt; that it already told me about twice.&lt;/p&gt;
&lt;p&gt;So I had to tell Hermes: “hey man, if you see something has stopped running, and you already
told me about it, don’t tell me about it again, just let me know when one of the generators
is done, and just &lt;em&gt;once&lt;/em&gt;.”&lt;/p&gt;
&lt;p&gt;And Hermes was all like: “oh sorry about that Jake” “cronjob: edit”&lt;/p&gt;
&lt;p&gt;What was really cool about all of this was all the little self-improvement and learning things
it does along the way as you prompt it: it picks up on tidbits about you and things that you ask
it to do, and it’s always improving as you continue to prompt it.&lt;/p&gt;
&lt;p&gt;Now here’s where things got really cool for me: I didn’t want to lose the file the scripts had generated.
If I lost it, I’d have to wait weeks potentially for the scripts to generate those levels again.
That would be terrible.&lt;/p&gt;
&lt;p&gt;But then I remembered: &lt;em&gt;that Lenovo has access to my source control&lt;/em&gt;… Which means that &lt;em&gt;Hermes&lt;/em&gt;
can use the source control too!!&lt;/p&gt;
&lt;p&gt;So I told Hermes: “hey bruh, go and commit those new levels to git for me and just push them straight
to the main branch.”&lt;/p&gt;
&lt;p&gt;And Hermes was all: “oh yea dude I gotchu” as it proceeded to commit files to git for me.&lt;/p&gt;
&lt;p&gt;That was the &lt;em&gt;first time&lt;/em&gt; in &lt;em&gt;ever&lt;/em&gt; that I committed a file to version control
&lt;em&gt;without my fingers being physically attached to the keyboard of the computer&lt;/em&gt; that the code was
all on. Like… I know that one time I had Comet make an empty repo for me, but this felt… very
different. I even told Hermes to just commit the new files every time one of those scripts finishes
so that I don’t lose them. We’ll see if Hermes actually follows through with that or not 🤣&lt;/p&gt;
&lt;p&gt;Heck, I even asked it to start off a new generator and watch that one too! And it was able to!!&lt;/p&gt;
&lt;p&gt;Now… Obviously, the stakes are really low with an example like this: I’m making an AI agent
monitor processes, commit things to git, and send me an occassional notification or two. Very
low-risk. But just think about the possibilities of this: it’s no wonder someone was able to
make a social media skill that was entirely made up of OpenClaw agents people owned!&lt;/p&gt;
&lt;p&gt;Agents like Hermes are able to perform tasks on a cron schedule, perform tasks on-demand, manage
multiple contexts through different sessions, and continuously self-improve. As long as you are
able to give Hermes feedback on what it does well and what it could improve on, it can do pretty
much anything you want it to!&lt;/p&gt;
&lt;p&gt;And to many people reading this who are adopters of AI tools, you might think that this just seems
like a different Claude Cowork or Claude Code with Remote Control enabled. But the reality is: it’s
simply not. Cowork and Claude Code don’t continuously run and aren’t really capable of monitoring
things for you. In fact, one of the first things I tried looking into with Claude and ChatGPT was
how I could schedule tasks.&lt;/p&gt;
&lt;p&gt;I’m quite positive you can’t do this, or if you can it’s buried, and I don’t think you can use them
unless you run the desktop clients.&lt;/p&gt;
&lt;p&gt;Even though I’m technically using a cloud-deployed AI model, using something like a Hermes agent
through Telegram and Ollama really feels more like it’s &lt;em&gt;my AI&lt;/em&gt; and not the AI that a company
is giving me a license to use, or the permission to use as long as I continue to use &lt;em&gt;their&lt;/em&gt; agent
harnesses. It’s also nice to know that I can try out different AI models through Ollama if I
wanted to! I hear Meta’s Muse Glimmer is a pretty popular one these days.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;These small examples have really shown me the value of Hermes and what it’s capable of. Agents are
powerful little pieces of technology that have tons of potential. With clear enough prompts, or
at least clearer ones than I was able to provide to Hermes, you can have it efficiently and
effectively automate some of our day-to-day routines.&lt;/p&gt;
&lt;p&gt;If you are just starting your AI journey, Ollama and Hermes could potentially be a great place to
start! With a lower barrier to entry than other tools like Claude Code or Codex, you can explore
how to use AI to accomplish your goals, start new projects, or experiment with small ways that you
can leverage AI for work!&lt;/p&gt;</content:encoded></item><item><title>The Trap of Modern Computer Hardware</title><link>https://jvarness.blog/the-trap-of-modern-computer-hardware/</link><guid isPermaLink="true">https://jvarness.blog/the-trap-of-modern-computer-hardware/</guid><description>When modern hardware is good, if only for a moment</description><pubDate>Fri, 12 Jun 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;2026 is here. It’s both an incredible and terrifying time to be in tech: AI is disrupting every industry,
and is inflating computer hardware prices to all-time highs.&lt;/p&gt;
&lt;p&gt;Software is advancing at an incredible pace with agentic coding becoming an increasingly common way to
develop said software. LLMs are getting better and better as time has gone on, and the demand for a local
workstation that allows users to run their own LLMs to escape privacy concerns and subscriptions is at an all-time high.&lt;/p&gt;
&lt;p&gt;In addition to all this, there is a growing trend in the computer industry surrounding the actual hardware:
prices are increasing, and while onboard hardware is getting better for the price, it comes with a hidden cost of
becoming increasingly non-repairable and inserviceable. Software bloating up and utilizing more of those system
resources (even at idle) creates an ecosystem where base models of any new computer are rapidly becoming
obsolete.&lt;/p&gt;
&lt;p&gt;Macbooks are one of the most prolific modern examples of this. While I love my Macbook Pro M1 Pro, I’ve lately
found myself longing for more. More RAM, more disk space, and less Liquid Glass hogging up all my resources.
Don’t get me wrong: I love this machine. It’s great for &lt;em&gt;most things&lt;/em&gt; I would need it to do. While macOS has
become more and more bloated over time, it’s still my preferred operating system and ecosystem for work and
for my personal devices.&lt;/p&gt;
&lt;p&gt;But the soldered RAM, the soldered SSD, having little to no upgrade paths, the fact that at idle my system
uses roughly 8 out of the 16 gigabytes available on board, I’ve got little to no overhead for anything else after
running Comet tabs, Cursor, and the occasional Orca Slicer, Gimp, Notion, Claude, Android Studio, XCode,
etc.&lt;/p&gt;
&lt;p&gt;After everything is said and done, things like Docker or Ollama are an afterthought, even if I ran with
some CPU-friendly LLMs.&lt;/p&gt;
&lt;p&gt;For some of the things I’ve been working on lately, I’m really capped by my compute capacity: 8 gigs of RAM
isn’t getting me very far with scripts I’m running to generate levels for me for a game I’m trying to develop.
I really would like to get 32-36 or even 64 gigabytes of RAM, but I don’t really want to fork over the thousands
of dollars it would take to get a new, reliable system with those specifications, and my dream of eventually
owning a Framework Desktop 64gb is getting increasingly more expensive as time goes on.&lt;/p&gt;
&lt;p&gt;And this all started to make me remember how I used to be able to upgrade my computer hardware…&lt;/p&gt;
&lt;h2 id=&quot;the-apple-illusion&quot;&gt;The Apple Illusion&lt;/h2&gt;
&lt;p&gt;My Macbook Pro that I purchased in 2014 didn’t age very gracefully, BUT in the 8 or so years I actively used it,
I was able to upgrade it a couple of times to give it a new lease on life, so to speak.&lt;/p&gt;
&lt;p&gt;First was the RAM upgrade. I believe when I first purchased it, it had 4 gigabytes of RAM. Then, a couple years
later, I upgraded the RAM to 8 gigabytes, giving it a little more headroom to run things. Then, a couple years
after that, I got an SSD for Christmas from my wife and not only doubled its storage capacity, but considerably
boosted the speed.&lt;/p&gt;
&lt;p&gt;Over a decade later, it’s not doing anything.&lt;/p&gt;
&lt;p&gt;Not because I don’t want it to or haven’t tried, but because &lt;em&gt;it can’t&lt;/em&gt;, really.&lt;/p&gt;
&lt;p&gt;This non-retina Macbook Pro is essentially an EOL product. There’s no path to upgrade the onboard hardware or the
operating system in any way that makes it useable. Even software that I try to download that claims it can run on
an “Intel Mac” won’t run on my Mac because my Mac still runs Mac OS X, and can’t be upgraded to macOS at all.&lt;/p&gt;
&lt;p&gt;I could throw Linux on it, but that kind of defeats the entire purpose of having a Mac at all. I could try to sell
it, but compared to the money I put into it, I’d practically be giving it away.&lt;/p&gt;
&lt;p&gt;I start looking at Framework and I start to get very envious… I start to realize that I love my Macbook Pros until
they… Really don’t work for me anymore.&lt;/p&gt;
&lt;p&gt;It’s got me wondering for how much longer I’m going to actually be able to use this device I’m typing on right now.
Sure, I bought it refurbed for a good price a couple years back, but as I continue to use this device, I grow
increasingly worried about this device succumbing to planned obsolescence.&lt;/p&gt;
&lt;p&gt;But you’re thinking “dude it’s an M1 Pro, relax, you’re still good for a while”. Am I though? I couldn’t even use
iCloud Passwords in Comet because I didn’t upgrade to Tahoe. Not even software developers, or Apple themselves,
tolerate choice when it comes to software or hardware anymore, unless you’re using the latest and greatest of
everything.&lt;/p&gt;
&lt;p&gt;And while the claims are that Apple “uses RAM differently/more efficiently” on the M-series silicon, I have to
wonder how true that claim actually is when I’m staring at Activity Monitor at startup and half of the available
on-board RAM is just… Gone. You can certainly say Apple devices are “built different”, but I’d argue after
having one of these things for so long, the whole “efficiency” claim is really not backed up by actual fact anymore.&lt;/p&gt;
&lt;p&gt;Thank goodness for open source and Linux and companies still willing to make DDR3 RAM.&lt;/p&gt;
&lt;h2 id=&quot;the-microsoft-illusion&quot;&gt;The Microsoft Illusion&lt;/h2&gt;
&lt;p&gt;This also really got me thinking about Microsoft as well. The first computer I was ever given for work was a
Lenovo W540 back in 2014 (kinda funny how I got both of those devices around the same time).&lt;/p&gt;
&lt;p&gt;This thing, by 2026 standards, is what most people would consider to be kind of a piece of crap: it’s heavier
than pretty much every other modern device, it only came with 16 gigs of RAM when I got it back from Cerner,
it has a 256gb SSD in it, which is small for modern devices, and doesn’t come with “modern” ports like USB-C.
It came with Windows 7 that I eventually was able to upgrade to Windows 10, but when it came to getting
Windows 11, I was told by Microsoft’s tool that my computer was too old for their new operating system. It gets
warm enough that using it as a laptop gets uncomfortable after a while.&lt;/p&gt;
&lt;p&gt;And holy bejeezus, no matter what I do, this thing has by far the &lt;em&gt;worst&lt;/em&gt; touchpad on any computer I’ve ever used.
You so much as breathe on it and it registers a click, much less brushing your hand against the touchpad while
you’re typing.&lt;/p&gt;
&lt;p&gt;However, for what it lacks in “modernity” it makes up for in a number of different ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A big, non-reflective screen that has 0 glare&lt;/li&gt;
&lt;li&gt;Carbon-fiber casing that makes it really tough&lt;/li&gt;
&lt;li&gt;The typing experience is fantastic&lt;/li&gt;
&lt;li&gt;It’s &lt;em&gt;so so so repairable&lt;/em&gt;, with easy access to pretty much every component&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I’ll come back to that last part for a second, but I wanted to stay on topic for the whole Windows 10/11
debacle. When Microsoft came out with Windows 11, they announced that only computers with UEFI secure boot
were able to upgrade to Windows 11.&lt;/p&gt;
&lt;p&gt;Guess what the W540 &lt;em&gt;doesn’t&lt;/em&gt; have? Guess what my W540 &lt;em&gt;can’t&lt;/em&gt; have as a result?&lt;/p&gt;
&lt;p&gt;Thank goodness for open source and Linux and companies still willing to make DDR3 RAM.&lt;/p&gt;
&lt;h2 id=&quot;repairability&quot;&gt;Repairability&lt;/h2&gt;
&lt;p&gt;When Microsoft’s Windows 11 Upgrade Eligibility told me I couldn’t upgrade, I took it very personally as
an affront to me and all that me has become.&lt;/p&gt;
&lt;p&gt;Just kidding, I downloaded Linux Mint onto a bootable USB drive and installed that instead. I hadn’t really
used Linux or had a machine with Linux on it in quite some time. This may not come as a shock to anyone
reading this, but I was surprised at how &lt;em&gt;little&lt;/em&gt; Linux actually needs to run. At idle, Linux Mint is taking
up only about 2 gigabytes of RAM.&lt;/p&gt;
&lt;p&gt;14 out of an available 16 gigabytes of RAM? That’s my kind of overhead. And for what it is, it’s still an
excellent device for being over 12 years old at this point! I’ve got Cursor, Claude Code, Docker,
all kinds of stuff installed on it. I can actually take advantage of the resources on board as opposed to all the hardware
being held hostage by the operating system.&lt;/p&gt;
&lt;p&gt;Then recently, after asking Claude, I realized that it &lt;em&gt;could&lt;/em&gt; have up to 32gb of RAM on it! The only problem
was actually finding the RAM. It’s DDR3L 1600 Mhz RAM, and only gets so big. But Amazon of all places had
4x8gb kits available of this RAM! for only about $80!! Far less money than what I’d spend on any new device.&lt;/p&gt;
&lt;p&gt;The formatted capacity of the 4 sticks I bought ended up registering 33gb of RAM total, and again, Linux at
idle is only taking around 2 of that. For my use-cases only revolving around raw compute and time, this is
really fantastic for me! Now, I can run the memory-intensive scripts on Linux without having to worry about
macOS hogging it all.&lt;/p&gt;
&lt;h2 id=&quot;truly-appreciating-repairability&quot;&gt;Truly Appreciating Repairability&lt;/h2&gt;
&lt;p&gt;This recent experience has really become a turning point for me in how I think about longevity of all of my
devices, and in various ways:&lt;/p&gt;
&lt;p&gt;I have two different Apple devices, one of which I couldn’t sustainably use anymore unless I got rid of the
operating system that all the hardware is designed around, and one that lacks the lustre of upgradeability
and will eventually become obsolete.&lt;/p&gt;
&lt;p&gt;At the same time, I’ve also got something completely different in the Lenovo: a loss of hardware and software
cohesion in exchange for having a significant amount of modularity. On top of being able to easily access many
of the core parts of the PC, the W540 could also potentially be upgraded with network cards, CD-ROM and/or disk
expansion bays, and has many parts that could easily be replaced or repaired, including the battery, the
keyboard, the awful trackpad, etc.&lt;/p&gt;
&lt;p&gt;If something fails in this laptop in the future, I likely could repair it, and it would probably be cheaper than
buying a different PC that likely would run into the same issues with obsolescence, repairability, and sustainability
as my M1 Pro Macbook Pro.&lt;/p&gt;
&lt;p&gt;I think about how we got here, and I respect the decisions behind how we got here: professional-grade devices
that prioritize power over everything. Soldered RAM that exists closer to the CPU/GPU/APU/NPU allows for a
significant boost in speed, and an extremely flexible architecture that allows RAM to be dynamically
allocated to serve graphics and compute. That’s not possible with expandable/repairable memory modules
like most people have in their desktop rigs.&lt;/p&gt;
&lt;p&gt;It’s not for a lack of trying either: Framework, in the development of the Framework Desktop, attempted to
work with AMD to see if the Ryzen AI Max 385/395+ could use traditional DDR5 RAM. AMD, in response,
basically told Framework that it’s not possible to do that without dramatic signal loss between the chip and
the RAM.&lt;/p&gt;
&lt;p&gt;As an industry though: how hard are PC manufacturers really trying? Ever since Apple released the M-series
Macbooks, soldered RAM, SSDs, and everything in between started to become more and more commonplace. It used
to be that most laptops had expandable RAM and storage. Nowadays, it seems like everyone is jumping on the
professional-grade upgrade-locked hardware hype train. Everything from Mac Minis, to DGX Spark, to the
recently announced RTX Spark: it’ll all be so good that it’ll be the last device you ever need.&lt;/p&gt;
&lt;p&gt;But is that really true? I want to use macOS on this device, but will that even be feasible a few years
from now? Is my W540 more well-positioned to outlast my M1 Pro Macbook? For being a decade-old device,
it’s still chugging along well enough to last me into the future. Even if I just used it as a desktop, it’s
doing the job right now I need it to do, and very well might for years to come. The Linux Mint upgrades will
likely keep flowing indefinitely, and as long as the support exists, I’ll likely be able to use Mint on this
PC for the foreseeable future, and if not Mint, then whatever other successful Linux distribution exists
at the time. I’ve heard lots of good things about Omarchy…&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I’m still really heavily embedded in the Apple ecosystem, and my M1 isn’t going anywhere soon, but as far
as future PC purchases go, I think I might end up prioritizing repairability a lot more than I currently
do. The idea of having computing devices that can potentially withstand the test of time is something that
is becoming more appealing to me as time goes on, especially as I begin to realize how much time is a factor
in how long all of my devices will actually last.&lt;/p&gt;</content:encoded></item><item><title>I Used ChatGPT to Edit a Pokemon Save File</title><link>https://jvarness.blog/nerdery/pokemon-gold-chatgpt-egglocke-1/</link><guid isPermaLink="true">https://jvarness.blog/nerdery/pokemon-gold-chatgpt-egglocke-1/</guid><description>I tried using ChatGPT&apos;s Agent Mode to create a Pokemon Gold save for an Egglocke. The results were... interesting.</description><pubDate>Wed, 18 Feb 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Pokemon is one of my favorite video game series ever. Aside from Generation 4, I’ve worked
my way through each of the different regions in the mainline Pokemon games. Avid Pokemon fans
might resent me for this… But I’ve never actually finished a playthrough of Platinum or HG/SS.
Can I still call myself a true fan if I haven’t done that? I’ll let you be the judge.&lt;/p&gt;
&lt;p&gt;For today, I wanted to post about something I’ve been experimenting with recently. Streamers who
play Pokemon games find many fun ways to play this 30-year-old game series, many of whom adapt
the Nuzlocke format in order to make runs more challenging and/or interesting. One format that I
always thought was interesting was the Egglocke: a format where a save file is customized with a
collection of eggs, many generated by followers or friends of the streamer. The spirit of a Nuzlocke
still exists in this format: you catch a Pokemon in every new route you visit, but instead of keeping
that Pokemon, you grab an egg from your boxes and you release what you caught. That’s what makes
it an “Egg”locke.&lt;/p&gt;
&lt;p&gt;I’ve always liked the idea of this type of run before! Every Pokemon game limits your collection
to the species of Pokemon that you have access to as the game progresses. In Generation 2, there
are also some Pokemon that were brand new to the series that you could &lt;em&gt;only capture in the postgame content&lt;/em&gt;.
No Houndour, Larvitar, or Murkrow without beating the Elite Four first. What if you had a chance to
use one of these Pokemon earlier in the game though?&lt;/p&gt;
&lt;p&gt;For a while, I sort of gave up on the idea of doing an Egglocke in any of the games. Not because
I didn’t think it would be fun or interesting, but because… Well… The setup would be arduous:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I’d have to have two copies of the game, two consoles, and a link cable. Not exactly cheap.&lt;/li&gt;
&lt;li&gt;I’d have to get far enough in one of the games to gain access to most of the Pokemon I would want to use.&lt;/li&gt;
&lt;li&gt;In that same game, I’d have to then &lt;em&gt;breed&lt;/em&gt; all the Pokemon eggs, which is not a fast process.&lt;/li&gt;
&lt;li&gt;I’d have to get far enough in the &lt;em&gt;other&lt;/em&gt; game to catch enough throwaway Pokemon to trade the eggs over.&lt;/li&gt;
&lt;li&gt;I’d have to then link together both games, trade 5 eggs over at a time, until all the eggs I bred were transferred.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;😀&lt;/p&gt;
&lt;p&gt;Then I’d be able to start playing the game!&lt;/p&gt;
&lt;p&gt;🥲&lt;/p&gt;
&lt;p&gt;By the time I’d be done with all that, I would have a couple dozen hours into one game, a couple more hours
into another, with one of the games basically completed. Gold and Silver are basically the same game, and
while Crystal does have some major content differences, it’s mechanically the same game with the same
characters and everything. It would be a pretty big waste of time to have to do all that setup in one
game just to play a different game in a similar way.&lt;/p&gt;
&lt;p&gt;Plus: there’s no randomness involved! If I’m the one breeding all the Pokemon, I already know what each
egg &lt;em&gt;could&lt;/em&gt; contain instead of it being a surprise. That’s one of the big things that makes a Nuzlocke
fun: you can’t predict which Pokemon you’re going to encounter, and you have to make due with what you
get. I could try modifying a save file from my Analogue Pocket using PkHex, but I’ve got two major
problems standing in my way with that: 1. I don’t have a Windows PC anymore after they prevented many
Windows 10 laptops from upgrading, and 2. there’s still not element of surprise if I’m choosing the
eggs that get added.&lt;/p&gt;
&lt;p&gt;For a while, I gave up on the whole idea.&lt;/p&gt;
&lt;p&gt;But then I got a ChatGPT subscription 😎&lt;/p&gt;
&lt;p&gt;You know what you can use in ChatGPT with a subscription?&lt;/p&gt;
&lt;h2 id=&quot;agent-mode&quot;&gt;Agent Mode&lt;/h2&gt;
&lt;p&gt;I used ChatGPT Agent Mode briefly a couple of times before this, but before I get into how I used it,
let me explain the difference between Agent Mode and some of the other modes you may be familiar with.&lt;/p&gt;
&lt;p&gt;ChatGPT has several modes you can use for various tasks. It’s got a Web Search mode that will literally
Google that for you: it’s pretty useful if you want to ask ChatGPT something but you want it
to use context from the internet to provide a more accurate and informed answer. Deep Research allows
you to present ChatGPT with a research topic that you want it to investigate and give you a detailed
report on. In the past, I’ve used Deep Research mode to do market research on potential app ideas.
It’s saved me a lot of time not developing something that already exists or isn’t viable. Deep Research
is a lot like Web Search, except it’ll go much more in-depth and work for significantly longer than
it will in Web Search mode. Create Image mode is capable of either creating an image from thin air,
or it can also edit existing images based on a prompt.&lt;/p&gt;
&lt;p&gt;It’s also got a couple other modes I haven’t used as much like Study and Learn mode and Shopping mode,
but the real star of the show here is Agent Mode.&lt;/p&gt;
&lt;p&gt;See, in the other modes I’ve mentioned, ChatGPT relies mainly on web searches to provide you with
results and information. You ask it something in a textual form, it gives you textual responses,
summarizes information, etc. It doesn’t really &lt;em&gt;do&lt;/em&gt; much apart from giving you walls of text
to read.&lt;/p&gt;
&lt;p&gt;Agent Mode is &lt;em&gt;very very different&lt;/em&gt;. In Agent Mode you can give ChatGPT various files and other kinds
of context, and it will perform work within a virtual Linux environment to complete various tasks.
It will perform web searches as it needs to, it’ll use Python scripts or other Linux utilities to
modify files, it’s fun watching it work! The only other time besides the current subject I’ve actually
used Agent Mode was when I was asking ChatGPT to create a holiday-themed letter, and it… Did ok for
the most part 😅&lt;/p&gt;
&lt;p&gt;In using Agent Mode, it hit me: what if I asked ChatGPT to help me create a save file for an Egglocke?
Well I asked it if it could! But… It couldn’t.&lt;/p&gt;
&lt;h2 id=&quot;guardrails&quot;&gt;Guardrails&lt;/h2&gt;
&lt;p&gt;I started out just asking ChatGPT if it could just… Generate a save file for me. Not the ROM, just
a save file.&lt;/p&gt;
&lt;p&gt;Turns out, there’s several reasons why ChatGPT can’t do that, many mostly being legal, but also
from a technical perspective. Save files for Pokemon games are very complex, the data for each Pokemon
is very unique to the game, the player’s progress, and data generated at the start of the game. From a
technical feasibility standpoint, it would be very difficult to just create a file that could be dropped
into a game.&lt;/p&gt;
&lt;p&gt;From a legal standpoint, creating a save file from thin air would be considered creating a derivative
work of Pokemon, which would land you in hot water with Nintendo. ChatGPT specifically has guardrails
in place that would prevent any of it’s models from generating any kind of content that would violate
copyright or other intellectual property laws.&lt;/p&gt;
&lt;p&gt;So I couldn’t have it create a save file for me… But… What if I… &lt;em&gt;Gave it one&lt;/em&gt; to use?&lt;/p&gt;
&lt;h2 id=&quot;attempt-0&quot;&gt;Attempt 0&lt;/h2&gt;
&lt;p&gt;Using my Analogue Pocket, I was able to grab the save file for Pokemon Gold, and then I was able to
send it off to ChatGPT’s Agent Mode! This was the first prompt I tried:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;This file I&apos;ve attached here is a Pokemon Gold save file.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;I want you to create a save file that will allow me to do what is called an Egglocke: I want you to generate 30 eggs at random that I can hatch after I catch a pokemon on a route in Pokemon Gold. Here are the conditions for the generation:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;- Only generate first-stage pokemon in the eggs: no evolved forms of any pokemon. For example, Charizard should not be allowed, but Charmander could be; Kingdra is not allowed, but Horsea could be, etc.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;- Do not put legendary pokemon in the eggs, so no Mewtwos or Mews or anything of that sort&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;- Make one of the eggs contain a shiny pokemon. Do not generate more than 1 shiny.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;- Put all pokemon eggs you generate this way into boxes 2 and 3&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In Agent Mode, it browsed the web and used various CLIs and Python scripts in order to edit the file,
and once it finished up I was able to load that save file into my Pocket, and I was actually really
surprised with the results!&lt;/p&gt;
&lt;p&gt;I really wish I had actually saved what it had generated and taken a few screenshots, but I wasn’t
thinking about making a blog post about this at the time… Sad day for me. In this save file, I was in
Cherrygrove City, the second city in Johto the player encounters. When I went to the Pokemon Center and
opened my boxes, I was plesently surprised to see that ChatGPT did in fact generate 30 eggs! I was
elated!&lt;/p&gt;
&lt;p&gt;… Until I hatched one of the pokemon. It was a Geodude.&lt;/p&gt;
&lt;p&gt;“Oh but Jake”, you’re thinking, “Geodude isn’t that bad, you’re overreacting, go to Violet City and
defeat Falkner!”. And normally you’d be right. But it being a Geodude wasn’t the issue. The issue
was that it was a level 1 Geodude. A level 1 Geodude that didn’t have any moves. It didn’t know
Tackle or Defense Curl. I didn’t even bother checking to see which Pokemon in my boxes was shiny
at that point, I just knew that there wasn’t any way I was going to be able to continue on this
file if I was only going to be hatching Pokemon that didn’t know any moves.&lt;/p&gt;
&lt;p&gt;So I gave it the same save file, but told it:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;I want you to do the same thing to this file, except:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;- The pokemon you generate can&apos;t have no moves: that&apos;s going to corrupt the save file. The pokemon when they hatch should hatch with the moves they normally would if they were to hatch under normal conditions in the game.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;- Make the EVs/IVs random: don&apos;t make all of them completely 0. Obviously for the shiny you&apos;re constrained, but for all the other ones don&apos;t make them all 0.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;- This is a fresh save file. I want you to fill up the first two boxes with eggs now, not just 30.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;attempt-1&quot;&gt;Attempt 1&lt;/h2&gt;
&lt;p&gt;I went back to Cherrygrove City and opened my boxes and I hatched my first Pokemon: a Sandshrew!
But this time, it actually knew some moves! But… It was also still at level 1. I was able to
switch-train it up to level 5 and start my journey!&lt;/p&gt;
&lt;p&gt;I made it to Azalea Town where the second gym badge is. All the other eggs I hatched up until
that point pretty much met my expectations: they were all first-stage Pokemon, no legendaries,
but they were all still at level 1.&lt;/p&gt;
&lt;p&gt;But then, I hatched a couple other Pokemon and something… Weird had happened. I got a Vulpix
and a Nidoran. These two, unlike the previous eggs, hatched at Level 5. I thought that was a
little strange at first, but I didn’t realize how strange it was going to get:&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;#x22;src&amp;#x22;:&amp;#x22;lvl-5-vulpix-0-exp.png&amp;#x22;,&amp;#x22;alt&amp;#x22;:&amp;#x22;A screenshot of the stats screen of Vulpix at Level 5 in Pokemon Gold&amp;#x22;,&amp;#x22;index&amp;#x22;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;See how Vulpix has 0 EXP? Even though it’s level 5? Turns out that’s not good. Pokemon pretty much
always hatch with exactly the amount of EXP they would to have at the level they hatched at. However,
Vulpix was at level 5 here with 0 EXP. What ended up happening here is that when Vulpix gained any
amount of EXP, it leveled “up” to level 2. How? By leveling all the way up to level 100 first, then
resetting back to 1, then 2. I ended up with a level 2 Vulpix that had a cracked moveset for the
second badge:&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;#x22;src&amp;#x22;:&amp;#x22;stacked-vulpix.png&amp;#x22;,&amp;#x22;alt&amp;#x22;:&amp;#x22;A screenshot of Vulpix at Level 2 in Pokemon Gold that knows Flamethrower and Confuse Ray&amp;#x22;,&amp;#x22;index&amp;#x22;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;I decided that what I’d do from this point on is if I encounter a bug or glitch like this, I’d
make ChatGPT generate a new save and try again.&lt;/p&gt;
&lt;p&gt;This time around though, I did actually pop the file into &lt;a href=&quot;https://pkhex-web.github.io/&quot;&gt;PkHex Web&lt;/a&gt; and
I did examine the boxes and everything. Interestingly enough, it had a couple duplicate pokemon in there,
and it also had no baby Pokemon or Pokemon that didn’t evolve. The Pokemon all appeared to also start at level
1 like the other Pokemon I had hatched.&lt;/p&gt;
&lt;p&gt;And the shiny Pokemon? None other than Geodude. I’m starting to think Geodude may be ChatGPT’s favorite Pokemon.&lt;/p&gt;
&lt;h2 id=&quot;attempt-2&quot;&gt;Attempt 2&lt;/h2&gt;
&lt;p&gt;So I decided the night that I was typing this whole post up that I wanted to have ChatGPT try once more to generate
the eggs. This time I fed Agent Mode THIS prompt:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;This file I&apos;ve attached here is a Pokemon Gold save file.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;I want you to create a save file that will allow me to do what is called an Egglocke: I want you to generate eggs at random that I can hatch after I catch a pokemon on a route in Pokemon Gold. Here are the conditions for the egg generation:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;- Only generate either first-stage pokemon, or pokemon that can&apos;t evolve in the eggs: no evolved forms of any pokemon. For example, Charizard should not be allowed, but Charmander could be; Kingdra is not allowed, but Horsea could be; Pichu is ok, but Pikachu shouldn&apos;t be because it evolves from Pichu; Miltank, Skarmory, and Tauros don&apos;t evolve, so that can be placed in an egg, etc.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;- Do not put legendary pokemon in the eggs, so no Mewtwos, Mews, legendary dogs/birds, or anything of that sort&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;- Make one of the eggs contain a shiny pokemon. Do not generate more than 1 shiny.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;- Fill the first two boxes with the pokemon eggs you generate.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;- The pokemon you generate can&apos;t have no moves: that&apos;s going to corrupt the save file. When the pokemon hatch, they hatch should hatch with the moves they normally would if they were to hatch under normal conditions in the game.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;- Make the EVs/IVs random: don&apos;t make all of them completely 0. Obviously for the shiny you&apos;re constrained, but for all the other ones don&apos;t make them all 0.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;- Each pokemon should hatch at level 5. This is Generation 2, so each pokemon needs to hatch with the correct amount of EXP to make it a level 5 pokemon.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Pretty reasonable prompt I’d say, except… I didn’t exactly read the output from ChatGPT. One of the things it
said was:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Experience and levels: Each Pokémon’s EXP was set to a value appropriate for level 5 (100, 125, 135 or 156 depending on growth group) so they hatch at level 5. This matches the experience thresholds for the Gen II growth formulas (e.g., medium fast uses n³ = 125 and slow uses 5n³/4 = 156).&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now this isn’t incorrect for ChatGPT to say: these EXP values are exactly what you’re supposed to have for newly
hatched pokemon starting out at level 5. This isn’t really important until I show you what I got when I hatched the
first egg from this new save file. What I &lt;em&gt;didn’t&lt;/em&gt; read, however, is that ChatGPT thought that it should
infer what &lt;em&gt;moves&lt;/em&gt; a Pokemon was supposed to have when it eventually hatched:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Move sets: Each egg’s move list contains Tackle (ID 33), Growl (45), Quick Attack (98), and Poison Sting (40). These moves are all early‑game moves (Tackle, Growl and Poison Sting appear in the low‑index move list, and Quick Attack is also an early‑level move), and Bulbasaur’s Gold/Silver learnset confirms that Pokémon normally have moves like Tackle and Growl before level 5. Assigning these ensures each egg has valid moves on hatching.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So you could imagine my surprise when I hatched my first egg and it was a Charmander! Charmander is a great
starting pokemon to have! Except… It didn’t know Scratch and Leer like it was supposed to know being level 5.
Instead it knew Tackle, Growl, Quick Attack, and Poison Sting.&lt;/p&gt;
&lt;p&gt;To my surprise, it also had like… 86 Million EXP points… But it was still somehow level 5? I was quite perplexed,
and since I wasn’t going to start using this file for obvious reasons, I decided to take a look at the other Pokemon
ChatGPT had generated for me.&lt;/p&gt;
&lt;p&gt;Every Pokemon in those eggs was Level 100, and knew Tackle, Growl, Quick Attack, and Poison Sting 🙃🙃🙃&lt;/p&gt;
&lt;p&gt;Not exactly what you want when you’re first starting the game! Or trying to finish the game for that matter!&lt;/p&gt;
&lt;p&gt;What I did appreciate though, is ChatGPT did &lt;em&gt;correctly&lt;/em&gt; generate a slightly more random set of Pokemon that
weren’t all just first-stage Pokemon: on examination of the save, there was Shuckle, Pinsir, and a few other
Pokemon that didn’t have evolutions in Generation 2. And there was a Geodude, but this time it wasn’t shiny
and it did have moves. Instead I had a shiny level 100 Growlithe that knew Tackle, Growl, Quick Attack, and
Poison Sting!&lt;/p&gt;
&lt;h2 id=&quot;for-next-time&quot;&gt;For Next Time&lt;/h2&gt;
&lt;p&gt;Overall, I’ve really enjoyed using ChatGPT for something fun as opposed to productive. At the time
of writing this, I’m working on a new prompt, and I’m going to start Attempt 3. Hopefully I don’t fail, and
hopefully Agent Mode doesn’t fail me either!&lt;/p&gt;
&lt;p&gt;A couple of closing thoughts that I did have after experimenting:&lt;/p&gt;
&lt;p&gt;Pokemon save files are definitely complex little pieces of binary data: even with some sort of “template”
to go off of, even AI still has issues generating binary data with any amount of integrity. I’ve seen posts
online about coding agents eventually modifying the straight binary files instead of writing code, and
after seeing what Agent Mode does to a save file… I’m not convinced AI is anywhere close to that.&lt;/p&gt;
&lt;p&gt;This does make me wonder though: I’m using ChatGPT Agent Mode to modify the save file. What if I were to
use a CLI agent like Codex instead? Would I be able to have it modify the file in such a way that the data
integrity is sound? Would it actually do better than ChatGPT’s Agent Mode?&lt;/p&gt;
&lt;p&gt;I’ll definitely explore that another time, but until then, I hope you found this to be an entertaining
read, and if you have questions or comments about this little experiment, feel free to reach out to
me on my socials at the bottom of the page!&lt;/p&gt;
&lt;p&gt;Happy hunting, folks.&lt;/p&gt;</content:encoded></item><item><title>Reflections on Agentic Coding</title><link>https://jvarness.blog/software-engineering-in-2026/</link><guid isPermaLink="true">https://jvarness.blog/software-engineering-in-2026/</guid><description>How agentic coding is transforming the way I work</description><pubDate>Sat, 17 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;2025 went out with a bang in the world of software engineering. Coding agents like
Claude and Codex and Copilot and the recently viral OpenCode have transformed the way
engineers work on a daily basis. Prior to 2024, AI was more of a joke than a tool
people took seriously. I myself remember working as an engineer in 2024 and &lt;em&gt;barely&lt;/em&gt;
using ChatGPT to solve some problems in languages and tools I wasn’t as familiar with,
asking it what problem space I was in and seeing if it could solve tricker problems for
me. I primarily used VS Code to write all my code, and it was still me actually writing
it. No tab complete. No AI agents. Just good ol fashioned ass-in-seat, hands-on-keyboard
coding.&lt;/p&gt;
&lt;p&gt;Towards the beginning of 2025 however, I started to adopt Github Copilot into my
coding tasks. It pretty much all started out as just using tab-complete to write
code and tests. I wasn’t really delegating or handing off tasks to it, more so
allowing the tab-complete to save me some time and effort, while watching it be
kind of correct some of the time, making manual adjustments, and coming up with
something that worked well.&lt;/p&gt;
&lt;p&gt;Throughout 2025, I slowly started adopting agentic coding. First, I started out
using Windsurf’s SWE-1 model within Cascade to generate code changes and files
that I needed. It worked ok, but I found that a lot of the time I needed to go
in and do some pretty significant rework of a lot of the stuff it generated in
order for it to be ready. Granted, I was a lot worse at prompting around this
time too, so it was probably just as much a reflection of my own skill using
agents as it was the agent itself.&lt;/p&gt;
&lt;p&gt;Even with the rework, I was still finding in-editor coding agents to provide
a decent productivity boost: I couldn’t fully trust the work, but I was finding
the models capable of getting me around 70% of the way there, and it was still a
lot faster than me writing it out by hand, telling VS Code to make me new files when
I needed it to, copy-pasting test files and tab-completing them until they passed…
AI was becoming more of a companion than ever.&lt;/p&gt;
&lt;p&gt;Throughout the summer and going into fall, as Claude Code gained more popularity,
I started trying to figure out if it was possible for me to use open-source and
free models locally as an alternative to paying any AI subscriptions. As it turns
out, running LLMs locally is really challenging and resource-intensive. I started
to realize that as nice as my M1 Pro with it’s 16 GB of RAM really is, it was
nowhere near enough hardware to run any good LLM locally.&lt;/p&gt;
&lt;p&gt;October was really where I caved: I needed to understand what all the agentic
coding hype was all about, and that’s when I did some research using ChatGPT and
Claude to figure out which offering was better: Claude Code or Codex. In retrospect,
I made the right decision to use Codex as opposed to Claude. Reddit in recent months
has been blowing up with posts about how bad Claude has been working for them:&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;#x22;src&amp;#x22;:&amp;#x22;./claude-ai-reddit-1.png&amp;#x22;,&amp;#x22;alt&amp;#x22;:&amp;#x22;Reactions to Claude Code at the start of 2026&amp;#x22;,&amp;#x22;index&amp;#x22;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;#x22;src&amp;#x22;:&amp;#x22;./claude-ai-reddit-2.png&amp;#x22;,&amp;#x22;alt&amp;#x22;:&amp;#x22;More Reactions to Claude code in 2026&amp;#x22;,&amp;#x22;index&amp;#x22;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;Meanwhile, I’ve been using Codex 5.X models for a few months, and I have really
enjoyed using them. I haven’t really many, if any, issues with how the models work.
In projects using technologies like NPM that I’m very familiar with, it’s been a
great companion. In projects that use technologies I’m not nearly as familiar with,
like iOS development, agents have been able to help me go from having 0 code written
up, to having something workable and iterable within a matter of hours. The skills
that I lack are what these coding agents are able to help me make up for in my overall
skillset as an engineer.&lt;/p&gt;
&lt;p&gt;What I do notice, however, is how much these models really end up being more of an
&lt;em&gt;extension&lt;/em&gt; of me as opposed to being an omipotent being of infinite knowledge. One
fairly discreet example is how models approach creating great UI/UX. I will be the
first person to admit that I am nowhere near the best at creating intuitive and
friendly user experiences. I do know how to work off of mock-ups and discreet designs,
and I can be an amazing partner to any UX designer. However, it would take me more
time to create great user experiences without the help of a designer or a design
system to work off of, agent or not.&lt;/p&gt;
&lt;p&gt;I’m sure if I was better at crafting wonderful user experiences, I could tell
an agent what I wanted and how to accomplish it. Heck, even if I was able to create
a good mock-up or two myself, I could ask Codex to work off of a
&lt;a href=&quot;https://developers.openai.com/codex/workflows#prototype-from-a-screenshot&quot;&gt;screenshot of a prototype&lt;/a&gt;.
I didn’t even know until very recently that Codex was even capable of this!&lt;/p&gt;
&lt;p&gt;Along the way, there are some tips and tricks that I’ve learned that either you’re
going to read and say to yourself “wElL dUh, tHis iS ObvIoUs” or “huh, I haven’t
considered that before, maybe I will now”. Hopefully these will be useful to you:&lt;/p&gt;
&lt;h2 id=&quot;context-matters&quot;&gt;Context Matters&lt;/h2&gt;
&lt;p&gt;Providing your tools with as much context as possible is going to always yield
better results in the long run, whether you’re working with existing or new code.
I have yet to fully adopt planning mode in a lot of agents because… Well, frankly
I find it more useful to just give it a list of instructions and functionality that
I want. I think if I actually wanted help with actually planning out a new project,
I’d likely try it, but more often than not I usually have a pretty good idea of what
I want the agent to work on. I’ll typically list everything out that I want and
allow the agent to iterate on it.&lt;/p&gt;
&lt;p&gt;For example, if I was going to create the internet’s favorite CRUD starting project,
a TODO app, I’d likely start building the app by using my framework of choice’s Getting
Started guide to create a scaffold. I’ll explain in the next section why I might do
this. So I might start out using &lt;code&gt;npx create-next-app&lt;/code&gt;, just as an example, if I wanted
to use Next.js. Depending on what else I think I might need, like Auth, a DB, and styling,
I might also go and do some research to see what else I could take advantage of to speed
up development. Tailwind and Supabase are two pretty popular options, so I might craft up
a prompt telling the agent what I want the app to do, and what I want it to use to
accomplish my goals:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&gt; I would like to create a small project that will display a web page that shows a list of TODOs:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;* The app&apos;s landing page should prompt the user to login if they haven&apos;t already. There should also &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;be a button prompting them to sign up if they do not have a login.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;* Once logged in, the user should see their list of things to do. If they don&apos;t have anything, &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;write a motivational message encouraging them to start adding things.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;* Allow the user to add something to do, and for each list item, allow them to click it to navigate &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;to a page where they can update the item with more details.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;* Allow them to put a due date, a more detailed description, a priority, and an emoji that will display &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;on the TODO list next to the item.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;* On the TODO list page, allow the user to mark items complete. When they mark an item complete, display a &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;confetti animation. Keep completed items at the bottom of the list.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;* After 30 days, archive completed and deleted items from the list and keep them in a separate &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;section of archives where they can see them, but not interact with them.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;* Allow the user to sort the list by due date, priority, and alphabetically.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;I want you to use Tailwind for styling, react-icons for any icons you might need, assume that this app will be deployed on &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Vercel using Next.js, and use Supabase for Auth and DB.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This all assumes that you have a good idea of what you want your architecture to look like,
and you know what services you want to take advantage of. If you don’t, the other thing you
could do is use a combination of ChatGPT chat and deep research modes to perform an
analysis of what services might be a good fit based on what your requirements are. Both
ChatGPT and Claude offer research modes in their chat clients if you have a subscription
that allows you to use their coding agents too.&lt;/p&gt;
&lt;h2 id=&quot;keeping-existing-tooling-in-context&quot;&gt;Keeping Existing Tooling in Context&lt;/h2&gt;
&lt;p&gt;One thing I continue to find is that in some instances, coding agents don’t quite
understand that some source-controlled code is auto-generated by means other than
agentically, or that there are standard tools that frameworks provide to generate
necessary code, files, and configuration. This could either be in the form of
those tools existing at the beginning stage of a project, or during the development
of a project.&lt;/p&gt;
&lt;p&gt;In instances such as this, I tend to lean on using existing tooling first to
generate a scaffold, then turn to the agent to help with finite business logic.&lt;/p&gt;
&lt;p&gt;As an example, I’ve been using &lt;a href=&quot;https://www.openapis.org/&quot;&gt;OpenAPI&lt;/a&gt; for years
to help generate API specifications for my RESTful services, as well as to
generate clients. I’ve found that in some instances, rather than using OpenAPI
command-line APIs to generate a client, it tends to want to modify the client
as if it’s a hand-written file, as opposed to using other commands to generate
clients based on a spec.&lt;/p&gt;
&lt;p&gt;Another example: whenever I’m starting a new project, I notice that if I use
the agent to actually create the project scaffold, sometimes it ends up creating
something that is out of date, or it tries to create a project that under normal
circumstances is incomplete.&lt;/p&gt;
&lt;p&gt;In cases such as these, I may interrupt an agent in order to use existing tooling,
then turn it loose to help with the rest. Either that, or I’ll give it more explicit
instructions:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&gt; This repository contains a client package that is generated using OpenAPI. I&apos;ve &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;pulled down the latest spec. Use `npm run generate:client` to generate the client &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;package, then use `npm run build` to ensure that all the rest of the code still &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;compiles.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Adding this kind of tooling to your repo’s instruction files (like &lt;code&gt;AGENTS.md&lt;/code&gt; or a
similar file) can help with ensuring your agents have context to what kinds of tools
it should use for certain tasks. Balance this with the time it takes you to just run
these tools yourself of course, but if you’re running a lot of these commands, it may
behoove you to teach the agent to use them instead.&lt;/p&gt;
&lt;h2 id=&quot;one-shotting-using-mentions&quot;&gt;One-Shotting Using Mentions&lt;/h2&gt;
&lt;p&gt;Agents fairly often might just try to generate code using practices that the underlying
model has been trained on. For many teams, this isn’t always the desired behavior.
Sometimes a long-established pattern or practice is what is desired over whatever the
model thinks is best.&lt;/p&gt;
&lt;p&gt;Let’s say you’re working on a RESTful service, and you want to use an agent to help you
add some new functionality to it. There are already some well-established patterns for
breaking down how the code is structured from the routing, down to how the data model
is built. You might have a prompt like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&gt; I need a new set of endpoints built out to help manage TODOs in this service:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;* Create CRUD endpoints for all the TODOs.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;* Create a data model for the TODOs that relates many TODOs to one user.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Every online course that teaches you how to use Generative AI teaches the
concept of zero-shot, one-shot, and few-shot prompting. The above prompt is an
example of a zero-shot prompt: you’re telling the model what you want, and you’re
going to let it decide how it does it. You’re not providing any examples of
existing code.&lt;/p&gt;
&lt;p&gt;Will this produce code that works? Possibly. Will the code follow best practices
that are present in the repo? Probably not. The model is very likely to yolo in
what you’re asking for without giving a second thought to everything else around
it. It very well might miss important considerations like security, telemetry,
and performance optimizations already present in other parts of the code.&lt;/p&gt;
&lt;p&gt;You can help aid the model by providing it with more context in the form of a
one-shot or few-shot prompt using file mentions. File mentions allow you to refer
to existing code in your instructions. By adding mentions to a prompt, you’re
turning your existing zero-shot prompt into a one- or few-shot prompt, contextually
providing examples that the model can leverage to generate better results. The
above prompt might change to:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&gt; I need a new set of endpoints built out to help manage TODOs in this service:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;* Create CRUD endpoints for all the TODOs. See @src/api/controllers/foobars.controller.ts &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;for an example of how to create a controller for TODOs. Ensure you add all the same &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;logging and security annotations to the controller methods that are present in the &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;foobar controller to the new one.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;* Create a data model for the TODOs that relates many TODOs to one user. We use Prisma &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;for our ORM, so I&apos;d recommend adding the new schema to @src/prisma/schema.prisma &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;and running `npx prisma generate` to generate the new model. Ensure that the model has &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;row-level security built-into it, like we did with the foobar migration: @src/prisma/migrations/20250116000000_add_all_teh_foobars/migration.sql&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Zero-shot prompts, I have found, are really not as useful if I’m working with an existing
codebase with well-established patterns and practices. If you want the model to be more
creative in how it solves a particular problem, zero-shotting may be a better route to
take, otherwise it might try too hard to use the context provided from a few-shot prompt.&lt;/p&gt;
&lt;h2 id=&quot;dependency-upgrades&quot;&gt;Dependency Upgrades&lt;/h2&gt;
&lt;p&gt;Technical debt still runs rampant in many organizations. Outdated dependencies are
not only ticking time bomb for security vulnerabilities, but as dependencies evolve,
they become beneficial for your end-users in the form of added stability, performance,
and features.&lt;/p&gt;
&lt;p&gt;You know what really sucks about outdated dependencies though? Especially in Node projects?
Updating all of them. I thought updating dependencies in Java was a pain whenever I was
knee-deep in Maven dependency hell. I still to this day &lt;em&gt;hate hate hate&lt;/em&gt; updating any
frontend Node project dependencies, because pretty much everything is bound to break
when you do. Agents, though, are able to iterate on upgrades, linting, building, and
test runs until everything just works™️.&lt;/p&gt;
&lt;p&gt;In many projects, I’ve asked agents to help upgrade dependencies while ensuring that
all of my quality checks still pass. For example, earlier today I asked Codex to
upgrade all the dependencies for my blog:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;If you were to run `npm outdated` you&apos;ll notice that several dependencies in this project are outdated. Please upgrade the &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;dependencies in here to the latest for each, ensuring that everything will compile still by the end using `npm run build`.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Recently, the company I work for also went through a rebranding, which meant
that our design system also went through a pretty drastic change. I had gone through
and updated one of our core component libraries to match this new design system and
include updated branding. As part of this, I had also written documents regarding
upgrading from older versions of this library to the new one in the form of markdown.&lt;/p&gt;
&lt;p&gt;Normally, taking an app from an older version of this library to the new one would have
required a lot of manual rework of existing components that consumed that library. However,
I was able to migrate an older app to using a new version of this library using Claude
through Github Copilot CLI by copy-pasting much of the migration documentation I had written
into the prompt I had made to tell it to upgrade the other dependencies in the project.&lt;/p&gt;
&lt;p&gt;Claude, with a little bit of handholding, was able to upgrade the dependencies, as well as
use the context from the documentation I wrote to successfully migrate the app to utilize
the new branding and design within our core component library. I got a bit scared when it
started to think that it would be a good idea to temporarily disable the script we had that
used eslint to lint our code… But after a few more explicit prompts and guidance, it was
able to get the linting working again.&lt;/p&gt;
&lt;p&gt;For shared components and libraries, this recent experience made me realize just how important
documentation is to a project: if I hadn’t written any of those documents explaining how to
upgrade from an older version to the newer version, this process would have been a lot more
painful: Claude would have had to make more assumptions about the code and the libraries
than it had to previously, and likely would have ended up making more mistakes than it would
have without the documentation.&lt;/p&gt;
&lt;h2 id=&quot;tooling-preferences&quot;&gt;Tooling Preferences&lt;/h2&gt;
&lt;p&gt;Speaking of the good ol days of coding by hand: I remember while working at Cerner,
every dev and their mother had their preferences of IDEs/editors they swore by. All
the Rails folks used Sublime. Java devs were all split between IntelliJ and Eclipse.
.NET Devs didn’t even touch their code unless they had a license to Visual Studio
Enterprise. When teams started integrating Node into their codebases, everyone started
out using editors like Sublime or Atom until Microsoft released VS Code.&lt;/p&gt;
&lt;p&gt;I think what we’re seeing in the industry now with agents is akin to the days of
arguing which editors were supreme! There are people who swear by Claude Code, others
who only use Codex, and there are growing numbers of people who prefer to have access
to several models and agents through subscriptions to Github Copilot, Cursor, Windsurf,
or Antigravity.&lt;/p&gt;
&lt;p&gt;In deciding which agent I wanted to start using, I actually had Claude and ChatGPT
perform web research and sentiment analysis on which subscription might be better.
Considering all the responses that Claude and ChatGPT gave me, I ended up subscribing
to ChatGPT. Through continued use and experimentation, I’ve found that Codex not only
works well for what I want it to do, but I also find it behaving more efficiently than
other models have. The behaviors of how it executes really matters in terms of being
able to autonomously work towards “completeness”, and I’ve noticed that while the quality
of work that each model produces is pretty comparable, how each agent behaves can
vary greatly:&lt;/p&gt;
&lt;p&gt;Typically if I have a list of instructions or requirements that I want the agent to
follow, Claude and Codex tend to take very different approaches to completing things.
Pretty much every model will take my instructions and compile it down into a plan of
tasks that it wants to perform. It basically goes through it’s own little planning mode
before executing. No biggie.&lt;/p&gt;
&lt;p&gt;What &lt;em&gt;is an issue&lt;/em&gt; though is the continuity of execution: despite the model creating
it’s own plan of tasks, Claude tends to do one or more subsets of the plan and then
it just… Stops? It’ll complete some things and then just say at the end something
like:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;plaintext&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Ok, so here&apos;s all the stuff I did:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;// insert list of accomplishments&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span&gt;Whenever you&apos;re ready, let&apos;s move onto the other tasks that you&apos;ve asked me to do!&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But… But… But I do want you to do the rest of that stuff! I’m not ready &lt;em&gt;later&lt;/em&gt;,
I’m ready &lt;em&gt;right now&lt;/em&gt;! What do you think you’re doing? What’re you stopping for? The
biggest value-add of an agent is to delegate things that it can automatically do for
you so that you can spend more time on other things that it cannot. What’s with
stopping partway through and waiting for me to type &lt;code&gt;continue&lt;/code&gt; and hit Enter?&lt;/p&gt;
&lt;p&gt;I will say though: this is an issue that I’ve yet to run into with Codex. Codex as a
coding agent is pretty good at coming up with a plan and executing it continuously. In
contrast to my experience with Claude, I once asked Codex to generate some files for
me that hepled generate levels for a game I was working on. It created a script to
generate the levels instead, but what it did after that was pretty interesting: it
actually ran the script, which took several hours to execute, and verified the
results. I don’t believe I ever had to tell it to continue before.&lt;/p&gt;
&lt;p&gt;I will reiterate though that so much of my desire to continue using Codex over
Claude is &lt;em&gt;preference&lt;/em&gt;. I don’t think that Claude is inherently bad as far as
coding agent models go. In fact, from my usage of both, Claude can hold it’s own
against Codex in terms of quality and internal design. The best advice I can really
offer regarding preference is to just try out new models and agents and tools as
they become available, and see which ones work best for your workflow, use-cases,
and team.&lt;/p&gt;
&lt;p&gt;With how rapidly these models are evolving, the tools are changing and getting better
and easier to use, and how the industry continues to adopt them in new and innovating
ways, engineers will first and foremost keep their fingers on the pulses of the
industry to understand how these tools are changing and evolving and what is becoming
available. Secondly, they’ll need to have more fluid preferences than they previously
have had.&lt;/p&gt;
&lt;p&gt;I’ve used VS Code-based editors for nearly a decade. In contrast, I’ve used several
different coding models and agents. The code didn’t change. The frameworks and libraries
didn’t change.&lt;/p&gt;
&lt;p&gt;The tools changed. I’ve changed along with them.&lt;/p&gt;
&lt;p&gt;The tools will continue to change. I’ll continue to change along with them.&lt;/p&gt;
&lt;h2 id=&quot;buying-time-back&quot;&gt;Buying Time Back&lt;/h2&gt;
&lt;p&gt;Beyond the terminal, outside the editor window, and beyond your hard drive, there are
still other things as a software engineer that you’re responsible for. Design,
documentation, backlog grooming, code reviews, &lt;em&gt;&lt;strong&gt;yourself&lt;/strong&gt;&lt;/em&gt;, etc. The time you save
automating your coding work can be used to propel you in so many other ways.&lt;/p&gt;
&lt;p&gt;When was the last time you had an “and” project that you really thought would add
a lot of value to your organization? When was the last time you felt like you had any
time to actually dedicate to it? I know for a fact many of you out there probably have
something you want to learn more about. Take the time you aren’t coding to do the more
manual parts of your work, to learn or experiment with something new, to collaborate
with or provide mentorship for your colleagues, or read one of those books you bought
but never finished because you had too many features with approaching deadlines you
needed to ship.&lt;/p&gt;
&lt;p&gt;I talked about this in a previous post, but one thing you’ll need to make sure you do
is spend more of your time reviewing code. Not just other people’s code, but also the
code that you’re delegating to agents. I still fall into this trap and I have to keep
reminding myself that as good as some of these agents are getting, they still make
mistakes that could be resolved simply by reviewing the code and making a few edits
before sending it to the rest of your team.&lt;/p&gt;
&lt;p&gt;If you are working on something that might require changes across multiple codebases,
using agents is a great opportunity to delegate the changes to multiple agents to
coordinate changes across multiple repositories. If you have multiple tasks you’re
assigned across multiple repos, this is an even greater opportunity for delegation!&lt;/p&gt;
&lt;p&gt;The only thing I haven’t done yet is delegeting multiple sets of changes to the same
repository without having multiple copies checked out at once. If I figure out how to
do this while trusting an agent with &lt;code&gt;git&lt;/code&gt; access, I’ll share later 😅.&lt;/p&gt;
&lt;h2 id=&quot;thats-a-wrap&quot;&gt;That’s a Wrap!&lt;/h2&gt;
&lt;p&gt;Well that was a lot of thoughts I spewed for a Saturday. I hope you found some of this
helpful, interesting, thought-provoking, or garnered some other kind of positive reaction
from you. Wherever you are in your AI-fueled journey, I hope this post has motivated you
to continue to learn and develop your skills!&lt;/p&gt;
&lt;p&gt;If you have follow-up comments or questions and you made it this far into the
post without bouncing, you can always reach out to me on any of the social medias
at the bottom of the page!&lt;/p&gt;</content:encoded></item><item><title>Review Your (AI&apos;s) Code</title><link>https://jvarness.blog/review-your-ais-code/</link><guid isPermaLink="true">https://jvarness.blog/review-your-ais-code/</guid><description>AI is changing how we write code, and I&apos;m going to change how I approach code reviews.</description><pubDate>Fri, 15 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;It’s no secret that Generative AI has become a massive trend in software
development. My own experiences have evolved over time as tools have become
increasingly more powerful.&lt;/p&gt;
&lt;p&gt;Two years ago, everyone started out using ChatGPT as a replacement for
StackOverflow. I’d be lying if I said I didn’t use it to better understand Ruby
code (and to write some of it for me 🤣). We could copy/paste prompts into
a web interface with our code in order to make it write test cases for us.&lt;/p&gt;
&lt;p&gt;As time went on, the tools just kept getting better. I remember the first time I
used Github Copilot and I thought to myself “oh this is really cool”. Watching
those faint lines of code appear after things I type, the algorithm trying it’s
damndest to predict my next move, and having it come up with the right answer
sometimes, really started to show me how much more productive I could be with
these tools.&lt;/p&gt;
&lt;p&gt;Just when I thought the tooling couldn’t get better, I downloaded Windsurf and
started seriously using it. Yea yea, I know, Cursor is a thing, but I also use
Bulma instead of Tailwind for everything, ok? I go against the grain sometimes.
As I’m writing this post, I’m actually writing it in Windsurf. Don’t worry: I
didn’t have Windsurf write most of this for me. In fact: I’m not really sure I
can recommend using Windsurf to write a blog post for you. As I’m typing along
and watching Windsurf predict what I’m going to write, &lt;del&gt;it’s not as good as
predicting what I’m going to write. It’s not as good as
predicting what I’m going to write.&lt;/del&gt; you can see that those last few tabs
didn’t quite convey anything coherent with everything else I’m talking about,
and… For some reason it repeated itself?&lt;/p&gt;
&lt;p&gt;Beyond that though, Windsurf has been helping me immensely with work: I’ve been
using it to rapidly prototype projects that I’d normally only have on the back
burner, and automating more tedious tasks while taking time to review other
team members code or updating JIRAs or working on designs.&lt;/p&gt;
&lt;p&gt;However, one thing I have noticed in the work I produce using these tools is that
I tend to not take enough time to review whatever the AI model is creating. There
are sometimes bugs in the code that’s been generated, or typos, or something else
in the code is just not correct, and if I took a little more time to review it
before putting it up for review, I would be able to avoid a lot of the thrash of
receiving comments and addressing them.&lt;/p&gt;
&lt;p&gt;I had a bit of an experience like that this week, and it’s made me take a pause
regarding how I approach code reviews.&lt;/p&gt;
&lt;h2 id=&quot;how-i-used-to-approach-code-reviews&quot;&gt;How I Used to Approach Code Reviews&lt;/h2&gt;
&lt;p&gt;The first time I ever participated in a code review was when I was working for
Cerner back in 2014 in their DevAcademy training program for new hires. Code
reviews were a really big focus for all of us in training: it was the first time
that so many of our technical skills and communication skills were put to the test.
Do you want to be able to close a task out soon? Gotta get your code up for review.
Hope to ship that feature you’ve been working on all sprint? Go get them approvals.&lt;/p&gt;
&lt;p&gt;Code reviews for a long time have acted as a litmus test: you can’t close a task
if your code isn’t merged, and you can’t merge your code until you get all the
necessary approvals on your review(s), and you can’t get those approvals until
you address all the feedback. If it at least passes the vibe check with the rest
of the team, you’re good to go. There’s a lot of other quality gates teams can
put in place like test coverage and static analysis tools, but code reviews have
been the engineering team’s last line of defense to catch bugs before pushing
them to the rest of the business (QA, Security, Support, etc.).&lt;/p&gt;
&lt;p&gt;In the past, when I’ve put code up for review that simply wasn’t ready to be
shipped, it either came down to a lack of understanding of what problem I was
trying to solve, or it was more of a rushed job, and in either case, it became
obvious to myself and any other reviewers that whatever I put up wasn’t quite
“done” yet. Because of this, and for as long as I can rememeber, I &lt;em&gt;always&lt;/em&gt;
tried to ensure that I was &lt;em&gt;absolutely sure&lt;/em&gt; that whatever I was offering up
in a review was ready to be shipped &lt;em&gt;now&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;As I began to mentor new engineers throughout my career, that’s also the same
advice I gave them: if you want others to review it, you better make sure you’re
ready to ship it. If you wouldn’t ship it today without being completely
confident that it’s ready to go, don’t even put it up for review. Part of that
stemmed from the fact that there used to require a lot of manual effort to even
write the code to begin with, and that you as the author understood &lt;em&gt;what&lt;/em&gt; that
code was doing, and &lt;em&gt;why&lt;/em&gt; you chose to make certain implementation choices.&lt;/p&gt;
&lt;p&gt;I still stand by that advice, but I’ve come to realize that when I’m using AI
tooling to write code, I need to take more of my own advice.&lt;/p&gt;
&lt;h2 id=&quot;how-i-now-approach-code-reviews&quot;&gt;How I &lt;em&gt;Now&lt;/em&gt; Approach Code Reviews&lt;/h2&gt;
&lt;p&gt;What I’ve come to learn from using AI is that it’s the same as using any tool in
software development: you have to learn how to use it effectively. Some folks use
AI and they’re really great at getting their desired end-result from it. Others
take vibe-coding to an almost unhealthy level, simply trusting what’s generating
will work without reviewing the changes themselves.&lt;/p&gt;
&lt;p&gt;On the other side of that adoption spectrum, there are folks who outright refuse
to use AI tools, either due to skepticism that what they’ll get is awful, or
because they truly believe they are much better at writing code than AI is.&lt;/p&gt;
&lt;p&gt;What I find to be best for myself is to integrate AI tools into my daily coding
workflow, either when I get stuck on something, or if I want to save myself time
with creating files that AI can create based on documentation I created, or if I
want to go from nothing to POC on something as quickly as possible. Of course I’ll
have to clean things up myself later, and put all the proprietary knobs and bits
into the places I need them in, but I find that I’m able to accomplish a great deal
more with this little pair programmer on the side of my editor than I could if I
was researching and creating all of the code myself.&lt;/p&gt;
&lt;p&gt;But therein lies the issue: just because the tool made it doesn’t mean it’s
&lt;em&gt;ready for prime time&lt;/em&gt;. In more recent examples at work: I had it generate a bunch
of files for me based on documentation that I had the rest of my team reviewing
over the last week. It was able to do a decent job, but after I put up all the
files for review, I realized something:&lt;/p&gt;
&lt;p&gt;I didn’t really review any of the files myself, and in doing so I put a lot of
undue burden on other team members.&lt;/p&gt;
&lt;p&gt;I’d say the tools got me about 65-70% of the way there, but there were so many
little things I missed if I would have just taken the time to review it myself.
I could have gone in and manually edited each file to make sure each one was
correct. Heck, I probably could have told Windsurf what it had done wrong and
it might have gone and done it for me.&lt;/p&gt;
&lt;p&gt;What I’ve realized in using these tools is that my code review process needs to
change. I need to pair with my newfangled editor, not just let it take the wheel.
Each line and statement should be scrutinized, and not assumed to be correct.&lt;/p&gt;
&lt;p&gt;I’m realizing that I need to reverse the principle a little bit: with all the
time saved in implementing something, I need to dedicate a little more time to
reviewing the code &lt;em&gt;myself&lt;/em&gt; before it’s reviewed by others. After all, I’m still
trying to ship something, and if it’s not ready, someone else is gonna catch it,
and that’s not really fair to whoever that someone else is.&lt;/p&gt;
&lt;p&gt;There’s an entire tab in VSCode/Windsurf/Cursor that I’ve always had that allows
me to see git diffs of all the changes in the current working branch of code I’m
working on. I’ve literally never used it though, because most of the time I’m
using the Git CLI for everything. Some people might like using a visual client
for Git, but I can’t stand them. I find them much harder to use than the CLI.&lt;/p&gt;
&lt;p&gt;However, one thing that the CLI really lacks is a good way to quickly review
diffs of unstaged changes. Much like how we typically rely on Github or Gitlab
PRs/MRs to review code, I’m starting to realize that I should be picking through
diffs of what Windsurf is helping me write before I send it off to the rest of
the team. I think that little tab in the editor is going to start getting a lot
more use from me!&lt;/p&gt;
&lt;p&gt;So those are all my thoughts on how I’m going to start changing my workflow.
Windsurf has been an absolute pleasure to use, and I’m getting a ton of value
out of it, but no matter how fast I’m able to move with it, I’m realizing I
can’t speed up at the expense of slowing everyone else down.&lt;/p&gt;</content:encoded></item><item><title>Pellet Grill Pulled Pork</title><link>https://jvarness.blog/recipes/pellet-grill-pulled-pork/</link><guid isPermaLink="true">https://jvarness.blog/recipes/pellet-grill-pulled-pork/</guid><description>Delicious barbeque at home doesn&apos;t get any easier than this</description><pubDate>Sun, 17 Nov 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;#x22;src&amp;#x22;:&amp;#x22;./finished-pulled-pork.png&amp;#x22;,&amp;#x22;alt&amp;#x22;:&amp;#x22;A pork shoulder after having sat in a smoker for over 9 hours&amp;#x22;,&amp;#x22;index&amp;#x22;:0}&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;what-youll-need&quot;&gt;What You’ll Need&lt;/h2&gt;
&lt;h3 id=&quot;ingredients&quot;&gt;Ingredients&lt;/h3&gt;
&lt;p&gt;&lt;input type=&quot;checkbox&quot;&gt; 1 pork shoulder (a.k.a. Boston Butt)
&lt;br&gt;
&lt;input type=&quot;checkbox&quot;&gt; Approx. 1/4 cup yellow mustard
&lt;br&gt;
&lt;input type=&quot;checkbox&quot;&gt; BBQ Rub of your choice (see below for recommendations)&lt;/p&gt;
&lt;h3 id=&quot;optional-ingredients&quot;&gt;Optional Ingredients&lt;/h3&gt;
&lt;p&gt;&lt;input type=&quot;checkbox&quot;&gt; Rolls or buns to serve it on
&lt;br&gt;
&lt;input type=&quot;checkbox&quot;&gt; Sauce to serve on the side
&lt;br&gt;&lt;/p&gt;
&lt;h3 id=&quot;recommended-tools&quot;&gt;Recommended Tools&lt;/h3&gt;
&lt;p&gt;In order to precisely cook the pork to the desired temperature, it’s important that you have a meat thermometer.
Also, a pellet grill would be good!&lt;/p&gt;
&lt;h2 id=&quot;recipe&quot;&gt;Recipe&lt;/h2&gt;
&lt;ol start=&quot;0&quot;&gt;
&lt;li&gt;Calculate how long your pork shoulder will need to cook for, and ensure you will have enough time to cook it prior to starting. For every pound of meat, you should expect to smoke it for about 2 hours. The pork shoulder in my photos is about 4.5 lbs, and it took roughly 9 hours to cook thoroughly.&lt;/li&gt;
&lt;li&gt;30 minutes prior to when you need to start smoking the meat, take the meat out of the refrigerator, and start preheating your grill to 225 °F.&lt;/li&gt;
&lt;li&gt;Place your pork shoulder on a cutting board, with the fat cap side face-up. Use a paper towel to dry off the surface of the meat, then score the fat cap.
&lt;ol&gt;
&lt;li&gt;The best way that I’ve found to do this is to cut in only one direction (not a checkerboard style), 1 inches apart, and deep enough where your cuts are getting through where the fat cap meets the lean.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Rub the mustard into the pork shoulder, creating a thin layer of binder all around the meat, being sure to rub mustard in between the cuts. Then, generously sprinkle your choice of BBQ rub onto the pork shoulder, covering all sides of the meat.&lt;/li&gt;
&lt;li&gt;Insert a meat thermometer into the middle of the pork shoulder.&lt;/li&gt;
&lt;li&gt;Allow the meat to sit on the cutting board for 15-20 minutes while the smoker is preheating (this will allow the meat to warm up a little bit and for the seasoning to bind to the meat)&lt;/li&gt;
&lt;li&gt;Once the grill is preheated to 225 °F, transfer the pork shoulder to the center of the bottom rack of your grill, with the fat cap of the shoulder facing up.&lt;/li&gt;
&lt;li&gt;Smoke the shoulder for approximately 2 hours for every 1 lb of pork, or until the pork reaches an internal temperature of 195 °F.&lt;/li&gt;
&lt;li&gt;Remove the pork shoulder from the grill, and transfer it to some kind of dish with walls, like a glass baking dish or a disposable aluminum dish. Let it sit in the oven or microwave to rest for about 10 minutes.&lt;/li&gt;
&lt;li&gt;Shred the pork with a couple of forks inside of the dish it’s currently sitting in and enjoy!&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;#x22;src&amp;#x22;:&amp;#x22;./served-pulled-pork.png&amp;#x22;,&amp;#x22;alt&amp;#x22;:&amp;#x22;Pulled pork served on Hawaiian Rolls with a side of roasted potatoes&amp;#x22;,&amp;#x22;index&amp;#x22;:0}&quot;&gt;&lt;/p&gt;
&lt;h2 id=&quot;easy-simple-delicious&quot;&gt;Easy, Simple, Delicious&lt;/h2&gt;
&lt;p&gt;For Father’s Day a few years ago, I was able to get my first pellet grill, and one of the very
first things I ever smoked on it was a pork shoulder! It’s one of my favorite things to make on
a pellet smoker, because it’s a good beginner recipe for those who are new to smoking meat, and
it tastes great.&lt;/p&gt;
&lt;p&gt;If you follow the above recipe, you should be able to make a delicious dinner for several people,
and I also have a few other tips that can help you on your journey to making some of the best meals
of your life:&lt;/p&gt;
&lt;h3 id=&quot;look-at-me-im-about-to-touch-the-buuuuutt&quot;&gt;“Look at me! I’m about to touch the buuuuutt!”&lt;/h3&gt;
&lt;p&gt;Sorry, but I love that movie. Anyway, when you’re going to the store to pick out your cut, you’re
going to want for specific cuts of pork. The cut you’re looking for goes by a couple of different
names, the two main ones I’ve seen are a &lt;strong&gt;pork shoulder&lt;/strong&gt; or a &lt;strong&gt;Boston butt&lt;/strong&gt;. They are
essentially pork roasts with the fat cap still on.&lt;/p&gt;
&lt;p&gt;Picking out a pork shoulder with a decent fat cap is one of the keys to success. A common phrase
used by many pitmasters across America is “fat is flavor”, which makes plenty of sense: it’s common
to put butter on things like steaks to enhance the flavor of leaner cuts of meat, or to wrap
brisket in butcher paper and beef tallow after it reaches a certain point in the cook. Sometimes
what folks might do when they’re cooking a pork shoulder is towards the end of the cook (maybe
about an hour or two before the shoulder is done) they will add butter and brown sugar to the meat,
place it in a metal container and cover it with tin foil to be able to lock in moisture and reduce
the amount of flavor lost from the butter or rendered fat dropping into the bottom of the grill.&lt;/p&gt;
&lt;p&gt;Why didn’t my recipe include that as a step? Well… One of the other things I don’t typically like
to do anymore is trim the fat cap of my pork shoulder. I used to, but I realized I was either
cutting away too much fat, or that my pulled pork wasn’t as flavorful with that fat missing.&lt;/p&gt;
&lt;p&gt;The other thing you want to be wary of is how large your cut is, how long it will take to cook, and
how many people you’re looking to feed. Typically, I will pick out a 4.5 lb pork shoulder. If I
have that cut on the grill and cooking starting at 8 a.m., after about 9 hours of smoking, 15
minutes of rest time, and a few more minutes of shredding, I can easily have it ready to eat by
5:30 p.m.&lt;/p&gt;
&lt;p&gt;If you think each person you’re cooking for could eat half a pound of meat, that’s 9 people you
could feed without leftovers. My wife and I end up getting &lt;em&gt;plenty&lt;/em&gt; of leftovers out of this dish
since it’s usually us and maybe a couple other people who eat with us.&lt;/p&gt;
&lt;h3 id=&quot;its-all-in-the-preparation&quot;&gt;It’s All in the Preparation&lt;/h3&gt;
&lt;p&gt;Once you’ve got your cut of meat, you actually need to prepare it! I’m now very particular about
how I prepare my pork shoulder, and it’s through trial and error… Well… Maybe not error as
much as experimentation until I find what I like best.&lt;/p&gt;
&lt;h4 id=&quot;to-score-or-not-to-score&quot;&gt;To Score, or Not to Score&lt;/h4&gt;
&lt;p&gt;Do you &lt;em&gt;have&lt;/em&gt; to score the fat cap of your pork shoulder? Absolutely not. Do I heavily &lt;em&gt;heavily&lt;/em&gt;
recommend you do? Yes, and I have a particular way I like to do it and I have my reasons for doing
so:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The best way that I’ve found to do this is to cut in only one direction (not a checkerboard style), 1 inches apart, and deep enough where your cuts are getting through where the fat cap meets the lean.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;How did I arrive at the conclusion that this was the best scoring method? Like I said, I have
experimented many times with different scoring methods, including not scoring at all. Here are my
findings:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No scoring&lt;/strong&gt;: the meat towards the top of the fat cap is not as flavorful due to a lack of smoke penetrating that part of the meat, though the pork shoulder is quite moist.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bi-directional (checkerboard-pattern) scoring&lt;/strong&gt;: the meat towards the top of the fat cap has more smoke flavor, though the meat is a little less moist.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Scoring the meat in one direction at an angle (around 45 degrees, doesn’t have to be perfect) has
never failed me, and has produced the best tasting pulled pork.&lt;/p&gt;
&lt;h4 id=&quot;the-condiments-that-bind&quot;&gt;The Condiments That Bind&lt;/h4&gt;
&lt;p&gt;While smoke provides the greatest amount of flavor to your pork, there’s also another major factor
that can change the flavor profile, and that’s how you season the meat. I’ve tried a few different
barbeque rubs, and I have really grown to enjoy Meat Mitch WHOMP! Rub, Meat Church Honey Hog, and
there is a local barbeque place in Kansas City called Jack Stack that sells an all-purpose meat
and poultry rub that tastes great.&lt;/p&gt;
&lt;p&gt;The best part about picking a rub is how much it can change your cook: Meat Church Honey Hog is
a much sweeter rub, while something like Meat Mitch or Jack Stack would be much more savory. In
combination with the smoke from whatever your pellets of choice are, the flavor profile of your
cook can change.&lt;/p&gt;
&lt;p&gt;Before applying any seasoning, however, it’s important to apply a binder so that you don’t lose
any of the seasoning prior to putting the meat into the smoker. For the purpose of this cook, I
used mustard. It’s &lt;em&gt;perfectly ok&lt;/em&gt; to use mustard for this, or you can use something like mayo.
Mustard is not normally a condiment I would put on anything because I just… Don’t like it at all,
but what I can tell you is that if you don’t like mustard, don’t be afraid to use it as a binder. I
can’t taste any mustard once everything is said and done.&lt;/p&gt;
&lt;p&gt;I’ve also seen online where people will use things like sriracha as a binder too, but I can’t
guarantee whether or not that will change the flavor of your cook. Mustard and mayonnaise typically
don’t have a very strong taste, but something like sriracha absolutely does. Maybe I’ll try it one
day, who knows.&lt;/p&gt;
&lt;h3 id=&quot;sitting-and-waiting-and-sitting&quot;&gt;Sitting and Waiting and Sitting…&lt;/h3&gt;
&lt;p&gt;One thing you can be sure about during this cook is that there will be a lot of downtime, but at
each stage of the game, it’s very important to allow time to pass:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Before putting the meat into the smoker and after applying bindings and seasonings, it’s a good idea to allow your meat to “sweat” in order to allow the seasonings and bindings to stick to the meat.&lt;/li&gt;
&lt;li&gt;During the cook, it’s important to just allow the pork shoulder to sit in the smoker and not fuss with it too much. Some people like to spray apple cider or something onto their pork shoulder
every couple of hours, but I have found in doing this that it doesn’t really affect things much.&lt;/li&gt;
&lt;li&gt;I used to shred my pork shoulders &lt;em&gt;immediately&lt;/em&gt; after pulling it off the grill, and I would shred it on a cutting board. After allowing the shoulder to sit in the microwave for a few minutes in a pan and shredding it while it’s already in a pan, I’ve found that this prevents a loss of moisture that would otherwise just be all over the cutting board and countertop.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The downtime, however, is also what makes this recipe so easy: the majority of your time is just
spent monitoring the temperature of the pork shoulder. You don’t even need to open the lid of the
smoker for hours (unless you want to take pictures).&lt;/p&gt;
&lt;h3 id=&quot;serving-up-deliciousness&quot;&gt;Serving Up Deliciousness&lt;/h3&gt;
&lt;p&gt;At this point the world is your oyster: you’ve got some perfectly cooked pulled pork in front of
you, and all that’s left is to serve it up! My favorite way is to just slap it on top of some
Hawaiian Rolls with some BBQ sauce and eat it like sliders, with some baked beans and some kind of
potato dish as a side. Pictured above is some french onion soup roasted potatoes, which is a really
easy side dish to make, and only takes 3 ingredients to make (that’s worth a post itself). You can
also serve it on a bun of your choice, or if you’re gluten-intolerant just by itself and eating it
with a fork.&lt;/p&gt;
&lt;p&gt;Usually this recipe will yield quite a bit of leftovers, and there’s even more that you can do with
any leftover pork that you have: you can either serve it the same way you ate it initially, or if
you’re feeling adventurous you can reheat it in a pan with some taco seasoning and make carnitas
with it!&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I hope you enjoyed this post! This is the first of many recipe posts that I hope to make in the
future, and if you did try this yourself, let me know how it went!&lt;/p&gt;</content:encoded></item><item><title>Adding Social Media Images to a Gatsby Site</title><link>https://jvarness.blog/adding-social-media-images-to-gatsby/</link><guid isPermaLink="true">https://jvarness.blog/adding-social-media-images-to-gatsby/</guid><description>My site didn&apos;t used to have great images on social media cards. I fixed that recently.</description><pubDate>Fri, 17 May 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;When you post links on social media, sometimes the links generate a card that
looks really really nice. I say sometimes because… Well… This site never
had good ones. I basically took that little “JV” logo I made in Gimp and set
that as the image. It &lt;em&gt;worked&lt;/em&gt;, but it wasn’t &lt;em&gt;great&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;When my links get posted online, I wanted to make sure that they looked at
least somewhat professional. I may be the only one ever posting them, but I
at least wanted them to look good! Not just a couple letters.&lt;/p&gt;
&lt;p&gt;So today, I’m going to tell you about the methods I researched to be able to
add social media images to my site, and how I landed on using a Gatsby plugin called &lt;a href=&quot;https://www.gatsbyjs.com/plugins/gatsby-plugin-satorare/&quot;&gt;gatsby-plugin-satorare&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;alternative-solutions&quot;&gt;Alternative Solutions&lt;/h2&gt;
&lt;p&gt;Let’s start off by pointing out how others solved this: there are quite a few
people who have solved this issue in the past, and many of the solutions
involve a similar process: build a component using React that you will
use in tandem with puppeteer to be able to render the images in a browser
window and then have it take a screenshot of the preview page. Here were some
of the posts that I had found:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.emgoto.com/gatsby-react-social-card/&quot;&gt;Emma Goto - “Generate custom social card images for your Gatsby blog”&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://danspratling.dev/blog/automatically-generating-a-social-image-in-gatsby&quot;&gt;Dan Spratling - “Automatic social images in Gatsby”&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.maxpou.fr/blog/generate-social-image-share-with-gatsby/&quot;&gt;Max Poutard - “How to generate social share images with Gatsby”&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These solutions work just fine, so if for whatever reason you don’t like the
way that I did this, you could try one of these. These solutions do have an
easy way for you to test out that your generator is working. The solution I
used did not have the easiest way of testing out that things worked, but
once I got it working it’s smooth sailing.&lt;/p&gt;
&lt;p&gt;In doing the research for which plugin/solution I ultimately wanted to use, I went to search for plugins on Gatsby for social images, and
&lt;code&gt;gatsby-plugin-satorare&lt;/code&gt; came up as a potential option. It uses another library
from Vercel called &lt;a href=&quot;https://github.com/vercel/satori&quot;&gt;&lt;code&gt;satori&lt;/code&gt;&lt;/a&gt; that can take
JSX syntax and convert it into an image. They also have this really great
&lt;a href=&quot;https://og-playground.vercel.app/&quot;&gt;Playground&lt;/a&gt; where you can take the code you
want to use to generate the image and you can test out how the end product
looks. If I were you, and you want to use &lt;code&gt;gatsby-plugin-satorare&lt;/code&gt;, I would
probably start there.&lt;/p&gt;
&lt;h2 id=&quot;the-og-image-playground&quot;&gt;The OG Image Playground&lt;/h2&gt;
&lt;p&gt;Vercel’s OG Image Playground uses &lt;code&gt;satori&lt;/code&gt; to be able to generate images using
JSX syntax. However, this library does have it’s limitations in terms of the
types of styling that it supports. Before diving into this, I would
recommend taking a look at the &lt;a href=&quot;https://github.com/vercel/satori?tab=readme-ov-file#css&quot;&gt;list of supported CSS properties&lt;/a&gt;
that you can use to create an image. One of the things I ran into when I was
doing this was that border styles weren’t working the way I expected them to.&lt;/p&gt;
&lt;p&gt;My blog uses border styles quite a bit to make some of the elements look like
they have slanted edges. For example, this is the style used in a couple of
different places on the site:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A&quot;&gt;border-left&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;: 3em solid transparent&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A&quot;&gt;border-bottom&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;: 3em solid &lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;#e5e02d&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By using combinations of &lt;code&gt;border-*&lt;/code&gt; styles and defining one as a solid colored
border and the other as a solid transparent border, you can cut a little of the
colored border off on either side. I wanted to use this type of styling in my
images, but &lt;code&gt;satori&lt;/code&gt; doesn’t have the ability to do this when it’s generating
the images.&lt;/p&gt;
&lt;p&gt;If you wanted to try playing around with this effect, try heading to this
&lt;a href=&quot;https://codepen.io/jvarness/pen/ExJqKVL&quot;&gt;codepen&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you were to try this same effect in the playground, however, you would
notice that this simply doesn’t work. I’m assuming this is because of how
satori works: it converts JSX syntax into an SVG, and I’m guessing that the
translation from CSS styles to SVGs isn’t perfect.&lt;/p&gt;
&lt;p&gt;The workaround I used was that I just essentially created a little box that was
filled with a black color that would cut off a little piece off the end of the
date line on my images, and that ends up working ok.&lt;/p&gt;
&lt;p&gt;If you want to see the actual HTML/JSX I’m using to generate the image, I was
able to create a shareable link on the &lt;a href=&quot;https://og-playground.vercel.app/?share=nVXfT9swEP5XLE-TNqk0TWgHimAPbEOaNKRp8JiHOvUlMTh2ZDtAV_V_n52fdVu2QV_q3J3Pd9_3-bzBK0kBx_iCssdEIKTNmsPlZuPWCFGmK07WMVpmHJ6Xk9bq1l-ZgpVhUljfSvK6FL33iVFTWGsYzWbVsKcAlhfGmj-d7lhTsnrIlawF_SK5VDFKcMqtLcF9gFQUGruWnFEULqpn9A4WMIvoXtAvQlmtXWhkgwZnRShlInf2UyhROF1AOTgzKcw1KRm3LSb4ijPxcENWt2ttoLy2vi5wu03EZ7e4KMIBIWTbbkse62kS3rLf4Mxzd5Dd2-xEaLO8NXWWLW0umygowi5j9P8ZbQN-xhupwG7fTRu1aTs69wndoTTBjscBih7GO1n1WLWQ76M9cjkbLB3nCT5bvB8CHWoIdbXaPvvg_YrQ2LdPfkOf1KyVWYIVcGLYI3gBqTRGls4dTs92uXW_kqiciR-Q2WoT7FHf099jG3m-tvaheoR-SqsJiqRAN2SN5qbo2uoB34X8WIseuLaODtzDhgco94vtUT_0GEWEzqRqUFDSEAMf5gsK-ccXoSSpPb82PpSmre5kbm-o5-AdgOfuRh9D6SKwzbfCG1dvkGDLV0Om1-M_Su81MApS7Su0xf9qEEtk58hxfb9BtodXBCHCWS6-2znSjCTX5wkIP-QV8rt_JEqA1tOUy_xQeqzsjLZMtbpMcGFMpeMg8PYFrCQ56KBca-DZ9L6CPMHeFb7chNF5d3avON_2krLH6buYjSPgb5weDvdjs33EIvD01f7jCZaVE4bG8QY3LeDYPTwT3BaPY_veTDCFtM5xnBGuYYKhlPfsbl25d888NV82kWPjW5kCxbFRNWwn2JDURhTAuXySilO8_QM&quot;&gt;OG Playground&lt;/a&gt;
where you can see it.&lt;/p&gt;
&lt;p&gt;Once I had the image working, it was time to configure the plugin!&lt;/p&gt;
&lt;h2 id=&quot;configuring-gatsby-plugin-satorare&quot;&gt;Configuring &lt;code&gt;gatsby-plugin-satorare&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;The first thing you’re going to want to do is create a small JavaScript file
that acts as the “component” of the image. I say “component” because it’s not
so much a React component as much as it’s just something that uses JSX syntax
to define how the image is supposed to look.&lt;/p&gt;
&lt;p&gt;You’ll want this file to &lt;code&gt;export default&lt;/code&gt; a &lt;code&gt;function&lt;/code&gt; that takes an argument
that is a Gatsby &lt;code&gt;Node&lt;/code&gt;. You can change the behavior of how the image is
rendered based on the type of node it is. In my case, all of my blog posts are
generated using the &lt;a href=&quot;https://www.gatsbyjs.com/plugins/gatsby-transformer-remark/&quot;&gt;&lt;code&gt;gatsby-transformer-remark&lt;/code&gt;&lt;/a&gt;
plugin, so they are all of type &lt;code&gt;MarkdownRemark&lt;/code&gt;. I decided not to generate
images for all of the pages yet, so I’m only configuring the plugin to target
&lt;code&gt;MarkdownRemark&lt;/code&gt; nodes. In the end, this is how my little component looked:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;// src/components/social-image-card.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt; default&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#E36209&quot;&gt;node&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt; postedDate&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; Date&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(node.frontmatter.date).&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;toLocaleDateString&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;    undefined&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;    { month: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;long&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, day: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;numeric&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, year: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;numeric&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;  )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;div&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;      style&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;{{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;        display: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;`flex`&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;        flexDirection: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;`column`&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;        width: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;`1200px`&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;        height: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;`630px`&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;        backgroundColor: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;black&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;        border: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;solid 15px #e5e02d&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;        borderRadius: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;25px&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;        padding: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;3em 1.5em&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;        fontFamily: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;BlinkMacSystemFont&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;      }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;    &gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;      &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; style&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;{{ color: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;#e5e02d&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, fontSize: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;4em&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; }}&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;        {node.frontmatter.title}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;      &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;      &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; style&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;{{ color: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;#e5e02d&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, fontSize: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;3em&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; }}&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;        {node.frontmatter.description}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;      &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;      &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;div&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;        style&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;{{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;          display: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;flex&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;          borderTop: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;3em solid #e5e02d&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;          height: &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;          width: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;75%&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;        }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;      &gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;        &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;h2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;          style&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;{{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;            color: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;black&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;            position: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;relative&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;            bottom: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;1.75em&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;            marginLeft: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;.5em&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;            fontSize: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;2em&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;          }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;        &gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;          Posted on {postedDate}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;        &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;        &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;div&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;          style&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;{{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;            borderTop: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;5em solid black&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;            width: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;5em&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;            height: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;5em&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;            transform: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;rotate(45deg)&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;            position: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;absolute&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;            top: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;-40px&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;            left: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;800px&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;          }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;        &gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;      &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;      &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;div&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;        style&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;{{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;          display: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;flex&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;          margin: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;1em&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;          position: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;absolute&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;          bottom: &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;          right: &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;          borderBottom: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;2px solid #e5e02d&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;        }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;      &gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;        &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;h2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;          style&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;{{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;            color: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;#e5e02d&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;            alignItems: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;flex-end&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;            fontSize: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;2em&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;          }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;        &gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;          jvarness.blog&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;        &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;        &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;img&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;          src&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;https://jvarness.blog/images/myself.jpeg&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;          width&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;128&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;          height&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;128&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;          style&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;{{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;            borderRadius: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;50%&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;            margin: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;1em&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;            border: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;solid 5px #e5e02d&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;          }}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;        /&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;      &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;    &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;  )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see here, it’s a little different from my example code in the OG
Playground, but the key differences are mainly that it’s templated using the
&lt;code&gt;frontmatter&lt;/code&gt; contained within all my blog posts. Other than that, it’s pretty
much exactly what I put in the playground.&lt;/p&gt;
&lt;p&gt;One thing that is important to note here as well: you may notice that for the
whole component I’m using a font style &lt;code&gt;fontFamily: &quot;BlinkMacSystemFont&quot;&lt;/code&gt;. In
order to get a custom font into the plugin to resolve correctly, you’ll need to
download the fonts you want to use. I was abel to find these fonts in &lt;a href=&quot;https://github.com/aliifam/BlinkMacSystemFont&quot;&gt;this
github repo&lt;/a&gt; and I was able to
get it in &lt;code&gt;.otf&lt;/code&gt; format. I’m not sure if that matters or not, but the author
of the satorare plugin was using &lt;code&gt;.otf&lt;/code&gt; in their example, so that’s what I did.&lt;/p&gt;
&lt;p&gt;Anyway, now that I’ve got the fonts I wanted to use &lt;em&gt;and&lt;/em&gt; I’ve got the
component created that I wanted to use, it’s time to modify my
&lt;code&gt;gatsby-config.js&lt;/code&gt; with the correct configuration:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;resolve&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;`gatsby-plugin-satorare`&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;options&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;  path&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;`${&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;__dirname&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;}/src/components/social-image-card.js`&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;  fonts&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;      name: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;BlinkMacSystemFont&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;      path: &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;`${&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;__dirname&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;}/content/assets/BlinkMacSystemFont.otf`&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;  ],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;  target_nodes&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;: [&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;MarkdownRemark&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;],&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;},&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now that this is configured, the plugin, at build time, will:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Load the font(s) you want to use&lt;/li&gt;
&lt;li&gt;Load up all the node types contained in the &lt;code&gt;target_nodes&lt;/code&gt; array&lt;/li&gt;
&lt;li&gt;Call the &lt;code&gt;social-image-card.js&lt;/code&gt; function for each of the nodes, which will
then create images for the pages.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Perfect. We’re almost done! Now that we have the images generating, now we need
to actually start using them.&lt;/p&gt;
&lt;h2 id=&quot;actually-using-the-images&quot;&gt;Actually Using the Images&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;gatsby-plugin-satorare&lt;/code&gt; will create new schema within the GraphQL store that
Gatsby uses to generate your site for each node type that you target. In this
case, it generated a &lt;code&gt;markdownRemarkOgImage&lt;/code&gt; type in GraphQL that we can use
to reference the location of each image. We are able to do this using the IDs
of each blog post.&lt;/p&gt;
&lt;p&gt;For my blog posts, this was what the query used to look like:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt; const&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt; pageQuery&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; graphql&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62&quot;&gt;  query BlogPostBySlug($id: String!) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62&quot;&gt;    markdownRemark(id: { eq: $id }) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62&quot;&gt;      excerpt(pruneLength: 160)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62&quot;&gt;      html&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62&quot;&gt;      frontmatter {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62&quot;&gt;        title&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62&quot;&gt;        date(formatString: &quot;MMMM DD, YYYY&quot;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62&quot;&gt;        description&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62&quot;&gt;      timeToRead&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To be able to get the image data, I am now able to add a small snippet below
the &lt;code&gt;markdownRemark&lt;/code&gt; query block:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt; const&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt; pageQuery&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; graphql&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;`&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62&quot;&gt;  query BlogPostBySlug($id: String!) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62&quot;&gt;    markdownRemark(id: { eq: $id }) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62&quot;&gt;      /* ... */&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62&quot;&gt;    markdownRemarkOgImage(parent: { id: { eq: $id } }) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62&quot;&gt;      attributes {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62&quot;&gt;        publicURL&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#032F62&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now when my blog posts render, the &lt;code&gt;data&lt;/code&gt; prop will have the &lt;code&gt;publicURL&lt;/code&gt; that
can be used for the image!&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; BlogPostTemplate&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; ({ &lt;/span&gt;&lt;span style=&quot;color:#E36209&quot;&gt;data&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E36209&quot;&gt;pageContext&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; }) &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;publicURL&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; data.markdownRemarkOgImage.attributes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;  // the rest of the code...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I’m using the images mainly in a &lt;code&gt;Helmet&lt;/code&gt; to be able
to set the appropriate meta tags for these to show up on social media. If you
are ever unsure of whether or not you’re using the right tags for this, I was
able to use &lt;a href=&quot;https://socialsharepreview.com/&quot;&gt;socialsharepreview&lt;/a&gt; to test them.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Well now my blog looks a little more professional! I’m pretty happy with the
way they turned out, and now hopefully social card links will look a little
nicer than they used to! Thanks for reading if you made it this far, and let me
know on DEV or LinkedIn if you tried this out at all and if it was helpful to
you!&lt;/p&gt;</content:encoded></item><item><title>Making Yourself a Garbage Collector</title><link>https://jvarness.blog/making-yourself-a-garbage-collector/</link><guid isPermaLink="true">https://jvarness.blog/making-yourself-a-garbage-collector/</guid><description>Or: How to Deallocate Dereferenced Objects in Your Community</description><pubDate>Wed, 10 Apr 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h1 id=&quot;i-love-morning-walks-however&quot;&gt;I Love Morning Walks, However…&lt;/h1&gt;
&lt;p&gt;Over the course of the last few months, barring any cold weather, my wife and I
decided that we were going to start going on walks together with our daughter!
It’s been so nice in the morning being able to just go on a walk around our
community and see all the squirrels and rabbits running around, running into
the same neighbors that we’ve seen several times who’s name we don’t know
and their dogs who’s name we also don’t know, bumbling over crambly walking
paths, and of course, my most favorite part of all:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Walking down the sidewalk past all of the empty liqour shooters and coffee
cups, beer cans that had been shredded by lawn mowers, and lots of other
incredibly random pieces of trash, such as pieces of industrial electrical cable
and tupperware.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;What, who doesn’t love themselves some good ol’ fashion trash? It’s no secret
that people litter, and it’s not that I didn’t notice that there was &lt;em&gt;some&lt;/em&gt; trash before, but we didn’t always go on walks 3-5 times per week, and I never
noticed the &lt;em&gt;amount&lt;/em&gt; of trash around my neighborhood until we did. It was
just… Kinda gross. Really gross. Pretty yucky.&lt;/p&gt;
&lt;p&gt;Now, street sweepers would pick up trash sometimes, and they regularly come
around and clean up the streets, but they don’t get everything, and they
certainly don’t drive over the curb to pick up the trash on the sides of the
sidewalk. If you’re like me too, you’re probably not going to pick up any trash
unless it actually lands on your property. But… what if the property the
trash is on is technically owned by the city, but yet the city doesn’t send
anyone to pick the trash up? Well, you end up with what the three of us saw on
our morning walks.&lt;/p&gt;
&lt;p&gt;But then one day, at Target, I saw that they had these little plastic $5 trash
pickers, and I realized in that moment that I was going to become the one thing
I was always the most thankful for in so many programming languages:&lt;/p&gt;
&lt;h2 id=&quot;ma-im-a-garbage-collector&quot;&gt;Ma, I’m a Garbage Collector!&lt;/h2&gt;
&lt;p&gt;Picking up trash around your neighborhood can be really fun! All you gotta do
is get something you can pick up trash with. That could be a pair of heavy-duty
gloves (so that you don’t get poked or prodded), or it could be a grabber claw
thingy like I have (though I might recommend a heavier-duty one than the $5 one
from Target). For just $5, I’ve been able to relish in the newfound benefits
that garbage collecting around my neighborhood provides!&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;#x22;src&amp;#x22;:&amp;#x22;./garbage-collected.png&amp;#x22;,&amp;#x22;alt&amp;#x22;:&amp;#x22;A bag of trash I picked up from around my neighborhood, with the garbage\ngrabber I got leaning on top of it&amp;#x22;,&amp;#x22;index&amp;#x22;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;Picking up trash around your community not only helps your neighborhood look
nicer and cleaner, but it’s also just a fun activity that literally anyone can
do, for little to no cost, that gets you out of the house. For someone like me,
who loves to spend their time writing code, making websites, and playing video
games, this is a great way for me to bump up my step counts.&lt;/p&gt;
&lt;p&gt;I’m probably not going to be picking up trash &lt;em&gt;every day&lt;/em&gt;, but I do think I’ll
enjoy doing this at least once per week for the foreseeable future. I’m really
hoping that the above bag of trash is not going to be the norm, and I honestly
think that picking up the trash that I did really did make a difference.&lt;/p&gt;
&lt;p&gt;Some of the trash that I had picked up was trash that had been sitting around
for at least a week, and I wasn’t really convinced that anyone was really going
to do anything about it. Besides, not everyone just walks around certain parts
of our neighborhood because they’re mostly empty plots of land. Still, it all
got there somewhere, and I know the wind didn’t shred those beer cans up.&lt;/p&gt;
&lt;p&gt;Anyway, it felt good to do something like this. I had never really done
anything like it before, and it felt a lot like cleaning around my house or
mowing my &lt;del&gt;beer cans&lt;/del&gt; grass or any other household chore: it took some time
to do it, but I felt a lot better about how everthing looked when it was all
said and done. Now when we go on our walks, I feel just a little less gross!&lt;/p&gt;
&lt;h2 id=&quot;what-now&quot;&gt;What Now?&lt;/h2&gt;
&lt;p&gt;Like I said, I’m going to try to do this once a week for a while. If you got
this far into the post, I’d encourage you to give this a shot, or find some
other way to help out around your neighborhood! Heck, some people even do live
streams of them picking up trash near where they live.&lt;/p&gt;
&lt;p&gt;This post was trash, but hopefully the next one will be something cool. Catch
all y’all on the next one.&lt;/p&gt;</content:encoded></item><item><title>Creating a Radio Using HTML Canvases</title><link>https://jvarness.blog/html5-acnh-radio-2/</link><guid isPermaLink="true">https://jvarness.blog/html5-acnh-radio-2/</guid><description>In this post, I demonstrate how you can create visuals using HTML canvas elements.</description><pubDate>Sun, 20 Dec 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Hey everyone! It’s been a solid month since my last post, but I’m back again, and this time I want to focus on finishing up that crappy little radio we made last time. For context, &lt;a href=&quot;https://ugly-kk-radio.vercel.app/&quot;&gt;here&lt;/a&gt; is what I left off with from &lt;a href=&quot;/html5-acnh-radio&quot;&gt;this post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This little project started out as a submission for a programming competition, where I had to use 32 lines of code to make… Something, anything. But now that the competition is over, I can make this little project of mine whole with more code, specifically with CSS to draw a little radio on the screen, and some more JavaScript to make this project a little more robust than it is.&lt;/p&gt;
&lt;p&gt;But before we add play and pause functionality, we need to actually render something that resembles a radio. While it might not actually be a radio, I’m going to try to render something that looks like ACNH’s Tape Deck, because I like the way it looks.&lt;/p&gt;
&lt;h1 id=&quot;drawing-a-radio&quot;&gt;Drawing a Radio&lt;/h1&gt;
&lt;p&gt;First, I need to draw a radio. Most people would likely just… Draw one in Paint, Gimp, or their other favorite image manipulation program. However, this is a coding blog, and drawing a .png file doesn’t require writing any code, so instead we’re going to use a HTML &lt;a href=&quot;https://www.w3schools.com/html/html5_canvas.asp&quot;&gt;&lt;code&gt;canvas&lt;/code&gt; element&lt;/a&gt;, which are really cool little elements you can use to draw things with using JavaScript.&lt;/p&gt;
&lt;p&gt;This was pretty tough for me to do because I didn’t fully know what methods were available to me in order to be able to draw the radio. I mostly needed to be able to draw shapes, but for the face of the radio I also wanted it to have some textures. I decided to go ahead and start with a box for the body of the radio. In order to do this I need a &lt;code&gt;canvas&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;canvas&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;radio&quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; width&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;500px&quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; height&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;300px&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;canvas&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Easy. Now, I want to draw a box representing the body of the radio. In order to do that, I have to get the 2-dimensional context from the &lt;code&gt;canvas&lt;/code&gt; and start drawing shapes:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt; canvas&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; document.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;getElementById&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&apos;radio&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt; ctx&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; canvas.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;getContext&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&apos;2d&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;ctx.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;beginPath&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;ctx.fillStyle &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt; &apos;#ddd&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;ctx.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;fillRect&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;25&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;50&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;450&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;250&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The code gets a little bit boring from here. It’s mostly repeating setting the &lt;code&gt;fillStyle&lt;/code&gt; property and calling &lt;code&gt;fillRect&lt;/code&gt; to draw most of the body. I also drew a couple of circles by calling the &lt;code&gt;arc&lt;/code&gt; function to create a tape deck looking box, but the circle-drawing code is a little different. &lt;code&gt;fillRect&lt;/code&gt; draws rectangles and fills them in with a pattern or solid color, whereas arcs can be drawn differently depending on whether or not you call &lt;code&gt;fill&lt;/code&gt; or &lt;code&gt;stroke&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;ctx.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;beginPath&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;ctx.fillStyle &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt; &apos;#aaa&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;ctx.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;arc&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;128&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;210&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;Math.&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;PI&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;ctx.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;fill&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;ctx.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;beginPath&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;ctx.fillStyle &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt; &apos;#ddd&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;ctx.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;arc&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;128&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;210&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;8&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;Math.&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;PI&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;ctx.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;fill&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;ctx.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;beginPath&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;ctx.fillStyle &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt; &apos;#aaa&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;ctx.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;arc&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;170&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;210&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;10&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;Math.&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;PI&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;ctx.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;fill&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;ctx.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;beginPath&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;ctx.fillStyle &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt; &apos;#ddd&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;ctx.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;arc&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;170&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;210&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;8&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;Math.&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;PI&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;ctx.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;fill&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This code will draw gray circles below much lighter-gray circles. Using &lt;code&gt;fill&lt;/code&gt; here will create a circle filled in with a particular color based on what &lt;code&gt;fillStyle&lt;/code&gt; is set to. &lt;code&gt;stroke&lt;/code&gt;, however, has a different effect. Rather than just drawing a circle of the specified color, it draws a circle with a black outline.&lt;/p&gt;
&lt;p&gt;I wanted the stereo of the radio to have a textured look, but I didn’t want to repeat a ton of code to write little lines, so what I did is I created a tiny little image with the texture I wanted, and used the context’s &lt;code&gt;createPattern&lt;/code&gt; function to create a pattern with that image:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;var&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; radioTexture &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; Image&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;radioTexture.src &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt; &apos;radio_texture.png&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;radioTexture.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;onload&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;  var&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; radioPattern &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; ctx.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;createPattern&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(radioTexture, &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&apos;repeat&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;  ctx.fillStyle &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; radioPattern;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;  ctx.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;beginPath&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;  ctx.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;arc&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;350&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;175&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;100&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;Math.&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;PI&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;  ctx.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;fill&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This made it really easy to create the texture I wanted without drawing it all using the canvas.&lt;/p&gt;
&lt;p&gt;After a little added CSS, I’m starting to like what I created. The radio is a little less ugly now, and it… Actually looks like a radio!&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;#x22;src&amp;#x22;:&amp;#x22;./radio.png&amp;#x22;,&amp;#x22;alt&amp;#x22;:&amp;#x22;A digital-looking screenshot of something that resembles a 90s tape deck.&amp;#x22;,&amp;#x22;index&amp;#x22;:0}&quot;&gt;&lt;/p&gt;
&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;I still have a lot more that I want to add to this, but this is a pretty good start for something looking a little bit better. To see the product as it is now, you can &lt;a href=&quot;https://less-ugly-kk.vercel.app/&quot;&gt;click here&lt;/a&gt;. I think at some point in 2021 we’ll start to add more functionality, and hopefully by… 2025 we’ll have a finished product!&lt;/p&gt;
&lt;p&gt;This is probably going to be the last blog post I make this year, so I just wanted to say that if you enjoyed any of my posts that I’ve written this year, first off thanks so much for reading, and let me know what your favorite one was and why on social media!&lt;/p&gt;
&lt;p&gt;Happy Holidays and a Happy New Year to you and your family and friends! I’ll see you all again in 2021!&lt;/p&gt;</content:encoded></item><item><title>Building an ACNH Radio using HTML5 Audio Tags</title><link>https://jvarness.blog/html5-acnh-radio/</link><guid isPermaLink="true">https://jvarness.blog/html5-acnh-radio/</guid><description>Learning how to use the audio tag with everyone&apos;s favorite COVID-19 obsession, Animal Crossing: New Horizons</description><pubDate>Sat, 07 Nov 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://cerner.com&quot;&gt;Cerner&lt;/a&gt;, the company I’m currently employed at, holds an annual hackathon called 2^5, where every day for 32 days, you can make 1 submission of code that is 32 lines long or less. I’ve blogged about this previously on dev.to, and you can check out the post &lt;a href=&quot;https://dev.to/jvarness/32-lines-of-code-4bgc&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I’ve been a participant for 4 years, and it always surprises me how much folks are able to do using only 32 lines of code. This year was one of my favorite years to participate because I themed all of my submissions around Animal Crossing: New Horizons. Like millions of other Nintendo Switch gamers out there, ACNH became daily therapy as I caught bugs and fish, dug up fossils, and built an island full of really awesome villagers (the best overall being &lt;a href=&quot;https://nookipedia.com/wiki/Cherry&quot;&gt;Cherry&lt;/a&gt;, as I’m sure everyone who has ever had her as a villager would agree).&lt;/p&gt;
&lt;p&gt;What excited me even more was to find a &lt;a href=&quot;http://acnhapi.com/&quot;&gt;community-supported REST API&lt;/a&gt; for the new game that would allow you to query for &lt;em&gt;a lot&lt;/em&gt; of in-game items and get information about those items in the form of a JSON body, and almost every submission for 2^5 that I made &lt;a href=&quot;https://github.com/jvarness/cerner-2-to-the-5th/tree/master/2020&quot;&gt;this year&lt;/a&gt; revolved around this free API.&lt;/p&gt;
&lt;p&gt;There’s one submission that I made though that… Bothers me. A lot. I’ve thought about it non-stop since I submitted it, not for any reason other than the fact that it is visually one of the &lt;em&gt;ugliest&lt;/em&gt; things I’ve ever concocted. That submission is the &lt;a href=&quot;https://github.com/jvarness/cerner-2-to-the-5th/blob/master/2020/JS/kk/index.html&quot;&gt;radio that plays K.K. Slider songs&lt;/a&gt;. For brevity, I’ve deployed this file to Vercel &lt;a href=&quot;https://ugly-kk-radio.vercel.app/&quot;&gt;here&lt;/a&gt; so that you can see what it does.&lt;/p&gt;
&lt;p&gt;As you can see, this is really &lt;em&gt;really&lt;/em&gt; not visually appealing in any sense of the word. The JavaScript that was needed to make this work correctly made the file so large that there wasn’t really enough time leftover to make it pretty…&lt;/p&gt;
&lt;p&gt;I’m working on making it prettier right now, so for now, I’ll focus on what the &lt;code&gt;audio&lt;/code&gt; tag in HTML5 can do for you, and how I used it to make a little mvp of a radio!&lt;/p&gt;
&lt;h2 id=&quot;retrieving-music&quot;&gt;Retrieving Music&lt;/h2&gt;
&lt;p&gt;First thing we need to discuss is: how are we going to be retrieving the music we want to play? Well first I needed to go retrieve a song to play. The ACNH API has a &lt;a href=&quot;http://acnhapi.com/doc#tag/Songs&quot;&gt;Songs endpoint&lt;/a&gt; that makes this easy. Since I’m buildling a radio, I just want to go get random songs to play, so I’ll first start by generating a random integer in JavaScript between 1 and 95:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;Math.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;floor&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(Math.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;random&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt; 94&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is one of those quirky things about JavaScript that I really dislike: unlike other modern languages that can actually generate a random integer, us JavaScript developers have to use a combination of &lt;code&gt;Math.random&lt;/code&gt; (which generates a random decimal number between 0.0 and 1.0) and &lt;code&gt;Math.floor&lt;/code&gt; (which will round a number down to it’s nearest whole number value, so numbers like 3.9, 3.7, and 3.0000001 all become 3). My intention here is to generate a random number between 1 and 95, because the ANCH API uses positive integers for the IDs, and currently the only way to get songs from the API is to use ID numbers within that range as query parameters:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt; req&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; XMLHttpRequest&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;req.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;open&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&apos;GET&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;`https://acnhapi.com/v1/songs/${&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;Math&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;floor&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;Math&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;random&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt; 94&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;}`&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;req.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;onload&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; () { &lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;setSong&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(req.response); };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;req.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;send&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I’m not using NPM for this project, so just using &lt;code&gt;XMLHttpRequest&lt;/code&gt; works for my needs. Now… What is that &lt;code&gt;setSong&lt;/code&gt; and what does it do? Well, I use that to set some attributes on an &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/audio&quot;&gt;HTML5 &lt;code&gt;audio&lt;/code&gt; tag&lt;/a&gt;. Using this tag will help me answer the next conundrum:&lt;/p&gt;
&lt;h2 id=&quot;playing-music&quot;&gt;Playing Music&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;audio&lt;/code&gt; tag, when provided with a music &lt;code&gt;source&lt;/code&gt;, can play audio media straight from a browser once the browser has loaded the audio! So we can take our response from the API call, extract the URL of the MP3 from it, and begin to play it:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;audio&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; autoplay&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;source&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;audio/mpeg&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;/&gt;Looks like your browser doesn&apos;t support audio tags :(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;audio&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; setSong&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E36209&quot;&gt;resp&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt; json&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt; JSON&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;parse&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(resp);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;  document.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;querySelector&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&apos;#text&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;).textContent &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; json[&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;][&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;name-USen&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;  document.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;querySelector&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&apos;source&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;setAttribute&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&apos;src&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, json[&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;music_uri&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;]);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;  document.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;querySelector&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&apos;audio&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;load&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This code will set the &lt;code&gt;src&lt;/code&gt; of the &lt;code&gt;source&lt;/code&gt; tag, which will then allow the &lt;code&gt;audio&lt;/code&gt; tag to start playing music, once it’s told to start playing. Before I go any further, I want to address how this code actually plays music, and why if you’re on a Chrome-based browser, the &lt;code&gt;autoplay&lt;/code&gt; attribute likely isn’t causing the song to auto-play like you would expect:&lt;/p&gt;
&lt;p&gt;From the Mozilla docs I linked above, the &lt;code&gt;audio&lt;/code&gt; tag has many attributes. The two main ones I want to focus on are &lt;code&gt;autoplay&lt;/code&gt; and &lt;code&gt;controls&lt;/code&gt;. Many browsers will honor &lt;code&gt;autoplay&lt;/code&gt; if the &lt;code&gt;controls&lt;/code&gt; attribute is included here, the reason being that &lt;code&gt;controls&lt;/code&gt; asks the browser to supply music controls for the media. For this project, I don’t want to render the default controls, and I want it to still &lt;code&gt;autoplay&lt;/code&gt; where available, which is why I left it in.&lt;/p&gt;
&lt;p&gt;However, Chrome refuses to &lt;code&gt;autoplay&lt;/code&gt; any media without controls being present to play/pause said media. Because of this, I had to introduce something into the UI that would allow it to play the media based on a user-action, so I just added an &lt;code&gt;onClick&lt;/code&gt; handler on the &lt;code&gt;body&lt;/code&gt; tag, the entirety of which ends up looking like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; onclick&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;document&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;querySelector&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;(&apos;audio&apos;).&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;load&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;();&quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; onload&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;loadNextSong&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;()&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;content&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;text&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;Click here to start playing music.&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;h2&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;  &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;audio&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; autoplay&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;source&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; type&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;audio/mpeg&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;/&gt;Looks like your browser doesn&apos;t support audio tags :(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;  &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;audio&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, when the page loads, the user is prompted to click somewhere in order to start playing music. Now, we’re building a radio, so when the first song we loaded stops, how do we load the next one?&lt;/p&gt;
&lt;h2 id=&quot;continuously-playing-music&quot;&gt;Continuously Playing Music&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;audio&lt;/code&gt; tag comes with very convenient event handlers that we can take advantage of. The main one that we’ll be able to take advantage of for our radio is the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/ended_event&quot;&gt;&lt;code&gt;ended&lt;/code&gt;&lt;/a&gt; event. So far, the JavaScript we’ve written looks like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; setSong&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E36209&quot;&gt;resp&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt; json&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt; JSON&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;parse&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(resp);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;  document.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;querySelector&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&apos;#text&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;).textContent &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; json[&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;][&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;name-USen&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;  document.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;querySelector&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&apos;source&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;setAttribute&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&apos;src&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, json[&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;music_uri&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;]);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;  document.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;querySelector&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&apos;audio&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;load&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;function&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; loadNextSong&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;  document.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;querySelector&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&apos;#text&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;).textContent &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt; &quot;Loading...&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt; req&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; XMLHttpRequest&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;  req.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;open&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&apos;GET&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;`https://acnhapi.com/v1/songs/${&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;Math&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;floor&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;Math&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;random&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;*&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt; 94&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;+&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt; 1&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;}`&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;  req.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;onload&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; () { &lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;setSong&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(req.response); };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;  req.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;send&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We have functions for retrieving the next song, and loading it into our web page. However, this code will stop playing after the first randomly selected song. We can’t have it stop. What would K.K. Slider think of us if that happened?&lt;/p&gt;
&lt;p&gt;Luckily, we can just load the next song when the audio tag has ended the playing of media. We can do this by adding an event handler for the &lt;code&gt;ended&lt;/code&gt; event:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;document.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;querySelector&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&apos;audio&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;).&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;addEventListener&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&apos;ended&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, loadNextSong);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When the song stops playing, we’ll query up another song, set all the appropriate tags, and then &lt;code&gt;document.querySelector(&apos;audio&apos;).load()&lt;/code&gt; will play the next song for us! Because we added &lt;code&gt;autoplay&lt;/code&gt; to the audio tag, and the user had to click on the body of the page in order to start playing, songs will continue to play even in Chrome until the browser is closed!&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This is not a bad start for an ACNH radio, but the internet deserves better! So far, I don’t have a way to turn the radio off once it’s on, and it… Really doesn’t look so much like a radio.&lt;/p&gt;
&lt;p&gt;Stay tuned for an upcoming post where I use some CSS magic to turn this blob of text on a screen into something we can all be proud of. Until then, I hope you liked learning a little bit about how you could use the &lt;code&gt;audio&lt;/code&gt; tag! If you have any questions or feedback for me, links to my social media can be found on the footer of my website. Thanks for reading, and have a good one!&lt;/p&gt;</content:encoded></item><item><title>Adding serverless APIs to Gatsby projects in Vercel</title><link>https://jvarness.blog/adding-serverless-apis-to-gatsby-projects-in-vercel/</link><guid isPermaLink="true">https://jvarness.blog/adding-serverless-apis-to-gatsby-projects-in-vercel/</guid><description>I show how it&apos;s possible to dynamically load data into a Gatsby page using Vercel Serverless Functions.</description><pubDate>Sat, 31 Oct 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Hey everyone! It’s been a solid two weeks since I’ve actually written a blog. I’ve been feeling really under the weather, so I’ve been mostly taking the last few weeks easy (don’t worry, it wasn’t/isn’t COVID). That, and Pokemon Crown Tundra got released, so I’ve been playing a lot of that lately, but it feels nice to be back to writing some blogs!&lt;/p&gt;
&lt;p&gt;In the blog I wrote about &lt;a href=&quot;/how-this-site-was-made&quot;&gt;how I created my blog&lt;/a&gt;, I briefly mentioned that one of the reasons that I didn’t need to use Next.js for this site was because of the fact that it offered more functionality than I needed. All the pages on this site are built statically, and Next.js can do that too, but it also has great support for &lt;a href=&quot;https://nextjs.org/docs/api-routes/introduction&quot;&gt;dynamic routes and APIs&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I’m not convinced that this point that I’ll ever need dynamic routing built into this site since it’s using Gatsby. However, I might want to create APIs later for mailing lists, forms, etc. If I ever do need those APIs, Vercel actually makes it really easy to add APIs to any project.&lt;/p&gt;
&lt;p&gt;Originally this post was going to be about how easy making microservice APIs is using &lt;a href=&quot;https://github.com/vercel/micro&quot;&gt;micro&lt;/a&gt;, but then I discovered that micro was designed to be ran within a container, and that Vercel has better support for adding APIs to any Node project using it’s &lt;a href=&quot;https://vercel.com/docs/runtimes#official-runtimes/node-js/node-js-request-and-response-objects&quot;&gt;Serverless Helper Functions&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;adding-an-api&quot;&gt;Adding an API&lt;/h2&gt;
&lt;p&gt;Adding serverless APIs to Vercel projects is dead simple. You can review the link above and find some instructions. What I’ve done on this site is I’ve deployed the example shown in the link to a route on my website at &lt;a href=&quot;/api/examples/hello-world&quot;&gt;&lt;code&gt;api/examples/hello-world&lt;/code&gt;&lt;/a&gt;. For posterity, the code just looks like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;module&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;exports&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#E36209&quot;&gt;req&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#E36209&quot;&gt;resp&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt; &quot;World&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; req.query;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;  resp.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;json&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;`Hello ${&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;}!`&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a fairly straight-forward function: it accepts two objects, one representing the &lt;code&gt;req&lt;/code&gt;uest, which contains all the query parameters and any applicable bodies, and then an object we can use to send the &lt;code&gt;resp&lt;/code&gt;onse with.&lt;/p&gt;
&lt;p&gt;I added this route by simply creating an &lt;code&gt;api&lt;/code&gt; folder at the root of my project. Vercel will build out serverless API routes using the file structure defined within the &lt;code&gt;api&lt;/code&gt; folder, and will serve any &lt;code&gt;.js&lt;/code&gt;, &lt;code&gt;.go&lt;/code&gt;, &lt;code&gt;.py&lt;/code&gt;, or &lt;code&gt;.rb&lt;/code&gt; files defined within as serverless lambda functions.&lt;/p&gt;
&lt;h2 id=&quot;consuming-in-gatsby&quot;&gt;Consuming in Gatsby&lt;/h2&gt;
&lt;p&gt;I was really hoping to consume the API directly from this blog post, but I’m not using &lt;a href=&quot;https://github.com/mdx-js/mdx&quot;&gt;mdx&lt;/a&gt; for my posts quite yet, and injecting JavaScript in-line on a markdown file didn’t really seem like a very &lt;em&gt;safe&lt;/em&gt; thing to try and do, nor did I think it was feasible. SO, instead, I created an example page of how a Gatsby page might consume a serverless function.&lt;/p&gt;
&lt;p&gt;You can view the demo &lt;a href=&quot;/examples/api-example&quot;&gt;here&lt;/a&gt;, but I’ll talk more about the code here. You might consider opening the demo page up on another tab.&lt;/p&gt;
&lt;p&gt;In order to get the query parameters, Gatsby passes in &lt;a href=&quot;https://www.gatsbyjs.com/docs/location-data-from-props/&quot;&gt;&lt;code&gt;location&lt;/code&gt; data&lt;/a&gt; to each of it’s pages. We can use this, along with the &lt;a href=&quot;https://www.gatsbyjs.com/docs/recipes/querying-data/#querying-data-client-side-with-fetch&quot;&gt;&lt;code&gt;fetch&lt;/code&gt;&lt;/a&gt; API to grab the query params, can call our serverless function with the parameters:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; React, { useEffect, useState } &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt; &apos;react&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; { Link } &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt; &quot;gatsby&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; Layout &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt; &quot;../../components/layout&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; SEO &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt; &quot;../../components/seo&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; queryString &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt; &quot;query-string&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt; default&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; ({&lt;/span&gt;&lt;span style=&quot;color:#E36209&quot;&gt;location&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;}) &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;search&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; location&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; { &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt; &quot;World&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; } &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; queryString.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;parse&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(search)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; [ &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;greeting&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;setGreeting&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; ] &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; useState&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&apos;Loading...&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;  useEffect&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(() &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;    fetch&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;`/api/examples/hello-world?name=${&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;}`&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;      .&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;then&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E36209&quot;&gt;resp&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; resp.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;json&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;())&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;      .&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;then&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#E36209&quot;&gt;greet&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt; =&gt;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; setGreeting&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(greet))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;  }, [name])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; (&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;    &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;Layout&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;      &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;SEO&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; title&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;`Hello ${&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;}`&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;}/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;      &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; className&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;hero is-white is-large&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;        &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; className&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;hero-body&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;          &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; className&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;title&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;{greeting}&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;h1&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;        &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;      &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;      &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;        If you stumbled upon this page not knowing what it was, go &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;Link&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; to&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;`/adding-serverless-apis-to-gatsby-projects-in-vercel`&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;}&gt; here.&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;Link&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;      &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;section&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;    &amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;Layout&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;  )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We’re able to use &lt;code&gt;fetch&lt;/code&gt; to call an API using query parameters that were read from &lt;code&gt;location&lt;/code&gt; data, and then render that data client-side once the server responds! Neato!&lt;/p&gt;
&lt;p&gt;The one thing you might notice when loading the page is that while the page rendering is pretty quick, there’s a bit of a delay in loading the actual information from the serverless function created by Vercel, hence our page says “Loading…” first before getting the actual greeting. I will say that this is one thing that Next.js does pretty well that Gatsby does not: all pages in Gatsby are static, whereas Next.js can actually create &lt;em&gt;lambdas&lt;/em&gt; of pages, so the loading and rendering of the data is handled server-side. If we were using Next.js, we could use it’s &lt;a href=&quot;https://nextjs.org/docs/basic-features/data-fetching#getserversideprops-server-side-rendering&quot;&gt;&lt;code&gt;getServerSideProps&lt;/code&gt;&lt;/a&gt; API to render everything server-side so that the client doesn’t have to load any data itself. No need for loading indicators.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Hopefully you’ve found some of this information useful! As always, links to my social media are located below if you want to ask questions about this post or if you want to suggest a future post. Thanks for reading!&lt;/p&gt;</content:encoded></item><item><title>Trying Out One-Line Dark Mode Tricks</title><link>https://jvarness.blog/trying-out-one-line-dark-mode-tricks/</link><guid isPermaLink="true">https://jvarness.blog/trying-out-one-line-dark-mode-tricks/</guid><description>A single CSS style for an easy dark mode... How difficult is it to implement?</description><pubDate>Tue, 13 Oct 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’ve read a few articles on the internet about how you can implement dark mode on your website in one line of CSS. Honestly, it’s a really nifty trick. For reference, here are the articles I have seen:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/dip15739/dark-mode-with-only-1-css-property-17fl&quot;&gt;Dark Mode with only 1 CSS PROPERTY&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/akhilarjun/one-line-dark-mode-using-css-24li&quot;&gt;One line - Dark Mode using CSS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://dev.to/ekaterina_vu/dark-mode-with-one-line-of-code-4lkm&quot;&gt;Dark Mode With One Line Of Code&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It’s a neat trick, really it is. I’m a fan, and it works pretty well… For some websites. Since I now have a website, I thought to myself “self, why don’t you also include some kind of toggle for dark mode on your website using this trick!”.&lt;/p&gt;
&lt;p&gt;So I tried it… And uh… Well, let’s get into why I don’t really like the idea very much.&lt;/p&gt;
&lt;h2 id=&quot;trying-with-1-css-style&quot;&gt;Trying with 1 CSS Style&lt;/h2&gt;
&lt;p&gt;Let’s just start with figuring out what this website looks like if we apply this filter style on my website in Chrome dev tools. Adding this CSS property on the &lt;code&gt;&amp;#x3C;html&gt;&lt;/code&gt; element yields interesting results for the site:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;css&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#22863A&quot;&gt;filter&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;: invert(1) hue-rotate(180deg);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All the colors are inverted, but it turns out the yellow color I chose doesn’t look all that great when it’s inverted:&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;#x22;src&amp;#x22;:&amp;#x22;./dark-mode-initial.png&amp;#x22;,&amp;#x22;alt&amp;#x22;:&amp;#x22;My website after inverting the colors and a 180-degree hue rotation&amp;#x22;,&amp;#x22;index&amp;#x22;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;The whites turn black, the blacks turn white, and the yellow turns… Brown? Ew… Well, what if I just tried it without the &lt;code&gt;hue-rotate&lt;/code&gt; style and just had &lt;code&gt;filter: invert(1)&lt;/code&gt;? The result is a little bit better:&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;#x22;src&amp;#x22;:&amp;#x22;./blue-dark-mode.png&amp;#x22;,&amp;#x22;alt&amp;#x22;:&amp;#x22;The yellows on the site turn blue instead&amp;#x22;,&amp;#x22;index&amp;#x22;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;#x22;src&amp;#x22;:&amp;#x22;./code-highlighting.png&amp;#x22;,&amp;#x22;alt&amp;#x22;:&amp;#x22;The code highlighting looks pretty good&amp;#x22;,&amp;#x22;index&amp;#x22;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;This looks a little bit better, even some of the posts don’t look too bad: the code snippets and inline highlighting don’t look all that bad. However, there are other subtle elements of the site that don’t really look right. The footer, for example, has a really poor contrast ratio between the links I have there and the now white background:&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;#x22;src&amp;#x22;:&amp;#x22;./footer-with-blue.png&amp;#x22;,&amp;#x22;alt&amp;#x22;:&amp;#x22;The footer with just invert(1)&amp;#x22;,&amp;#x22;index&amp;#x22;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;My fear here is that users who have colorblindness might not be able to easily see some of these links. The icons look pretty good inverted though, so what I can do is make the links the same color as the icons, and that’ll solve that problem pretty easily, because they’ll turn the same blue as the icons:&lt;/p&gt;
&lt;p&gt;&lt;img __ASTRO_IMAGE_=&quot;{&amp;#x22;src&amp;#x22;:&amp;#x22;./blue-links.png&amp;#x22;,&amp;#x22;alt&amp;#x22;:&amp;#x22;Links are as blue as the icons on the footer&amp;#x22;,&amp;#x22;index&amp;#x22;:0}&quot;&gt;&lt;/p&gt;
&lt;p&gt;So this isn’t too bad still… But I’m not sure I really like the blue color still. I picked that yellow because I like it. I want it to stay that way. Plus, this is just a style: I still need to figure out a way to turn it off and on again, which will require some JavaScript on my part.&lt;/p&gt;
&lt;p&gt;I’ll eventually get a dark mode added to my website, but I don’t think I’ll be using this method for it. I think for other websites that have simpler color schemes this might be a great technique to use! But for my website, it’s just not working the way I want it to.&lt;/p&gt;
&lt;h2 id=&quot;other-examples&quot;&gt;Other Examples&lt;/h2&gt;
&lt;p&gt;Other websites have great examples of how their dark mode is implemented. One notable one is Dan Abramov’s site &lt;a href=&quot;https://overreacted.io/&quot;&gt;overreacted.io&lt;/a&gt;. Dan is the creator of React, and this blog was created using Gatsby! You can check out the source code &lt;a href=&quot;https://github.com/gaearon/overreacted.io&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Dan’s implementation is very elegant: the base color scheme for all the text and content just looks visually appealing regardless of whether or not the background is light or dark. The background becomes a different color based on classes added to the &lt;code&gt;body&lt;/code&gt; of the page. Dan also has some code in here that will persist the selected theme between sessions so that the next time the site is visited it’s using the same theme.&lt;/p&gt;
&lt;p&gt;The Gatsby community seems to agree that this is a pretty good implementation! Someone from the community decided to create a plugin that implements much of the code that Dan uses to persist the theme state and trigger updates to the theme. Source code for that plugin can be found &lt;a href=&quot;https://github.com/insin/gatsby-plugin-dark-mode&quot;&gt;here&lt;/a&gt;. For anyone looking to implement similar themes or triggers, this is a good starting point!&lt;/p&gt;
&lt;h2 id=&quot;wrapping-up&quot;&gt;Wrapping Up&lt;/h2&gt;
&lt;p&gt;So what does this teach us about dark mode? You can certainly use a CSS style like &lt;code&gt;filter&lt;/code&gt; to invert all of the colors on your website to achieve the desired effect, but as the color scheme I’m using can prove, it can be a little difficult to implement it using &lt;code&gt;filter&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In a later blog post, if I’m ever going to be able to figure out how to make this work for my site, I’ll discuss how I overcame all these different challenges, and how I was able to actually implement it.&lt;/p&gt;</content:encoded></item><item><title>How I made jvarness.blog</title><link>https://jvarness.blog/how-this-site-was-made/</link><guid isPermaLink="true">https://jvarness.blog/how-this-site-was-made/</guid><description>I go meta and discuss how I made my blog, including examining alternatives I had.</description><pubDate>Wed, 07 Oct 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;A colleague of mine reached out to me and asked if I could spend a little bit of time blogging about how I created this blog. I told that colleague I would soon, so hopefully they’ll enjoy this.&lt;/p&gt;
&lt;p&gt;Aside from being asked by a colleague: I want to talk about what my needs &lt;em&gt;currently&lt;/em&gt; are for the blog, the technologies I’m using to create the blog, and why I chose those technologies over competitors.&lt;/p&gt;
&lt;h2 id=&quot;bear-bare-necessities&quot;&gt;&lt;del&gt;Bear&lt;/del&gt; Bare Necessities&lt;/h2&gt;
&lt;p&gt;First things first: this is a blog. It’s a website, not an app, and I knew I didn’t need or want to maintain any kind of app. That helped narrow down my tech search. I wanted this to just be a website that I could post my thoughts and ideas and projects to.&lt;/p&gt;
&lt;p&gt;There were things I could have done that would have made the site much more complicated to setup initially, but I could have added more features over time: I could have created some kind of Ruby on Rails application and served my content via a CMS such as &lt;a href=&quot;https://strapi.io/&quot;&gt;Strapi&lt;/a&gt;, but there were two major concerns that I had about that:&lt;/p&gt;
&lt;p&gt;First thing is that I would have needed to setup and deploy both the website in Rails, as well as a Strapi instance somewhere like &lt;a href=&quot;https://www.digitalocean.com/&quot;&gt;Digital Ocean&lt;/a&gt; or on &lt;a href=&quot;https://www.heroku.com/&quot;&gt;Heroku&lt;/a&gt;, but for something like a blog there are cheaper options.&lt;/p&gt;
&lt;p&gt;The second concern I would have had about that is performance: Rails screams, but only if you have the hardware an infrastructure to help it scale. I didn’t want to worry too much about performance with this, because in the end it’s &lt;em&gt;just a blog&lt;/em&gt;, and you could end up paying big with that kind of server side rendering architecture… Or really any kind of rendering for that matter.&lt;/p&gt;
&lt;p&gt;I knew that I could achieve better performance through static rendering and generation than I could if I hosted my content on a CMS and loaded that content in for each page hit, and because I know how to write JavaScript (and I like to write JavaScript code), it became pretty clear what I wanted to do: &lt;a href=&quot;https://jamstack.org/&quot;&gt;JAMStack&lt;/a&gt; it!&lt;/p&gt;
&lt;h2 id=&quot;jamstack&quot;&gt;JAMStack&lt;/h2&gt;
&lt;p&gt;In the world of JAMStack, there are many technologies and companies that make it extremely simple to make a website. In fact, on the JAMStack site, there are a ton of options &lt;a href=&quot;https://jamstack.org/generators/&quot;&gt;listed here&lt;/a&gt; that can help you achieve what you’re wanting to do. I’m not going to talk about all of the options that you have, but I will talk about a few that I did consider:&lt;/p&gt;
&lt;h3 id=&quot;nextjs&quot;&gt;Next.js&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://nextjs.org/&quot;&gt;Next.js&lt;/a&gt; is a React framework for building websites, created by &lt;a href=&quot;https://vercel.com/&quot;&gt;Vercel&lt;/a&gt; (formerly Zeit), with the aim of being extremely flexible: site pages can be generated statically, they can render dynamically using microservice APIs, it’s easy to add your own microservices into the same code base, and code-splitting is built-in, meaning that your JavaScript isn’t bundled into one big blob, but rather just the JavaScript that each individual page needs.&lt;/p&gt;
&lt;p&gt;For pages that are dynamically rendered, Next.js creates a lambda function, which is a huge plus for anyone who wants to create dynamically rendered pages: lambda functions are a great way to keep the costs of deploying a website down, and it doesn’t require a server to be constantly running.&lt;/p&gt;
&lt;p&gt;I’m a huge fan of using Next.js to build applications and websites. I would recommend it to a lot of people. However, I didn’t really feel as if I needed &lt;em&gt;all&lt;/em&gt; of the power that Next.js had to offer: I don’t have a need to create any microservices, and if I did I can always create and deploy those very easily. If I did feel as if I needed them though, Next.js would be what I would reach for.&lt;/p&gt;
&lt;p&gt;One other thing I don’t find particularly convenient about Next.js is the ability to create posts using Markdown: Kendall Strautman made a blog that you can find &lt;a href=&quot;https://dev.to/tinacms/creating-a-markdown-blog-with-next-js-52hk&quot;&gt;here&lt;/a&gt; on how to setup a Markdown blog using Next.js. I spent a good long while trying to get this to work with &lt;a href=&quot;https://www.netlifycms.org/&quot;&gt;NetlifyCMS&lt;/a&gt;, but Next.js just isn’t elegant for this because I believe at it’s core it’s trying to solve a completely different use-case: quickly rendering pages through the use of microservice architectures. But like I said, I don’t really need those, I just want to write Markdown and get a site working.&lt;/p&gt;
&lt;h3 id=&quot;nuxtjs&quot;&gt;Nuxt.js&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://nuxtjs.org/&quot;&gt;Nuxt&lt;/a&gt; is another JavaScript framework that looks to solve many of the same use-cases as Next, but instead of using React it uses Vue.&lt;/p&gt;
&lt;p&gt;I don’t really have more experience with Nuxt than I do with Next, but of the experience that I do have, I can tell you that Nuxt’s plugin system is pretty elegant. With Next, there tends to be a lot of webpack configuration you have to go through in order to get things exactly how you want them if you’re deviating from use-cases that Next tries to solve. In my opinion, Nuxt has a lot more intuitive configuration and plugin setup, and there are so many nice conventions in Nuxt that make organizing the source code very easy.&lt;/p&gt;
&lt;p&gt;For more complex websites, Nuxt is a great option for those who want more configurability in their site, or for those who just love Vue more than they love React. Nuxt really was a close second for this site.&lt;/p&gt;
&lt;h3 id=&quot;gatsby&quot;&gt;Gatsby&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.gatsbyjs.com/&quot;&gt;Gatsby&lt;/a&gt; is considered to be the defacto static site generator for React developers by many in the React/JAMStack community. It’s primary goal is to utilize APIs to create static pages. It heavily utilizes GraphQL and plugins curated by the Gatsby community to query data sources and build a site. It’s also very easy to learn if you have a good understanding of React. In fact, much of the groundwork for this website was laid using the tutorial on Gatsby’s website, found &lt;a href=&quot;https://www.gatsbyjs.com/tutorial/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The main difference between Nuxt/Next and Gatsby to me is that Gatsby makes it extremely easy to source information from files within a repository in order to build the content, whereas Nuxt/Next make it easy to create small services that can be used to dynamically render pages. To me, this was the simplest and easiest way to create a blog: I wrote posts in Markdown, and Gatsby turns it into a website!&lt;/p&gt;
&lt;p&gt;The one caveat about Gatsby, that I think I’m willing to compromise on at the moment, has to deal with build times. Next and Nuxt are both best tailored to load content from REST APIs, which means that your build times are only as long as it takes to build each lambda or static page that your site requires. You sacrifice a small portion of load times to have extremely fast builds.&lt;/p&gt;
&lt;p&gt;As of the publishing of this post, there are only a total of 4 blog posts, and as such, Gatsby’s build times are extremely quick. However, with my current implementation, Gatsby won’t be able to scale as I continue to add more and more posts. My builds will start to take longer because Gatsby will have to build &lt;em&gt;every single post&lt;/em&gt; as a new page.&lt;/p&gt;
&lt;p&gt;However, loading times for statically rendered sites are significantly faster than those backed by services. In this case, I’m willing to sacrifice slower builds to be able to host the same content and have that content be really fast to load.&lt;/p&gt;
&lt;h2 id=&quot;hosting&quot;&gt;Hosting&lt;/h2&gt;
&lt;p&gt;There are about as many options for hosting as there are for actually generating your site. I already mentioned Digital Ocean and Heroku, but those fit different use-cases than what I was really needing. I didn’t want to have to manage an OS, or hardware resources, or whether or not I wanted my site to be scalable… I just wanted to deploy a website.&lt;/p&gt;
&lt;p&gt;There are a few platforms I’m aware of that make this extremely easy to do. I’ll discuss two of them that I didn’t use, and what I ultimately decided to utilize.&lt;/p&gt;
&lt;h3 id=&quot;surge&quot;&gt;Surge&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://surge.sh/&quot;&gt;Surge&lt;/a&gt; is a platform you can use to deploy static sites quickly and easily. It offers a CLI that can be easily installed via NPM, and the free tier is extremely generous in terms of being able build as many projects into Surge as you want. It’s really easy to use.&lt;/p&gt;
&lt;p&gt;However, Surge is almost too simple: your website has to be built first in order to deploy it. The project has to be in a pre-built state before being published to the Surge network. This means that if you want to automate deployments when you push to a repo, you’ll need to setup some kind of continuous integration service to take care of getting the CLI and publishing for you. If you’re interested in Surge but you want automated deployments, there should be a guide in the docs on how to set it up with an old favorite of mine, &lt;a href=&quot;https://travis-ci.org/&quot;&gt;Travis&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Sadly, I did not choose Surge for my deployments and hosting.&lt;/p&gt;
&lt;h3 id=&quot;netlify&quot;&gt;Netlify&lt;/h3&gt;
&lt;p&gt;Oh boy… I’m sure I’m going to get some flak for this… I’ll admit it: I’ve actually never tried using &lt;a href=&quot;https://www.netlify.com/&quot;&gt;Netlify&lt;/a&gt;. For those of you reading this who love Gatsby, you must think I’m crazy. You might be right.&lt;/p&gt;
&lt;p&gt;Netlify is a big favorite amongst many in the JAMStack community, and it’s not hard to understand why: Netlify deploys sites to a super fast CDN, and is capable of deploying static pages, as well as lambdas. It’s a really great choice for anyone who is creating a website with Nuxt, Next, Gatsby… Really, any static site generator.&lt;/p&gt;
&lt;p&gt;Netlify also has an easy-to-integrate CMS aptly named &lt;a href=&quot;https://www.netlifycms.org/&quot;&gt;Netlify CMS&lt;/a&gt;. The way that Netlify CMS works is that the data is actually all hosted in GitLab or GitHub, and Netlify CMS will load posts from those sources. Then, when a post is edited or added, those updates will be pushed to the repository from Netlify CMS on your behalf, and can be stored as JSON, Markdown, whatever is supported.&lt;/p&gt;
&lt;p&gt;This is Gatsby’s strong suit: since the data that Gatsby uses to generate all of the pages is held within the repo itself, it’s possible to easily add Netlify CMS to any Gatsby site.&lt;/p&gt;
&lt;p&gt;Netlify, Netlify CMS, and Gatsby, would all be extremely attractive options if you wanted to create a website for practically no money down, and you wanted multiple people to be able to contribute to it, or if you wanted people who were not engineers to be able to contribute without having to understand Markdown or code. Couple that with things that developers care about, like Git integration and built-in site generation and deployments, and you have a match made in heaven.&lt;/p&gt;
&lt;p&gt;… Or at least for other people. Not necessarily for me. There’s another platform I’ve been using for quite some time now that I just can’t stop using.&lt;/p&gt;
&lt;h3 id=&quot;vercelzeit&quot;&gt;Vercel/Zeit&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://vercel.com/&quot;&gt;Vercel&lt;/a&gt; (Zeit) is a company that you may or may not have heard about: I don’t think they get nearly the amount of praise that Netlify does or the kind of attention that Netlify typically does, but they are just as good as Netlify for building and deploying sites. The company itself owns a lot of really neat &lt;a href=&quot;https://vercel.com/oss&quot;&gt;open-source software&lt;/a&gt; that you may already be using, such as the Hyper terminal emulator, and they’re also the minds behind Next.js, Mongoose… My main point is that they do a lot of really neat stuff.&lt;/p&gt;
&lt;p&gt;There are so many great things about Vercel that make it an excellent platform for developers: a free pricing tier that allows you to deploy all kinds of projects is just the start. Actually, fun fact about Vercel: as of the writing of this article, ALL personal accounts are FREE, meaning you don’t have to pay anything to deploy your personal projects. Accounts only become paid if they are team accounts, where you want multiple contributors to join your project.&lt;/p&gt;
&lt;p&gt;Next are the different features: full integration with GitLab, GitHub, and Bitbucket, easy to use integrations to other sites through their integrations marketplace, but probably my favorite feature of all is the CLI.&lt;/p&gt;
&lt;p&gt;With the &lt;a href=&quot;https://vercel.com/docs/cli&quot;&gt;Vercel CLI&lt;/a&gt;, it’s possible to take advantage of all the power Vercel has to offer right at your fingertips. You can buy a domain name, manage DNS records for your domains, deploy a node project straight to the Vercel platform (regardless of whether or not it’s stored in a Git repository), manage deployments… Literally anything you would normally want to manage through a web client, you can do on the command line. You never have to leave your development environment to manage your projects in production. Like Surge and Netlify, Vercel will also deploy your site with every push, can can create vanity URLs on it’s platform for every Git branch you create.&lt;/p&gt;
&lt;p&gt;For me, having used Vercel for many years, this wasn’t a difficult decision to make.&lt;/p&gt;
&lt;h2 id=&quot;thats-about-all-folks&quot;&gt;That’s About All Folks&lt;/h2&gt;
&lt;p&gt;And that’s all she wrote! These are the decisions that lead me to develop my website the way you’re currently experiencing it. Hopefully these insights and thoughts that I’ve expressed have perhaps inspired you to consider creating your own blog, or experimenting with creating any kind of static website. Like I said before: there’s not much risk involved with using these platforms. It’s very easy, and almost always free, to create and experiment with different technologies and ways of creating websites. If you have any questions, please reach out to me on social media! You can find links below. I’d be happy to answer your questions or hear your feedback. Thanks for reading!&lt;/p&gt;</content:encoded></item><item><title>My Gripes about C-Style for-loops</title><link>https://jvarness.blog/my-gripes-about-c-style-for-loops/</link><guid isPermaLink="true">https://jvarness.blog/my-gripes-about-c-style-for-loops/</guid><description>The first loop you might have ever learned is the first one you should probably forget.</description><pubDate>Fri, 25 Sep 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;One of the most useful (and often one of the most fundamental) concepts when learning to code is looping.
Loops are all around us, in virtually every language we know, and even if your language of choice doesn’t
include primitive loops, there is likely a way to achieve executing the same block of code a fixed number
of times, or by implementing some kind of basic means of iterating.&lt;/p&gt;
&lt;p&gt;The first programming language that I ever wrote code in was Python, but the first programming language I
really got a firm grasp on, and that I still use to this day, is Java.&lt;/p&gt;
&lt;p&gt;Over Java’s history, it’s evolved immensely: JDK 11 has introduced modules, which is another way of organizing
a codebase, JDK 8 introduced lambda functions (a feature which existed in many other langauges including
C# and JavaScript for some time), and JDK 5 was when the enhanced for-loop was introduced.&lt;/p&gt;
&lt;p&gt;JDK 5’s last update was over a decade ago, but regardless of how old it is, I can’t help but notice that
sometimes people are continuing to use C-Style for-loops, and not only that, but I can find very heavy
usage of C-Style loops in a lot of code bases in other languages as well, such as C#. I want to write
this blog post as a caution to those who are continuing to use this loop, and provide reasons as to why
whenever I see C-Style loops in a code review, I’ll &lt;em&gt;almost always&lt;/em&gt; ask someone to refactor it.&lt;/p&gt;
&lt;h2 id=&quot;stability&quot;&gt;Stability&lt;/h2&gt;
&lt;p&gt;My first big gripe about C-Style for-loops is that they are extremely prone to bugs. For every line of
code you write within a C-Style for-loop, there could be an error in almost every line, and there can
be potentially a number of bugs that are present before you even start talking about what’s in the loop.
Let’s look at a simple example, printing numbers in an array:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;[] nums &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; [] { &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; i &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;; i &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; nums.length; i&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;  System.out.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(nums[i]);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There’s technically nothing wrong with this code. We created an array, looped over each of the elements in
that array, and printed each number out to the console. However, this loop is prone to all kinds of bugs.
This code works without defects or error IF and ONLY IF:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;i&lt;/code&gt; is not mutated within the loop, and nothing is stopping it from being manipulated either temporarily or
permanently&lt;/li&gt;
&lt;li&gt;&lt;code&gt;i&lt;/code&gt; is always incremented by 1 after each execution of the loop&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;&amp;#x3C;&lt;/code&gt; condition doesn’t change&lt;/li&gt;
&lt;li&gt;&lt;code&gt;i&lt;/code&gt;’s initial value does not change&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If any of these things changes for any reason, we run the risk of encountering &lt;code&gt;ArrayIndexOutOfBoundsException&lt;/code&gt;s,
not looping over each element, or skipping elements within the array. For having the simple task of iterating over
5 numbers, this seems like a lot of risk to impose at runtime.&lt;/p&gt;
&lt;p&gt;We can mitigate all of these issues by using alternative methods to looping over this structure. Since JDK 5,
developers have been able to take advantage of enhanced for-loops, also referred to as for-each loops (yet again
another construct that’s always been available in C#).&lt;/p&gt;
&lt;p&gt;Using an enhanced for-loop, the code now looks like this:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;[] nums &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt; int&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; [] { &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; };&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; num &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; nums)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;  System.out.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(num);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This code will iterate over the array, and on each invocation of the loop it will assign the a value to the
variable &lt;code&gt;num&lt;/code&gt;, then we can use that number without having to access the array! This addresses all of the
concerns we had about C-Style for-loops in terms of stability.&lt;/p&gt;
&lt;p&gt;Enhanced for-loops can be used with any data structure that implements Java’s &lt;a href=&quot;https://docs.oracle.com/javase/8/docs/api/java/lang/Iterable.html&quot;&gt;&lt;code&gt;Iterable&lt;/code&gt;&lt;/a&gt;
interface, and because the &lt;a href=&quot;https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html&quot;&gt;&lt;code&gt;Collection&lt;/code&gt;&lt;/a&gt; interface
extends &lt;code&gt;Iterable&lt;/code&gt;, we can use it for every &lt;code&gt;List&lt;/code&gt; and &lt;code&gt;Set&lt;/code&gt; in our code.&lt;/p&gt;
&lt;p&gt;Speaking of &lt;code&gt;Collection&lt;/code&gt;s, let’s discuss my next big gripe:&lt;/p&gt;
&lt;h2 id=&quot;time-complexity&quot;&gt;Time Complexity&lt;/h2&gt;
&lt;p&gt;Let’s start this discussion with another example. I have a &lt;code&gt;List&lt;/code&gt; that I’m iterating over and I want to
print each element in the &lt;code&gt;List&lt;/code&gt;, and let’s start with a C-Style loop:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;List&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt; nums &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; ArrayList&amp;#x3C;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;nums.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;nums.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;nums.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;nums.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;nums.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; i &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;; i &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; nums.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;size&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(); i&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;  System.out.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(nums.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(i));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Again, same as before: nothing too fancy about this code, and it works fine. Now, let’s switch from using &lt;code&gt;ArrayList&lt;/code&gt; to &lt;code&gt;LinkedList&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;List&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt; nums &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; LinkedList&amp;#x3C;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;nums.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;nums.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;nums.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;nums.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;nums.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; i &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt; 0&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;; i &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; nums.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;size&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(); i&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;++&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;  System.out.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(nums.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(i));&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is the exact same output, and at face value the only real difference is the fact that we’re using a different implementation
of the &lt;code&gt;List&lt;/code&gt; interface. However, that’s an &lt;em&gt;extremely crucial&lt;/em&gt; difference in this situation.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ArrayList&lt;/code&gt; is what it sounds like: it’s an implementation of the &lt;code&gt;List&lt;/code&gt; interface that uses an array as it’s underlying structure.
This means that extracting data out of the list can happen in constant time.&lt;/p&gt;
&lt;p&gt;However, &lt;code&gt;LinkedList&lt;/code&gt; is a linked data structure. With an &lt;code&gt;ArrayList&lt;/code&gt;, the compromise for performance happens when adding elements to
the list: the array has to “grow” by creating a new array with a larger size than the current underlying array, and moving all the
elements to that new reference, and then garbage collection will take care of the rest. &lt;code&gt;LinkedList&lt;/code&gt;s are really efficient
during the population of the list because the structure can be created in such a way that growing the list can happen in constant
time. However, this comes at a cost of accessing the data by index: each &lt;code&gt;.get&lt;/code&gt; call will yield an n^2 time complexity, n being the
index you’re trying to access.&lt;/p&gt;
&lt;p&gt;Just by switching from &lt;code&gt;ArrayList&lt;/code&gt; to &lt;code&gt;LinkedList&lt;/code&gt;, we exponentially increased the time complexity of this code. However, enhanced
for-loops can help mitigate this issue:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;List&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt; nums &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; LinkedList&amp;#x3C;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;nums.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;nums.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;2&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;nums.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;3&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;nums.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;4&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;nums.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;add&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; (Integer num &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; nums)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;  System.out.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(num);&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But why is this more beneficial in terms of time complexity? Remember: &lt;code&gt;List&lt;/code&gt;s are &lt;code&gt;Collection&lt;/code&gt;s which are &lt;code&gt;Iterable&lt;/code&gt;. Each implementation of
a &lt;code&gt;List&lt;/code&gt; comes with a built-in &lt;a href=&quot;https://docs.oracle.com/javase/8/docs/api/java/util/List.html#iterator--&quot;&gt;&lt;code&gt;Iterator&lt;/code&gt;&lt;/a&gt; which can be used
to efficiently iterate over the list. Normally, &lt;code&gt;Iterator&lt;/code&gt;s are designed to be as efficient as possible. &lt;code&gt;Iterator&lt;/code&gt;s can be scoped to
the class implementing them to allow them to have scope to the internal members of the data structure, which allows them to do things like
access links within a &lt;code&gt;LinkedList&lt;/code&gt; directly so that the next link can be fetched without having to loop over them like most &lt;code&gt;.get&lt;/code&gt; operations
would normally do.&lt;/p&gt;
&lt;p&gt;Why wouldn’t we just use &lt;code&gt;ArrayList&lt;/code&gt; everywhere if this was the case though? You can control whether or not your API uses &lt;code&gt;ArrayList&lt;/code&gt;, sure, but
that won’t stop other engineers from using some other kind of implementation in theirs, so guard yourself against these types of caveats
by using the right loops.&lt;/p&gt;
&lt;h2 id=&quot;alternatives-to-enhanced-for-loops&quot;&gt;Alternatives to Enhanced for-loops&lt;/h2&gt;
&lt;p&gt;What are some other ways we could achieve the same kind of results without using for-loops? In JDK 8, Java was introduced to lambdas and
&lt;code&gt;Stream&lt;/code&gt;s, which aim to vastly improve our code by allowing us to manipulate structures by passing function references to &lt;code&gt;Streams&lt;/code&gt; to
perform work. We can write code like this to do the same kind of work:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;nums.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;forEach&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;((num) &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;-&gt;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; System.out.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(num));&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a lambda that just calls &lt;code&gt;System.out.println&lt;/code&gt; on a variable called &lt;code&gt;num&lt;/code&gt; that gets initialized to a new element in the &lt;code&gt;List&lt;/code&gt;
on each invocation. We can also simplify this code even further with some syntactic sugar:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;nums.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;forEach&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(System.out&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;::&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;println);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Apart from enhanced for-loops and lambdas, the only other thing I could recommend is using the actual &lt;code&gt;Iterator&lt;/code&gt; class in conjunction with
a &lt;code&gt;while&lt;/code&gt; loop:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;java&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;Iterator&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;Integer&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt; numIterator &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; nums.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;iterator&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;while&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; (numIterator.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;hasNext&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;()) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;  System.out.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;println&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(numIterator.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;next&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;());&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This has less issues than a C-Style for-loop does, but it can still pose issues if &lt;code&gt;.next&lt;/code&gt; is called more than once within
the &lt;code&gt;while&lt;/code&gt; block. Nevertheless, it’s just as efficient as an enhanced for-loop. If I remember correctly… I think
Java bytecode compiles down in such a way that a while-loop with an &lt;code&gt;Iterator&lt;/code&gt; and an enhanced for-loop are equivalent.&lt;/p&gt;
&lt;h2 id=&quot;cases-for-c-style&quot;&gt;Cases for C-Style&lt;/h2&gt;
&lt;p&gt;So now that I’ve gone on and on about how you shouldn’t use a C-style for-loop, let’s talk about when you should actually
use one.&lt;/p&gt;
&lt;p&gt;There might be some cases when you simply cannot use an enhanced for-loop, or where the other methods I outlined don’t make
logical sense. Maybe you code has to execute a finite number of times, and it’s not based on a collection or data structure
of any kind. Maybe it’s based on some count, or a requirement stating that something needs to be done X-times.&lt;/p&gt;
&lt;p&gt;I spoke about time complexity in this post, but truth be told enhanced for-loops are not the single most efficient loop
there is. In cases involving the need to iterate over data, yes, enhanced for-loops are your best bet, but they come
at a slight performance cost of needing to keep track of the state of the &lt;code&gt;Iterator&lt;/code&gt;, as well as the additional calls
to get the info out of the &lt;code&gt;Iterator&lt;/code&gt;. For applications where performance, both in terms of memory and time
consumption, it might not be wise to utilize &lt;code&gt;Iterator&lt;/code&gt;s or enhanced for-loops.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Thanks for letting me air out my grievances about one of our oldest language constructs! If you enjoyed this post,
I’d love to hear your feedback on Twitter or Dev! Be sure to check out my blog for other posts like this!&lt;/p&gt;</content:encoded></item><item><title>Why I love Bulma</title><link>https://jvarness.blog/why-i-love-bulma/</link><guid isPermaLink="true">https://jvarness.blog/why-i-love-bulma/</guid><description>CSS is hard. Bulma makes it easy.</description><pubDate>Wed, 23 Sep 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’ve never been good at styling things. This website might be some evidence of that! 😁 But styling a website
isn’t just about picking color schemes: fonts, spacing, icons, etc… There’s a lot to consider when all I
really want to do is create a few pages that look decent.&lt;/p&gt;
&lt;p&gt;I’ve tried &lt;a href=&quot;https://getbootstrap.com/&quot;&gt;Bootstrap&lt;/a&gt; before, which has been a staple of the internet for many
years, and &lt;a href=&quot;https://tailwindcss.com/&quot;&gt;Tailwind&lt;/a&gt; has gained significant traction over the last few years,
but my go-to library for my CSS needs has been &lt;a href=&quot;https://bulma.io/&quot;&gt;Bulma&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I think I discovered Bulma through Twitter. I think someone tweeted about it, and the more I looked
into it the more interested I became. Hopefully just talking about some of the things I like about
Bulma might spark more interest in it!&lt;/p&gt;
&lt;h2 id=&quot;componentselements&quot;&gt;Components/Elements&lt;/h2&gt;
&lt;p&gt;Bulma has many components built into it that are very easy to setup, and are well documented! One big
selling point that Bulma pushes is that it’s all in one CSS file. In the big world of programming, you
can always take a bunch of different CSS files, and minify them into one file. The selling point here
is mainly to emphasize that Bulma comes with &lt;em&gt;no javascript bundle&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;90% of the time, this isn’t a problem: all of the components Bulma has to offer work without any javascript.
There is &lt;em&gt;one&lt;/em&gt; exception to this rule though, which you can find in the documentation &lt;a href=&quot;https://bulma.io/documentation/components/navbar/#navbar-menu&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;TL;DR: &lt;code&gt;navbar&lt;/code&gt; elements require some javascript to get them to appropriately collapse in mobile. The example
they have on their site has a pretty extensive javascript that’ll handle multiple navbars. I’m usually
only creating one as part of my layout, so I just slap some IDs on the elements I care about:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;jsx&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;burger&quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; onClick&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;{toggleStyles} &lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;role&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;button&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;  class&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;navbar-burger&quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; data-target&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;navMenu&quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; aria-label&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;menu&quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; aria-expanded&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;false&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; aria-hidden&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;true&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; aria-hidden&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;true&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;  &amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; aria-hidden&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;true&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;span&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;a&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;navbar-menu&quot;&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; id&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;navbarmenu&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;  &amp;#x3C;!-- other elements here --&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Toggling whether or not to make the menu visible becomes trivial using a few selectors and an &lt;code&gt;onClick&lt;/code&gt; event
bound to that burger:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;js&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;/*&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;* Added this to toggle the is-active class. See:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;* &lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;* https://bulma.io/documentation/components/navbar/#navbar-menu&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;* https://github.com/jgthms/bulma/issues/856&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6A737D&quot;&gt;*/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; toggleStyles&lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;color:#D73A49&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;  document.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;querySelector&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&apos;#burger&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;).classList.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;toggle&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&apos;is-active&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;  document.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;querySelector&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&apos;#navbarmenu&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;).classList.&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt;toggle&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&apos;is-active&apos;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One other quick tip: Microsoft Edge has issues with how Bulma has implemented navbars, but this can be fixed
with CSS. Multiple work-arounds can be found &lt;a href=&quot;https://github.com/jgthms/bulma/issues/2503&quot;&gt;here&lt;/a&gt; depending on
your use-case.&lt;/p&gt;
&lt;h2 id=&quot;customization&quot;&gt;Customization&lt;/h2&gt;
&lt;p&gt;Bulma is very variable-oriented. Pretty much everything that has a default in Bulma can be customized. Colors,
responsive breakpoints, fonts, you name it, anything can be customized!&lt;/p&gt;
&lt;p&gt;This comes in handy when you have a site that has a very particular color scheme. It’s possible to customize
the colors and sizes of a lot of elements just by setting a variable.&lt;/p&gt;
&lt;p&gt;You can check out the full list of variables &lt;a href=&quot;https://bulma.io/documentation/customize/variables/&quot;&gt;here&lt;/a&gt;. I’m
one of those individuals who tries not to put CSS in too many places. As a stylistic preference, I’m not normally
a fan of sytles within HTML or JSX. I’ll normally write one Sass file, and overwrite Bulma’s variables as needed,
and that way it gets applied throughout the whole site:&lt;/p&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;scss&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E36209&quot;&gt;$primary&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;: &lt;/span&gt;&lt;span style=&quot;color:#005CC5&quot;&gt;#c01045&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;@import &lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&apos;~bulma/scss/bulma.scss&apos;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That color I chose was as close as I could get to spelling out “colors” in hexidecimal format, but in this
example, we’re changing the &lt;code&gt;$primary&lt;/code&gt; color of Bulma. Bulma has a variety of colors that are available by
default, and they can be used for a variety of purposes, including denoting success or indicating something that
the user should give some attention to. Other colors like &lt;code&gt;$danger&lt;/code&gt; and &lt;code&gt;$warning&lt;/code&gt; can be customized to help
apply the same color across multiple components.&lt;/p&gt;
&lt;h2 id=&quot;responsiveness&quot;&gt;Responsiveness&lt;/h2&gt;
&lt;p&gt;Bulma is responsive right out of the box. There are a number of breakpoints that Bulma comes packaged with,
and they can be used in conjunction with styles to ensure that elements are displaying only when they’re supposed
to be.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://bulma.io/documentation/helpers/visibility-helpers/#hide&quot;&gt;Here&lt;/a&gt; is where an entire list of classes can
be found that can help with displaying/hiding elements based on sceensize. For example, the following
element displays differently based on screensize:&lt;/p&gt;
&lt;div class=&quot;is-hidden-touch has-background-black has-text-white&quot;&gt;You&apos;re on a larger device!&lt;/div&gt;
&lt;div class=&quot;is-hidden-desktop has-background-black has-text-white&quot;&gt;You&apos;re on a smaller device!&lt;/div&gt;
&lt;pre class=&quot;astro-code github-light&quot; style=&quot;background-color:#fff;color:#24292e; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;&quot; tabindex=&quot;0&quot; data-language=&quot;html&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;is-hidden-touch has-background-black has-text-white&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;You&apos;re on a larger device!&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#6F42C1&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#032F62&quot;&gt;&quot;is-hidden-desktop has-background-black has-text-white&quot;&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;You&apos;re on a smaller device!&amp;#x3C;/&lt;/span&gt;&lt;span style=&quot;color:#22863A&quot;&gt;div&lt;/span&gt;&lt;span style=&quot;color:#24292E&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Depending on your use-case, this could be a very nifty trick up your Bulma sleeve.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I hope that I’ve sparked a little bit of interest in Bulma with this post. If you’ve got any feedback for me, I’d
love to hear back from you! Links to my social media platforms can be found at the bottom of this page!&lt;/p&gt;</content:encoded></item><item><title>Press Start</title><link>https://jvarness.blog/press-start/</link><guid isPermaLink="true">https://jvarness.blog/press-start/</guid><description>I started a blog! Learn about me and read my ramblings!</description><pubDate>Mon, 21 Sep 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;As I start writing this, it feels so surreal and exciting. To be honest, I wasn’t sure if I would
ever start a blog. I don’t have any logistics figured out for this: &lt;em&gt;when&lt;/em&gt; should I post, or
&lt;em&gt;how often&lt;/em&gt; should I post, or really anything like that. I just know I have ideas for things
to write about, and I’m going to use this site to write about them!&lt;/p&gt;
&lt;p&gt;So who am I? I’m Jake, and I’ve spent a number of years working as a software engineer/developer. I went
to Eastern Washington University and I graduated with a Bachelor’s in Computer Science. During school, I
worked as a software developer for a company called &lt;a href=&quot;https://www.service-link.ca/&quot;&gt;Service-Link&lt;/a&gt; where
I developed a number of enhancements to their build scripts, as well as to their Android and Windows
applications. From there, I went on to work for &lt;a href=&quot;http://cerner.com/&quot;&gt;Cerner&lt;/a&gt;, and that’s where I’ve been
ever since! I started as a software engineer, and I’ve spent my career developing software used by pharmacists,
nurses, and physicians across the globe to manage patient care.&lt;/p&gt;
&lt;p&gt;For nearly the last decade, I’ve been living and breathing enterprise software development, and I’ve had my
hands on all kinds of programming languages and technologies: Java, C#, JavaScript, C++, SQL, Ruby…
I’ve done quite a bit. There are also some other languages I’ve learned for fun, like Dart and Kotlin.&lt;/p&gt;
&lt;p&gt;But enough about my LinkedIn profile, what’s this blog about?&lt;/p&gt;
&lt;p&gt;Well…&lt;/p&gt;
&lt;p&gt;To be honest I don’t have much of a plan, just ideas. I’m really just hoping that I can put this
out there, promote it, talk about different types of software engineering topics that I find interesting,
maybe meet some of you through Twitter or DEV.to along the way. This is just me… Taking a deep dive
into the world of blogging and seeing what I’ll come back up to the surface with.&lt;/p&gt;
&lt;p&gt;In the past, I’ve written blogs on &lt;a href=&quot;https://dev.to/&quot;&gt;DEV.to&lt;/a&gt;, which has an excellent following an community
for all developers. While I’ve really enjoyed blogging on there in the past… Well, you can kind of tell
that I haven’t really written much. It’s been over a year since my last post and uh… Well… It was a
joke…&lt;/p&gt;
&lt;p&gt;No, not in like a self-deprecating type of way, it was literally a &lt;a href=&quot;https://dev.to/jvarness/why-was-0110-afraid-of-0111-56nc&quot;&gt;corny joke post&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Part of my hope in creating this site is that I’ll be more motivated to keep updating it, and more
motivated to post new content and new stories and whatnot. The thought of sharing knowledge on a platform
that I’m &lt;em&gt;solely responsible for&lt;/em&gt; places that extra sense of responsibility to keep creating content.&lt;/p&gt;
&lt;p&gt;Overall, I’m really excited to start blogging, and I hope to make more posts very soon! If you
have any questions you want to ask me, you can find links to my social media profiles on the footer of
the site that you can use to contact me! Thanks for reading! Have a good one.&lt;/p&gt;</content:encoded></item></channel></rss>