<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  <title>Penumbra Development Journal</title>
  <subtitle>Tracking the development of Penumbra, a web-centric ray tracer.</subtitle>
  <link href="https://limulus.net/penumbra/feed.xml" rel="self" />
  <link href="https://limulus.net/penumbra" />
  <updated>2024-06-04T20:20:00Z</updated>
  <id>https://limulus.net/penumbra</id>
  <author>
    <name>Eric McCarthy</name>
    <email>eric@limulus.net</email>
  </author>
  <entry>
    <title>The Twist You Possibly Expected: Rust</title>
    <link href="https://limulus.net/penumbra/journal/rust/" />
    <updated>2024-06-04T20:20:00Z</updated>
    <id>https://limulus.net/penumbra/journal/rust/</id>
    <content type="html">&lt;p&gt;
  I’ve &lt;a href=&quot;https://limulus.net/penumbra/journal/tuples/#looking-ahead&quot;&gt;previously&lt;/a&gt;
  &lt;a
    href=&quot;https://limulus.net/penumbra/journal/canvas-and-matrices/#implementing-the-canvas-class&quot;
  &gt;mentioned&lt;/a&gt; my intention to eventually switch from targeting JavaScript to targeting &lt;a
    href=&quot;https://webassembly.org/&quot;
  &gt;WebAssembly&lt;/a&gt;. Well, I’ve done it! I went through and reimplemented everything I have
  done so far to target WebAssembly using &lt;a
    href=&quot;https://en.wikipedia.org/wiki/Single_instruction,_multiple_data&quot;
  &gt;SIMD&lt;/a&gt; instructions. Here’s the previous
  &lt;a href=&quot;https://limulus.net/penumbra/journal/ray-sphere-interactions/#demo&quot;
  &gt;sphere’s shadow demo&lt;/a&gt; alongside the new WebAssembly version:
