<rss version="2.0">
  <channel>
    <title>Videos on Leon Mika</title>
    <link>https://lmika.org/categories/videos/</link>
    <description></description>
    
    <language>en</language>
    
    <lastBuildDate>Thu, 07 May 2026 16:55:03 +1000</lastBuildDate>
    
    <item>
      <title></title>
      <link>https://lmika.org/2026/05/07/end-of-the-path.html</link>
      <pubDate>Thu, 07 May 2026 16:55:03 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2026/05/07/end-of-the-path.html</guid>
      <description>&lt;p&gt;End of the path.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.mov/25293/2026/pxl-20260507-004505661/playlist.m3u8&#34; poster=&#34;https://cdn.uploads.micro.blog/25293/2026/frames/1742959-0-8b1d10.jpg&#34; width=&#34;1920&#34; height=&#34;1080&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2026/02/17/i-remember-os-may-be.html</link>
      <pubDate>Tue, 17 Feb 2026 19:09:37 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2026/02/17/i-remember-os-may-be.html</guid>
      <description>&lt;p&gt;I remember. OS/2 may be gone, but it&amp;rsquo;s not forgotten. 🙂&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2026/podcast-clip-2026-02-17t090912z.mp4&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34; poster=&#34;https://lmika.org/uploads/2026/800726d1c9.jpg&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2026/01/07/i-got-around-to-putting.html</link>
      <pubDate>Wed, 07 Jan 2026 06:42:02 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2026/01/07/i-got-around-to-putting.html</guid>
      <description>&lt;p&gt;I got around to putting together that walkthrough video of Alto for that person I&amp;rsquo;ve shared it with. Reposting it here for posterity and for anyone who&amp;rsquo;s curious. Fair warning: don&amp;rsquo;t expect amazing video production quality.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.mov/25293/2026/getting-started-with-alto/playlist.m3u8&#34; poster=&#34;https://cdn.uploads.micro.blog/25293/2026/frames/1654347-0-51cefc.jpg&#34; width=&#34;1280&#34; height=&#34;720&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2026/01/02/making-use-of-that-animation.html</link>
      <pubDate>Fri, 02 Jan 2026 20:54:18 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2026/01/02/making-use-of-that-animation.html</guid>
      <description>&lt;p&gt;Making use of that animation package: test scene and interaction for something I&amp;rsquo;m putting together for my niece.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.mov/25293/2026/ebetian-project-bus/playlist.m3u8&#34; poster=&#34;https://cdn.uploads.micro.blog/25293/2026/frames/1650949-0-7146b6.jpg&#34; width=&#34;820&#34; height=&#34;480&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Devlog: An API For a Keyframe Animation Package</title>
      <link>https://lmika.org/2025/12/30/devlog-an-api-for-a.html</link>
      <pubDate>Tue, 30 Dec 2025 16:42:35 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/12/30/devlog-an-api-for-a.html</guid>
      <description>&lt;p&gt;Spent the day building a key-frame animator for an Ebitengine project. All coded in Go, which should make it usable for some other projects in theory. I don&amp;rsquo;t have a lot of experience with animation frameworks — other than as an end-user of apps that consist of a timeline where I place keyframes — so I&amp;rsquo;m not aware of what constitutes best practice for a programatic API. So I set out to build one with an API that made sense to me. After one major iteration, this is the approach I came up with.&lt;/p&gt;
