<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" version="2.0">
  <channel>
  <title>Erik Onarheim</title>
  <link>https://erikonarheim.com/</link>
  <description>Erik Onarheim</description>
  <copyright>Sat, 08 Mar 2025 00:00:00 +0000</copyright>
  <pubDate>Sat, 08 Mar 2025 00:00:00 +0000</pubDate>
  <lastBuildDate>Sat, 08 Mar 2025 00:00:00 +0000</lastBuildDate>
  
  <item>
    <title>2024 The Best Worst Year</title>
    <link>https://erikonarheim.com/posts/2024-the-best-worst-year/</link>
    <description>Erik Onarheim</description>
    <guid>https://erikonarheim.com/posts/2024-the-best-worst-year/</guid>
    <pubDate>Sat, 08 Mar 2025 00:00:00 +0000</pubDate>
    <content type="html" >&lt;h2&gt;My Darling Daughter&lt;/h2&gt;
&lt;p&gt;2024 started with paternity leave, and spending lots of time with my daughter and family. It was a wonderful time. There was more laughter than tears.&lt;/p&gt;
&lt;p&gt;Technically my daughter Maeve was born in 2023, but she&#39;s really become her own person this year. Such a wonderful human. So full of smiles and giggles, they bring me life. She&#39;s hands down been the best thing that&#39;s happened to me.&lt;/p&gt;
&lt;h2&gt;Family in Norway&lt;/h2&gt;
&lt;p&gt;The whole family in America got to travel to Norway for 2 weeks, we met with all our extended family on my father&#39;s side and reconnected with folks I haven&#39;t seen in years. I learned a lot of transactional Norwegian.&lt;/p&gt;
&lt;p&gt;We landed in Bergen and spent a week there! Our family surprised us at the airport with a big van to bring us to our lodging, I was so happy I almost cried after the long travel day. We really appreciate Sigbjorn driving us around. They brought us groceries and my great aunt even baked us a chocolate cake ❤️🎂&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/2024-the-best-worst-year/bergen-airport.jpg&quot; alt=&quot;Bergen sign outside of the airport&quot; /&gt;&lt;/p&gt;
&lt;p&gt;My cousin Margrette (though we call her aunt) loved our daughter Maeve, she was such a huge help while we were there.&lt;/p&gt;
&lt;p&gt;We stayed nearby historic &lt;a href=&quot;https://www.google.com/search?q=bryggen&quot;&gt;Bryggen&lt;/a&gt; (think colorful historic buildings on the water), which has a lot of fun food and shopping. We ate some traditional fair at &lt;a href=&quot;https://www.bryggeloftet.no/meny&quot;&gt;Bryggeloftet&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/2024-the-best-worst-year/bryggen-road.jpg&quot; alt=&quot;Street where the family is walking in Bryggen by the Julehuset (Christmas House in Norwegian)&quot; /&gt;&lt;/p&gt;
&lt;p&gt;One of the most memorable was our visit to the village of &lt;a href=&quot;https://en.wikipedia.org/wiki/Onarheim&quot;&gt;Onarheim on the island of Tysnesøya&lt;/a&gt; to see the family farm and have a big reunion.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/2024-the-best-worst-year/onarheim.jpg&quot; alt=&quot;Road sign for the village of Onarheim&quot; /&gt;&lt;/p&gt;
&lt;p&gt;We took the scenic train ride across Norway to Oslo, which was absolutely wonderful! You should definitely take this train ride if you visit.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/2024-the-best-worst-year/train3.jpg&quot; alt=&quot;Between Bergen and Oslo&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;NDC Oslo 2024&lt;/h2&gt;
&lt;p&gt;While in Norway, I presented at the prestigious NDC Oslo! I gave my spicy talk about serverless tech &amp;quot;&lt;a href=&quot;https://www.youtube.com/watch?v=xfkqNLzQCX8&quot;&gt;You Don&#39;t Want Serverless&lt;/a&gt;&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/2024-the-best-worst-year/ndc-2024.jpg&quot; alt=&quot;Erik on Stage at NDC Oslo 2024&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Serverless is a lose-lose. Don&#39;t use it. There&#39;s been a lot of over-hype around it and I&#39;m here to tell you not to buy in.&lt;/p&gt;
&lt;p&gt;I&#39;ll talk about the various shortcomings, mitigations, and solutions!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cloud provider business incentive misalignment&lt;/li&gt;
&lt;li&gt;Very poor developer experience&lt;/li&gt;
&lt;li&gt;Cold starts and performance problems&lt;/li&gt;
&lt;li&gt;Concurrency myths&lt;/li&gt;
&lt;li&gt;Cheap cost myths&lt;/li&gt;
&lt;li&gt;Finally when you &lt;em&gt;should&lt;/em&gt; use serverless, spoiler alert there are very few use cases that make sense&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At the end of this you&#39;ll know when and where to use serverless, and when to use &amp;quot;boring&amp;quot; technology to solve your problems.&lt;/p&gt;
&lt;h2&gt;NDC Oslo 2025&lt;/h2&gt;
&lt;p&gt;I&#39;ll be back in Norway in 2025 about how to make &lt;a href=&quot;https://ndcoslo.com/agenda/javascript-blazingly-fast-lessons-from-a-game-engine-0qrq/0lubfjy6nxx&quot;&gt;&lt;strong&gt;JavaScript Blazingly fast! lessons from a game engine&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Is your app slow? Don&#39;t blame JavaScript! It might be a problem between the chair and the keyboard...&lt;/p&gt;
&lt;p&gt;I&#39;ve spent over a decade building a game engine for the web called excalibur.js, I&#39;ve learned a ton of tricks and techniques to make JavaScript run BLAZINGLY fast. These learnings are broadly applicable to more than just games, they&#39;ve been very useful in my day to day work building massive web applications for EdTech.&lt;/p&gt;
&lt;p&gt;You&#39;ll learn how to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Demystify the browser performance tools in Chrome &amp;amp; Firefox&lt;/li&gt;
&lt;li&gt;Optimize slow functions&lt;/li&gt;
&lt;li&gt;Identify and prevent memory leaks&lt;/li&gt;
&lt;li&gt;Cache expensive computations&lt;/li&gt;
&lt;li&gt;Prevent regressions&lt;/li&gt;
&lt;li&gt;And when to use WebWorkers, WASM, WebGPU, and TypedArrays&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You&#39;ll walk away with practical JavaScript optimization techniques you can apply RIGHT NOW!&lt;/p&gt;
&lt;h2&gt;Death&lt;/h2&gt;
&lt;p&gt;In August my father passed away suddenly. It&#39;s been pretty hard. He was a great man, and a wonderful father. Great listener, full of laughter, and always quick with a joke.&lt;/p&gt;
&lt;p&gt;He loved our daughter, and I&#39;m glad she was able to meet him. Also he fed her a chocolate donut 🍩 when babysitting instead of the baby food I left him. They were two peas in a pod, that girly sure does love chocolate, always room for dessert.&lt;/p&gt;
&lt;p&gt;I&#39;m glad we were able to take him to Norway, he has wanted to visit again for years. The last time he was there he was 12 years old with his mother and father.&lt;/p&gt;
&lt;p&gt;Navigating the world without him has been challenging for the entire family. So many things remind me of him, he brought a lot of smiles to all of us.&lt;/p&gt;
&lt;h2&gt;2D Con&lt;/h2&gt;
&lt;p&gt;Excalibur did its first convention at 2D Con in August in Bloomington Minnesota! And we won a gameplay award at the show!?&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/2024-the-best-worst-year/2d-con.jpg&quot; alt=&quot;booth at 2D con, Kamran is setting up&quot; /&gt;&lt;/p&gt;
&lt;p&gt;We presented 3 of our high fidelity sample games&lt;/p&gt;
&lt;h3&gt;Sweepstacks&lt;/h3&gt;
&lt;p&gt;Sweep across the screen to clear blocks! It&#39;s a match-3 like where you can also match diagonals.&lt;/p&gt;
&lt;p&gt;This game was originally created for Ludum Dare 31 where it placed in the top 100. Coming soon to app stores near you!&lt;/p&gt;
&lt;p&gt;Click on the image to play! (Warning addictive)&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://excaliburjs.com/sweep/&quot;&gt;&lt;img src=&quot;https://erikonarheim.com/images/2024-the-best-worst-year/sweepstacks.png&quot; alt=&quot;sweepstacks&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Sum Monsters&lt;/h3&gt;
&lt;p&gt;Play the mathimagical game where you arrange monsters to complete the dungeon’s sum-mons. May Trix the Witch is doing all she can to bring the dungeon to order!&lt;/p&gt;
&lt;p&gt;It&#39;s like sudoku, except you&#39;re trying to sum the rows and columns to the desired number to clear the stage&lt;/p&gt;
&lt;p&gt;Click on the image to play! (Warning addictive)&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://excaliburjs.com/sum-monsters/&quot;&gt;&lt;img src=&quot;https://erikonarheim.com/images/2024-the-best-worst-year/summonsters.png&quot; alt=&quot;sum monsters&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Jelly Jumper&lt;/h3&gt;
&lt;p&gt;High fidelity sample of a platforming game with jump physics inspired by Super Mario World!&lt;/p&gt;
&lt;p&gt;This was created with painstaking effort by our new maintainer Matt Jennings.&lt;/p&gt;
&lt;p&gt;Click on the image to play!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://excaliburjs.com/sample-jelly-jumper/&quot;&gt;&lt;img src=&quot;https://erikonarheim.com/images/2024-the-best-worst-year/jelly-jumper.gif&quot; alt=&quot;jelly jumper&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Distance Running&lt;/h2&gt;
&lt;p&gt;Not my best running year, I&#39;ve definitely slowed down from my successful sub-4 hour marathon at Grandma&#39;s in 2023. My plan for this year is to keep it simple, work on the fundamentals and base build then race again in 2026. My new goal is to run sub 3:30, and eventually I&#39;d like to qualify for the Boston marathon.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/2024-the-best-worst-year/marathon.jpg&quot; alt=&quot;sub-4 hour run at grandma&#39;s marathon&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;IGDATC (International Game Developers Association Twin Cities)&lt;/h2&gt;
&lt;p&gt;Pronounced &amp;quot;igg-daa-TC&amp;quot; by the locals 😁&lt;/p&gt;
&lt;p&gt;I&#39;ve recently become very active in the IGDATC, volunteering, speaking, and attending events.&lt;/p&gt;
&lt;p&gt;I&#39;ve made a lot of new very talented friends that have been wonderful, and they are willing to listen my nonsense about games in JavaScript/TypeScript. I&#39;m especially fond of our late night Applebee&#39;s/Mac&#39;s game dev discussions.&lt;/p&gt;
&lt;p&gt;Presented about building &lt;a href=&quot;https://www.youtube.com/watch?v=-pvSQkigIYA&quot;&gt;Excalibur.js, the Friendly Open Source Game Engine&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
    &lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/-pvSQkigIYA?si=RdOCgCntUbkwyQAG&quot; title=&quot;YouTube video player&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen=&quot;&quot;&gt;
    &lt;/iframe&gt;
&lt;/p&gt;
&lt;h2&gt;Excalibur&lt;/h2&gt;
&lt;p&gt;Excalibur has had a BIG year!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;We&#39;ve added 2 new official maintainers with commit access, &lt;a href=&quot;https://github.com/jyoung4242&quot;&gt;Justin Young&lt;/a&gt; and &lt;a href=&quot;https://github.com/mattjennings&quot;&gt;Matt Jennings!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;We did our first con! (2D Con!)&lt;/li&gt;
&lt;li&gt;Started a &lt;a href=&quot;https://discord.gg/W6zUd4tTY3&quot;&gt;Discord&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Saw Huge community growth&lt;/li&gt;
&lt;li&gt;Tons of cool stuff being built&lt;/li&gt;
&lt;li&gt;Tons of &lt;a href=&quot;https://github.com/excaliburjs/Excalibur/releases&quot;&gt;new features&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;New plugins: &lt;a href=&quot;https://github.com/excaliburjs/excalibur-tiled/&quot;&gt;Tiled Rewrite&lt;/a&gt;, &lt;a href=&quot;https://github.com/excaliburjs/excalibur-ldtk/&quot;&gt;LDtk&lt;/a&gt;, &lt;a href=&quot;https://github.com/excaliburjs/excalibur-spritefusion/&quot;&gt;Spritefusion&lt;/a&gt;, &lt;a href=&quot;https://github.com/excaliburjs/excalibur-pathfinding/&quot;&gt;Path Finding&lt;/a&gt;, &lt;a href=&quot;https://github.com/excaliburjs/excalibur-jsfxr/&quot;&gt;JSFXR&lt;/a&gt;, and more!&lt;/li&gt;
&lt;li&gt;Large number of &lt;a href=&quot;https://github.com/excaliburjs/Excalibur/releases/tag/v0.30.0&quot;&gt;new contributors&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Check out my &lt;a href=&quot;https://excaliburjs.com/blog&quot;&gt;other posts about excalibur&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Caliburn Games&lt;/h2&gt;
&lt;p&gt;Started a business to publish and make games in Excalibur.js&lt;/p&gt;
&lt;p&gt;We&#39;re currently offering custom development projects, game dev consulting, and professional support!&lt;/p&gt;
&lt;p&gt;Check us out if you&#39;re interested! &lt;a href=&quot;https://caliburn.games/products/&quot;&gt;Caliburn Games&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Our plan for 2025 is to release 2 commercial games on various platforms AND offer Nintendo Switch Console publishing!!!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/2024-the-best-worst-year/switch.jpg&quot; alt=&quot;nintendo switch&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;C Programming&lt;/h2&gt;
&lt;p&gt;One of my goals this year was to re-learn C. I definitely did classes in university but I don&#39;t really think I understood it that well.&lt;/p&gt;
&lt;p&gt;One reason C appeals to me is that it&#39;s the original lingua franca of computers, if it can run in C it can run anywhere. Similarly JavaScript has become the new lingua franca, running everywhere with Electron, Capacitor.js, Tauri, etc. I&#39;m attracted to the simplicity and portability of C.&lt;/p&gt;
&lt;p&gt;One of the coolest things is that the Lua interpreter &amp;quot;lua.c&amp;quot; is a &lt;a href=&quot;https://www.lua.org/download.html&quot;&gt;single iso C file&lt;/a&gt; meaning its super easy to include ANYWHERE because of the portability of C. Heck Balatro was written in Lua with &lt;a href=&quot;https://love2d.org/&quot;&gt;Love2D&lt;/a&gt;! Really speaks to the power of C.&lt;/p&gt;
&lt;p&gt;I picked up the book &amp;quot;&lt;a href=&quot;https://www.amazon.com/gp/product/1718501048/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&amp;amp;psc=1&quot;&gt;Effective C&lt;/a&gt;&amp;quot; and can recommend . I&#39;ve pre-ordered &lt;a href=&quot;https://www.amazon.com/gp/product/1633437779/ref=ppx_yo_dt_b_asin_title_o01_s00?ie=UTF8&amp;amp;psc=1&quot;&gt;Modern C, 3rd Edition C23&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I spent this year&#39;s Advent of Code learning modern C 23 and clang, you can observe my probably poorly written C &lt;a href=&quot;https://github.com/eonarheim/advent-of-code-2024&quot;&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Neovim &amp;amp; RSI&lt;/h2&gt;
&lt;p&gt;Another bummer is I&#39;ve managed to develop a RSI (repetitive stress injury) this year in my hands! It really sucks! It&#39;s quite painful to pick things up wrong, or to lean incorrectly on my fingers.&lt;/p&gt;
&lt;p&gt;I&#39;m learning Neovim to hopefully help this, and it&#39;s definitely taken me a solid 2 months to get fast in it. I&#39;m pretty fast now-a-days, this blog post was written in neovim!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/2024-the-best-worst-year/neovim-logo-shadow.png&quot; alt=&quot;neovim logo&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I&#39;m looking into ergonomic keyboards. I think concave key wells are probably my best bet. I&#39;ve yet to purchase one, so if y&#39;all have some affordable recommendations send them my way.&lt;/p&gt;
&lt;h2&gt;Optimism, Dreams, and Schemes&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Despite the disappointing and terrible events in 2024, I remain optimistic about the future. Even though life will be very different, and probably really hard for the next few years, we have good friends and family to get us through. I want to have a world my daughter can grow up in where she&#39;ll have the most opportunity possible.&lt;/li&gt;
&lt;li&gt;I&#39;m excited about my business&lt;/li&gt;
&lt;li&gt;Planning on shipping a commercial game this year using Excalibur.js to Nintendo Switch! It&#39;s going to be something chill and cozy that everyone can enjoy.&lt;/li&gt;
&lt;li&gt;We have a conference coming up at VGM Con in April 2025!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Cheers,&lt;/p&gt;
&lt;p&gt;Erik&lt;/p&gt;
</content>
  </item>
  
  <item>
    <title>Animating with Coroutines</title>
    <link>https://erikonarheim.com/posts/animating-with-coroutines/</link>
    <description>Erik Onarheim</description>
    <guid>https://erikonarheim.com/posts/animating-with-coroutines/</guid>
    <pubDate>Thu, 02 Jun 2022 00:00:00 +0000</pubDate>
    <content type="html" >&lt;div style=&quot;width:100%;height:0;padding-bottom:60%;position:relative;&quot;&gt;&lt;iframe src=&quot;https://giphy.com/embed/8vznMJFViyp8mLy1xr&quot; width=&quot;100%&quot; height=&quot;100%&quot; style=&quot;position:absolute&quot; frameBorder=&quot;0&quot; class=&quot;giphy-embed&quot; allowFullScreen=&quot;&quot;&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;p&gt;Using an concept known as coroutines you can produce some really nice looking imperative animation code! I was inspired by &lt;a href=&quot;https://youtu.be/09V_JAGTs2E&quot;&gt;two&lt;/a&gt; &lt;a href=&quot;https://youtu.be/WTUafAwrunE&quot;&gt;great&lt;/a&gt; YouTube videos recently to try a new approach to building animations in games.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Look at this nice imperative animation code 😎&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;coroutine&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;animation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// scale the entity 2x over 1000 ms duration&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;scaleTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entity&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// delay animation 1000 ms duration&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;delay&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// move the entity to (200, 100) 500 ms duration&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;moveTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entity&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;x&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; y&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// rotate the entity to 4 PI  over 1000 ms duration&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rotateTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entity&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PI&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;TLDR &lt;a href=&quot;https://github.com/eonarheim/coroutine-animations&quot;&gt;show me the code&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;What is a coroutine anyway?&lt;/h2&gt;
&lt;p&gt;The word &amp;quot;coroutine&amp;quot; definitely sounds fancy! Coroutines are a type of suspendable execution. They are a useful way of simulating concurrent tasks or sequences over time without blocking the main thread. They are made possible by a new(ish) feature in JavaScript called generators!&lt;/p&gt;
&lt;p&gt;Why are they called &amp;quot;coroutines&amp;quot;? Well it&#39;s because they cooperatively share execution. In our example below the coroutine passes control into the generator, and it &lt;code&gt;yield&lt;/code&gt;&#39;s control back up to the coroutine.&lt;/p&gt;
&lt;p&gt;In our example, we are working with animation&#39;s over time, so each &lt;code&gt;yield&lt;/code&gt; can be thought of as a single frame that takes an &amp;quot;elapsed&amp;quot; amount of time.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;coroutine&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;generatorFunction&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; Generator&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; generator &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;generatorFunction&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// instantiate the coroutine&lt;/span&gt;&lt;br /&gt;    generator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// execute until the first yield to start the generator&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;elapsed&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; generator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;elapsed&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;coroutine&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;myAnimation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; elapsed&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// each yield represents a frame&lt;/span&gt;&lt;br /&gt;    elapsed &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// frame 1&lt;/span&gt;&lt;br /&gt;    elapsed &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// frame 2&lt;/span&gt;&lt;br /&gt;    elapsed &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// frame 3&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Implementing Animations with &lt;code&gt;requestAnimationFrame&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;We need something to drive updating each frame for our animations, we can use a classic game update approach with &lt;code&gt;requestAnimationFrame&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; lastTime &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; performance&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; running &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;mainloop&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;time&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;running&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token function&quot;&gt;requestAnimationFrame&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mainloop&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; now &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; time&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; elapsed &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; now &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; lastTime&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// update coroutines&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; animation &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; animations&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token function&quot;&gt;animation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;elapsed&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// draw stuff&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token function&quot;&gt;clear&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token function&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; elapsed&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        lastTime &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; now&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        running &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;mainloop&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;performance&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;animations&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;coroutine&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;myAnimation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can use our fancy coroutines to make some fancy animations!&lt;/p&gt;
&lt;h3&gt;MoveTo Generator with Linear Interpolation&lt;/h3&gt;
&lt;p&gt;We can build some animation primitives. One of the first things you might want to do is move things around, something like &lt;code&gt;moveTo&lt;/code&gt; which will animate an entity to a set of coordinates over a duration.&lt;/p&gt;
&lt;p&gt;First things first we&#39;ll need to define a &amp;quot;Linearly Interpolate&amp;quot; function, or as they say in the biz &amp;quot;lerp&amp;quot;. Traditionally easing functions like &lt;code&gt;lerp&lt;/code&gt; specify a numeric &lt;code&gt;start&lt;/code&gt; and &lt;code&gt;end&lt;/code&gt; value, and a &lt;code&gt;time&lt;/code&gt; between 0 and 1.&lt;/p&gt;
&lt;p&gt;This means that when time is 0, we return the start, and when time is 1 we return the end, else we mix them. Looking at our example below that math checks out. You can think of this as a weighted average between the start and end over time 😎&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;lerp&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;start&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; end&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; time&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; start &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;time&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; end &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; time&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Another useful helper is &lt;code&gt;clamp&lt;/code&gt;, which is useful for keep a value between an upper and lower bound. And it is important that our &lt;code&gt;time&lt;/code&gt; passed to &lt;code&gt;lerp&lt;/code&gt; stays in between 0 and 1.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;clamp&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;val&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; min&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; max&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;min&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;max&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;val&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; min&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we have those utilities explained, let&#39;s start with the basic structure of our animation generator:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;moveTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entity&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Entity&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; destination&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;x&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; y&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; durationMs&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; totalTime &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; elapsed &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        totalTime &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; elapsed&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// TODO implement the rest&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The first thing you might notice above is the apparent &lt;strong&gt;infinite loop!&lt;/strong&gt; Believe it or not this is totally okay in a generator, the &lt;code&gt;yield&lt;/code&gt; will pause execution and &amp;quot;yield&amp;quot; it back up to our main loop for the next animation.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The second thing you might notice is &lt;code&gt;let elapsed = yield;&lt;/code&gt; this is sort of wild, but the &lt;code&gt;yield&lt;/code&gt; &lt;strong&gt;acts like a two way return!&lt;/strong&gt; Things can be passed down into the generator and they fall out left hand side, but also things can be passed back out of the generator if on the right, for example &lt;code&gt;yield 42;&lt;/code&gt; will &amp;quot;return&amp;quot; 42 up to the caller. This in/out duality in generators makes them ideal for coroutines.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Next we can use JavaScript scope to capture the entities original x/y position. Notice that it is above the yield.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;moveTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entity&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Entity&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; destination&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;x&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; y&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; durationMs&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; totalTime &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Capture the original position&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; x&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; originalX&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; y&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; originalY &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; entity&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; elapsed &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        totalTime &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; elapsed&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// TODO implement the rest&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then Convert our current totalTime to something between 0 and 1 for our &lt;code&gt;lerp&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; currentTime &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;clamp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;totalTime &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; durationMs&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then the meat of our &lt;code&gt;moveTo&lt;/code&gt; is calculating the &lt;code&gt;lerp&lt;/code&gt; and setting the properties on the entity we are animating!&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; currentX &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lerp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;originalX&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; destination&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; currentTime&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; currentY &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lerp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;originalY&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; destination&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; currentTime&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;entity&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; currentX&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;entity&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; currentY&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;totalTime &lt;span class=&quot;token operator&quot;&gt;&gt;=&lt;/span&gt; durationMs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;moveTo complete&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; currentX&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; currentY&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, putting the whole thing together it looks like this&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;moveTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entity&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Entity&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; destination&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;x&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; y&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; durationMs&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; totalTime &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; x&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; originalX&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; y&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; originalY&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; entity&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; elapsed &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        totalTime &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; elapsed&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; currentTime &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;clamp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;totalTime &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; durationMs&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; currentX &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lerp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;originalX&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; destination&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; currentTime&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; currentY &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;lerp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;originalY&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; destination&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; currentTime&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        entity&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; currentX&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        entity&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; currentY&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;totalTime &lt;span class=&quot;token operator&quot;&gt;&gt;=&lt;/span&gt; durationMs&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;moveTo complete&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; currentX&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; currentY&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;        &lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here is an example of our &lt;code&gt;moveTo&lt;/code&gt; animations in action, each animation runs in sequence on after the other!&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;yeild*&lt;/code&gt; is a new piece of syntax but it basically means that if the thing to the right is a generator, dig into and run that generator! Cool right?&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;coroutine&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;boxAnimation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;moveTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entity&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;x&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; y&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;550&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;moveTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entity&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;x&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;750&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; y&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;550&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;moveTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entity&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;x&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;750&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; y&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;moveTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entity&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;x&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; y&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/animating-with-coroutines/box-animation.gif&quot; alt=&quot;box animating counter clockwise around the screen&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Concurrency with Coroutines&lt;/h2&gt;
&lt;p&gt;There are more cool tricks we can play, like simulating concurrent animations with coroutines!&lt;/p&gt;
&lt;p&gt;Let&#39;s say in addition to &lt;code&gt;moveTo&lt;/code&gt; I also create a &lt;code&gt;rotateTo&lt;/code&gt; and a &lt;code&gt;scaleTo&lt;/code&gt; animation, AND I want to do all three at once! Well now that we have generators helping us out we can drive multiple generators at the same time.&lt;/p&gt;
&lt;p&gt;In this example we grab a list of our animations, and drive them until they are all done:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;parallel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;animations&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Generator&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; elapsed &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; results&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; IteratorResult&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// Drive each animation 1 frame&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; anim &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; animations&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            results&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;anim&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;next&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;elapsed&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// Wait to all the child animations are done&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;results&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;every&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;f &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; f&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;done&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;See how it reads in usage:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;coroutine&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;boxAnimation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// animations run in parallel&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;parallel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token function&quot;&gt;moveTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entity&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;x&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;400&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; y&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;400&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token function&quot;&gt;rotateTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entity&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PI&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token function&quot;&gt;scaleTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entity&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/animating-with-coroutines/box-parallel-animation.gif&quot; alt=&quot;!box moving, rotating, and scaling at the same time&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Wrapping Sequences with Coroutines&lt;/h2&gt;
&lt;p&gt;Sometimes it&#39;s useful to specify different groups of animations that you want to run.&lt;/p&gt;
&lt;p&gt;This collects up the animations and runs each of them!&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sequence&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;animations&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Generator&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;generatorSequence&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; generator &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; animations&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; generator&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we can run 2 separate sequential animations AT THE SAME TIME! 🤯&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;coroutine&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;manyBoxesAnimation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;parallel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token function&quot;&gt;sequence&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token function&quot;&gt;moveTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;yellowEntity&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;x&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; y&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;550&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token function&quot;&gt;moveTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;yellowEntity&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;x&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;750&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; y&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;550&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token function&quot;&gt;moveTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;yellowEntity&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;x&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;750&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; y&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token function&quot;&gt;moveTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;yellowEntity&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;x&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; y&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token function&quot;&gt;sequence&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token function&quot;&gt;moveTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;greenEntity&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;x&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;750&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; y&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token function&quot;&gt;moveTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;greenEntity&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;x&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;750&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; y&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;550&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token function&quot;&gt;moveTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;greenEntity&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;x&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; y&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;550&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token function&quot;&gt;moveTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;greenEntity&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;x&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; y&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/animating-with-coroutines/box-parallel-sequences-animation.gif&quot; alt=&quot;Two boxes animating at the same time&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I hope this helps you aspiring game devs out there who are trying to build some animations!&lt;/p&gt;
&lt;iframe src=&quot;https://codesandbox.io/embed/dazzling-moore-ywpyrx?fontsize=14&amp;hidenavigation=1&amp;theme=dark&amp;view=preview&quot; style=&quot;width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;&quot; title=&quot;coroutine-animations&quot; allow=&quot;accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking&quot; sandbox=&quot;allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/eonarheim/coroutine-animations&quot;&gt;Check out the code and play around&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;-Erik&lt;/p&gt;
</content>
  </item>
  
  <item>
    <title>Handling Height in Isometric Tile Maps</title>
    <link>https://erikonarheim.com/posts/handling-height-in-isometric/</link>
    <description>Erik Onarheim</description>
    <guid>https://erikonarheim.com/posts/handling-height-in-isometric/</guid>
    <pubDate>Wed, 02 Feb 2022 00:00:00 +0000</pubDate>
    <content type="html" >&lt;p&gt;Some of my favorite games are isometric styled. I played a lot of &amp;quot;Super Mario RPG&amp;quot; and &amp;quot;Final Fantasy Tactics&amp;quot; in my day and I&#39;ve always wanted to build isometric games 😎&lt;/p&gt;
