<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Simon Jäger]]></title><description><![CDATA[Hi, my name is Simon, I'm a full stack developer from Switzerland.]]></description><link>https://blog.simonjaeger.ch</link><generator>RSS for Node</generator><lastBuildDate>Fri, 09 Oct 2026 02:05:05 GMT</lastBuildDate><atom:link href="https://blog.simonjaeger.ch/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Implementing 9-slice scaling with the Canvas API]]></title><description><![CDATA[The 9-slice scaling technique allows resizing an image to a different aspect ratio without any ugly distortions. This is achieved by slicing the original image into 9 rectangular parts and using those to construct the final resized image. Take a look...]]></description><link>https://blog.simonjaeger.ch/implementing-9-slice-scaling-with-the-canvas-api</link><guid isPermaLink="true">https://blog.simonjaeger.ch/implementing-9-slice-scaling-with-the-canvas-api</guid><category><![CDATA[HTML Canvas]]></category><category><![CDATA[canvas]]></category><category><![CDATA[Frontend Development]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[vanilla-js]]></category><dc:creator><![CDATA[Simon Jäger]]></dc:creator><pubDate>Fri, 22 Apr 2022 15:03:01 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1650618538594/1z3N6eh9y.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The 9-slice scaling technique allows resizing an image to a different aspect ratio without any ugly distortions. This is achieved by slicing the original image into 9 rectangular parts and using those to construct the final resized image. Take a look at the following example. In the top right, you can see the result of 9-slice scaling, while the bottom right shows the distortion that would occur with normal scaling.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1650622856565/Fj1ivSTKM.png" alt="9-slice-visualization.png" /></p>
<h2 id="heading-theory">Theory</h2>
<p>When constructing the resized image, this algorithm first positions the original corner parts (1, 3, 7, 9) in the corners of the resulting image without modifying them. Next, it positions the edge parts (2, 4, 6, 8) on the edges of the resulting image and stretches them horizontally (2, 8) and vertically (4, 6). The remaining hole in the center is filled by stretching part 5.</p>
<p>This scaling technique is useful for fancy buttons, windows and the like. By only stretching the middle parts, the corners remain as is and are safe from unintended distortions. Let's take a look at how to implement this algorithm with the HTML Canvas API and JavaScript.</p>
<h2 id="heading-implementation">Implementation</h2>
<p>Start by setting everything up. We need a canvas element, a rendering context and an image.</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> canvas = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"canvas"</span>)
canvas.width = <span class="hljs-number">1000</span>
canvas.height = <span class="hljs-number">1000</span>
<span class="hljs-keyword">const</span> ctx = canvas.getContext(<span class="hljs-string">"2d"</span>)
<span class="hljs-built_in">document</span>.body.appendChild(canvas)
<span class="hljs-keyword">const</span> img = <span class="hljs-keyword">new</span> Image()
img.src = <span class="hljs-string">"/box.png"</span>
img.onload = <span class="hljs-function">() =&gt;</span> <span class="hljs-comment">// render logic here</span>
</code></pre>
<p>As soon as the image loads, we'll start rendering. Calculate the size of a slice by dividing the image width by 3. Define each part with a 4 number tuple. The numbers represent the position (x, y) and size (width, height) of the part in the original image.</p>
<pre><code class="lang-js"><span class="hljs-comment">// calculate the size of a slice</span>
<span class="hljs-keyword">const</span> s = img.width / <span class="hljs-number">3</span>

<span class="hljs-comment">// define the 9 parts as [x, y, width, height]</span>
<span class="hljs-keyword">const</span> part1 = [<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, s, s]
<span class="hljs-keyword">const</span> part2 = [s, <span class="hljs-number">0</span>, s, s]
<span class="hljs-keyword">const</span> part3 = [s * <span class="hljs-number">2</span>, <span class="hljs-number">0</span>, s, s]
<span class="hljs-keyword">const</span> part4 = [<span class="hljs-number">0</span>, s, s, s]
<span class="hljs-keyword">const</span> part5 = [s, s, s, s]
<span class="hljs-keyword">const</span> part6 = [s * <span class="hljs-number">2</span>, s, s, s]
<span class="hljs-keyword">const</span> part7 = [<span class="hljs-number">0</span>, s * <span class="hljs-number">2</span>, s, s]
<span class="hljs-keyword">const</span> part8 = [s, s * <span class="hljs-number">2</span>, s, s]
<span class="hljs-keyword">const</span> part9 = [s * <span class="hljs-number">2</span>, s * <span class="hljs-number">2</span>, s, s]
</code></pre>
<p>To render the target image, perform a total of 9 <code>drawImage()</code> calls that implement the logic described in the beginning of this article. The parts can easily be passed to the function calls by using the spread operator.</p>
<pre><code class="lang-js">  <span class="hljs-comment">// target width/height (try different values!)</span>
  <span class="hljs-keyword">const</span> width = <span class="hljs-number">16</span> * <span class="hljs-number">8</span>
  <span class="hljs-keyword">const</span> height = <span class="hljs-number">16</span> * <span class="hljs-number">4</span>

  <span class="hljs-comment">// draw the corners</span>
  ctx.drawImage(img, ...part1, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, s, s) <span class="hljs-comment">// top left</span>
  ctx.drawImage(img, ...part3, width - s, <span class="hljs-number">0</span>, s, s) <span class="hljs-comment">// top right</span>
  ctx.drawImage(img, ...part7, <span class="hljs-number">0</span>, height - s, s, s) <span class="hljs-comment">// bottom left</span>
  ctx.drawImage(img, ...part9, width - s, height - s, s, s) <span class="hljs-comment">// bottom right</span>

  <span class="hljs-comment">// draw the edges</span>
  ctx.drawImage(img, ...part2, s, <span class="hljs-number">0</span>, width - <span class="hljs-number">2</span> * s, s) <span class="hljs-comment">// top</span>
  ctx.drawImage(img, ...part8, s, height - s, width - <span class="hljs-number">2</span> * s, s) <span class="hljs-comment">// bottom</span>
  ctx.drawImage(img, ...part4, <span class="hljs-number">0</span>, s, s, height - <span class="hljs-number">2</span> * s) <span class="hljs-comment">// left</span>
  ctx.drawImage(img, ...part6, width - s, s, s, height - <span class="hljs-number">2</span> * s) <span class="hljs-comment">// right</span>

  <span class="hljs-comment">// draw the center</span>
  ctx.drawImage(img, ...part5, s, s, width - <span class="hljs-number">2</span> * s, height - <span class="hljs-number">2</span> * s)
</code></pre>
<p>Putting it all together, we arrive at the following solution. Try changing the target width and height to make sure it works as intended. If you want to go even further, try putting the 9-slice algorithm into a reusable function.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://codepen.io/simon-jaeger/pen/rNpbjWo">https://codepen.io/simon-jaeger/pen/rNpbjWo</a></div>
<h2 id="heading-closing-remarks">Closing remarks</h2>
<p>Even though the Canvas API lacks built-in support for 9-slice scaling, it's simple enough to implement it yourself. By using this technique, images become more flexible and can be resized freely without any distortions. Where have you seen or used 9-slice scaling in the web? Let me know in the comments.</p>
<h2 id="heading-references">References</h2>
<ul>
<li>Box sprite by <a target="_blank" href="https://pixelfrog-assets.itch.io/pixel-adventure-1">PixelFrog</a></li>
<li>Unity manual: <a target="_blank" href="https://docs.unity3d.com/Manual/9SliceSprites.html">9-slicing Sprites</a></li>
<li>MDN: <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage">CanvasRenderingContext2D.drawImage()</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[A love letter to React function components]]></title><description><![CDATA[These days, we have an abundance of JavaScript frameworks to choose from. I've had my fair share of experience with a few of them, from Angular to Vue and even some Svelte and Alpine. But one Framework that stands out from the rest to me, is React. W...]]></description><link>https://blog.simonjaeger.ch/a-love-letter-to-react-function-components</link><guid isPermaLink="true">https://blog.simonjaeger.ch/a-love-letter-to-react-function-components</guid><category><![CDATA[React]]></category><category><![CDATA[JSX]]></category><category><![CDATA[javascript framework]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Frontend Development]]></category><dc:creator><![CDATA[Simon Jäger]]></dc:creator><pubDate>Sat, 16 Apr 2022 20:21:33 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1650140387876/2crJElz6o.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>These days, we have an abundance of JavaScript frameworks to choose from. I've had my fair share of experience with a few of them, from Angular to Vue and even some Svelte and Alpine. But one Framework that stands out from the rest to me, is React. Why is that? Where other frameworks create dozens of abstractions and APIs, React seemingly almost vanishes from you code by sticking very close to how JavaScript actually works. Let me explain with an example.</p>
<p>Please take a minute to think about how you'd build a simple component system with vanilla JavaScript, no framework, no nothing. Got it? Chances are, you're thinking about a simple function that takes in some parameters and returns some HTML. Something kind of like this:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// component</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Card</span>(<span class="hljs-params">props: { title: <span class="hljs-built_in">string</span>, body: <span class="hljs-built_in">string</span> }</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-string">`&lt;div&gt;
    &lt;h2&gt;<span class="hljs-subst">${props.title}</span>&lt;/h2&gt;
    &lt;p&gt;<span class="hljs-subst">${props.body}</span>&lt;/p&gt;
  &lt;/div&gt;`</span>
}

<span class="hljs-comment">// usage</span>
<span class="hljs-built_in">document</span>.body.innerHTML = <span class="hljs-string">`
  &lt;h1&gt;Welcome to my website&lt;/h1&gt;
  <span class="hljs-subst">${Card({
    title: <span class="hljs-string">"HTML"</span>,
    body: <span class="hljs-string">"Defines the meaning and structure of web content"</span>,
  }</span>)}

  <span class="hljs-subst">${Card({
    title: <span class="hljs-string">"CSS"</span>,
    body: <span class="hljs-string">"Describes the presentation of a document written in HTML"</span>,
  }</span>)}
`</span>
</code></pre>
<p>I've taken the liberty to use TypeScript to make it a bit more robust and self-documenting, but that's optional. As you can see, we're just defining a simple reusable function and call it inside our page template later to create instances of our component. Intuitive, simple and without any vendor specific boilerplate.</p>
<p>Please proceed to take a look at the following React code:</p>
<pre><code class="lang-ts"><span class="hljs-comment">// component</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Card</span>(<span class="hljs-params">props: { title: <span class="hljs-built_in">string</span>, body: <span class="hljs-built_in">string</span> }</span>) </span>{
  <span class="hljs-keyword">return</span> &lt;div&gt;
    &lt;h2&gt;{props.title}&lt;/h2&gt;
    &lt;p&gt;{props.body}&lt;/p&gt;
  &lt;/div&gt;
}

<span class="hljs-comment">// usage</span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> &lt;div&gt;
    &lt;h1&gt;Welcome to my website&lt;/h1&gt;
    &lt;Card
      title=<span class="hljs-string">"HTML"</span>
      body=<span class="hljs-string">"Defines the meaning and structure of web content"</span>
    /&gt;
    &lt;Card
      title=<span class="hljs-string">"CSS"</span>
      body=<span class="hljs-string">"Describes the presentation of a document written in HTML"</span>
    /&gt;
  &lt;/div&gt;
}
</code></pre>
<p>Looks familiar, wouldn't you agree? All I had to do is remove the backticks around the HTML and the <code>$</code> before the variable interpolation to turn the template string into what's known as JSX. And instead of calling the function directly, we can now call it with a syntax closer to normal HTML, where the tag name is the function name and the arguments are passed like attributes. Under the hood, it's still a good old function though. And that's the beauty of it.</p>
<p>Instead of introducing its own way of defining properties, like Angular or Vue do, React embraces JavaScript's native capabilities. Components are simply functions, properties simply arguments. This also means that we can do everything with them we can do with ordinary functions, like making the arguments type safe with TypeScript, again, without adding any kind of framework specific boilerplate.</p>
<p>This philosophy is why I have such high hopes for the future of React. By keeping its API light, almost invisible, the maintenance horror of future API changes reduces drastically. It's also easier to get started, because, in the end, it's just JavaScript the way you know and love it. JSX might look scary at first, especially if you aren't used to functions like <code>map()</code> or short-circuit evaluation, but I urge you to give it a try, even if you may have disliked it at first glance.</p>
<p>In my opinion, more frameworks should strive to reduce – and not increase – their surface area the way React did with its function components. Elegance lies in simplicity after all, right?</p>
]]></content:encoded></item><item><title><![CDATA[Fun with CSS variables and Tailwind]]></title><description><![CDATA[Version 3 of Tailwind includes a plethora of new and awesome features. One of them is the ability to use arbitrary values and properties in your utility classes – this even works with CSS variables! Here's the example we're going to build today:

The...]]></description><link>https://blog.simonjaeger.ch/fun-with-css-variables-and-tailwind</link><guid isPermaLink="true">https://blog.simonjaeger.ch/fun-with-css-variables-and-tailwind</guid><category><![CDATA[Tailwind CSS]]></category><category><![CDATA[CSS]]></category><category><![CDATA[CSS Animation]]></category><category><![CDATA[variables]]></category><dc:creator><![CDATA[Simon Jäger]]></dc:creator><pubDate>Thu, 14 Apr 2022 10:58:46 GMT</pubDate><content:encoded><![CDATA[<p>Version 3 of Tailwind includes a plethora of new and awesome features. One of them is the ability to use arbitrary values and properties in your utility classes – this even works with CSS variables! Here's the example we're going to build today:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1649932246768/WORStOYOc.gif" alt="hover-me.gif" /></p>
<p>The top and bottom lines should grow from 0% to 100% width when you hover over the button. Let's start with the basic html for this component:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"relative"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"absolute left-0 w-full h-1 bg-green-500 transition-all"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"p-4"</span>&gt;</span>HOVER ME<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"absolute right-0 w-full h-1 bg-green-500 transition-all"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
</code></pre>
<p>So far so good. Next, let's use Tailwind's new bracket syntax to define and use a CSS variable called <code>--fill</code> that represents the width of the lines. To do that, add <code>[--fill:0%]</code> to the button element and replace <code>w-full</code> with <code>w-[var(--fill)]</code> in both span elements.</p>
<p>The final piece of the puzzle is updating the variable on hover. Tailwind makes this easy, just add <code>hover:[--fill:100%]</code> to the button element and you're done. </p>
<p>And here's the final result:</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://codepen.io/simon-jaeger/pen/ExodgrB">https://codepen.io/simon-jaeger/pen/ExodgrB</a></div>
<p>Pretty neat! I'm looking forward to exploring this technique more in the future. Let me know in the comments if you stumble across other use cases.</p>
]]></content:encoded></item><item><title><![CDATA[Hello, world!]]></title><description><![CDATA[Hey, hi and welcome to my blog.
I've always wanted to start writing about my journey as a developer and now I've finally taken that step. After taking a look at a few different platforms for blogging, I've decided to use Hashnode. It's focused on dev...]]></description><link>https://blog.simonjaeger.ch/hello-world</link><guid isPermaLink="true">https://blog.simonjaeger.ch/hello-world</guid><dc:creator><![CDATA[Simon Jäger]]></dc:creator><pubDate>Wed, 13 Apr 2022 08:20:34 GMT</pubDate><content:encoded><![CDATA[<p>Hey, hi and welcome to my blog.</p>
<p>I've always wanted to start writing about my journey as a developer and now I've finally taken that step. After taking a look at a few different platforms for blogging, I've decided to use Hashnode. It's focused on developers, supports markdown and gives me full ownership of my blog – great!</p>
<p>Expect to see posts about all aspects of modern web development, from frontend to backend and even some devops. Thank you for visiting and consider subscribing to my newsletter to never miss a post.</p>
<p>See you around<br />Simon</p>
]]></content:encoded></item></channel></rss>