&lt;p&gt;The core model type is the Var, which represents an animatable value. These are essentially handles describing the type of value the (package) user wants to animate. At the moment there is only a single type, which is a float:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;xPos&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;animator&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;NewFloatVar&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;yPos&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;animator&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;NewFloatVar&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;To animate the value, the user will need to create an Animation and place any created Vars on a track. Tracks consist of key-frames, which is essentially a time offset, and one or more values a Var should have at that time. These values can be created from the Var itself, by calling &lt;code&gt;Set()&lt;/code&gt;.   This returns a type holding what that Var should be set to at that key-frame (&amp;ldquo;set&amp;rdquo; is probably not the best term for this):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;moveDown&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;animator&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;NewAnimation&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;posTrack&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;moveDown&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;NewTrack&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;posTrack&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;KeyFrame&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;0.0&lt;/span&gt;, []&lt;span style=&#34;color:#a6e22e&#34;&gt;animator&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;FloatSet&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;xPos&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Set&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;0.0&lt;/span&gt;), &lt;span style=&#34;color:#a6e22e&#34;&gt;yPos&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Set&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;0.0&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;posTrack&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;KeyFrame&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;3.0&lt;/span&gt;, []&lt;span style=&#34;color:#a6e22e&#34;&gt;animator&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;FloatSet&lt;/span&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;xPos&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Set&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;100.0&lt;/span&gt;), &lt;span style=&#34;color:#a6e22e&#34;&gt;yPos&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Set&lt;/span&gt;(&lt;span style=&#34;color:#ae81ff&#34;&gt;100.0&lt;/span&gt;),
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;})
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Not all Vars need to be included on a particular keyframe, but prior to animating, each of the Vars known to the track will need to be tweened if there isn&amp;rsquo;t a &amp;ldquo;set&amp;rdquo; for them on the key-frame, so it&amp;rsquo;s generally good practice to set all the Vars for each track. Different tracks can have a different of Vars, so if different keyframes are needed, it probably should exist on a separate track.&lt;/p&gt;
&lt;p&gt;Animations are designed to be reusable and simply encode what the Animation is. The motivation here is that all the expensive work should be done once, when the Animation is created. To actually animate the Vars, the user will need to create a timeline and set it to the Animation.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;tl&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;animator&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;NewTimeline&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;tl&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;SetAnimation&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;moveDown&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This will initialise all the Var values to what they would be at frame 0 (at the moment, frame 0 must be a time 0, but down the line I&amp;rsquo;d like to remove this to allow for blending between Animations). The value of each Var can now be retrieved, as Vars only have a value within the scope of a Timeline.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;xPos&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Value&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;tl&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;y&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;yPos&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Value&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;tl&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// x and y == 0, as that is the value they were set to in the first frame&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;drawRect&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;x&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;y&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The Timeline clock is advanced by calling the &lt;code&gt;Advance()&lt;/code&gt; method, which takes a delta in fractions of a second. This will tween all the Vars based on the current action, and the new value can be retrieved by calling &lt;code&gt;Value()&lt;/code&gt; again. Thus the core use of this package is advancing the clock and querying the values for each tweened frame.&lt;/p&gt;
&lt;p&gt;Within an Ebitengine project, this is done by calling &lt;code&gt;Advance&lt;/code&gt; within &lt;code&gt;Update&lt;/code&gt; function and sampling the values within &lt;code&gt;Draw&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; (
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;tl&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;animator&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Timeline&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;xPos&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;animator&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;FloatVar&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;yPos&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;animator&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;FloatVar&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Update&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;dt&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;1.0&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; float64(&lt;span style=&#34;color:#a6e22e&#34;&gt;ebiten&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;TPS&lt;/span&gt;())  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#a6e22e&#34;&gt;tl&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Advance&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;dt&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Draw&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;screen&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ebiten&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Image&lt;/span&gt;) {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;vector&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;FillRect&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;screen&lt;/span&gt;,  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       float32(&lt;span style=&#34;color:#a6e22e&#34;&gt;xPos&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Value&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;tl&lt;/span&gt;)), float32(&lt;span style=&#34;color:#a6e22e&#34;&gt;yPos&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Value&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;tl&lt;/span&gt;)),  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;, &lt;span style=&#34;color:#ae81ff&#34;&gt;100&lt;/span&gt;,  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;       &lt;span style=&#34;color:#a6e22e&#34;&gt;col&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;true&lt;/span&gt;,  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    )  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Here&amp;rsquo;s an test animation:&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.mov/25293/2025/cleanshot-2025-12-30-at-17.14.42/playlist.m3u8&#34; poster=&#34;https://cdn.uploads.micro.blog/25293/2025/frames/1647920-0-36a228.jpg&#34; width=&#34;1232&#34; height=&#34;720&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m quite happy with how this turns out. I like how little &amp;ldquo;magic&amp;rdquo; is involved in the API: values and clocks are not changed from underneath you: you need to explicitly advance the clock yourself, and read the values when you need them.&lt;/p&gt;
&lt;p&gt;Obviously there&amp;rsquo;s room for improvement. Tracks and keyframes cannot be changed; only linear interpolation of float values are supported; and there&amp;rsquo;s no looping, bouncing, or reversing of animations. I&amp;rsquo;d hope to add all this in due time, probably based on the needs of the project I&amp;rsquo;m working on. There are also a few things I&amp;rsquo;m a little wary of, such as a global atomic int responsible for allocating an ID for each newly created Var. And the Timeline holds Var values in a map which I hope is fast enough for rendering on a screen.&lt;/p&gt;
&lt;p&gt;But it&amp;rsquo;s nice to have something like this in my toolbox. It&amp;rsquo;s been something I&amp;rsquo;ve been wishing for a while.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Devlog: Godot Project - Level 3-2 And Bobbing Water</title>
      <link>https://lmika.org/2025/12/08/devlog-godot-project-level-and.html</link>
      <pubDate>Mon, 08 Dec 2025 21:32:32 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/12/08/devlog-godot-project-level-and.html</guid>
      <description>&lt;p&gt;I spent a lot of time on distractions recently, so I was a little surprised to find myself wanting to get back to working on that Godot game. The level under design is going okay: it took a few attempts to find the right way to start. Turns out writing down how you want the level to progress helps, like having three &amp;ldquo;acts&amp;rdquo; where the first act consists of some jumping puzzles, then introducing one of the gimmick, than a variant of said gimmick, and so on.&lt;/p&gt;
&lt;p&gt;Anyway, I&amp;rsquo;m working on the second &amp;ldquo;act&amp;rdquo; which will feature a low-power mechanic: there&amp;rsquo;s only so many units of power to energise the various zones, and the player needs to juggle it all to get through the act. Because power is involved, I wanted to have a generator sprite to provide some decoration. This is what I came up with:&lt;/p&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2025/out-20251203-221842.png&#34; width=&#34;600&#34; height=&#34;327&#34; alt=&#34;Auto-generated description: A pixelated knight stands next to a large, metal generator in a block-brick environment with blue water below.&#34;&gt;
&lt;p&gt;It&amp;rsquo;s… fine. I did try to get some inspiration by uploaded the tile-set to Google Gemini and asked it to produce something that resembled a generator:&lt;/p&gt;

  &lt;blockquote&gt;
    &lt;p&gt;Using the tile set images uploaded, please provide some suggested designs for a tile-set representing an electric generator. The suggestion must match the style and colour scheme of the supplied image.&lt;/p&gt;

  &lt;/blockquote&gt;
&lt;p&gt;This helped, although what I have here is a fair bit different to what was generated. I may adjust the colours a bit (the simple colours are by design as I want to maintain the palette used by the existing tile-set) and I may need to add some wire decorations and maybe a sign that says &amp;ldquo;Generator&amp;rdquo; to make it clear that&amp;rsquo;s what it is, and that it&amp;rsquo;s not a cannon, as the alt-text generation suggests. We&amp;rsquo;ll see how it goes, I guess.&lt;/p&gt;
&lt;p&gt;One other thing I found myself wanting to add is water that can be raised and lowered when activated. I came up with something from first principals that looks a little like this (the tile layer is hidden to show the &lt;code&gt;Area2D&lt;/code&gt; shapes):&lt;/p&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2025/out-20251208-221530.png&#34; width=&#34;600&#34; height=&#34;226&#34; alt=&#34;Auto-generated description: A 2D platformer game editor displays a character, crates, water sections, and terrain blocks.&#34;&gt;
&lt;p&gt;It consists of is a top-level &lt;code&gt;Node2D&lt;/code&gt; which will raise and lower when triggered. This is done in code, just to allow me to configure the speed and displacement on a case-by-base basis. A child of that is a &lt;code&gt;TileMapLayer&lt;/code&gt; containing the water tiles. It&amp;rsquo;s at Z-index 6, which is just in front of the player so that it looks like it engulfs them if they fall in. Four units below the top is the kill-plane — water is a hazard — and four units below that is the &amp;ldquo;bobbing&amp;rdquo; plane. This is a &lt;code&gt;Node2D&lt;/code&gt; that simply oscillates up and down by 2 units every second. A child of that is an &lt;code&gt;Area2D&lt;/code&gt; solid with allows the player to move through, but will collide with a new crate sprite, which also collides with everything else.&lt;/p&gt;
&lt;p&gt;This has the effect of a water plane in which creates would appear buoyant yet slightly submerged, giving the player somewhere to stand. Activating the water layer will allow it to &amp;ldquo;drain,&amp;rdquo; bringing the crates down to rest on any solids. Activate it again and the water level will rise, catching any crates which will begin floating:&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.mov/25293/2025/screencast-water-bobbing/playlist.m3u8&#34; poster=&#34;https://cdn.uploads.micro.blog/25293/2025/frames/1633294-2-a7753f.jpg&#34; width=&#34;1158&#34; height=&#34;720&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s probably better ways to do this, and there are some drawbacks. It can&amp;rsquo;t be bundled into a dedicated scene, so each instance will need to be built manually. And if more than one crate is in the scene, they will bob in unison (although that could probably be alleviated with splitting the bobbing plane into areas with distinct offsets). But for something devised from first principals, I&amp;rsquo;m quite happy with it.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/11/30/laughed-out-loud-when-i.html</link>
      <pubDate>Sun, 30 Nov 2025 14:24:28 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/11/30/laughed-out-loud-when-i.html</guid>
      <description>&lt;p&gt;Laughed out loud when I heard this as my experience with Stripe&#39;s API has been quite different. Stripe does quite well with keeping support for old versions of their API, but they&#39;re not afraid of making backwards-incompatible changes between versions. We encountered quite a few of these last time we were updating the SDK, and while I was going through their API docs a few weeks ago, I saw quite a few more that we&#39;ll need to make next go-around. I wouldn&#39;t call that &amp;quot;low needs&amp;quot; myself.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2025/podcast-clip-2025-11-30t042353z.mp4&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34; poster=&#34;https://lmika.org/uploads/2025/16f357fba8.jpg&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/11/11/slow-strobes.html</link>
      <pubDate>Tue, 11 Nov 2025 06:52:40 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/11/11/slow-strobes.html</guid>
      <description>&lt;p&gt;Slow strobes.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.mov/25293/2025/pxl-20251110-202806145/playlist.m3u8&#34; poster=&#34;https://lmika.org/uploads/2025/2ce3048eb2.jpg&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/11/11/this-clip-made-me-think.html</link>
      <pubDate>Tue, 11 Nov 2025 05:44:27 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/11/11/this-clip-made-me-think.html</guid>
      <description>&lt;p&gt;This clip made me think. Not because of anything to do with Apple, Google, and their dealings. Rather, it made me wonder if this is applicable to things like how one spends their time and effort at self improvement. Focusing more on what you know your good at, for example.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2025/podcast-clip-2025-11-10t194407z.mp4&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34; poster=&#34;https://lmika.org/uploads/2025/poster.jpg&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Devlog: Dynamo Browse - Item View Annotations and Asynchronous Tasks</title>
      <link>https://lmika.org/2025/11/04/devlog-dynamo-browse-item-view.html</link>
      <pubDate>Tue, 04 Nov 2025 20:42:40 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/11/04/devlog-dynamo-browse-item-view.html</guid>
      <description>&lt;p&gt;The laundry list of things to do in Dynamo Browse has grown over the last week, as I find myself wanting using it and wanting more from it. I&amp;rsquo;ve knocked off many of the small ones: fixing bugs, making it easier to get the first item from a result set. The time has come to tackle some of the larger ones.&lt;/p&gt;
&lt;p&gt;The first is the ability to annotate fields in the item view, as in add additional information to the right of the value. I would personally find that useful for describing the value of an other table using it&amp;rsquo;s ID. But the point is that it can be anything. I&amp;rsquo;d like users to add these annotations via extensions, using UCL. The way I&amp;rsquo;m thinking of doing this is by &amp;ldquo;installing&amp;rdquo; a field annotator, something along the lines as follows:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;ui:add-item-annotator { |rs attr_path| 
    return &amp;#34;&amp;#34;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This will add an annotator which will take a result set, and a path to an attribute. It will return the annotated value. We&amp;rsquo;ll see how well this will work, but first I&amp;rsquo;ll need to build the Go types. Rendering the item view is done using an &lt;code&gt;ItemRenderer&lt;/code&gt; which basically walks through the attributes of an item and renders it as a table. I think I&amp;rsquo;ll change this to take an item annotation. I also realised I need a type to represent the attribute path. I think a simple linked list would work here. Here&amp;rsquo;s what I got:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;AttrPathNode&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;Name&lt;/span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;Index&lt;/span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;IsIndex&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;bool&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;Parent&lt;/span&gt;  &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;AttrPathNode&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The trouble is representing both string attribute names and numerical indicies in the same type. Go doesn&amp;rsquo;t have a great way of doing this, so I&amp;rsquo;ve gone with something simple and added boolean which would be true if the node is actually an integer index to a list or set.&lt;/p&gt;
&lt;p&gt;Actually, that may not be necessary. Poking around the renderer code, I found this type used to represent the sub items of an item:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;type&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;SubItem&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;Key&lt;/span&gt;   &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;Value&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;Renderer&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So I can simply use strings for the key. Good to know. Okay, added a test annotator and gave it a quick test:
&lt;a href=&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-11-03-at-20.37.46.png&#34; 
   class=&#34;glightbox&#34;
   data-gallery=&#34;8765091e77c1a5bd3340e2f3fa6a373e&#34;
   
&gt;
  &lt;img src =&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-11-03-at-20.37.46.png&#34; 
       loading=&#34;lazy&#34;
       decoding=&#34;async&#34;
       style=&#34;border-radius: 5px; max-width: 100%&#34;
       alt=&#34;CleanShot 2025-11-03 at 20.37.46.png&#34; 
        
  /&gt;
&lt;/a&gt;


Not bad, although found some glaring issues. It would be nice if the annotation was closer to the value. And laying out the annotations in a dedicated column will cause the entire column to shift as I move through the items. So instead of making it a separate column, I&amp;rsquo;ll try simply concatenating it to the end of the value. I&amp;rsquo;ll also apply the meta-info styling to dim the text a little:
&lt;a href=&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-11-03-at-20.39.24.png&#34; 
   class=&#34;glightbox&#34;
   data-gallery=&#34;8765091e77c1a5bd3340e2f3fa6a373e&#34;
   
&gt;
  &lt;img src =&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-11-03-at-20.39.24.png&#34; 
       loading=&#34;lazy&#34;
       decoding=&#34;async&#34;
       style=&#34;border-radius: 5px; max-width: 100%&#34;
       alt=&#34;CleanShot 2025-11-03 at 20.39.24.png&#34; 
        
  /&gt;
&lt;/a&gt;


That&amp;rsquo;s much better. I&amp;rsquo;m banking on only a few attributes having annotations, so I&amp;rsquo;m hoping it won&amp;rsquo;t be as busy as it looks here.&lt;/p&gt;
&lt;p&gt;Now to consider the UCL integration. Hmm, how am I going to connect the two? As expected, injecting the annotation directly into &lt;code&gt;ItemRenderer&lt;/code&gt; would introduce a dependency loop. What I could do instead is add a setter allowing the caller of the &lt;code&gt;ItemRenderer&lt;/code&gt; to change the annotation on the fly, and inject the &lt;code&gt;ItemRenderer&lt;/code&gt; as a dependency of the command controller.&lt;/p&gt;
&lt;p&gt;Implemented this, and it was actually easier than I thought.  Now to test this. I settled on the following UCL command:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;ui:set-item-annotator { |rs item path| 
    &amp;#34;annotation&amp;#34;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;where:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;rs&lt;/code&gt; is the result set&lt;/li&gt;
&lt;li&gt;&lt;code&gt;item&lt;/code&gt; is the item being rendered in the view&lt;/li&gt;
&lt;li&gt;&lt;code&gt;path&lt;/code&gt; is the attribute path, represented as a list.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The attribute path is a new proxy, just to reduce the amount of memory copying between Go and UCL. I kept the same list index semantics, where &amp;gt; 0 starts from the left, and &amp;lt; 0 starts from the right, but it was a little mind bending to reverse this for a linked list.&lt;/p&gt;
&lt;p&gt;A simple annotator which returns the currently displayed item value as an annotation can be implemented as follows:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;ui:set-item-annotator { |rs item path|
    $item.($path.(-1))
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here it is in action:
&lt;a href=&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-11-03-at-20.41.25.png&#34; 
   class=&#34;glightbox&#34;
   data-gallery=&#34;8765091e77c1a5bd3340e2f3fa6a373e&#34;
   
&gt;
  &lt;img src =&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-11-03-at-20.41.25.png&#34; 
       loading=&#34;lazy&#34;
       decoding=&#34;async&#34;
       style=&#34;border-radius: 5px; max-width: 100%&#34;
       alt=&#34;CleanShot 2025-11-03 at 20.41.25.png&#34; 
        
  /&gt;
&lt;/a&gt;


Brilliant, it&amp;rsquo;s working! Naturally as commands are simple UCL statements, this could be entered on the command line.&lt;/p&gt;
&lt;p&gt;One thing to consider is that unlike normal commands, the UCL block rendering the annotation is running on the UI thread. Not sure I like this, but the amount of effort required to change this would be significant. I guess I&amp;rsquo;ll just tell everyone to keep annotation rendering fast. And as it&amp;rsquo;s currently implement, it is reasonably fast. Or more accurately, it&amp;rsquo;s not noticeably slow, which is good enough.&lt;/p&gt;
&lt;p&gt;The next feature to add to Dynamo Browse is a way to asynchronously schedule blocks. I think it may be worth tapping into the existing command looper in some way.&lt;/p&gt;
&lt;p&gt;Commands in Dynamo Browse are invoked on a dedicated goroutine. Calling &lt;code&gt;execute()&lt;/code&gt; will attempt to send a command via a channel. If that fails, &lt;code&gt;execute()&lt;/code&gt; will return an error indicating that a command is currently running. This keeps running UCL code off the UI thread, and it also makes it possible to implement commands like &lt;code&gt;ui:prompt&lt;/code&gt; synchronously from the UCL code&amp;rsquo;s perspective, when in reality it pauses this goroutine and sends a message to the UI with a callback to resume the thread:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; (&lt;span style=&#34;color:#a6e22e&#34;&gt;m&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;uiModule&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;uiPrompt&lt;/span&gt;(
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;context&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Context&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;args&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;ucl&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;CallArgs&lt;/span&gt;,
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;) (&lt;span style=&#34;color:#66d9ef&#34;&gt;any&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;error&lt;/span&gt;) {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;prompt&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;args&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Bind&lt;/span&gt;(&lt;span style=&#34;color:#f92672&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;prompt&lt;/span&gt;); &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;resChan&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make(&lt;span style=&#34;color:#66d9ef&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;)  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#a6e22e&#34;&gt;cancelChan&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; make(&lt;span style=&#34;color:#66d9ef&#34;&gt;chan&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt;{})  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;go&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;() {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;commandctrl&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;PostMsg&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;events&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;PromptForInputMsg&lt;/span&gt;{  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;Prompt&lt;/span&gt;: &lt;span style=&#34;color:#a6e22e&#34;&gt;prompt&lt;/span&gt;,  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;OnDone&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;value&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;string&lt;/span&gt;) &lt;span style=&#34;color:#a6e22e&#34;&gt;tea&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Msg&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#a6e22e&#34;&gt;resChan&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;value&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            },  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;OnCancel&lt;/span&gt;: &lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt;() &lt;span style=&#34;color:#a6e22e&#34;&gt;tea&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Msg&lt;/span&gt; {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#a6e22e&#34;&gt;cancelChan&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt;{}{}  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;                &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            },
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        })  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }()  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;select&lt;/span&gt; {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;value&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;resChan&lt;/span&gt;:  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;value&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;cancelChan&lt;/span&gt;:  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;, &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Done&lt;/span&gt;():  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Err&lt;/span&gt;()  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;So tapping into this event loop would be nice. But how does one do so?&lt;/p&gt;
&lt;p&gt;I think, probably the simplest way to do so is with buffered channels. These are bounded, meaning that there will be an upper limit to the number of pending tasks, but maybe that&amp;rsquo;s not a bad thing. Having too many pending tasks crowding out the user&amp;rsquo;s ability to run commands will probably make for a poor user experience. So let&amp;rsquo;s set the limit to something quite generous, say 50, and integrate it into the event loop:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;for&lt;/span&gt; {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;select&lt;/span&gt; {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;cmdChan&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;cmdChan&lt;/span&gt;:  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a6e22e&#34;&gt;res&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ExecuteAndWait&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;, &lt;span style=&#34;color:#a6e22e&#34;&gt;cmdChan&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;cmd&lt;/span&gt;)  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;postMessage&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;events&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Error&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;))  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        } &lt;span style=&#34;color:#66d9ef&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;res&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;postMessage&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;events&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;StatusMsg&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;fmt&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Sprint&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;res&lt;/span&gt;)))  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;execCtx&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;requestRefresh&lt;/span&gt; {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;postMessage&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;events&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;ResultSetUpdated&lt;/span&gt;{})  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#75715e&#34;&gt;// New code here&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;task&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;&amp;lt;-&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;pendingTaskChan&lt;/span&gt;:  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#66d9ef&#34;&gt;if&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;:=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;task&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;task&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;ctx&lt;/span&gt;); &lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;!=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;nil&lt;/span&gt; {  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a6e22e&#34;&gt;c&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;postMessage&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;events&lt;/span&gt;.&lt;span style=&#34;color:#a6e22e&#34;&gt;Error&lt;/span&gt;(&lt;span style=&#34;color:#a6e22e&#34;&gt;err&lt;/span&gt;))  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Now for the UCL API. I have an idea of adding a new &lt;code&gt;async&lt;/code&gt; package for this, which will provide commands for running things asynchronously. It&amp;rsquo;s simplest command would be &lt;code&gt;async:do&lt;/code&gt;, which will schedule a block when the command loop is free. So invoking the following:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;ui:command testasync {  
    echo &amp;#34;This&amp;#34;
    async:do {
        echo &amp;#34;Other&amp;#34;
        async:do { echo &amp;#34;Sierra&amp;#34; }
    }
    async:do {
        echo &amp;#34;Romeo&amp;#34;
    }
    echo &amp;#34;That&amp;#34;
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Should display:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;This
That
Other
Romeo
Sierra
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In the logs. Trying it out and here&amp;rsquo;s how it looks:
&lt;a href=&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-11-03-at-21.31.42.png&#34; 
   class=&#34;glightbox&#34;
   data-gallery=&#34;8765091e77c1a5bd3340e2f3fa6a373e&#34;
   
&gt;
  &lt;img src =&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-11-03-at-21.31.42.png&#34; 
       loading=&#34;lazy&#34;
       decoding=&#34;async&#34;
       style=&#34;border-radius: 5px; max-width: 100%&#34;
       alt=&#34;CleanShot 2025-11-03 at 21.31.42.png&#34; 
        
  /&gt;
&lt;/a&gt;


Okay, that&amp;rsquo;s pretty good. Now to build on this. The next thing to add is a command that will schedule tasks in the future, similar to &lt;code&gt;window.setTimeout()&lt;/code&gt;. For this, I plan to use the &lt;a href=&#34;https://github.com/go-co-op/gocron&#34;&gt;gocron&lt;/a&gt; package. Lots there, but for my purpose, I plan to use the &lt;a href=&#34;https://pkg.go.dev/github.com/go-co-op/gocron/v2@v2.17.0#OneTimeJob&#34;&gt;OneTimeJob&lt;/a&gt; type. It does feel like bringing in a crane to lift an empty wood pallet, but the alternative is building my own scheduler (or getting AI to vibe-code one) using a heap. Maybe something for later, but I think this is fine for now.&lt;/p&gt;
&lt;p&gt;To make use of this, I&amp;rsquo;ll add &lt;code&gt;async:in&lt;/code&gt;, which takes a timeout in seconds, and a block to run. To test this, I&amp;rsquo;ll do the classic &amp;ldquo;count down&amp;rdquo; tests:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;proc countdown { |from|
    if (le $from 0) {
        echo &amp;#34;Blast off!!&amp;#34;
        return
    }
    echo &amp;#34;$from&amp;#34;
    async:in 1 { countdown (sub $from 1) }
}

ui:testasync {
    countdown 10
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Here it is in action:&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-11-03-at-22.12.51.mp4&#34; poster=&#34;https://lmika.org/uploads/2025/72bad33388.png&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;One last thing to add to async, the ability to run a query in the background and execute a block once the results are available, keeping long running queries off the UCL goroutine. I think for this I will add another thread-pool which will execute up to two queries in the background, then schedule a task to run once the results are ready.&lt;/p&gt;
&lt;p&gt;The API for running queries is pretty well established, to the point that I&amp;rsquo;ve actually got a helper functions which deal with the UCL side of things, so it&amp;rsquo;s just a matter of implementing an asynchronous version of this. I&amp;rsquo;m thinking of an interface along the following lines:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;async:query &amp;lt;query&amp;gt; { |rs|
    # do something with the result-set $rs
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It should also support keyword arguments too. Unfortunately, UCL requires keyword arguments to be placed after the positional arguments, so they would need to be placed after the block, which is a little yucky.&lt;/p&gt;
&lt;p&gt;Implemented the code, now for the test. This one&amp;rsquo;s a little contrived. What it does is asynchronously run a query on startup, counting the number of opened and closed offices in the &lt;code&gt;business-addresses&lt;/code&gt; table. Once those results are available, it will install a new column annotation, which will display the count to the right of the &lt;code&gt;officeOpened&lt;/code&gt; fields.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;proc _prep_officeCount {
    openedOffices = 0
    closedOffices = 0

    async:query &amp;#39;officeOpened=true&amp;#39; { |rs|
        openedOffices = len $rs
        async:query &amp;#39;officeOpened=false&amp;#39; { |rs|
            closedOffices = len $rs

            ui:set-item-annotator { |rs item path|
                if (eq $path.(-1) &amp;#34;officeOpened&amp;#34;) {
                    if $item.officeOpened {
                        &amp;#34;Count = ${openedOffices}&amp;#34;
                    } else {
                        &amp;#34;Count = ${closedOffices}&amp;#34;
                    }
                } else {
                    &amp;#34;&amp;#34;
                }
            }
        } -table business-addresses
    } -table business-addresses
}

_prep_officeCount
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;It is contrived, but I&amp;rsquo;m hoping to use this in a real setting where I annotate ID fields with a value I retrieve from another table, so a use case like this is pretty close to why I built this feature. Because the queries are running in the background, the goal is to avoid blocking the UI thread, but since this runs on startup before the user selects a table, the table needs to be specified as part of the call. I may have to have a think of how I am to fix that.&lt;/p&gt;
&lt;p&gt;But here it is working. Note the &lt;code&gt;Count = 244&lt;/code&gt; next to the &lt;code&gt;officeOpened&lt;/code&gt; field:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-11-04-at-13.49.19.png&#34; 
   class=&#34;glightbox&#34;
   data-gallery=&#34;8765091e77c1a5bd3340e2f3fa6a373e&#34;
   
&gt;
  &lt;img src =&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-11-04-at-13.49.19.png&#34; 
       loading=&#34;lazy&#34;
       decoding=&#34;async&#34;
       style=&#34;border-radius: 5px; max-width: 100%&#34;
       alt=&#34;CleanShot 2025-11-04 at 13.49.19.png&#34; 
        
  /&gt;
&lt;/a&gt;


Excellent. The next thing to do is try this out in a real setting. I finished off making a proper goroutine pool for the task that actually runs the query — which I&amp;rsquo;m calling the &amp;ldquo;aux task pool&amp;rdquo; — and a few other changes, like making the meta information a little easier to see.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/11/02/manage-to-catch-a-sighting.html</link>
      <pubDate>Sun, 02 Nov 2025 11:38:44 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/11/02/manage-to-catch-a-sighting.html</guid>
      <description>&lt;p&gt;Manage to catch a sighting of the Long Island Steel Train passing through Albury. 🚂&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://media.lmika.org/videos/2025/11/pxl_20251102_013229982.mp4&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Devlog: Godot Game - Level 3-2 and a Rotating Platform</title>
      <link>https://lmika.org/2025/10/28/devlog-godot-game-level-and.html</link>
      <pubDate>Tue, 28 Oct 2025 21:19:28 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/10/28/devlog-godot-game-level-and.html</guid>
      <description>&lt;p&gt;Okay, time to start level 3-2. This, like level 3-1, is in the mountainous regions. Except this time, the player will be a little higher. So that means jagged platforms, more verticality, lots of gaps: a real sense that care of where one steps must be taken.&lt;/p&gt;
&lt;p&gt;Starting with some platforming to give this sense: a few narrow safe areas, separated by pits, leading into an area with platforms.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-10-22-at-21.23.18.png&#34; 
   class=&#34;glightbox&#34;
   data-gallery=&#34;8eeed4ab2dca5262f0cb22b195a74537&#34;
   
&gt;
  &lt;img src =&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-10-22-at-21.23.18.png&#34; 
       loading=&#34;lazy&#34;
       decoding=&#34;async&#34;
       style=&#34;border-radius: 5px; max-width: 100%&#34;
       alt=&#34;CleanShot 2025-10-22 at 21.23.18.png&#34; 
        
  /&gt;
&lt;/a&gt;

&lt;/p&gt;
&lt;p&gt;Now, I have two choices of mechanics here: I can have the rotating platform, or I can have an area of the tile map fall away when the player lands on it. I think I prefer the rotating platform for the sole reason that adding the falling away platform may be a little overwhelming for the player.&lt;/p&gt;
&lt;p&gt;Actually, no. Danger and instability is the feeling I want to go for here. So I&amp;rsquo;ll add the falling platform, followed by a large safe area where the player can see the rotating player. Also, since this is a new mechanic, it&amp;rsquo;s only right that the player should play with it in a safe area first.&lt;/p&gt;
&lt;p&gt;Okay, I&amp;rsquo;ve added the falling platform. Well to be honest, I designated an area of the field where the falling platform will go. This leads into a large safe area which would be an ideal place to introduce the rotating platforms I have in mind.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m thinking of a scene with an &lt;code&gt;AnimationPlayer&lt;/code&gt; that will do the actual rotation animation: as in rotate the sprites from 0° to 90°. The question is, do I want the entire sequence timed using the &lt;code&gt;AnimationPlayer&lt;/code&gt;? As in, have a single animation that will rotate the platform all 4 times, with gaps between each stage? Or should I stick with the &lt;code&gt;AnimationPlayer&lt;/code&gt; simply animating a 90° rotation, and having another thing timing the wait time between stages?&lt;/p&gt;
&lt;p&gt;I think I prefer the latter. That way, I have more control over the pause between stage rotations. I can do things like disable it, or making it configurable. All desirable features.&lt;/p&gt;
&lt;p&gt;I guess the next question then is whether I want the &lt;code&gt;AnimationPlayer&lt;/code&gt; at all. Wouldn&amp;rsquo;t it be more flexible to do the animation in code? Probably, but I&amp;rsquo;m not sure I want that flexibility, at least not yet. Maybe in time it would be needed, but I think for now, I&amp;rsquo;ll just stick with the &lt;code&gt;AnimationPlayer&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So, let&amp;rsquo;s start building out the animation. I think I&amp;rsquo;ll start with four animations, each one rotate the platform from θ to θ+90°, just from different starting positions. I&amp;rsquo;ll use names that include the start and end angles, like &lt;code&gt;rotate_0_to_90&lt;/code&gt;, to allow for bidirectional rotation, should I decided to add that. Angle 0° will be up, and rotation will be clockwise. I think each rotation will be 0.5 seconds at speed 1, just so I have a consistent speed control. I can adjust the speed of the overall playback on the &lt;code&gt;AnimationPlayer&lt;/code&gt; itself.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-10-25-at-16.22.23.png&#34; 
   class=&#34;glightbox&#34;
   data-gallery=&#34;8eeed4ab2dca5262f0cb22b195a74537&#34;
   
&gt;
  &lt;img src =&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-10-25-at-16.22.23.png&#34; 
       loading=&#34;lazy&#34;
       decoding=&#34;async&#34;
       style=&#34;border-radius: 5px; max-width: 100%&#34;
       alt=&#34;CleanShot 2025-10-25 at 16.22.23.png&#34; 
        
  /&gt;
&lt;/a&gt;

&lt;/p&gt;
&lt;p&gt;Okay, animations made. Now to think of collision. I don&amp;rsquo;t like the idea of a collision box rotating along with the platforms. I&amp;rsquo;m not too certain about how well this plays with the physics engine, and even if there were no issues, non-orthogonal geometry is just not a thing in this game. So what I&amp;rsquo;m thinking of doing is adding two collision boxes, one horizontal and one vertical, and just toggling between the two as the platform moves into position. While the platform is rotating, both boxes will be turned off.&lt;/p&gt;
&lt;p&gt;Ooh, I didn&amp;rsquo;t know the collision layer could be added as a animatable track. That&amp;rsquo;s pretty cool.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-10-25-at-16.33.27.png&#34; 
   class=&#34;glightbox&#34;
   data-gallery=&#34;8eeed4ab2dca5262f0cb22b195a74537&#34;
   
&gt;
  &lt;img src =&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-10-25-at-16.33.27.png&#34; 
       loading=&#34;lazy&#34;
       decoding=&#34;async&#34;
       style=&#34;border-radius: 5px; max-width: 100%&#34;
       alt=&#34;CleanShot 2025-10-25 at 16.33.27.png&#34; 
        
  /&gt;
&lt;/a&gt;

&lt;/p&gt;
&lt;p&gt;Now to add a &lt;code&gt;Timer&lt;/code&gt; which will actually dictate the cadence. The included code is nice and neat: basically take the current rotation of the sprites in degrees, add 90 to it, and produce a string which will become the next animation to play:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-gdscript&#34; data-lang=&#34;gdscript&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_on_timer_timeout&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;void&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; next &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_next_animation&lt;/span&gt;()
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	animation_player&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;play&lt;/span&gt;(next)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;func&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;_next_animation&lt;/span&gt;() &lt;span style=&#34;color:#f92672&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;String&lt;/span&gt;:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;var&lt;/span&gt; rot &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;(sprites&lt;span style=&#34;color:#f92672&#34;&gt;.&lt;/span&gt;rotation &lt;span style=&#34;color:#f92672&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;180&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;/&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;PI&lt;/span&gt;) &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;360&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;	&lt;span style=&#34;color:#66d9ef&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;rotate_&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;%s&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;_to_&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;%s&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#f92672&#34;&gt;%&lt;/span&gt; [rot, rot &lt;span style=&#34;color:#f92672&#34;&gt;+&lt;/span&gt; &lt;span style=&#34;color:#ae81ff&#34;&gt;90&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Added it to a test level, and I had to speed up the &lt;code&gt;AnimationPlayer&lt;/code&gt; to 3x normal speed, just so that the movement is snappy enough to justify the loss of collision during the rotation. It may need further adjusting a little later, but so far works pretty well. Although I do think I need to telegraph when the platform is about to move.&lt;/p&gt;
&lt;p&gt;Oh, I remember how I&amp;rsquo;m going to telegraph to the player when the platform is about to rotate! It&amp;rsquo;s to be an indicator panel mounted at the front that will rotate slowly on it&amp;rsquo;s own. When it reaches a new orientation it will pause, then the platform behind it will rotate.&lt;/p&gt;
&lt;p&gt;Okay, new sprite. How the heck did I choose a canvas size with non-even dimensions and still end up with a sprite that doesn&amp;rsquo;t have a definitive centre line? 🤦&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-10-28-at-21.21.15.png&#34; 
   class=&#34;glightbox&#34;
   data-gallery=&#34;8eeed4ab2dca5262f0cb22b195a74537&#34;
   
&gt;
  &lt;img src =&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-10-28-at-21.21.15.png&#34; 
       loading=&#34;lazy&#34;
       decoding=&#34;async&#34;
       style=&#34;border-radius: 5px; max-width: 100%&#34;
       alt=&#34;CleanShot 2025-10-28 at 21.21.15.png&#34; 
        
  /&gt;
&lt;/a&gt;

&lt;/p&gt;
&lt;p&gt;Turns out it was how I was removing the upper and lower circles. I was using the eraser for that, and I didn&amp;rsquo;t position it properly.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-10-28-at-21.24.05.png&#34; 
   class=&#34;glightbox&#34;
   data-gallery=&#34;8eeed4ab2dca5262f0cb22b195a74537&#34;
   
&gt;
  &lt;img src =&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-10-28-at-21.24.05.png&#34; 
       loading=&#34;lazy&#34;
       decoding=&#34;async&#34;
       style=&#34;border-radius: 5px; max-width: 100%&#34;
       alt=&#34;CleanShot 2025-10-28 at 21.24.05.png&#34; 
        
  /&gt;
&lt;/a&gt;


Okay, here&amp;rsquo;s the sprite:&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-10-28-at-21.29.07.png&#34; 
   class=&#34;glightbox&#34;
   data-gallery=&#34;8eeed4ab2dca5262f0cb22b195a74537&#34;
   
&gt;
  &lt;img src =&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-10-28-at-21.29.07.png&#34; 
       loading=&#34;lazy&#34;
       decoding=&#34;async&#34;
       style=&#34;border-radius: 5px; max-width: 100%&#34;
       alt=&#34;CleanShot 2025-10-28 at 21.29.07.png&#34; 
        
  /&gt;
&lt;/a&gt;

&lt;/p&gt;
&lt;p&gt;Now to think about animating it. I&amp;rsquo;m wondering if it would be possible to simply add it to the same animation player as the platform. The thing is, I would like them to be somewhat independent. The indicator should move on it&amp;rsquo;s own accord, even when the platform sprite is rotating to a new orientation. I would also like the indicator to take on the platform rotation cadence, sending it a signal when it reaches a stop (this will remove the need for the &lt;code&gt;Timer&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Can I do that all in a single scene though? Maybe with two animation players? I&amp;rsquo;ll try that and see how viable it is.&lt;/p&gt;
&lt;p&gt;Okay, just tried that, and yes, using two &lt;code&gt;AnimationPlayers&lt;/code&gt; is viable. Now to prepare the animation. The current rotation period is 3 seconds so I&amp;rsquo;ll start with a 6 second animation that would just rotate the indicator over 180° with a slight pause halfway to trigger the platform. One good thing about the indicator&amp;rsquo;s symmetry is that one animation can cover the full rotation. Although be sure to change the loop wrap mode to &amp;ldquo;Clamp&amp;rdquo;, otherwise you&amp;rsquo;ll see the sprite spin round to 0° when the animation repeats.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-10-28-at-21.58.34.png&#34; 
   class=&#34;glightbox&#34;
   data-gallery=&#34;8eeed4ab2dca5262f0cb22b195a74537&#34;
   
&gt;
  &lt;img src =&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-10-28-at-21.58.34.png&#34; 
       loading=&#34;lazy&#34;
       decoding=&#34;async&#34;
       style=&#34;border-radius: 5px; max-width: 100%&#34;
       alt=&#34;CleanShot 2025-10-28 at 21.58.34.png&#34; 
        
  /&gt;
&lt;/a&gt;

&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s the full thing in action. And yeah, adding the indicator was pretty crucial in the end. The platform wouldn&amp;rsquo;t have been fair otherwise.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-10-28-at-21.56.12.mp4&#34; poster=&#34;https://lmika.org/uploads/2025/12f0aa11e2.png&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/10/22/this-sounds-ominous-does-this.html</link>
      <pubDate>Wed, 22 Oct 2025 05:45:50 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/10/22/this-sounds-ominous-does-this.html</guid>
      <description>&lt;p&gt;This sounds ominous. Does this mean more unsolicited push notifications in iOS or promotional crap added to Apple Maps? As someone who aims to not know when an F1 race is happening, it&#39;s a good indication that an iPhone is not for me.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2025/podcast-clip-2025-10-21t194523z.mp4&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34; poster=&#34;https://lmika.org/uploads/2025/8c74893ba0.png&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/10/20/itd-be-amusing-to-ponder.html</link>
      <pubDate>Mon, 20 Oct 2025 05:54:01 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/10/20/itd-be-amusing-to-ponder.html</guid>
      <description>&lt;p&gt;It&#39;d be amusing to ponder, given how podcasts all have a video component now, that if Apple did name their new box &amp;quot;Home Pod,&amp;quot; in 5 years time, would people think the &amp;quot;pod&amp;quot; in &amp;quot;podcasts&amp;quot; refers to that? Everyone&#39;s referring to their shows as &amp;quot;pods&amp;quot; now I do wonder if they&#39;re forgetting where &amp;quot;pod&amp;quot; originated from.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2025/podcast-clip-2025-10-19t195332z.mp4&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34; poster=&#34;https://lmika.org/uploads/2025/8f78733a9b.png&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/09/29/a-bit-more-work-on.html</link>
      <pubDate>Mon, 29 Sep 2025 22:31:18 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/09/29/a-bit-more-work-on.html</guid>
      <description>&lt;p&gt;A bit more work on my Godot game, mainly building out mechanic for world 3. Tonight it was building an old-style lift with a caged door that the player can use to travel between different heights. Turned out really well.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-09-29-at-22.16.57.mp4&#34; poster=&#34;https://lmika.org/uploads/2025/af19dc6338.png&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Animating the door was a slog, and if that was all I achieved this evening, I would&amp;rsquo;ve considered that a success. But I had a bit of time to code up the lift too. I was unsure of how to approach this at first: I knew I wanted to turn off player movement and collisions and move the player (and camera) along with the lift.&lt;/p&gt;
&lt;p&gt;This turned out to be easier than I was anticipating. When the player enters the lift, all motion on the player is disabled (this was done by setting a &amp;ldquo;disable_motion&amp;rdquo; boolean which would break out of the players progress loop early if true) and the player node is reparented to the lift. The lift then moves to the target, taking the player with it. At the destination, the player&amp;rsquo;s original parent is restored and motion is enabled again, allowing the player to move freely. I also had to turn off camera motion smoothing before I reparented the player as it seems like some offset vectors were incorrect for a frame and it had the camera shoot to the right. This is done when the door closing animation plays, before the node is reparented which happens just before the lift moves.&lt;/p&gt;
&lt;p&gt;There&amp;rsquo;s still work to do. The z-order seems to be messed up when the lift reaches it&amp;rsquo;s destination (the player appears in front of the doors as they open). And at the moment, the lift only goes in one direction. But I&amp;rsquo;m really happy with what was achieved tonight.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/09/14/its-amusing-to-imagine-how.html</link>
      <pubDate>Sun, 14 Sep 2025 11:42:43 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/09/14/its-amusing-to-imagine-how.html</guid>
      <description>&lt;p&gt;It&amp;rsquo;s amusing to imagine how far Apple&amp;rsquo;s bizarre, corporate-esque copywriting goes. Would one be able to go into Caffè Macs in Apple Park, pick up a packed sandwich, and see printed on the label:&lt;/p&gt;

  &lt;blockquote&gt;
    &lt;p&gt;With this sandwich, our focus is to maximise sustenance and nourishment so we can drive continued living in our employees.&lt;/p&gt;
&lt;p&gt;We&amp;rsquo;ve also introduced a new ecosystem of ingredients to compliment this unique sandwich. Thanks to the incredible availability of nuts and other allergens, we&amp;rsquo;re able to create a new awareness that this sandwich may contain some of these.&lt;/p&gt;

  &lt;/blockquote&gt;
&lt;p&gt;😼&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2025/podcast-clip-2025-09-14t014221z.mp4&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34; poster=&#34;https://lmika.org/uploads/2025/fc34bc7439.png&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/09/09/really-enjoyed-this-discussion-on.html</link>
      <pubDate>Tue, 09 Sep 2025 07:52:30 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/09/09/really-enjoyed-this-discussion-on.html</guid>
      <description>&lt;p&gt;Really enjoyed this discussion on the &lt;a href=&#34;https://shoptalkshow.com/681/&#34;&gt;latest Shoptalk show&lt;/a&gt; discussing why one would want a website. I disagree with the idea that restauranteurs can get away with just an Instagram. Restaurant websites generally suck, but I&#39;m not sure what I&#39;ll do if they aren&#39;t around, and I can&#39;t see their menu.&lt;/p&gt;
&lt;p&gt;Oh, and P.S. I don&#39;t know how to use Instagram.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2025/podcast-clip-2025-09-08t215159z.mp4&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34; poster=&#34;https://lmika.org/uploads/2025/2096385a7e.png&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Devlog: Dequoter — Something Different Today</title>
      <link>https://lmika.org/2025/09/06/devlog-dequoter-something-different-today.html</link>
      <pubDate>Sat, 06 Sep 2025 16:10:04 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/09/06/devlog-dequoter-something-different-today.html</guid>
      <description>&lt;p&gt;When it comes to hobby projects, I&amp;rsquo;m trying to reduce the number of things I build for work. But I&amp;rsquo;ve decided to revisit one that I&amp;rsquo;ve abandoned, given the frequent need for this. The issue is simple: I have a JSON data structure that is quoted within a string, and I want to &amp;ldquo;unquote&amp;rdquo; it and filter the JSON so that I can read it.&lt;/p&gt;
&lt;p&gt;So I thought I&amp;rsquo;d spend today restarting the Dequoter project. The best way to describe it is &lt;a href=&#34;https://github.com/IvanMathy/Boop&#34;&gt;a Boop clone&lt;/a&gt;. I like Boop, I use Boop. And I know Boop is extendable, so I could implement any processor I need using JavaScript. But I&amp;rsquo;m not a huge fan of JavaScript, and Go has the function I need &lt;a href=&#34;https://pkg.go.dev/strconv@go1.25.1#Unquote&#34;&gt;right there in the standard library&lt;/a&gt;. And with most things I encounter, I want to build my own. I know I shouldn&amp;rsquo;t, and I&amp;rsquo;ve been better at resisting. But I&amp;rsquo;d figured this could be a nice little distraction. And I thought I could get much of what I need done in a morning.&lt;/p&gt;
&lt;p&gt;So I started a new &lt;a href=&#34;https://wails.io&#34;&gt;Wales project&lt;/a&gt; and after about 3 hours, I had a scratchpad with an invokable command palette that I can use to dequote a string and format a JSON object:&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-09-06-at-15.57.26.mp4&#34; poster=&#34;https://lmika.org/uploads/2025/ecf16f805a.png&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Granted, it&amp;rsquo;s not much for 3 hours. While I did use Claude Code a little, much of this was hand rolled. And I spent a lot of time learning the ins and outs of &lt;a href=&#34;https://codemirror.net&#34;&gt;Code Mirror&lt;/a&gt;. This is why I wanted to use Wales this time around. The &lt;a href=&#34;https://lmika.org/2024/07/20/continuing-my-exploration.html&#34;&gt;previous run at this&lt;/a&gt; used &lt;a href=&#34;https://fyne.io/&#34;&gt;Fyne&lt;/a&gt;, which was really nice to use, but the available widgets were quite limited. The nice thing about Wales is that I can build the UI in HTML and it uses the built-in HTML renderer from the OS: no need to bundle Chrome. The frontend is mainly vanilla HTML and JavaScript, although I am using &lt;a href=&#34;https://stimulus.hotwired.dev&#34;&gt;Stimulus&lt;/a&gt; to help with some of the controls. The backend is, of course, Go.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2025/cleanshot-2025-09-06-at-15.46.43.png&#34; width=&#34;400&#34; height=&#34;572&#34; alt=&#34;Auto-generated description: Window displaying file information for an application named dequoter, including details like size, location, and version.&#34;&gt;
&lt;figcaption&gt;Final build size is 8.4 MB.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;By the end of this morning&amp;rsquo;s session, what I had was not pretty, but it&amp;rsquo;s functional and it already does what I need it to do. I do have some plans for integrating this with UCL, and using that to define processors. That should hopefully leave all the heavy core stuff to be built near the beginning, and that could sit pretty while the extensions are added in a nicer language. Anyway, more on this if this goes anywhere.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/09/03/ghz-for-a-phone-chip.html</link>
      <pubDate>Wed, 03 Sep 2025 07:40:09 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/09/03/ghz-for-a-phone-chip.html</guid>
      <description>&lt;p&gt;3.78 GHz for a phone chip! I remember getting a desktop clocked at just over 1 GHz and thinking that was the fastest computer I&#39;ve ever used. These phone chips are almost 4 times faster, and there&#39;s like 7 cores here, with 5 clocked faster then 3 GHz. Absolutely crazy when you think about it.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2025/podcast-clip-2025-09-02t213946z.mp4&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34; poster=&#34;https://lmika.org/uploads/2025/cbf8b478fc.png&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/08/19/talk-to-anyone-working-on.html</link>
      <pubDate>Tue, 19 Aug 2025 07:19:41 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/08/19/talk-to-anyone-working-on.html</guid>
      <description>&lt;p&gt;Talk to anyone working on the Go language and they&#39;ll tell you about the JSON parser they built. Maybe the CSS designer equivalent is making their own CSS reset. 😏&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2025/podcast-clip-2025-08-18t211912z.mp4&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34; poster=&#34;https://lmika.org/uploads/2025/ff0c1e5134.png&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/08/14/seeing-some-very-interesting-visitor.html</link>
      <pubDate>Thu, 14 Aug 2025 22:14:16 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/08/14/seeing-some-very-interesting-visitor.html</guid>
      <description>&lt;p&gt;Seeing some very interesting visitor pattens over the last two days. There seems to be two or three visitors from the US opening what seems to be every single page on this site. It&amp;rsquo;d be interesting to know who it is… or what it is. Maybe I should ask around.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://media.lmika.org/videos/2025/08/seinfield-ai-scraping-meme.mp4&#34; poster=&#34;https://lmika.org/uploads/2025/seinfield-ai-scraping-meme-poster.png&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/08/06/oh-interesting-thats-a-good.html</link>
      <pubDate>Wed, 06 Aug 2025 07:26:57 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/08/06/oh-interesting-thats-a-good.html</guid>
      <description>&lt;p&gt;Oh, interesting. That&amp;rsquo;s a good explanation as to why OpenAI et. al. would want to make a browser. And if they do tout it as being &amp;ldquo;AI powered&amp;rdquo;, then it kinda makes sense that Google would do likewise, as a defensive move to keep marketshare.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2025/podcast-clip-2025-08-05t212633z.mp4&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34; poster=&#34;https://lmika.org/uploads/2025/16f3733558.png&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/08/03/enjoying-listening-to-the-latest.html</link>
      <pubDate>Sun, 03 Aug 2025 09:15:24 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/08/03/enjoying-listening-to-the-latest.html</guid>
      <description>&lt;p&gt;Enjoying listening to the latest Talk Show with LMNT (I&#39;m about 67% through it so far). Especially liked this part about Safari, and not just because it validated my feelings about it. 😀&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2025/podcast-clip-2025-08-02t231501z.mp4&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34; poster=&#34;https://lmika.org/uploads/2025/eeb036701b.png&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/08/01/i-wonder-if-the-prudent.html</link>
      <pubDate>Fri, 01 Aug 2025 08:34:37 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/08/01/i-wonder-if-the-prudent.html</guid>
      <description>&lt;p&gt;I wonder if the prudent course of action for iOS app developers is to hold off from releasing their redesigns on day one. I wonder if iOS&amp;rsquo;s new look will be overwhelming for users and having an app that&amp;rsquo;s unchanged for a week or a month could provide them with something familiar to them. 🤷&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2025/podcast-clip-2025-07-31t223411z.mp4&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34; poster=&#34;https://lmika.org/uploads/2025/02c0d92972.png&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/07/27/making-that-seinfield-reference-in.html</link>
      <pubDate>Sun, 27 Jul 2025 10:05:21 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/07/27/making-that-seinfield-reference-in.html</guid>
      <description>&lt;p&gt;Making that Seinfield reference in my post on iPadOS 26 and Liquid Glass got my creative/meme-ing juices going. Opened DaVinci Resolve for this one.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://media.lmika.org/videos/2025/07/seinfield-liquid-glass-meme.mp4&#34; poster=&#34;https://lmika.org/uploads/2025/seinfield-liquid-glass-poster.png&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/07/25/if-you-asked-me-today.html</link>
      <pubDate>Fri, 25 Jul 2025 08:52:56 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/07/25/if-you-asked-me-today.html</guid>
      <description>&lt;p&gt;If you asked me today, I&amp;rsquo;d probably call this game &amp;ldquo;rock paper scissors,&amp;rdquo; most likely due to my consumption of American media. But growing up, I do remember calling this game &amp;ldquo;paper scissors rock.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2025/podcast-clip-2025-07-24t225222z.mp4&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34; poster=&#34;https://lmika.org/uploads/2025/f514d4b9ba.png&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/07/12/amazing-dithering-this-week-loved.html</link>
      <pubDate>Sat, 12 Jul 2025 13:13:16 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/07/12/amazing-dithering-this-week-loved.html</guid>
      <description>&lt;p&gt;Amazing Dithering this week. Loved the discussion on why Apple is so driven to remove all software chrome. Never considered that it was because of how the various teams are organised (spoilers in the included clip).&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2025/podcast-clip-2025-07-12t031246z.mp4&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34; poster=&#34;https://lmika.org/uploads/2025/b227f903ac.png&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/06/19/found-a-particularly-annoying-failure.html</link>
      <pubDate>Thu, 19 Jun 2025 17:14:06 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/06/19/found-a-particularly-annoying-failure.html</guid>
      <description>&lt;p&gt;Found a particularly interesting bug in Safari when I tried adding a background transition to radio-button labels styled to look like regular buttons. Tapping the labels on the iPad causes the background colour to flicker:&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2025/screenrecording-06-19-2025-12-43-37-1.mp4&#34; poster=&#34;https://lmika.org/uploads/2025/e68d08b04a.png&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Fixed it by working around the problem: I only need the transition when the user taps &amp;ldquo;Submit&amp;rdquo;, so I held-off from applying the transition attributes until that happens. But wow, what an weird way to fail.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/06/14/appreciate-that-theres-someone-else.html</link>
      <pubDate>Sat, 14 Jun 2025 16:25:52 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/06/14/appreciate-that-theres-someone-else.html</guid>
      <description>&lt;p&gt;Appreciate that there&#39;s someone else out there getting driven crazy by Apple throwing up permission pop-ups everywhere in MacOS. And the Terminal, of all places.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2025/podcast-clip-2025-06-14t062526z.mp4&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/06/07/chalk-me-up-as-one.html</link>
      <pubDate>Sat, 07 Jun 2025 13:54:11 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/06/07/chalk-me-up-as-one.html</guid>
      <description>&lt;p&gt;Chalk me up as one of those people that wished they could use Markdown everywhere. I use it for &lt;a href=&#34;https://obsidian.md/&#34;&gt;notes&lt;/a&gt;, for &lt;a href=&#34;https://en.m.wikipedia.org/wiki/Slack_(software)&#34;&gt;messaging&lt;/a&gt;, &lt;a href=&#34;https://micro.blog/&#34;&gt;writing here&lt;/a&gt;, etc. I occasionally dabble with WYSIWYG editors but I always turn back to Markdown. Love it.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2025/podcast-clip-2025-06-07t035348z.mp4&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/05/18/all-the-recent-changes-to.html</link>
      <pubDate>Sun, 18 May 2025 14:07:39 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/05/18/all-the-recent-changes-to.html</guid>
      <description>&lt;p&gt;All the recent changes to UCL is in service of unifying the scripting within Dynamo Browse. Right now there are two scripting languages: one for the commands entered after pressing  &lt;code&gt;:&lt;/code&gt;, and one for extensions. I want to replace both of them with UCL, which will power both interactive commands, and extensions.&lt;/p&gt;
&lt;p&gt;Most of the commands used within the in-app REPL loop has been implemented in UCL. I&amp;rsquo;m now in the process of building out the UCL extension support, start with functions for working with result sets, and pseudo-variables for modifying elements of the UI.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s a demo of what I&amp;rsquo;ve got so far. This shows the user&amp;rsquo;s ability to control the current result-set, and the selected item programatically. Even after these early changes, I&amp;rsquo;m already seeing much better support for doing such things than what was there before.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://media.lmika.org/videos/2025/dynamo-browse-pvals-demo.mp4&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/04/18/made-some-more-progress-on.html</link>
      <pubDate>Fri, 18 Apr 2025 14:30:18 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/04/18/made-some-more-progress-on.html</guid>
      <description>&lt;p&gt;Made some more progress on that Godot game. I haven&amp;rsquo;t gotten any further with the first level of world 2, so I&amp;rsquo;ve been spending much of my time making mechanics. One of them was the slow moving &amp;ldquo;level 2&amp;rdquo; mechanic that I stole wholesale from Super Mario World. That mechanic, despite it being frustrating to speed-runners, was always slightly interesting to me. To have areas of a level become accessible or hazardous just due to a layer of it oscillate up and down, it promised to make for some interesting timing challenges. At least in theory.&lt;/p&gt;
&lt;figure&gt;
&lt;video src=&#34;https://media.lmika.org/videos/2025/godot-w4-layer2.mp4&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;
&lt;figcaption&gt;Portion of the new level showing all three new mechanics.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I decided to put that theory to the test, and start work on one the later levels. And despite being a little skeptical about whether the mechanic could carry through a level on it&amp;rsquo;s own, I came up with one that I&amp;rsquo;m reasonably happy with. The mechanic is introduce slowly, and in a rather non-threatening way, proving the player the means to get to higher ground. This leads into the second half, which will be a long underground section which will ramp up the difficulty by introducing the risk of getting crushed or missing platforms.&lt;/p&gt;
&lt;p&gt;To compliment this is a new enemy that rushes the player. The player cannot do anything to defeat this enemy: combat is not really a thing in this game. All they could do is evade it before the enemy gives up. I am reusing the same &amp;ldquo;green slime&amp;rdquo; sprite for this but I&amp;rsquo;m hoping that the differing animations provide some hints of how this enemy&amp;rsquo;s behaviour differs from that of the simpler one.&lt;/p&gt;
&lt;p&gt;Finally, it was time to consider checkpoints. While the first few levels were too short to justify adding them in, this one is just that bit too long without one. And given the difficulty ramp-up in the second half, having the player go through the slower first half every time they died would probably lead to frustration. So checkpoints are now a thing. They&amp;rsquo;re not free — costing 5 coins to activate — and they are sometimes mandatory, blocking the player from progressing until they pay the toll. But I think their presence helps with eliminating the areas of the level that would just be boring to play through again and again.&lt;/p&gt;
&lt;p&gt;So yeah, I&amp;rsquo;m quite happy with this level. And I&amp;rsquo;m also happy in realising that I&amp;rsquo;m not bound to building this game in the same progression that the player will experience it. It&amp;rsquo;s better sometimes to just work on the areas that you&amp;rsquo;re ready to. I mean, it&amp;rsquo;s sounds obvious to say that now. Not sure why it took me this long to actually do so.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/04/08/spent-some-time-over-the.html</link>
      <pubDate>Tue, 08 Apr 2025 22:35:06 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/04/08/spent-some-time-over-the.html</guid>
      <description>&lt;p&gt;Spent some time over the last few days working on that Godot game, mainly building new mechanics. This evening I started working on an interceptor, something that would jump out of the quicksand in order to disrupt the player&amp;rsquo;s jump. Here&amp;rsquo;s an example of how they look in the test bed:&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://media.lmika.org/videos/2025/godot-w2-sand-spinners.mp4&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;And yeah, they&amp;rsquo;re pretty much a carbon-copy of the Podoboos from Mario. But I think there&amp;rsquo;s a reason they&amp;rsquo;re still making an appearance in games, years after their debut in Super Mario Brothers. They&amp;rsquo;re quite a versatile enemy, making jumping challenges a bit more interesting than just seeing whether the player the clear a gap. Plus they&amp;rsquo;re reasonably easy to make.&lt;/p&gt;
&lt;p&gt;Another mechanic taken from Mario was a switch that revealed coins and tiles for a limited time. Hit it once and the child nodes of this &amp;ldquo;timed_limited_visible&amp;rdquo; scene are displayed and activated for 10 seconds, before they disappear again:&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://media.lmika.org/videos/2025/godot-w2-floor-switch.mp4&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Much like the blue P switch this mechanic takes inspiration from, the switch can only be activated once. So it may be only useful for bonuses and areas the player can afford to miss.&lt;/p&gt;
&lt;p&gt;I had to do some special handling for nested &lt;code&gt;TileMap&lt;/code&gt; nodes, since the player could still collide with them even when they&amp;rsquo;re hidden. How I solved this was nothing too spectacular: basically I just walk the child tree looking for &lt;code&gt;TileMap&lt;/code&gt; instances, and when encountering one, just enabling or disabling the first layer:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;func _show_and_activate_children():
    visible = true
    process_mode = Node.PROCESS_MODE_INHERIT
    for tm in find_children(&amp;#34;*&amp;#34;, &amp;#34;TileMap&amp;#34;, false):
        tm.set_layer_enabled(0, true)

func _hide_and_deactivate_children():
    visible = false
    process_mode = Node.PROCESS_MODE_DISABLED
    for tm in find_children(&amp;#34;*&amp;#34;, &amp;#34;TileMap&amp;#34;, false):
        tm.set_layer_enabled(0, false)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Building these elements was fun, but the main problem is that I&amp;rsquo;m struggling to come up with a centrepiece mechanic for level 2-1, something that defines the level in some way. I have an idea for level 2-2 — this world is set in a desert so I&amp;rsquo;m hoping to introduce a thirst mechanic — but level 2-1 I&amp;rsquo;m hoping to keep relatively plain so as to avoid overwhelming the player with too many new things. The fear is to avoid making it little more than what the player encountered in world 1: a series of jumping puzzles over pits. Sure, that&amp;rsquo;s pretty much the entire game in a way, but some variety would be nice.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;m hoping one of these mechanics could help here. I guess I&amp;rsquo;ll find one once I&amp;rsquo;ve start seriously building the level.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/04/01/started-working-on-world-and.html</link>
      <pubDate>Tue, 01 Apr 2025 20:52:50 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/04/01/started-working-on-world-and.html</guid>
      <description>&lt;p&gt;Started working on world 2, and one of the main mechanics of this world: quicksand. It won&amp;rsquo;t kill the player directly, but it will make it difficult for them to manoeuvre, and getting too low could cause death. Might be one of the more annoying mechanics in the game, but that&amp;rsquo;s kind of the point.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://media.lmika.org/videos/2025/level1-2-quicksand.mp4&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/03/24/a-bit-more-on-godot.html</link>
      <pubDate>Mon, 24 Mar 2025 21:39:10 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/03/24/a-bit-more-on-godot.html</guid>
      <description>&lt;p&gt;A bit more on Godot this evening, mainly working on pausing the game, and the end-of-level sequence. Have got something pretty close to what I was looking for: a very Mario-esc sequence where the player enters a castle, it start auto-walking the character, and the level stats show up and &amp;ldquo;spin&amp;rdquo; for a bit. Not too bad, although I may need to adjust the timing and camera a little to keep the stats from being unreadable.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://media.lmika.org/videos/2025/godot-ending-sequence.mp4&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Adventures In Godot: Respawning A Falling Platform</title>
      <link>https://lmika.org/2025/03/08/adventures-in-godot-respawning-a.html</link>
      <pubDate>Sat, 08 Mar 2025 11:35:07 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/03/08/adventures-in-godot-respawning-a.html</guid>
      <description>&lt;p&gt;My taste of going through a Godot tutorial last week has got me wanting more, so I&amp;rsquo;ve set about building a game with it. Thanks to my limited art skills, I&amp;rsquo;m using &lt;a href=&#34;https://brackeysgames.itch.io/brackeys-platformer-bundle&#34;&gt;the same asset pack&lt;/a&gt; that was used in the video, although I am planning to add a bit of my own here and there.&lt;/p&gt;
&lt;p&gt;But it&amp;rsquo;s the new mechanics I enjoy working on, such as adding falling platforms. If you&amp;rsquo;ve played any platformer, you know what these look like: platforms that are suspended in air, until the player lands on them, at which point gravity takes a hold and they start falling, usually into a pit killing the player in the process:&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://media.lmika.org/videos/2025/falling-platform-1.mp4&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;The platforms are built as a &lt;code&gt;CharacterBody2D&lt;/code&gt; with an &lt;code&gt;Area2D&lt;/code&gt; that will detect when a player enters the collision shape. When they do, a script will run which will have the platform &amp;ldquo;slipping&amp;rdquo; for a second, before the gravity is turned on and the platform falls under it&amp;rsquo;s own weight. The whole thing is bundled as a reusable scene which I could drag into the level I&amp;rsquo;m working on.&lt;/p&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2025/out-20250308-123202.png&#34; width=&#34;600&#34; height=&#34;391&#34; alt=&#34;Auto-generated description: A game development interface with a sprite and code editor is shown, from a software environment like Godot.&#34;&gt;
&lt;p&gt;I got the basics of this working reasonably quickly, yet today, I had a devil of a time going beyond that.
The issue was that I wanted the platform to respawn after it fell off the map, so that the player wouldn&amp;rsquo;t get soft-locked at at an area where the platform was needed to escape. After a false-start trying to reposition the platform at it&amp;rsquo;s starting point after it fell, I figured it was just easier to respawn the platform when the old one was removed. To do this I had to solve two problems:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;How do I get the platform starting point?&lt;/li&gt;
&lt;li&gt;How can I actually respawn the platform?&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;getting-the-starting-point&#34;&gt;Getting The Starting Point&lt;/h2&gt;
&lt;p&gt;A &lt;code&gt;Node2D&lt;/code&gt; object has the property &lt;a href=&#34;https://docs.godotengine.org/en/stable/classes/class_node2d.html#class-node2d-property-global-position&#34;&gt;global_position&lt;/a&gt;, which returns the position of the object based on the world coordinates. However, it seems like this position is not correct when the &lt;a href=&#34;https://docs.godotengine.org/en/stable/classes/class_object.html#class-object-private-method-init&#34;&gt;_init&lt;/a&gt; function of the attached script is called. I suspect this is because this function is called before the platform is added to the scene tree, when the final world coordinates are known.&lt;/p&gt;
&lt;p&gt;Fortunately, there exists the &lt;code&gt;_ready&lt;/code&gt; notification, which is invoked when the node is added to the scene tree. After some experimentation, I managed to confirm that &lt;code&gt;global_position&lt;/code&gt; properly was correct. So tracking the starting point is a simple as storing that value in a variable:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;var init_global_position = null

func _ready():
	init_global_position = global_position
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Another option is to use the &lt;code&gt;_enter_tree()&lt;/code&gt; notification. From &lt;a href=&#34;https://docs.godotengine.org/en/stable/tutorials/best_practices/godot_notifications.html#ready-vs-enter-tree-vs-notification-parented&#34;&gt;the documentation&lt;/a&gt;, it looks like either would probably work here, with the only difference being the order in which this notification is invoked on parents and children (&lt;code&gt;_enter_tree&lt;/code&gt; is called by the parent first, whereas &lt;code&gt;_ready&lt;/code&gt; is called by the children first).&lt;/p&gt;
&lt;h2 id=&#34;respawning-the-platform&#34;&gt;Respawning The Platform&lt;/h2&gt;
&lt;p&gt;The next trick was finding out how to respawn the platform. The usual technique for doing so, based on the results of my web searching, is to load the platform scene, &lt;a href=&#34;https://docs.godotengine.org/en/stable/classes/class_packedscene.html#description&#34;&gt;instantiate a new instance&lt;/a&gt; of it, and added it to the scene tree.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;@onready var FallingPlatform = preload(&amp;#34;res://scenes/falling_platform.tscn&amp;#34;)

func respawn():	
    var dup = FallingPlatform.instantiate()
    add_child(dup)
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Many of the examples I&amp;rsquo;ve seen online added the new scene node as a child of the current node. This wouldn&amp;rsquo;t work for me as I wanted to free the current node at the same time, and doing so would free the newly instantiated child. The fix for this was easy enough: I just added the new node as a child of the current scene.&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;@onready var FallingPlatform = preload(&amp;#34;res://scenes/falling_platform.tscn&amp;#34;)


func respawn():	
    var dup = FallingPlatform.instantiate()
    get_tree().current_scene.add_child(dup)
    queue_free()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I still had to reposition the new node to the spawn point. Fortunately the &lt;code&gt;global_position&lt;/code&gt; property is also settable, so it was simply a matter of setting that property before adding it to the tree (this is so that it&amp;rsquo;s correct when the newly instantiated node receives the &lt;code&gt;_ready&lt;/code&gt; notification).&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;@onready var FallingPlatform = preload(&amp;#34;res://scenes/falling_platform.tscn&amp;#34;)

func respawn():	
    var dup = FallingPlatform.instantiate()
    dup.global_position = init_global_position
    get_tree().current_scene.add_child(dup)
    queue_free()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This spawned the platform at the desired positioned, but there was a huge problem: when the player jumped on the newly spawn platform, it wouldn&amp;rsquo;t fall. The &lt;code&gt;Area2D&lt;/code&gt; connection was not invoking the script to turn on the gravity:&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://media.lmika.org/videos/2025/falling-platform-2.mp4&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;It took me a while to figured out what was going on, but I came to the conclusion that the packed scene was loading properly, but without the script attached. Turns out a &lt;a href=&#34;https://docs.godotengine.org/en/stable/classes/class_script.html&#34;&gt;Script&lt;/a&gt; is a resource separate from the scene, and can be loaded and attached to an object via the &lt;a href=&#34;https://docs.godotengine.org/en/stable/classes/class_object.html#class-object-method-set-script&#34;&gt;set_script&lt;/a&gt; method:&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;@onready var FallingPlatform = preload(&amp;#34;res://scenes/falling_platform.tscn&amp;#34;)
@onready var FallingPlatformScript = preload(&amp;#34;res://scripts/falling_platform.gd&amp;#34;)

func respawn():	
    var dup = FallingPlatform.instantiate()
    dup.set_script(FallingPlatformScript)

    dup.global_position = init_global_position
    get_tree().current_scene.add_child(dup)
    queue_free()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Finally, after figuring all this out, I was able to spawn a new falling platform, have it positioned at the starting position of the old platform, and react to the player standing on it.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://media.lmika.org/videos/2025/falling-platform-3.mp4&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;The time it took to work this out is actually a little surprising. I was expecting others to run into the same problem I was facing, where they were trying to instantiate a scene only to have the scripts not do anything. Yet it took me 45 minutes of web searching through Stack Overflow and forum posts that didn&amp;rsquo;t solve my problem. It was only after a bit of experimentation and print-debugging on my own that I realised that I actually had to attached the script after instantiating the node.&lt;/p&gt;
&lt;p&gt;To be fair, I will attribute some of this to not understanding the problem at first: I actually thought the &lt;code&gt;Area2D&lt;/code&gt; wasn&amp;rsquo;t actually being instantiated at all. Yet not one of the Stack Overflow answers or forum post floated the possibility that the script wasn&amp;rsquo;t being loaded alongside the scene.  This does suggest to me that my approach may not be optimal. There does exist a &amp;ldquo;Local to Scene&amp;rdquo; switch in the script inspector that could help, although turning it on doesn&amp;rsquo;t seem to do much. But surely there must be some way to instantiate the script alongside the scene.&lt;/p&gt;
&lt;p&gt;Anyway, that&amp;rsquo;s for later. For now, I&amp;rsquo;m happy that I&amp;rsquo;ve got something that works.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/03/02/it-lives.html</link>
      <pubDate>Sun, 02 Mar 2025 16:31:50 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/03/02/it-lives.html</guid>
      <description>&lt;p&gt;It lives!&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://media.lmika.org/videos/2025/godot-tutorial.mp4&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/02/24/prototyped-a-game-i-had.html</link>
      <pubDate>Mon, 24 Feb 2025 21:02:53 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/02/24/prototyped-a-game-i-had.html</guid>
      <description>&lt;p&gt;Prototyped a game I had in mind, sort of a 2D Sokoban-like thing, where you control a robot with a retractable pushing arm that is to push gems to a &amp;ldquo;receiver&amp;rdquo; tile. Not entirely sure if it&amp;rsquo;s fun enough to actually build.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://media.lmika.org/videos/2025/naclbot-prototype.mp4&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Used &lt;a href=&#34;https://pixijs.com&#34;&gt;PixiJS&lt;/a&gt; to build it. Not a bad framework.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/02/14/so-sorry-to-hear-about.html</link>
      <pubDate>Fri, 14 Feb 2025 16:04:47 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/02/14/so-sorry-to-hear-about.html</guid>
      <description>&lt;p&gt;So sorry to hear about the loss of &lt;a href=&#34;https://micro.blog/merlinmann&#34;&gt;@merlinmann&lt;/a&gt;&#39;s pet lizard, which I just learnt is a central bearded dragon (they&#39;re good looking lizards). I didn&#39;t include it in the clip but he had some really nice things to say about it.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2025/podcast-clip-2025-02-14t060443z.mp4&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/02/11/request-for-any-opensource-projects.html</link>
      <pubDate>Tue, 11 Feb 2025 10:39:58 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/02/11/request-for-any-opensource-projects.html</guid>
      <description>&lt;p&gt;Request for any open-source projects that want to put banner ads on their site: please consider hard-coding the height of your banner to prevent the ad from reflowing the page. Otherwise, it may have an impact on the experience of those reading your docs.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://media.lmika.org/videos/2025/mermade-ads-autoscrolling.mp4&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/02/11/oh-thats-nice-looks-like.html</link>
      <pubDate>Tue, 11 Feb 2025 09:00:32 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/02/11/oh-thats-nice-looks-like.html</guid>
      <description>&lt;p&gt;Oh, that&amp;rsquo;s nice. Looks like Obsidian allows you to set the starting ordinal for numbered lists.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://media.lmika.org/videos/2025/obsidian-markdown-ol-demo.mp4&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;This was something I wish &lt;a href=&#34;https://lmika.org/2020/09/01/on-ordered-lists.html&#34;&gt;vanilla Markdown had&lt;/a&gt; for a while, so it&amp;rsquo;s good to see at least one Markdown editor embracing this.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2025/01/19/just-heard-the-name-for.html</link>
      <pubDate>Sun, 19 Jan 2025 14:16:38 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2025/01/19/just-heard-the-name-for.html</guid>
      <description>&lt;p&gt;Just heard the name for John&#39;s new app. Must say I kinda like it. It grows on you. No spoilers (except in the clip), but I do appreciate that it follows a similar vein to the &lt;a href=&#34;https://lmika.org/2024/12/28/im-a-bit-behind-atp.html&#34;&gt;crazy names I came up with&lt;/a&gt;. It just does it so much better.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2025/podcast-clip-2025-01-19t041634z.mp4&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2024/12/28/more-fun-today-working-on.html</link>
      <pubDate>Sat, 28 Dec 2024 10:30:36 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2024/12/28/more-fun-today-working-on.html</guid>
      <description>&lt;p&gt;More fun today working on Blogging Tools. Finished a feature for uploading larger videos to object storage so they can be added to a post using the standard video tag, as opposed to an embedded video player. If you see the screencast below, that means it&amp;rsquo;s working.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://media.lmika.org/videos/2024/blogging-tools-video-upload.mp4&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2024/12/24/thats-it-im-never-going.html</link>
      <pubDate>Tue, 24 Dec 2024 09:45:03 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2024/12/24/thats-it-im-never-going.html</guid>
      <description>&lt;p&gt;That&amp;rsquo;s it! I&amp;rsquo;m never going to use a framework that uses Webpack or installs more than 5 Node dev dependencies. Why? Because every time I check it out to work on it, all these dependencies break, and I&amp;rsquo;m left to spend hours updating them.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2024/every-effin-time.mp4&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Never again! 😡&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2024/12/22/i-wonder-if.html</link>
      <pubDate>Sun, 22 Dec 2024 19:31:20 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2024/12/22/i-wonder-if.html</guid>
      <description>&lt;p&gt;I wonder if we could convince Ben to order another run of Stratechery mugs shaped like the one he drinks from. I really like my  Stratechery mug — it&#39;s one I often use — yet the mug he describes here is intriguing.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2024/podcast-clip-2024-12-22t093116z.mp4&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2024/12/07/in-other-buildingsmallthingsformyself.html</link>
      <pubDate>Sat, 07 Dec 2024 13:19:05 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2024/12/07/in-other-buildingsmallthingsformyself.html</guid>
      <description>&lt;p&gt;In other building-small-things-for-myself news, I spent a bit of time this morning on the image processor for Blogging Tools. The big new change was adding support for working with multiple source images, instead of just one. This made way for a new &amp;ldquo;Phone Shot&amp;rdquo; processor, which arranges multiple screenshots of phone apps in a row, while also downscaling them and proving some quick crops and distribution options.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://media.lmika.org/cleanshot-2024-12-07-11.52.08.mp4&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;This should reduce the vertical size of mobile app screenshots I post here, something that&amp;rsquo;s been bothering me a little.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2024/11/29/agree-with-manton.html</link>
      <pubDate>Fri, 29 Nov 2024 16:20:43 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2024/11/29/agree-with-manton.html</guid>
      <description>&lt;p&gt;Agree with &lt;a href=&#34;https://micro.blog/manton&#34;&gt;@manton&lt;/a&gt; here. I used to be quite religious about Test Driven Development, but I&#39;m less so nowadays. For the simple stuff, it works great; but for anything larger, you know little about how your going to build something until after you build it. Only then should you lock it in with tests.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2024/podcast-clip-2024-11-29t062040z.mp4&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2024/11/15/listening-to-this.html</link>
      <pubDate>Fri, 15 Nov 2024 07:57:50 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2024/11/15/listening-to-this.html</guid>
      <description>&lt;p&gt;Listening to this part of HV got me wondering if the secret to punctual trains is just a whole lot of them. You&amp;rsquo;re less likely  to do something to delay a train — like hold the doors open — if you know the next one&amp;rsquo;s only a few minutes away, and will arrive on time. One builds on the other.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2024/podcast-clip-2024-11-14t215746z.mp4&#34; poster=&#34;https://lmika.org/uploads/2024/d99c0e70c2.png&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2024/11/06/just-to-add.html</link>
      <pubDate>Wed, 06 Nov 2024 15:48:21 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2024/11/06/just-to-add.html</guid>
      <description>&lt;p&gt;Just to add one point of anecdata to Ben&amp;rsquo;s experience: I&amp;rsquo;ve never been happy with the performance of the mobile radio of Pixel phones. You can be in the middle of the CBD and still experience weird dropouts while using mobile data. It&amp;rsquo;s quite frustrating.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2024/podcast-clip-2024-11-11t110532z.mp4&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2024/10/05/while-on-my.html</link>
      <pubDate>Sat, 05 Oct 2024 17:10:47 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2024/10/05/while-on-my.html</guid>
      <description>&lt;p&gt;While on my walk, I stopped briefly to clear a stone from my shoe and this &lt;a href=&#34;https://en.wikipedia.org/wiki/Australasian_swamphen&#34;&gt;purple swamphen&lt;/a&gt; (or pūkeko for our Kiwi friends) came up quite close to me. Not sure why. Looking for food maybe?&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2024/purple-swamphen.mp4&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2024/08/06/my-recent-exploration.html</link>
      <pubDate>Tue, 06 Aug 2024 21:39:25 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2024/08/06/my-recent-exploration.html</guid>
      <description>&lt;p&gt;My recent exploration of &lt;a href=&#34;https://fyne.io&#34;&gt;Fyne&lt;/a&gt; has got me looking at building a level editor again. Have started work on the viewport, with camera movement using the WASD keys, and a basic mouse tracker for painting cells. Feels pretty good so far, although the cell mouse tracker might need some refinement.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2024/level-editor-screencast.mov&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2024/08/04/spending-some-time.html</link>
      <pubDate>Sun, 04 Aug 2024 22:20:36 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2024/08/04/spending-some-time.html</guid>
      <description>&lt;p&gt;Spending some time with the birds. Archie&amp;rsquo;s on heat, which is why she&amp;rsquo;s making those chirping noises. Ivy&amp;rsquo;s happily keeping to herself off to the side.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2024/archie-ivy-hangout.mp4&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Day Trip to Bundanoon</title>
      <link>https://lmika.org/2024/06/10/day-trip-to-bundanoon.html</link>
      <pubDate>Sun, 09 Jun 2024 23:26:00 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2024/06/10/day-trip-to-bundanoon.html</guid>
      <description>&lt;p&gt;Decided to go on a day trip to Bundanoon today. It&amp;rsquo;s been five years since I last visited and I remember liking the town enough that I thought it&amp;rsquo;d be worth visiting again. It&amp;rsquo;s not close, around 1 hour and 40 minutes from Canberra, but it not far either and I thought it would be a nice way to spend the day. Naturally, others agreed, which I guess explains why it was busier than I expected, what with the long weekend and all. Fortunately, it wasn&amp;rsquo;t too crowded, and I still had a wonderful time.&lt;/p&gt;
&lt;p&gt;The goal was to go on a bush-walk first. I chose to do the Erith Coal Mine track, for no particular reason other than it sounded interesting. This circuit track was meant to take you to a waterfall by an old coal mine. However, the track leading to the actual mine was closed, thanks to the recent rain. In fact, if I could describe the bush-walks in one word, it would be &amp;ldquo;wet&amp;rdquo;. The ground was soaked, as were the paths, and although conditions were lovely, the paths were still very slippery.&lt;/p&gt;
&lt;div class=&#34;img-gallery&#34;&gt;
&lt;figure&gt;
&lt;img src=&#34;https://lmika.org/uploads/2024/pxl-20240609-010511518.jpg&#34;
     
        alt=&#34;Auto-generated description: A narrow, rocky trail winds through thick, bushy vegetation and trees under a clear blue sky.&#34; 
     
      /&gt;

  &lt;figcaption&gt;
  
  Eirth Coal Mine track starting off pretty well, if a little wet.
  &lt;/figcaption&gt;

&lt;/figure&gt;
&lt;figure&gt;
&lt;img src=&#34;https://lmika.org/uploads/2024/pxl-20240609-011050785.jpg&#34;
     
        alt=&#34;Auto-generated description: A narrow, winding trail with wooden steps descends through a dense forest of tall trees and thick vegetation.&#34; 
     
      /&gt;

  &lt;figcaption&gt;
  
  Starting our desent into the vally.
  &lt;/figcaption&gt;

&lt;/figure&gt;
&lt;figure&gt;
&lt;img src=&#34;https://lmika.org/uploads/2024/pxl-20240609-011536112.jpg&#34;
     
        alt=&#34;Auto-generated description: A metal railing pathway leads through a wooded area with numerous trees and plants under a clear blue sky.&#34; 
     
      /&gt;

  &lt;figcaption&gt;
  
  Continuing our desent via these elevated platforms. The stairs here were very narrow.
  &lt;/figcaption&gt;

&lt;/figure&gt;
&lt;figure&gt;
&lt;img src=&#34;https://lmika.org/uploads/2024/pxl-20240609-012326198.jpg&#34;
     
        alt=&#34;Auto-generated description: A fenced-off construction site with Danger Construction Site signs is located next to a flowing waterway amidst surrounding greenery.&#34; 
     
      /&gt;

  &lt;figcaption&gt;
  
  I assume the path is meant to cross this flat stone, which I&amp;#39;m guessing is either dry, or has a small stream. But all the recent rain has turned it into a torrent.
  &lt;/figcaption&gt;

&lt;/figure&gt;
&lt;figure&gt;
&lt;img src=&#34;https://lmika.org/uploads/2024/pxl-20240609-012638908.jpg&#34;
     
        alt=&#34;Auto-generated description: A weathered picnic table and bench set is situated in a natural, wooded area with a signpost nearby.&#34; 
     
      /&gt;

  &lt;figcaption&gt;
  
  My make shift walking staff, which prooved useful getting through the slippery parts of the trail.
  &lt;/figcaption&gt;

&lt;/figure&gt;
&lt;figure&gt;
&lt;img src=&#34;https://lmika.org/uploads/2024/pxl-20240609-012854757.jpg&#34;
     
        alt=&#34;Auto-generated description: A winding gravel road curves through a dense forested area under a clear blue sky.&#34; 
     
      /&gt;

  &lt;figcaption&gt;
  
  View behind me as a start climbing back to road level.
  &lt;/figcaption&gt;

&lt;/figure&gt;
&lt;/div&gt;
&lt;figure&gt;
&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2024/bundanoon-walk-1.mov&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;
&lt;figcaption&gt;I assume the mine was across these rocks, but there was no way I was going to cross it.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;After completing that circuit in probably 45 minutes, my appetite for bush-walking was still unsatisfied, so I tried the Fairy Bower Falls walk next. This was not as steep as the first one, but it turned to be a much harder track due to how wet and slippery everything was.&lt;/p&gt;
&lt;div class=&#34;img-gallery&#34;&gt;
&lt;figure&gt;
&lt;img src=&#34;https://lmika.org/uploads/2024/pxl-20240609-015027509.jpg&#34;
     
        alt=&#34;Auto-generated description: A dirt pathway in a forested area is marked by a sign indicating Fairy Beaver Walk and features another small signpost further along the path.&#34; 
     
      /&gt;

  &lt;figcaption&gt;
  
  Enterance to Fairy Bower Falls walk.
  &lt;/figcaption&gt;

&lt;/figure&gt;
&lt;figure&gt;
&lt;img src=&#34;https://lmika.org/uploads/2024/pxl-20240609-015716731.jpg&#34;
     
        alt=&#34;Auto-generated description: A narrow, rocky trail winds through a dense, wooded area with sunlight filtering through the trees.&#34; 
     
      /&gt;

  &lt;figcaption&gt;
  
  This track wet and very slippery. Much of it was barely walkable if you wanted to keep your shoes dry.
  &lt;/figcaption&gt;

&lt;/figure&gt;
&lt;figure&gt;
&lt;img src=&#34;https://lmika.org/uploads/2024/pxl-20240609-020820102.jpg&#34;
     
        alt=&#34;Auto-generated description: A dense thicket of bushes and trees with varying shades of green foliage.&#34; 
     
      /&gt;

  &lt;figcaption&gt;
  
  This was the best shot I have of the waterfall, which is pretty bad, but I can assure you, it was there amongst the trees.
  &lt;/figcaption&gt;

&lt;/figure&gt;
&lt;figure&gt;
&lt;img src=&#34;https://lmika.org/uploads/2024/pxl-20240609-021321005.jpg&#34;
     
        alt=&#34;Auto-generated description: A muddy forest trail is flanked by greenery with wooden planks placed sporadically for stability.&#34; 
     
      /&gt;

  &lt;figcaption&gt;
  
  The walk back to the road. This was much easier, partly because it was uphill but also because I know I already walked this part once.
  &lt;/figcaption&gt;

&lt;/figure&gt;
&lt;/div&gt;
&lt;p&gt;I stopped short of the end of this one too, as it seems the path was washed away. But I did manage to get a glimpse of the waterfall, so I&amp;rsquo;m considering that a win.&lt;/p&gt;
&lt;p&gt;After that, I returned to the town for lunch and some train spotting. The train line to Goulburn runs through Bundanoon, and the last time I was there, there was probably a freight train every hour or so. So I was hoping to get a good view of a lot of freight traffic. Maybe shoot a video of a train passing through the station I could share here.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2024/pxl-20240609-034857614.jpg&#34; width=&#34;600&#34; height=&#34;451&#34; alt=&#34;Auto-generated description: A quaint train station platform with a sign that reads Bundanoon is shown, surrounded by trees and blue skies.&#34;&gt;
&lt;figcaption&gt;Bundanoon train station.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I had lunch outside and walked around the town a little, always within sight of the railway line, hoping for at least one train to pass through. But luck wasn&amp;rsquo;t on my side, and it wasn&amp;rsquo;t until I was on my way home that I saw what I think was a grain train passing through Wingello. I pulled over to take a video, and while I miss the locomotive, I got a reasonable enough recording of the wagons.&lt;/p&gt;
&lt;figure&gt;
&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2024/bundanoon-freight-3.mov&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;
&lt;figcaption&gt;Stopping by the side of the road to film these grain wagons passing by.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Being a little more hopeful, I stopped at Tallong, the next town along the road. I bought a coffee and went to the station to drink it and hopefully see a train pass through. Sadly, it was not to be. So I decided to head back home.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2024/pxl-20240609-043946516.jpg&#34; width=&#34;600&#34; height=&#34;451&#34; alt=&#34;Auto-generated description: A quiet train station platform is shown with tracks stretching into the distance and surrounded by trees.&#34;&gt;
&lt;figcaption&gt;Tallong train station.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;So the train spotting was a bust, and the bush-walks were difficult, but all in all it was quite a nice day. I look forward to my next visit to Bundanoon. Lets hope the trains are running a little more frequently then.&lt;/p&gt;
&lt;p&gt;&lt;audio controls=&#34;controls&#34; src=&#34;https://cdn.uploads.micro.blog/25293/2024/day-trip-to-bundanoon.mp3&#34; preload=&#34;metadata&#34; style=&#34;display: none;&#34;&gt;&lt;/audio&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2024/06/06/attempting-to-give.html</link>
      <pubDate>Thu, 06 Jun 2024 21:56:07 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2024/06/06/attempting-to-give.html</guid>
      <description>&lt;p&gt;Attempting to give head scratches while recording video is more difficult than it looks. 🦜&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2024/2024-head-scratches.mov&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Small Calculator</title>
      <link>https://lmika.org/2024/04/07/small-calculator.html</link>
      <pubDate>Sun, 07 Apr 2024 21:19:01 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2024/04/07/small-calculator.html</guid>
      <description>&lt;p&gt;&lt;strong&gt;Date:&lt;/strong&gt; Unknown, but probably around 2005&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Status:&lt;/strong&gt; Retired&lt;/p&gt;
&lt;p&gt;Give me Delphi 7, a terminal control, and an expression parser, and of
course I&amp;rsquo;m going to build a silly little REPL program.&lt;/p&gt;
&lt;p&gt;I can&amp;rsquo;t really remember why I though this was worth spending time on,
but I was always interested in little languages (still am), and I guess
I though having a desk calculator that used one was worth having. I was
using a parser library I found on Torry&amp;rsquo;s Delphi Pages (the best site
at the time to get free controls for Delphi) for something else, and
after getting a control which simulated a terminal, I wrote a very
simple REPL loop which used the two.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2024/0720335caa.jpg&#34;&gt;
&lt;figcaption&gt;Example of basic usage.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;And credit to the expression parser developer: it was pretty decent. It
supported assignments and quite a number of functions. Very capable for
powering a desk calculator.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2024/2bd70652b6.jpg&#34;&gt;
&lt;figcaption&gt;List of functions the parser library supported.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;For a while the app was simply that. But, as with most things like this,
I got the itch to extend it a little. I started by added a few extra
commands. Simple things, like one that would echo something to the
screen. All quite innocent, if a little unnecessary. But it soon grew to
things like if statements, blocks using curly brackets, and function
definitions.&lt;/p&gt;
&lt;p&gt;It even extended to small batch scripts, like the one below.  The &lt;a href=&#34;https://folio.red/page/small-calculator-commands&#34;&gt;full
set of commands is listed here&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;x := 2
y := 3

if {x = y} {echo 5} \
  {echo 232}

return 
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These never went anywhere beyond a few tests. The extra commands was not
really enough to be useful, and they were all pretty awful. I was
already using a parser library so I didn&amp;rsquo;t want to spend any time
extending it. As a result, many of these extensions were little more
than things that scanned and spliced strings together. It was more of a
macro language rather than anything else.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2024/e47c08b61f.jpg&#34;&gt;
&lt;figcaption&gt;The full set of extensions.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Even with the expression parser the program didn&amp;rsquo;t see a great deal of
use. I was working on the replacement at the time which would eventually
be much more capable, and as soon as that was ready, this program fell
out of use.&lt;/p&gt;
&lt;p&gt;Even so, it was still quite a quirky little program to make a bit of an
impression.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://media.lmika.org/small-calc-usage.mov&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2024/04/06/ive-released-a.html</link>
      <pubDate>Sat, 06 Apr 2024 11:59:36 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2024/04/06/ive-released-a.html</guid>
      <description>&lt;p&gt;🎥 I&amp;rsquo;ve released a video tutorial on &lt;a href=&#34;https://youtu.be/-HsCUeDoy1k&#34;&gt;how to use and configure the Sidebar For Tiny Theme&lt;/a&gt;. This walks through the process of creating and using a custom Micro.blog theme to configure the sidebar with custom HTML. Hope others find it useful.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2024/03/30/picnic-train-now.html</link>
      <pubDate>Sat, 30 Mar 2024 11:17:22 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2024/03/30/picnic-train-now.html</guid>
      <description>&lt;p&gt;Picnic train, now boarding. 🚂&lt;/p&gt;
&lt;p&gt;&lt;video controls=&#34;controls&#34; playsinline=&#34;playsinline&#34; src=&#34;https://cdn.uploads.micro.blog/25293/2024/image.mp4&#34; width=&#34;640&#34; height=&#34;360&#34; poster=&#34;https://lmika.org/uploads/2024/poster.png&#34; preload=&#34;none&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Photo Bucket Update: More On Galleries</title>
      <link>https://lmika.org/2024/03/05/photo-bucket-update.html</link>
      <pubDate>Tue, 05 Mar 2024 21:43:05 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2024/03/05/photo-bucket-update.html</guid>
      <description>&lt;p&gt;Spent a bit more time working on Photo Bucket this last week&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;, particularly around galleries. They&amp;rsquo;re progressing quite well. I&amp;rsquo;m made some strides in getting two big parts of the UI working now: adding and removing images to galleries, and re-ordering gallery items via drag and drop.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;ll talk about re-ordering first. This was when I had to bite the bullet and start coding up some JavaScript. Usually I&amp;rsquo;d turn to &lt;a href=&#34;https://stimulus.hotwired.dev&#34;&gt;Stimulus&lt;/a&gt; for this but I wanted to give &lt;a href=&#34;https://blog.jim-nielsen.com/2023/html-web-components/&#34;&gt;HTML web components&lt;/a&gt; a try. And so far, they&amp;rsquo;ve been working quite well.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2024/moving-gallery-images.mov&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;The gallery page is generated server-side into the following HTML:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;main&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;pb-draggable-imageset&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;href&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/_admin/galleries/1/items&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;class&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;image-grid&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;pb-draggable-image&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;position&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;item-id&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;7&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;href&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/_admin/photos/3&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;img&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;src&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/_admin/img/web/3&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;a&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;pb-draggable-image&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;pb-draggable-image&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;position&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;item-id&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;4&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;href&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/_admin/photos/4&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;img&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;src&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/_admin/img/web/4&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;a&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;pb-draggable-image&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;pb-draggable-image&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;position&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;2&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;item-id&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;8&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;a&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;href&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/_admin/photos/1&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &amp;lt;&lt;span style=&#34;color:#f92672&#34;&gt;img&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;src&lt;/span&gt;&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/_admin/img/web/1&amp;#34;&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;a&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;pb-draggable-image&lt;/span&gt;&amp;gt;        
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;pb-draggable-imageset&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/&lt;span style=&#34;color:#f92672&#34;&gt;main&lt;/span&gt;&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Each &lt;code&gt;&amp;lt;pb-draggable-image&amp;gt;&lt;/code&gt; node is a direct child of an &lt;code&gt;&amp;lt;pb-draggable-imageset&amp;gt;&lt;/code&gt;. The idea is that the user can rearrange any of the &lt;code&gt;&amp;lt;pb-draggable-image&amp;gt;&lt;/code&gt; elements within a single &lt;code&gt;&amp;lt;pb-draggable-imageset&amp;gt;&lt;/code&gt; amongst themselves. Once the user has moved an image onto to another one, the image will signal its new position by firing a custom event. The containing &lt;code&gt;&amp;lt;pb-draggable-imageset&amp;gt;&lt;/code&gt; element is listening to this event and will respond by actually repositioning the child element and sending a JSON message to the backend to perform the move in the database.&lt;/p&gt;
&lt;p&gt;A lot of this was based on the MDN documentation for &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API&#34;&gt;drag and drop&lt;/a&gt; and it follows the examples quite closely. I did find a few interesting things though. My first attempt at this was to put it onto the &lt;code&gt;&amp;lt;pb-draggable-image&amp;gt;&lt;/code&gt; element, but I wasn&amp;rsquo;t able to get any drop events when I did. Moving the &lt;code&gt;draggable&lt;/code&gt; attribute onto the &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; element seemed to work. I not quite sure why this is. Surely I can&amp;rsquo;t think of any reason as to why it wouldn&amp;rsquo;t work. It may had something else, such as how I was initialising the HTTP components.&lt;/p&gt;
&lt;p&gt;Speaking of HTML components, there was a time where the custom component&amp;rsquo;s &lt;code&gt;connectedCallback&lt;/code&gt; method was being called before the child &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; elements were present in the DOM. This was because I had the &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag in the the HTML head and configured to be evaluated during parsing. Moving it to the end of the body and loading it as a module fixed that issue. Also I found that moving elements around using &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/API/Element/before&#34;&gt;element.before&lt;/a&gt; and &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/API/Element/after&#34;&gt;element.after&lt;/a&gt; would actually call &lt;code&gt;connectedCallback&lt;/code&gt; and &lt;code&gt;disconnectedCallback&lt;/code&gt; each time, meaning that any event listeners registered within &lt;code&gt;connectedCallback&lt;/code&gt; would need to be de-registered, otherwise events would be handled multiple times. This book-keeping was slightly annoying, but it worked.&lt;/p&gt;
&lt;p&gt;Finally, there was moving the items with the database. I&amp;rsquo;m not sure how best to handle this, but I have that method that seems to work. What I&amp;rsquo;m doing is tracking the position of each &amp;ldquo;gallery item&amp;rdquo; using a &lt;code&gt;position&lt;/code&gt; field. This field would be 1 for the first item, 2 for the next, and so on for each item in the gallery. The result of fetching items would just order using this field, so as long as they&amp;rsquo;re distinct, they don&amp;rsquo;t need to be a sequence incrementing by 1, but I wanted to keep this as much as possible.&lt;/p&gt;
&lt;p&gt;The actual move involves two update queries. The first one will update the positions of all the items that are to shift left or right by one to &amp;ldquo;fill the gap&amp;rdquo;. The way it does this is that when an item is moved from position X to position Y, the value of &lt;code&gt;position&lt;/code&gt; between X and Y would be changed by +1 if X &amp;gt; Y, or by –1 if Y &amp;gt; X. This is effectively the same as setting position X to X + 1, and so on, but done using one &lt;code&gt;UPDATE&lt;/code&gt; statement. The second query just sets the position of item X to Y.&lt;/p&gt;
&lt;p&gt;So that&amp;rsquo;s moving gallery items. I&amp;rsquo;m not sure how confident I am with this approach, but I&amp;rsquo;ve been testing this, both manually and by writing unit tests. It&amp;rsquo;s not quite perfect yet: I&amp;rsquo;m still finding bugs (I found some while coming up with these screencasts). Hopefully, I&amp;rsquo;ll be able to get to the bottom of them soon.&lt;/p&gt;
&lt;p&gt;The second bit of work was to actually add and remove images in the gallery themselves. This, for the moment, is done using a &amp;ldquo;gallery picker&amp;rdquo; which is available in the image details. Clicking &amp;ldquo;Gallery&amp;rdquo; while viewing an image will show the list of galleries in the system, with toggles on the left. The galleries an image already belongs to is enabled, and the user can choose the galleries they want the image to be in by switching the toggles on and off. These translate to &lt;code&gt;inserts&lt;/code&gt; and &lt;code&gt;remove&lt;/code&gt; statements behind the scenes.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://lmika.org/uploads/2024/adding-removing-images-to-galleries.mov&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;The toggles are essentially just HTML and CSS, and a bulk of the code was &lt;a href=&#34;https://www.w3schools.com/howto/howto_css_switch.asp&#34;&gt;taken from this example&lt;/a&gt;, with some tweaks. They look good, but I think I may need to make them slightly smaller for mouse and keyboard.&lt;/p&gt;
&lt;p&gt;I do see some downside with this interaction. First, it reverses the traditional idea of adding images to a gallery: instead of doing that, your selecting galleries for an image. I&amp;rsquo;m not sure if this would be confusing for others (it is modelled on how Google Photos works). Plus, there&amp;rsquo;s no real way to add images in bulk. Might be that I&amp;rsquo;ll need to add a way to select images from the &amp;ldquo;Photos&amp;rdquo; section and have a dialog like this to add or remove them all from a gallery. I think this would go far in solving both of these issues.&lt;/p&gt;
&lt;p&gt;So that&amp;rsquo;s where things are. Not sure what I&amp;rsquo;ll work on next, but it may actually be import and export, and the only reason for this is that I screwed up the base model and will need to make some breaking changes to the DB schema. And I want to have a version of export that&amp;rsquo;s compatible with the original schema that I can deploy to the one and only production instance of Photo Bucket so that I can port the images and captions over to the new schema. More on this in the future, I&amp;rsquo;m sure.&lt;/p&gt;
&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&#34;fn:1&#34;&gt;
&lt;p&gt;Apparently I&amp;rsquo;m more than happy to discuss work in progress, yet when it comes to talking about something I&amp;rsquo;ve finished, I freeze up. 🤷&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
</description>
    </item>
    
    <item>
      <title>Photo Bucket Galleries and Using the HTML Popover API</title>
      <link>https://lmika.org/2024/02/19/spent-a-bit.html</link>
      <pubDate>Mon, 19 Feb 2024 22:05:48 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2024/02/19/spent-a-bit.html</guid>
      <description>&lt;p&gt;Spent a bit more on Photo Bucket this evening. Tonight I started working on galleries, which&amp;rsquo;ll work more or less like albums.&lt;/p&gt;
&lt;p&gt;At the moment you can create a gallery and add a photo to it. Most of the work so far has been backend so the UI is pretty rough. Eventually you&amp;rsquo;ll be able to do things like rearrange photos within galleries, but for the moment they&amp;rsquo;ll just be added to the end.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2024/galleries.mov&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;I did need to add some modals to the UI, such as the New Gallery model that&amp;rsquo;s shown for the gallery name. This gave me the opportunity to try out the new &lt;a href=&#34;https://12daysofweb.dev/2023/popover-api/&#34;&gt;popover API&lt;/a&gt;. And yeah, it does exactly what it says on the tin: add the &lt;code&gt;popover&lt;/code&gt; attribute to an element and it becomes a working popover (at least in the latest version of Vivaldi). Must say it&amp;rsquo;s impressive that this is now possible with HTML alone.&lt;/p&gt;
&lt;p&gt;The initial version of the modals used a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; for the popover target. And while that worked, there were some small annoyances. First was that the form within the popover didn&amp;rsquo;t get focus when the popover was displayed. It would be nice to click &amp;ldquo;New&amp;rdquo; and start typing out the gallery name. But this is a small thing that&amp;rsquo;s easily solvable with JavaScript, so it&amp;rsquo;s no big deal.&lt;/p&gt;
&lt;p&gt;The second, slightly larger one, was that dismissing the popover by clicking outside of it will not eat the input. If you were to click a sidebar link while the New Gallery model is opened, you&amp;rsquo;ll end up on that newly selected page. I&amp;rsquo;m not a fan of this. Dismissing the popover feels like its own user gesture, and I fear the user accidentally activating things when all they&amp;rsquo;re trying to do is dismiss the popover (it&amp;rsquo;s not in place now, but I am planning to dim the background when the Create Gallery modal is visible).&lt;/p&gt;
&lt;p&gt;Fortunately, there&amp;rsquo;s a simple solution to this. It turns out that replacing the &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; element with a &lt;code&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt; element would solves both problems. It works seamlessly with the new popover attributes, yet showing the dialog will give focus to the form, and will eat the click when the user dismisses it.&lt;/p&gt;
&lt;p&gt;Perfect. Looks like I&amp;rsquo;ve delayed the need for JavaScript a little longer (it will come eventually; it always will).&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Build Indicators</title>
      <link>https://lmika.org/2024/01/29/build-indicators.html</link>
      <pubDate>Mon, 29 Jan 2024 19:31:00 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2024/01/29/build-indicators.html</guid>
      <description>&lt;p&gt;&lt;strong&gt;AKA:&lt;/strong&gt; Das Blinkenlights&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Date:&lt;/strong&gt; 2017 — now&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Status:&lt;/strong&gt; Steady Green&lt;/p&gt;
&lt;p&gt;I sometimes envy those that work in hardware. To be able to build
something that one can hold and touch. It&amp;rsquo;s something you really cannot
do with software. And yeah, I dabbled a little with Arduino, setting up
sketches that would run on prebuilt shields, but I never went beyond the
point of building something that, however trivial or crappy, I could
call my own.&lt;/p&gt;
&lt;p&gt;Except for this one time.&lt;/p&gt;
&lt;p&gt;And I admit that this thing is pretty trivial and crappy: little more
than some controllable LEDs. But the ultimate irony is that it turned
out to be quite useful for a bunch of software projects. &lt;/p&gt;
&lt;h3 id=&#34;the-hardware&#34;&gt;The Hardware&lt;/h3&gt;
&lt;figure&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2024/a12fd62320.jpg&#34;&gt;
&lt;figcaption&gt;The build indicator light shield, on top of an Arduino.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I built this Arduino shield a while ago, probably something like 2013.
It&amp;rsquo;s really not that complicated: just a bunch of LEDs wired up in
series to a bunch of resistors atop an Arduino prototyping shield. The
LEDs can be divided up into two groups of three, with each group having
a red, amber, and green LED, arrange much like two sets of traffic
lights. I&amp;rsquo;m using the analogue pins of the Arduino, making it possible
to dim the LEDs (well, &amp;ldquo;dimmed&amp;rdquo;: the analogue pins are little more
than a square pulse with an adjustable duty cycle).&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2024/232a7216e3.jpg&#34;&gt;
&lt;figcaption&gt;Build indicator shield beside a rather dusty Arduino Duemilanove.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2024/5df18b0f71.jpg&#34;&gt;
&lt;figcaption&gt;The underside of the shield, show the connection between the resistors and the LEDs.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;I can&amp;rsquo;t remember why I built this shield originally: it might had
something to do with train signals, or maybe they were intended as
indicators right out of the box. But after briefly using them for their
original purpose, it sat on my desk for a while before I started using
them as indicator lights. Their first use was for some tool that would
monitor the download and transcode of videos. This would take between
45–60 minutes, and it was good to be able to start the job, leave the
room, and get the current progress without having to wake the screen
while I pass by the door. The red LED will slowly pulse while the
download was in progress, then the yellow LED will start flashing when
transcoding begins. Once everything is done, the green LED will be lit
(or the red LED, which will indicate an error). The Arduino sketch had a
bunch of predefined patterns, encoded as strings. Each character would
indicate an intensity, with &amp;ldquo;a&amp;rdquo; being the brightness, and &amp;ldquo;z&amp;rdquo; being
the dimmest (I believe the space or dot meant &amp;ldquo;off&amp;rdquo;). Each LED could
be set to a different pattern, which was done via commands sent over the
RS-232 connection. I think the code driving this connection was baked
into the download-and-transcode tool itself. The Arduino would reset
whenever the RS-232 connection is formed, and just letting it do this
when the tool started up meant that I didn&amp;rsquo;t need to worry about
connection state (it didn&amp;rsquo;t make the code portable though).&lt;/p&gt;
&lt;h3 id=&#34;watching-webpack&#34;&gt;Watching Webpack&lt;/h3&gt;
&lt;p&gt;Eventually this tool fell out of use, and for the long time this board
sat in my drawer. Projects came and went, until one came along with a
problem that was perfect for this device. I was working on a HTML
web-app and I was switching between the code and a web-browser, while
Webpack was watching for changes. Because I only had a single screen,
the terminal was always out of sight — behind either the code editor or
the web-browser — and the version of Webpack I was using would stop
watching when it encountered an error (a Go application was serving the
files, and Webpack was simply deploying the bundle assets to a public
folder, so even though Webpack would stop working, the actual web-server
will continue running). Not seeing these errors, I&amp;rsquo;d fall into the trap
into thinking that I was changing things, and getting confused as to why
I wasn&amp;rsquo;t seeing them in the browser. I could go for a minute or two
like this before I found out that Webpack died because of an earlier
error and my changes were not getting deployed at all. So I dug this
device out, built a very simple Go CLI tool and daemon that would talk
to it, and hacked it into the Webpack config. When a Webpack build
started, it would light up the amber LED. If the build was successful,
the green LED would light up; if not, the red LED would.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2024/d99bab7023.jpg&#34;&gt;
&lt;figcaption&gt;The green LED lit, indicating that the last build was successful.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2024/1407daab26.jpg&#34;&gt;
&lt;figcaption&gt;The amber LED, indicating a build in progress.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2024/68f60dc0c0.jpg&#34;&gt;
&lt;figcaption&gt;The red LED, indicating a failed build.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;This proved to be super useful, and took out the guesswork of knowing
when a change was deployed. As long as the green LED was lit, it&amp;rsquo;s good
to go, but as soon as amber becomes red, I know I&amp;rsquo;ll have to check for
errors and get it green once more.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://media.lmika.org/indicator-lights-720p.mp4&#34; controls=&#34;controls&#34; preload=&#34;metadata&#34;&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;The sketch and daemon software is a lot simpler than what this device
used to do. Now, instead of individual patterns of intensity, the daemon
— which is itself controlled by a CLI tool — would communicate to the
device using a very simple protocol that would either turn LEDs on or
off. Some of the protocol details, taken from the Arduino sketch, are
included below:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/*
 * ledstatus - simple led indicators
 * 
 * SERIAL FORMAT
 * 
 * Commands take the form:  &amp;lt;cmd&amp;gt; &amp;lt;pars&amp;gt;... NL.  Any more than
 * 8 bytes (1 command, 7 parameters) will be ignored.
 * 
 * Responses from the device will take the form: &amp;lt;status&amp;gt; &amp;lt;par&amp;gt;... NL
 * 
 */

// Commands
\#define CMD_NOP       0x0
\#define CMD_PING      &#39;p&#39;   // a ping, which should simply respond with RES_OK
\#define CMD_TURN_ON   &#39;o&#39;   // &#39;o&#39; &amp;lt;addr&amp;gt;   :: turn on the leds at these addresses
\#define CMD_TURN_OFF  &#39;f&#39;   // &#39;f&#39; &amp;lt;addr&amp;gt;   :: turn off the leds at these addresses

// Response
\#define RES_OK        &#39;1&#39;

\#define PIN_ADDR_G1   (1 &amp;lt;&amp;lt; 0)
\#define PIN_ADDR_Y1   (1 &amp;lt;&amp;lt; 1)
\#define PIN_ADDR_R1   (1 &amp;lt;&amp;lt; 2)
\#define PIN_ADDR_G2   (1 &amp;lt;&amp;lt; 3)
\#define PIN_ADDR_Y2   (1 &amp;lt;&amp;lt; 4)
\#define PIN_ADDR_R2   (1 &amp;lt;&amp;lt; 5)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;But in a way the simplicity actually helps here. Because it&amp;rsquo;s now a
command and daemon, I could use it in anything else where I&amp;rsquo;d like to
show progress without having to see the screen. Just now, for example,
I&amp;rsquo;m working on a Go project that uses &lt;a href=&#34;https://github.com/cosmtrek/air&#34;&gt;Air&lt;/a&gt; to rebuild and restart
whenever I change a template. The cycle is slightly longer than a simple
Webpack run, and I tend to reload the browser window too soon. So
waiting for this device to go  from amber to green cuts down on these
early reloads.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2024/404c1a3e20.jpg&#34;&gt;
&lt;figcaption&gt;The ledstatus command line tool. It would communicate with the daemon via gRPC bound to a local TCP port.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;So thats the Build Indicators. The project is steady, and I have no
desire to do anything significant, like modify the hardware. But if I
were to work on it again, I think I&amp;rsquo;d like it to add variable intensity
back, and extend the command language to let the user upload customer
patterns. But for the moment, it&amp;rsquo;s doing it&amp;rsquo;s job just fine.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2024/01/26/you-know-that.html</link>
      <pubDate>Fri, 26 Jan 2024 15:08:32 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2024/01/26/you-know-that.html</guid>
      <description>&lt;p&gt;Working on one of the admin sections of the project I was &lt;a href=&#34;https://lmika.org/2024/01/25/075025.html&#34;&gt;alluding to yesterday&lt;/a&gt;. Here&amp;rsquo;s a screencast of how it&amp;rsquo;s looking so far.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2024/photo-bucket-admin-v1.mov&#34; height=&#34;360&#34; width=&#34;640&#34; controls poster=&#34;https://lmika.org/uploads/2024/photo-bucket-admin-v1-poster.png&#34;&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;The styling and layout is not quite final. I&amp;rsquo;m focusing more on functionality, and getting layout and whitespace looking good always takes time. But compared to how it looked before I started working on it this morning, I think it&amp;rsquo;s a good start.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2024/01/10/in-the-end.html</link>
      <pubDate>Wed, 10 Jan 2024 20:49:46 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2024/01/10/in-the-end.html</guid>
      <description>&lt;p&gt;In the end it took significantly more time to &lt;a href=&#34;https://lmika.org/2024/01/05/for-reasons-that.html&#34;&gt;write about it&lt;/a&gt; then to actually do it, but the dot product approach seems to work.&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2024/hex-tracking.mov&#34; poster=&#34;https://lmika.org/uploads/2024/hex-tracking-poster.png&#34; controls&gt;&lt;a href=&#34;https://cdn.uploads.micro.blog/25293/2024/hex-tracking.mov&#34;&gt;Download video&lt;/a&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2024/01/10/elm-connections-deploying.html</link>
      <pubDate>Wed, 10 Jan 2024 15:39:38 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2024/01/10/elm-connections-deploying.html</guid>
      <description>&lt;p&gt;🎥 &lt;a href=&#34;https://youtu.be/xWdZSRD5Ts4&#34;&gt;Elm Connections #7: Deploying&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In which I round out the series by deploying Clonections to Netlify.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2024/01/08/elm-connections-fetching.html</link>
      <pubDate>Mon, 08 Jan 2024 11:26:46 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2024/01/08/elm-connections-fetching.html</guid>
      <description>&lt;p&gt;🎥 &lt;a href=&#34;https://youtu.be/ekk-tGYdNYU&#34;&gt;Elm Connections #6: Fetching And JSON Decoding Puzzles&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In which I use Elm&amp;rsquo;s HTTP client and JSON decoder to fetch puzzles from an external resource.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2024/01/03/elm-connections-option.html</link>
      <pubDate>Wed, 03 Jan 2024 09:30:48 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2024/01/03/elm-connections-option.html</guid>
      <description>&lt;p&gt;🎥 &lt;a href=&#34;https://youtu.be/3aPCmcHkFjU&#34;&gt;Elm Connections #5: Option Shuffling&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In which I use Elm&amp;rsquo;s random number generator to shuffle the options.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2024/01/01/elm-connections-styling.html</link>
      <pubDate>Mon, 01 Jan 2024 19:15:25 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2024/01/01/elm-connections-styling.html</guid>
      <description>&lt;p&gt;🎥 &lt;a href=&#34;https://youtu.be/jW7ro94NjQ4&#34;&gt;Elm Connections #4: Styling&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In which I put away Elm for a bit to make the playfield look good (or at least, better than it was).&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2023/12/26/elm-connections-group.html</link>
      <pubDate>Wed, 27 Dec 2023 12:40:13 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2023/12/26/elm-connections-group.html</guid>
      <description>&lt;p&gt;🎥 &lt;a href=&#34;https://youtu.be/f6cH0yuG5Xg&#34;&gt;Elm Connections #3: Group Matching&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In which I work on &amp;ldquo;categories&amp;rdquo;, the model and logic that deals with the groups the player is to &amp;ldquo;connect&amp;rdquo;, plus find my way with how sets work in Elm.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2023/12/24/elm-connections-starting.html</link>
      <pubDate>Tue, 26 Dec 2023 10:35:06 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2023/12/24/elm-connections-starting.html</guid>
      <description>&lt;p&gt;🎥 &lt;a href=&#34;https://youtu.be/k8q6mKTV5BU&#34;&gt;Elm Connections #2: Starting The Playfield&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In which I continue work on a Connections clone in Elm by starting work on the playfield.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2023/12/24/elm-connections-first.html</link>
      <pubDate>Sun, 24 Dec 2023 08:23:39 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2023/12/24/elm-connections-first.html</guid>
      <description>&lt;p&gt;🎥 &lt;a href=&#34;https://youtu.be/2e2YiBY76ps&#34;&gt;Elm Connections #1: First Steps&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In which I record video of me building a Connections (or &lt;a href=&#34;https://lexfriedman.com/connections/&#34;&gt;Conlextions&lt;/a&gt;) clone in Elm (while at the same time, have a go at editing video).&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2023/12/22/making-some-progress.html</link>
      <pubDate>Fri, 22 Dec 2023 12:29:15 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2023/12/22/making-some-progress.html</guid>
      <description>&lt;p&gt;Making some progress in learning &lt;a href=&#34;https://elm-lang.org/&#34;&gt;Elm&lt;/a&gt; for building frontends. Started working on a Connections clone, which I&amp;rsquo;m calling &amp;ldquo;Clonections&amp;rdquo;. This is what I&amp;rsquo;ve got so far:&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2023/clonections-screencast.mov&#34; controls width=&#34;1280&#34; height=&#34;720&#34; poster=&#34;https://lmika.org/uploads/2023/clonections-screencast-poster.png&#34;&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s been fun using Elm to build this. So far I&amp;rsquo;m liking the language. Of course, now I&amp;rsquo;ll have to come up with puzzles for this. 😐&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2023/12/17/i-realise-ive.html</link>
      <pubDate>Sun, 17 Dec 2023 08:47:51 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2023/12/17/i-realise-ive.html</guid>
      <description>&lt;p&gt;I realise I&amp;rsquo;ve been posting a lot about Ivy, and not a whole lot about Archie. So to even the scales a little, here&amp;rsquo;s a video of Archie receiving a head scratch this morning.&lt;/p&gt;
&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2023/archie-head-scratch.mov&#34; poster=&#34;https://lmika.org/uploads/2023/archie-head-scratch-poster.png&#34; width=&#34;1280&#34; height=&#34;720&#34; controls&gt;
  &lt;a href=&#34;https://cdn.uploads.micro.blog/25293/2023/archie-head-scratch.mov&#34;&gt;Download&lt;/a&gt;
&lt;/video&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2023/12/06/should-state-that.html</link>
      <pubDate>Wed, 06 Dec 2023 08:20:14 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2023/12/06/should-state-that.html</guid>
      <description>&lt;p&gt;🥛🦜&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2023/ivy-and-the-glass.mov&#34; controls&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Should state that both vessels hold ordinary tap water.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2023/12/01/spent-a-little.html</link>
      <pubDate>Sun, 03 Dec 2023 20:09:27 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2023/12/01/spent-a-little.html</guid>
      <description>&lt;p&gt;Spent a little more time working on my idea for Dynamo-Browse this week. Managed to get it somewhat feature complete this weekend:&lt;/p&gt;
&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2023/rel-item-example-1.mp4&#34; poster=&#34;https://lmika.org/uploads/2023/rel-item-example-1-poster.png&#34; width=&#34;1440&#34; height=&#34;1080&#34; controls&gt;
  &lt;a href=&#34;https://cdn.uploads.micro.blog/25293/2023/rel-item-example-1.mp4&#34;&gt;Download Video&lt;/a&gt; 
&lt;/video&gt;
&lt;p&gt;I probably should say a few words on what it actually is. The idea is to make it quick and easy to run pre-canned queries based on the currently selected item and table.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s say you&amp;rsquo;ve got a table with customer information, and another table with subscription information, and they&amp;rsquo;re linked with some form of customer ID. If you wanted to see the subscriptions of a customer, up until now, you&amp;rsquo;d have to copy the customer ID to the paste-board, change the currently viewed table, then run a query to select the subscription with that customer ID. It&amp;rsquo;s not difficult but it&amp;rsquo;s extremely tedious.&lt;/p&gt;
&lt;p&gt;This change is meant to streamline this. Now, in a script function, you can define a &amp;ldquo;related item&amp;rdquo; provider which, if matched against the currently displayed table, will be given the currently selected item, and will return a list of queries that will display items related to the current item (depending on whatever definition of &amp;ldquo;related&amp;rdquo; will be). This will be presented to the user as a list. When the user chooses the item, the query will run and the results will be displayed.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s an example of the script used for the screencasts:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;ext.related_items(&amp;quot;business-addresses&amp;quot;, func(item) {
    return [
        {&amp;quot;label&amp;quot;: &amp;quot;Customer&amp;quot;, &amp;quot;query&amp;quot;: `city=$city`, &amp;quot;args&amp;quot;: {&amp;quot;city&amp;quot;: &amp;quot;Austin&amp;quot;}},
        {&amp;quot;label&amp;quot;: &amp;quot;Payment&amp;quot;, &amp;quot;query&amp;quot;: `address^=&amp;quot;3&amp;quot;`},
        {&amp;quot;label&amp;quot;: &amp;quot;Thing&amp;quot;, &amp;quot;table&amp;quot;: &amp;quot;inventory&amp;quot;, 
            &amp;quot;query&amp;quot;: `pk=$pk`, &amp;quot;args&amp;quot;: {&amp;quot;pk&amp;quot;: &amp;quot;01fca33a-5817-4c27-8a8f-82380584e69c&amp;quot;}},
    ]
})

ext.related_items(&amp;quot;inventory&amp;quot;, func(item) {
    sk := string(item.attr(&amp;quot;sk&amp;quot;))
    return [
        {&amp;quot;label&amp;quot;: &amp;quot;SK: &amp;quot; + sk, &amp;quot;table&amp;quot;: &amp;quot;business-addresses&amp;quot;, 
            &amp;quot;query&amp;quot;: `pk^=$sk`, &amp;quot;args&amp;quot;: {&amp;quot;sk&amp;quot;: sk}},
    ]
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice how the last &lt;code&gt;business-addresses&lt;/code&gt; item specifies the &amp;ldquo;inventory&amp;rdquo; table, and that the &amp;ldquo;inventory&amp;rdquo; provider actually uses an attribute of the item. Here&amp;rsquo;s a screencast of that working:&lt;/p&gt;
&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2023/rel-item-example-2.mp4&#34; poster=&#34;https://lmika.org/uploads/2023/rel-item-example-2-poster.png&#34; width=&#34;1440&#34; height=&#34;1080&#34; controls&gt;
  &lt;a href=&#34;https://cdn.uploads.micro.blog/25293/2023/rel-item-example-2.mp4&#34;&gt;Download Video&lt;/a&gt; 
&lt;/video&gt;
&lt;p&gt;This feature has been on the idea board for a while. I was trying to work out how best to handle the pre-canned queries, especially considering that they will likely be different for each item and table. Some ideas I had were adding additional UI elements that the user could use to configure these queries. These would go into the workspace file, a sort of an embedded database which is created for each session. This was pretty crappy, especially when you consider that workspaces usually only last until the user exists. It was only a few weeks ago when I considered using the scripting facilities to implement this (which, honestly, shows how much it remains under-utilised).&lt;/p&gt;
&lt;p&gt;Anyway, I&amp;rsquo;ve only just finished development of it. I&amp;rsquo;d still like to try it for the various related items I tend to use during my day-to-day. We&amp;rsquo;ll see how well it works out.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Idea For Mainboard Mayhem: A Remote Pickup</title>
      <link>https://lmika.org/2023/11/19/sort-of-inbetween.html</link>
      <pubDate>Sun, 19 Nov 2023 20:21:56 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2023/11/19/sort-of-inbetween.html</guid>
      <description>&lt;p&gt;Sort of in-between projects at the moment so I&amp;rsquo;m doing a bit of light stuff on Mainboard Mayhem. I had an idea for a new element: a remote control which, when picked up, will allow the player to toggle walls and tanks using the keyboard, much like the green and blue buttons.&lt;/p&gt;
&lt;p&gt;I used ChatGGT to come up with some artwork, and it produced something that was pretty decent.&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2023/red-pixel-button-generated-by-dalle.png&#34; width=&#34;600&#34; height=&#34;600&#34; alt=&#34;Image generated from DALL-E with the prompt: pixel art of a remote control with a single red button styled like the tiles found in Chips Challange, rotated 45 degrees to the right.&#34;&gt;
&lt;figcaption&gt;Prompt: pixel art of a remote control with a single red button styled like the tiles found in Chips Challange, rotated 45 degrees to the right.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;Only issue was that the image was huge — 1024 x 1024 — and the tiles in Mainboard Mayhem were only 32 x 32.&lt;/p&gt;
&lt;p&gt;I tried shrinking it down in Acorn, using various scaling algorithms. The closest that worked was bringing it down slowly to about 128 x 128 using Nearest Neighbour, than trying to go all the way down  to 32 x 32 using Lanczos. That worked, but it required true 32 bit colour to be recognisable, and I wanted to preserve the 16 colour palette used by the original Chips Challenge.&lt;/p&gt;
&lt;p&gt;So using the original image as a reference, I bit the bullet and drew my own in Acorn. You can see it here in this test level:&lt;/p&gt;
&lt;figure&gt;
&lt;img src=&#34;https://cdn.uploads.micro.blog/25293/2023/mainboard-mayhem-example-levem.png&#34; width=&#34;600&#34; height=&#34;315&#34; alt=&#34;Example Mainboard Mayhem level showing the green and blue remote controls. The controls have 4 small buttons and one large bulbous button that is either blue or green, with a bit of phong and shadow applied&#34;&gt;
&lt;figcaption&gt;They&#39;re the elements that look like remote controls.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;It turn out okay. At least it&amp;rsquo;s recognisable. Anyway, I coded it up and gave it a bit of a try:&lt;/p&gt;
&lt;p&gt;&lt;video src=&#34;https://cdn.uploads.micro.blog/25293/2023/mainboard-mayhem-demo.mov&#34; poster=&#34;https://lmika.org/uploads/2023/mainboard-mayhem-demo-poster.png&#34; controls=&#34;controls&#34; playsinline=&#34;playsinline&#34;&gt;&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Yeah, it works well. When the player has the appropriate colour remote, they can hit either &lt;kbd&gt;Z&lt;/kbd&gt; or &lt;kbd&gt;X&lt;/kbd&gt; to toggle the green walls or blue tanks respectively. I really should add some indicators in the status bar to show which button to press.&lt;/p&gt;
&lt;p&gt;Not sure what I&amp;rsquo;ll do after this. The fun part was coming up with the element. But I guess I&amp;rsquo;ll have to come up with a few puzzles that use it.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2023/11/03/also-got-a.html</link>
      <pubDate>Fri, 03 Nov 2023 21:00:50 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2023/11/03/also-got-a.html</guid>
      <description>&lt;p&gt;Also got a bit of train spotting in as well. I parked at Kyneton station in the hope of seeing a train go by. Wish I could say my timing was strategic but in truth I was just lucky.&lt;/p&gt;
&lt;p&gt;&lt;video controls=&#34;controls&#34; playsinline=&#34;playsinline&#34; src=&#34;https://cdn.uploads.micro.blog/25293/2023/kyneton-train-crossing.mov&#34; poster=&#34;https://lmika.org/uploads/2023/kyneton-train-crossing-poster.png&#34; preload=&#34;none&#34; width=&#34;600&#34; height=&#34;337&#34;  alt=&#34;A V-Line velocity train leaving a station off camera to the right and crossing a protected level crossing with boom-gates and flashing lights&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2023/10/21/this-conversation-with.html</link>
      <pubDate>Sat, 21 Oct 2023 10:13:47 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2023/10/21/this-conversation-with.html</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://micro.blog/Gaby/25194972&#34;&gt;This conversation&lt;/a&gt; with &lt;a href=&#34;https://micro.blog/Gaby&#34;&gt;@Gaby&lt;/a&gt; got my creative juices flowing so I though I&amp;rsquo;d put together a &lt;a href=&#34;https://www.youtube.com/watch?v=Vcq2cDCUi6U&#34;&gt;small video tutorial&lt;/a&gt; for using the GLightbox plugin by &lt;a href=&#34;https://micro.blog/jsonbecker&#34;&gt;@jsonbecker&lt;/a&gt;. There have been a few updates with the plugin so how I use it might be slightly out of date. Either way, please enjoy.&lt;/p&gt;
&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
      &lt;iframe allow=&#34;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen&#34; loading=&#34;eager&#34; referrerpolicy=&#34;strict-origin-when-cross-origin&#34; src=&#34;https://www.youtube.com/embed/Vcq2cDCUi6U?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; title=&#34;YouTube video&#34;&gt;&lt;/iframe&gt;
    &lt;/div&gt;

</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2023/07/26/224328.html</link>
      <pubDate>Wed, 26 Jul 2023 22:43:28 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2023/07/26/224328.html</guid>
      <description>&lt;p&gt;Success! Managed to get a Go app built, signed, and notarised all from within a GitHub Action. It even cross-compiles to ARM, which is something considering that it&amp;rsquo;s using &lt;a href=&#34;https://www.libsdl.org&#34;&gt;SDL&lt;/a&gt;. Here&amp;rsquo;s the test app being downloaded and launched in a VM (ignore the black window, the interesting part is the title).&lt;/p&gt;
&lt;p&gt;&lt;video controls=&#34;controls&#34; src=&#34;https://cdn.uploads.micro.blog/25293/2023/cclm-download.mov&#34; poster=&#34;https://lmika.org/uploads/2023/4144e2fc7b.png&#34; alt=&#34;Video of an app being downloaded, and launched successfully. The app is a blank screen&#34; width=&#34;600&#34; height=&#34;422&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2023/01/07/i-wont-lie.html</link>
      <pubDate>Sat, 07 Jan 2023 17:02:00 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2023/01/07/i-wont-lie.html</guid>
      <description>&lt;p&gt;I won&amp;rsquo;t lie to you. I got some pretty strong vibes of &lt;em&gt;the Birds&lt;/em&gt; at this point in my walk.&lt;/p&gt;
&lt;p&gt;&lt;video controls=&#34;controls&#34; playsinline=&#34;playsinline&#34; src=&#34;https://cdn.uploads.micro.blog/25293/2023/ae5eede29f.mov&#34; poster=&#34;https://lmika.org/uploads/2023/98731cedd4.png&#34; preload=&#34;none&#34; width=&#34;600&#34; height=&#34;337&#34;  alt=&#34;Birds following me as I walk backwards&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2022/11/01/githubcomcharmbraceletvhs-this-little.html</link>
      <pubDate>Tue, 01 Nov 2022 08:55:34 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2022/11/01/githubcomcharmbraceletvhs-this-little.html</guid>
      <description>&lt;p&gt;🔗 &lt;a href=&#34;https://github.com/charmbracelet/vhs&#34;&gt;github.com/charmbracelet/vhs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This little tool is awesome. It allows you to easily make GIFs of a command line session from a text-based DSL. I tried it on the full screen TUI app I&amp;rsquo;m working on and it worked flawlessly.&lt;/p&gt;
&lt;video controls width=&#34;600&#34; height=&#34;420&#34; poster=&#34;https://lmika.org/uploads/2022/035390629c.png&#34;&gt;
  &lt;source src=&#34;https://lmika.org/uploads/2022/4409c211f5.mp4&#34; type=&#34;video/mp4&#34;&gt;
&lt;/video&gt;
&lt;p&gt;Now wondering if I could use it for automated testing. 🤔&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2022/03/10/heres-another-clip.html</link>
      <pubDate>Thu, 10 Mar 2022 07:45:00 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2022/03/10/heres-another-clip.html</guid>
      <description>&lt;p&gt;Here&amp;rsquo;s another clip of the echidna, taken from the same 2 minute video I took yesterday.  It&amp;rsquo;s also the third video of wildlife looking for food that I&amp;rsquo;ve posted on this blog.  Is a trend forming I wonder? 🤔&lt;/p&gt;
&lt;p&gt;&lt;video controls=&#34;controls&#34; playsinline=&#34;playsinline&#34; src=&#34;https://cdn.uploads.micro.blog/25293/2022/9c9c569d5f.mov&#34; poster=&#34;https://lmika.org/uploads/2022/42928e0a91.png&#34; preload=&#34;none&#34; width=&#34;640&#34; height=&#34;360&#34; alt=&#34;Echidna looking for food&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2022/03/10/went-for-my.html</link>
      <pubDate>Thu, 10 Mar 2022 07:00:00 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2022/03/10/went-for-my.html</guid>
      <description>&lt;p&gt;Went for my afternoon walk yesterday, and saw an echidna looking for food.  That doesn&amp;rsquo;t happen every day, so it seemed like a good subject for a video.&lt;/p&gt;
&lt;p&gt;&lt;video controls=&#34;controls&#34; playsinline=&#34;playsinline&#34; src=&#34;https://cdn.uploads.micro.blog/25293/2022/fe0d3275df.mov&#34; poster=&#34;https://lmika.org/uploads/2022/2961294a14.png&#34; preload=&#34;none&#34; width=&#34;640&#34; height=&#34;360&#34; alt=&#34;Echidna looking for food&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2021/12/13/saw-this-feller.html</link>
      <pubDate>Mon, 13 Dec 2021 11:56:00 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2021/12/13/saw-this-feller.html</guid>
      <description>&lt;p&gt;Saw this on my lunchtime walk today.  I don&amp;rsquo;t often see cockatoos find food this way.&lt;/p&gt;
&lt;p&gt;&lt;video controls=&#34;controls&#34; playsinline=&#34;playsinline&#34; src=&#34;https://cdn.uploads.micro.blog/25293/2021/5a1ab87a60.mov&#34; poster=&#34;https://lmika.org/uploads/2021/5531fcdd2c.png&#34; preload=&#34;none&#34; width=&#34;640&#34; height=&#34;360&#34; alt=&#34;Cockatoo looking for food in a hole&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title></title>
      <link>https://lmika.org/2020/12/25/test.html</link>
      <pubDate>Fri, 25 Dec 2020 08:12:30 +1000</pubDate>
      
      <guid>http://lmika.micro.blog/2020/12/25/test.html</guid>
      <description>&lt;p&gt;Follow on from &lt;a href=&#34;http://lmika.org/2020/12/25/christmas-eve-spent.html&#34;&gt;the last post&lt;/a&gt;, I also had the opportunity to spot a few trains.  Here&amp;rsquo;s one on it&amp;rsquo;s way to Bendigo, taken just outside Woodend.&lt;/p&gt;
&lt;p&gt;&lt;video controls=&#34;controls&#34; playsinline=&#34;playsinline&#34; src=&#34;https://cdn.uploads.micro.blog/25293/2020/7275f5ec1f.mov&#34; width=&#34;640&#34; height=&#34;360&#34; poster=&#34;http://lmika.org/uploads/2020/7e1165dd41.png&#34; preload=&#34;none&#34;&gt;&lt;/video&gt;&lt;/p&gt;
</description>
    </item>
    
  </channel>
</rss>