<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Homepage on </title>
    <link>https://wizardlog.com/</link>
    <description>Recent content in Homepage on </description>
    <generator>Hugo</generator>
    <language>en-us</language>
    <lastBuildDate>Sun, 27 Sep 2026 16:54:36 +1000</lastBuildDate>
    <atom:link href="https://wizardlog.com/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Dsheet: Beyond the PDF</title>
      <link>https://wizardlog.com/posts/dsheet-beyond-the-pdf/</link>
      <pubDate>Sun, 27 Sep 2026 16:54:36 +1000</pubDate>
      <guid>https://wizardlog.com/posts/dsheet-beyond-the-pdf/</guid>
      <description>&lt;h1 id=&#34;dsheet-beyond-the-pdf&#34;&gt;DSheet: Beyond the PDF&lt;/h1&gt;&#xA;&#xA;&#xA;&#xA;&#xA;  &#xA;  &#xA;&#xA;  &#xA;  &#xA;  &#xA;&#xA;  &lt;details class=&#34;img-block&#34;&gt;&#xA;    &lt;summary data-size=&#34;60kB&#34;&gt;&#xA;      &lt;img class=&#34;preview&#34;&#xA;           src=&#34;data:image/webp;base64,UklGRlgAAABXRUJQVlA4IEwAAABwAwCdASoZABAAP3GYvEyqJSMhMAgBRi4J6QAAettipwqQuQAA/uwJ8&amp;#43;ohTTZpvwD5&amp;#43;nxBeGGPjEPo8xNvCYjWiEija4gi1mmIAAAA&#34;&#xA;           width=&#34;1200&#34;&#xA;           height=&#34;773&#34;&#xA;           alt=&#34;preview&#34;&#xA;           decoding=&#34;async&#34;&gt;&#xA;    &lt;/summary&gt;&#xA;&#xA;    &lt;img class=&#34;full&#34;&#xA;         src=&#34;https://wizardlog.com/images/dsheetreduction_hu_af683919fe9cf777.webp&#34;&#xA;         width=&#34;1200&#34;&#xA;         height=&#34;773&#34;&#xA;         alt=&#34;full image&#34;&#xA;         loading=&#34;lazy&#34;&#xA;         decoding=&#34;async&#34;&gt;&#xA;  &lt;/details&gt;&#xA;&#xA;&#xA;&lt;p&gt;Engineering datasheets are a fundamental source of component information, but PDF is designed primarily as a document interchange and presentation format. For an engineering platform that needs to index, query, and reference information inside thousands of datasheets, I wanted more control over how these documents are stored and accessed.&lt;/p&gt;&#xA;&lt;p&gt;I developed Dsheet, a purpose-built document format for engineering datasheets. The conversion pipeline extracts the document&amp;rsquo;s text, SVGs, images, fonts, and page structure and reconstructs them into a compact binary representation. Deduplicated images and data can be reduced to one refrence source and images can be transcoded into more efficient formats such as WebP.&lt;/p&gt;</description>
    </item>
    <item>
      <title>The Halo Array: A Concept for a Highly Isolated Computer System</title>
      <link>https://wizardlog.com/posts/the-halo-array-architecture/</link>
      <pubDate>Wed, 23 Sep 2026 16:54:36 +1000</pubDate>
      <guid>https://wizardlog.com/posts/the-halo-array-architecture/</guid>
      <description>&lt;h1 id=&#34;the-halo-array-a-concept-for-a-highly-isolated-computer-system&#34;&gt;The Halo Array: A Concept for a Highly Isolated Computer System&lt;/h1&gt;&#xA;&#xA;&#xA;&#xA;&#xA;  &#xA;  &#xA;&#xA;  &#xA;  &#xA;  &#xA;&#xA;  &lt;details class=&#34;img-block&#34;&gt;&#xA;    &lt;summary data-size=&#34;82kB&#34;&gt;&#xA;      &lt;img class=&#34;preview&#34;&#xA;           src=&#34;data:image/webp;base64,UklGRrwAAABXRUJQVlA4WAoAAAAQAAAAGAAAEQAAQUxQSCoAAAABL0CYbeTPuN&amp;#43;B9DQiIp4BNY2kQMcngOCA4F/mtrQR/Z&amp;#43;AaZom6i&amp;#43;4pQVWUDggbAAAAPADAJ0BKhkAEgA/cazIWKomJCGoCAFGLgnAGVaBsYgCuuJmQ/v9qMAA/tOVi5&amp;#43;kes4KqfdzRlR67awSsXConoX51QBOE4Ed1L7redASaP3zq6IslPYP2T6YfK6h6TuBvnoOsjfkEp2MclAAAA==&#34;&#xA;           width=&#34;1200&#34;&#xA;           height=&#34;867&#34;&#xA;           alt=&#34;preview&#34;&#xA;           decoding=&#34;async&#34;&gt;&#xA;    &lt;/summary&gt;&#xA;&#xA;    &lt;img class=&#34;full&#34;&#xA;         src=&#34;https://wizardlog.com/images/overview_hu_7c166f4eb135f01.webp&#34;&#xA;         width=&#34;1200&#34;&#xA;         height=&#34;867&#34;&#xA;         alt=&#34;full image&#34;&#xA;         loading=&#34;lazy&#34;&#xA;         decoding=&#34;async&#34;&gt;&#xA;  &lt;/details&gt;&#xA;&#xA;&#xA;&lt;p&gt;This was an idea I had one afternoon while thinking about how I would design a computer system capable of handling increasingly complex cyberattacks. The basic idea is to build the computer environment in layers, with each layer providing another opportunity to isolate, observe, or stop an attack before it can move further through the system.&lt;/p&gt;&#xA;&lt;p&gt;I started thinking about attacks as a rough progression:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Building a 3kB render</title>
      <link>https://wizardlog.com/posts/3d-render/</link>
      <pubDate>Mon, 21 Sep 2026 16:54:36 +1000</pubDate>
      <guid>https://wizardlog.com/posts/3d-render/</guid>
      <description>&lt;p&gt;&lt;span style=&#34;&#xA;color: var(--text);&#xA;padding: 0.2em 0.4em;&#xA;font-weight: bold;&#xA;font-size: 2.2em;&#xA;&#34;&gt;&#xA;Building a 3kB render&lt;/p&gt;&#xA;&lt;style&gt; .pmesh-viewer-container { width: 95%; max-width: 1400px; height: 700px; margin: 2.5rem auto; background: #202020; border: 1px solid #444; border-radius: 4px; overflow: hidden; } .pmesh-viewer { display: block; width: 100%; height: 100%; } .pmesh-lazy { position: relative; } .pmesh-placeholder { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; background: radial-gradient( circle at center, #303030 0%, #202020 70% ); } .pmesh-load-button { padding: .9rem 1.4rem; border: 1px solid #666; border-radius: 5px; background: #303030; color: #eee; font: inherit; cursor: pointer; transition: background .15s ease, border-color .15s ease, transform .15s ease; } .pmesh-load-button:hover { background: #3b3b3b; border-color: #888; transform: translateY(-1px); } .pmesh-error { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; color: #d88; }&#xA;&#xA;&lt;/style&gt;&#xA;&lt;script src=&#34;https://wizardlog.com/pmesh/pmesh-viewer.minmax.js&#34;&gt;&lt;/script&gt;&#xA;&lt;p&gt;&lt;strong&gt;Ceramic Capacitor&lt;/strong&gt;&#xA;  &lt;div class=&#34;pmesh-viewer-container&#34; id=&#34;pmesh-0&#34;&gt;  &lt;canvas class=&#34;pmesh-viewer&#34;&gt;&lt;/canvas&gt;  &lt;/div&gt; &lt;script&gt; (() =&gt; { const c = document.getElementById(&#34;pmesh-0&#34;); const init = canvas =&gt; { const r = new RendererV2(canvas); const resize = () =&gt; { canvas.width = canvas.clientWidth; canvas.height = canvas.clientHeight; r.resize(); }; addEventListener(&#34;resize&#34;, resize); resize(); fetch(&#34;\/models\/Ceramic Capacitor.pmesh&#34;) .then(x =&gt; { if (!x.ok) throw Error(`HTTP ${x.status}`); return x.blob(); }) .then(PMeshV2.load) .then(r.setMesh.bind(r)) .catch(console.error); };  init(c.querySelector(&#34;canvas&#34;));  })(); &lt;/script&gt;&#xA;&lt;/p&gt;</description>
    </item>
    <item>
      <title>The Storage Tile</title>
      <link>https://wizardlog.com/posts/modular-storage-grid-pcb/</link>
      <pubDate>Mon, 21 Sep 2026 16:54:36 +1000</pubDate>
      <guid>https://wizardlog.com/posts/modular-storage-grid-pcb/</guid>
      <description>&lt;p&gt;&lt;span style=&#34;&#xA;color: var(--text);&#xA;padding: 0.2em 0.4em;&#xA;font-weight: bold;&#xA;font-size: 2.2em;&#xA;&#34;&gt;&#xA;The Storage Tile&lt;/p&gt;&#xA;&lt;p&gt;Top view of brainboard&#xA;&#xA;&#xA;&#xA;&#xA;  &#xA;  &#xA;&#xA;  &#xA;  &#xA;  &#xA;&#xA;  &lt;details class=&#34;img-block&#34;&gt;&#xA;    &lt;summary data-size=&#34;58kB&#34;&gt;&#xA;      &lt;img class=&#34;preview&#34;&#xA;           src=&#34;data:image/webp;base64,UklGRmgAAABXRUJQVlA4IFwAAABwAwCdASoZAA4AP3GYvU0qJSMhMAgBRi4JwBhmgrq8wh/HboAA/lPsMpekrK66XINAeCNFmZc1AEluKdWZPfluSaH&amp;#43;8Z60FJKTLvCQPQpc5Vwi4NR1gO0SNcAAAA==&#34;&#xA;           width=&#34;1200&#34;&#xA;           height=&#34;650&#34;&#xA;           alt=&#34;preview&#34;&#xA;           decoding=&#34;async&#34;&gt;&#xA;    &lt;/summary&gt;&#xA;&#xA;    &lt;img class=&#34;full&#34;&#xA;         src=&#34;https://wizardlog.com/images/Spring%20PCB_hu_77021dbc719668e4.webp&#34;&#xA;         width=&#34;1200&#34;&#xA;         height=&#34;650&#34;&#xA;         alt=&#34;full image&#34;&#xA;         loading=&#34;lazy&#34;&#xA;         decoding=&#34;async&#34;&gt;&#xA;  &lt;/details&gt;&#xA;&#xA;&lt;/p&gt;&#xA;&lt;p&gt;I had a problem with storing and organising the tools and electronic parts in my workshop, so I decided to design my own modular automatic storage system. The idea is to create a grid of small, interconnected storage modules that can keep track of where items are stored and help locate them when needed.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Submersible Smart Power Distribution Unit (SPDU)</title>
      <link>https://wizardlog.com/posts/submersible-smart-power-distribution-unit-spdu/</link>
      <pubDate>Sun, 20 Sep 2026 16:54:36 +1000</pubDate>
      <guid>https://wizardlog.com/posts/submersible-smart-power-distribution-unit-spdu/</guid>
      <description>&lt;p&gt;&lt;span style=&#34;&#xA;color: var(--text);&#xA;padding: 0.2em 0.2em;&#xA;font-weight: bold;&#xA;font-size: 2.2em;&#xA;&#34;&gt;&#xA;Submersible Smart Power Distribution Unit (SPDU)&lt;/p&gt;&#xA;&#xA;&#xA;&#xA;&#xA;  &#xA;  &#xA;&#xA;  &#xA;  &#xA;  &#xA;&#xA;  &lt;details class=&#34;img-block&#34;&gt;&#xA;    &lt;summary data-size=&#34;62kB&#34;&gt;&#xA;      &lt;img class=&#34;preview&#34;&#xA;           src=&#34;data:image/webp;base64,UklGRqgAAABXRUJQVlA4IJwAAAAwBACdASoZAA4AP3GYu0yqJSMhMAgBRi4JwBjgv/wGBRctNdVrGtLnyoAA/nFQcMlkBCGaD6vPcDWSfrcugSz7n/nSRiOsCZ5vJswwrM7zvlYXCPOWzhQGL3H30Q/0J4DP891NncHZtIa/kzUrMeZl4F4m2kf2N2kIxn49H3K9u7pdrj3gnlkIjUMjEyS2M8jZCJkgnt0P6IzIAAA=&#34;&#xA;           width=&#34;1200&#34;&#xA;           height=&#34;675&#34;&#xA;           alt=&#34;preview&#34;&#xA;           decoding=&#34;async&#34;&gt;&#xA;    &lt;/summary&gt;&#xA;&#xA;    &lt;img class=&#34;full&#34;&#xA;         src=&#34;https://wizardlog.com/images/powerboard_hu_cb25b0ea532e8939.webp&#34;&#xA;         width=&#34;1200&#34;&#xA;         height=&#34;675&#34;&#xA;         alt=&#34;full image&#34;&#xA;         loading=&#34;lazy&#34;&#xA;         decoding=&#34;async&#34;&gt;&#xA;  &lt;/details&gt;&#xA;&#xA;&#xA;&lt;p&gt;The Submersible Smart Power Distribution Unit is a compact, ruggedized power management system engineered for harsh and water-exposed environments. Housed in a modified aluminium junction enclosure, the unit is purpose-built for submersion while maintaining full operational reliability and safety.&lt;/p&gt;&#xA;&lt;p&gt;Designed with durability and versatility in mind, the enclosure features four stainless steel external handles that serve multiple functions: enabling safe lifting and handling, acting as stable support legs for flexible placement, and providing elevated protection for all external components against impact and accidental damage.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Why I imposed a 14 kB limit on my website</title>
      <link>https://wizardlog.com/posts/small-websites/</link>
      <pubDate>Sun, 20 Sep 2026 16:54:36 +1000</pubDate>
      <guid>https://wizardlog.com/posts/small-websites/</guid>
      <description>&lt;h1&gt;&lt;/h1&gt;&#xA;&lt;p&gt;&lt;span style=&#34;&#xA;color: var(--text);&#xA;padding: 0.2em 0.4em;&#xA;font-weight: bold;&#xA;font-size: 2.2em;&#xA;&#34;&gt;Self-Imposed 14 kB Website Limit&lt;/p&gt;&#xA;&lt;p&gt;Designing a website to obey the 14kB rule &amp;amp; be fast&lt;/p&gt;&#xA;&lt;p&gt;After reading the endtimes devs write up on the 14kB rule I thought it would be interesting to apply that knowledge and make a test blog/site.&lt;/p&gt;&#xA;&lt;p&gt;The 14kB rule is for the first  transmission control protocol (TCP). The rule usually only apply to the HTML of a page put I thought why not push it for everything on the page. So the main components to consider on any page can be boiled down the simple building blocks, and we can build up from there.&lt;/p&gt;</description>
    </item>
    <item>
      <title>DIY geiger counter</title>
      <link>https://wizardlog.com/posts/geiger-counter/</link>
      <pubDate>Fri, 10 Apr 2026 16:54:36 +1000</pubDate>
      <guid>https://wizardlog.com/posts/geiger-counter/</guid>
      <description>&lt;h1&gt;&lt;/h1&gt;&#xA;&lt;p&gt;&lt;span style=&#34;&#xA;color: var(--text);&#xA;padding: 0.2em 0.4em;&#xA;font-weight: bold;&#xA;font-size: 2.2em;&#xA;&#34;&gt;&#xA;DIY Geiger counter&lt;/p&gt;&#xA;&#xA;&#xA;&#xA;&#xA;  &#xA;  &#xA;&#xA;  &#xA;  &#xA;  &#xA;&#xA;  &lt;details class=&#34;img-block&#34;&gt;&#xA;    &lt;summary data-size=&#34;32kB&#34;&gt;&#xA;      &lt;img class=&#34;preview&#34;&#xA;           src=&#34;data:image/webp;base64,UklGRnIAAABXRUJQVlA4IGYAAAAwBACdASoZAA4AP3GYvUyqJSMhMAgBRi4J6QAAUvyvQRX7xrmX6d3ZHUAAzeBOgdVNx05/PWyg8gwXKvJfxo7zvXdh/hU1ao84zGLvtUmzokLZjPBz4in5aNJszdM9NeOTFn4BAAA=&#34;&#xA;           width=&#34;1200&#34;&#xA;           height=&#34;675&#34;&#xA;           alt=&#34;preview&#34;&#xA;           decoding=&#34;async&#34;&gt;&#xA;    &lt;/summary&gt;&#xA;&#xA;    &lt;img class=&#34;full&#34;&#xA;         src=&#34;https://wizardlog.com/images/geigercounter1_hu_3b15aa57e845149b.webp&#34;&#xA;         width=&#34;1200&#34;&#xA;         height=&#34;675&#34;&#xA;         alt=&#34;full image&#34;&#xA;         loading=&#34;lazy&#34;&#xA;         decoding=&#34;async&#34;&gt;&#xA;  &lt;/details&gt;&#xA;&#xA;&#xA;&lt;hr&gt;&#xA;&#xA;&#xA;&#xA;&#xA;  &#xA;  &#xA;&#xA;  &#xA;  &#xA;  &#xA;&#xA;  &lt;details class=&#34;img-block&#34;&gt;&#xA;    &lt;summary data-size=&#34;36kB&#34;&gt;&#xA;      &lt;img class=&#34;preview&#34;&#xA;           src=&#34;data:image/webp;base64,UklGRnIAAABXRUJQVlA4IGYAAADQAwCdASoZAA4AP3GWvEyqJSMhMAgBRi4J6QAAPpZAw9Atd3falYAAzd/lt&amp;#43;3XKIDy1kwGMcjAZQd2QkzYXV4QFC39byxAziJ3uDDQIIT6SN1RjfTcRkGpNB5JpWFRVSHkAfjmYAA=&#34;&#xA;           width=&#34;1200&#34;&#xA;           height=&#34;675&#34;&#xA;           alt=&#34;preview&#34;&#xA;           decoding=&#34;async&#34;&gt;&#xA;    &lt;/summary&gt;&#xA;&#xA;    &lt;img class=&#34;full&#34;&#xA;         src=&#34;https://wizardlog.com/images/geigercounter2_hu_97e22e6c30c42e30.webp&#34;&#xA;         width=&#34;1200&#34;&#xA;         height=&#34;675&#34;&#xA;         alt=&#34;full image&#34;&#xA;         loading=&#34;lazy&#34;&#xA;         decoding=&#34;async&#34;&gt;&#xA;  &lt;/details&gt;&#xA;&#xA;&#xA;&#xA;&#xA;&#xA;&#xA;  &#xA;  &#xA;&#xA;  &#xA;  &#xA;  &#xA;&#xA;  &lt;details class=&#34;img-block&#34;&gt;&#xA;    &lt;summary data-size=&#34;51kB&#34;&gt;&#xA;      &lt;img class=&#34;preview&#34;&#xA;           src=&#34;data:image/webp;base64,UklGRqQAAABXRUJQVlA4IJgAAABwBACdASoZAA4AP3GYvEyqJSMhMAgBRi4J7ACdEf/iTVhxXjyiQF9glmxWgAD&amp;#43;Fd/Y3MJwZTrFbIAy3hNY/fGDBoRsN63qkLaPSUbr53FEutER2XF1m7Nhh4ZpTsuAcZ0&amp;#43;jaK1apPc9JaBUxR/mjlAhjiHMUUKOU5OVrQsN8erC3pwJy8A2X34yvpmsjBGjhHMOXbeszV4AA==&#34;&#xA;           width=&#34;1200&#34;&#xA;           height=&#34;675&#34;&#xA;           alt=&#34;preview&#34;&#xA;           decoding=&#34;async&#34;&gt;&#xA;    &lt;/summary&gt;&#xA;&#xA;    &lt;img class=&#34;full&#34;&#xA;         src=&#34;https://wizardlog.com/images/geigercounter3_hu_bf504351bdaf23c5.webp&#34;&#xA;         width=&#34;1200&#34;&#xA;         height=&#34;675&#34;&#xA;         alt=&#34;full image&#34;&#xA;         loading=&#34;lazy&#34;&#xA;         decoding=&#34;async&#34;&gt;&#xA;  &lt;/details&gt;</description>
    </item>
    <item>
      <title>About</title>
      <link>https://wizardlog.com/about/</link>
      <pubDate>Sat, 27 Sep 2025 16:50:42 +1000</pubDate>
      <guid>https://wizardlog.com/about/</guid>
      <description>&lt;h1 id=&#34;behind-the-mask&#34;&gt;Behind the mask&lt;/h1&gt;&#xA;&lt;style&gt;.pmesh-viewer-container{width:100%;max-width:80ch;height:350px;margin:1rem auto;position:relative;overflow:hidden;background:var(--bg)}.pmesh-viewer-container::before{content:&#34;&#34;;position:absolute;inset:15% 20%;background:radial-gradient(circle at center,color-mix(in srgb,var(--highlight) 35%,transparent),transparent 70%);pointer-events:none}.pmesh-viewer{display:block;width:100%;height:100%;position:relative;z-index:1}.pmesh-lazy{position:relative;width:100%;height:100%}.pmesh-placeholder{width:100%;height:100%;display:flex;align-items:center;justify-content:center;background:radial-gradient(circle at center,color-mix(in srgb,var(--highlight) 25%,transparent) 0%,transparent 65%);position:relative;z-index:1}.pmesh-load-button{padding:.7rem 1.1rem;border:1px solid var(--border);border-radius:3px;background:var(--bg);color:var(--text);font:inherit;cursor:pointer;transition:background .15s ease,border-color .15s ease,transform .15s ease}.pmesh-load-button:hover{background:var(--highlight);border-color:var(--text);transform:translateY(-1px)}.pmesh-error{width:100%;height:100%;display:flex;align-items:center;justify-content:center;color:var(--text);background:var(--bg)}&lt;/style&gt;&#xA;&lt;script&gt;const V=`#version 300 es&#xA;in vec3 p,n;uniform mat4 m,v,P;out vec3 N;out vec3 WP;void main(){vec4 w=m*vec4(p,1.);WP=w.xyz;N=mat3(m)*n;gl_Position=P*v*w;}`,F=`#version 300 es&#xA;precision highp float;in vec3 N;in vec3 WP;uniform vec3 l,l2,l3,l4,c;uniform float s,mode;out vec4 o;void main(){vec3 n=normalize(N),vd=normalize(vec3(0.,0.,1.));float ndv=max(dot(n,vd),0.),edge=pow(1.-ndv,3.5),rim=pow(1.-ndv,9.),d=max(dot(n,l),0.),d2=max(dot(n,l2),0.)*s,d3=max(dot(n,l3),0.)*.28,d4=max(dot(n,l4),0.)*.18,hv=pow(max(dot(n,normalize(l+vd)),0.),100.);if(mode&lt;.5){float b=.25+(d*.8+d2*.6)*1.3+pow(1.-d,3.)*.35;b=pow(smoothstep(0.,1.2,b),.9);float g=sin((n.x+n.z)*5.)*.16+.94;o=vec4(c*b*mix(.75,1.,b)*g*mix(vec3(1.),n*.5+.5,.2),1.);}else{float q=n.x*3.+n.y*2.+n.z*4.+edge*10.;vec3 rb=.5+.5*vec3(sin(q),sin(q+2.094),sin(q+4.188)),glass=vec3(.055,.075,.19);glass=mix(glass,rb,min(edge*1.45,1.));float front=pow(ndv,.65)*.32,light=.12+d*.25+d2*.15+d3+d4+front;glass*=light+.12;glass+=vec3(1.)*hv*1.8;glass+=rb*rim*1.5;glass+=vec3(.3,.5,1.)*edge*.55;float outline=smoothstep(.04,.22,edge);glass+=vec3(.55,.72,1.)*outline*.02;float alpha=clamp(.52+edge*.38+hv*.25+rim*.18,.42,.96);o=vec4(glass,alpha);}}`;class Shader{constructor(g){let q=(t,s)=&gt;{let x=g.createShader(t);g.shaderSource(x,s);g.compileShader(x);return x},p=g.createProgram(),a=q(g.VERTEX_SHADER,V),b=q(g.FRAGMENT_SHADER,F);g.attachShader(p,a);g.attachShader(p,b);g.linkProgram(p);g.deleteShader(a);g.deleteShader(b);this.p=p;this.m=g.getUniformLocation(p,&#34;m&#34;);this.v=g.getUniformLocation(p,&#34;v&#34;);this.P=g.getUniformLocation(p,&#34;P&#34;);this.l=g.getUniformLocation(p,&#34;l&#34;);this.l2=g.getUniformLocation(p,&#34;l2&#34;);this.l3=g.getUniformLocation(p,&#34;l3&#34;);this.l4=g.getUniformLocation(p,&#34;l4&#34;);this.s=g.getUniformLocation(p,&#34;s&#34;);this.c=g.getUniformLocation(p,&#34;c&#34;);this.mode=g.getUniformLocation(p,&#34;mode&#34;);this.ap=g.getAttribLocation(p,&#34;p&#34;);this.an=g.getAttribLocation(p,&#34;n&#34;)}}const persp=(f,a,n,r)=&gt;{let t=1/Math.tan(f/2),q=1/(n-r);return new Float32Array([t/a,0,0,0,0,t,0,0,0,0,(r+n)*q,-1,0,0,2*r*n*q,0])},mul=(a,b)=&gt;{let o=new Float32Array(16);for(let r=0;r&lt;4;r++)for(let c=0;c&lt;4;c++)o[c+r*4]=a[r*4]*b[c]+a[r*4+1]*b[c+4]+a[r*4+2]*b[c+8]+a[r*4+3]*b[c+12];return o},rotX=a=&gt;{let c=Math.cos(a),s=Math.sin(a);return new Float32Array([1,0,0,0,0,c,s,0,0,-s,c,0,0,0,0,1])},rotY=a=&gt;{let c=Math.cos(a),s=Math.sin(a);return new Float32Array([c,0,-s,0,0,1,0,0,s,0,c,0,0,0,0,1])},scale=s=&gt;new Float32Array([s,0,0,0,0,s,0,0,0,0,s,0,0,0,0,1]);class PMeshV2{static async load(f){let b=await f.arrayBuffer();b=await new Response(new Response(b).body.pipeThrough(new DecompressionStream(&#34;gzip&#34;))).arrayBuffer();let v=new DataView(b),o=0,u8=()=&gt;v.getUint8(o++),u32=()=&gt;{let x=v.getUint32(o,1);o+=4;return x},i16=()=&gt;{let x=v.getInt16(o,1);o+=2;return x};for(let i=0;i&lt;5;i++)u8();if(u8()!=2)throw&#34;Unsupported version&#34;;let nv=u32(),nt=u32(),p=new Int16Array(nv*3),n=new Int16Array(nv*3),i=new Uint32Array(nt*3);for(let x=0;x&lt;p.length;x++)p[x]=i16();for(let x=0;x&lt;n.length;x++)n[x]=i16();for(let x=0;x&lt;i.length;x++)i[x]=u32();return{positions:p,normals:n,indices:i}}}class RendererV2{constructor(c){this.c=c;let g=this.gl=c.getContext(&#34;webgl2&#34;,{alpha:true});if(!g)throw Error(&#34;WebGL2 required&#34;);g.enable(g.DEPTH_TEST);g.enable(g.CULL_FACE);g.enable(g.BLEND);g.blendFunc(g.SRC_ALPHA,g.ONE_MINUS_SRC_ALPHA);this.x=5;this.y=-1;this.auto=1;this.sp=.003;this.drag=0;this.lx=this.ly=0;this.zoom=1.5;this.mesh=null;this.P=persp(Math.PI/4,c.width/c.height,.1,1e3);let z=1/Math.sqrt(26);this.v=new Float32Array([1,0,0,0,0,5*z,0,0,0,0,5*z,0,0,0,-5,1]);this.sh=new Shader(g);this.L=[1/Math.sqrt(1.09),0,-.3/Math.sqrt(1.09)];this.L2=[-1,0,-.25];this.L3=[0,0,1];this.L4=[-1,0,.5];this.dark=document.documentElement.dataset.theme===&#34;dark&#34;;new MutationObserver(()=&gt;{this.dark=document.documentElement.dataset.theme===&#34;dark&#34;}).observe(document.documentElement,{attributes:true,attributeFilter:[&#34;data-theme&#34;]});this.mouse();this.start()}resize(){let c=this.c;this.P=persp(Math.PI/4/this.zoom,c.width/c.height,.1,1e3);this.gl.viewport(0,0,c.width,c.height)}setMesh(m){this.mesh=m;let g=this.gl,s=this.sh;this.vao=g.createVertexArray();g.bindVertexArray(this.vao);let b=(d,a)=&gt;{let x=g.createBuffer();g.bindBuffer(g.ARRAY_BUFFER,x);g.bufferData(g.ARRAY_BUFFER,d,g.STATIC_DRAW);g.enableVertexAttribArray(a);g.vertexAttribPointer(a,3,g.SHORT,true,0,0)};b(m.positions,s.ap);b(m.normals,s.an);let x=g.createBuffer();g.bindBuffer(g.ELEMENT_ARRAY_BUFFER,x);g.bufferData(g.ELEMENT_ARRAY_BUFFER,m.indices,g.STATIC_DRAW);this.index=m.indices.length;g.bindVertexArray(null)}mouse(){let c=this.c;c.addEventListener(&#34;pointerdown&#34;,e=&gt;{this.drag=1;this.auto=0;this.lx=e.clientX;this.ly=e.clientY;c.setPointerCapture(e.pointerId)});c.addEventListener(&#34;pointermove&#34;,e=&gt;{if(this.drag){this.y+=(e.clientX-this.lx)*.01;this.x+=(e.clientY-this.ly)*.01;this.lx=e.clientX;this.ly=e.clientY}});c.addEventListener(&#34;pointerup&#34;,e=&gt;{this.drag=0;this.auto=1;if(c.hasPointerCapture(e.pointerId))c.releasePointerCapture(e.pointerId)});c.addEventListener(&#34;pointercancel&#34;,()=&gt;{this.drag=0;this.auto=1});c.addEventListener(&#34;wheel&#34;,e=&gt;{e.preventDefault();this.zoom=Math.max(.2,Math.min(5,this.zoom+e.deltaY*.001));this.P=persp(Math.PI/4/this.zoom,c.width/c.height,.1,1e3)},{passive:false})}start(){let f=()=&gt;{if(this.auto)this.y+=this.sp;this.draw();requestAnimationFrame(f)};f()}draw(){let g=this.gl,m=this.mesh;g.clearColor(0,0,0,0);g.clear(g.COLOR_BUFFER_BIT|g.DEPTH_BUFFER_BIT);if(!m)return;let s=this.sh,a=rotX(this.x);a=mul(a,rotY(this.y));a=mul(a,scale(m.scale||1));g.useProgram(s.p);g.uniformMatrix4fv(s.m,0,a);g.uniformMatrix4fv(s.v,0,this.v);g.uniformMatrix4fv(s.P,0,this.P);g.uniform3fv(s.l,this.L);g.uniform3fv(s.l2,this.L2);g.uniform3fv(s.l3,this.L3);g.uniform3fv(s.l4,this.L4);g.uniform1f(s.s,.5);g.uniform3f(s.c,1,1,1);g.uniform1f(s.mode,this.dark?1:0);g.bindVertexArray(this.vao);g.drawElements(g.TRIANGLES,this.index,g.UNSIGNED_INT,0)}} &lt;/script&gt;&#xA;&lt;p&gt;  &lt;div class=&#34;pmesh-viewer-container&#34; id=&#34;pmesh-0&#34;&gt;  &lt;canvas class=&#34;pmesh-viewer&#34;&gt;&lt;/canvas&gt;  &lt;/div&gt; &lt;script&gt; (() =&gt; { const c = document.getElementById(&#34;pmesh-0&#34;); const init = canvas =&gt; { const r = new RendererV2(canvas); const resize = () =&gt; { canvas.width = canvas.clientWidth; canvas.height = canvas.clientHeight; r.resize(); }; addEventListener(&#34;resize&#34;, resize); resize(); fetch(&#34;\/models\/smallermask.pmesh&#34;) .then(x =&gt; { if (!x.ok) throw Error(`HTTP ${x.status}`); return x.blob(); }) .then(PMeshV2.load) .then(r.setMesh.bind(r)) .catch(console.error); };  init(c.querySelector(&#34;canvas&#34;));  })(); &lt;/script&gt;&#xA;&#xA;This website is a collection of projects that I have worked on, or am currently working on, with the express goal of serving as both reference material and a record of my progress. I hope you find some of the information here useful or interesting.&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