&lt;p&gt;With that desire in mind, I&#39;ve been working on Tiled map editor support for Excalibur. Simulating and drawing tiles at a certain height can be tricky with z-indexing. In this post I&#39;ll talk about drawing isometric maps and some of the techniques I used to produce a height illusion in an isometric map with a moving character.&lt;/p&gt;
&lt;p&gt;TLDR &lt;a href=&quot;https://github.com/eonarheim/isometric-layers&quot;&gt;show me the code&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Isometric Math&lt;/h2&gt;
&lt;p&gt;There is a &lt;a href=&quot;https://clintbellanger.net/articles/isometric_math/&quot;&gt;great post&lt;/a&gt; by Clint Bellanger that goes into detail about the derivation of the math. I highly recommend reading his post for a nuanced understanding of the math.&lt;/p&gt;
&lt;p&gt;Here is the basics though: given a 2D grid of tiles, we need to draw it effectively rotated by 45 degrees to produce the isometric 2.5 illusion. A common approach to drawing this in pixel art this is 2 pixels over and 1 down.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/handling-height-in-isometric/isometric-rotation.png&quot; alt=&quot;Image demonstrating rotation of isometric maps compared to the traditional 2D case&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Okay let&#39;s say our tile data structure looks like below, each tile has its x/y coordinate, a screen position, and a image to show, and the &lt;code&gt;IsometricMap&lt;/code&gt; contains a list of &lt;code&gt;Tile&lt;/code&gt;s.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Tile&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; x&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; y&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; screenX&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; screenY&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; image&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; HTMLImageElement&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; map&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; IsometricMap&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;IsometricMap&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; tiles&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Tile&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; widthInTiles&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; heightInTiles&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; tileWidthPx&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; tileHeightPx&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Calculating Screen Position&lt;/h3&gt;
&lt;p&gt;Here is my verbal reasoning for the isometric formula, again I recommend reading Clint&#39;s post for more nuance.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;For each positive step in x tile coordinate, the final drawing is shifted down screen y and right in screen x by half a tile&lt;/li&gt;
&lt;li&gt;For each positive step in y tile coordinate, the final drawing is shifted down screen y and left in screen x by half a tile&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If we combine all the x changes and y changes we get:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;IsometricMap&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;/**&lt;br /&gt;     * Returns the top left corner of the tile in screen coordinates&lt;br /&gt;     */&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;tileCoordinateToScreen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tileX&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; tileY&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; halfTileWidth &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tileWidthPx &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; halfTileHeight &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tileHeightPx &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// each screen x is dependent on tile.x to the right &amp;amp; tile.y to the left&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; screenX &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tileX &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; tileY&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; halfTileWidth&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// each screen y is dependent on tile.x down &amp;amp; tile.y down&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; screenY &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tileX &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; tileY&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; halfTileHeight&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;screenX&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; screenY&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Selecting Tile width and height based on assets&lt;/h2&gt;
&lt;p&gt;The tile height should be the height of the base parallelogram &lt;strong&gt;not the height of the tile image asset&lt;/strong&gt; necessarily.&lt;/p&gt;
&lt;p&gt;For example if your tile is &amp;quot;flat&amp;quot;, the height of the parallelogram and the image are the same.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/handling-height-in-isometric/flat.png&quot; alt=&quot;Example of a &amp;quot;flat&amp;quot; tile asset where the heights are teh same&quot; /&gt;&lt;/p&gt;
&lt;p&gt;With other art assets the logical height can be different, in this case roughly half the height of the asset. This height will depend on your art assets.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/handling-height-in-isometric/grass.png&quot; alt=&quot;Example of a more 3d shape where the heights are not the same&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Drawing isometric tiles&lt;/h2&gt;
&lt;p&gt;Drawing isometric maps can be slightly different from your traditional 2D maps, specifically it is often convenient to draw isometric tiles from the bottom left instead of the top right in the traditional 2D case. (The &lt;a href=&quot;https://www.mapeditor.org/&quot;&gt;Tiled editor&lt;/a&gt; does this)&lt;/p&gt;
&lt;p&gt;One reason to draw from the bottom, is this preserves the mental model of placing a 3D object down on the grid&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/handling-height-in-isometric/grid.png&quot; alt=&quot;Placing an object on a grid&quot; /&gt;&lt;/p&gt;
&lt;p&gt;To accomplish this we need to offset our screen coordinates, by the full height of our tile image.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Tile&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; x&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; y&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; screenX&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; screenY&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; image&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; HTMLImageElement&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; map&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; IsometricMap&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;gfx&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CanvasRenderingContext2D&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;image&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; halfTileWidth &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;image&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        gfx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// shift left origin to corner of map, not the left corner of the first sprite&lt;/span&gt;&lt;br /&gt;        gfx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;translate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;halfTileWidth&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        gfx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;translate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;screenX&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;screenY&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// shift the image up to draw from the bottom (minus tile height)&lt;/span&gt;&lt;br /&gt;        gfx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;drawImage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;image&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;image&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;map&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tileHeightPx&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        gfx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;restore&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Multiple isometric tiles at different &amp;quot;elevation&amp;quot;&lt;/h2&gt;
&lt;p&gt;This is were things can get tricky, because as a player or objects move in your environment the order in which each tile or object needs be drawn must change to preserve the illusion.&lt;/p&gt;
&lt;p&gt;Conceptually, as objects move &amp;quot;closer&amp;quot; to the screen they need to be drawn last (the classic painter technique of painting close things last).&lt;/p&gt;
&lt;p&gt;Z-index is a useful way to think about closeness to the screen that developers might be familiar with. Given a high z-index, this means an object is close to the screen, and low z-index further away.&lt;/p&gt;
&lt;h3&gt;Solution: Sort entity draw by z-index&lt;/h3&gt;
&lt;p&gt;One way to make the illusion work is to sort our objects by a z-index that we calculate every frame from a synthetic &amp;quot;elevation&amp;quot;.&lt;/p&gt;
&lt;p&gt;First add &lt;code&gt;z&lt;/code&gt; and &lt;code&gt;elevation&lt;/code&gt; to your entity implementation.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Entity&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    z&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// distance to the screen&lt;/span&gt;&lt;br /&gt;    elevation&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// &quot;height&quot; of the layer in the illusion&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Tile&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Entity&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// add z and elevation to implementation&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Player&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Entity&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// add z and elevation to implementation&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Set your entities to the desired elevation for your simulation.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Set the elevation of the ground tiles&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; ground &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;IsometricMap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;ground&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tiles&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;t &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; t&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;elevation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Set the elevation of the box tiles&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; boxes &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;IsometricMap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;boxes&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tiles&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;t &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; t&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;elevation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Set the elevation of the player, the player will be at the&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// same elevation as the boxes&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; player &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Player&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;player&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;elevation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Process through all the entities&#39; &lt;code&gt;elevation&lt;/code&gt; and calculate the correct z-index given their position on screen at any given time, then sort before drawing them all. This lets object move about and retain the proper draw order based on z-index.&lt;/p&gt;
&lt;p&gt;The trick is to pick the maximum possible y-coordinate for your game screen, this allows you to bucket each &lt;code&gt;elevation&lt;/code&gt; into its own range of z-indexes. For example the grass tiles will never be drawn in front of the box tiles because they are at a different elevation.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Some canvas details omitted for brevity&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// See full code: https://github.com/eonarheim/isometric-layers&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; entities &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;ground&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tiles&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;boxes&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tiles&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; player&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;processElevation&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entity&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Entity&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; maxZIndexPerElevation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;600&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; newZ &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; maxZIndexPerElevation &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; entity&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;elevation &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; entity&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;screenY&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    entity&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;z &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; newZ&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;clearScreen&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;gfx&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CanvasRenderingContext2D&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    gfx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fillStyle &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;#176BAA&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    gfx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fillRect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;mainloop&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;requestAnimationFrame&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mainloop&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;clearScreen&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;gfx&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Given the elevation and y coord calculate the correct z-index&lt;/span&gt;&lt;br /&gt;    entities&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;processElevation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;e&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Sort entities in place&lt;/span&gt;&lt;br /&gt;    entities&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; a&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;z &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;z&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Draw our entities&lt;/span&gt;&lt;br /&gt;    gfx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    gfx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;translate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;400&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; entity &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; entities&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        entity&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;gfx&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    gfx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;restore&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;mainloop&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Voila! 🎉&lt;/p&gt;
&lt;p&gt;In this example all the green grass tiles have &lt;code&gt;elevation = 0&lt;/code&gt; and the black cube and boxes have &lt;code&gt;elevation = 1&lt;/code&gt;. Notice how the black cube is properly in front of the box tile to the left, but behind the box tile to the right.&lt;/p&gt;
&lt;p&gt;Check out the &lt;a href=&quot;https://github.com/eonarheim/isometric-layers&quot;&gt;code and play around&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/handling-height-in-isometric/example.png&quot; alt=&quot;Example of z index appropriately sorting drawings&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Hope this helps you isometric game enthusiasts out there!&lt;/p&gt;
&lt;p&gt;-Erik&lt;/p&gt;
</content>
  </item>
  
  <item>
    <title>Excalibur v0.25.2 Released!</title>
    <link>https://erikonarheim.com/posts/excalibur-v0252-released/</link>
    <description>Erik Onarheim</description>
    <guid>https://erikonarheim.com/posts/excalibur-v0252-released/</guid>
    <pubDate>Sat, 22 Jan 2022 00:00:00 +0000</pubDate>
    <content type="html" >&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/excalibur-v025-released/logo-white@2x.png&quot; alt=&quot;Excalibur Text Logo&quot; /&gt;&lt;/p&gt;
&lt;p&gt;After the winter break, the team has put out a new release of &lt;a href=&quot;https://github.com/excaliburjs/Excalibur/releases/tag/v0.25.2&quot;&gt;Excalibur@v0.25.2&lt;/a&gt; with a lot of improvements to the core engine and plugins! Check the &lt;a href=&quot;https://github.com/excaliburjs/Excalibur/issues/1161&quot;&gt;roadmap for our current plans.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Check out the new version on npm!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; npm install excalibur@0.25.2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;quot;Winter holiday, when developers work on their side projects&amp;quot; - Anonymous Coworker&lt;/p&gt;
&lt;h2&gt;Dev Tools&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; npm install @excaliburjs/dev-tools
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We&#39;ve built a brand new tool to help debug Excalibur games! &lt;a href=&quot;https://github.com/excaliburjs/dev-tools&quot;&gt;Check it out!&lt;/a&gt;. This tool lets you see information about the the Excalibur engine, scenes, actors, clocks, and more!&lt;/p&gt;
&lt;p&gt;Debugging why things aren&#39;t working has historically been pretty difficult. This plugin will greatly assist in the game development cycle. Nearly everything is available and configurable.&lt;/p&gt;
&lt;p&gt;It&#39;s pretty low effort to install into your game:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; DevTool &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;@excaliburjs/dev-tools&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; game &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Engine&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; devtool &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;DevTool&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;game&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/excalibur-v0252-released/dev-tools.png&quot; alt=&quot;Dev Tools Screenshot&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Tiled Updates&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; npm install @excaliburjs/plugin-tiled
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Tiled plugin now implicitly adds a z-index to each layer (which can be overridden) which means things will look as you expect in Excalibur as they do in the Tiled editor.&lt;/p&gt;
&lt;p&gt;Set the starting layer z (defaults to -1) and get gaming!&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; map &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;TiledMapResource&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;path/to/map.tmx&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; firstLayerZIndex&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/excalibur-v0252-released/tiled.gif&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Renderer Performance Improvements&lt;/h2&gt;
&lt;p&gt;The performance gains were achieved through some core renderer refactors and identifying places where expensive calculations could be cached!&lt;/p&gt;
&lt;p&gt;This is huge, we stay above 30fps in the 4000 actor benchmark, and we have dramatic improvement in average fps in both cases!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/excalibur-v0252-released/v25.0-v25.2.png&quot; alt=&quot;Excalibur benchmark&quot; /&gt;&lt;/p&gt;
&lt;p&gt;This benchmark was performed on my Surface Book 2 with the power plugged in, in Chrome.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Processor: Intel(R) Core(TM) i7-8650U CPU @ 1.90GHz, 2112 Mhz, 4 Core(s), 8 Logical Processor(s)&lt;/li&gt;
&lt;li&gt;Physical Memory: (RAM) 16.0 GB&lt;/li&gt;
&lt;li&gt;Graphics: NVIDIA GeForce GTX 1060&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A number of improvements were made to Excalibur in the graphics systems to get to this performance.
The big factors to this improvement were:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Avoiding recalculation of graphics transforms and other expensive operations when they can be cached&lt;/li&gt;
&lt;li&gt;Refactoring the renderer to be simpler and to use index buffers to share geometry vertices.&lt;/li&gt;
&lt;li&gt;Rendering batches at the actual maximum for the batch renderer&lt;/li&gt;
&lt;li&gt;Avoid recreating &lt;code&gt;Matrix&lt;/code&gt; types, they are somewhat expensive to create then garbage collect&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Post Processing&lt;/h2&gt;
&lt;p&gt;The postprocessor improvements allow custom WebGL shaders, this can produce some cool effects! (Minimally modified from &lt;a href=&quot;https://www.shadertoy.com/view/Ms23DR&quot;&gt;this ShaderToy&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/excalibur-v0252-released/postprocessors2.gif&quot; alt=&quot;Excalibur example running with CRT television postprocessor&quot; /&gt;&lt;/p&gt;
&lt;p&gt;To produce the above effect Excalibur has a new built in &lt;code&gt;ScreenShader&lt;/code&gt; type for doing quick shaders meant for the whole screen.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CrtPostProcessor&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;PostProcessor &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; _shader&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ex&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ScreenShader&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;initialize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;gl&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; WebGLRenderingContext&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; crtEffectSource &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;modified-crt-shader-source&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;innerText&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_shader &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ScreenShader&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;crtEffectSource&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;getLayout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ex&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;VertexLayout &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_shader&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getLayout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token function&quot;&gt;getShader&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ex&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Shader &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_shader&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getShader&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;game&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;graphicsContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addPostProcessor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;CrtPostProcessor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Renderer Improvements&lt;/h2&gt;
&lt;h3&gt;Renderer Design&lt;/h3&gt;
&lt;p&gt;When v0.25.0 was released, it was a &amp;quot;monolithic&amp;quot; renderer design, meaning everything Excalibur could possibly draw was built into a single renderer and shader program. This became fairly onerous fairly quickly. And as the old adage goes &amp;quot;you don&#39;t know how to build something until you&#39;ve built it twice&amp;quot;&lt;/p&gt;
&lt;p&gt;With v0.25.2 each type of drawing is split internally into separate renderer plugins, while this does come with some overhead when switching shader programs, the simplicity, maintainability, and extensibility benefits are a boon.&lt;/p&gt;
&lt;h3&gt;Image Filtering&lt;/h3&gt;
&lt;p&gt;Excalibur now allows you the ability to control the WebGL image filtering mode both implicitly and explicitly. Really this means Excalibur will try to pick a smart default, but allows overrides&lt;/p&gt;
&lt;p&gt;Explicitly when loading &lt;code&gt;ex.ImageSource&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; myImage &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ImageSource&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;path/to/image&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ex&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ImageFiltering&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Pixel&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ex.ImageFiltering.Blended&lt;/code&gt; - Blended is useful when you have high resolution artwork and would like it blended and smoothed&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/excalibur-v0252-released/blended.png&quot; alt=&quot;Example of blended mode&quot; /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ex.ImageFiltering.Pixel&lt;/code&gt; - Pixel is useful for pixel art when you do not want smoothing aka antialiasing applied to your graphics.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/excalibur-v0252-released/pixel.png&quot; alt=&quot;Example of pixel mode&quot; /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Implicitly if the &lt;code&gt;ex.EngineOption&lt;/code&gt; antialiasing property is set:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;antialiasing: true&lt;/code&gt;, then the blend mode defaults to &lt;code&gt;ex.ImageFiltering.Blended&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;antialiasing: false&lt;/code&gt;, then the blend mode defaults to &lt;code&gt;ex.ImageFiltering.Pixel&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Custom Renderer Plugins&lt;/h2&gt;
&lt;p&gt;Excalibur knows how to draw many types graphics to the screen by default comes with those pre-installed into the ExcaliburGraphicsContext. However, you may have a unique requirement to provide custom WebGL commands into Excalibur, this can be done with a custom renderer plugin.&lt;/p&gt;
&lt;p&gt;A custom renderer can be registered with Excalibur and draw in any draw routine! Read more in the &lt;a href=&quot;https://excaliburjs.com/docs/custom-renderer-plugins&quot;&gt;docs&lt;/a&gt;&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; game &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Engine&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MyCustomRenderer&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;RendererPlugin &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;myrenderer&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;game&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// register&lt;/span&gt;&lt;br /&gt;    game&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;graphicsContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MyCustomRenderer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// call from a graphics callback or event&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; actor &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Actor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;actor&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;graphics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;onPostDraw&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;graphicsContext&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    graphicsContext&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;MyCustomRenderer&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;myrenderer&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Community&lt;/h2&gt;
&lt;p&gt;We&#39;ve had a lot of community engagement this iteration, especially through the issues and &lt;a href=&quot;https://github.com/excaliburjs/Excalibur/discussions&quot;&gt;github discussions&lt;/a&gt;. Lots of good issues, and lots of cool things in the show and tell&lt;/p&gt;
&lt;p&gt;Big thanks to everyone:
@ivasilov
@luttje
@tsanyqudsi
@lampewebdev
@joshuadoan
@berkayyildiz
@simon-jaeger
@YJDoc2
@JumpLink&lt;/p&gt;
&lt;h2&gt;The Future&lt;/h2&gt;
&lt;p&gt;We are progressing at full speed toward the v1 vision, there is still a lot to do but the end is in sight. Here are a few things that I&#39;m personally really excited for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Event system redo&lt;/li&gt;
&lt;li&gt;Particle system refactor&lt;/li&gt;
&lt;li&gt;Final deprecation of old drawing api&lt;/li&gt;
&lt;li&gt;New TileMap enhancements for hexagonal and isometric maps&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This was a point release, but despite that a lot of exciting things were added! Looking forward to v0.26.0!&lt;/p&gt;
&lt;p&gt;-Erik&lt;/p&gt;
</content>
  </item>
  
  <item>
    <title>Fixing WebGL Tile Map Seams</title>
    <link>https://erikonarheim.com/posts/webgl-tile-map-seams/</link>
    <description>Erik Onarheim</description>
    <guid>https://erikonarheim.com/posts/webgl-tile-map-seams/</guid>
    <pubDate>Wed, 15 Dec 2021 00:00:00 +0000</pubDate>
    <content type="html" >&lt;p&gt;There is a &lt;a href=&quot;https://www.google.com/search?q=tilemap+seam&quot;&gt;common issue&lt;/a&gt; with tile based maps having &lt;a href=&quot;https://stackoverflow.com/questions/25716284/what-is-the-source-of-these-pixel-gaps-in-between-identical-vertices-in-opengls&quot;&gt;visible seams&lt;/a&gt; where they shouldn&#39;t.&lt;/p&gt;
&lt;p&gt;In this post I want to explain why they were happening to me, and to document the solutions I found that you can mix and match in your code! 😎&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/webgl-tile-map-seams/seam.png&quot; alt=&quot;example seam&quot; /&gt;&lt;/p&gt;
&lt;p&gt;TLDR Show me the &lt;a href=&quot;https://github.com/eonarheim/webgl-tiling-tester&quot;&gt;code&lt;/a&gt; and &lt;a href=&quot;https://eonarheim.github.io/webgl-tiling-tester/&quot;&gt;demo&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;The Problem&lt;/h2&gt;
&lt;p&gt;The core problem that causes seams is &lt;strong&gt;floating point numbers&lt;/strong&gt;. Floating point numbers in computers do not have infinite resolution, there are &amp;quot;gaps&amp;quot; in the possible numbers that can be represented by a computer. In fact, the gaps in representable numbers get worse the further from zero you go!&lt;/p&gt;
&lt;p&gt;This issue is super unintuitive. If you start from pure mathematics, this shouldn&#39;t be possible, but because of limited floating point precision and error accumulation seams in the geometry can happen.&lt;/p&gt;
&lt;p&gt;Factors in the webgl that influence the issue:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lower pixel density screens (standard definition) seem to be easier to reproduce this problem&lt;/li&gt;
&lt;li&gt;The screen size and &lt;code&gt;window.devicePixelRatio&lt;/code&gt; (&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio&quot;&gt;ratio between logical CSS pixels to physical screen pixels&lt;/a&gt;) seem to affect the appearance of these artifacts.&lt;/li&gt;
&lt;li&gt;Large amounts (tm) of floating point manipulations of the geometry before rendering introduces and propagates floating point errors.
&lt;ul&gt;
&lt;li&gt;Geometry manipulation&lt;/li&gt;
&lt;li&gt;Camera positioning&lt;/li&gt;
&lt;li&gt;Canvas scaling&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Texture sampling can sometimes bleed at UV&#39;s near 1.0 into adjacent pixels in your source image that you did not intend 😱 (#thanks-float-point)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Some Specifics&lt;/h3&gt;
&lt;p&gt;WebGL 1.0 is based on the &lt;a href=&quot;https://www.khronos.org/registry/OpenGL/specs/es/2.0/es_full_spec_2.0.pdf&quot;&gt;OpenGL ES 2.0 spec&lt;/a&gt; which indicates that if the center of the fragment is not in the polygon screen pixel projection it doesn&#39;t color it in. So when the screen pixel center (0.5, 0.5) falls directly on a geometry boundary between two quads, but neither is far enough into a screen pixel for webgl to color the pixel. Mathematically this seems like it shouldn&#39;t be possible, but because of limited floating point precision there are holes in the numbers (at least with the method that &lt;a href=&quot;https://excaliburjs.com/&quot;&gt;Excalibur&lt;/a&gt; uses to build tiles).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/webgl-tile-map-seams/pixel-gap.png&quot; alt=&quot;geometry-coloring&quot; /&gt;&lt;/p&gt;
&lt;p&gt;This explanation fits with the flickering moire pattern to the left that can be seen when moving across the screen. You can see the background peaking through sometimes when the rasterizer doesn&#39;t fill in the pixel.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/webgl-tile-map-seams/moire.gif&quot; alt=&quot;moire pattern&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Solution 1 - Shared Tile Edge (best for tile maps)&lt;/h2&gt;
&lt;p&gt;If you know ahead of time that you are tiling, you can re-use the right edge of the previous tile so that there are no floating point gaps. There can be no gaps because you are using the exact same edge and not recomputing it.&lt;/p&gt;
&lt;p&gt;Recomputing edges is where we can get into floating point trouble. Note is that this identity for the ith tile &lt;strong&gt;does not hold true&lt;/strong&gt; for all floating point numbers given rounding/error, even though mathematically that is true.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;i * width + width / 2 == (i + 1) * width - width / 2&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Avoid recomputing edges.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;So here is an example where we precompute all the x-edges and y-edges and use them to build our tile geometry&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;generateTiles&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;                    tileRows&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                    tileColumns&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                    tileWidthPixels&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                    tileHeightPixels&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Tile&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; tiles&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Tile&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; tileXs&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; tileYs&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Precompute all the x&#39;s &amp;amp; y&#39;s for the tile geometry&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// this keeps us from getting into trouble with floating point math &lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; x &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; x &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tileColumns &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; x&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        tileXs&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;x&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; x &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; tileWidthPixels&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; y &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; y &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tileRows &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; y&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        tileYs&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;y&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; y &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; tileHeightPixels&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Create tile geometry that share the same edges&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; x &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; x &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; tileColumns&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; x&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; y &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; y &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; tileRows&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; y&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; tile &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Tile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                left&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; tileXs&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;x&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                right&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; tileXs&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;x &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                top&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; tileYs&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;y&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                bottom&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; tileYs&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;y &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;            tiles&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tile&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; tiles&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Shared Edge Solution in action&lt;/h3&gt;
&lt;p&gt;You can see the gap in far right appear and disappear&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/webgl-tile-map-seams/shared-edge.gif&quot; alt=&quot;shared-edge-geometry&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Solution 2 - Bodge the UV coordinates near 1.0&lt;/h2&gt;
&lt;p&gt;If you are resizing images on the fly to make them power-of-two dimensions or have a texture atlas with multiple sprites packed into one image, the texture sampling can bleed into the new transparent pixels. A slightly hacky work around is to back off of the UV by a small bodge factor, &lt;code&gt;0.01&lt;/code&gt; but seems to work without losing actual image pixels.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;br /&gt; &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; num&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;size &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        data&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; vertex &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        data&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; vertex &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        vertex &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; size&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        data&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; vertex &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        data&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; vertex &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tileHeightPixels &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.01&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; tilePOTHeight&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        vertex &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; size&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        data&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; vertex &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tileWidthPixels  &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.01&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; tilePOTWidth&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        data&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; vertex &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        vertex &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; size&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        data&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; vertex &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tileWidthPixels &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.01&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; tilePOTWidth&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        data&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; vertex &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tileHeightPixels &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.01&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; tilePOTHeight&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        vertex &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Quick note on other texture related issues&lt;/h3&gt;
&lt;p&gt;WebGL will sample and blend pixels from other parts of a texture atlas sometimes (and is desirable for a lot of images). WebGL is trying to be helpful and picking pixels to blend next to produce high quality images.&lt;/p&gt;
&lt;p&gt;Some additional texture consideration:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You can change your sampling mode to &lt;code&gt;gl.NEAREST&lt;/code&gt; (this might not work out depending on your art style). I believe to do this in Unity this is SpriteAtlas with texture packing, and filter mode set &lt;code&gt;Point&lt;/code&gt;, you&#39;ll need to build/start the project.&lt;/li&gt;
&lt;li&gt;Be sure to clamp to the edge of the texture (not useful for bleed in the atlas)&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;gl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;texParameteri&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;gl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;TEXTURE_2D&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; gl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;TEXTURE_WRAP_S&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; gl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;CLAMP_TO_EDGE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;gl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;texParameteri&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;gl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;TEXTURE_2D&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; gl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;TEXTURE_WRAP_T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; gl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;CLAMP_TO_EDGE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;Add transparent padding between sprites in your texture atlas to hack around the sampler&lt;/li&gt;
&lt;li&gt;You can extrude the edge pixel out 1 pixel to hack around the sampler, this might be a ton of effort to update all your tiles, there are some tools that exist to do this for you.
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/sporadic-labs/tile-extruder&quot;&gt;Tile Extruder&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;UV Bodge In action&lt;/h3&gt;
&lt;p&gt;Notice the horizontal gap in the center of the tiles.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/webgl-tile-map-seams/uv-bodge.gif&quot; alt=&quot;uv-bodge&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Solution 3 - Avoid Unnecessary Floating Point Manipulation&lt;/h2&gt;
&lt;h3&gt;3.1 Unnecessary geometry scaling for HiDPI&lt;/h3&gt;
&lt;p&gt;Kronos has a &lt;a href=&quot;https://www.khronos.org/webgl/wiki/HandlingHighDPI&quot;&gt;good article on handling hidpi in webgl&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;But one important thing to keep in mind is to have your orthographic matrix mapped to your &amp;quot;logical&amp;quot; resolution (or clip space if you prefer). And keep your &lt;code&gt;gl.viewport()&lt;/code&gt; set to the size of the hidpi scaled canvas.&lt;/p&gt;
&lt;p&gt;If you think about it makes sense because that gl viewport is the size of the drawing surface in real machine pixels.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// logical resolution&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; resolution &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  width&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;800&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// &quot;CSS&quot; logical pixels&lt;/span&gt;&lt;br /&gt;  height&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;600&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// &quot;CSS&quot; logical pixels&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// hidpi scaling&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;applyHiDPIScaling&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;devicePixelRatio &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; resolution&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;devicePixelRatio&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; resolution&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;devicePixelRatio&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;  resolution&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;px&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; resolution&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;px&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token builtin&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;pixel ratio&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;devicePixelRatio&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;applyHiDPIScaling&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; shader &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/*...*/&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// setup orthographic 2D projection for our shaders&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Notice the orthographic is the logical resolution, not the scaled&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; ortho &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Matrix&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ortho&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; resolution&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; resolution&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;400&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;400&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;shader&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addUniformMatrix&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;u_matrix&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ortho&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// draw frame&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Clear the context with the newly set color.&lt;/span&gt;&lt;br /&gt;    gl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;clearColor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;114&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;213&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;224&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;255&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1.0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    gl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;clear&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;gl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;COLOR_BUFFER_BIT&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Use the physical scaled resolution as the viewport&lt;/span&gt;&lt;br /&gt;    gl&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;viewport&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Do all the drawing&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// ...&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This eliminates the need to artificially scale your geometry (which can introduce floating point error), consider the following (which you should NOT USE)&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// DO NOT USE THIS SNIPPET&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;applyHiDPIScaling&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; shader &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;/*...*/&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// If we used the scaled width/height it forces use to &quot;zoom-in&quot; later on the geometry&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; ortho &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Matrix&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;ortho&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;400&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;400&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;shader&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addUniformMatrix&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;u_matrix&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ortho&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;transform&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Matrix&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;identity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// This is applied to all geometry!! so can introduce floating point errors&lt;/span&gt;&lt;br /&gt;transform&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;devicePixelRatio&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;devicePixelRatio&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// DO NOT USE THIS SNIPPET&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3.2 - Keep geometry in local coordinates for as long as possible&lt;/h3&gt;
&lt;p&gt;Do as little transformation as possible to the geometry in your pipeline. Each floating point operation is an opportunity for error to compound or propagate. If you can help it, keep geometry in local coordinates until the very last moment where you must render.&lt;/p&gt;
&lt;h3&gt;3.3 - Pixel snap&lt;/h3&gt;
&lt;p&gt;Rounding to the nearest pixel, or truncating the fraction portion can fix some issues.&lt;/p&gt;
&lt;p&gt;However, depending on where you do your rounding or truncate the geometry might fall ahead or behind where it should in screen space. You might need to look at the &amp;quot;Nudge&amp;quot; solution to remedy this.&lt;/p&gt;
&lt;p&gt;See this example were truncating makes it worse&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/webgl-tile-map-seams/truncate.gif&quot; alt=&quot;truncate&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;3.4 - Position your camera in ideal locations&lt;/h3&gt;
&lt;p&gt;If you implement your camera by transforming the entire context, it may be a good idea to keep the camera at whole pixel values to avoid floating point issues from propagating.&lt;/p&gt;
&lt;h2&gt;Solution 0.5: &amp;quot;Nudge&amp;quot; pixels to screen (Useful for Ad-Hoc Drawing Systems)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;I don&#39;t recommend&lt;/strong&gt; this solution unless you have no other choice, or you have limited control of your drawing.&lt;/p&gt;
&lt;p&gt;That said, this technique doesn&#39;t know if you plan to draw tiles, but if you happened to draw a tiles it will work 😎&lt;/p&gt;
&lt;p&gt;This type of solution is covered in the beginning of &lt;a href=&quot;https://youtu.be/qhbVhzRs2nw?t=127&quot;&gt;OLC code zone stream #28&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To fix the seam in the geometry we want to nudge the game geometry of each draw so that it will bias the left and right edge of each image to a screen pixel without a gap.&lt;/p&gt;
&lt;p&gt;Basic algorithm:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Map vertices to screen space&lt;/li&gt;
&lt;li&gt;Nudge it to the nearest screen pixel up or down&lt;/li&gt;
&lt;li&gt;Map vertices back to world space and use those&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Our scheme to nudge pixels will be to take all our (red) right edges and add a &lt;code&gt;0.5&lt;/code&gt; pixel bodge then find the ceiling, and we take all our (blue) left edges and add a &lt;code&gt;0.5&lt;/code&gt; pixel bodge then find the floor.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/webgl-tile-map-seams/pixel-gap-quantized.png&quot; alt=&quot;geometry-coloring&quot; /&gt;&lt;/p&gt;
&lt;p&gt;While this works pretty well, &lt;strong&gt;this does have a drawback of overlapping the geometry&lt;/strong&gt; by 1 pixel on the left or right in the majority case when the edges don&#39;t straddle the mid-pixel.&lt;/p&gt;
&lt;p&gt;But maybe 1 pixel overlap is better than having a perceptible gap? You decide. It is a more noticeable effect if your assets are small, or your are zoomed out, because the 1 screen pixel will become a larger portion of the asset on screen.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/webgl-tile-map-seams/pixel-gap-quantized-overlap-left.png&quot; alt=&quot;geometry-coloring&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/webgl-tile-map-seams/pixel-gap-quantized-overlap.png&quot; alt=&quot;geometry-coloring&quot; /&gt;&lt;/p&gt;
&lt;h4&gt;Quick note&lt;/h4&gt;
&lt;p&gt;You might be thinking why not use ceiling for both edges (or floor) all the time to avoid overlapping by 1 pixel, well the same mid-pixel problem we were trying to solve before is now shifted to the pixel boundaries and we still have a gap.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/webgl-tile-map-seams/pixel-gap-boundary.png&quot; alt=&quot;geometry-coloring&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Nudge code&lt;/h3&gt;
&lt;p&gt;It&#39;s important to multiply whatever your screen space dimensions are by the &lt;code&gt;window.devicePixelRatio&lt;/code&gt; to account for hidpi displays. Remember that it&#39;s important to factor in the ratio between physical screen pixels and logical &amp;quot;css&amp;quot; pixels to do this mapping properly.&lt;/p&gt;
&lt;p&gt;For HTML games&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Game resolution in &quot;logical&quot; pixels&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// &amp;lt;canvas width=&quot;800&quot; height=&quot;600&quot; &gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; resolution &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  width&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;800&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  height&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;600&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Screen space in actual screen pixels &lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// &amp;lt;canvas style=&quot;width:800px;height:600px&quot;&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// &quot;logical&quot; * devicePixelRatio = physical pixels&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; screen &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  width&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;viewport&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;devicePixelRatio&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  height&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;viewport&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;devicePixelRatio &lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Map the coordinate from world &amp;quot;game&amp;quot; resolution to screen space.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;toScreenSpace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;coord&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; resolution&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; screen&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Map coordinate to screen space&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; screenSpacePos &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;vec&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;coord&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; resolution&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; screen&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;coord&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; resolution&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; screen&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; screenSpacePos&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Make the inverse to map back to world space&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;toWorldSpace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;coord&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Vector&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; resolution&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Dimension&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; screen&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Dimension&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Map coordinate to world space&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; worldSpacePos &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;vec&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;coord&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; screen&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; resolution&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;coord&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; screen&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; resolution&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; worldSpacePos&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Putting this all together, we apply our half pixel algorithm in both the floor and ceil&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/**&lt;br /&gt; * Pushes a world space coordinate towards the nearest screen pixel (floor)&lt;br /&gt; */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;nudgeToScreenPixelFloor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;transform&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Matrix&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; coord&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Vector&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; resolution&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Dimension&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Vector &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    coord &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; transform&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getAffineInverse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;multv&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;coord&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; screen &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        width&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; resolution&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;devicePixelRatio&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        height&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; resolution&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;devicePixelRatio&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; screenSpacePos &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;toScreenSpace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;coord&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; resolution&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; screen&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Adjust by half a pixel &quot;bodge&quot; factor&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; screenSpacePosBodge &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; screenSpacePos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;vec&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0.5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Find the nearest screen pixel&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; nearestScreenPixelFloor &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;vec&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;        Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;floor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;screenSpacePosBodge&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;floor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;screenSpacePosBodge&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Convert back to game resolution&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; worldSpace &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;toWorldSpace&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;nearestScreenPixelFloor&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; resolution&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; screen&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Transform back to world coordinate&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; transform&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;multv&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;worldSpace&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;/**&lt;br /&gt; * Pushes a world space coordinate towards the nearest screen pixel (ceiling)&lt;br /&gt; */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;nudgeToScreenPixelCeil&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;transform&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Matrix&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; coord&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Vector&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; resolution&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Dimension&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Vector &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// Same as above but with Math.ceil()&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Putting it all together, we apply our floor nudge to the left edge, and the ceiling nudge ot the right&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;drawTile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tile&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Tile&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Quad update&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; topLeft &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;vec&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tile&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;left&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; tile&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;top&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; bottomRight &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;vec&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tile&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;right&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; tile&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bottom&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    topLeft &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;nudgeToScreenPixelFloor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;transform&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; topLeft&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; resolution&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    bottomRight &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;nudgeToScreenPixelCeil&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;transform&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;current&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; bottomRight&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; resolution&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// (0, 0) - 0&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; vertices &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; def&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;buffer&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bufferData&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    vertices&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;vertIndex&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; topLeft&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    vertices&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;vertIndex&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; topLeft&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// (0, 1) - 1&lt;/span&gt;&lt;br /&gt;    vertices&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;vertIndex&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; topLeft&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    vertices&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;vertIndex&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; bottomRight&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// (1, 0) - 2&lt;/span&gt;&lt;br /&gt;    vertices&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;vertIndex&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; bottomRight&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    vertices&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;vertIndex&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; topLeft&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// (1, 1) - 3&lt;/span&gt;&lt;br /&gt;    vertices&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;vertIndex&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; bottomRight&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    vertices&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;vertIndex&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; bottomRight&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&amp;quot;Nudge&amp;quot; solution in action&lt;/h3&gt;
&lt;p&gt;Notice the semi-obvious overlap that could be undesirable in your game.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/webgl-tile-map-seams/nudge.gif&quot; alt=&quot;geometry-nudge&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Wrapping up&lt;/h2&gt;
&lt;p&gt;Check out the &lt;a href=&quot;https://github.com/eonarheim/webgl-tiling-tester&quot;&gt;code&lt;/a&gt; and &lt;a href=&quot;https://eonarheim.github.io/webgl-tiling-tester/&quot;&gt;demo&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;There are a lot of quirks when doing tile based drawing, the majority of them boil down to floating point math or texture settings.&lt;/p&gt;
&lt;p&gt;You may need to apply one or many solutions in this post, or remove some problematic code from your game.&lt;/p&gt;
&lt;p&gt;Hope this helps any future explorers!&lt;/p&gt;
&lt;p&gt;-Erik&lt;/p&gt;
</content>
  </item>
  
  <item>
    <title>Excalibur v0.25.0 Released!</title>
    <link>https://erikonarheim.com/posts/excalibur-v025-released/</link>
    <description>Erik Onarheim</description>
    <guid>https://erikonarheim.com/posts/excalibur-v025-released/</guid>
    <pubDate>Sun, 03 Oct 2021 00:00:00 +0000</pubDate>
    <content type="html" >&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/excalibur-v025-released/logo-white@2x.png&quot; alt=&quot;Excalibur Text Logo&quot; /&gt;&lt;/p&gt;
&lt;p&gt;After a year of work a lot of great additions and improvements have made it into Excalibur, and we are making good progress towards our v1.0 release! Check the &lt;a href=&quot;https://github.com/excaliburjs/Excalibur/issues/1161&quot;&gt;roadmap for our current plans.&lt;/a&gt; It&#39;s hard to believe how different things are now since the &lt;a href=&quot;https://github.com/excaliburjs/Excalibur/commit/aefa1a125bcbeeb97f20500a220523962eb99702&quot;&gt;first commit of Excalibur&lt;/a&gt; (back when it was called GameTS)!&lt;/p&gt;
&lt;p&gt;Excalibur started as a tech demo in a presentation to show how powerful TypeScript can be. The engine has come so far since then, it&#39;s really amazing!&lt;/p&gt;
&lt;p&gt;We are really excited to share this release with you! This release contains over 30 bug fixes and 50 new features! It&#39;s been a labor of love over the last year by many people, and we have some big features to share.&lt;/p&gt;
&lt;p&gt;Check out the &lt;a href=&quot;https://github.com/excaliburjs/Excalibur/releases/tag/v0.25.0&quot;&gt;official release&lt;/a&gt;!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; npm install excalibur@0.25.0
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Performance&lt;/h2&gt;
&lt;p&gt;There is a combination of features (mentioned below) that resulted in big performance gains. Across the board, there&#39;s been a dramatic increase in what Excalibur can do in v0.25.0 vs v0.24.5.&lt;/p&gt;
&lt;p&gt;I want to highlight the graphics performance specifically:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/excalibur-v025-released/benchmark.gif&quot; alt=&quot;Graphics Benchmark test gif&quot; /&gt;&lt;/p&gt;
&lt;p&gt;There is much better performance across the board with a higher baseline fps in v0.25.0 for the same number of actors. You&#39;ll notice that FPS improves over time as more actors are offscreen in v0.25.0 compared to v0.24.5.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/excalibur-v025-released/benchmark.png&quot; alt=&quot;Graphics Side by side comparison of v0.24.5 and v0.25.0 FPS over time&quot; /&gt;&lt;/p&gt;
&lt;p&gt;This benchmark was performed on my Surface Book 2 with the power plugged in, in Chrome.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Processor:	Intel(R) Core(TM) i7-8650U CPU @ 1.90GHz, 2112 Mhz, 4 Core(s), 8 Logical Processor(s)&lt;/li&gt;
&lt;li&gt;Physical Memory: (RAM)	16.0 GB&lt;/li&gt;
&lt;li&gt;Graphics: NVIDIA GeForce GTX 1060&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Plugin Strategy Going Forward&lt;/h2&gt;
&lt;p&gt;We are adopting a similar versioning strategy to Angular, during pre-1.0. All plugins compatible with the core library will share the same prefix through the minor version.
- Example: If core is &lt;code&gt;excalibur@0.25.0&lt;/code&gt; then the plugins that support this version are &lt;code&gt;@excaliburjs/plugin-tiled@0.25.x&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;DisplayMode Updates&lt;/h2&gt;
&lt;p&gt;Excalibur DisplayModes have been refactored and renamed to clarify their utility.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;FillContainer - Fill the game viewport to take up as much of the immediate parent as possible&lt;/li&gt;
&lt;li&gt;FillScreen - Fill the game viewport to take up as much of the screen as possible&lt;/li&gt;
&lt;li&gt;FitContainer - Fit the game maintaining aspect ratio into the immediate parent&lt;/li&gt;
&lt;li&gt;FitScreen - Fit the game maintaining aspect ration into the screen&lt;/li&gt;
&lt;li&gt;Fixed - Specify a static size for the game width/height&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Refactor to Entity Component System (ECS) Based Architecture&lt;/h2&gt;
&lt;p&gt;The core plumbing of Excalibur has been refactored to use an ECS style architecture. With this change developers using Excalibur do not need to know or care about the this underlying change to ECS if they don&#39;t want too.&lt;/p&gt;
&lt;p&gt;What does this mean? Roughly speaking ECS architecture breaks down like this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Components&lt;/code&gt; - Contain data needed for various systems&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Systems&lt;/code&gt; implement the &amp;quot;behavior&amp;quot; by looping over entities that match a list of components. For example the graphics system processes all entities with a &lt;code&gt;TransformComponent&lt;/code&gt; and a &lt;code&gt;GraphicsComponent&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Entities&lt;/code&gt; are a holders of components&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;code&gt;Actor&lt;/code&gt;, &lt;code&gt;Scene&lt;/code&gt;, and &lt;code&gt;Engine&lt;/code&gt; remain the friendly interface to build games, just implemented differently under-the-hood. The reason for the change was to break down growing and complex logic that had accumulated in the &lt;code&gt;Actor&lt;/code&gt; and &lt;code&gt;Scene&lt;/code&gt; implementnation into &lt;code&gt;Component&lt;/code&gt;s and &lt;code&gt;System&lt;/code&gt;s for maintainability. This change increases the flexibility of Excalibur to add new novel behavior directly into the core loop with custom components ones if desired.&lt;/p&gt;
&lt;p&gt;Excalibur does not have the purest implementation of an ECS by design, the built in components are more than just data. The built in components do provide behavior, convenience features, and helpers to maintain our core mission of keeping Excalibur easy to use. The Excalibur core team goal with ECS is flexibility and maintainability, not performance. (&lt;a href=&quot;https://github.com/excaliburjs/Excalibur/issues/1361&quot;&gt;read more&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;A quick example of using the new ECS features&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;SearchComponent&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Component&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;search&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;search&#39;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; target&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ex&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Vector&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;SearchSystem&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;System&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;ex&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;TransformComponent &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; SearchComponent&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Types need to be listed as a const literal&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;readonly&lt;/span&gt; types &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;ex.transform&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;search&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Lower numbers mean higher priority&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// 99 is low priority&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; priority &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;99&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Run this system in the &quot;update&quot; phase&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; systemType &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ex&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;SystemType&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Update&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; _searchSpeed &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// pixels/sec&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entities&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ex&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Entity&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; delta&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; entity &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; entities&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; target &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; entity&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;SearchComponent&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token comment&quot;&gt;// ex.TransformComponent is a built in type&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt;&lt;/span&gt; transform &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; entity&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ex&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;TransformComponent&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; ex&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;TransformComponent&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; direction &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sub&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;transform&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pos&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; motion &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; direction&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;normalize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_searchSpeed&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;token comment&quot;&gt;// Moves these entities towards the target at 10 pixels per second&lt;/span&gt;&lt;br /&gt;            transform&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pos &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; transform&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;motion&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;delta &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Actors come with batteries included built in features&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; actor &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Actor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    pos&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ex&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;vec&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    width&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    height&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;30&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    color&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; ex&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Color&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Red&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;actor&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addComponent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;SearchComponent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ex&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;vec&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;400&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;400&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Create a scene with your new system&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; scene &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Scene&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;scene&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;world&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;SearchSystem&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;scene&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;actor&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Collision System Improvements&lt;/h2&gt;
&lt;p&gt;The collision system has been significantly overhauled to improve the quality of the simulation and the stability of collisions. The core simulation loop &amp;quot;solver&amp;quot; has been redone to use an &lt;a href=&quot;https://erikonarheim.com/posts/understanding-collision-constraint-solvers/&quot;&gt;iterative impulse constraint solver&lt;/a&gt;, which provides a robust method of computing resolution that has improved performance and stability.&lt;/p&gt;
&lt;p&gt;Collision intersection logic has now also been refactored to report multiple contact points at once. Multiple contacts improves the stability of stacks of colliders over single contact collisions (which can result in oscillations of boxes back and forth).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/excalibur-v025-released/stacks.gif&quot; alt=&quot;stacks of boxes&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Colliding bodies can now optionally go to sleep. This relieves some of the pressure on the collision solver and improves the stability of the simulation by not moving these objects if they don&#39;t need to move. Colliders can be started asleep before a player in a game might interact with them&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/excalibur-v025-released/sleeping.gif&quot; alt=&quot;stacks of boxes sleeping&quot; /&gt;&lt;/p&gt;
&lt;p&gt;New &lt;code&gt;CompositeCollider&lt;/code&gt;s now make it possible to combine Excalibur Collider primitives (&lt;code&gt;PolygonCollider&lt;/code&gt;, &lt;code&gt;CircleCollider&lt;/code&gt;, and &lt;code&gt;EdgeCollider&lt;/code&gt;) to make any arbitrary collision geometry. These new composite colliders power the new &lt;code&gt;TileMap&lt;/code&gt; cell collisions and also power the new &lt;code&gt;ex.Shape.Capsule(width, height)&lt;/code&gt; collider.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/excalibur-v025-released/composite.png&quot; alt=&quot;Tile Map Geometry&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Capsule&lt;/code&gt; collider is a useful geometry tool for making games with ramps or slightly jagged floors you want a character to glide over without getting stuck. This collider also helps with any &lt;a href=&quot;https://box2d.org/posts/2020/06/ghost-collisions/&quot;&gt;&amp;quot;ghost collisions&amp;quot;&lt;/a&gt; that you might run into under certain conditions in your game.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/excalibur-v025-released/capsule.png&quot; alt=&quot;Capsule Shape&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;CollisionGroup&lt;/code&gt;s allow more granular control over what collides above and beyond &lt;a href=&quot;https://excaliburjs.com/docs/api/edge/enums/CollisionType.html&quot;&gt;collision type&lt;/a&gt;. Collsion groups allow you to create named groups of colliders like &amp;quot;player&amp;quot;, &amp;quot;npc&amp;quot;, or &amp;quot;enemy&amp;quot;. With these groups, you can specify that players and enemies collide, player and npcs don&#39;t collide, and that npcs and enemies don&#39;t collide without needing to implement that logic in a collision event handler.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Create a group for each distinct category of &quot;collidable&quot; in your game&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; playerGroup &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ex&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;CollisionGroupManager&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;player&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; npcGroup &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ex&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;CollisionGroupManager&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;npcGroup&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; floorGroup &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ex&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;CollisionGroupManager&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;floorGroup&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; enemyGroup &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ex&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;CollisionGroupManager&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;enemyGroup&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Define your rules&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; playersCanCollideWith &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ex&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;CollisionGroup&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;collidesWith&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;  playersGroup&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// collide with other players&lt;/span&gt;&lt;br /&gt;  floorGroup&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// collide with the floor&lt;/span&gt;&lt;br /&gt;  enemyGroup &lt;span class=&quot;token comment&quot;&gt;// collide with enemies&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; player &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Actor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  collisionGroup&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; playersCanCollideWith&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;New Graphics System&lt;/h2&gt;
&lt;p&gt;The new Excalibur graphics system has been rebuilt from the ground up with speed in mind. It is now built on a WebGL foundation with a built-in batch renderer. This means that Excalibur will batch up draw commands and submit the minimum amount of draw calls to the machine when the screen is updated. This dramatically improves the draw performance and also the number of things wec can display on screen (as noted in the benchmarks earlier).&lt;/p&gt;
&lt;p&gt;For drawing hooks the &lt;code&gt;ExcaliburGraphicsContext&lt;/code&gt; is replacing the browser &lt;code&gt;CanvasRenderingContext2D&lt;/code&gt;. If you still need to do some custom drawing using the &lt;code&gt;CanvasRenderingContext2D&lt;/code&gt; the new &lt;a href=&quot;https://excaliburjs.com/docs/api/edge/classes/Canvas.html&quot;&gt;&lt;code&gt;Canvas&lt;/code&gt;&lt;/a&gt; graphic can help you out.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; canvas &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Canvas&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  cache&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// If true draw once until flagged dirty again, otherwise draw every time&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token function-variable function&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ctx&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; CanvasRenderingContext2D&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fillStyle &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;red&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fillRect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;actor&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;graphics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;use&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;canvas&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;TileMap and Tiled updates&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.mapeditor.org/&quot;&gt;Tiled&lt;/a&gt; is easily one of the best tools out there for building and designing levels for your game. It has certainly been a valuable tool in our toolbox. We have doubled down on our efforts to provide a first class Tiled integration with Excalibur via the &lt;code&gt;excaliburjs/plugin-tiled&lt;/code&gt;. This work also involved a few improvements to the &lt;code&gt;TileMap&lt;/code&gt; to improve it&#39;s graphics API and collision performance.&lt;/p&gt;
&lt;p&gt;Check out the &lt;a href=&quot;https://github.com/excaliburjs/excalibur-tiled&quot;&gt;Tiled Excalibur Plugin&lt;/a&gt;!&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Full support for the Tiled object model&lt;/li&gt;
&lt;li&gt;Full support for all Tiled file types&lt;/li&gt;
&lt;li&gt;Excalibur built ins&lt;/li&gt;
&lt;li&gt;Not yet supported
&lt;ul&gt;
&lt;li&gt;Tiled Group Layers&lt;/li&gt;
&lt;li&gt;Custom Tile colliders&lt;/li&gt;
&lt;li&gt;Isometric/Hexagonal maps&lt;/li&gt;
&lt;li&gt;Parallax&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/excalibur-v025-released/tiled.gif&quot; alt=&quot;Example of map built in Tiled&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Documentation&lt;/h2&gt;
&lt;p&gt;A lot of time was spent reviewing and improving our documentation. Part of this work was ensuring that the &lt;a href=&quot;https://github.com/excaliburjs/excalibur-snippets&quot;&gt;snippets&lt;/a&gt; don&#39;t go stale over time by building them in GitHub Actions.&lt;/p&gt;
&lt;p&gt;Please check out the new and shiny doc site with new code examples &lt;a href=&quot;https://excaliburjs.com/&quot;&gt;excaliburjs.com&lt;/a&gt;!&lt;/p&gt;
&lt;h2&gt;Testing&lt;/h2&gt;
&lt;p&gt;The Excalibur core repo now has &lt;a href=&quot;https://wallabyjs.com/&quot;&gt;WallabyJS&lt;/a&gt; enabled to improve the VS Code test development and debugging experience. Wallaby is a paid tool; because of that Excalibur will always also support the Karma based testing framework for official tests.&lt;/p&gt;
&lt;p&gt;A useful update to &lt;a href=&quot;https://github.com/excaliburjs/excalibur-jasmine&quot;&gt;&lt;code&gt;excalibur-jasmine&lt;/code&gt;&lt;/a&gt; allows async matchers, which greatly simplifies checking image diffs in Jasmine unit tests.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;should match images&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; engine &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ex&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Engine&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;width&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; height&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;expectAsync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;engine&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;canvas&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toEqualImage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;images/expectedcanvas.png&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;.99&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A brand new integration test utility has been created called &lt;a href=&quot;https://github.com/excaliburjs/excalibur-testing&quot;&gt;&lt;code&gt;@excaliburjs/testing&lt;/code&gt;&lt;/a&gt;, which provides a quick way to drive Excalibur games with Puppeteer and do image-based snapshot testing.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// excalibur testing&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;An integration test&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;page&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Check for the excalibur loaded page&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;expectLoaded&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Compare game to expected an expected image&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;expectPage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Can check a page&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;./images/actual-page.png&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;./images/expected-page.png&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Use puppeteer page object to interact&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; page&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;evaluate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; actor &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;window &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;actor&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        actor&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;400&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        actor&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;400&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Compare game to a new expected image&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;expectPage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Can move an actor and check&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;./images/actual-page-2.png&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toBe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;./images/expected-page-2.png&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/excalibur-v025-released/snapshot.gif&quot; alt=&quot;Excalibur Image snapshot testing&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Templates&lt;/h2&gt;
&lt;p&gt;There are a lot of different ways to build web apps; we&#39;ve created repo templates for some of the popular ones:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/excaliburjs/template-ts-webpack&quot;&gt;Webpack v5&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/excaliburjs/template-ts-parcel-v2&quot;&gt;Parcel v2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/excaliburjs/template-ts-parcel&quot;&gt;Parcel v1&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/excaliburjs/template-ts-rollup&quot;&gt;Rollup&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Samples&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/excaliburjs/sample-breakout&quot;&gt;Brick Breaker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/excaliburjs/sample-platformer&quot;&gt;Platformer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/excaliburjs/sample-shootemup&quot;&gt;Shoot&#39;em Up&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Community&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;We&#39;ve had tons of community contributions since the last release. Heartfelt thanks to everyone in the discussions, issues and PRs!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Contributors:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;@jedeen&lt;/li&gt;
&lt;li&gt;@kamranayub&lt;/li&gt;
&lt;li&gt;@alanag13&lt;/li&gt;
&lt;li&gt;@DaVince&lt;/li&gt;
&lt;li&gt;@DrSensor&lt;/li&gt;
&lt;li&gt;@djcsdy&lt;/li&gt;
&lt;li&gt;@catrielmuller&lt;/li&gt;
&lt;li&gt;@AndrewCraswell&lt;/li&gt;
&lt;li&gt;@miqh&lt;/li&gt;
&lt;li&gt;@rledford&lt;/li&gt;
&lt;li&gt;@SirPedr&lt;/li&gt;
&lt;li&gt;@helloausrine&lt;/li&gt;
&lt;li&gt;@dpayne5&lt;/li&gt;
&lt;li&gt;@herobank110&lt;/li&gt;
&lt;li&gt;@didii&lt;/li&gt;
&lt;li&gt;@Charkui&lt;/li&gt;
&lt;li&gt;@muirch&lt;/li&gt;
&lt;li&gt;@rumansaleem&lt;/li&gt;
&lt;li&gt;@mogoh&lt;/li&gt;
&lt;li&gt;@kala2&lt;/li&gt;
&lt;li&gt;@MrBartusek&lt;/li&gt;
&lt;li&gt;@josh-greenlaw&lt;/li&gt;
&lt;li&gt;@LokiMidgard&lt;/li&gt;
&lt;li&gt;@romaintailhurat&lt;/li&gt;
&lt;li&gt;@EduardoHidalgo&lt;/li&gt;
&lt;li&gt;@jaredegan&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Breaking Changes&lt;/h2&gt;
&lt;p&gt;There are some breaking changes in v0.25.0 from v0.24.5; see the&lt;a href=&quot;https://github.com/excaliburjs/Excalibur/blob/main/CHANGELOG.md&quot;&gt;changelog&lt;/a&gt; and &lt;a href=&quot;https://github.com/excaliburjs/Excalibur/releases/&quot;&gt;release notes&lt;/a&gt; for more specifics, but they generally fall into these categories. See the &lt;a href=&quot;https://excaliburjs.com/docs/migration&quot;&gt;migration guide&lt;/a&gt; for guidance&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;New APIs replacements
&lt;ul&gt;
&lt;li&gt;Graphics API&lt;/li&gt;
&lt;li&gt;Actor drawing functions moved to graphics component&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;API renames for clarity&lt;/li&gt;
&lt;li&gt;Bug fixed necessitated change&lt;/li&gt;
&lt;li&gt;Extracted behavior to a plugin
&lt;ul&gt;
&lt;li&gt;Perlin noise is now offered as a plugin and is no longer included in the core library &lt;code&gt;@excaliburjs/plugin-perlin&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Big Plugin changes
&lt;ul&gt;
&lt;li&gt;The Tiled plugin is now published under @excaliburjs/plugin-tiled and will start with version v0.25.0&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Next on the horizon looking towards &amp;quot;v1&amp;quot;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Pointer events plumbing refactor; the current system is hard to follow and debug/enhance&lt;/li&gt;
&lt;li&gt;Particle system refactor&lt;/li&gt;
&lt;li&gt;Graphics enhancements to support advanced postprocessing/shaders&lt;/li&gt;
&lt;li&gt;ExcaliburGraphicsContext enhancements to grant more flexibility&lt;/li&gt;
&lt;li&gt;Event system redo&lt;/li&gt;
&lt;li&gt;Better Scene management and granular asset loading&lt;/li&gt;
&lt;li&gt;Expand and enhance TileMap&lt;/li&gt;
&lt;li&gt;Progressive WebAssembly enhancements in the physics simulation&lt;/li&gt;
&lt;li&gt;Potential New plugins on the horizon
&lt;ul&gt;
&lt;li&gt;Browser Debugger Utility&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.aseprite.org/&quot;&gt;Aseprite&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://pyxeledit.com/&quot;&gt;Pyxel Edit&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;AI patterns and plugins like A* search&lt;/li&gt;
&lt;li&gt;API finalization&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I want to thank everyone who helped make this version of Excalibur possible. A lot of effort went into it and I&#39;m really proud of what we achieved.&lt;/p&gt;
&lt;p&gt;-Erik&lt;/p&gt;
</content>
  </item>
  
  <item>
    <title>Bookmarklets - Automating Websites</title>
    <link>https://erikonarheim.com/posts/automating-websites-with-bookmarklets/</link>
    <description>Erik Onarheim</description>
    <guid>https://erikonarheim.com/posts/automating-websites-with-bookmarklets/</guid>
    <pubDate>Mon, 06 Sep 2021 00:00:00 +0000</pubDate>
    <content type="html" >&lt;p&gt;Every so often I find myself on a website (like YouTube) where I wish it had X or Y feature. Bookmarklets are powerfull little tools you can use to create automation against websites you use.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/eonarheim/webpack-bookmarklet&quot;&gt;TLDR show me the code&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Bookmarklets&lt;/h2&gt;
&lt;p&gt;Bookmarklets are a piece of custom JavaScript run from the bookmark&#39;s UI in your browser on the current page. They are a bookmark that points to javascript instead of a URL. Think lo-fi proto browser plugin 🤷‍♂️&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/automating-websites-with-bookmarklets/save-bookmarklet.png&quot; alt=&quot;adding bookmarklet to chrome&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;⚠ WARNING ⚠&lt;/strong&gt; Make sure you understand whatever is in a bookmarklet, this code is running AS YOU against websites that you may be logged into (like a bank, social media, etc). A nefarious bookmarklet author could do bad things to you.&lt;/p&gt;
&lt;p&gt;Things that can be done with a bookmarklet&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Poke authenticated api endpoints&lt;/li&gt;
&lt;li&gt;Drive UI like clicking&lt;/li&gt;
&lt;li&gt;Manipulate the DOM&lt;/li&gt;
&lt;li&gt;Malware...😱&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;See the &lt;a href=&quot;https://support.mozilla.org/en-US/kb/bookmarklets-perform-common-web-page-tasks&quot;&gt;MDN article for more details&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Structure of the bookmarklet&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Prefixed with &lt;code&gt;javascript:&lt;/code&gt; with some code to execute for example: &lt;code&gt;javascript:(function(){alert(&#39;hello world&#39;);})()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Must not contain newlines&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Example &amp;quot;hello world&amp;quot; bookmarklet&lt;/p&gt;
&lt;p&gt;&lt;code&gt;javascript:(function(){alert(&#39;hello world&#39;);})()&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;YouTube playlist managment (at the time of writing this)&lt;/h2&gt;
&lt;p&gt;One feature I wish YouTube had was to remove videos automatically that are at a certain percentage watched. Currently the &amp;quot;Remove Watched&amp;quot; removes any video with any amount of watch time 😢 this is no good for me because sometimes I watch a few seconds. I want to remove videos at 80 or maybe 90 percent watched.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/automating-websites-with-bookmarklets/remove-watched.gif&quot; alt=&quot;gif of removing videos&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Websites change over time, and anything you write to automate them will decay, the code in this blog post is based on a &lt;a href=&quot;https://www.reddit.com/r/youtube/comments/9t3ps3/updated_script_to_remove_watched_videos/&quot;&gt;reddit post&lt;/a&gt; that doesn&#39;t work anymore, but I&#39;ve updated it for August 2021 version of YouTube (&lt;a href=&quot;https://github.com/eonarheim/webpack-bookmarklet&quot;&gt;also the source is on github&lt;/a&gt;)&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* Unprocessed script for removing videos */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;removeVids&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;/* Ask user for number of videos to remove */&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; n &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;prompt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Number of videos to remove?&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;/* What is the &quot;watched percent&quot; */&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; watchedPercent &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;prompt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Percent to consider watched&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;/* Find the videos that match that percentage based on the width of the progress element */&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; vids &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Array&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelectorAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;ytd-playlist-video-renderer&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; vidsThatMatch &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; vids&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; v&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelectorAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;#progress&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;parseInt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;v&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;#progress&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;=&lt;/span&gt; watchedPercent&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;/* Janky loop based on timing since we are driving UI we need to give it time to respond*/&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;vidsThatMatch&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; n&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; n &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; vidsThatMatch&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; interval &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setInterval&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;         &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;n &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;             &lt;span class=&quot;token comment&quot;&gt;/* open the video context menu */&lt;/span&gt;&lt;br /&gt;            vidsThatMatch&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;yt-icon-button.ytd-menu-renderer&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; title &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; vidsThatMatch&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;querySelector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;#video-title&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;            console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Removed:&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; title&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;innerText&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; title&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;href&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;token comment&quot;&gt;/* Need to search the whole document pop up lives in another container in the DOM */&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token comment&quot;&gt;/* Some xpath to find the remove from playlist dialog in the DOM */&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; removeResults &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;evaluate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;//span[contains(., &#39;Remove from&#39;)]&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; XPathResult&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;ANY_TYPE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; removeText &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; removeResults&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;iterateNext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;                removeText&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;                n&lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;                i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;No vids to remove&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token function&quot;&gt;clearInterval&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;interval&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;removeVids&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Building Bookmarklets with Webpack&lt;/h2&gt;
&lt;p&gt;Depending on how complicated your bookmarklet becomes, manually crafting the &lt;code&gt;javascript:...&lt;/code&gt; might become too onerous. It is possible to use a bundler like webpack to help out, this also suggests the possiblility of really rich bookmarklet experiences!&lt;/p&gt;
&lt;p&gt;Transforming the source to match the bookmarklet isn&#39;t too bad, based on this &lt;a href=&quot;https://stackoverflow.com/a/46920791&quot;&gt;SO post&lt;/a&gt; I&#39;ve crafted a webpack configuration.&lt;/p&gt;
&lt;p&gt;I tweaked the webpack plugin in the original post to be compatible with webpack v5&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// Modified for webpack v5: See https://stackoverflow.com/a/46920791/839595&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AssetToBookmarkletPlugin&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    pluginName &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;AssetToBookmarkletPlugin&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;compiler&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        compiler&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hooks&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;thisCompilation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;tap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pluginName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;compilation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            compilation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;hooks&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;processAssets&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;tap&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                name&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pluginName&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                stage&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; webpack&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Compilation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PROCESS_ASSETS_STAGE_ADDITIONAL&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;assets&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token comment&quot;&gt;// Emit a new .bookmarklet&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; assetName &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; assets&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; asset &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; assets&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;assetName&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; content &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;javascript:&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;encodeURIComponent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;(function(){&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; asset&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;})()&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;                    compilation&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;emitAsset&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;assetName &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;.bookmarklet&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;webpack&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sources&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;RawSource&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;content&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Tada! 🎉&lt;/p&gt;
&lt;p&gt;Here is the &lt;a href=&quot;https://github.com/eonarheim/webpack-bookmarklet&quot;&gt;source code&lt;/a&gt; for the bookmarklet.&lt;/p&gt;
&lt;p&gt;(Remember to verify any bookmarklets you decide to trust) Click and drag this link into your bookmarks bar to
&lt;a title=&quot;Remove Videos By Percent&quot; href=&quot;javascript:(function()%7B%2F******%2F%20(()%20%3D%3E%20%7B%20%2F%2F%20webpackBootstrap%0Avar%20__webpack_exports__%20%3D%20%7B%7D%3B%0Avar%20removeVids%20%3D%20function%20()%20%7B%0D%0A%20%20%20%20var%20n%20%3D%20parseInt(prompt(&#39;Number%20of%20videos%20to%20remove%3F&#39;%2C%201))%3B%0D%0A%20%20%20%20var%20watchedPercent%20%3D%20parseInt(prompt(&#39;Percent%20to%20consider%20watched&#39;%2C%20100))%3B%0D%0A%20%20%20%20var%20vids%20%3D%20Array.from(document.querySelectorAll(&#39;ytd-playlist-video-renderer&#39;))%3B%0D%0A%20%20%20%20var%20vidsThatMatch%20%3D%20vids.filter(v%20%3D%3E%20%7B%0D%0A%20%20%20%20%20%20%20%20return%20v.querySelectorAll(&#39;%23progress&#39;).length%20%26%26%20parseInt(v.querySelector(&#39;%23progress&#39;).style.width)%20%3E%3D%20watchedPercent%3B%0D%0A%20%20%20%20%7D)%3B%0D%0A%20%20%20%20if%20(vidsThatMatch.length%20%3C%20n)%20%7B%20n%20%3D%20vidsThatMatch.length%20%7D%3B%20%0D%0A%20%20%20%20var%20i%20%3D%200%3B%20%0D%0A%20%20%20%20var%20interval%20%3D%20setInterval(function%20()%20%7B%0D%0A%20%20%20%20%20%20%20%20%20if%20(n%20%3E%200)%20%7B%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20vidsThatMatch%5Bi%5D.querySelector(&#39;yt-icon-button.ytd-menu-renderer&#39;).click()%3B%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20var%20title%20%3D%20vidsThatMatch%5Bi%5D.querySelector(&#39;%23video-title&#39;)%3B%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20console.log(&#39;Removed%3A&#39;%2C%20title.innerText%2C%20title.href)%3B%0D%0A%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20need%20to%20search%20the%20whole%20document%20pop%20up%20lives%20in%20another%20container%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20setTimeout(()%20%3D%3E%20%7B%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20var%20removeResults%20%3D%20document.evaluate(%22%2F%2Fspan%5Bcontains(.%2C%20&#39;Remove%20from&#39;)%5D%22%2C%20document%2C%20null%2C%20XPathResult.ANY_TYPE%2C%20null)%3B%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20var%20removeText%20%3D%20removeResults.iterateNext()%3B%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20removeText.click()%3B%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20n--%3B%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20i%2B%2B%3B%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D)%3B%0D%0A%20%20%20%20%20%20%20%20%7D%20else%20%7B%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20console.log(&#39;No%20vids&#39;)%3B%0D%0A%20%20%20%20%20%20%20%20%20%20%20%20clearInterval(interval)%3B%0D%0A%20%20%20%20%20%20%20%20%7D%0D%0A%20%20%20%20%7D%2C%20500)%3B%0D%0A%7D%3B%20%0D%0AremoveVids()%3B%0A%2F******%2F%20%7D)()%0A%3B%7D)()&quot;&gt;Remove Videos By Percent&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Hope this helps anyone wanting to do some bookmarklet automation!
-Erik&lt;/p&gt;
</content>
  </item>
  
  <item>
    <title>Understanding Collision Constraint Solvers</title>
    <link>https://erikonarheim.com/posts/understanding-collision-constraint-solvers/</link>
    <description>Erik Onarheim</description>
    <guid>https://erikonarheim.com/posts/understanding-collision-constraint-solvers/</guid>
    <pubDate>Sun, 21 Mar 2021 00:00:00 +0000</pubDate>
    <content type="html" >&lt;p&gt;Constraints are a useful way to build relatively cheap, stable, and efficient physics systems. Lots of cool stuff can be unlocked with this approach 😎&lt;/p&gt;
&lt;p&gt;In this post I want to help people understand constraints too!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/understanding-iterative-constraing-solvers/ballsimulation.gif&quot; alt=&quot;balls colliding simulation&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I&#39;ll admit I had a hard time wrapping my brain 🧠 around using constraints to resolve collisions. I watched &lt;a href=&quot;https://www.youtube.com/watch?v=SHinxAhv1ZE&quot;&gt;this amazing talk&lt;/a&gt; by Erin Catto at GDC 2014 and wanted to replicate and understand the technique.&lt;/p&gt;
&lt;p&gt;What I want to do is reason out why these constraints might be the way they are by intuition and perhaps helpful ways to think about constraints.&lt;/p&gt;
&lt;p&gt;The actual derivation is better served by Erin&#39;s talk, I recommend you check it out. I&#39;ve probably watched it 10 times 😉&lt;/p&gt;
&lt;p&gt;TLDR show &lt;a href=&quot;https://github.com/eonarheim/iterative-constraint-solver&quot;&gt;me the code&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;What is a &amp;quot;Constraint&amp;quot;&lt;/h3&gt;
&lt;p&gt;Think of a constraint like a statement you want to be true and the &amp;quot;solver&amp;quot; attempts to make it true. Examples of constraints in a physics system might be: &amp;quot;I don&#39;t want these two objects to overlap&amp;quot;, &amp;quot;I want these two objects to be attached to another&amp;quot;, or &amp;quot;I want these two objects to bounce off each other&amp;quot;&lt;/p&gt;
&lt;p&gt;A constraint solver, takes all the contraints in your system and finds a solution that satisfies them all.&lt;/p&gt;
&lt;p&gt;In theory a set of constraints can be thought of as a group of related equations that can be solved. A stack of colliding objects is a good example of related contraints where the solution is their correct positions and velocities without any overlap.&lt;/p&gt;
&lt;p&gt;Awesome! I think I get it. How do I turn those into code?&lt;/p&gt;
&lt;h3&gt;Solving with Sequential Impulse&lt;/h3&gt;
&lt;p&gt;In this setup we are going to attempt to &amp;quot;solve&amp;quot; these constraints by applying a series of &amp;quot;impulses&amp;quot; to each object in contact. Once enough impulses are applied over time, a stable configuration of all the objects under constraints should fall out the other side.&lt;/p&gt;
&lt;p&gt;I have a goofy metaphor for this. Picture shaking a box of puzzle pieces that have magic magnets which are attracted to the right position. Shake until it&#39;s solved. 🤷‍♂️&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/understanding-iterative-constraing-solvers/puzzle.gif&quot; alt=&quot;home simpson smacking a puzzle&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Okay, what is an impulse? Well an impulse is defined as force added up over a time period. A super quick derivation from Newtonian physics from the familiar 2nd law:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;force = mass * acceleration&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Acceleration is another way of saying change in velocity in a given time step so re-written:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;force = mass * deltaVelocity/deltaTime&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Multiply by &lt;code&gt;deltaTime&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;force * deltaTime = mass * deltaVelocity&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Force over a time is the definition of impulse, so we can solve for our velocity. We will call our time period is the same for each frame so you can think of it as 1 unit of time 😎&lt;/p&gt;
&lt;p&gt;&lt;code&gt;impulse = mass * deltaVelocity&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;deltaVelocity = impulse * (1/mass)&lt;/code&gt; - &lt;strong&gt;Linear Impulse&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The angular version of this &lt;a href=&quot;https://en.wikipedia.org/wiki/Torque&quot;&gt;has a similar formulation&lt;/a&gt;, but I&#39;ll cut to the chase.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;deltaAngularVelocity = impulse x (1/momentOfInertia)&lt;/code&gt; - &lt;strong&gt;Angular Impulse&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/**&lt;br /&gt; * Apply an impulse at a point&lt;br /&gt; * @param point &lt;br /&gt; * @param impulse &lt;br /&gt; * @returns &lt;br /&gt; */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;applyImpulse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;point&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Vector&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; impulse&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Vector&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Important for the torque term, the distance from the center&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Changes the rotational amount applied &lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; distanceFromCenter &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; point&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sub&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;xf&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pos&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;m&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vel &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;m&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vel&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;impulse&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;inverseMass&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;m&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;angularVelocity &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;inverseInertia &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; distanceFromCenter&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;cross&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;impulse&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Check out (&lt;a href=&quot;https://en.wikipedia.org/wiki/Impulse_(physics)&quot;&gt;additional reading on impulses&lt;/a&gt;)&lt;/p&gt;
&lt;h3&gt;Building Constraints - Overlap&lt;/h3&gt;
&lt;p&gt;Let&#39;s start with &amp;quot;not allowing objects to overlap.&amp;quot; We know the exact amount that two circles overlap with each other. We&#39;ll say that a negative separation means overlap.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; combinedRadius &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; circleA&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;radius &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; circleB&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;radius&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; distance &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; circleA&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;distance&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;circleB&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pos&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;distance &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; combinedRadius&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; separation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; combindedRadius &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; distance&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// making it negative to signify &quot;overlap&quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;// only a convention for the math&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;separation&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To avoid overlap we want to trend &lt;code&gt;separation === 0&lt;/code&gt; over time.&lt;/p&gt;
&lt;p&gt;To do this, we can apply a steering factor every iteration to push &lt;code&gt;separation&lt;/code&gt; towards 0. In the biz 😎, this steering factor is called &lt;strong&gt;Baumgarte stabilization&lt;/strong&gt;, the idea of which is to feed the current &amp;quot;error&amp;quot;, scaled by a chosen constant, back into the solver.&lt;/p&gt;
&lt;p&gt;Erin Catto suggests not feeding the position correction term into the actual velocities because it introduces more artificial kinetic energy into the system, this differs from other solver implementations that do correct position overlap with velocity based impulses. Erin calls this positional approach a &amp;quot;pseudo-impulse&amp;quot;.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// DO THIS FOR X Iterations per frame, in practice only a couple are necessary&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; contact &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; contacts&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; point &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; contact&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;points&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; separation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; contact&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getSeparation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Magic number by 0.2 seems to be a good amount&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; steeringConstant &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0.2&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Limit the amount of correction at once for stability&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; maxCorrection &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Be tolerant of 1 pixel of overlap&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; slop &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Clamp to avoid over-correction&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Remember that we are shooting for 0 overlap in the end&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; steeringForce &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;clamp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;steeringConstant &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;separation &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; slop&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; maxCorrection&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; impulse &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; contact&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;normal&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;steeringForce &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; point&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;normalMass&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// NOTE! Update positions of bodyA &amp;amp; bodyB directly by &quot;pseudo-impulse&quot;, we still use the same impulse formula from above&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;bodyA&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        bodyA&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;xf&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pos &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; bodyA&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;xf&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;impulse&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;negate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;bodyA&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;inverseMass&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        bodyA&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;xf&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;rotation &lt;span class=&quot;token operator&quot;&gt;-=&lt;/span&gt; point&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;aToContact&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;cross&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;impulse&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; bodyA&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;inverseInertia&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;bodyB&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        bodyB&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;xf&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pos &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; bodyB&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;xf&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;impulse&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;bodyB&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;inverseMass&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        bodyB&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;xf&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;rotation &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; point&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bToContact&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;cross&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;impulse&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; bodyB&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;inverseInertia&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In theory we could adjust both body&#39;s by the exact overlap (&lt;code&gt;steeringConstant === 1.0&lt;/code&gt;), which we do know, but this introduces overlap in other shapes and the simulation ends up looking pretty terrible with shapes bouncing back and forth into each other.&lt;/p&gt;
&lt;p&gt;Example of &lt;code&gt;steeringConstant === 1.0&lt;/code&gt; ☹
&lt;img src=&quot;https://erikonarheim.com/images/understanding-iterative-constraing-solvers/overcorrection.gif&quot; alt=&quot;circles overcorrecting into each other&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Build Constraints - Velocity Collision Response&lt;/h3&gt;
&lt;p&gt;To prevent overlap in the direction of collision, we want the relative velocity of the two shapes to be 0 along the normal. So &lt;code&gt;relativeVelocity.dot(normal) === 0&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;In this code we calculate the velocity in the normal direction and apply the impulse in the opposite direction to cancel it out. Voila! Constraint met!&lt;/p&gt;
&lt;p&gt;Hand-waving some of the Newtonian math, impulses works out like so for us. (&lt;a href=&quot;https://en.wikipedia.org/wiki/Impulse_(physics)&quot;&gt;More reading on impulses&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;code&gt;effectiveMass * deltaVelocity = impulse&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Given this formula, if we can solve for an &lt;code&gt;impulse&lt;/code&gt; that will yeild a &lt;code&gt;deltaVelocity&lt;/code&gt; hat will bring velocity to 0 along the normal we are all set! See below:&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// DO THIS FOR X Iterations per frame, in practice 6ish&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; contact &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; contacts&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; point &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; contact&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;points&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Need to recalc relative velocity because the previous step could have changed vel&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; relativeVelocity &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; point&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getRelativeVelocity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; effectiveMass &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; bodyA&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;inverseMass &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; bodyB&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;inverseMass &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;br /&gt;                          bodyA&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;inverseInertia &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; aToContactNormal &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; aToContactNormal &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;br /&gt;                          bodyB&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;inverseInertia &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; bToContactNormal &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; bToContactNormal&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Compute impulse in normal direction&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; normalVelocity &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; relativeVelocity&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;dot&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;contact&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;normal&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; impulseDelta &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;normalVelocity &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; effectiveMass&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; impulseVector &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; contact&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;normal&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;impulseDelta&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// By convention the normal points away from A, so negate&lt;/span&gt;&lt;br /&gt;    contact&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bodyA&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;applyImpulse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;point&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;point&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; impulseVector&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;negate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    contact&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bodyB&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;applyImpulse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;point&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;point&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; impulse&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is only part of the picture the above only, what about objects bouncing off of each other? Borrowing from the &lt;a href=&quot;https://en.wikipedia.org/wiki/Collision_response&quot;&gt;wiki page for impulse based reactions&lt;/a&gt; the formula for this is:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;-(1 + restitution) * relativeVelocity.dot(normal) / effectiveMass&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Restitution is the ratio the body velocities after collision, one way to think about this is perhaps the &amp;quot;bounciness&amp;quot; of the system. Values of restitution should be between 0 and 1.&lt;/p&gt;
&lt;p&gt;So lets adjust the code from above to add that &amp;quot;bounce&amp;quot;&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// DO THIS FOR X Iterations per frame, in practice 6ish&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; contact &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; contacts&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; point &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; contact&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;points&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Need to recalc relative velocity because the previous step could have changed vel&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; relativeVelocity &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; point&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getRelativeVelocity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; effectiveMass &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; bodyA&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;inverseMass &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; bodyB&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;inverseMass &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;br /&gt;                          bodyA&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;inverseInertia &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; aToContactNormal &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; aToContactNormal &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;br /&gt;                          bodyB&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;inverseInertia &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; bToContactNormal &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; bToContactNormal&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; restitution &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; bodyA&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;restitution &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; bodyB&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;restitution&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Compute impulse in normal direction&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; normalVelocity &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; relativeVelocity&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;dot&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;contact&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;normal&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; impulseDelta &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; restitution&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; normalVelocity&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; effectiveMass&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; impulseVector &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; contact&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;normal&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;impulseDelta&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// By convention the normal points away from A, so negate&lt;/span&gt;&lt;br /&gt;    contact&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bodyA&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;applyImpulse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;point&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;point&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; impulseVector&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;negate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    contact&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bodyB&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;applyImpulse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;point&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;point&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; impulse&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now the resulting velocity after is the opposite in the normal direction scaled according to the restitution term! Voila we have bouncing! ✨&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/understanding-iterative-constraing-solvers/bounce.gif&quot; alt=&quot;bouncing&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Build Constraints - Friction&lt;/h3&gt;
&lt;p&gt;For friction, the process is similar to the constraint in the normal direction. We want to trend velocity in the tangent direction &lt;code&gt;relativeVelocity.dot(tangent) === 0&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Notice that the effective mass in the tangent direction is different than the normal direction.&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; contact &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; contacts&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; point &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; contact&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;points&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; relativeVelocity &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; point&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getRelativeVelocity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; effectiveMass &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; bodyA&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;inverseMass &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; bodyB&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;inverseMass &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;br /&gt;                          bodyA&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;inverseInertia &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; aToContactTangent &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; aToContactTangent &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;br /&gt;                          bodyB&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;inverseInertia &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; bToContactTangent &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; bToContactTangent&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; tangentVelocity &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;relativeVelocity&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;dot&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;contact&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tangent&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; impulseDelta &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; tangentVelocity &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; point&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tangentMass&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Impulse along the TANGENT&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; impulseVector &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; contact&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tangent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;impulseDelta&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// By convention the normal points away from A, so negate&lt;/span&gt;&lt;br /&gt;    contact&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bodyA&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;applyImpulse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;point&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;point&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; impulseVector&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;negate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    contact&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bodyB&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;applyImpulse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;point&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;point&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; impulse&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Not too bad, and it produces a pretty believable simulation.&lt;/p&gt;
&lt;h3&gt;Contact Warming for Stability&lt;/h3&gt;
&lt;p&gt;We can take advantage of previous work in earlier frames to help improve simulation stability (especially for large stacks of objects) by accumating the impulse for contacts that persist across frames. This helps overcome the force of gravity on big stacks by giving objects at the bottom extra impulse to start with.&lt;/p&gt;
&lt;p&gt;Notice compression of the stack when warming is off
&lt;img src=&quot;https://erikonarheim.com/images/understanding-iterative-constraing-solvers/warming.gif&quot; alt=&quot;warming stack&quot; /&gt;&lt;/p&gt;
&lt;p&gt;There is a trick to this, you can&#39;t just stash all the the impulses. We need to preserve the constraint that the sum of all impulses is positive (&lt;code&gt;Velocity &amp;gt;= 0&lt;/code&gt;) over time or it&#39;s possible shapes will end up overlaping on warming.&lt;/p&gt;
&lt;p&gt;In these examples we keep track of accumulated impulses in each persistent contact point.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Clamping based in Erin Catto&#39;s GDC 2014 talk&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Accumulated impulse stored in the contact is always positive (V &gt;= 0)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; newImpulse &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;point&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;normalImpulse &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; impulseDelta&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// But current impulse deltas can be negative&lt;/span&gt;&lt;br /&gt;impulseDelta &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; newImpulse &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; point&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;normalImpulse&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;point&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;normalImpulse &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; newImpulse&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Friction needs an additional check to keep things proportional to the normal force. Intiutively this makes sense, the harder something is pushing down on a surface, the more it sticks and resists sliding.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Clamping based in Erin Catto&#39;s GDC 2006 talk&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Correct clamping https://github.com/erincatto/box2d-lite/blob/master/docs/GDC2006_Catto_Erin_PhysicsTutorial.pdf&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Accumulated fiction impulse is always between -uMaxFriction &amp;lt; dT &amp;lt; uMaxFriction&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// But deltas can vary&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; maxFriction &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; friction &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; point&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;normalImpulse&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; newImpulse &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;clamp&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;point&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tangentImpulse &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; impulseDelta&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;maxFriction&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; maxFriction&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;impulseDelta &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; newImpulse &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; point&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tangentImpulse&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;point&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tangentImpulse &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; newImpulse&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once we have the impulses, at the beginning of the frame we can apply the accumulated impulses to any body&#39;s part of a persistent contact.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; contact &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; contacts&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; point &lt;span class=&quot;token keyword&quot;&gt;of&lt;/span&gt; contact&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;points&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; normalImpulse &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; contact&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;normal&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;point&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;normalImpulse&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Scaling back the tangent impulse seems to increase stack stability?&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; tangentImpulse &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; contact&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tangent&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;point&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;tangentImpulse&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;.2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; impulse &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; normalImpulse&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;tangentImpulse&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;br /&gt;    contact&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bodyA&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;applyLinearImpulse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;normalImpulse&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;negate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    contact&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bodyA&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;applyAngularImpulse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;point&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;point&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; tangentImpulse&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;negate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    contact&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bodyB&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;applyLinearImpulse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;normalImpulse&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    contact&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bodyB&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;applyAngularImpulse&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;point&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;point&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; tangentImpulse&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Order is important&lt;/h3&gt;
&lt;p&gt;Order of solving constraints creates precedence, constraints solved later in the frame take precedence. In general, your position constraints (like overlap) will probably take the most precedence in your simulation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Lowest precedence&lt;/strong&gt;&lt;/p&gt;
&lt;ol start=&quot;0&quot;&gt;
&lt;li&gt;Warm Contacts&lt;/li&gt;
&lt;li&gt;Friction&lt;/li&gt;
&lt;li&gt;Collsion Response (Velocity)&lt;/li&gt;
&lt;li&gt;No Overlap (Position)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Highest precedence&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;Summary&lt;/h3&gt;
&lt;p&gt;Constraint based collision resolution feels very similar in principle to other steering approaches, like &lt;a href=&quot;https://www.youtube.com/watch?v=IoKfQrlQ7rA&quot;&gt;flocking AI&#39;s&lt;/a&gt;, or &lt;a href=&quot;https://www.youtube.com/watch?v=6BrZryMz-ac&quot;&gt;enemy/npm AI&lt;/a&gt;. Steering is a powerful technique to create interesting emergent behavior with simple rules.&lt;/p&gt;
&lt;p&gt;Things to explore next with constraints might be joints, motors, etc using constraints!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/eonarheim/iterative-constraint-solver&quot;&gt;Read the code&lt;/a&gt;, and &lt;a href=&quot;https://eonarheim.github.io/iterative-constraint-solver/index.html&quot;&gt;see the demo!&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Resources &amp;amp; Additional Reading&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Also check out &lt;a href=&quot;http://allenchou.net/2013/12/game-physics-resolution-contact-constraints/&quot;&gt;Allen Chou&#39;s&lt;/a&gt; physics blog post series, and his &lt;a href=&quot;https://youtube.com/playlist?list=PL878TtL1s96VYNqoG0atuSr2EIU0kIuH0&quot;&gt;great video series on the topic&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Erin Catto also has a GDC 2006 &lt;a href=&quot;https://github.com/erincatto/box2d-lite/blob/master/docs/GDC2006_Catto_Erin_PhysicsTutorial.pdf&quot;&gt;slide deck&lt;/a&gt; that goes into detail about these different constrants.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Hopefully this helps folks out there implementing or trying to understand their own constraint systems!&lt;/p&gt;
&lt;p&gt;-Erik&lt;/p&gt;
</content>
  </item>
  
  <item>
    <title>Don&#39;t Test Fonts</title>
    <link>https://erikonarheim.com/posts/dont-test-fonts/</link>
    <description>Erik Onarheim</description>
    <guid>https://erikonarheim.com/posts/dont-test-fonts/</guid>
    <pubDate>Sun, 13 Dec 2020 00:00:00 +0000</pubDate>
    <content type="html" >&lt;p&gt;Recently for Excalibur I found myself in need of testing text rendering on the canvas, and found myself in a whole world of hurt 🤕. I was unaware of all of the pain around font rendering differences on different platforms.&lt;/p&gt;
&lt;h3&gt;The Problems&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Finding a font shared by all platforms is hard, &lt;a href=&quot;https://web.mit.edu/jmorzins/www/fonts.html&quot;&gt;web safe fonts&lt;/a&gt; get you close sometimes&lt;/li&gt;
&lt;li&gt;Platforms Windows/Linux/MacOS/Mobile render the &lt;em&gt;exact&lt;/em&gt; same font slightly differently&lt;/li&gt;
&lt;li&gt;Flash of unstyled text, ensuring a font is available for rendering&lt;/li&gt;
&lt;li&gt;Writing tests for text in a font&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;TLDR &lt;a href=&quot;https://github.com/eonarheim/font-loader-example&quot;&gt;the code&lt;/a&gt; and the &lt;a href=&quot;https://github.com/excaliburjs/excalibur-jasmine#new-and-improved-toequalimage&quot;&gt;jasmine matcher&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Use a specific font&lt;/h2&gt;
&lt;p&gt;Loading a specific open font is probably your best bet, relying on system fonts existing will not be consistent across platforms. I used the google fonts to find a font with a compatible license for me, in this example I used &amp;quot;Open Sans&amp;quot;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://fonts.google.com/specimen/Open+Sans&quot;&gt;https://fonts.google.com/specimen/Open+Sans&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/dont-test-fonts/google-fonts.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Let&#39;s disect the google font link quick.&lt;/h3&gt;
&lt;p&gt;The first &lt;code&gt;link&lt;/code&gt; is this preconnect to the google cdn where the actual font files are stored. &lt;code&gt;preconnect&lt;/code&gt; is a hint to the browser to start opening a connection to that domain so that it&#39;s ready to accept requests for fonts as soon as possible.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;preconnect&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://fonts.gstatic.com&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The second &lt;code&gt;link&lt;/code&gt; is a style sheet that defines the CSS &lt;code&gt;font-face&lt;/code&gt; for the font.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;https://fonts.googleapis.com/css2?family=Open+Sans&amp;amp;display=swap&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;stylesheet&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Popping that link into the browser you get something like below. Notice it&#39;s referencing the font CDN to grab the font files we mentioned earlier.&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* latin */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@font-face&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-family&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Open Sans&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; normal&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-weight&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 400&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;font-display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; swap&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token url&quot;&gt;&lt;span class=&quot;token function&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;https://fonts.gstatic.com/s/opensans/v18/mem8YaGs126MiZpBA-UFVZ0b.woff2&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;woff2&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;unicode-range&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; U+0000-00FF&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; U+0131&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; U+0152-0153&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; U+02BB-02BC&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; U+02C6&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; U+02DA&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; U+02DC&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; U+2000-206F&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; U+2074&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; U+20AC&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; U+2122&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; U+2191&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; U+2193&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; U+2212&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; U+2215&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; U+FEFF&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; U+FFFD&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;...&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Fix the Flash of Unstyled Text&lt;/h2&gt;
&lt;p&gt;After loading your fonts, there is a period of time before they are loaded preventing consistent tests.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/dont-test-fonts/unstyled.gif&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;There is a new browser api &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/FontFaceSet&quot;&gt;FontFaceSet&lt;/a&gt; that works most places you&#39;ll want to test in.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;FontFaceSet.load()&lt;/code&gt; forces a specific font to be loaded and returns a promise when it&#39;s done. This needs to be a fairly specific font string to work, including the the size, style, and font you want to load. ProTip&lt;sup&gt;tm&lt;/sup&gt; you &lt;strong&gt;must&lt;/strong&gt; specify italic or bold explicitly if you want to wait for it to load.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fonts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;18px Open Sans&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fonts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;italic 18px Open Sans&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fonts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;bold 18px Open Sans&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For some reason the &lt;code&gt;load()&lt;/code&gt; API doesn&#39;t seem to guarantee that the font is also &amp;quot;available&amp;quot;. You must also &lt;code&gt;check()&lt;/code&gt; that the font has been loaded and is available, but doesn&#39;t initiate a load itself.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fonts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;check&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;18px Open Sans&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With all of that here is the final helper to wait for a font, sourced from this &lt;a href=&quot;https://stackoverflow.com/a/64192936/839595&quot;&gt;SO post&lt;/a&gt;&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;waitForFontLoad&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;font&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; timeout &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; interval &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;resolve&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; reject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// repeatedly poll check&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; poller &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setInterval&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fonts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;font&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token function&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;err&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fonts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;check&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;font&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token function&quot;&gt;clearInterval&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;poller&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; interval&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;clearInterval&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;poller&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; timeout&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Putting it together&lt;/h3&gt;
&lt;p&gt;If you are using text in the dom, one trick is to use a marker CSS class on the document like &lt;code&gt;font-loaded&lt;/code&gt; to control display.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;waitForFontLoad&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;18px Open Sans&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;waitForFontLoad&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;bold 18px Open Sans&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;waitForFontLoad&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;italic 18px Open Sans&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;classList&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;font-loaded&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.text&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;font-family&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Open Sans&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.font-loaded .text&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; block&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.text.italic&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;font-style&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; italic&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.text.bold&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;font-weight&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; bold&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is great for testing! We can know if the font is present before running our test or drawing text in the canvas!&lt;/p&gt;
&lt;p&gt;However, this is not great visually if you inflict this on users 😢.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/dont-test-fonts/waitforload.gif&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Brief aside, here are a few options to fix this visual if you want to load fonts like this for people:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Block loading the WHOLE site until fonts are ready (not recommended, it&#39;s better to show your users something).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add placeholder rectangles while things are loading. This can work great if you need to load other data that&#39;ll take some time. Or if the text is being loaded from an endpoint.&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token selector&quot;&gt;.text&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;font-family&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Open Sans&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; inline-block&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; transparent&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; #ccc&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; solid #ccc&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 3px&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.font-loaded .text&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; none&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;background-color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; transparent&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; black&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/dont-test-fonts/rectangle.gif&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;My favorite, some CSS animations to fade in as things load&lt;/p&gt;
&lt;pre class=&quot;language-css&quot;&gt;&lt;code class=&quot;language-css&quot;&gt;&lt;span class=&quot;token atrule&quot;&gt;&lt;span class=&quot;token rule&quot;&gt;@keyframes&lt;/span&gt; fadeIn&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token selector&quot;&gt;0%&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;opacity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 0&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token selector&quot;&gt;100%&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token property&quot;&gt;opacity&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; 1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token selector&quot;&gt;.font-loaded .text&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; block&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;animation&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; fadeIn ease-in-out .2s&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/dont-test-fonts/fade-in.gif&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Writing the tests&lt;/h2&gt;
&lt;p&gt;If you&#39;re in jasmine, they support running &lt;code&gt;async&lt;/code&gt; functions in your &lt;code&gt;beforeAll&lt;/code&gt;, this means we can wait for things before starting our tests.&lt;/p&gt;
&lt;p&gt;I recommend downloading the font files from google fonts and making your own &lt;code&gt;fonts.css&lt;/code&gt; for the faces and characters you care about. I used the google sheet &lt;code&gt;https://fonts.googleapis.com/css2?family=Open+Sans&amp;amp;display=swap&lt;/code&gt; as a reference. Some CI platforms won&#39;t allow fonts to be loaded from an outside link (like AppVeyor).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/dont-test-fonts/download.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token function&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;My Text&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;beforeAll&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// Insert font into DOM&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// Fonts are stored in the locally in the project&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// path/to/my/font-normal.woff&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; fontfaces &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;link&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        fontfaces&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;href &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token string&quot;&gt;&#39;path/to/my/fonts.css&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        fontfaces&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;rel &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;stylesheet&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;head&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fontfaces&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// Wait for all font flavors to be available before starting the tests&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fonts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;18px Open Sans&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fonts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;bold 18px Open Sans&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fonts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;italic bold 18px Open Sans&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fonts&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;italic 18px Open Sans&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Supporting different platforms&lt;/h3&gt;
&lt;p&gt;If you are doing pixel diffing (like me) the same font will not render exactly the same on each platform. So I built a couple helpers that take advantage of &lt;code&gt;navigator.platform&lt;/code&gt;. Normally I would &lt;strong&gt;NOT recommend&lt;/strong&gt; using &lt;code&gt;navigator.platform&lt;/code&gt; for production code, but with CI I have control of the environment.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;runOnWindows&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;asyncCtx&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;navigator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;platform &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Win32&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; navigator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;platform &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;Win64&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;runOnLinux&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;asyncCtx&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;navigator&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;platform&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Linux&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I&#39;m using a very &lt;a href=&quot;https://github.com/excaliburjs/excalibur-jasmine#new-and-improved-toequalimage&quot;&gt;basic image matcher built for excalibur&lt;/a&gt; we implemented that can compare a canvas pixel by pixel with an expected image.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; ExcaliburAsyncMatchers &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;excalibur-jasmine&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;beforeEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;   jasmine&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addAsyncMatchers&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ExcaliburAsyncMatchers&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;should match images&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; canvasElement &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;canvas&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; ctx &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; canvasElement&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getContext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;2d&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;font &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;bold 18px Open Sans&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fillText&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Some Text&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;runOnWindows&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;expectAsync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;canvasElement&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toEqualImage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;src/spec/images/GraphicsTextSpec/text.png&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;runOnLinux&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;expectAsync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;canvasElement&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toEqualImage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;src/spec/images/GraphicsTextSpec/text-linux.png&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This outputs results as base64 to the console, not the best but works in all the CI platforms and can be copied to a browser to compare results.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/dont-test-fonts/image-diff.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;For a more full featured image diffing in your tests I&#39;d look into &lt;a href=&quot;https://github.com/mapbox/pixelmatch&quot;&gt;pixelmatch&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Hopes this helps you text and font peeps!&lt;/p&gt;
&lt;p&gt;Here is the &lt;a href=&quot;https://github.com/eonarheim/font-loader-example&quot;&gt;code&lt;/a&gt;, &lt;a href=&quot;https://github.com/excaliburjs/excalibur-jasmine#new-and-improved-toequalimage&quot;&gt;jasmine matcher&lt;/a&gt;, and the &lt;a href=&quot;https://github.com/excaliburjs/Excalibur/blob/0e0f94a1f282077206eae27e1377bd3ca8d39e45/src/spec/GraphicsTextSpec.ts#L129-L153&quot;&gt;excalibur example&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;-Erik&lt;/p&gt;
</content>
  </item>
  
  <item>
    <title>Using AssemblyScript with Webpack and TypeScript</title>
    <link>https://erikonarheim.com/posts/webpack-assemblyscript-and-wasm-loader/</link>
    <description>Erik Onarheim</description>
    <guid>https://erikonarheim.com/posts/webpack-assemblyscript-and-wasm-loader/</guid>
    <pubDate>Wed, 25 Nov 2020 00:00:00 +0000</pubDate>
    <content type="html" >&lt;p&gt;I&#39;ve recently been playing around with AssemblyScript for increasing the performance of my game engine &lt;a href=&quot;https://excaliburjs.com/&quot;&gt;Excalibur&lt;/a&gt;. It&#39;s a great language for WebAssembly, it&#39;s a subset of TypeScript (sounds familiar 😂) that compiles to WebAssembly. It was my first choice because I&#39;m very familiar with TypeScript, but there are great resources out there for C++ and Rust to WebAssembly.&lt;/p&gt;
&lt;p&gt;For my setup, I want to build my main app in TypeScript, my wasm in AssemblyScript and use a bundler to make it all happen. Turns out this was a bit tricky.&lt;/p&gt;
&lt;p&gt;TLDR show me the &lt;a href=&quot;https://github.com/eonarheim/assemblyscript-webpack-wasm-loader&quot;&gt;code&lt;/a&gt; 😎&lt;/p&gt;
&lt;h2&gt;Enter AssemblyScript&lt;/h2&gt;
&lt;p&gt;Getting AssemblyScript installed and compiling is fast with npm&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; npm install --save-dev --save-exact assemblyscript
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I built a small wasm adder built in AssemblyScript to demostrate, it should look pretty familiar for peeps used to TypeScript. I&#39;ll be writing a more in-depth post on using AssemblyScript, but I recommend &lt;a href=&quot;https://www.assemblyscript.org/introduction.html&quot;&gt;reading more&lt;/a&gt;. The only piece I will say, is that wasm only understands specialized number types and AssemblyScript has builtins to help with these. In this case below &lt;code&gt;i32&lt;/code&gt; stands for signed 32-bit integer.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// wasm-adder.ts&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; i32&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; b&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; i32&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; i32 &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; a &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; b&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You also need to setup a &lt;code&gt;tsconfig.json&lt;/code&gt; nearby to pull in those special AssemblyScript types with &lt;code&gt;extends&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;//tsconfig.json&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;extends&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;assemblyscript/std/assembly.json&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;include&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token string&quot;&gt;&quot;wasm-adder.ts&quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With all this setup it can be built into wasm on the commandline with:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; asc --optimize -b ./wasm/wasm-adder.wasm -t ./wasm/wasm-adder.wat ./wasm/wasm-adder.ts
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which when compiled to the wasm text format &lt;code&gt;.wat&lt;/code&gt; looks like this. The final &lt;code&gt;.wasm&lt;/code&gt; is a binary file!&lt;/p&gt;
&lt;pre class=&quot;language-wasm&quot;&gt;&lt;code class=&quot;language-wasm&quot;&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$wasm/assemblyscript/wasm-adder/add&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;param&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$0&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;i32&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;param&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$1&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;i32&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;i32&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;local&lt;/span&gt;.get &lt;span class=&quot;token variable&quot;&gt;$0&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;local&lt;/span&gt;.get &lt;span class=&quot;token variable&quot;&gt;$1&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token keyword&quot;&gt;i32&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;add&lt;/span&gt;&lt;br /&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Webpack Setup&lt;/h2&gt;
&lt;p&gt;I&#39;m a big fan of &lt;a href=&quot;https://parceljs.org/&quot;&gt;Parcel&lt;/a&gt; for quick easy dev, but it&#39;s WebAssembly support &lt;a href=&quot;https://github.com/parcel-bundler/parcel/issues/4867&quot;&gt;isn&#39;t&lt;/a&gt; &lt;a href=&quot;https://github.com/parcel-bundler/parcel/issues/1325&quot;&gt;there&lt;/a&gt; &lt;a href=&quot;https://github.com/parcel-bundler/parcel/issues/647&quot;&gt;yet&lt;/a&gt;. I tried to make my setup work in parcel but couldn&#39;t make it happen. Hopefully in &lt;a href=&quot;https://v2.parceljs.org/&quot;&gt;Parcel 2&lt;/a&gt; 🤞&lt;/p&gt;
&lt;p&gt;The Webpack setup here wasn&#39;t too bad. Here I&#39;ve setup the typescript loading using the popular &lt;a href=&quot;https://github.com/TypeStrong/ts-loader&quot;&gt;ts-loader&lt;/a&gt; and the excellent &lt;a href=&quot;https://github.com/ballercat/wasm-loader&quot;&gt;wasm-loader&lt;/a&gt; from &lt;code&gt;ballercat&lt;/code&gt; (who arguably has the best GitHub username ever 😎).&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// webpack.config.js&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; path &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;path&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// The &#39;first&#39; file to start the import chain&lt;/span&gt;&lt;br /&gt;    entry&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;./main.ts&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Local dev setings&lt;/span&gt;&lt;br /&gt;    mode&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;development&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    devtool&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;source-map&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    devServer&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        contentBase&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;__dirname&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;.&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        compress&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        port&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;9000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Output bunddle into the dist folder&lt;/span&gt;&lt;br /&gt;    output&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        library&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;main&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        libraryTarget&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;umd&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        path&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;__dirname&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;dist&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    resolve&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// Add `.ts` and `.tsx` as a resolvable extension (means you can leave the file extension off)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// I purposley didn&#39;t put &quot;.wasm&quot; here to illustrate the file being loaded&lt;/span&gt;&lt;br /&gt;        extensions&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;.ts&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;.tsx&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;.js&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    module&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        rules&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token comment&quot;&gt;// all files with a `.ts` or `.tsx` extension will be handled by `ts-loader`&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;br /&gt;                test&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token regex&quot;&gt;/\.tsx?$/&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token comment&quot;&gt;// Tells webpack how to interpret TypeScript files into JavaScript-land&lt;/span&gt;&lt;br /&gt;                loader&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ts-loader&quot;&lt;/span&gt; &lt;br /&gt;            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                test&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token regex&quot;&gt;/\.wasm$/&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token comment&quot;&gt;// Tells webpack how to interpret wasm files into JavaScript-land&lt;/span&gt;&lt;br /&gt;                loader&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;wasm-loader&quot;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;AssemblyScript + Webpack&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.assemblyscript.org/&quot;&gt;AssemblyScript&lt;/a&gt; doesn&#39;t have an official Webpack loader, but there are a few out there by &lt;a href=&quot;https://github.com/SinaMFE/assemblyscript-typescript-loader#readme&quot;&gt;others (buyer beware hasn&#39;t been updated in a while)&lt;/a&gt;. However, I&#39;m building my AssemblyScript manually, mostly because I have need to configure a few of the newer compiler options in my eventual use case.&lt;/p&gt;
&lt;p&gt;Here I use the AssemblyScript compiler, &lt;code&gt;asc&lt;/code&gt;, directly in my npm scripts. The AssemblyScript compiler has a lot of &lt;a href=&quot;https://www.assemblyscript.org/compiler.html#command-line-options&quot;&gt;options&lt;/a&gt; the ones I have here specificy the &lt;code&gt;-b&lt;/code&gt; binary, &lt;code&gt;-t&lt;/code&gt; web assembly text file (for debugging), &lt;code&gt;-d&lt;/code&gt; the TypeScript declaration file (this will be important for strong typing our wasm module), and finally the &lt;code&gt;--optimize&lt;/code&gt; to do optimizations on the final generated assembly.&lt;/p&gt;
&lt;p&gt;Below the idea is to build the wasm with the AssemblyScript compiler, then use the webpack &lt;code&gt;wasm-loader&lt;/code&gt; to bundle it.&lt;/p&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// package.json&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token property&quot;&gt;&quot;scripts&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;build&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;npm run build:assembly &amp;amp;&amp;amp; webpack&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;build:assembly&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;asc --optimize -b ./wasm/wasm-adder.wasm -t ./wasm/wasm-adder.wat -d ./wasm/types.d.ts ./wasm/assemblyscript/wasm-adder.ts&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// For development the wasm is only built once&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// The wasm will need to be rebuilt each time there isn&#39;t an asc --watch command yet&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;start&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;npm run build:assembly &amp;amp;&amp;amp; webpack serve&quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Configuring your AssemblyScript and wasm-loader Types&lt;/h2&gt;
&lt;p&gt;One cool trick when importing non-TypeScript files is to setup a &lt;code&gt;files.d.ts&lt;/code&gt; declaration at the root of your project. The &lt;code&gt;declare module &#39;*.wasm&#39;&lt;/code&gt; caters to the &lt;code&gt;wasm-loader&lt;/code&gt;&#39;s runtime JavaScript interface which provides a builder function with the optional WebAssembly imports. For AssemblyScript, you generally need to provide an &lt;code&gt;importsObject&lt;/code&gt; directly with an &lt;code&gt;env&lt;/code&gt; containingchunk of WebAssembly &lt;code&gt;memory&lt;/code&gt; and an &lt;code&gt;abort&lt;/code&gt; function.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// files.d.ts&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;declare&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;*.wasm&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Strongly type the exports with T&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;wasmBuilderFunc&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;importsObject&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; WebAssembly&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Imports&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;Promise&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;instance&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; WebAssembly&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Instance &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; exports&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; wasmBuilderFunc&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With Webpack and all the types configured, you can import the wasm file directly like so in &lt;code&gt;main.ts&lt;/code&gt;!&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// main.ts&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// wasmBuilder for https://github.com/ballercat/wasm-loader webpack loader&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; wasmBuilder &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;./wasm/wasm-adder.wasm&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;wasmBuilder&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    env&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        memory&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;WebAssembly&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Memory&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; initial&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token function-variable function&quot;&gt;abort&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wasm &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One slightly goofy thing about the AssemblyScript declaration file is that it&#39;s the types of the instantiated WebAssembly module instance&#39;s exports, &lt;strong&gt;not&lt;/strong&gt; the value directly out of the &lt;code&gt;import&lt;/code&gt; which gives us a &lt;code&gt;wasm-loader&lt;/code&gt; builder at runtime. So I renamed the AssemblyScript type declartion file to something else &lt;code&gt;types.d.ts&lt;/code&gt; to not confuse TypeScript types and import those types separately (note in the &lt;code&gt;package.json&lt;/code&gt; &lt;code&gt;build:assembly&lt;/code&gt;). This approach was inspired by the way AssemblyScript imports the types using the &lt;a href=&quot;https://www.assemblyscript.org/loader.html#typescript-definitions&quot;&gt;small assemblyscript file loader&lt;/a&gt; if your interested.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// wasmBuilder for https://github.com/ballercat/wasm-loader webpack loader&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; wasmBuilder &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;./wasm/wasm-adder.wasm&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// TypeScript type-only import&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;AdderModule&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;./wasm/types&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token generic-function&quot;&gt;&lt;span class=&quot;token function&quot;&gt;wasmBuilder&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt; AdderModule&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;wasm &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; Adder &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; wasm&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;instance&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;exports&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Full type support!&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; results &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Adder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Huzzah! 1 + 2 = &#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; results&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Pardon the document.write 😢&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;iframe src=&quot;https://codesandbox.io/embed/webpack-assemblyscript-ckf64?fontsize=14&amp;hidenavigation=1&amp;theme=dark&quot; style=&quot;width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;&quot; title=&quot;webpack-assemblyscript&quot; allow=&quot;accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking&quot; sandbox=&quot;allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;Yay strong typing on wasm modules using AssemblyScript and Webpack!&lt;/p&gt;
&lt;p&gt;Hope this helps my TypeScript and WebAssembly peeps out there!&lt;/p&gt;
&lt;p&gt;Cheers!
Erik&lt;/p&gt;
</content>
  </item>
  
  <item>
    <title>Android Games with Capacitor and JavaScript</title>
    <link>https://erikonarheim.com/posts/capacitorjs-game/</link>
    <description>Erik Onarheim</description>
    <guid>https://erikonarheim.com/posts/capacitorjs-game/</guid>
    <pubDate>Thu, 29 Oct 2020 00:00:00 +0000</pubDate>
    <content type="html" >&lt;p&gt;&lt;strong&gt;Updated on Feb 21st 2022 to the latest Excalibur, Capacitor.js &amp;amp; Parcel!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In this post we put a web canvas game built in Excalibur into an Android (or iOS) app with &lt;a href=&quot;https://capacitorjs.com/&quot;&gt;Capacitor.js&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;In the past I would have used something like Cordova, but this new thing from the folks at &lt;a href=&quot;https://ionic.io/&quot;&gt;Ionic&lt;/a&gt; has TypeScript support out of the box for their native APIs and support for using any Cordova plugins you might miss.&lt;/p&gt;
&lt;p&gt;TLDR &lt;a href=&quot;https://github.com/eonarheim/capacitor-game-v2&quot;&gt;show me the code&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Capacitor Setup&lt;/h2&gt;
&lt;p&gt;The capacitor project setup is pretty straightforward from their docs, it can &lt;a href=&quot;https://capacitorjs.com/docs/getting-started#adding-capacitor-to-an-existing-web-app&quot;&gt;drop in place&lt;/a&gt; in an existing project or &lt;a href=&quot;https://capacitorjs.com/docs/getting-started#optional-starting-a-fresh-project&quot;&gt;create a brand new project&lt;/a&gt; from scratch.&lt;/p&gt;
&lt;p&gt;I opted for the brand new project:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; npm init @capacitor/app
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then follow their wizard and instructions to configure.&lt;/p&gt;
&lt;p&gt;After that step add the platforms you&#39;re interested in, in this case Android&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; npx cap add android
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I recommend reading the &lt;a href=&quot;https://capacitorjs.com/docs/basics/workflow&quot;&gt;capacitor documentation&lt;/a&gt; on workflow with a hybrid native app. The gist is this&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Run &lt;code&gt;npx cap sync&lt;/code&gt; to copy your web project into capacitor&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;npx cap run android&lt;/code&gt; to start the project on android (or start in the Android SDK)&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Android Setup&lt;/h3&gt;
&lt;p&gt;Before you try to run the project&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Download Android Studio &lt;a href=&quot;https://developer.android.com/studio&quot;&gt;Android Studio&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Open it up and check for updates if needed (first time initialization takes some time)&lt;/li&gt;
&lt;li&gt;Accept your SDK package licenses, the easiest way I&#39;ve found to do this is with the SDK command line tools with Powershell on W.
&lt;ol&gt;
&lt;li&gt;Find the SDK Manager
&lt;img src=&quot;https://erikonarheim.com/images/capacitorjs-game/sdk-manager.png&quot; alt=&quot;Android Studio SDK Manager&quot; /&gt;&lt;/li&gt;
&lt;li&gt;In SDK Tools, check &lt;code&gt;Android SDK Command-line Tools&lt;/code&gt;
&lt;img src=&quot;https://erikonarheim.com/images/capacitorjs-game/android-cli.png&quot; alt=&quot;SDK Tools Command-line&quot; /&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Next we need to accept licenses.
&lt;img src=&quot;https://erikonarheim.com/images/capacitorjs-game/sdk-location.png&quot; alt=&quot;Android SDK location&quot; /&gt;
&lt;ul&gt;
&lt;li&gt;In powershell, navigate to the Android SDK Location for command line tools
&lt;code&gt;C:\Users\&amp;lt;username&amp;gt;\AppData\Local\Android\Sdk\cmdline-tools\latest\bin&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Set your java home temporarily &lt;code&gt;$env:JAVA_HOME = &#39;C:\Program Files\Android\Android Studio\jre&#39;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;.\sdkmanager.bat --licenses&lt;/code&gt; and select &lt;code&gt;y&lt;/code&gt; for each&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Starting the App&lt;/h3&gt;
&lt;p&gt;Now that we have Android all setup we can start the app with the capacitor command line.&lt;/p&gt;
&lt;p&gt;The gist is that it copies the final compiled html/css/js assets from your favorite frontend frameworks and build tools into the native container&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; npx cap sync
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After that we can open it in Android Studio with the capacitor commandline&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; npx cap open android
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Building the project and running the first time can take some time, so be patient after hitting the big green play button.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/capacitorjs-game/start.png&quot; alt=&quot;Android Studio Start Bar with Green Play Triangle Button&quot; /&gt;&lt;/p&gt;
&lt;p&gt;ProTip&lt;sup&gt;TM&lt;/sup&gt; &lt;strong&gt;The Emulator is MEGA slow&lt;/strong&gt; to start so once you get it on, leave it on. You can redeploy the app to a running emulator with the &amp;quot;re-run&amp;quot; hightlighted below.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/capacitorjs-game/restart-activity.png&quot; alt=&quot;Android Studio Restart Activity Button&quot; /&gt;&lt;/p&gt;
&lt;p&gt;If your Android emulator crashes on the first try like mine did with something like &lt;code&gt;The emulator process for AVD Pixel_3a_API_30_x86 was killed&lt;/code&gt;, this &lt;a href=&quot;https://www.youtube.com/watch?v=AOK9ZxiBOGg&quot;&gt;youtube video&lt;/a&gt; was super helpful. For me the problem was disk space, the AVD needs 7GBs of disk space to start so I had to clean out some junk on the laptop 😅&lt;/p&gt;
&lt;h2&gt;Building Your Canvas Game&lt;/h2&gt;
&lt;p&gt;The dev cycle is pretty slick, run &lt;code&gt;npm cap copy android&lt;/code&gt; to move your built JS living in the &lt;code&gt;www&lt;/code&gt; to the right android folder. The default app looks like this after running it in the android emulator.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/capacitorjs-game/emulator.png&quot; alt=&quot;Default Capacitor screen on Android emulator&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Setting Up Your JS Build&lt;/h3&gt;
&lt;p&gt;First let&#39;s setup our TypeScript by installing and creating an empty &lt;code&gt;tsconfig.json&lt;/code&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; npm install typescript --save-dev --save-exact
&amp;gt; npx tsc --init`
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Recently I&#39;ve been a big fan of &lt;a href=&quot;https://parceljs.org/&quot;&gt;parcel&lt;/a&gt;(v1) for quick and easy project setup, and it works great with &lt;a href=&quot;https://github.com/excaliburjs/template-ts-parcel&quot;&gt;excalibur&lt;/a&gt; also &lt;a href=&quot;https://github.com/excaliburjs/template-ts-webpack&quot;&gt;webpack is cool too&lt;/a&gt; if you need more direct control of your js bundling.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; npm install parcel --save-dev --save-exact
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I copied the generated &lt;code&gt;manifest.json&lt;/code&gt;, &lt;code&gt;index.html&lt;/code&gt;, and &lt;code&gt;css/&lt;/code&gt; folder out of the original generated &lt;code&gt;www/&lt;/code&gt; and put it into &lt;code&gt;game/&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/capacitorjs-game/game-folder.png&quot; alt=&quot;Folder structure of capacitor frontend project&quot; /&gt;&lt;/p&gt;
&lt;p&gt;We need to setup our development and final build script in the &lt;code&gt;package.json&lt;/code&gt;. The npm &lt;code&gt;&amp;quot;start&amp;quot;&lt;/code&gt; script tells parcel to run a dev server and use &lt;code&gt;game/index.html&lt;/code&gt; as our entry point to the app and follow the links and build them (notice the magic inline &lt;code&gt;&amp;lt;script type=&amp;quot;module&amp;quot; src=&amp;quot;./main.ts&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt;) ✨&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token doctype&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;!&lt;/span&gt;&lt;span class=&quot;token doctype-tag&quot;&gt;DOCTYPE&lt;/span&gt; &lt;span class=&quot;token name&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;html&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;lang&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;en&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;dir&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;ltr&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;head&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;charset&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;UTF-8&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Game Test&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;title&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;viewport&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;viewport-fit=cover, width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;format-detection&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;telephone=no&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;meta&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;msapplication-tap-highlight&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;no&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;manifest&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;./manifest.json&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;link&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rel&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;stylesheet&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;./css/style.css&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;head&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;module&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;./main.ts&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this setup I&#39;m sending all my built output with &lt;code&gt;--dist-dir&lt;/code&gt; into the &lt;code&gt;www&lt;/code&gt; directory, which is what capacitor will copy to android. I went ahead and deleted the provided default app in the &lt;code&gt;www&lt;/code&gt; directory.&lt;/p&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/* package.json */&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;my-cool-game&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;scripts&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;start&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;parcel game/index.html --dist-dir www&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;typecheck&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;tsc -p . --noEmit&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token property&quot;&gt;&quot;build&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;parcel build game/index.html --dist-dir www&quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;  ...&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Vanilla Canvas code&lt;/h3&gt;
&lt;p&gt;To start with I have a really awesome game that shows the fps and a red square. This shows how get started from scratch with the HTML Canvas.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// main.ts&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; canvas &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;canvas&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; HTMLCanvasElement&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; ctx &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getContext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;2d&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; CanvasRenderingContext2D&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;innerHeight&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;innerWidth&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;canvas&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; lastTime &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; performance&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; mainloop&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;FrameRequestCallback&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;now&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; delta &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;now &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; lastTime&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    lastTime &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; now&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fillStyle &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;blue&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fillRect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;    ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;font &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;50px sans-serif&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fillStyle &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;lime&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fillText&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;delta&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toFixed&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fillStyle &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;red&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fillRect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;40&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;40&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;requestAnimationFrame&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;mainloop&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;mainloop&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;performance&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/capacitorjs-game/examplerunning.png&quot; alt=&quot;Vanilla js game running in Android emulator&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Using Excalibur🗡&lt;/h2&gt;
&lt;p&gt;Using the Excalibur engine with capacitor and parcel will be a breeze! Really any web based game engine could be substituted here if you want. Here is the &lt;a href=&quot;https://github.com/eonarheim/capacitor-game-v2&quot;&gt;source on github&lt;/a&gt;!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; npm install excalibur --save-exact
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Update the &lt;code&gt;main.ts&lt;/code&gt; with some Excalibur&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; Actor&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; DisplayMode&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Engine&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Input&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Loader&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ImageSource &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;excalibur&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; game &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Engine&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    displayMode&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; DisplayMode&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;FillScreen&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    pointerScope&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Input&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;PointerScope&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Canvas&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; sword &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ImageSource&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;assets/sword.png&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; loader &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Loader&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;sword&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;game&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;loader&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    game&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;input&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pointers&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;primary&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;move&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; event &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; delta &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;  event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;worldPos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;sub&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;actor&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pos&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        actor&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vel &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; delta&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// Original asset is at a 45 degree angle need to adjust&lt;/span&gt;&lt;br /&gt;        actor&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;rotation &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; delta&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toAngle&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PI&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; actor &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Actor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        x&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; game&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;halfDrawWidth&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        y&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; game&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;halfDrawHeight&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        width&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;40&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        height&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;40&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    actor&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;graphics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;use&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;sword&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toSprite&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    game&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;actor&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note, depending on your emulator settings you may need to tweak it&#39;s graphics settings and restart Android Studio for it to build and run (This works out of the box fine on real hardware tested in BrowserStack, for some reason the emulator graphics can be confused)&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/capacitorjs-game/emulator-graphics.png&quot; alt=&quot;Update graphics support&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Tada! 🎉&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/capacitorjs-game/excalibur-capacitor.gif&quot; alt=&quot;Animated gif of excalibur sword running with Capacitor in Android&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Hope this helps you web game devs out there!&lt;/p&gt;
&lt;p&gt;-Erik&lt;/p&gt;
</content>
  </item>
  
  <item>
    <title>JavaScript Object Pools for Value Objects</title>
    <link>https://erikonarheim.com/posts/value-objects-in-javascript-object-pools/</link>
    <description>Erik Onarheim</description>
    <guid>https://erikonarheim.com/posts/value-objects-in-javascript-object-pools/</guid>
    <pubDate>Sun, 18 Oct 2020 00:00:00 +0000</pubDate>
    <content type="html" >&lt;p&gt;What do I mean by &amp;quot;value&amp;quot; objects? I mean things that behave like numbers conceptually. For example &lt;code&gt;const result = 1 + 2&lt;/code&gt;, adding two numbers doesn&#39;t change the value of &lt;code&gt;1&lt;/code&gt; or &lt;code&gt;2&lt;/code&gt; they are immutable, but a new value falls out the left hand side into the &lt;code&gt;result&lt;/code&gt;. This is a useful property, and sometimes you want JavaScript objects to behave this way. I&#39;ll call such objects them &lt;strong&gt;&amp;quot;value&amp;quot; objects&lt;/strong&gt; in this post.&lt;/p&gt;
&lt;h2&gt;Value Objects&lt;/h2&gt;
&lt;p&gt;In the example below &lt;code&gt;one&lt;/code&gt; and &lt;code&gt;two&lt;/code&gt; behave like values and are immutable, &lt;code&gt;result&lt;/code&gt; is a new value object, not a reference to &lt;code&gt;one&lt;/code&gt; or &lt;code&gt;two&lt;/code&gt; that was updated.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Vector&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;constuctor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; x&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; y&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;v&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Vector&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Vector &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Vector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; v&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; v&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;/// More implementation hidden&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; one &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Vector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; two &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Vector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; result &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; one&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;two&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// one still has the value (1, 1) after the &#39;add&#39; operation&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// two still has the value (2, 2) after the &#39;add&#39; operation&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// result is a new &quot;value&quot; object that has the value (3, 3)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Immutability helps protect against bugs, especially when working with objects that represent mathematical quantities. If the value of &lt;code&gt;one&lt;/code&gt; was updated to &lt;code&gt;(3, 3)&lt;/code&gt; after the &lt;code&gt;.add()&lt;/code&gt;, it might be unexpected (at least to me very confusing to have a &amp;quot;value&amp;quot; object change like this)!&lt;/p&gt;
&lt;h2&gt;The JavaScript Value Object Problem&lt;/h2&gt;
&lt;p&gt;So one downside to this type of value object is how quickly these ephemeral value objects can be created and discarded! This can build up in memory quickly and cause garbage collection pauses leading to some jankiness&lt;sup&gt;tm&lt;/sup&gt;!&lt;/p&gt;
&lt;p&gt;This might be unacceptable depending on your app. If you need high throughput and performance, like a game, value object related garbage collection could be a big problem.&lt;/p&gt;
&lt;p&gt;One solution is to use an &lt;strong&gt;object pool&lt;/strong&gt; strategy! While this technique is nothing new, it can be useful for these ephemeral value objects that might be used for intermediate calculations, this can cut down on &lt;code&gt;new Vector()&lt;/code&gt; allocations by an order of magnitude!&lt;/p&gt;
&lt;p&gt;TLDR: &lt;a href=&quot;https://github.com/eonarheim/object-pool&quot;&gt;Object Pool Source&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;⚠ Caveats of Object Pools! ⚠&lt;/h2&gt;
&lt;p&gt;I need to offer an obligatory warning, object pooling is a memory optimization technique. It effectivley works by taking on the role of memory manager instead of the &lt;strong&gt;very powerful&lt;/strong&gt; and &lt;strong&gt;well engineered&lt;/strong&gt; browser. Also don&#39;t trust me because I&#39;m writing about it, verify for yourself something will work for your usecase.&lt;/p&gt;
&lt;h3&gt;1. They are easy to get wrong and cause a memory leak&lt;/h3&gt;
&lt;p&gt;It&#39;s important to have a limit or perhaps a soft limit with logging in an object pool. Using a pool or implementing a pool incorrectly will just cause a memory leak that the browser cannot garbage collect anymore.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mitigation&lt;/strong&gt;: Add some stress tests with large numbers of objects over time to make sure pools are working as expected.&lt;/p&gt;
&lt;h3&gt;2. Hard to track down bugs&lt;/h3&gt;
&lt;p&gt;Using a reference to a value object that has been returned to the pool can cause bugs. Often the source of the bug is separated from where it manifested. For example if a leaked reference to a value object managed by the pool was reused and values were change it may cause invalid results in calculations.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mitigation&lt;/strong&gt;: Track the state of your objects and throw when used in invalid contexts.&lt;/p&gt;
&lt;h2&gt;Value Object Pool Implementation Details&lt;/h2&gt;
&lt;p&gt;We can compare the difference in allocations with a quick modification to our &lt;code&gt;Vector&lt;/code&gt; type to track the number of constructions. This type of thing is super useful in general if you&#39;re looking to increase memory efficency&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Vector&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;ALLOCATIONS&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;constuctor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; x&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; y&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        Vector&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;ALLOCATIONS&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;//...&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In order for this type of value object to make full use of the pool we need to pollute the type with some pool logic 😱 A less effecient version could be done without doing this. I try to minimize the intrusiveness of this change with a &lt;code&gt;_new(x: number, y: number)&lt;/code&gt; helper to abstract the pooling decision. Send me a note if you have any other suggestions on how to accomplish this better!&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Poolable&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Type &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;any&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    _pool&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Pool&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Type&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Implements a `Poolable` interface which decorates a `_pool` prop&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Vector&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Poolable&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Vector&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; _ALLOCATIONS &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// &lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; _pool&lt;span class=&quot;token operator&quot;&gt;?&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Pool&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Vector&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;_new&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;x&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; y&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Vector &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_pool&lt;span class=&quot;token operator&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;x&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; x&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Vector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;x&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; x&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;//...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;v&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Vector&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Vector &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;_new&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; v&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; v&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;//...&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With our &lt;code&gt;Vector&lt;/code&gt; value object setup to make use of pooling, we can use &lt;code&gt;using(...)&lt;/code&gt; to do all of our intermediate calculations, then when the using block is done all of the vectors used are recycled! This means we only need enough unique vectors to perform the calculation, none of the instances get waisted.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; VectorPool &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Pool&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Vector&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Builder Function tells the pool how to build an object&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;x&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; y&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Vector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;x&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; y&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Recycler Function tells the pool how to update an object for re-use&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;v&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; x&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; y&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; v&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; x&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; v&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; y&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; v&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// Max size on a pool is important to help catch memory leaks&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Update 200 things in my game loop&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; entities&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// After the using all Vectors are reclaimed for later use!&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;pos&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; vel&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; VectorPool&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;using&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; Pool&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;Vector&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// Uses the builder or recycler to retrieve a vector instance&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; position &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; p&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;copyFrom&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entities&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pos&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; velocity &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; p&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;copyFrom&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;entities&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vel&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; acceleration &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; p&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; accel&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// Perform euler position approximation&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; finalVelocity &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; velocity&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;acceleration&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;time&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; finalPosition &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; position&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;velocity&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;time&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;acceleration&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;.5&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; time &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; time&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        entities&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pos&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;copyFrom&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;finalPosition&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        entities&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;vel&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;copyFrom&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;finalVelocity&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// Returning these vectors from the pool `using()` signals that these will be unmanaged&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// These vectors are taken out of the pool&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;finalPosition&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; finalVelocity&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Object Pool Example &amp;amp; Results&lt;/h2&gt;
&lt;p&gt;The results are really impressive for the slightly contrived example of a game type program below! It becomes pretty clear the amount of objects that can be generated over time in this type of scenario if not pooled.&lt;/p&gt;
&lt;p&gt;Here is the source for the &lt;a href=&quot;https://github.com/eonarheim/object-pool&quot;&gt;object pool&lt;/a&gt; if you want to use it for yourself!&lt;/p&gt;
&lt;h3&gt;Pooled&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/value-objects-in-javascript-object-pools/pooled.gif&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Non-pooled&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/value-objects-in-javascript-object-pools/non-pooled.gif&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;More allocations can be squeezed if no pooled value objects are allowed to leave the pool with a &lt;code&gt;using()&lt;/code&gt; or &lt;code&gt;done()&lt;/code&gt;. Organizing your internal calculation this way can produce some very memory efficent results 😎&lt;/p&gt;
&lt;iframe src=&quot;https://codesandbox.io/embed/charming-goodall-9clgi?fontsize=14&amp;hidenavigation=1&amp;theme=dark&amp;view=preview&quot; style=&quot;width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;&quot; title=&quot;object-pool&quot; allow=&quot;accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking&quot; sandbox=&quot;allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;Hope this helps the person out there trying to do the same thing!&lt;/p&gt;
&lt;p&gt;Cheers,&lt;/p&gt;
&lt;p&gt;-Erik&lt;/p&gt;
</content>
  </item>
  
  <item>
    <title>Quickly Open Visual Studio on the Command Line</title>
    <link>https://erikonarheim.com/posts/quick-visual-studio/</link>
    <description>Erik Onarheim</description>
    <guid>https://erikonarheim.com/posts/quick-visual-studio/</guid>
    <pubDate>Tue, 06 Oct 2020 00:00:00 +0000</pubDate>
    <content type="html" >&lt;p&gt;I&#39;m a huge fan of using the command line for things, and I use the command line to open vs code all the time with &lt;code&gt;code .&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/quick-visual-studio/vscode.gif&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I wanted a way to do the same thing for visual studio, turns out you can! In the example below I use visual studio in a directory. The code works by searching recursivel for the &lt;code&gt;.sln&lt;/code&gt; file and passing the solution file path to &lt;code&gt;devenv.exe&lt;/code&gt; and you&#39;re set.&lt;/p&gt;
&lt;p&gt;Just stick this in your powershell profile, which can be opened with vs code with &lt;code&gt;code $PROFILE&lt;/code&gt; at the powershell prompt. Now type &lt;code&gt;vs .&lt;/code&gt; in the root of your favorite visual studio project.&lt;/p&gt;
&lt;pre class=&quot;language-powershell&quot;&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; vs&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token namespace&quot;&gt;[string]&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$start&lt;/span&gt; = &lt;span class=&quot;token string&quot;&gt;&quot;.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;# Locate a solution file recursivle &quot;*.sln&quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token variable&quot;&gt;$sln&lt;/span&gt; = &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;Get-ChildItem&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Path &lt;span class=&quot;token variable&quot;&gt;$start&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;Filter&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;sln &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Recurse&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;|&lt;/span&gt; where &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$_&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fullname &lt;span class=&quot;token operator&quot;&gt;-notmatch&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;node_modules&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;0&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;# Open the solution file with the well know visual studio path&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;# If you have the community edition replace &quot;Professional&quot; with &quot;Community&quot;&lt;/span&gt;&lt;br /&gt;    &amp;amp; &lt;span class=&quot;token string&quot;&gt;&quot;C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\Common7\IDE\devenv.exe&quot;&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$sln&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fullname&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/quick-visual-studio/vs.gif&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;This approach can be used for more than just visual studio, it could be applied to any program that has it&#39;s own project type. Possibilities might be unity, photoshop, aseprite, etc.&lt;/p&gt;
&lt;p&gt;Hope this makes your visual studio development a delight!
-Erik&lt;/p&gt;
</content>
  </item>
  
  <item>
    <title>Understanding The Canvas Measure Text Metrics</title>
    <link>https://erikonarheim.com/posts/canvas-text-metrics/</link>
    <description>Erik Onarheim</description>
    <guid>https://erikonarheim.com/posts/canvas-text-metrics/</guid>
    <pubDate>Fri, 02 Oct 2020 00:00:00 +0000</pubDate>
    <content type="html" >&lt;p&gt;When doing canvas drawing with text you may want to measure how the text is placed. Different fonts and different font sizes result in different pixel rendering, and it can be difficult to work with text pixel positioning in graphics programing.&lt;/p&gt;
&lt;p&gt;One problem is that the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/TextMetrics&quot;&gt;TextMetrics&lt;/a&gt; object that comes out of canvas rendering context &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/measureText&quot;&gt;measureText()&lt;/a&gt; has a lot of information and it&#39;s not super clear what it all means.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; canvas &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;canvas&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; ctx &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getContext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;2d&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;font &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;italic 50px serif&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; metrics &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;measureText&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Some text, but at what length?&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;The &lt;code&gt;metrics.width&lt;/code&gt; Is A Lie&lt;/h2&gt;
&lt;p&gt;You probably want to add &lt;code&gt;actualBoundingBoxLeft&lt;/code&gt; and &lt;code&gt;actualBoundingBoxRight&lt;/code&gt;, this will be a more acurate than just &lt;code&gt;width&lt;/code&gt;. The reason is some fonts have glyphs that hang or stretch over their width used for text placement. This is especially true if you want to ensure text renders within certain confines, like UI for a game.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; metrics &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;measureText&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Some text, but at what length?&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; width &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; metrics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// this can be slightly smaller&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Use absolute values to calculate the width, depending on alignment and text these values may be negative.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; metrics &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;measureText&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Some text, but at what length?&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; width &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;metrics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;actualBoundingBoxLeft&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;br /&gt;              Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;metrics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;actualBoundingBoxRight&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;There Is No Height (or Spoon)&lt;/h2&gt;
&lt;p&gt;The only way to get the height of a piece of text is to measure from the text baseline the ascent or descent. Before this was available the only thing was to guess the pixel height using the font size 😢.&lt;/p&gt;
&lt;p&gt;The baseline is the horizontal line that the text rests against in some way. Some characters in a piece of text can be above or below in some amount from this line. The main &lt;code&gt;textBaseline&lt;/code&gt; (and the default) is the &lt;code&gt;alphabeticBaseline&lt;/code&gt; where text normally sits this is 0 by default. There are 2 other baselines, &lt;code&gt;hangingBaseline&lt;/code&gt; and &lt;code&gt;ideographicBaseline&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Calculating the real height of some text is the sum of &lt;code&gt;actualBoundingBoxAscent&lt;/code&gt; and &lt;code&gt;actualBoundingBoxDescent&lt;/code&gt;. Guessing by the font size doesn&#39;t really work.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; height &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;metrics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;actualBoundingBoxAscent&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;br /&gt;               Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;metrics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;actualBoundingBoxDescent&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Drawing Bounds Around Text&lt;/h2&gt;
&lt;p&gt;Canvas text is drawn from the bottom left, which is different from the rectangle apis that draw from the top left.&lt;/p&gt;
&lt;p&gt;One way to remember this is that the position specified in &lt;code&gt;fillText(&#39;some text&#39;, 20, 20)&lt;/code&gt; is on the baseline. The text rests on the same line that the position does.&lt;/p&gt;
&lt;p&gt;With this in mind to draw bounds around text we subtract the the &lt;code&gt;actualBoundingBoxAscent&lt;/code&gt; from the y coordinate and &lt;code&gt;actualBoundingBoxLeft&lt;/code&gt; from the x coordinate.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// [x, y]&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; pos &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; bounds &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  top&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; pos&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; metrics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;actualBoundingBoxAscent&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  right&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; pos&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; metrics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;actualBoundingBoxRight&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  bottom&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; pos&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; metrics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;actualBoundingBoxDescent&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  left&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; pos&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; metrics&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;actualBoundingBoxLeft&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;iframe src=&quot;https://codesandbox.io/embed/canvas-text-metrics-ltg7b?fontsize=14&amp;hidenavigation=1&amp;theme=dark&amp;view=preview&quot; style=&quot;width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;&quot; title=&quot;canvas-text-metrics&quot; allow=&quot;accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking&quot; sandbox=&quot;allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts&quot;&gt;&lt;/iframe&gt;
&lt;h2&gt;Cool Things with Bounds&lt;/h2&gt;
&lt;p&gt;Once you have an accurate bounding box for the text there are a lot of cool things that can be done.&lt;/p&gt;
&lt;p&gt;Finding the center of the text is the average of the correct bounds, let&#39;s you flip and rotate with ease!&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; center &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;bounds&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;left &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; bounds&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;right&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;bounds&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;top &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; bounds&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bottom&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Move the transform to center in the middle of the text&lt;/span&gt;&lt;br /&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;translate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;center&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// flip in y&lt;/span&gt;&lt;br /&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// rotate 45 degrees&lt;/span&gt;&lt;br /&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;rotate&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;PI&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fillText&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; pos&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; pos&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; center&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;restore&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;iframe src=&quot;https://codesandbox.io/embed/canvas-text-metrics-transformations-hg0vi?fontsize=14&amp;hidenavigation=1&amp;theme=dark&amp;view=preview&quot; style=&quot;width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;&quot; title=&quot;canvas-text-metrics-transformations&quot; allow=&quot;accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking&quot; sandbox=&quot;allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;Hope this helps with your canvas text endeavors!
-Erik&lt;/p&gt;
</content>
  </item>
  
  <item>
    <title>HttpClient and BOM sadness with JSON serialization</title>
    <link>https://erikonarheim.com/posts/csharp-httpclient-and-bom-in-json/</link>
    <description>Erik Onarheim</description>
    <guid>https://erikonarheim.com/posts/csharp-httpclient-and-bom-in-json/</guid>
    <pubDate>Sun, 13 Aug 2017 00:00:00 +0000</pubDate>
    <content type="html" >&lt;p&gt;This week I ran across a problem when building a custom extension method to format a &lt;code&gt;PATCH&lt;/code&gt; request to an api endpoint. Basically I wanted to create a &lt;code&gt;PatchAsync&lt;/code&gt; method that matched the same semantics as &lt;code&gt;PostAsync&lt;/code&gt; and &lt;code&gt;GetAsync&lt;/code&gt; in &lt;code&gt;HttpClient&lt;/code&gt;. I had some more unique JSON serialization requirements working with the &lt;a href=&quot;https://erikonarheim.com/posts/iis-admin-rest-api-with-dsc&quot;&gt;IIS Admin rest api&lt;/a&gt; like &lt;code&gt;snake_casing&lt;/code&gt; and booleans and numbers serialized at string literals like &amp;quot;124&amp;quot; or &amp;quot;true&amp;quot;, so I needed to be able to pass my own JSON.NET configuration to the serialization.&lt;/p&gt;
&lt;p&gt;Borrowing from this &lt;a href=&quot;https://stackoverflow.com/questions/26218764/patch-async-requests-with-windows-web-http-httpclient-class&quot;&gt;SO post&lt;/a&gt; I crafted this extension method:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code class=&quot;language-csharp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token return-type class-name&quot;&gt;Task&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;HttpResponseMessage&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token generic-method&quot;&gt;&lt;span class=&quot;token function&quot;&gt;PatchAsync&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;T&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HttpClient&lt;/span&gt; client&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;string&lt;/span&gt;&lt;/span&gt; requestUri&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MediaTypeFormatter&lt;/span&gt; formatter&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt;&lt;/span&gt; method &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token constructor-invocation class-name&quot;&gt;HttpMethod&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;PATCH&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token class-name&quot;&gt;HttpRequestMessage&lt;/span&gt; request&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt;&lt;/span&gt; ms &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token constructor-invocation class-name&quot;&gt;MemoryStream&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt;&lt;/span&gt; jsonFormatter &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; formatter &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;JsonMediaTypeFormatter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;br /&gt;        jsonFormatter&lt;span class=&quot;token punctuation&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;WriteToStream&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token type-expression class-name&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ms&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Encoding&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;UTF8&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt;&lt;/span&gt; content &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Encoding&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;UTF8&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ms&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetBuffer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;ms&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Length&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        request &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token constructor-invocation class-name&quot;&gt;HttpRequestMessage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;method&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; requestUri&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;                    &lt;br /&gt;            Content &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token constructor-invocation class-name&quot;&gt;StringContent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;content&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Encoding&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;UTF8&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; jsonFormatter&lt;span class=&quot;token punctuation&quot;&gt;?.&lt;/span&gt;SupportedMediaTypes&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;First&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;?.&lt;/span&gt;MediaType&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token class-name&quot;&gt;HttpResponseMessage&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;SendAsync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;request&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;TaskCanceledException&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As far as I could tell from human eyeballs everything looked good, but when I ran this code from code it would bomb with &amp;quot;Unsupported Media Type: Invalid JSON&amp;quot;. I could craft the same request by hand in &lt;a href=&quot;http://www.telerik.com/fiddler&quot;&gt;fiddler&lt;/a&gt; or &lt;a href=&quot;https://www.getpostman.com/&quot;&gt;postman&lt;/a&gt; and it would work!&lt;/p&gt;
&lt;p&gt;I did notice one odd artifact in the requests, the &lt;code&gt;Content-Length&lt;/code&gt; didn&#39;t match up between the failing and succeeding requests even with what looked like the same payload...&lt;/p&gt;
&lt;pre class=&quot;language-http&quot;&gt;&lt;code class=&quot;language-http&quot;&gt;&lt;br /&gt;&lt;span class=&quot;token request-line&quot;&gt;&lt;span class=&quot;token property&quot;&gt;PATCH&lt;/span&gt; https://mycoolserver&lt;span class=&quot;token attr-name&quot;&gt;:55539&lt;/span&gt;/api/webserver/logging/JpcOekeNc7uR-m9y8_uE9Q HTTP/1.1&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Access-Token:&lt;/span&gt; Bearer abcdefghijklmnopqrstuvwxyz&lt;br /&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Content-Type:&lt;/span&gt; application/json; charset=utf-8&lt;br /&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Host:&lt;/span&gt; mycoolserver:55539&lt;br /&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Content-Length:&lt;/span&gt; 76&lt;br /&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Expect:&lt;/span&gt; 100-continue&lt;span class=&quot;token application-json&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;JpcOekeNc7uR-m9y8_uE9Q&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;directory&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;D:\\inetpub\\logs\\coolsite160&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;token response-status&quot;&gt;HTTP/1.1 &lt;span class=&quot;token property&quot;&gt;200 OK&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Cache-Control:&lt;/span&gt; public, max-age=0&lt;br /&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Transfer-Encoding:&lt;/span&gt; chunked&lt;br /&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Content-Type:&lt;/span&gt; application/vnd.Microsoft.WebServer.Logging.2.0.0+json; charset=utf-8&lt;br /&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Server:&lt;/span&gt; Microsoft-HTTPAPI/2.0&lt;br /&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Date:&lt;/span&gt; Tue, 08 Aug 2017 20:08:59 GMT&lt;span class=&quot;token application-json&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Success Response&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-http&quot;&gt;&lt;code class=&quot;language-http&quot;&gt;&lt;span class=&quot;token request-line&quot;&gt;&lt;span class=&quot;token property&quot;&gt;PATCH&lt;/span&gt; https://mycoolserver&lt;span class=&quot;token attr-name&quot;&gt;:55539&lt;/span&gt;/api/webserver/logging/JpcOekeNc7uR-m9y8_uE9Q HTTP/1.1&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Access-Token:&lt;/span&gt; Bearer abcdefghijklmnopqrstuvwxyz&lt;br /&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Content-Type:&lt;/span&gt; application/json; charset=utf-8&lt;br /&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Host:&lt;/span&gt; mycoolserver:55539&lt;br /&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Content-Length:&lt;/span&gt; 79&lt;br /&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Expect:&lt;/span&gt; 100-continue&lt;span class=&quot;token application-json&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;JpcOekeNc7uR-m9y8_uE9Q&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;directory&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;D:\\inetpub\\logs\\coolsite160&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;token response-status&quot;&gt;HTTP/1.1 &lt;span class=&quot;token property&quot;&gt;415 Unsupported Media Type&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Cache-Control:&lt;/span&gt; public, max-age=0&lt;br /&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Transfer-Encoding:&lt;/span&gt; chunked&lt;br /&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Content-Type:&lt;/span&gt; application/problem+json&lt;br /&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Content-Language:&lt;/span&gt; en&lt;br /&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Server:&lt;/span&gt; Microsoft-HTTPAPI/2.0&lt;br /&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Accept-Patch:&lt;/span&gt; application/json;charset=utf-8&lt;br /&gt;&lt;span class=&quot;token header-name keyword&quot;&gt;Date:&lt;/span&gt; Tue, 08 Aug 2017 20:09:10 GMT&lt;span class=&quot;token application-json&quot;&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token number&quot;&gt;34&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;title&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;Invalid JSON request object&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token property&quot;&gt;&quot;status&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;415&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Aaaah HAAAA! There must be some invisible characters my dear Watson!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/csharp-httpclient-and-bom-in-json/watson.gif&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;So I cracked open the trusty HEX editor and lo and behold! A BOM (literally) aka a byte order mark has snuck it&#39;s way in between my request headers and JSON payload! This 3-byte mark is included in UTF encoded stuff to help readers decode correctly. Ironically it breaks some deserializers, like the one in the IIS Rest Admin API!&lt;/p&gt;
&lt;p&gt;Successful request:
&lt;img src=&quot;https://erikonarheim.com/images/csharp-httpclient-and-bom-in-json/successreq.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Failed request:
&lt;img src=&quot;https://erikonarheim.com/images/csharp-httpclient-and-bom-in-json/failedreq.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;After I discovered this the fix was pretty easy, &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/s064f8w2.aspx&quot;&gt;.NET provides&lt;/a&gt; a new &lt;code&gt;UTF8Encoding&lt;/code&gt; type that can be passed true or false to its constructor to indicated whether a BOM is wanted.&lt;/p&gt;
&lt;p&gt;So the fixed extension method:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code class=&quot;language-csharp&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;token return-type class-name&quot;&gt;Task&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;HttpResponseMessage&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token generic-method&quot;&gt;&lt;span class=&quot;token function&quot;&gt;PatchAsync&lt;/span&gt;&lt;span class=&quot;token generic class-name&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;T&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;HttpClient&lt;/span&gt; client&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;string&lt;/span&gt;&lt;/span&gt; requestUri&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;T&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MediaTypeFormatter&lt;/span&gt; formatter&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt;&lt;/span&gt; method &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token constructor-invocation class-name&quot;&gt;HttpMethod&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;PATCH&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token class-name&quot;&gt;HttpRequestMessage&lt;/span&gt; request&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// No BOM now&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt;&lt;/span&gt; utf8 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token constructor-invocation class-name&quot;&gt;UTF8Encoding&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt;&lt;/span&gt; ms &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token constructor-invocation class-name&quot;&gt;MemoryStream&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt;&lt;/span&gt; jsonFormatter &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; formatter &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;JsonMediaTypeFormatter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;br /&gt;        jsonFormatter&lt;span class=&quot;token punctuation&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;WriteToStream&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;typeof&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token type-expression class-name&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ms&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; utf8&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token class-name&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt;&lt;/span&gt; content &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; utf8&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ms&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;GetBuffer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;ms&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Length&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        request &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token constructor-invocation class-name&quot;&gt;HttpRequestMessage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;method&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; requestUri&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;                    &lt;br /&gt;            Content &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token constructor-invocation class-name&quot;&gt;StringContent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;content&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; utf8&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; jsonFormatter&lt;span class=&quot;token punctuation&quot;&gt;?.&lt;/span&gt;SupportedMediaTypes&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;First&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;?.&lt;/span&gt;MediaType&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token class-name&quot;&gt;HttpResponseMessage&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;SendAsync&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;request&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;TaskCanceledException&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;throw&lt;/span&gt; e&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; response&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Hopefully this helps out any of you JSON payload peeps trying to customize HttpClient. Somebody set us up the 💣!&lt;/p&gt;
</content>
  </item>
  
  <item>
    <title>IIS Administration REST API with PowerShell DSC in Azure</title>
    <link>https://erikonarheim.com/posts/iis-admin-rest-api-with-dsc/</link>
    <description>Erik Onarheim</description>
    <guid>https://erikonarheim.com/posts/iis-admin-rest-api-with-dsc/</guid>
    <pubDate>Sat, 17 Jun 2017 00:00:00 +0000</pubDate>
    <content type="html" >&lt;p&gt;For a long time I have been using the good ol&#39;fashioned DCOM based ServerManager client from Microsoft.Web.Administration.dll to configure IIS web servers. Now there is a nifty new &lt;a href=&quot;https://github.com/Microsoft/IIS.Administration&quot;&gt;open source administration REST api&lt;/a&gt; from Microsoft! OMGWTFBACON! This a great boon to your &amp;quot;DevOps&amp;quot; play because any language that speaks HTTP can be used to manage IIS cluster no matter how large or small! In this post I&#39;ll introduce you to PowerShell Desired State Configuration to install this powerful management tool in your environment. Like a boss 😎&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/iis-admin-rest-api-with-dsc/yeaaaah.gif&quot; alt=&quot;boss hoss&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;What is DSC?&lt;/h3&gt;
&lt;p&gt;PowerShell DSC is a super powerful desired state configuration tool that comes with your windows server as a part of WMF (it is similar in concept to Puppet or Chef which can also work with windows servers). DSC can be setup in multiple ways: &amp;quot;Pull&amp;quot; or &amp;quot;Push&amp;quot;. In my environment we&#39;ve setup things in a Pull configuration, where enrolled nodes check into the central Pull server every thirty minutes for configuration. Push is an on demand process that pushes config to target nodes with an admin credential. Optionally, you could use azure automation as a pull server in the cloud to manage your on-prem or cloud windows machines.&lt;/p&gt;
&lt;h3&gt;Constructing the DSC&lt;/h3&gt;
&lt;p&gt;This is actually pretty easy to setup manually following the steps outlined on the Microsoft &lt;a href=&quot;https://github.com/Microsoft/IIS.Administration&quot;&gt;github project&lt;/a&gt;, but if you have an environment with hundreds or thousands of servers that spin up and down, this isn&#39;t super sustainable.&lt;/p&gt;
&lt;p&gt;First we need to setup our configuration, all configuration in DSC needs to be in a &lt;code&gt;configuration&lt;/code&gt; block.&lt;/p&gt;
&lt;pre class=&quot;language-powershell&quot;&gt;&lt;code class=&quot;language-powershell&quot;&gt;configuration &lt;span class=&quot;token function&quot;&gt;Install-IIS&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Admin&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Rest&lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Api &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;&amp;lt;# Todo awesome config for these righteous web servers #&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;There are TONS of prebuilt &lt;a href=&quot;https://github.com/PowerShell/PSDscResources&quot;&gt;open source DSC resources&lt;/a&gt;, along with some &lt;a href=&quot;https://github.com/PowerShell/xPSDesiredStateConfiguration&quot;&gt;experimental resources&lt;/a&gt; from Microsoft. Their github has tons of examples. In PowerShell 5, we can source these resources from the internet using &lt;code&gt;Install-Module -Name xPSDesiredStateConfiguration&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;In order for the rest api to work there are a few requirements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;IIS installed&lt;/li&gt;
&lt;li&gt;Windows authentication enabled&lt;/li&gt;
&lt;li&gt;URL authorization enabled&lt;/li&gt;
&lt;li&gt;Hostable web core enabled&lt;/li&gt;
&lt;li&gt;ASP.NET Core hosting bundle&lt;/li&gt;
&lt;li&gt;Local in-bound firewall opened on management port 55539 (or whatever port you want)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The windows features are pretty simple, you just need to find the string for the feature you are looking for. The &lt;code&gt;Get-WindowsFeature *web*&lt;/code&gt; command will get you far. Notice the &lt;code&gt;DependsOn = &amp;quot;[ResourceType]ResourceName&amp;quot;&lt;/code&gt; strings, these are how you can make one resource depend on another. Unfortunately they are &amp;quot;stringly&amp;quot; typed and easy to mistype by mistake so I tend to copy paste these values.&lt;/p&gt;
&lt;pre class=&quot;language-powershell&quot;&gt;&lt;code class=&quot;language-powershell&quot;&gt;WindowsFeature InstallIIS &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    Name = &lt;span class=&quot;token string&quot;&gt;&quot;Web-Server&quot;&lt;/span&gt;&lt;br /&gt;    Ensure = &lt;span class=&quot;token string&quot;&gt;&quot;Present&quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;WindowsFeature EnableWinAuth &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    Name = &lt;span class=&quot;token string&quot;&gt;&quot;Web-Windows-Auth&quot;&lt;/span&gt;&lt;br /&gt;    Ensure = &lt;span class=&quot;token string&quot;&gt;&quot;Present&quot;&lt;/span&gt;&lt;br /&gt;    DependsOn = &lt;span class=&quot;token string&quot;&gt;&quot;[WindowsFeature]InstallIIS&quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;WindowsFeature EnableURLAuth &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    Name = &lt;span class=&quot;token string&quot;&gt;&quot;Web-Url-Auth&quot;&lt;/span&gt;&lt;br /&gt;    Ensure = &lt;span class=&quot;token string&quot;&gt;&quot;Present&quot;&lt;/span&gt;&lt;br /&gt;    DependsOn = &lt;span class=&quot;token string&quot;&gt;&quot;[WindowsFeature]InstallIIS&quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;WindowsFeature HostableWebCore &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    Name = &lt;span class=&quot;token string&quot;&gt;&quot;Web-WHC&quot;&lt;/span&gt;&lt;br /&gt;    Ensure = &lt;span class=&quot;token string&quot;&gt;&quot;Present&quot;&lt;/span&gt;&lt;br /&gt;    DependsOn = &lt;span class=&quot;token string&quot;&gt;&quot;[WindowsFeature]InstallIIS&quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For installers available online you can download them on the fly with the &lt;code&gt;xRemoteFile&lt;/code&gt; resource, one method of sourcing such dependencies is to check them into your git repo using git lfs. Check out my friends &lt;a href=&quot;https://kamranicus.com/posts/2017-06-14-downloading-git-lfs-files-from-tfs-vsts&quot;&gt;post on that.&lt;/a&gt;. Otherwise you can source the direct download links like I did for this demo. Note that if you are in a corporate environment you may work behind a proxy which this resource takes into account.&lt;/p&gt;
&lt;pre class=&quot;language-powershell&quot;&gt;&lt;code class=&quot;language-powershell&quot;&gt;xRemoteFile DownloadDotNetCoreHostingBundle &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    Uri = &lt;span class=&quot;token string&quot;&gt;&quot;https://go.microsoft.com/fwlink/?linkid=844461&quot;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;#https://docs.microsoft.com/en-us/aspnet/core/publishing/iis&lt;/span&gt;&lt;br /&gt;    DestinationPath = &lt;span class=&quot;token string&quot;&gt;&quot;C:\temp\dnhosting.exe&quot;&lt;/span&gt;&lt;br /&gt;    MatchSource = &lt;span class=&quot;token boolean&quot;&gt;$false&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;# Match source false wont re-download if the files change&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;#Proxy = &quot;optional, your corporate proxy here&quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;#ProxyCredential = &quot;optional, your corporate proxy credential here&quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The built in &lt;code&gt;Package&lt;/code&gt; resource is pretty simple, it does require some hard to find metadata. I find most consistent way to discover the metadata necessary for DSC is to install it once and run &lt;code&gt;Get-WmiObject Win32_product | ft IdentifyingNumber,Name&lt;/code&gt; to find it&#39;s ID and Product Name. Note that IIS &lt;code&gt;WindowsFeature&lt;/code&gt; and the &lt;code&gt;xRemoteFile&lt;/code&gt; installer resource dependency before we can install the hosting bundle. Then I cheat by temporarily adding &lt;code&gt;dotnet.exe&lt;/code&gt; to the path to avoid a reboot.&lt;/p&gt;
&lt;pre class=&quot;language-powershell&quot;&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;# Discover your product name and id with Get-WmiObject Win32_product | ft IdentifyingNumber,Name after installing it once&lt;/span&gt;&lt;br /&gt;xPackage InstallDotNetCoreHostingBundle &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    Name = &lt;span class=&quot;token string&quot;&gt;&quot;Microsoft ASP.NET Core Module&quot;&lt;/span&gt;&lt;br /&gt;    ProductId = &lt;span class=&quot;token string&quot;&gt;&quot;B1B05FBB-1255-4F5B-9BAF-43B971A92613&quot;&lt;/span&gt;&lt;br /&gt;    Arguments = &lt;span class=&quot;token string&quot;&gt;&quot;/quiet /norestart /log C:\temp\dnhosting_install.log&quot;&lt;/span&gt;&lt;br /&gt;    Path = &lt;span class=&quot;token string&quot;&gt;&quot;C:\temp\dnhosting.exe&quot;&lt;/span&gt;&lt;br /&gt;    DependsOn = @&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;[WindowsFeature]InstallIIS&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                  &lt;span class=&quot;token string&quot;&gt;&quot;[xRemoteFile]DownloadDotNetCoreHostingBundle&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# Cheating and adding the dotnet.exe to the path to avoid reboot&lt;/span&gt;&lt;br /&gt;Script PutDotNetOnPath &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    SetScript = &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token variable&quot;&gt;$env&lt;/span&gt;:Path = &lt;span class=&quot;token variable&quot;&gt;$env&lt;/span&gt;:Path &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;C:\Program Files\dotnet\;&quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    TestScript = &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;$env&lt;/span&gt;:Path&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Contains&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;C:\Program Files\dotnet\;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    GetScript = &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; @&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            SetScript = &lt;span class=&quot;token variable&quot;&gt;$SetScript&lt;/span&gt;&lt;br /&gt;            TestScript = &lt;span class=&quot;token variable&quot;&gt;$TestScript&lt;/span&gt;&lt;br /&gt;            GetScript = &lt;span class=&quot;token variable&quot;&gt;$GetSCript&lt;/span&gt;&lt;br /&gt;            Result = &lt;span class=&quot;token string&quot;&gt;&quot;Set dotnet path&quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, lets download the Admin Rest API from Microsoft&#39;s GitHub &lt;a href=&quot;https://github.com/Microsoft/IIS.Administration/releases/&quot;&gt;release page&lt;/a&gt; and run the script installer. Note that in this case I use the &lt;code&gt;Archive&lt;/code&gt; resource to unpzip the downloaded package into a directory for me to call later with a &lt;code&gt;Script&lt;/code&gt; resource. For things that don&#39;t exist by default or in an external module, you can use &lt;code&gt;Script&lt;/code&gt; resources to write vanilla powershell. The script resource has a few parts, the &lt;code&gt;SetScript&lt;/code&gt; which does the work if the resource is not in compliance, &lt;code&gt;TestScript&lt;/code&gt; which returns &lt;code&gt;$true&lt;/code&gt; if in compliance and &lt;code&gt;$false&lt;/code&gt; if not, and the &lt;code&gt;GetScript&lt;/code&gt; which can be used to return the status of the node with the &lt;code&gt;@{ Result = &amp;quot;status&amp;quot;}&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-powershell&quot;&gt;&lt;code class=&quot;language-powershell&quot;&gt;xRemoteFile DownloadAdminRestApi &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    Uri = &lt;span class=&quot;token string&quot;&gt;&quot;https://github.com/Microsoft/IIS.Administration/releases/download/v1.1.1/IIS.Administration.zip&quot;&lt;/span&gt;&lt;br /&gt;    DestinationPath = &lt;span class=&quot;token string&quot;&gt;&quot;C:\temp\IISAdministration.zip&quot;&lt;/span&gt;&lt;br /&gt;    MatchSource = &lt;span class=&quot;token boolean&quot;&gt;$false&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Archive UnzipAdminRestApi &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    Path = &lt;span class=&quot;token string&quot;&gt;&quot;C:\temp\IISAdministration.zip&quot;&lt;/span&gt;&lt;br /&gt;    Destination = &lt;span class=&quot;token string&quot;&gt;&quot;C:\temp\Admin\IISAdministration&quot;&lt;/span&gt;&lt;br /&gt;    Ensure = &lt;span class=&quot;token string&quot;&gt;&quot;Present&quot;&lt;/span&gt;&lt;br /&gt;    DependsOn = &lt;span class=&quot;token string&quot;&gt;&quot;[xRemoteFile]DownloadAdminRestApi&quot;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Script InstallAdminRestApi &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    DependsOn = @&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;[Archive]UnzipAdminRestApi&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&quot;token string&quot;&gt;&quot;[WindowsFeature]InstallIIS&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&quot;token string&quot;&gt;&quot;[WindowsFeature]EnableURLAuth&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&quot;token string&quot;&gt;&quot;[WindowsFeature]EnableWinAuth&quot;&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&quot;token string&quot;&gt;&quot;[xPackage]InstallDotNetCoreHostingBundle&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;                    &lt;span class=&quot;token string&quot;&gt;&quot;[Script]PutDotNetOnPath&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;    SetScript = &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;# Run the IIS Administration installer&lt;/span&gt;&lt;br /&gt;        &amp;amp; C:\temp\Admin\IISAdministration\setup\setup&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ps1 Install &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;Verbose                &lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    TestScript = &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token variable&quot;&gt;$svc&lt;/span&gt; = &lt;span class=&quot;token variable&quot;&gt;$null&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token variable&quot;&gt;$svc&lt;/span&gt; = &lt;span class=&quot;token function&quot;&gt;Get-Service&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Microsoft IIS Administration&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;ErrorAction SilentlyContinue&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token variable&quot;&gt;$svc&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    GetScript = &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; @&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            SetScript = &lt;span class=&quot;token variable&quot;&gt;$SetScript&lt;/span&gt;&lt;br /&gt;            TestScript = &lt;span class=&quot;token variable&quot;&gt;$TestScript&lt;/span&gt;&lt;br /&gt;            GetScript = &lt;span class=&quot;token variable&quot;&gt;$GetScript&lt;/span&gt;&lt;br /&gt;            Result = &lt;span class=&quot;token string&quot;&gt;&quot;Install Admin Rest Api&quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&#39;s see how it&#39;s all put together with the final configuration script! Checkout my &lt;a href=&quot;https://gist.github.com/eonarheim/703e0f1807b26066d6a2ff5acf4f662d&quot;&gt;gist&lt;/a&gt; with the code.&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/eonarheim/703e0f1807b26066d6a2ff5acf4f662d.js&quot;&gt;&lt;/script&gt;
&lt;h3&gt;Azure DSC Pull Server&lt;/h3&gt;
&lt;p&gt;Now let&#39;s deploy this to some servers to build our web farm using &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/automation/automation-dsc-overview&quot;&gt;Azure Automation DSC&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you don&#39;t already have an Azure Automation account they are easy to create and by far the easiest way to setup a DSC pull server. But if paying for a pull server isn&#39;t your speed checkout the OSS project &lt;a href=&quot;https://github.com/PowerShellOrg/tug&quot;&gt;Tug&lt;/a&gt; or try &lt;a href=&quot;https://msdn.microsoft.com/en-us/powershell/dsc/pullserver&quot;&gt;standing up your own&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/iis-admin-rest-api-with-dsc/azureautomation.png&quot; alt=&quot;Azure Automation&quot; /&gt;&lt;/p&gt;
&lt;p&gt;All you need to do now is install the modules you need in your DSC environment, upload your completed configuration, and compile! In our case we need the &lt;code&gt;xNetworking&lt;/code&gt; and the &lt;code&gt;xPSDesiredStateConfiguration&lt;/code&gt; modules.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/iis-admin-rest-api-with-dsc/modules.png&quot; alt=&quot;Azure Automation&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/iis-admin-rest-api-with-dsc/compilingconfig.png&quot; alt=&quot;Azure Automation&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Deploying to Azure VMs&lt;/h3&gt;
&lt;p&gt;Here I show the UI way to enroll, but if automation is your goal the Azure RM PowerShell SDK has a cmdlet for enrolling VM&#39;s automagically &lt;a href=&quot;https://docs.microsoft.com/en-us/powershell/module/azurerm.automation/register-azurermautomationdscnode?view=azurermps-4.1.0&quot;&gt;&lt;code&gt;Register-AzureRmAutomationDscNode&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/iis-admin-rest-api-with-dsc/addnode.png&quot; alt=&quot;Enroll server&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/iis-admin-rest-api-with-dsc/addvm.png&quot; alt=&quot;Enroll server&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/iis-admin-rest-api-with-dsc/setconfig.png&quot; alt=&quot;Enroll server&quot; /&gt;&lt;/p&gt;
&lt;p&gt;You can test it manually by running &lt;code&gt;Update-DscConfiguration -Wait -Verbose&lt;/code&gt; this is helpful when spotting any potential errors in your DSC. If there is already a configuration running you can stop it with &lt;code&gt;Stop-DscConfiguration -Force&lt;/code&gt; and start it on demand with &lt;code&gt;Start-DscConfiguration –UseExisting –Verbose –Wait&lt;/code&gt;. In production it may be useful to checkout the &lt;a href=&quot;https://blogs.msdn.microsoft.com/powershell/2014/01/03/using-event-logs-to-diagnose-errors-in-desired-state-configuration/&quot;&gt;event log&lt;/a&gt; if you need to debug configuration errors.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/iis-admin-rest-api-with-dsc/applyingconfig.png&quot; alt=&quot;apply dsc config&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Final product&lt;/h3&gt;
&lt;p&gt;And voila, you can login to the admin api with your admin credentials and generate an API token to do work (don&#39;t worry this IP is long gone 😎). You can get a single pane of glass view of your VMs using this REST Api with the Microsoft tool https://manage.iis.net/&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/iis-admin-rest-api-with-dsc/adminprompt.png&quot; alt=&quot;admin login&quot; /&gt;
&lt;img src=&quot;https://erikonarheim.com/images/iis-admin-rest-api-with-dsc/adminscreen.png&quot; alt=&quot;admin screen&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Manage your cloud web farm with REST Apis!!!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/iis-admin-rest-api-with-dsc/adminapi.png&quot; alt=&quot;admin login&quot; /&gt;&lt;/p&gt;
&lt;p&gt;So cool!&lt;/p&gt;
</content>
  </item>
  
  <item>
    <title>Building Custom Analytics with Azure Functions</title>
    <link>https://erikonarheim.com/posts/custom-analytics-azure-functions/</link>
    <description>Erik Onarheim</description>
    <guid>https://erikonarheim.com/posts/custom-analytics-azure-functions/</guid>
    <pubDate>Thu, 27 Apr 2017 00:00:00 +0000</pubDate>
    <content type="html" >&lt;p&gt;Recently we did a &lt;a href=&quot;https://excaliburjs.com/ludum-38/&quot;&gt;game jam&lt;/a&gt; for Ludum Dare 38, and we were not satisfied with the level of customization in analytics providers out there, so we decided to build our own with &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/azure-functions/functions-create-first-azure-function&quot;&gt;Azure Functions&lt;/a&gt; with &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/storage/storage-dotnet-how-to-use-tables&quot;&gt;Azure Table Storage&lt;/a&gt; as a semi-unstructured data store. We were up and running quickly and the process was fairly easy.&lt;/p&gt;
&lt;h2&gt;Setting up the function&lt;/h2&gt;
&lt;p&gt;For pennies on the dollar, you can setup Azure functions easily on in an azure account (currently forcasted to spend ~20 cents this billing period!). All that&#39;s required is an existing Azure account, which can be created &lt;a href=&quot;https://portal.azure.com/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Next navigate to the new plus icon in the top left of your screen, search for function, and click the item labeled &lt;strong&gt;Function App&lt;/strong&gt; published by Microsoft. After clickig create you&#39;ll have a few options. You&#39;ll notice that azure fuctions live inside of the &lt;code&gt;*.azurewebsites.net&lt;/code&gt; subdomain, this is because technically they live in the Azure web apps ecosystem.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/custom-analytics-azure-functions/azure-dashboard.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;You&#39;ll need to pick a name, location (I recommend a place near-ish where people will be calling the function), hosting plan, and a storage account.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/custom-analytics-azure-functions/azure-function-create.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Writing a function&lt;/h2&gt;
&lt;p&gt;In this example I&#39;m using the Node.js support in Azure functions to write a function. It is pretty easy to test and setup output to Azure table storage. It can even be wired up with source control so that code checked into github or another source code hosting provider is automatically deployed (Under &lt;strong&gt;Platform Features&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Deployment Options&lt;/strong&gt;).&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; uuid &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;node-uuid&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;module&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;exports&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;context&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; req&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;JavaScript HTTP trigger function processed a request.&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;req&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;body &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; req&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;started&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// Add the required properties for Azure Table Storage&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; payload &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token comment&quot;&gt;// Records in a single partition are fast to retrieve together, since I don&#39;t really have many records I used this scheme to force a convenient sorting in Storage Explorer, probably not ideal for a production scenario.&lt;/span&gt;&lt;br /&gt;            PartitionKey&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Number&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;MAX_SAFE_INTEGER&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; Date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token comment&quot;&gt;// RowKey is the unique identifier in a partition, using GUIDs to solve this.&lt;/span&gt;&lt;br /&gt;            RowKey&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; uuid&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;v4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// Since table storage is NoSQL-ish you can drop whatever columns you want into it dynamically&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; prop &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; req&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token comment&quot;&gt;// exclude private _ members&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;prop&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;_&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                payload&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;prop&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;req&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;body&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;prop&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// These bindings need to be added to the contex and are magically added &lt;/span&gt;&lt;br /&gt;        context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bindings&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ludum38data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;        context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bindings&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ludum38data&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// Return value to echo back data stored&lt;/span&gt;&lt;br /&gt;        context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;res &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token comment&quot;&gt;// Store analytics payload in table storage&lt;/span&gt;&lt;br /&gt;            &lt;br /&gt;            body&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Stored analytics: &quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;res &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            status&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;400&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;            body&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Please pass a valid analytics body&quot;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The one &lt;strong&gt;hiccup&lt;/strong&gt; is that in order to use node modules like &lt;code&gt;node-uuid&lt;/code&gt; you need to navigate to your functions scm (Kudu) site, create a &lt;code&gt;package.json&lt;/code&gt; file, and run &lt;code&gt;npm install&lt;/code&gt; manually. This can be found in the function&#39;s &lt;strong&gt;Platform features&lt;/strong&gt; tab labeled &lt;strong&gt;Advanced tools (Kudu)&lt;/strong&gt; or if you go to &lt;code&gt;&amp;lt;nameofyourapp&amp;gt;.scm.azurewebsites.net&lt;/code&gt;. Navigate to the directory containing the &lt;code&gt;package.json&lt;/code&gt; and run &lt;code&gt;npm install&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code class=&quot;language-json&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;ludum38stats&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token property&quot;&gt;&quot;dependencies&quot;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token property&quot;&gt;&quot;node-uuid&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;~1.4.8&quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/custom-analytics-azure-functions/scmnpm.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Integrating with Azure Table Storage&lt;/h2&gt;
&lt;p&gt;Remember that storage account we created when we set up the Azure function? We&#39;ll use that to store our semi-unstructured data from analytics.&lt;/p&gt;
&lt;p&gt;In the &lt;strong&gt;Integrate&lt;/strong&gt; section of your specific function you can attack different data outputs to your function. In this case we want to persist it to Azure table storge.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/custom-analytics-azure-functions/function-tree.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Once we select the &lt;strong&gt;Azure Table Storage&lt;/strong&gt; preset in the &#39;New Output&#39; wizard, it is pretty easy to add things to it.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/custom-analytics-azure-functions/output-data.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/custom-analytics-azure-functions/ouput-data-connection.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;In your function you&#39;ll need to reference the &lt;code&gt;outputTable&lt;/code&gt; that you&#39;ve created in order to store things. Unfortunately it is a little unintuitive but you&#39;ll need to create your own array off of the &lt;code&gt;Azure function context&lt;/code&gt; to submit your values.&lt;/p&gt;
&lt;p&gt;So this would be an example of using the table parameter name above:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; payload &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    PartitionKey&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Number&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;MAX_SAFE_INTEGER&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; Date&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;    RowKey&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; uuid&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;v4&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;...&lt;/span&gt;&lt;br /&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bindings&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;outputTable &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;bindings&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;outputTable&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In order to insert into Azure table storage there are 2 required properites &lt;code&gt;PartitionKey&lt;/code&gt; and &lt;code&gt;RowKey&lt;/code&gt;. &lt;code&gt;PartitionKey&lt;/code&gt; allows you to partition data to enhance data clustering, things with the same &lt;code&gt;PartitionKey&lt;/code&gt; can be queried more quickly. &lt;code&gt;RowKey&lt;/code&gt; is meant to be the unique itentifier for a row witin a partition. The rest of the properties are up to you, there are some limitations to be aware of, but they are pretty generous.&lt;/p&gt;
&lt;p&gt;To test if things are working, Azure has a convenient test window to send fiddler like requests to your function.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/custom-analytics-azure-functions/function-test.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Once you&#39;ve pushed data into Azure Table Storage there is a convenient cross platform client from Microsoft to view the data located at http://storageexplorer.com/&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/custom-analytics-azure-functions/storage-explorer.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;CORS (Cross-Origin Resource Sharing) in Azure Functions&lt;/h2&gt;
&lt;p&gt;This setting is a pretty well hidden, but if you click on the &lt;strong&gt;Platform Features&lt;/strong&gt; tab inside of the Azure function you&#39;ll find &lt;code&gt;CORS&lt;/code&gt; under the &lt;code&gt;API&lt;/code&gt; heading. Enter your domains to whitelist, &lt;strong&gt;IF YOU WANT TO ALLOW ALL&lt;/strong&gt; you&#39;ll need to delete all entries and put a &lt;code&gt;*&lt;/code&gt;, this does mean that &lt;strong&gt;ANYONE IN THE WORLD&lt;/strong&gt; can call your function from any web page. Generally speaking this is a bad idea, but for our game analytics for LD38 it doesn&#39;t really matter.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/custom-analytics-azure-functions/cors.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;With CORs implemented all we needed to do on to build our custom client-side logger was the following. &lt;code&gt;Config.analyticsEndpoint&lt;/code&gt; is just the obscured function url that can be accessed in Azure with a click of the &lt;strong&gt;Get function URL&lt;/strong&gt; button.&lt;/p&gt;
&lt;pre class=&quot;language-typescript&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;IPosition&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;   x&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;   y&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;interface&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;IPayload&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;   date&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// date&lt;/span&gt;&lt;br /&gt;   commit&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;   seed&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// seeded value&lt;/span&gt;&lt;br /&gt;   started&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// time&lt;/span&gt;&lt;br /&gt;   timePlayed&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// amount of time played&lt;/span&gt;&lt;br /&gt;   won&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;boolean&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// won or lost&lt;/span&gt;&lt;br /&gt;   enemiesOnScreen&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;br /&gt;   foodCollected&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token builtin&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;   playerPositions&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; IPosition&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;br /&gt;   enemyPositions&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; IPosition&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Analytics&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;   &lt;span class=&quot;token keyword&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;publish&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;payload&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; IPayload&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetch&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Config&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;analyticsEndpoint&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;         method&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;POST&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;         headers&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token string&quot;&gt;&#39;Content-Type&#39;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;application/json&#39;&lt;/span&gt;&lt;br /&gt;         &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;         body&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;payload&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;   &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;   &lt;br /&gt;   &lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Putting it all together&lt;/h2&gt;
&lt;p&gt;Once that was complete we were able to build a heat map for player analytics for our game to see where people go in order to help better design the game.&lt;/p&gt;
&lt;p&gt;Check out the cool heat map with our custom data (pun intended) 😎&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/custom-analytics-azure-functions/heat-map.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
</content>
  </item>
  
  <item>
    <title>Building a Sprite Editor for the NES</title>
    <link>https://erikonarheim.com/posts/nes-sprite-editor/</link>
    <description>Erik Onarheim</description>
    <guid>https://erikonarheim.com/posts/nes-sprite-editor/</guid>
    <pubDate>Sun, 26 Mar 2017 00:00:00 +0000</pubDate>
    <content type="html" >&lt;p&gt;I &lt;a href=&quot;https://www.youtube.com/watch?v=mnUXYl5B9Qs&quot;&gt;did a talk&lt;/a&gt; about building nintendo games using the &lt;a href=&quot;http://www.nespowerpak.com/nesasm/&quot;&gt;NESASM3&lt;/a&gt; assembler. For this talk I wanted to be able to build my own sprites rather than use existing game rom files. The unfortunate thing was I couldn&#39;t find any in-depth documentation online about how sprites worked on the Nintendo, other than they are 8x8 pixels large, take up 16-bytes, and can only define 4 possible colors (1 of which needs to be the background).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/nes-sprite-editor/playersprite.png&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;https://erikonarheim.com/images/nes-sprite-editor/colorpalette.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;This lead me down a path to reverse engineer the byte format of NES sprites using the emulator &lt;a href=&quot;http://www.fceux.com/web/version.html&quot;&gt;FCEUX&lt;/a&gt; and then build a &lt;a href=&quot;https://eonarheim.github.io/NES-Sprite-Editor/&quot;&gt;simple editor&lt;/a&gt; that could produce sprite files format for my game. Check it out, the source is up on &lt;a href=&quot;https://github.com/eonarheim/NES-Sprite-Editor&quot;&gt;github!&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/nes-sprite-editor/simplespriteeditor.PNG&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;NES Sprite Format&lt;/h3&gt;
&lt;p&gt;Originally, I thought that each sequential 2-bit chuck of the 16-bytes allocated per sprite encoded the color 1-4 of the sprite. Since 2-bits can represent all four possible colors (00, 01, 10, and 10), seems pretty reasonable right? Wrong!&lt;/p&gt;
&lt;p&gt;Actually the format is much trickier than that, still not 100% sure why Nintendo did things this way, but I can only guess that there is a performance reason behind it.&lt;/p&gt;
&lt;p&gt;Sprites are definited by &lt;code&gt;byte n&lt;/code&gt; and &lt;code&gt;byte n+8&lt;/code&gt; to control the color of the first row of pixels in the 8x8 sprite. This means that the 1st byte and the 9th byte control the first row of pixels, and the 8th byte and the 16th byte control the last row of pixels for a sprite. The layout in memory to the corresponding 8x8 pixel looks like this:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/nes-sprite-editor/nesspritescheme.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Think about these two pairs of bytes (&lt;code&gt;byte n&lt;/code&gt; and &lt;code&gt;byte n+8&lt;/code&gt;) as separate channels, where the second channel&#39;s binary digits are weighted by 2 and the resulting color is the sum of channel 1 and channel 2 together. For example look at the sprite in the top left corner and the calculation of its colors.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/nes-sprite-editor/playersprite.png&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;https://erikonarheim.com/images/nes-sprite-editor/colorpalette.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/nes-sprite-editor/nesbyteexample.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Reverse engineering the format&lt;/h3&gt;
&lt;p&gt;Using FCEUX&#39;s PPU Viewer and PPU memory viewing feature I was able to reverse engineer the format by poking at bytes individually. It took a while to discover the scheme above, but this is roughly the trial and error process I followed to determine the colors of each pixel.&lt;/p&gt;
&lt;p&gt;Each row of the the FCEUX hex editor is 16 bytes wide by default, which makes it convenient for testing out sprite behavior since we already know that 16 bytes are allocated per sprite. Each byte in the editor is represented by 2 hexidecimal digits where are grouped together for easy reading.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/nes-sprite-editor/hexeditor.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;First, by setting the first byte to all 1&#39;s (hexidecimal FF) the first color in the palette was selected for the first row of the first sprite.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/nes-sprite-editor/hexfirstones.png&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;https://erikonarheim.com/images/nes-sprite-editor/firstrowgreen.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Next, filling out the next 7 bytes with 1&#39;s produces a solid 8x8 block. This produces color 1 in the palette.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/nes-sprite-editor/16byteones.png&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;https://erikonarheim.com/images/nes-sprite-editor/spritegreen.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;On the 9th byte, we can change the top left pixel by entering a byte that has these binary digits &lt;code&gt;10000000&lt;/code&gt; which is &lt;code&gt;80&lt;/code&gt; in hexidecimal. This produces color 3 in the palette.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/nes-sprite-editor/9thbyteone.png&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;https://erikonarheim.com/images/nes-sprite-editor/9thbytesprite.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;To produce color 2 we need to set the corresponding bit in the channel 1 byte to 0.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/nes-sprite-editor/firstbytezero.png&quot; alt=&quot;&quot; /&gt;
&lt;img src=&quot;https://erikonarheim.com/images/nes-sprite-editor/firstbytesprite.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Reading binary files in JavaScript&lt;/h3&gt;
&lt;p&gt;Now that we know byte format for each sprite&#39;s pixel, we can build a simple web app to help edit and make binary NES sprite files. The app I built isn&#39;t the most beautiful app ever, but it got the job done. Hopefully I&#39;ll be able to update it in the future and adding common image editing features like flood fill, selections, layers, etc.&lt;/p&gt;
&lt;p&gt;To deal with binary data, JavaScript has a useful type called the &lt;code&gt;ArrayBuffer&lt;/code&gt;. With this type we can load up bytes directly from a source files using the &lt;code&gt;XHR&lt;/code&gt; method and the &lt;code&gt;FileReader&lt;/code&gt; method.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/// Upload utilities&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;readBlob&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; files &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;nesfile&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;files&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;files&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token function&quot;&gt;alert&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;Please select a file!&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; file &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; files&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; start &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; stop &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; file&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;size &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; reader &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;FileReader&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// If we use onloadend, we need to check the readyState.&lt;/span&gt;&lt;br /&gt;    reader&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;onloadend&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;evt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;evt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;readyState &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; FileReader&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;DONE&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// DONE == 2&lt;/span&gt;&lt;br /&gt;            spriteRomData &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Uint8Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;evt&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;target&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;result&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token function&quot;&gt;NEStoCanvas&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;spriteRomData&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; blob &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; file&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;slice&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;start&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; stop &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    reader&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;readAsArrayBuffer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;blob&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;/// Load up default sprite sheet&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; xhr &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;XMLHttpRequest&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;xhr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;GET&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;main.chr&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;xhr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;responseType &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;arraybuffer&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;xhr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;load&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;evt&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    spriteRomData &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Uint8Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;xhr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;response&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;NEStoCanvas&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;spriteRomData&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;xhr&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In order to see the native NES sprite files, we need to output it to an HTML5 canvas. The idea is to hop through the binary file 16 bytes (1 sprite) at a time and calculate the 8x8 pixels to place on the canvas. The &lt;code&gt;putPixel&lt;/code&gt; method handled the mapping for the current palette from color b, 1, 2, 3 to the appropriate RGB.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;NEStoCanvas&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;byteArray&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; xpos &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; ypos &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// every sprite is 16 bytes&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// 1 byte is 8 pixels &lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// byte n and byte n+8 control the color of that pixel&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;//  (0,0) background&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;//  (1,0) color 1&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;//  (0,1) color 2&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;//  (1,1) color 3&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; b &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; b &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; byteArray&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; b&lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        ypos &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;floor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;b&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;height&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// draw sprite&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; j &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; j &lt;span class=&quot;token operator&quot;&gt;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; j&lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; mask &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; channel1 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; byteArray&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;b &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; channel2 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; byteArray&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;b &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; color &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;channel1 &lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&gt;&lt;/span&gt; j&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt; mask&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;channel2 &lt;span class=&quot;token operator&quot;&gt;&gt;&gt;&gt;&lt;/span&gt; j&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&lt;/span&gt; mask&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;span class=&quot;token function&quot;&gt;putPixel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;xpos &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; j&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ypos &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; i&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; palette&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; mapping&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;color&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; imageData&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;            &lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;        &lt;br /&gt;        xpos &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;xpos &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; width&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;    &lt;span class=&quot;token function&quot;&gt;paintCanvas&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;paintCanvas&lt;/code&gt; method is pretty simple, it uses the &lt;code&gt;putImageData&lt;/code&gt; &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/putImageData&quot;&gt;api&lt;/a&gt; to write color bytes directly to the canvas context.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;// On-screen canvas set to be scaled&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; canvas &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;editor&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; ctx &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getContext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;2d&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;imageSmoothingEnabled &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; scale &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; width &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;128&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; height &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;256&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; width &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; scale&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; height &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; scale&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Off-screen sprite canvas&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; spriteCanvas &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;canvas&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;spriteCanvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; width&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;spriteCanvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; height&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; spriteCtx &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; spriteCanvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getContext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;2d&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;spriteCtx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;imageSmoothingEnabled &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// On-screen image data&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; imageData &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getImageData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; spriteCanvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; spriteCanvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; data &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; imageData&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;data&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;paintCanvas&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    spriteCtx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;putImageData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;imageData&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;drawImage&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;spriteCanvas&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; width &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; scale&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; height &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; scale&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;showGridLines&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token function&quot;&gt;drawSpriteBorderGridLines&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Outputing the proper format&lt;/h3&gt;
&lt;p&gt;Outputting to the binary format was a little trickier. Since I know the correct bit tuples to output in the channel 1 and channel 2 bytes, I decided to do a first pass to convert RGB values of the canvas element to the appropriate tuple (00, 01, 10, 11) using &lt;code&gt;rgbColorTopaletteTuple&lt;/code&gt; for writing back to a binary NES file. The second pass does a pretty complicated loop to fill in a new byteArray with the appropriate values.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;canvasToNES&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;imageData&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// 16 byte wide sprite with 512 sprites&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; byteArray &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Uint8Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;512&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// tuple buffer&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; tupleBuffer &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;imageData&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; imageData&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; y &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; y &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; imageData&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; y&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; x &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; x &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; imageData&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; x&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;        &lt;br /&gt;            &lt;span class=&quot;token comment&quot;&gt;// extract which color it is from imageData&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; color &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getPixel&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;x&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; y&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; imageData&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;token comment&quot;&gt;// find the pallet color&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; palletTuple &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;rgbColorTopaletteTuple&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;color&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; palette&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;token comment&quot;&gt;// write it to the tupleBuffer&lt;/span&gt;&lt;br /&gt;            tupleBuffer&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;x &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; imageData&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; y&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; palletTuple&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;    &lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// tuple buffer has imageData.width * imageData.heigh pixels, so divide that by 16 for sprites&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; xtotal &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; ytotal &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; byteArray&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        ytotal &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;floor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;height&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;&lt;br /&gt;        &lt;br /&gt;        &lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; y &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; ytotal&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; y &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ytotal &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; y&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token comment&quot;&gt;// do each row channel&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; byteChannel1 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; byteChannel2 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0x00&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;            &lt;span class=&quot;token comment&quot;&gt;// complete row calculation&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; x &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; xtotal&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; x &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;xtotal &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; x&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; tup &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; tupleBuffer&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;x &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; y &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; imageData&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;                byteChannel1 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;byteChannel1 &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; tup&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;                byteChannel2 &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;byteChannel2 &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;|&lt;/span&gt; tup&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token comment&quot;&gt;// write calc&#39;d row channels to appropriate byte locations&lt;/span&gt;&lt;br /&gt;            byteArray&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; byteChannel1&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;            byteArray&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; byteChannel2&lt;br /&gt;            i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        xtotal &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;xtotal &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt; width&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; byteArray&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The binary content can be downloaded with the neat little trick by dynamically creating an anchor tag and manufacturing a click event to trigger a download (which seems a little spooky 👻, feels like a way to engineer a drive-by-download type attack 😨).&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;/// Download utilities&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;download&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;filename&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; byteArray&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; type&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;// convert to a blob&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; blob &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Blob&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;byteArray&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;type&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; type&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;octect/stream&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; url &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;URL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createObjectURL&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;blob&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; url &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; byteArray&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; pom &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;a&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    pom&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;href&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; url&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    pom&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;setAttribute&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;download&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; filename&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;createEvent&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; event &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;MouseEvents&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;initEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;click&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        pom&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;dispatchEvent&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        pom&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Putting it together&lt;/h3&gt;
&lt;p&gt;Once the binary file is downloaded, it can be included in NESASM3 with the &lt;code&gt;.incbin&lt;/code&gt; directive. Check out the full source of my NES game &lt;a href=&quot;https://github.com/eonarheim/nesgame&quot;&gt;here&lt;/a&gt;. I&#39;ll have a post coming soon about more in-depth NES programming until then please watch my &lt;a href=&quot;https://www.youtube.com/watch?v=mnUXYl5B9Qs&quot;&gt;talk&lt;/a&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-asm6502&quot;&gt;&lt;code class=&quot;language-asm6502&quot;&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;;;;;;;;;;;;;;;  &lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;; Load in external sprite or audio data&lt;/span&gt;&lt;br /&gt;  &lt;br /&gt;  &lt;span class=&quot;token directive keyword&quot;&gt;.bank&lt;/span&gt; &lt;span class=&quot;token decimalnumber string&quot;&gt;2&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token directive keyword&quot;&gt;.org&lt;/span&gt; &lt;span class=&quot;token hexnumber string&quot;&gt;$0000&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token directive keyword&quot;&gt;.incbin&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;art.chr&quot;&lt;/span&gt;   &lt;span class=&quot;token comment&quot;&gt;;includes 8KB graphics file&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And voila! We have our own sprites for our brand new Nintendo game.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/nes-sprite-editor/nesgame.gif&quot; alt=&quot;nesgame&quot; /&gt;&lt;/p&gt;
</content>
  </item>
  
  <item>
    <title>Repairing an old broken NES</title>
    <link>https://erikonarheim.com/posts/repairing-an-old-nes/</link>
    <description>Erik Onarheim</description>
    <guid>https://erikonarheim.com/posts/repairing-an-old-nes/</guid>
    <pubDate>Sun, 26 Feb 2017 00:00:00 +0000</pubDate>
    <content type="html" >&lt;p&gt;I recently acquired an original Nintendo Entertainment System for an upcoming talk where I show how to develop real NES games in 6502. There was only one problem, the NES was not working and flashing the infamous &amp;quot;Red Blink of Death.&amp;quot; In this post I&#39;ll walk through the steps I used to restore and repair my NES.&lt;/p&gt;
&lt;h3&gt;Spelunking inside the NES&lt;/h3&gt;
&lt;p&gt;First I wanted to see what was wrong, so I opened up the NES for visual inspection to check for any obvious problems. The original NES is surprisingly easy to take apart with a standard Philips head screwdriver (compared to later Nintendo devices with bizarre screws that no one has the wrench for). There are only 6 screws to undo and the top of the Nintendo will come right off.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/repairing-an-old-nes/buttomnes.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I wonder if they&#39;ll still help me... 😉&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/repairing-an-old-nes/newwarrantee.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Looking inside you&#39;ll see the RF shielding which is fairly easy to remove, it&#39;s just held on with a couple screws.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/repairing-an-old-nes/rfsheilding.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I just went through all the other parts and unscrewed everything. Once I did that, you can pull the loader mechanism off fairly easy. The loader mount has the only special long screws in the NES, the rest are interchangeable, remember where they go.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/repairing-an-old-nes/loadermechanismgone.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The top side of the PCB board looks pretty good, there is some slight visible corrosion on some of the PPU and CPU pins. For the most part the traces look okay on this side, no burns, no dead capacitors, etc.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/repairing-an-old-nes/nespcb.png&quot; alt=&quot;nes pcb&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The bottom of the PCB (which faces towards to top of the console when it&#39;s mounted) is a different story. It looks like there was some sort of liquid spilled into the console, possibly soda, or juice. It looks like it also caused some corrosion as well.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/repairing-an-old-nes/bottompcb.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;After this discovery, I spent around an hour our so with isopropyl alcohol ~90% (don&#39;t worry it&#39;s perfectly safe for electronics) and some Q-tips cleaning up the sticky residue on the bottom of the PCB. I went through a lot of Q-tips to get this clean. One downside of this is that the Q-tips began to leave cotton fuzz everywhere that I needed to pull off later, I don&#39;t think cotton on the PCB is good for the NES 😉&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/repairing-an-old-nes/qtipswabs.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;While I was at it I also cleaned up the PCB 72-pin connector contact as well&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/repairing-an-old-nes/72pincontact.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;TA-DA! A much cleaner PCB, you&#39;ll want to let this dry for a bit. (Photo was taken the next day, marked improvement from before)&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/repairing-an-old-nes/cleanpcb.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;But after all that cleaning, things still didn&#39;t work 😭&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/repairing-an-old-nes/nesblinkofdeath.gif&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Enter the 72-pin connector&lt;/h3&gt;
&lt;p&gt;Another common thing that can wear out over time is the 72-pin connector that connects the game cartridge to the NES PCB, so I decided to see if I couldn&#39;t clean/repair that. There are a lot of people that have had success fixing the &amp;quot;Red Blink of Death&amp;quot; buy cleaning the contacts of corrosion either by rubbing the pins with a cleaner like isopropyl alcohol, or by using the &lt;a href=&quot;https://www.youtube.com/watch?v=HrrRSAr1rVs&quot;&gt;boiling method&lt;/a&gt;. However, I didn&#39;t have a cooking pot I wanted to sacrifice to mad science, so I went with the &lt;a href=&quot;https://www.youtube.com/watch?v=1AHJGJhCLs8&quot;&gt;pin bending&lt;/a&gt; method instead. (I prefer my food not taste like 35 year old electronics! Ack!)&lt;/p&gt;
&lt;p&gt;I cleaned the connections as best I could with rubbing alcohol but that had no effect. There is some definite corrosion on the pins highlighted that doesn&#39;t show up in the photo. It is difficult to clean this small space, and if I had a science pot I&#39;d be boiling it for 30 minutes.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/repairing-an-old-nes/72pingconnector.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Let the bending of the pins commence! I used a safety pin and an overhead desk lamp to bend the pins up slightly, this will have the side effect of making the cartridge harder to insert into the mechanism but hopefully that means better contact.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/repairing-an-old-nes/safetypin.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Here you can see the first 6 pins bent upwards, I proceeded to bend the rest of the pins and remounted everything in the NES.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/repairing-an-old-nes/pinsbent.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;At this point I had assembled and disassembled the NES like 6 times, so I just put things together without screws to see if things worked... and booyah!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/repairing-an-old-nes/loadednes.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/repairing-an-old-nes/nesscreen.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Wrapping it up&lt;/h3&gt;
&lt;p&gt;After all this work, the NES still has about a 50% success rate of booting the cartridge. This is much better than the 0% success rate before I started. You can make it load better doing the &amp;quot;wiggle trick.&amp;quot; While the cart is loaded in the NES, wiggle the top of it and repeatedly hit reset until the game boots. I suspect even with the bent pins on the 72-pin connector the corrosion is significant enough to prevent good contact. (If there isn&#39;t good contact to the lock-out chip the NES will do the &amp;quot;red blink of death&amp;quot; thinking it&#39;s a non-licensed Nintendo cart).&lt;/p&gt;
&lt;p&gt;Since I don&#39;t want to try boiling electronics in my cookware, I purchased a &lt;a href=&quot;https://www.amazon.com/gp/product/B00EUT0BQU&quot;&gt;replacement 72-pin connector on Amazon&lt;/a&gt; for $10 which I thought was reasonable. Hopefully, this will increase the success rate to 100% of the time it works 100% of the time 😎 I&#39;ll post an update to this as soon as I receive the part.&lt;/p&gt;
&lt;h4&gt;Update&lt;/h4&gt;
&lt;p&gt;After installing the replacement connector everything works 100% of the time! The replacement connector grabs more tightly, so it does take a little effort to push carts into the NES. If anyone tries the boiling method let me know!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/repairing-an-old-nes/castlevania.png&quot; alt=&quot;castlevania&quot; /&gt;&lt;/p&gt;
&lt;p&gt;-Erik&lt;/p&gt;
</content>
  </item>
  
  <item>
    <title>Migrating to Wyam in GH Pages from WordPress</title>
    <link>https://erikonarheim.com/posts/using-wyam-blog/</link>
    <description>Erik Onarheim</description>
    <guid>https://erikonarheim.com/posts/using-wyam-blog/</guid>
    <pubDate>Fri, 17 Feb 2017 00:00:00 +0000</pubDate>
    <content type="html" >&lt;p&gt;Recently I needed to update my blog WordPress version (yet again), along with patch my server, update my HTTPS certificate, and pay my hosting bill. The amount of admin-istrivia around maintaining your own server and application platform is more than I want to do for a blog going forward. This got me thinking there must be a better way to do this. My friends, &lt;a href=&quot;https://twitter.com/kamranayub&quot;&gt;@kamranayub&lt;/a&gt; in particular, have been pushing me to do more blogging and to move to static site generation. So here goes!&lt;/p&gt;
&lt;p&gt;(BTW, this setup is saving me $400 per year on hosting costs!)&lt;/p&gt;
&lt;h2&gt;Intro Wyam&lt;/h2&gt;
&lt;p&gt;This leads me to the Wyam static site generator. It is a great little static site generator built in C#/.NET (full framework). If you come from a Markdown/Razor background you&#39;ll really find this stuff familiar and easy to use. Wyam is super configurable, fully customizable, and compatible with GitHub pages. Let&#39;s dig into it!&lt;/p&gt;
&lt;h2&gt;Installing Wyam&lt;/h2&gt;
&lt;p&gt;Installing Wyam is pretty easy, navigate &lt;a href=&quot;https://wyam.io/docs/usage/obtaining&quot;&gt;here&lt;/a&gt; and follow one of the many ways to install. I used the Windows installer, unfortunately it does not automatically add itself to the path. Fortunately, it is easy to do with the following command once installed:&lt;/p&gt;
&lt;pre class=&quot;language-powershell&quot;&gt;&lt;code class=&quot;language-powershell&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt;LocalAppData&lt;span class=&quot;token operator&quot;&gt;%&lt;/span&gt;\Wyam\Wyam&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Windows &lt;span class=&quot;token function&quot;&gt;add-path&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In a new command window you can confirm wyam is in your path:&lt;/p&gt;
&lt;pre class=&quot;language-powershell&quot;&gt;&lt;code class=&quot;language-powershell&quot;&gt;wyam &lt;span class=&quot;token operator&quot;&gt;--&lt;/span&gt;help&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Building your blog in Wyam&lt;/h2&gt;
&lt;p&gt;Check out the &lt;a href=&quot;https://wyam.io/recipes/blog/overview&quot;&gt;blog recipe&lt;/a&gt; on wyam&#39;s site, but honestly it is as easy as running:&lt;/p&gt;
&lt;pre class=&quot;language-powershell&quot;&gt;&lt;code class=&quot;language-powershell&quot;&gt;mkdir blog&lt;br /&gt;cd blog&lt;br /&gt;wyam new &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt;r Blog&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;wyam new -r Blog&lt;/code&gt; will generate the blog scaffolding in the current directory.&lt;/p&gt;
&lt;p&gt;To build your static html files into the &lt;code&gt;output/&lt;/code&gt; directory, run &lt;code&gt;wyam -r Blog -t CleanBlog&lt;/code&gt;. This will build the Blog recipe with the CleanBlog theme. You may also just encode these parameters in your &lt;code&gt;config.wyam&lt;/code&gt; created at the root then you only need to run &lt;code&gt;wyam&lt;/code&gt; in the directory with the config file.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code class=&quot;language-csharp&quot;&gt;&lt;span class=&quot;token preprocessor property&quot;&gt;#recipe Blog&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token preprocessor property&quot;&gt;#n Wyam.Markdown&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token preprocessor property&quot;&gt;#t CleanBlog&lt;/span&gt;&lt;br /&gt;Settings&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;BlogKeys&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Title&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;Erik Onarheim&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Top level files in your input directory will show up in your nav bar, notice that they can be a mix of cshtml or markdown! So really some pages that need some more power can use Razor, others just Markdown.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://images/using-wyam-blog/nav.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://images/using-wyam-blog/nav-wyam.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Building a new blog post is as simple as dropping a new markdown file in your input/posts directory and adding the appropriate metadata to the file.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://images/using-wyam-blog/newpost.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;pre class=&quot;language-markdown&quot;&gt;&lt;code class=&quot;language-markdown&quot;&gt;&lt;br /&gt;Title: Migrating to Wyam in GH Pages from WordPress&lt;br /&gt;Published: 2/17/2017&lt;br /&gt;Tags: &lt;br /&gt; &lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Static Site&lt;br /&gt; &lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Wyam&lt;br /&gt; &lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Markdown&lt;br /&gt; &lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Razor&lt;br /&gt; &lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; WordPress&lt;br /&gt; &lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; GitHub Pages&lt;br /&gt;&lt;span class=&quot;token title important&quot;&gt;disqus_identifier: https://erikonarheim.com/posts/using-wyam-blog/&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;---&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Recently I needed to update my blog WordPress version (yet again)...&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The default theme is pretty slick, &lt;strong&gt;but if you ever want to tweak it&lt;/strong&gt;, it is as easy as dropping a new file with the same name as the theme. Below I&#39;ve added a custom &lt;code&gt;_Layout.cshtml&lt;/code&gt;, &lt;code&gt;_Footer.cshtml&lt;/code&gt;, and more that I copied from &lt;a href=&quot;https://github.com/Wyamio/Wyam/tree/develop/themes/Blog/CleanBlog&quot;&gt;Wyam&#39;s CleanBlog github&lt;/a&gt; and tweaked with my own google analytics and favicon. You&#39;ll also notice that you can mix and match Markdown with you Razor cshtml!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://images/using-wyam-blog/overridestheme.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Customizing Wyam with Disqus&lt;/h3&gt;
&lt;p&gt;Wyam comes with a bunch of built-in &lt;a href=&quot;https://wyam.io/recipes/blog/document-metadata&quot;&gt;document metadata&lt;/a&gt; which can be used to give the post a title, tags, published date. Custom metadata is also supported as well! Notice the &lt;code&gt;disqus_identifier&lt;/code&gt; metadata which I use to add comments into my posts. This particular tag is picked up by my  custom &lt;code&gt;_PostFooter.cshtml&lt;/code&gt; here, note the &lt;code&gt;@Model.String(&amp;quot;disqus_identifier&amp;quot;)&lt;/code&gt; the rest comes from disqus&#39;s embedding documentation.&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;div&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;disqus_thread&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;div&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;script&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;text/javascript&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token script&quot;&gt;&lt;span class=&quot;token language-javascript&quot;&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; disqus_shortname &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;erik-onarheim&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; disqus_identifier &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;@(Model.String(&quot;disqus_identifier&quot;) ?? Model.FilePath(Keys.RelativeFilePath).FileNameWithoutExtension.FullPath)&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; disqus_title &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;@Model.String(BlogKeys.Title)&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; disqus_url &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;@Context.GetLink(Model, true)&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class=&quot;token comment&quot;&gt;/* * * DON&#39;T EDIT BELOW THIS LINE * * */&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; dsq &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;script&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; dsq&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;text/javascript&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; dsq&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;async &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        dsq&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;src &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;//&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; disqus_shortname &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;.disqus.com/embed.js&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementsByTagName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;head&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementsByTagName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;body&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;dsq&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; s &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;script&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;async &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;type &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;text/javascript&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        s&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;src &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;//&#39;&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; disqus_shortname &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;.disqus.com/count.js&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementsByTagName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;HEAD&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementsByTagName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;BODY&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;appendChild&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;s&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;noscript&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Please enable JavaScript to view the &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;http://disqus.com/?ref_noscript&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;comments powered by Disqus.&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;noscript&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;http://disqus.com&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;dsq-brlink&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;comments powered by &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;span&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;logo-disqus&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Disqus&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;span&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It&#39;s pretty much that easy to make changes to the default template to make your own customizations!&lt;/p&gt;
&lt;h2&gt;Testing Wyam locally with IIS (or just use the easy way)&lt;/h2&gt;
&lt;p&gt;When I started working on this I tried a number of different of local servers to test this, TLDR: just use &lt;code&gt;wyam preview&lt;/code&gt; in the root directory of our blog (above the input folder).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://images/using-wyam-blog/wyam-preview2.png&quot; alt=&quot;preview&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;If you want to know the hard way&lt;/strong&gt; and see how to use IIS in a non-standard directory to run Wyam read on, &lt;strong&gt;otherwise skip to the next section :)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I keep a projects directory on my machine where I do most of my development on various projects. Unfortunately IIS does not have the permission to read into directories outside of &lt;code&gt;C:\inetpub\wwwroot&lt;/code&gt; by default which is a good default for servers. But if you want to test outside of your web root in your development space it is a problem. To fix this you&#39;ll need to set some file ACLs so that IIS can read your files. Give &lt;code&gt;IIS_IUSRS&lt;/code&gt; and &lt;code&gt;Users&lt;/code&gt; on the local machine Execute, List, and Read.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://images/using-wyam-blog/iis-perms.PNG&quot; alt=&quot;Folder ACLs&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Next you&#39;ll need to solve the problem of the extension-less &lt;code&gt;/posts/name-of-my-post&lt;/code&gt; file names that need to be served as if they contained an &lt;code&gt;index.html&lt;/code&gt; when they don&#39;t.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://images/using-wyam-blog/url-non-rewrite.PNG&quot; alt=&quot;extensionless&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Versus&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://images/using-wyam-blog/url-non-rewrite-html.PNG&quot; alt=&quot;extension&quot; /&gt;&lt;/p&gt;
&lt;p&gt;In order to fix this Wyam has some &lt;a href=&quot;https://wyam.io/docs/deployment/azure&quot;&gt;azure documentation&lt;/a&gt; referencing the rewrite module in azure. IIS does not come with this pre-installed so you&#39;ll need to &lt;a href=&quot;https://www.iis.net/downloads/microsoft/url-rewrite&quot;&gt;install the module&lt;/a&gt; located at the bottom of the page.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://images/using-wyam-blog/download-rewrite.PNG&quot; alt=&quot;rewrite-module&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Once that is complete you can drop in a &lt;code&gt;web.config&lt;/code&gt; in your &lt;code&gt;input&lt;/code&gt; directory with the rewrite rule referenced in the Wyam docs and voila!&lt;/p&gt;
&lt;pre class=&quot;language-xml&quot;&gt;&lt;code class=&quot;language-xml&quot;&gt;&lt;span class=&quot;token prolog&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot;?&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;configuration&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;system.webServer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;rewrite&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;rules&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;rule&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;html&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;match&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;(.*)&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;conditions&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;add&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;{REQUEST_FILENAME}&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;matchType&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;IsFile&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;negate&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;true&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;            &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;add&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;{REQUEST_FILENAME}&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;matchType&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;IsDirectory&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;negate&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;true&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;conditions&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;          &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;action&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Rewrite&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;{R:1}.html&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;rule&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;rules&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;rewrite&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;system.webServer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;configuration&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://images/using-wyam-blog/url-rewrite.PNG&quot; alt=&quot;rewrite&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Now you can run &lt;code&gt;wyam -w&lt;/code&gt; in your root blog directory and it will rebuilt the output when any input changes! The best part is this will be served by IIS that you&#39;ve just stood up.&lt;/p&gt;
&lt;h2&gt;Preserve you WordPress old links&lt;/h2&gt;
&lt;p&gt;If your blog has some good SEO juice, or maybe you just don&#39;t want to break older links, you&#39;ll want to preserve old links or at least redirect to your new ones. Here is how it is done&lt;/p&gt;
&lt;p&gt;Wyam handles these via the Meta-refresh tag on specific pages using the &lt;code&gt;RedirectFrom&lt;/code&gt; meta data like so&lt;/p&gt;
&lt;pre class=&quot;language-markdown&quot;&gt;&lt;code class=&quot;language-markdown&quot;&gt;Title: &quot;Game Development – A Year in Review 2014&quot;&lt;br /&gt;Published: 1/9/2015&lt;br /&gt;Tags:&lt;br /&gt;&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; News&lt;br /&gt;&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Game Dev&lt;br /&gt;&lt;span class=&quot;token list punctuation&quot;&gt;-&lt;/span&gt; Excalibur&lt;br /&gt;RedirectFrom: blog/game-development-a-year-in-review-2014/index.html&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Setting up automatic deployment with AppVeyor and GitHub Pages&lt;/h2&gt;
&lt;p&gt;AppVeyor is a super powerful CI/CD tool for Windows with free plans for open source. It&#39;s pretty much TravisCI for Windows. It&#39;s super easy to tie it to your GitHub account and add your repository for building.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://images/using-wyam-blog/appveyorlogin.PNG&quot; alt=&quot;appveyor&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Find your GH pages repo and turn it on.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://images/using-wyam-blog/appveyoradd.PNG&quot; alt=&quot;appveyorrepo&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I suggest only building on official pushes and not PR&#39;s because it is possible for anyone to craft a malicious PR to output secrets from appveyor. Also I recommend only building when &lt;code&gt;.appvyor.yml&lt;/code&gt; files are present to prevent gratuituous error emails in your inbox before repo is ready for prime time.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://images/using-wyam-blog/settings.PNG&quot; alt=&quot;appveyorsettings&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Wyam has a really nice &lt;code&gt;appveyor.yml&lt;/code&gt; file &lt;a href=&quot;https://wyam.io/docs/deployment/appveyor&quot;&gt;example&lt;/a&gt; to follow. One caveat is that GitHub pages for user pages must be built from the master branch.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://images/using-wyam-blog/must-be-built.PNG&quot; alt=&quot;master-only&quot; /&gt;&lt;/p&gt;
&lt;p&gt;In order to accomodate this I had to tweak the provied yaml file a little. AppVeyer will only build on my source&lt;/p&gt;
&lt;pre class=&quot;language-yml&quot;&gt;&lt;code class=&quot;language-yml&quot;&gt;&lt;span class=&quot;token key atrule&quot;&gt;branches&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token key atrule&quot;&gt;only&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; source&lt;br /&gt;    &lt;br /&gt;&lt;span class=&quot;token key atrule&quot;&gt;install&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; git submodule update &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;init &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;recursive&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; mkdir ..\Wyam&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; mkdir ..\output&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;# Fetch the latest version of Wyam &lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;curl -s https://raw.githubusercontent.com/Wyamio/Wyam/master/RELEASE -o ..\\Wyam\\wyamversion.txt&quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; set /P WYAMVERSION=&amp;lt; ..\Wyam\wyamversion.txt&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; echo %WYAMVERSION%&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;# Get and unzip the latest version of Wyam&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;ps&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Start&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;FileDownload &quot;https&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;//github.com/Wyamio/Wyam/releases/download/$env&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;WYAMVERSION/Wyam&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;$env&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;WYAMVERSION.zip&quot; &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;FileName &quot;..\Wyam\Wyam.zip&quot;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; 7z x ..\Wyam\Wyam.zip &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;o..\Wyam &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;r&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token key atrule&quot;&gt;build_script&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; ..\Wyam\wyam &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;output ..\output&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token key atrule&quot;&gt;on_success&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;# Switch branches to gh-pages, clean the folder, copy everything in from the Wyam output, and commit/push&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;# See http://www.appveyor.com/docs/how-to/git-push for more info&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; git config &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;global credential.helper store&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;# EDIT your Git email and name&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; git config &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;global user.email $env&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;op_build_user_email&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; git config &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;global user.name AppVeyor&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;token key atrule&quot;&gt;ps&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; Add&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;Content &quot;$env&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;USERPROFILE\.git&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;credentials&quot; &quot;https&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;//$($env&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;access_token)&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;x&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;oauth&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;basic@github.com`n&quot;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; git checkout master&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; git rm &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;rf .&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; xcopy ..\output . /E&lt;br /&gt;  &lt;span class=&quot;token comment&quot;&gt;# EDIT the origin of your repository - have to reset it here because AppVeyor pulls from SSH, but GitHub won&#39;t accept SSH pushes&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; git remote set&lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;url origin https&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;//github.com/eonarheim/eonarheim.github.io.git&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; git add &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;A&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; git commit &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;a &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt;m &quot;Commit from AppVeyor&quot;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;-&lt;/span&gt; git push&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Also you&#39;ll notice my &lt;code&gt;env:access_token&lt;/code&gt; this is setup in AppVeyor&#39;s encrypted environment variables.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://images/using-wyam-blog/accesstokenencryption.PNG&quot; alt=&quot;access_token&quot; /&gt;&lt;/p&gt;
&lt;p&gt;This can be generated by logging into GitHub, and generating a &amp;quot;Personal Access Token&amp;quot;, with &lt;code&gt;repo&lt;/code&gt; scope.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://images/using-wyam-blog/githubtokenscope.PNG&quot; alt=&quot;access token scope&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Now AppVeyor builds commits to my origin &lt;code&gt;source&lt;/code&gt; branch automagically! And Voila!
&lt;img src=&quot;https://images/using-wyam-blog/appveyorbuild.PNG&quot; alt=&quot;build&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Finished product!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://images/using-wyam-blog/blogcomplete.PNG&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Using CloudFlare CDN for HTTPS and Custom Domains&lt;/h2&gt;
&lt;p&gt;CloudFlare is super useful (and free) for setting up HTTPS for your GitHub pages, and for the free tier account it is very full featured. If you aren&#39;t too squeamish about surrendering your NS (name server) records, it is pretty simple.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Sign up for a free account on &lt;a href=&quot;https://www.cloudflare.com/&quot;&gt;cloudflare&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;CloudFlare can scan the DNS records in your site and let you know if there will be any problems migrating.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://images/using-wyam-blog/cloudflarescan.PNG&quot; alt=&quot;dnsscan&quot; /&gt;&lt;/p&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;Update your name server records to point to CloudFlare&#39;s names servers so the can serve up DNS on your behalf. In my case, I use a service called DNSimple.com but you may use GoDaddy or NameCheap as your registrar.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://images/using-wyam-blog/dnsimplenameservers.PNG&quot; alt=&quot;name server&quot; /&gt;&lt;/p&gt;
&lt;ol start=&quot;4&quot;&gt;
&lt;li&gt;Setup your free SSL certificate by switching the SSL drop down to &amp;quot;full&amp;quot;, &lt;strong&gt;this can take some time so keep that in mind&lt;/strong&gt;. The CloudFlare site says up to 24 hours (but from experience it seems to finish in about an hour or so).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://images/using-wyam-blog/cloudflare-crypto.PNG&quot; alt=&quot;crypto&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Once everything has been provisioned and propagated you&#39;ll notice that CloudFlare is serving your domain off of a SAN certificate.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://images/using-wyam-blog/san-cert.PNG&quot; alt=&quot;san1&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://images/using-wyam-blog/cloudflarescan2.PNG&quot; alt=&quot;san2&quot; /&gt;&lt;/p&gt;
&lt;p&gt;We are done! The new Wyam blog platform is now ready for new posts and is on a more sustainable and secure set of technologies. Hopefully you find this useful, let me know what you think.&lt;/p&gt;
&lt;p&gt;-Erik&lt;/p&gt;
</content>
  </item>
  
  <item>
    <title>Game Development – A Year in Review 2014</title>
    <link>https://erikonarheim.com/posts/game-development-a-year-in-review-2014/</link>
    <description>Erik Onarheim</description>
    <guid>https://erikonarheim.com/posts/game-development-a-year-in-review-2014/</guid>
    <pubDate>Fri, 09 Jan 2015 00:00:00 +0000</pubDate>
    <content type="html" >&lt;p&gt;This year I have really been exploring my passion for game development, and I feel like I’ve learned some useful things that I would like to share. Full disclaimer: this is mostly all unsubstantiated opinions.&lt;/p&gt;
&lt;p&gt;I attempted to do the &amp;quot;One Game a Month&amp;quot; challenge (which I recommend to anyone into games or wanting to improve their game making ability). It’s great because it forces you to build a product every month, and even if you don’t succeed you still get great practice. There are always more ideas than there is time, and this is a great way to explore many ideas in a short amount of time. It also prevents you into falling into the trap of the magnum opus idea, where you believe your idea to be more awesome than it actually is. It is so easy to wind up being more concerned about protecting your magnum opus from others than actually finding out if it’s good at all.&lt;/p&gt;
&lt;p&gt;I participated in a number of game jams this year including Ludum Dare 29 (Jam), Public Domain Jam, and Ludum Dare 31 (Jam). I think the three biggest lessons I’ve learned from jamming have been how to manage scope, how to brainstorm properly, and prototyping.&lt;/p&gt;
&lt;p&gt;Kraken Unchained for Ludum Dare 29&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/kraken-unchained.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Sleepy Hollow for the Public Domain Jam&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/sleepy-hollow.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Sweep Stacks for Ludum Dare 31&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/sweepstacks.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Managing scope, especially when you are really excited about an idea, is hard. It’s easy to want to build the biggest, coolest, and most awesome thing around, but in a game jam you have limited time, resources, and people forcing you to face reality. I think Rami Ismail of Vlambeer fame said it best, &amp;quot;Your scope is too damn big!&amp;quot;. As a team working on our LD 29 game, kraken unchained, we definitely learn that we sucked at managing scope. Over the course of this year we have relearned this lesson time and time again. Lately, we have begun to use the phrase minimum viable game to get at the root of a game idea, basically what is the simplest possible version of this game that is still interesting. In Ludum Dare 31, which yielded sweep stacks, we originally had a fantasy theme where the blocks were a marching army heading towards a castle wall, and you controlled a wizard zapping orcs, goblins, and spiders as they approached. Obviously, this really didn’t make the game any more fun than it is right now and we wound up cutting the idea all together since colored blocks were just as fun.&lt;/p&gt;
&lt;p&gt;For each of the jams, our group brainstorming process has evolved fairly organically and I feel like the results have been awesome. Basically, our method is throw out and fully explore every idea that everyone puts out until there are no more ideas and everyone agrees on one. This process generally takes approximately 4 hours of intense discussion, and a willingness to not get stuck on a particular idea just because you like it (caveat this process may not scale past a few people). There are so many ideas, and if you stop at the first &amp;quot;good&amp;quot; one, you will miss out on all of those other ideas that might actually be better. In the case of Ludum 31, there were a couple of ideas that I really wanted to do before we got to the ideas that spawned Sweep Stacks. I’d argue that because we continued to brainstorm we arrived at the best game possible, and it turned out to be really fun.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/sweepstacks.gif&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;During our last jam, we used a physical prototype for the game that would eventually become Sweep Stacks, and I cannot stress how well it worked for us. Our prototype was basically a checker board and some colored poker chips, then we took turns playing, suggesting new ideas and mechanics, and acting as the &amp;quot;game engine&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/checker.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Using prototypes is a great way to cheaply test new ideas and mechanics to make sure they are fun, don’t break the game, or have any problems. In our case we spotted one of the biggest problems, which we named the &amp;quot;shaft of doom&amp;quot;, basically it is possible to play in such a way that stacks of unclearable blocks rise to the top where the game will end abruptly. This was a huge problem...&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/shaft.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Before writing a single line of code, we were able to observe potential problems and come up with solutions, and our solution was the basic “sweep” mechanic that will either let you clear blocks of a single color or the mega &amp;quot;sweep&amp;quot; which clears the entire board at once. Boom! Problems solved before code was written all with a couple of poker chips.&lt;/p&gt;
&lt;p&gt;After all of these experiences, I’ve learned so much and gained a lot of respect for the game development community. It is not an easy thing to build a game, let alone offer it up to the masses for criticism. The masses can be very cruel. And in general, I’ve been really impressed with the indie game development community, everyone I have meet and spoken or interacted with has been so supportive and cool. We all are here because of our passions, and that is just so cool. I wish every online community was like this one.&lt;/p&gt;
&lt;p&gt;Do I feel like a &amp;quot;real&amp;quot; game developer after this year? yes. Did I just change my twitter bio to reflect that? yup 🙂&lt;/p&gt;
&lt;p&gt;Cheers!
Erik&lt;/p&gt;
</content>
  </item>
  
  <item>
    <title>Conway’s Game of Life in JavaScript</title>
    <link>https://erikonarheim.com/posts/conways-game-of-life-in-javascript/</link>
    <description>Erik Onarheim</description>
    <guid>https://erikonarheim.com/posts/conways-game-of-life-in-javascript/</guid>
    <pubDate>Tue, 10 Jun 2014 00:00:00 +0000</pubDate>
    <content type="html" >&lt;p&gt;After stumbling onto a code kata &lt;a href=&quot;http://vimeo.com/18350401&quot;&gt;video&lt;/a&gt; about Conway’s “Game of Life” I wanted to learn more about it.&lt;/p&gt;
&lt;p&gt;TL;DR – Here is the code on &lt;a href=&quot;https://github.com/eonarheim/GameOfLife&quot;&gt;github&lt;/a&gt;, and here is a running &lt;a href=&quot;http://erikonarheim.com/GameOfLife/&quot;&gt;example&lt;/a&gt;, click to seed the board and any key to start the simulation.&lt;/p&gt;
&lt;p&gt;Once I got to googling I noticed a neat little easter egg in the sides of the page:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://erikonarheim.com/images/google-easter-egg.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Bam! I was inspired to implement the simulation for myself.&lt;/p&gt;
&lt;p&gt;The “Game of Life” is a simulation of cellular automatons that demonstrates that complex patterns can emerge from simple rules. Evolution of the simulation is determined by the initial state of the simulation and progresses forward.&lt;/p&gt;
&lt;p&gt;The rules that drive the simulation are as follows:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Any live cell with fewer than two live neighbors dies, as if caused by under-population.
Any live cell with two or three live neighbors lives on to the next generation.
Any live cell with more than three live neighbors dies, as if by overcrowding.
Any dead cell with exactly three live neighbors becomes a live cell, as if by reproduction.
From &lt;a href=&quot;http://en.wikipedia.org/wiki/Conway&#39;s_Game_of_Life&quot;&gt;Wikipedia&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;There is a compact notation that is used to describe these rules to the simulation, fore example “B3/S23”. The way to read this is a cell is spontaneously born if it has exactly 3 neighboring cells, “stays lives on if it has 2 or 3 living neighboring cells. In all other cases, the cell dies. There are many people who tweak the rules to bring about interesting variations in the standard game.&lt;/p&gt;
&lt;p&gt;So how would you do this in JavaScript?&lt;/p&gt;
&lt;p&gt;The first thing to accomplish is to represent a “Cell”.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;Cell&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;x&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;y&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _cells&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; me &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isAlive &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; x&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; y&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;distance&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;cell&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cell&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cell&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;neighbors &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;        &lt;br /&gt;&lt;br /&gt;        me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;countNeighbors&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;neighbors&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;cell&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; cell&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isAlive&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;length&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; me&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Cells have an pair of coordinates, an “isAlive” flag, and they also know about their neighbors. Having a reference to their neighbors makes it very simple to interrogate cells and find out whether or not they will survive to the next generation of the simulation.&lt;/p&gt;
&lt;p&gt;Once we have the cells figured out, we need some way to arrange and keep track of them. I did this by creating a simple grid structure.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;Grid&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; height&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; me &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; _cells &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;width&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;height&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; _living &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// instantiate cells&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; width&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; i&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; j &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; j &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; height&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; j&lt;span class=&quot;token operator&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                        &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                                _cells&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;i&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;j&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;width&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Cell&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; j&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _cells&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;                        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;// Self executing function necessary to capture i and j values&lt;/span&gt;&lt;br /&gt;                             &lt;span class=&quot;token comment&quot;&gt;// For-loops in JavaScript DO NOT create scope which is a bummer                       &lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// Continued below...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here I’m applying a trick to pack a 2D grid into a 1D array. You may also notice the self executing function inside the for-loop, this is to create scope and capture the values of i and j.&lt;/p&gt;
&lt;p&gt;Next, we need to assign neighbor references to all the cell, in this example I’m really brute forcing this. There is definitely a more elegant way to do this, but for the purposes of the example I feel this is okay.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;       &lt;span class=&quot;token comment&quot;&gt;// assign neighbors&lt;/span&gt;&lt;br /&gt;        _cells&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;cell&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                cell&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;neighbors &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; _cells&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;cell2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                        &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; dx &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cell2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; cell&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;                        &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; dy &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cell2&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; cell&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;                        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;dx &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; dy &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;dx &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; dy &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;dx &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; dy &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;       &lt;span class=&quot;token comment&quot;&gt;// Continued below..&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The next piece is the implementation of the rules of the simulation. First the cells that die are calculated then the cells that live on and reproduce. This step is made easier by the ability to ask cells about their neighbors directly, no need for complicated array math with “.countNeighbors()”.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;        me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;updateLiving&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; deadOvercrowded &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; _cells&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;cell&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; cell&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isAlive &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cell&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;countNeighbors&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; deadUnderpop &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; _cells&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;cell&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; cell&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isAlive &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cell&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;countNeighbors&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; reproduction &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; _cells&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;cell&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;cell&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isAlive &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; cell&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;countNeighbors&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; livesOn &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; _cells&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;cell&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; cell&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isAlive &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cell&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;countNeighbors&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; cell&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;countNeighbors&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                deadOvercrowded&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;deadUnderpop&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;cell&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                        cell&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isAlive &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                reproduction&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;cell&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                        cell&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isAlive &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;                livesOn&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;cell&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                        cell&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isAlive &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;//Helpers&lt;/span&gt;&lt;br /&gt;        me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;filter&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;fcn&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; _cells&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;fcn&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;getCell&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;x&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;y&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; _cells&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;x&lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt;y&lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt;width&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; me&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now with the simulation “engine” and data structures out of the way, we can work on the drawing aspect. With the HTML5 canvas we can accomplish some pretty cool stuff. Here is the basic boiler plate we need before we can get started.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;App&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;targetElementId&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; squaresX&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; squaresY&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; me &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// Grab the canvas and drawing context&lt;/span&gt;&lt;br /&gt;        me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;canvas &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;targetElementId&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ctx &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getContext&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;2d&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// Grab the start button&lt;/span&gt;&lt;br /&gt;        me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;button &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;start&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// Initialize page styles&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; body &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementsByTagName&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;body&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;margin &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;0px&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        body&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;style&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;overflow &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;hidden&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// Set height and width to window inner height to make the app &#39;fullscreen&#39;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; viewWidth &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;innerWidth&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; viewHeight &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;innerHeight&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        squaresX &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; squaresX &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        squaresY &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; squaresY &lt;span class=&quot;token operator&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// Calculate the height and width of each cell&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; _squareWidth &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;squaresX&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; _squareHeight &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; _squareWidth&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// Initialize our Grid data structure from above&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; grid &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Grid&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;squaresX&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; squaresY&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// Continued below&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The user is going to want to setup the initial state of the simulation to they can play around, so we are going to setup event handlers for starting and stopping the simulation as well as handlers for clicking. To start and stop we will response with any keypress to make things simple, and mouse click and drag with lay down intial state.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;        &lt;span class=&quot;token comment&quot;&gt;// Handle Click events&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; _mouseDown &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;token function-variable function&quot;&gt;handleClick&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; x &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pageX &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;offsetLeft&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; y &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; event&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pageY &lt;span class=&quot;token operator&quot;&gt;-&lt;/span&gt; me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;offsetTop&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; i &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;floor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;x&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;_squareWidth&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; j &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Math&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;floor&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;y&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;_squareHeight&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                grid&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getCell&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;i&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; j&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isAlive &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; _startSim &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;onkeydown&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;ev&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                _startSim &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;_startSim&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;onresize&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;ev&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                viewWidth &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;innerWidth&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;//viewWidth || 600;&lt;/span&gt;&lt;br /&gt;                  viewHeight &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; window&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;innerHeight&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;//viewHeight || 600;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;mousedown&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                _mouseDown &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token function&quot;&gt;handleClick&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;event&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;                me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;mousemove&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; handleClick&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;mouseup&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                _mouseDown &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;                me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;removeEventListener&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;mousemove&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; handleClick&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// Continued below...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now for the fun part, drawing and updating&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;        &lt;span class=&quot;token comment&quot;&gt;// Here is our start responsible for kicking off our mainloop &lt;/span&gt;&lt;br /&gt;        me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;start&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token function&quot;&gt;setInterval&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                        me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;update&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;                        me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Mainloop set to refresh every ~60 milliseconds&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// Update is responsible for updating all state in the app&lt;/span&gt;&lt;br /&gt;        me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;update&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;_startSim&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                        grid&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;updateLiving&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;        &lt;br /&gt;                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token comment&quot;&gt;// Draw is responsible for drawing the entire app&lt;/span&gt;&lt;br /&gt;        me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;draw&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token comment&quot;&gt;// Erase previous draw by filling the entire canvas with white&lt;/span&gt;&lt;br /&gt;                me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fillStyle &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;white&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;                me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fillRect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;width&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;canvas&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;height&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;span class=&quot;token comment&quot;&gt;// Draw living squares first&lt;/span&gt;&lt;br /&gt;                grid&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;cell&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; cell&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;isAlive&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;forEach&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;cell&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                        me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fillStyle &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;black&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;                        me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;fillRect&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;cell&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;x &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; _squareWidth&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; cell&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;y &lt;span class=&quot;token operator&quot;&gt;*&lt;/span&gt; _squareHeight&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _squareWidth&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; _squareHeight&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;span class=&quot;token comment&quot;&gt;// Draw grid&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;span class=&quot;token comment&quot;&gt;// First draw vertical lines&lt;/span&gt;&lt;br /&gt;                me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fillStyle &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;gray&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; x &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; x &lt;span class=&quot;token operator&quot;&gt;&amp;lt;=&lt;/span&gt; viewWidth&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; x&lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt;_squareWidth&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                        me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;beginPath&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;                        me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;moveTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;x&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;                        me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;lineTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;x&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; viewHeight&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;                        me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stroke&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;                &lt;span class=&quot;token comment&quot;&gt;// Second draw horizontal lines&lt;/span&gt;&lt;br /&gt;                &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; y &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; y &lt;span class=&quot;token operator&quot;&gt;&amp;lt;=&lt;/span&gt; viewHeight&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; y&lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; _squareHeight&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;                        me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;beginPath&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;                        me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;moveTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; y&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;                        me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;lineTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;viewWidth&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; y&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;                        me&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ctx&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;stroke&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;        &lt;br /&gt;                &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;        &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; me&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To kick off the whole thing, all you need to do is the following&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; app &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;game&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Check out the code on github, and here is a running example on the web.&lt;/p&gt;
&lt;p&gt;Happy games!&lt;/p&gt;
&lt;p&gt;Cheers,
Erik&lt;/p&gt;
</content>
  </item>
  </channel>
</rss>