&lt;/p&gt;
&lt;div&gt;
  &lt;sphere-shadow-js-vs-wasm&gt;
    &lt;noscript&gt;
      &lt;p&gt;&lt;em&gt;View this dynamic content on the website with JavaScript enabled.&lt;/em&gt;&lt;/p&gt;
    &lt;/noscript&gt;
    &lt;script&gt;
    // Ensure that syndicated copies of this content don’t show a &quot;Loading…&quot; message. This is
  // necessary because some feed readers try to execute JavaScript.
  const firstPartyHosts = [&#39;limulus.net&#39;, &#39;localhost&#39;, &#39;127.0.0.1&#39;]
  if (firstPartyHosts.some((host) =&gt; window.location.host.includes(host))) {
    document.write(&#39;&lt;p&gt;&lt;em&gt;Loading…&lt;/em&gt;&lt;/p&gt;&#39;)
  } else {
    document.write(&#39;&lt;p&gt;&lt;em&gt;View this dynamic content on the website with JavaScript enabled.&lt;/em&gt;&lt;/p&gt;&#39;)
  }
    &lt;/script&gt;
  &lt;/sphere-shadow-js-vs-wasm&gt;
&lt;/div&gt;
&lt;p&gt;
  Click and drag (or touch and drag) to change the position of the light source, and thus
  change the shape of the sphere’s shadow. Change the resolution via the dropdown to observe
  the effect on render times.
&lt;/p&gt;
&lt;h2 id=&quot;eschewing-assemblyscript&quot; tabindex=&quot;-1&quot;&gt;Eschewing AssemblyScript&lt;/h2&gt;
&lt;p&gt;
  I previously mentioned that my plan was to rewrite using &lt;a
    href=&quot;https://www.assemblyscript.org/&quot;
  &gt;AssemblyScript&lt;/a&gt;, which is a TypeScript based language that compiles directly to
  WebAssembly. This seemed really promising to me. My goal with this project was not to
  learn a new programming language but to learn about ray tracing and maybe do something fun
  with it.
&lt;/p&gt;
&lt;p&gt;
  Unfortunately, as I began to look more seriously into AssemblyScript I started to have my
  doubts about it. I briefly joined the AssemblyScript Discord server and it became apparent
  that established WebAssembly features like threads were not going to be implemented any
  time soon — seemingly because the authors have become disenchanted with one or more of the
  W3C working groups of which they were once a part of. In a &lt;a
    href=&quot;https://www.assemblyscript.org/standards-objections.html&quot;
  &gt;long and somewhat inscrutable manifesto&lt;/a&gt; they list their objections, offenses, and
  demands. I can’t discount that they were mistreated but I nevertheless found it an
  off-putting read. They may well have some valid points — after all it is easy to be
  sympathetic about ensuring WebAssembly interoperates well with the web — but I can’t shake
  the feeling that maybe the WebAssembly standard will be better without their participation
  for a time.
&lt;/p&gt;
&lt;p&gt;
  Once I took AssemblyScript off the top of the list of possibilities I looked for
  alternatives, but ultimately &lt;a href=&quot;https://www.rust-lang.org/&quot;&gt;Rust&lt;/a&gt; was the obvious
  choice. It’s a language I have wanted to learn anyway.
&lt;/p&gt;
&lt;h2 id=&quot;adopting-rust&quot; tabindex=&quot;-1&quot;&gt;Adopting Rust&lt;/h2&gt;
&lt;p&gt;
  I have previously spent a little bit of time playing with Rust, but this was certainly a
  more thorough experience. It was helpful to understand that since I was building something
  that would solely target WebAssembly I could rely on &lt;a
    href=&quot;https://github.com/rustwasm/wasm-pack&quot;
  &gt;wasm-pack&lt;/a&gt; to take care of a lot of the build details.
&lt;/p&gt;
&lt;h3 id=&quot;tests&quot; tabindex=&quot;-1&quot;&gt;Tests&lt;/h3&gt;
&lt;p&gt;
  Getting tests working was also made pretty simple thanks to wasm-pack and &lt;a
    href=&quot;https://github.com/rustwasm/wasm-bindgen&quot;
  &gt;wasm-bindgen&lt;/a&gt;. The standard way of writing tests in Rust is to put the tests in the
  same file as the code under test, inside a &lt;code&gt;tests&lt;/code&gt; module. Here’s an example
  from &lt;a
    href=&quot;https://github.com/limulus/penumbra/blob/3558cf6/wasm/src/ray.rs#L27-L40&quot;
  &gt;&lt;code&gt;ray.rs&lt;/code&gt;&lt;/a&gt;:
&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;&lt;span class=&quot;hljs-meta&quot;&gt;#[cfg(test)]&lt;/span&gt;
&lt;span class=&quot;hljs-keyword&quot;&gt;mod&lt;/span&gt; tests {
  &lt;span class=&quot;hljs-keyword&quot;&gt;use&lt;/span&gt; super::*;
  &lt;span class=&quot;hljs-keyword&quot;&gt;use&lt;/span&gt; wasm_bindgen_test::*;

  &lt;span class=&quot;hljs-meta&quot;&gt;#[wasm_bindgen_test]&lt;/span&gt;
  &lt;span class=&quot;hljs-keyword&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;creating_and_querying_a_ray&lt;/span&gt;() {
    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;origin&lt;/span&gt; = Tuple::&lt;span class=&quot;hljs-title function_ invoke__&quot;&gt;point&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;1.0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;2.0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;3.0&lt;/span&gt;);
    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;direction&lt;/span&gt; = Tuple::&lt;span class=&quot;hljs-title function_ invoke__&quot;&gt;vector&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;4.0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;5.0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;6.0&lt;/span&gt;);
    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;r&lt;/span&gt; = Ray::&lt;span class=&quot;hljs-title function_ invoke__&quot;&gt;new&lt;/span&gt;(origin, direction);

    &lt;span class=&quot;hljs-built_in&quot;&gt;assert_eq!&lt;/span&gt;(r.origin, origin);
    &lt;span class=&quot;hljs-built_in&quot;&gt;assert_eq!&lt;/span&gt;(r.direction, direction);
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
  One downside to having all these tests in Rust means there is no obvious way to get them
  running on this site. As a result, I’ve taken down the test page that allowed you to run
  the JavaScript tests in your browser. I might explore that at some point, but its not a
  priority for me right now.
&lt;/p&gt;
&lt;h3 id=&quot;using-simd-instructions&quot; tabindex=&quot;-1&quot;&gt;Using SIMD Instructions&lt;/h3&gt;
&lt;p&gt;
  If you’re not familiar with “Single Instruction, Multiple Data,” it is a category of
  instruction sets CPUs implement to speed up calculations where you need to perform the
  same series of operations over different sets of variables. This comes in handy for things
  like matrix math. If you are old enough, you may even remember when SIMD instruction sets
  began to be added to processors: &lt;a
    href=&quot;https://en.wikipedia.org/wiki/MMX_(instruction_set)&quot;
  &gt;MMX&lt;/a&gt; on Intel and &lt;a href=&quot;https://en.wikipedia.org/wiki/AltiVec&quot;&gt;AltiVec&lt;/a&gt; for
  PowerPC. These days the common SIMD instruction sets are &lt;a
    href=&quot;https://en.wikipedia.org/wiki/Advanced_Vector_Extensions&quot;
  &gt;AVX&lt;/a&gt; on Intel or AMD processors and &lt;a
    href=&quot;https://en.wikipedia.org/wiki/ARM_architecture_family#Advanced_SIMD_(Neon)&quot;
  &gt;Neon&lt;/a&gt; on ARM processors.
&lt;/p&gt;
&lt;p&gt;
  Of course, WebAssembly is a virtual machine. You can’t just throw AVX and Neon
  instructions in the WASM file. Instead, WebAssembly has defined SIMD instructions that get
  compiled into the SIMD instructions for whatever architecture the browser is running on.
  In Rust these are exposed as compiler intrinsics in the &lt;a
    href=&quot;https://doc.rust-lang.org/core/arch/wasm32/index.html&quot;
  &gt;&lt;code&gt;std::arch::wasm32&lt;/code&gt;&lt;/a&gt; module.
&lt;/p&gt;
&lt;p&gt;
  WebAssembly’s SIMD instructions are all fixed-width, operating on 128-bit wide operands.
  So for example there’s &lt;code&gt;u8x16&lt;/code&gt; instructions for addition, subtraction,
  multiplication, division, comparisons, etc. that operate on 16 8-bit unsigned integers
  packed into 128-bit wide registers. Likewise, there are instructions for &lt;code
  &gt;i8x16&lt;/code&gt; for signed 8-bit integers and
  &lt;code&gt;f32x4&lt;/code&gt; for 32-bit floating point values.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a
      href=&quot;https://limulus.net/penumbra/journal/rust/#fn1&quot;
      id=&quot;fnref1&quot;
    &gt;[1]&lt;/a&gt;&lt;/sup&gt;
&lt;/p&gt;
&lt;p&gt;
  Here’s an &lt;a
    href=&quot;https://github.com/limulus/penumbra/blob/3558cf6/wasm/src/matrix.rs#L222-L238&quot;
  &gt;excerpt from &lt;code&gt;matrix.rs&lt;/code&gt;&lt;/a&gt; showing the multiplication operator
  implementation for
  &lt;code&gt;Tuple&lt;/code&gt; and &lt;code&gt;Matrix4&lt;/code&gt;.
&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;impl&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Mul&lt;/span&gt;&amp;lt;Tuple&amp;gt; &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; &amp;amp;Matrix4 {
  &lt;span class=&quot;hljs-keyword&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Output&lt;/span&gt; = Tuple;

  &lt;span class=&quot;hljs-keyword&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;mul&lt;/span&gt;(&lt;span class=&quot;hljs-keyword&quot;&gt;self&lt;/span&gt;, other: Tuple) &lt;span class=&quot;hljs-punctuation&quot;&gt;-&amp;gt;&lt;/span&gt; Tuple {
    &lt;span class=&quot;hljs-keyword&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;mut &lt;/span&gt;&lt;span class=&quot;hljs-variable&quot;&gt;sum&lt;/span&gt; = &lt;span class=&quot;hljs-title function_ invoke__&quot;&gt;f32x4_splat&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;0.0&lt;/span&gt;);
    &lt;span class=&quot;hljs-keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;hljs-variable&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;..&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt; {
      sum = &lt;span class=&quot;hljs-title function_ invoke__&quot;&gt;f32x4_add&lt;/span&gt;(
        sum,
        &lt;span class=&quot;hljs-title function_ invoke__&quot;&gt;f32x4_mul&lt;/span&gt;(
          &lt;span class=&quot;hljs-title function_ invoke__&quot;&gt;f32x4_splat&lt;/span&gt;(other.&lt;span class=&quot;hljs-title function_ invoke__&quot;&gt;get&lt;/span&gt;(i)),
          &lt;span class=&quot;hljs-keyword&quot;&gt;self&lt;/span&gt;.&lt;span class=&quot;hljs-title function_ invoke__&quot;&gt;col_v128&lt;/span&gt;(i),
        )
      );
    }
    Tuple::&lt;span class=&quot;hljs-title function_ invoke__&quot;&gt;from_v128&lt;/span&gt;(sum)
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
  Now that I have implemented everything using explicit WebAssembly SIMD intrinsics, I am
  wondering if I should have looked more closely at the still-experimental &lt;a
    href=&quot;https://doc.rust-lang.org/std/simd/&quot;
  &gt;portable SIMD&lt;/a&gt;
  module. The main benefit is that I could also target non-SIMD WebAssembly and compare the
  performance. I could probably also more easily make use of WebAssembly’s &lt;a
    href=&quot;https://github.com/WebAssembly/relaxed-simd/blob/95dc80e/proposals/relaxed-simd/Overview.md&quot;
  &gt;relaxed SIMD&lt;/a&gt;
  which includes instructions like &lt;a
    href=&quot;https://doc.rust-lang.org/stable/core/arch/wasm32/fn.f32x4_relaxed_madd.html&quot;
  &gt;&lt;code&gt;f32x4_relaxed_madd&lt;/code&gt;&lt;/a&gt; that would likely speed up matrix multiplication
  noticeably.
&lt;/p&gt;
&lt;h4 id=&quot;f32x4_relaxed_madd&quot; tabindex=&quot;-1&quot;&gt;Speaking of &lt;code&gt;f32x4_relaxed_madd&lt;/code&gt;…&lt;/h4&gt;
&lt;p&gt;
  …I’m curious how switching the above &lt;code&gt;Tuple * Matrix4&lt;/code&gt; implementation to it
  would perform. So I spent around two hours trying to get it to work, to no avail. I think
  the problem is that &lt;a href=&quot;https://github.com/rustwasm/walrus&quot;&gt;walrus&lt;/a&gt;, which is used
  by &lt;code&gt;wasm-bindgen&lt;/code&gt;, does not yet seem to support the relaxed SIMD instructions.
  It throws this error when it hits the &lt;code&gt;f32x4_relaxed_madd&lt;/code&gt; instruction:
&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;Error: failed to deserialize wasm module

Caused by:
    0: failed to parse code section
    1: Unknown 0xfd subopcode: 0x105 (at offset 312376)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
  Maybe this should not be too much of a surprise, considering Relaxed SIMD doesn’t quite
  yet have wide support. It’s shipping in Chrome currently and behind a feature flag in
  Firefox. It looks like Safari may be getting it soon based on &lt;a
    href=&quot;https://commits.webkit.org/265324@main&quot;
  &gt;this WebKit commit&lt;/a&gt; from 2023, although it’s not a feature flag in &lt;a
    href=&quot;https://developer.apple.com/safari/technology-preview/&quot;
  &gt;Safari Technology Preview&lt;/a&gt;.
&lt;/p&gt;
&lt;h2
  id=&quot;wait%2C-what%E2%80%99s-that-weird-artifact-in-the-top-left-of-%3Csphere-shadow-wasm%3E%3F&quot;
  tabindex=&quot;-1&quot;
&gt;
  Wait, What’s That Weird Artifact in the Top Left of &amp;lt;sphere-shadow-wasm&amp;gt;?
&lt;/h2&gt;
&lt;p&gt;
  I’m actually not sure! There’s 8 or pixels that are transparent, so if you are viewing the
  site in dark mode they will look black, and if in light mode they will look white. I
  haven’t spent too much time trying to figure it out, but I must be doing something wrong
  when copying the image data from WASM world to JS world, or thereabouts.
&lt;/p&gt;
&lt;h2 id=&quot;detours&quot; tabindex=&quot;-1&quot;&gt;Detours&lt;/h2&gt;
&lt;p&gt;
  This entry took a while to get completed thanks to various detours I took. The bulk of the
  Rust work was actually done pretty quickly. It maybe took a month or less. But I took a
  number of detours to work on this site, including adding support for serving videos and
  breaking apart the repository into three repositories. There’s now the &lt;a
    href=&quot;https://github.com/limulus/penumbra&quot;
  &gt;penumbra&lt;/a&gt; repo for the core library, &lt;a href=&quot;https://github.com/limulus/penumbra-www&quot;
  &gt;penumbra-www&lt;/a&gt; for this website, and &lt;a href=&quot;https://github.com/limulus/touch-pad&quot;
  &gt;touch-pad&lt;/a&gt; which is now available as an independent &lt;a
    href=&quot;https://www.npmjs.com/package/touch-pad&quot;
  &gt;npm package&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
  &lt;em&gt;Update 2024-11-20: The &lt;code&gt;penumbra-www&lt;/code&gt; repo has been promoted to the main
    repo for all of limulus.net! It’s been renamed to &lt;a
      href=&quot;https://github.com/limulus/limulus-dot-net&quot;
    &gt;limulus-dot-net&lt;/a&gt;.&lt;/em&gt;
&lt;/p&gt;
&lt;h2 id=&quot;what%E2%80%99s-next%3F&quot; tabindex=&quot;-1&quot;&gt;What’s Next?&lt;/h2&gt;
&lt;p&gt;
  With so much time spent on the above detours I’m looking forward to finally starting the
  next chapter of the book, which is “Light and Shading”. I’ll be screen recording as I work
  on it, so I might also produce some kind of video, likely focused on whatever demo I
  create.
&lt;/p&gt;
&lt;section class=&quot;footnotes section-separator&quot;&gt;
  &lt;ol class=&quot;footnotes-list&quot;&gt;
    &lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;
      &lt;p&gt;
        In addition to &lt;code&gt;u8x16&lt;/code&gt;, &lt;code&gt;i8x16&lt;/code&gt;, &lt;code&gt;f32x4&lt;/code&gt;, and &lt;code
        &gt;f64x2&lt;/code&gt; there are also instructions for
        &lt;code&gt;u16x8&lt;/code&gt;, &lt;code&gt;i16x8&lt;/code&gt;, &lt;code&gt;u32x4&lt;/code&gt;, &lt;code&gt;i32x4&lt;/code&gt;,
        &lt;code&gt;u64x2&lt;/code&gt;, and &lt;code&gt;i64x2&lt;/code&gt;. With all the ways you might want to
        slice 128-bit wide operands and all the different operations you want to do for each
        way of slicing, this makes for a lot of instructions! &lt;a
          href=&quot;https://limulus.net/penumbra/journal/rust/#fnref1&quot;
          class=&quot;footnote-backref&quot;
        &gt;↩︎&lt;/a&gt;
      &lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/section&gt;
</content>
  </entry>
  <entry>
    <title>How I Am Using GitHub Copilot</title>
    <link href="https://limulus.net/penumbra/journal/github-copilot/" />
    <updated>2024-03-23T22:15:00Z</updated>
    <id>https://limulus.net/penumbra/journal/github-copilot/</id>
    <content type="html">&lt;p&gt;
  Above is a video I produced to demo &lt;a href=&quot;https://copilot.github.com&quot;
  &gt;GitHub Copilot&lt;/a&gt; to my coworkers. If you haven’t yet explored using a Large Language
  Model to you help you code, it is worth a watch. I screen-recorded myself developing an
  optimization for &lt;a href=&quot;https://limulus.net/&quot;&gt;Penumbra&lt;/a&gt; (this project) and edited it
  down to about 6 minutes.
&lt;/p&gt;
&lt;p&gt;
  I use Copilot in other ways not covered in the video. It’s clearly been trained on other
  &lt;a href=&quot;https://pragprog.com/titles/jbtracer/the-ray-tracer-challenge/&quot;
  &gt;Ray Tracer Challenge&lt;/a&gt; implementations so it very quickly autocompletes tests with all
  the exact values. This has saved me a bunch of mindless typing. It also autocompletes
  production code that satisfies the tests, which is often less helpful for this project
  since I usually want to spend some time thinking about how to implement these things. But
  sometimes I turn it back on to get suggestions that prompt me to consider a different and
  potentially better solution.
&lt;/p&gt;
&lt;p&gt;
  If you’ve read my previous posts you’ll notice that I’ve switched to &lt;a
    href=&quot;https://www.rust-lang.org&quot;
  &gt;Rust&lt;/a&gt; targeting
  &lt;a href=&quot;https://webassembly.org&quot;&gt;WebAssembly&lt;/a&gt;. There’s a story behind that! But it
  will have to wait for a future post.
&lt;/p&gt;
&lt;p&gt;
  Making this video was a lot of fun! A little less fun was navigating how to host video on
  this site without introducing a dependency on a third-party. There’s a good reason why
  just about everyone uploads to YouTube — doing this reasonably well is not easy. This may
  wind up needing to be a journal entry or even video of its own.
&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Chapter 5: Ray-Sphere Interactions</title>
    <link href="https://limulus.net/penumbra/journal/ray-sphere-interactions/" />
    <updated>2023-12-29T21:00:00Z</updated>
    <id>https://limulus.net/penumbra/journal/ray-sphere-interactions/</id>
    <content type="html">&lt;p&gt;
  In chapter 5 of &lt;a href=&quot;https://pragprog.com/titles/jbtracer/the-ray-tracer-challenge/&quot;
  &gt;The Ray Tracer Challenge&lt;/a&gt; you finally get to implement something that starts to
  resemble a ray tracer. You implement ray, sphere, and intersection related functions and
  the exercise at the end ties it all together to create an image.
&lt;/p&gt;
&lt;h2 id=&quot;finding-intersections&quot; tabindex=&quot;-1&quot;&gt;Finding Intersections&lt;/h2&gt;
&lt;p&gt;
  The book does not go into the details of the math for how to determine the intersection
  points of a ray and sphere. I’m glad for that, but it bugged me that I do not have an
  intuitive understanding of &lt;em&gt;why&lt;/em&gt; &lt;a
    href=&quot;https://github.com/limulus/penumbra/blob/1fee85dad2f656c6d028a74d957b2129c0476f34/src/lib/sphere.ts#L27-L51&quot;
  &gt;this intersect method&lt;/a&gt; works.
&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Sphere&lt;/span&gt; {
  &lt;span class=&quot;hljs-title function_&quot;&gt;intersect&lt;/span&gt;(&lt;span class=&quot;hljs-attr&quot;&gt;ray&lt;/span&gt;: &lt;span class=&quot;hljs-title class_&quot;&gt;Ray&lt;/span&gt;): &lt;span class=&quot;hljs-title class_&quot;&gt;IntersectionCollection&lt;/span&gt; {
    &lt;span class=&quot;hljs-comment&quot;&gt;// Transform the ray into object space&lt;/span&gt;
    ray = ray.&lt;span class=&quot;hljs-title function_&quot;&gt;transform&lt;/span&gt;(&lt;span class=&quot;hljs-variable language_&quot;&gt;this&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;transformInverse&lt;/span&gt;)

    &lt;span class=&quot;hljs-comment&quot;&gt;// Vector from sphere origin to the ray origin&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; sphereToRayVec = ray.&lt;span class=&quot;hljs-property&quot;&gt;origin&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;sub&lt;/span&gt;(origin)

    &lt;span class=&quot;hljs-comment&quot;&gt;// Supporting characters to determine the discriminant and intersection&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; a = ray.&lt;span class=&quot;hljs-property&quot;&gt;direction&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;dot&lt;/span&gt;(ray.&lt;span class=&quot;hljs-property&quot;&gt;direction&lt;/span&gt;)
    &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; b = &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; * ray.&lt;span class=&quot;hljs-property&quot;&gt;direction&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;dot&lt;/span&gt;(sphereToRayVec)
    &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; c = sphereToRayVec.&lt;span class=&quot;hljs-title function_&quot;&gt;dot&lt;/span&gt;(sphereToRayVec) - &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;

    &lt;span class=&quot;hljs-comment&quot;&gt;// Discriminant does not intersect sphere if it is negative&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; discriminant = b ** &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; - &lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt; * a * c
    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (discriminant &amp;lt; &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;) &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;IntersectionCollection&lt;/span&gt;()

    &lt;span class=&quot;hljs-comment&quot;&gt;// Calculate the intersection points&lt;/span&gt;
    &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; sqrtDiscriminant = &lt;span class=&quot;hljs-title class_&quot;&gt;Math&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;sqrt&lt;/span&gt;(discriminant)
    &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; t1 = (-b - sqrtDiscriminant) / (&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; * a)
    &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; t2 = (-b + sqrtDiscriminant) / (&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; * a)
    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;IntersectionCollection&lt;/span&gt;(
      &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Intersection&lt;/span&gt;(t1, &lt;span class=&quot;hljs-variable language_&quot;&gt;this&lt;/span&gt;),
      &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Intersection&lt;/span&gt;(t2, &lt;span class=&quot;hljs-variable language_&quot;&gt;this&lt;/span&gt;)
    )
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
  The book does suggest some online resources for an explanation of the math at work. I took
  some time to read through &lt;a
    href=&quot;https://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-sphere-intersection.html&quot;
  &gt;this one&lt;/a&gt;. It includes two solutions: a geometric solution and an analytic solution.
  The geometric solution made sense to me but the analytic solution less so. Still — despite
  an error&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a
      href=&quot;https://limulus.net/penumbra/journal/ray-sphere-interactions/#fn1&quot;
      id=&quot;fnref1&quot;
    &gt;[1]&lt;/a&gt;&lt;/sup&gt; in that explanation — it did make some sense. One thing that helped was
  realizing that the &lt;code&gt;discriminant&lt;/code&gt; being negative means there is no intersection
  because that would require taking the square root of a negative number.
&lt;/p&gt;
&lt;p&gt;
  The solution the book provides and I implemented above is the analytic solution. I would
  have a deeper understanding of it if it were the geometric solution, but at least I now
  have a better-than-tenuous idea of why this code works.
&lt;/p&gt;
&lt;h2 id=&quot;demo&quot; tabindex=&quot;-1&quot;&gt;The Demo: &lt;code&gt;&amp;lt;sphere-shadow&amp;gt;&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;
  The exercise at the end of the chapter is to render the shadow of a sphere by casting rays
  from a light source onto a “wall”. I’ve implemented that here, with the addition that you
  can change the position of the light source by dragging from the element.
&lt;/p&gt;
&lt;div&gt;
  &lt;sphere-shadow-demo&gt;
    &lt;noscript&gt;
      &lt;p&gt;&lt;em&gt;View this dynamic content on the website with JavaScript enabled.&lt;/em&gt;&lt;/p&gt;
    &lt;/noscript&gt;
    &lt;script&gt;
    // Ensure that syndicated copies of this content don’t show a &quot;Loading…&quot; message. This is
  // necessary because some feed readers try to execute JavaScript.
  const firstPartyHosts = [&#39;limulus.net&#39;, &#39;localhost&#39;, &#39;127.0.0.1&#39;]
  if (firstPartyHosts.some((host) =&gt; window.location.host.includes(host))) {
    document.write(&#39;&lt;p&gt;&lt;em&gt;Loading…&lt;/em&gt;&lt;/p&gt;&#39;)
  } else {
    document.write(&#39;&lt;p&gt;&lt;em&gt;View this dynamic content on the website with JavaScript enabled.&lt;/em&gt;&lt;/p&gt;&#39;)
  }
    &lt;/script&gt;
  &lt;/sphere-shadow-demo&gt;
&lt;/div&gt;
&lt;p&gt;
  I don’t normally test drive my demo code since it is more exploratory fun than writing
  code I intend to reuse. But I figured I would want to make use of the dragging interaction
  again, so I &lt;a
    href=&quot;https://github.com/limulus/penumbra/blob/93ee15212eb71ad186f072d8c38e3d8a1f3b8500/src/lib/ui/touch-pad.spec.ts&quot;
  &gt;test-drove the creation&lt;/a&gt; of a &lt;a
    href=&quot;https://github.com/limulus/penumbra/blob/93ee15212eb71ad186f072d8c38e3d8a1f3b8500/src/lib/ui/touch-pad.ts&quot;
  &gt;TouchPad class&lt;/a&gt; to track all the mouse and touch events on (and off) of the element
  and emit only the needed move events. At some point I should add keyboard support to it as
  well.
&lt;/p&gt;
&lt;p&gt;
  Other than that there is not much new from the web technology side compared to the &lt;a
    href=&quot;https://limulus.net/penumbra/journal/canvas-and-matrices/&quot;
  &gt;previous demo&lt;/a&gt;. Rendering of the canvas still happens in a single web worker.
&lt;/p&gt;
&lt;h2 id=&quot;what%E2%80%99s-next&quot; tabindex=&quot;-1&quot;&gt;What’s Next&lt;/h2&gt;
&lt;p&gt;
  In the demo I included an output to show the render time of the last frame. I get around
  5.5ms in Chrome on my Mac Studio with an M2 Max. Firefox gets around 18.5ms and Safari
  around 9ms. I find this performance a little disappointing considering I feel like I have
  optimized things as much as I reasonably can. It makes me wonder if I should skip to
  targeting Web Assembly earlier than I was planning. I would like to keep the demos
  interactive in a real-time sort of way. Parallelization will help, but only so much on
  older devices with fewer CPU cores. Maybe now is the time…
&lt;/p&gt;
&lt;section class=&quot;footnotes section-separator&quot;&gt;
  &lt;ol class=&quot;footnotes-list&quot;&gt;
    &lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;
      &lt;p&gt;
        At the time of writing this the issue with that page is that in the “Analytic
        Solution” section “equation 5” is a repeat of “equation 4”. It should actually be
        the
        &lt;a href=&quot;https://en.m.wikipedia.org/wiki/Quadratic_formula&quot;&gt;quadratic formula&lt;/a&gt;:
      &lt;/p&gt;
      &lt;math display=&quot;block&quot;&gt;
        &lt;mi&gt;x&lt;/mi&gt;
        &lt;mo&gt; = &lt;/mo&gt;
        &lt;mfrac&gt;
          &lt;mrow&gt;
            &lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;b&lt;/mi&gt;
            &lt;mo&gt;±&lt;/mo&gt;
            &lt;msqrt&gt;
              &lt;msup&gt;&lt;mi&gt;b&lt;/mi&gt;&lt;mn&gt;2&lt;/mn&gt;&lt;/msup&gt;
              &lt;mo&gt;−&lt;/mo&gt;
              &lt;mn&gt;4&lt;/mn&gt;&lt;mi&gt;a&lt;/mi&gt;&lt;mi&gt;c&lt;/mi&gt;
            &lt;/msqrt&gt;
          &lt;/mrow&gt;
          &lt;mrow&gt;
            &lt;mn&gt;2&lt;/mn&gt;&lt;mi&gt;a&lt;/mi&gt;
          &lt;/mrow&gt;
        &lt;/mfrac&gt;
      &lt;/math&gt;
      &lt;p&gt;
        Or, with the discriminant represented as
        &lt;math display=&quot;inline&quot;&gt;&lt;mi mathvariant=&quot;normal&quot;&gt;Δ&lt;/mi&gt;&lt;/math&gt;:
      &lt;/p&gt;
      &lt;math display=&quot;block&quot;&gt;
        &lt;mi&gt;x&lt;/mi&gt;
        &lt;mo&gt; = &lt;/mo&gt;
        &lt;mfrac&gt;
          &lt;mrow&gt;
            &lt;mo&gt;−&lt;/mo&gt;&lt;mi&gt;b&lt;/mi&gt;
            &lt;mo&gt;±&lt;/mo&gt;
            &lt;msqrt&gt;
              &lt;mi mathvariant=&quot;normal&quot;&gt;Δ&lt;/mi&gt;
            &lt;/msqrt&gt;
          &lt;/mrow&gt;
          &lt;mrow&gt;
            &lt;mn&gt;2&lt;/mn&gt;&lt;mi&gt;a&lt;/mi&gt;
          &lt;/mrow&gt;
        &lt;/mfrac&gt;
      &lt;/math&gt;
      &lt;p&gt;
        If you decide to dig this deep hopefully the above can save you the intense head
        scratching that I went through. &lt;a
          href=&quot;https://limulus.net/penumbra/journal/ray-sphere-interactions/#fnref1&quot;
          class=&quot;footnote-backref&quot;
        &gt;↩︎&lt;/a&gt;
      &lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/section&gt;
</content>
  </entry>
  <entry>
    <title>Chapters 2–4: Canvas and Matrices</title>
    <link href="https://limulus.net/penumbra/journal/canvas-and-matrices/" />
    <updated>2023-12-09T01:30:00Z</updated>
    <id>https://limulus.net/penumbra/journal/canvas-and-matrices/</id>
    <content type="html">&lt;p&gt;
  In the &lt;a href=&quot;https://limulus.net/penumbra/journal/tuples/&quot;&gt;previous post&lt;/a&gt; I went a
  little further than the exercise at the end of the chapter asked for and created a web
  component that exercised my tuple implementation and included animation of the projectile.
  As it turns out, this wound up being very similar to the exercise at the end of chapter 2,
  which is about implementing a canvas. So I decided to skip that exercise and continue onto
  the next two chapters which walk you through implementing various matrix math operations.
&lt;/p&gt;
&lt;h2 id=&quot;implementing-the-canvas-class&quot; tabindex=&quot;-1&quot;&gt;Implementing the Canvas Class&lt;/h2&gt;
&lt;p&gt;
  Implementing a canvas class when targeting a web runtime is perhaps unnecessary since
  &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/HTML/Element/canvas&quot;&gt;&lt;code
    &gt;&amp;lt;canvas&amp;gt;&lt;/code&gt;&lt;/a&gt; provides a solid 2D canvas JavaScript API. However, the book
  has you implement color functions for tuples containing floats so a canvas that stores
  colors with floats instead of integer values seems like it might be a better bet going
  forward. So I decided to implement my own &lt;a
    href=&quot;https://github.com/limulus/penumbra/blob/d32022d755967a75c3923a156490e18e4315bf17/src/lib/canvas.ts&quot;
  &gt;&lt;code&gt;Canvas&lt;/code&gt; class&lt;/a&gt; backed by a &lt;code&gt;Float32Array&lt;/code&gt;.
&lt;/p&gt;
&lt;p&gt;
  I went with 32-bit floats over the JavaScript-native 64-bit floats since I am still
  planning on porting this to &lt;a href=&quot;https://www.assemblyscript.org&quot;&gt;AssemblyScript&lt;/a&gt; to
  take advantage of the &lt;a
    href=&quot;https://github.com/WebAssembly/simd/blob/a78b98a6899c9e91a13095e560767af6e99d98fd/proposals/simd/SIMD.md&quot;
  &gt;v128 SIMD operations&lt;/a&gt; in WebAssembly. The “128” in “v128” implies you can either have
  an SIMD instruction operate either on 4 32-bit floats or 2 64-bit floats.
  Four-times-faster is better than two-times-faster. And based on a bit of research the
  extra precision is usually not needed or at least easy to avoid needing.
&lt;/p&gt;
&lt;p&gt;
  Using a &lt;a
    href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray&quot;
  &gt;&lt;code&gt;TypedArray&lt;/code&gt;&lt;/a&gt; also opens the doors to backing a canvas with a
  &lt;a
    href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer&quot;
  &gt;&lt;code&gt;SharedArrayBuffer&lt;/code&gt;&lt;/a&gt; or something similar. I can imagine this being useful
  by having the ray tracer running in many WebWorkers, all updating a shared canvas.
&lt;/p&gt;
&lt;p&gt;There’s a bit of a snag with &lt;code&gt;SharedArrayBuffer&lt;/code&gt; however…&lt;/p&gt;
&lt;h3 id=&quot;a-side-quest-to-move-away-from-github-pages&quot; tabindex=&quot;-1&quot;&gt;
  A Side Quest to Move Away From GitHub Pages
&lt;/h3&gt;
&lt;p&gt;
  In response to the &lt;a
    href=&quot;https://en.wikipedia.org/wiki/Spectre_(security_vulnerability)&quot;
  &gt;Spectre vulnerability&lt;/a&gt;, browser vendors updated the &lt;code&gt;SharedArrayBuffer&lt;/code&gt;
  constructor to throw so that it could not be abused until they had a fix. The fix they
  ultimately adopted requires sending &lt;a
    href=&quot;https://hacks.mozilla.org/2020/07/safely-reviving-shared-memory/&quot;
  &gt;two HTTP headers&lt;/a&gt; with your HTML document. Well, you can’t set HTTP headers on GitHub
  Pages, where I was previously hosting this site.
&lt;/p&gt;
&lt;p&gt;
  I always planned on moving this site to my personal website, &lt;a
    href=&quot;https://limulus.net/&quot;
  &gt;limulus.net&lt;/a&gt;. But my setup for limulus.net is very out-of-date. I have a GitHub
  repository for it but deployment is no longer automated. I just manually upload any
  changes to S3. None of the other infrastructure for it like the CloudFront distribution
  has been turned into CloudFormation templates so it’s all just sitting in AWS resources
  without any version control. I wanted to avoid adding to that mess for now by publishing
  to GitHub Pages.
&lt;/p&gt;
&lt;p&gt;
  Even though I know &lt;code&gt;SharedArrayBuffer&lt;/code&gt; may not be how I ultimately choose to
  implement things I also didn’t want to be in the situation where I am forced into
  switching away from GitHub Pages in the middle of the project instead of early on. In the
  (ok, unlikely) event that anyone was subscribed to the &lt;a
    href=&quot;https://limulus.net/feed.xml&quot;
  &gt;RSS feed&lt;/a&gt; setting up redirects on GitHub Pages for that might be tricky. Better to
  just get it out of the way as soon as possible.
&lt;/p&gt;
&lt;p&gt;
  In a bid to get things done though I resisted the urge to write CloudFormation templates
  for everything, so unfortunately I have added to my AWS technical debt. However I did
  spend the time set things up in the new ways AWS recommends: I’m using &lt;a
    href=&quot;https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services&quot;
  &gt;GitHub’s OIDC provider&lt;/a&gt; to get temporary AWS credentials for the GitHub Action that
  publishes this site and I avoided setting up the S3 bucket to use public website mode. I
  learned that to get CloudFront to serve &lt;code&gt;index.html&lt;/code&gt; files for directories
  served from a private S3 origin you need to write a &lt;a
    href=&quot;https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cloudfront-functions.html&quot;
  &gt;CloudFront Function&lt;/a&gt; to rewrite the request. So unfortunately that means I now have a
  tiny bit of code for hosting this site that is not version controlled. But at least now I
  know how to set these things up in a more secure way.
&lt;/p&gt;
&lt;h2 id=&quot;implementing-the-matrix-class&quot; tabindex=&quot;-1&quot;&gt;Implementing the Matrix Class&lt;/h2&gt;
&lt;p&gt;
  There’s only a few things particularly interesting about the implementation of my &lt;a
    href=&quot;https://github.com/limulus/penumbra/blob/d32022d755967a75c3923a156490e18e4315bf17/src/lib/matrix.ts&quot;
  &gt;&lt;code&gt;Matrix&lt;/code&gt;
    class&lt;/a&gt;.
&lt;/p&gt;
&lt;h3 id=&quot;a-surprise-subclass&quot; tabindex=&quot;-1&quot;&gt;A Surprise Subclass&lt;/h3&gt;
&lt;p&gt;
  It likely should not have come as a surprise that the &lt;code&gt;Tuple&lt;/code&gt; implementation
  would need to be treated as a matrix when doing matrix math operations. In fact, tuples
  need to be treated as matrixes of four rows, which is not my intuition about how to
  conceptualize an array of four items. It was seeming like I was going to need special
  handling in my &lt;code&gt;Matrix&lt;/code&gt; class to account for whenever it was passed a &lt;code
  &gt;Tuple&lt;/code&gt; and that felt messy. The solution I landed on was to create a &lt;code
  &gt;TwoDimensionalArray&lt;/code&gt; class that would act as the base class for both the
  &lt;code&gt;Tuple&lt;/code&gt; and &lt;code&gt;Matrix&lt;/code&gt; classes. This way, the Tuple class can
  construct itself with 1 column and 4 rows and the &lt;code&gt;Matrix&lt;/code&gt; class doesn’t have
  to treat &lt;code&gt;Tuple&lt;/code&gt;s as special cases.
&lt;/p&gt;
&lt;p&gt;
  This kind of refactor is definitely where having a robust test suite (in this case
  provided by the book) shines. I had confidence in a relatively substantial refactor
  without any added effort.
&lt;/p&gt;
&lt;h3 id=&quot;chaining-matrix-transformations&quot; tabindex=&quot;-1&quot;&gt;Chaining Matrix Transformations&lt;/h3&gt;
&lt;p&gt;
  While I won’t pretend to understand the reasons why (maybe I knew back when I took linear
  algebra?) if you want a transformation matrix to have multiple transformations you have to
  multiply them in reverse order. In other words, if you want a matrix that you can use to
  do a translation, then a rotation, then a scaling up, you need to first multiply the
  scaling matrix by the rotation matrix, and then the result by the translation matrix. The
  books suggests that you implement a “fluent” API of chainable methods that takes care of
  this for you. For example:
&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; twoOClock = &lt;span class=&quot;hljs-title class_&quot;&gt;Matrix&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;transformation&lt;/span&gt;()
  .&lt;span class=&quot;hljs-title function_&quot;&gt;translate&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;1&lt;/span&gt;, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;)
  .&lt;span class=&quot;hljs-title function_&quot;&gt;rotateZ&lt;/span&gt;(-(&lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; / &lt;span class=&quot;hljs-number&quot;&gt;12&lt;/span&gt;) * &lt;span class=&quot;hljs-number&quot;&gt;2&lt;/span&gt; * &lt;span class=&quot;hljs-title class_&quot;&gt;Math&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;PI&lt;/span&gt;)
  .&lt;span class=&quot;hljs-title function_&quot;&gt;scale&lt;/span&gt;(clockRadius, -clockRadius, &lt;span class=&quot;hljs-number&quot;&gt;0&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
  What I’ve seen frequently in JS APIs is that they often require something like a final
  &lt;code&gt;.done()&lt;/code&gt; method to perform the final calculations and produce the end result
  of the chain of operations. However, there is a way around this if you can structure your
  class to have the first attempt to read the values of the returned object do the
  finalization.
&lt;/p&gt;
&lt;p&gt;
  Here’s how that works with my &lt;code&gt;Matrix&lt;/code&gt; class. The following is a selection of
  methods that demonstrate it. The &lt;code&gt;.translate()&lt;/code&gt;, &lt;code&gt;.rotateZ()&lt;/code&gt;, and
  &lt;code&gt;scale()&lt;/code&gt; methods in the example above all call &lt;code&gt;.#pushOperation()&lt;/code&gt;
  to push their operation onto the &lt;code&gt;#operationStack&lt;/code&gt; array and return &lt;code
  &gt;this&lt;/code&gt;.
&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;hljs&quot;&gt;&lt;span class=&quot;hljs-keyword&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Matrix&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;hljs-title class_ inherited__&quot;&gt;TwoDimensionalArray&lt;/span&gt; {
  &lt;span class=&quot;hljs-keyword&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;transformation&lt;/span&gt;(&lt;span class=&quot;hljs-params&quot;&gt;&lt;/span&gt;) {
    &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; chainable = &lt;span class=&quot;hljs-title class_&quot;&gt;Matrix&lt;/span&gt;.&lt;span class=&quot;hljs-title function_&quot;&gt;identity&lt;/span&gt;(&lt;span class=&quot;hljs-number&quot;&gt;4&lt;/span&gt;)
    chainable.#operationStack = []
    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; chainable
  }

  #operationStack?: &lt;span class=&quot;hljs-title class_&quot;&gt;Matrix&lt;/span&gt;[]

  &lt;span class=&quot;hljs-keyword&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;hljs-title function_&quot;&gt;values&lt;/span&gt;() {
    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (&lt;span class=&quot;hljs-variable language_&quot;&gt;this&lt;/span&gt;.#operationStack) {
      &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; operationStack = &lt;span class=&quot;hljs-variable language_&quot;&gt;this&lt;/span&gt;.#operationStack
      &lt;span class=&quot;hljs-variable language_&quot;&gt;this&lt;/span&gt;.#operationStack = &lt;span class=&quot;hljs-literal&quot;&gt;undefined&lt;/span&gt;
      &lt;span class=&quot;hljs-keyword&quot;&gt;const&lt;/span&gt; result = operationStack.&lt;span class=&quot;hljs-title function_&quot;&gt;reduceRight&lt;/span&gt;(
        &lt;span class=&quot;hljs-function&quot;&gt;(&lt;span class=&quot;hljs-params&quot;&gt;result, operation&lt;/span&gt;) =&amp;gt;&lt;/span&gt; result.&lt;span class=&quot;hljs-title function_&quot;&gt;mul&lt;/span&gt;(operation),
        &lt;span class=&quot;hljs-variable language_&quot;&gt;this&lt;/span&gt;
      )
      &lt;span class=&quot;hljs-variable language_&quot;&gt;super&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;values&lt;/span&gt; = result.&lt;span class=&quot;hljs-property&quot;&gt;values&lt;/span&gt;
    }
    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-variable language_&quot;&gt;super&lt;/span&gt;.&lt;span class=&quot;hljs-property&quot;&gt;values&lt;/span&gt;
  }

  #&lt;span class=&quot;hljs-title function_&quot;&gt;pushOperation&lt;/span&gt;(&lt;span class=&quot;hljs-attr&quot;&gt;operation&lt;/span&gt;: &lt;span class=&quot;hljs-title class_&quot;&gt;Matrix&lt;/span&gt;): &lt;span class=&quot;hljs-variable language_&quot;&gt;this&lt;/span&gt; {
    &lt;span class=&quot;hljs-keyword&quot;&gt;if&lt;/span&gt; (!&lt;span class=&quot;hljs-variable language_&quot;&gt;this&lt;/span&gt;.#operationStack) {
      &lt;span class=&quot;hljs-keyword&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;hljs-keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;hljs-title class_&quot;&gt;Error&lt;/span&gt;(&lt;span class=&quot;hljs-string&quot;&gt;&amp;#x27;Attempted to push operation to non-chainable matrix&amp;#x27;&lt;/span&gt;)
    }
    &lt;span class=&quot;hljs-variable language_&quot;&gt;this&lt;/span&gt;.#operationStack.&lt;span class=&quot;hljs-title function_&quot;&gt;push&lt;/span&gt;(operation)
    &lt;span class=&quot;hljs-keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;hljs-variable language_&quot;&gt;this&lt;/span&gt;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id=&quot;demo&quot; tabindex=&quot;-1&quot;&gt;The Demo: &lt;code&gt;&amp;lt;pixel-clock&amp;gt;&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;
  The end-of-chapter exercise for chapter 5 is to use your matrix and canvas implementation
  to color in a pixel for every hour of a 12 hour analog clock. I did two things I really
  didn’t have to for this exercise: add animated “hands” and perform the rendering in a &lt;a
    href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API&quot;
  &gt;Web Worker&lt;/a&gt;.
&lt;/p&gt;
&lt;div&gt;
  &lt;pixel-clock-demo&gt;
    &lt;noscript&gt;
      &lt;p&gt;&lt;em&gt;View this dynamic content on the website with JavaScript enabled.&lt;/em&gt;&lt;/p&gt;
    &lt;/noscript&gt;
    &lt;script&gt;
    // Ensure that syndicated copies of this content don’t show a &quot;Loading…&quot; message. This is
  // necessary because some feed readers try to execute JavaScript.
  const firstPartyHosts = [&#39;limulus.net&#39;, &#39;localhost&#39;, &#39;127.0.0.1&#39;]
  if (firstPartyHosts.some((host) =&gt; window.location.host.includes(host))) {
    document.write(&#39;&lt;p&gt;&lt;em&gt;Loading…&lt;/em&gt;&lt;/p&gt;&#39;)
  } else {
    document.write(&#39;&lt;p&gt;&lt;em&gt;View this dynamic content on the website with JavaScript enabled.&lt;/em&gt;&lt;/p&gt;&#39;)
  }
    &lt;/script&gt;
  &lt;/pixel-clock-demo&gt;
&lt;/div&gt;
&lt;p&gt;
  Now that I have some hands-on experience with Web Workers I expect to be able to offload
  the work of the ray tracer off the main thread, and possibly even parallelize the work
  into multiple workers.
&lt;/p&gt;
&lt;h2 id=&quot;up-next%3A-finally-casting-some-rays!&quot; tabindex=&quot;-1&quot;&gt;
  Up Next: Finally Casting Some Rays!
&lt;/h2&gt;
&lt;p&gt;
  Now that these fundamentals are out of the way and I’ve got this site hosted where I want
  it, there should be less of a delay until the next post. With any luck the next post will
  also not be quite as long!
&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Chapter 1: Tuples</title>
    <link href="https://limulus.net/penumbra/journal/tuples/" />
    <updated>2023-11-19T02:51:00Z</updated>
    <id>https://limulus.net/penumbra/journal/tuples/</id>
    <content type="html">&lt;p&gt;
  The first chapter of the book focuses on setting up a foundational “tuple” library for
  operations on vectors and points. I didn’t really expect there to be much to show for this
  other than working tests. But the chapter ended with a suggestion for creating a small
  program to experiment with a mini physics simulation that fires projectiles at various
  angles and velocities and have their trajectories effected by gravity and wind.
&lt;/p&gt;
&lt;p&gt;
  I decided to take this a step further and create a web component that would animate the
  projectile on a canvas. Here it is in action:
&lt;/p&gt;
&lt;div&gt;
  &lt;projectile-cannon-demo&gt;
    &lt;noscript&gt;
      &lt;p&gt;&lt;em&gt;View this dynamic content on the website with JavaScript enabled.&lt;/em&gt;&lt;/p&gt;
    &lt;/noscript&gt;
    &lt;script&gt;
    // Ensure that syndicated copies of this content don’t show a &quot;Loading…&quot; message. This is
  // necessary because some feed readers try to execute JavaScript.
  const firstPartyHosts = [&#39;limulus.net&#39;, &#39;localhost&#39;, &#39;127.0.0.1&#39;]
  if (firstPartyHosts.some((host) =&gt; window.location.host.includes(host))) {
    document.write(&#39;&lt;p&gt;&lt;em&gt;Loading…&lt;/em&gt;&lt;/p&gt;&#39;)
  } else {
    document.write(&#39;&lt;p&gt;&lt;em&gt;View this dynamic content on the website with JavaScript enabled.&lt;/em&gt;&lt;/p&gt;&#39;)
  }
    &lt;/script&gt;
  &lt;/projectile-cannon-demo&gt;
&lt;/div&gt;
&lt;p&gt;
  I attempted to represent the &lt;math display=&quot;inline&quot;&gt;&lt;mi&gt;z&lt;/mi&gt;&lt;/math&gt; axis by
  increasing/decreasing the size of the projectile. Something seems off with that though.
&lt;/p&gt;
&lt;p&gt;
  GitHub Copilot was helpful when writing the &lt;a
    href=&quot;https://github.com/limulus/penumbra/blob/420867ab2c91f8bf42a4fa0e49cb4e927de9dbeb/src/lib/Tuple.spec.ts&quot;
  &gt;tuple tests&lt;/a&gt;. I could take the Gherkin test from the book, put it in a comment, and
  Copilot would generate the test code using the
  &lt;a
    href=&quot;https://github.com/limulus/penumbra/blob/420867ab2c91f8bf42a4fa0e49cb4e927de9dbeb/src/gherkin.ts&quot;
  &gt;Gherkin-inspired test suite functions&lt;/a&gt; I wrote.
&lt;/p&gt;
&lt;h2 id=&quot;looking-ahead&quot; tabindex=&quot;-1&quot;&gt;Looking Ahead&lt;/h2&gt;
&lt;p&gt;
  One thing that pained me as I wrote the implementation of the &lt;a
    href=&quot;https://github.com/limulus/penumbra/blob/420867ab2c91f8bf42a4fa0e49cb4e927de9dbeb/src/lib/Tuple.ts&quot;
  &gt;Tuple methods&lt;/a&gt; was knowing how inefficient they will be running in a JavaScript
  runtime. Vector math is the usual use case for [SIMD] instructions, but presumably
  JavaScript engines are not detecting that these operations could be compiled to SIMD
  instructions. I did a bit of forward research though and discovered that &lt;a
    href=&quot;https://webassembly.org/&quot;
  &gt;WebAssembly&lt;/a&gt; has SIMD support! At some point I plan to look at reimplementing Penumbra
  in &lt;a href=&quot;https://www.assemblyscript.org/&quot;&gt;AssemblyScript&lt;/a&gt; — but I first want a plain
  JavaScript baseline to compare against.
&lt;/p&gt;
&lt;p&gt;Onward to chapter 2!&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>One More Yak to Shave</title>
    <link href="https://limulus.net/penumbra/journal/one-more-yak/" />
    <updated>2023-11-11T22:20:00Z</updated>
    <id>https://limulus.net/penumbra/journal/one-more-yak/</id>
    <content type="html">&lt;p&gt;
  The site is getting published. The CSS needs work. Now it’s time to try and get an
  in-browser test runner working. For this I have two goals:
&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;I should be able to take the Gherkin tests from the book and easily use them&lt;/li&gt;
  &lt;li&gt;The tests should be a part of this site&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
  Initially I was thinking that I would use the Gherkin tests directly from the book — by
  using some existing tool to parse them and provide hooks for wiring up the steps. But I’m
  not really finding anything like that out there. I found &lt;a
    href=&quot;https://github.com/hyperjump-io/json-schema/blob/0d9b0fec778dfd46e4136987f03b9fcf0147ea39/lib/mocha-gherkin.spec.ts&quot;
  &gt;this approach&lt;/a&gt;
  which defines functions for each of the Gherkin prefixes, maps them to Mocha functions,
  which seems like a better approach.
&lt;/p&gt;
&lt;p&gt;
  &lt;a href=&quot;https://mochajs.org/&quot;&gt;Mocha&lt;/a&gt; also seems like a good choice for the test
  runner. And after a decent amount of trial and error I got it working how I want. I even
  got Eleventy’s dev server to reload the page when the code changes, which will be nice for
  development.
&lt;/p&gt;
&lt;p&gt;Remaining yak shaving tasks:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Set up an RSS feed for this blog&lt;/li&gt;
  &lt;li&gt;Redo site styles&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
  But at this point I would rather get started on the first test. This stuff has taken up
  way too much time already.
&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Getting Nerd Sniped</title>
    <link href="https://limulus.net/penumbra/journal/nerd-sniped/" />
    <updated>2023-10-31T22:52:00Z</updated>
    <id>https://limulus.net/penumbra/journal/nerd-sniped/</id>
    <content type="html">&lt;p&gt;
  The way &lt;a href=&quot;https://pragprog.com/titles/jbtracer/the-ray-tracer-challenge/&quot;
  &gt;The Ray Tracer Challenge&lt;/a&gt; starts is refreshing. The “Getting Started” section doesn’t
  spend time on any development environment setup. Instead it is a simple introduction to
  the &lt;a href=&quot;https://cucumber.io/docs/gherkin/&quot;&gt;Gherkin&lt;/a&gt; syntax then a notes on some
  typical pitfalls. Then the first chapter gives a brief introduction to points and vectors
  and throws its first test at you. It doesn’t even remind you that you need to choose a
  language.
&lt;/p&gt;
&lt;p&gt;
  I thought about what I wanted to use for my implementation. I could have chosen this as a
  way to introduce myself to a new language, but I decided to initially go with something I
  was familiar with: TypeScript compiled to JavaScript running in the browser. This way I
  could focus on the ray tracer itself and demos would be easy to share. After some research
  I also concluded that there is runway for performance enhancements like WebAssembly, WebGL
  and WebGPU.
&lt;/p&gt;
&lt;p&gt;
  Unfortunately this raises lots of questions that all have to get addressed before I even
  get started!
&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;What would I name the project?&lt;/li&gt;
  &lt;li&gt;Where will I publish the site?&lt;/li&gt;
  &lt;li&gt;What will I use to build the site?&lt;/li&gt;
  &lt;li&gt;
    What test runner will I use? (My usual choice, Jest is great for a JSDOM environment,
    but that won’t work for advanced web features.)
  &lt;/li&gt;
  &lt;li&gt;How do I hook up the Gherkin tests from the book to my test runner?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
  For the name after some poking around on Wikipedia I settled on “Penumbra”. There’s
  probably some better names I could have chosen, but I couldn’t find any other ray tracers
  with that name already.
&lt;/p&gt;
&lt;p&gt;
  Deciding on where to publish the site was pretty straightforward. My &lt;a
    href=&quot;https://limulus.net/&quot;
  &gt;personal site&lt;/a&gt; would make sense, but it’s all tied up with its own repository. I also
  don’t have any static site generator for it. My &lt;a href=&quot;https://unallocated.com/&quot;
  &gt;professional site&lt;/a&gt; does have a static site generator (&lt;a href=&quot;https://gohugo.io/&quot;
  &gt;Hugo&lt;/a&gt;) but I couldn’t convince myself it was an appropriate place for this project. So
  I decided to create a new repository for the project and use &lt;a
    href=&quot;https://pages.github.com/&quot;
  &gt;GitHub Pages&lt;/a&gt; to publish it.
&lt;/p&gt;
&lt;p&gt;
  My past experience with Hugo was alright, but Go template syntax kinda irks me. So I
  decided to give &lt;a href=&quot;https://jekyllrb.com/&quot;&gt;Jekyll&lt;/a&gt; a try, seeing as how it is the
  default for GitHub Pages. This was the first real &lt;a href=&quot;https://xkcd.com/356/&quot;
  &gt;nerd snipe&lt;/a&gt;.&lt;sup class=&quot;footnote-ref&quot;&gt;&lt;a
      href=&quot;https://limulus.net/penumbra/journal/nerd-sniped/#fn1&quot;
      id=&quot;fnref1&quot;
    &gt;[1]&lt;/a&gt;&lt;/sup&gt; Jekyll is written in Ruby, and I figured I could just install the gem in
  my project. Unfortunately by default Ruby’s &lt;code&gt;bundle&lt;/code&gt; tool does not by default
  install gems in the project directory like I expect a package manager to work in this
  decade. It’s possible to get it to work like this, but after frustration with current
  documentation on how to do it not matching the version of Ruby that macOS ships with I
  decided to try to do my development in a devcontainer. I got that working but wasn’t
  really happy with having to run Docker locally just for this project.
&lt;/p&gt;
&lt;p&gt;
  After going back to the drawing board I started researching other static site generators.
  That’s when I came across &lt;a href=&quot;https://www.11ty.dev/&quot;&gt;Eleventy&lt;/a&gt;, which is a fast
  Node.js based site generator. I actually had known about it for a number of months, but
  had completely forgotten about it. So now that is what I am setting up and is what this
  site is using.
&lt;/p&gt;
&lt;p&gt;
  Now of course I am getting nerd sniped trying to figure out how to use Eleventy and
  general web design things:
&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;
    Why are &lt;a href=&quot;https://www.11ty.dev/docs/languages/webc/&quot;&gt;WebC&lt;/a&gt; templates not
    working like I expect?
  &lt;/li&gt;
  &lt;li&gt;How do I get a list of blog posts to show up on the home page?&lt;/li&gt;
  &lt;li&gt;How do I get footnotes in a Markdown file to get rendered?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
  I’ve managed to work through these now, but I’ve run into issues with Eleventy’s dev
  server not updating when it should and mysterious issues with the &lt;code&gt;webc:keep&lt;/code&gt;
  attribute in bundling mode. This has me wondering if my plan for using Eleventy’s dev
  server for development will work out. But that will have to be the next entry…
&lt;/p&gt;
&lt;section class=&quot;footnotes section-separator&quot;&gt;
  &lt;ol class=&quot;footnotes-list&quot;&gt;
    &lt;li id=&quot;fn1&quot; class=&quot;footnote-item&quot;&gt;
      &lt;p&gt;
        Because I have a an overly complicated project creation utility for personal
        TypeScript projects I always wind up starting a project by refreshing the
        dependencies for that utility. This time that led me to discovering that &lt;a
          href=&quot;https://www.nodegit.org&quot;
        &gt;node-git&lt;/a&gt; has stagnated and is no longer providing up-to-date pre-compiled
        binaries for the latest versions of Node. This results in 3-6 minutes of compile
        time when installing node-git. Yikes! That’s a lot for a CLI utility that is
        supposed to be run via &lt;code&gt;npm create&lt;/code&gt;. So I decided to spend the time to
        switch it over to &lt;a href=&quot;https://github.com/steveukx/git-js&quot;&gt;simple-git&lt;/a&gt; which
        is pure JavaScript and doesn’t require any compilation. Thankfully I had written
        tests for the git functionality which did not mock out &lt;a
          href=&quot;https://www.nodegit.org&quot;
        &gt;node-git&lt;/a&gt; and so swapping out the library was straightforward. &lt;a
          href=&quot;https://limulus.net/penumbra/journal/nerd-sniped/#fnref1&quot;
          class=&quot;footnote-backref&quot;
        &gt;↩︎&lt;/a&gt;
      &lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/section&gt;
</content>
  </entry>
</feed>