<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: JoeStrout</title>
    <description>The latest articles on DEV Community by JoeStrout (@joestrout).</description>
    <link>https://dev.to/joestrout</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F955389%2Ffdd96374-bc61-43f2-bf73-c2d6d6968a72.png</url>
      <title>DEV Community: JoeStrout</title>
      <link>https://dev.to/joestrout</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/joestrout"/>
    <language>en</language>
    <item>
      <title>HWYDT: Swinging from Vines</title>
      <dc:creator>JoeStrout</dc:creator>
      <pubDate>Wed, 06 May 2026 16:23:32 +0000</pubDate>
      <link>https://dev.to/joestrout/hwydt-swinging-from-vines-31ei</link>
      <guid>https://dev.to/joestrout/hwydt-swinging-from-vines-31ei</guid>
      <description>&lt;h2&gt;
  
  
  The Venerable History of Vine-Swinging
&lt;/h2&gt;

&lt;p&gt;Swinging on vines has been a favorite game mechanic since 1982, when both &lt;em&gt;Jungle Hunt&lt;/em&gt; (a thinly disguised Tarzan arcade game) and &lt;em&gt;Pitfall!&lt;/em&gt; (on of the Atari 2600's best-selling action games) hit the market.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsjya8jyz69i2yei11u3m.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsjya8jyz69i2yei11u3m.gif" alt="Animated GIF of Pitfall!"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since then, swinging from vines, ropes, webs, grappling hooks, extensible bionic arms, etc. has been a recurring staple (including in such modern hits as &lt;a href="https://joestrout.itch.io/spider-pig" rel="noopener noreferrer"&gt;&lt;em&gt;Spider-Pig!&lt;/em&gt;&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;But how can you actually do this in your own games?  Let's dig in and find out!&lt;/p&gt;

&lt;h2&gt;
  
  
  The Big Picture
&lt;/h2&gt;

&lt;p&gt;We're going to implement a vine-swinging demo in Mini Micro.  Our vines will be composed of five or so straight segments, connected like links in a chain.  These will oscillate back and forth, using some simple trigonometry (don't worry, I said &lt;em&gt;simple&lt;/em&gt; and I meant it!) to update their positions and rotations.  We need a sprite image for each vine segment; this should be a thick line with rounded ends (so they join neatly together), and for decoration, I've added some leaves:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fghxp4tr3pctp8xhzrs4a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fghxp4tr3pctp8xhzrs4a.png" alt="VineSegment.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Go ahead and save this image as &lt;code&gt;VineSegment.png&lt;/code&gt;, and fire up Mini Micro (download it &lt;a href="https://miniscript.org/MiniMicro/" rel="noopener noreferrer"&gt;here&lt;/a&gt; if you don't have it already).  Notice that the image is mostly empty on the left; the "pivot point" (around which the sprite rotates) in Mini Micro is always in the center of the image, so we've simply offset our drawing so that the center of the image is at one end of the visible segment.&lt;/p&gt;

&lt;p&gt;Our hero (Kip) will be, at any given moment, either attached to some vine segment, or flying ballistically through the air.  When attached, we just need to update his position along with the vine segment he's clinging to.  When flying, then Isaac Newton is in charge, and fortunately &lt;em&gt;his&lt;/em&gt; equations are even simpler.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preliminaries
&lt;/h2&gt;

&lt;p&gt;In Mini Micro, enter &lt;code&gt;edit&lt;/code&gt; to start a new program, and then paste in these preliminary steps to clear the screen, get a handy reference to the sprite display, and load some sounds we'll need later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import "mathUtil"

clear
spriteDisp = display(4)
jumpSound = file.loadSound("/sys/sounds/pickup.wav")
catchSound = file.loadSound("/sys/sounds/swoosh.wav")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, we're going to need a bit of math to convert between local and world coordinates.  By "local" coordinates, I mean coordinates relative to a sprite — for example, the pixel coordinates of some point in its image; those are &lt;em&gt;local&lt;/em&gt; to the sprite.  "World" coordinates are basically positions on the screen, except that we're going to be scrolling the view our hero progresses, so it's more accurate to say they are positions relative to the sprite display.  We need to convert back and forth: converting from local to world in order to position each vine segment relative to the previous one, or Kip relative to the segment he's holding; and converting from world to local to see if Kip is close enough to grab a vine when flying through the air.&lt;/p&gt;

&lt;p&gt;This is where the trigonometry comes in.  Honestly, I don't memorize or derive these equations; I just google 'em when I need them.  You can just copy and paste this into your program:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Set the x and y values of the given map to
// the world position corresponding to the
// given XY local to this sprite.  In other words,
// assume targetMap is attached to this sprite
// at local position localX, localY; update its
// x and y accordingly.
Sprite.setXYtoLocal = function(targetMap, localX, localY)
    radians = self.rotation * pi/180
    cosAng = cos(radians)
    sinAng = sin(radians)
    targetMap.x = self.x + localX * cosAng - localY * sinAng
    targetMap.y = self.y + localX * sinAng + localY * cosAng    
end function

// Get the local [x,y] position of some world object
// relative to this sprite.
Sprite.getLocal = function(worldXY)
    radians = self.rotation * pi/180
    dx = worldXY.x - self.x
    dy = worldXY.y - self.y
    cosAng = cos(radians)
    sinAng = sin(radians)
    return [dx * cosAng + dy * sinAng, -dx * sinAng + dy * cosAng]  
end function
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save your program as &lt;code&gt;swing.ms&lt;/code&gt; (or whatever you like), and run it just to be sure you haven't made a syntax error.  If it seems to do nothing, you're doing great so far!&lt;/p&gt;

&lt;h2&gt;
  
  
  Swingy vines
&lt;/h2&gt;

&lt;p&gt;Now let's add the code that actually makes a vine.  We'll have a Sprite subclass called Segment, just to give them all a common image and length; and then we'll have another class called Vine, which encapsulates a list of segments and knows how to update them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Segment = new Sprite
Segment.image = file.loadImage("VineSegment.png")
Segment.length = 64

Vine = {}
Vine.angRange = 55  // how far to swing from vertical (degrees)
Vine.period = 2  // how long a full back-and-forth takes (seconds)
Vine.Instances = []

Vine.Make = function(x=480, y=640, qtySegments=5)
    vine = new self
    vine.segments = []
    for i in range(0, qtySegments-1)
        seg = new Segment
        seg.x = x
        seg.y = y - seg.length * i
        seg.rotation = -90
        spriteDisp.sprites.push seg
        vine.segments.push seg
    end for
    Vine.Instances.push vine
    return vine
end function
Vine.update = function(time)
    t = 2*pi * time/self.period
    for i in self.segments.indexes
        seg = self.segments[i]
        ang = -90 + self.angRange * sin(t - i*0.2)
        seg.rotation = ang
        if i &amp;lt; self.segments.len-1 then
            seg.setXYtoLocal self.segments[i+1], seg.length, 0
        end if
    end for
end function
Vine.UpdateAll = function(time)
    for vine in Vine.Instances
        vine.update time
    end for
end function
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key bit is of course the &lt;code&gt;Vine.update&lt;/code&gt; function, which iterates over its segments, setting the angle of each, and then the position of the &lt;em&gt;next&lt;/em&gt; using that &lt;code&gt;setXYtoLocal&lt;/code&gt; function we prepared before.  The angle is set according to the time (divided by &lt;code&gt;self.period&lt;/code&gt;, which is how we make vines swing faster or slower), and subtracts a little factor of the segment number, &lt;code&gt;i * 0.2&lt;/code&gt;.  This makes the end of the vine lag a bit relative to the top of the vine, making it look like a rope/chain rather than a rigid bar.&lt;/p&gt;

&lt;p&gt;To test this code, let's add a simple main program that creates one vine, and updates it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Vine.Make
while true
    yield
    Vine.UpdateAll time
end while
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now run, and it should look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7y5t111qzl4rh7h1sww6.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7y5t111qzl4rh7h1sww6.gif" alt="Animated GIF of swinging vine"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Challenge:&lt;/strong&gt; Add a second vine, at a different position.  Double challenge: give it a different period, so they're not swinging in perfect sync!&lt;/p&gt;

&lt;h2&gt;
  
  
  Our Hero, Kip
&lt;/h2&gt;

&lt;p&gt;Now we need a player character to jump from vine to vine.  We'll use our hero Kip (fresh from the &lt;a href="https://joestrout.itch.io/kip-in-the-caves-of-lava" rel="noopener noreferrer"&gt;Caves of Lava&lt;/a&gt;), since his sprites are included with Mini Micro.  Delete the mini-main-program you added above, and paste in the code below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kip = new Sprite
kip.image = file.loadImage("/sys/pics/KP/KP-jump.png")
kip.grabbed = null  // Segment he's hanging onto
kip.grabPos = [0,0] // grab position local to that segment
kip.vx = 0; kip.vy = 0  // velocity, in pixels/sec

kip.update = function(dt)
    if self.grabbed then
        // Stick to the vine, updating our velocity as we go
        lastPos = [self.x, self.y]
        self.grabbed.setXYtoLocal self, self.grabPos[0], self.grabPos[1]
        self.vx = (self.x - lastPos[0]) / dt
        self.vy = (self.y - lastPos[1]) / dt
    else
        // free flying!
        self.vy -= 1000*dt  // gravity
        self.x += self.vx * dt
        self.y += self.vy * dt
        // Try to catch any vine except our last one.
        for vine in Vine.Instances
            if vine == self.lastVine then continue
            if self.tryCatch(vine) then break
        end for
    end if
end function

kip.jump = function(extraVx=0, extraVy=100)
    if not self.grabbed then return
    jumpSound.play
    self.grabbed = null
    self.vy += 100  
end function

kip.tryCatch = function(vine)
    for seg in vine.segments
        localPos = seg.getLocal(self)
        if (0 &amp;lt;= localPos[0] &amp;lt; seg.length) and
          (-12 &amp;lt;= localPos[1] &amp;lt; 12) then
            // Valid catch!
            self.grabbed = seg
            self.grabPos = localPos
            self.lastVine = vine
            catchSound.play
            return true
        end if
    end for
    return false
end function
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, Kip's &lt;code&gt;update&lt;/code&gt; method has two modes: it does one thing when he has grabbed a vine, and something else when he is flying through space.  Both cases are pretty simple.  An important trick in the first case is updating kip's velocity (vx and vy) based on how the vine is causing him to move.  That matters because when you jump, you want to continue with (more or less) that same velocity.&lt;/p&gt;

&lt;p&gt;In the free-flying case, we just apply some gravity to our vertical velocity (&lt;code&gt;vy&lt;/code&gt;), and then update our position according to current velocity.  The only tricky bit here is checking to see when we're close enough to another vine to grab it — so I extracted that into its own method, &lt;code&gt;kip.tryCatch&lt;/code&gt;.  This iterates over the segments of the given vine, and sees what our position would be local to that segment.  If it's close enough, then we do the catch.  &lt;em&gt;(Who says MiniScript doesn't have try/catch?!)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Camera, Final Setup, and Main Program
&lt;/h2&gt;

&lt;p&gt;Our demo is almost done, so let's press on with the final bit: a function to scroll the display so that the "camera" stays centered on the current vine; some code to create a bunch of vines, increasingly far apart; and the main program.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
updateCamera = function(dt)
    // try to center the active vine on the screen
    targetX = kip.lastVine.segments[0].x - 480
    spriteDisp.scrollX = mathUtil.moveTowards(
      spriteDisp.scrollX, targetX, 200 * dt)  
end function

// create the vines
x = 300; dx = 400
while x &amp;lt; 4000
    Vine.Make(x).period = 1.8 + rnd*0.4
    dx += 35
    x += dx
end while

// place Kip on the first vine
kip.lastVine = Vine.Instances[0]
kip.grabbed = kip.lastVine.segments[-2]
kip.grabPos = [40, 0]
kip.update
spriteDisp.sprites.push kip

// main loop
lastTime = time
jumpWasDown = false
while kip.y &amp;gt; 0
    yield
    now = time
    dt = now - lastTime
    lastTime = now
    Vine.UpdateAll now
    kip.update dt
    jumpDown = key.pressed("space")
    if jumpDown and not jumpWasDown then kip.jump
    jumpWasDown = jumpDown
    updateCamera dt
end while
key.clear
text.row = 1
print "Game over!"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's it!  Run now and you should have a simple but playable game.  How far can you make it before you fall?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2gicrva4riabni706z6w.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2gicrva4riabni706z6w.gif" alt="Animated screencap of swing demo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Full Program
&lt;/h2&gt;

&lt;p&gt;
  Here's the whole program in one big listing.
  &lt;br&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import "mathUtil"

clear
spriteDisp = display(4)
jumpSound = file.loadSound("/sys/sounds/pickup.wav")
catchSound = file.loadSound("/sys/sounds/swoosh.wav")

// Set the x and y values of the given map to
// the world position corresponding to the
// given XY local to this sprite.  In other words,
// assume targetMap is attached to this sprite
// at local position localX, localY; update its
// x and y accordingly.
Sprite.setXYtoLocal = function(targetMap, localX, localY)
    radians = self.rotation * pi/180
    cosAng = cos(radians)
    sinAng = sin(radians)
    targetMap.x = self.x + localX * cosAng - localY * sinAng
    targetMap.y = self.y + localX * sinAng + localY * cosAng    
end function

// Get the local [x,y] position of some world object
// relative to this sprite.
Sprite.getLocal = function(worldXY)
    radians = self.rotation * pi/180
    dx = worldXY.x - self.x
    dy = worldXY.y - self.y
    cosAng = cos(radians)
    sinAng = sin(radians)
    return [dx * cosAng + dy * sinAng, -dx * sinAng + dy * cosAng]  
end function

Segment = new Sprite
Segment.image = file.loadImage("VineSegment.png")
Segment.length = 64

Vine = {}
Vine.angRange = 55  // how far to swing from vertical (degrees)
Vine.period = 2  // how long a full back-and-forth takes (seconds)
Vine.Instances = []

Vine.Make = function(x=480, y=640, qtySegments=5)
    vine = new self
    vine.segments = []
    for i in range(0, qtySegments-1)
        seg = new Segment
        seg.x = x
        seg.y = y - seg.length * i
        seg.rotation = -90
        spriteDisp.sprites.push seg
        vine.segments.push seg
    end for
    Vine.Instances.push vine
    return vine
end function
Vine.update = function(time)
    t = 2*pi * time/self.period
    for i in self.segments.indexes
        seg = self.segments[i]
        ang = -90 + self.angRange * sin(t - i*0.2)
        seg.rotation = ang
        if i &amp;lt; self.segments.len-1 then
            seg.setXYtoLocal self.segments[i+1], seg.length, 0
        end if
    end for
end function
Vine.UpdateAll = function(time)
    for vine in Vine.Instances
        vine.update time
    end for
end function

kip = new Sprite
kip.image = file.loadImage("/sys/pics/KP/KP-jump.png")
kip.grabbed = null  // Segment he's hanging onto
kip.grabPos = [0,0] // grab position local to that segment
kip.vx = 0; kip.vy = 0  // velocity, in pixels/sec

kip.update = function(dt)
    if self.grabbed then
        // Stick to the vine, updating our velocity as we go
        lastPos = [self.x, self.y]
        self.grabbed.setXYtoLocal self, self.grabPos[0], self.grabPos[1]
        self.vx = (self.x - lastPos[0]) / dt
        self.vy = (self.y - lastPos[1]) / dt
    else
        // free flying!
        self.vy -= 1000*dt  // gravity
        self.x += self.vx * dt
        self.y += self.vy * dt
        // Try to catch any vine except our last one.
        for vine in Vine.Instances
            if vine == self.lastVine then continue
            if self.tryCatch(vine) then break
        end for
    end if
end function

kip.jump = function(extraVx=0, extraVy=100)
    if not self.grabbed then return
    jumpSound.play
    self.grabbed = null
    self.vy += 100  
end function

kip.tryCatch = function(vine)
    for seg in vine.segments
        localPos = seg.getLocal(self)
        if (0 &amp;lt;= localPos[0] &amp;lt; seg.length) and
          (-12 &amp;lt;= localPos[1] &amp;lt; 12) then
            // Valid catch!
            self.grabbed = seg
            self.grabPos = localPos
            self.lastVine = vine
            catchSound.play
            return true
        end if
    end for
    return false
end function

updateCamera = function(dt)
    // try to center the active vine on the screen
    targetX = kip.lastVine.segments[0].x - 480
    spriteDisp.scrollX = mathUtil.moveTowards(
      spriteDisp.scrollX, targetX, 200 * dt)  
end function

// create the vines
x = 300; dx = 400
while x &amp;lt; 4000
    Vine.Make(x).period = 1.8 + rnd*0.4
    dx += 35
    x += dx
end while

// place Kip on the first vine
kip.lastVine = Vine.Instances[0]
kip.grabbed = kip.lastVine.segments[-2]
kip.grabPos = [40, 0]
kip.update
spriteDisp.sprites.push kip

// main loop
lastTime = time
jumpWasDown = false
while kip.y &amp;gt; 0
    yield
    now = time
    dt = now - lastTime
    lastTime = now
    Vine.UpdateAll now
    kip.update dt
    jumpDown = key.pressed("space")
    if jumpDown and not jumpWasDown then kip.jump
    jumpWasDown = jumpDown
    updateCamera dt
end while
key.clear
text.row = 1
print "Game over!"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;




&lt;/p&gt;

&lt;h2&gt;
  
  
  Taking it Further
&lt;/h2&gt;

&lt;p&gt;This simple demo could be quickly expanded into a more engaging game:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keep a score, adding points for every successful jump, and/or for reaching new vines.&lt;/li&gt;
&lt;li&gt;Add hazards (water, alligators, whatever) below to heighten the tension.&lt;/li&gt;
&lt;li&gt;Add platforms/ground with traditional platformer mechanics (e.g. running and climbing).&lt;/li&gt;
&lt;li&gt;Enable Kip to climb up and down the vine he's on (this makes it a &lt;em&gt;lot&lt;/em&gt; easier!).&lt;/li&gt;
&lt;li&gt;Improve the vine physics, allowing stretching, slinging, and other fun effects, much like &lt;a href="https://joestrout.itch.io/spider-pig" rel="noopener noreferrer"&gt;&lt;em&gt;Spider-Pig&lt;/em&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Can you think of other good uses for this sort of mechanic?  How might you apply this in your own games?  Share your thoughts in the comments below!&lt;/p&gt;

</description>
      <category>miniscript</category>
      <category>minimicro</category>
      <category>programming</category>
      <category>gamedev</category>
    </item>
    <item>
      <title>MiniScript Weekly News — April 30, 2026</title>
      <dc:creator>JoeStrout</dc:creator>
      <pubDate>Thu, 30 Apr 2026 23:08:43 +0000</pubDate>
      <link>https://dev.to/joestrout/miniscript-weekly-news-april-30-2026-6dd</link>
      <guid>https://dev.to/joestrout/miniscript-weekly-news-april-30-2026-6dd</guid>
      <description>&lt;h2&gt;
  
  
  Development Updates
&lt;/h2&gt;

&lt;p&gt;MiniScript 2 got a solid round of command-line quality-of-life improvements this week. Joe added editable input history, searchable REPL history (&lt;code&gt;!? foo&lt;/code&gt; style queries), and a new &lt;code&gt;_in&lt;/code&gt; / &lt;code&gt;_out&lt;/code&gt; history model; he also fixed some extra blank lines in the REPL.&lt;/p&gt;

&lt;p&gt;On the raylib side, &lt;strong&gt;raylib-miniscript&lt;/strong&gt; moved forward nicely with raylib now pinned to &lt;strong&gt;6.0&lt;/strong&gt; as a git submodule, plus a bump to version &lt;strong&gt;0.3&lt;/strong&gt;. Even better, every API now has a code example in the &lt;a href="https://github.com/JoeStrout/raylib-miniscript/wiki" rel="noopener noreferrer"&gt;wiki&lt;/a&gt;, along with a new &lt;a href="https://github.com/JoeStrout/raylib-miniscript/wiki/Raylib_Types" rel="noopener noreferrer"&gt;Raylib Types&lt;/a&gt; page to help map Raylib structures into MiniScript.&lt;/p&gt;

&lt;p&gt;In the Mini Micro channel,  Joe explained display layering and mode switching in detail, and users kicked around some "worst sorting algorithm" ideas just for fun.&lt;/p&gt;

&lt;h2&gt;
  
  
  Community Projects
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Zaxabock&lt;/strong&gt; shared a playful MiniScript experiment called &lt;strong&gt;PseudoLambda&lt;/strong&gt;: &lt;a href="https://github.com/Marutzo/Mini-Micro/blob/main/PseudoLambda" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt;. It defines lambda-like expressions using Joe’s eval support, and it looks like a fun little throwback while waiting on more language features.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;𝔇𝔢𝔞𝔱𝔥&lt;/strong&gt; has been building an ambitious project, &lt;strong&gt;Ultimate Space Odyssey&lt;/strong&gt;, and shared a deep dive into Mini Micro display management while working through layered UI, sprite displays, and planet generation. The repo is here: &lt;a href="https://github.com/death-dev96/Ultimate_Space_Odyssey/tree/main/Game" rel="noopener noreferrer"&gt;Ultimate_Space_Odyssey/Game&lt;/a&gt; — great to see someone pushing the display system and documenting what they learn along the way.&lt;/p&gt;

&lt;p&gt;Joe also highlighted a great visual idea for the community to try: a &lt;strong&gt;Mini Micro kaleidoscope&lt;/strong&gt; built from sprites and animated UVs. He posted the write-up here: &lt;a href="https://dev.to/joestrout/make-a-mini-micro-kaleidoscope-1kbc"&gt;Make a Mini Micro Kaleidoscope&lt;/a&gt;, and it sounds like a fun little program to play with for anyone looking for a colorful weekend project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Discussion Highlights
&lt;/h2&gt;

&lt;p&gt;There was a lively thread about how MiniScript fits into game architecture, especially around threading and when to use &lt;code&gt;install&lt;/code&gt; versus simply switching display modes. Joe’s advice was consistent and reassuring: MiniScript is already thread-safe, and in most games you’ll be happier treating &lt;code&gt;install&lt;/code&gt; as a special-case tool rather than a default workflow.&lt;/p&gt;

&lt;p&gt;Another useful discussion centered on REPL smart quotes and paste behavior in Mini Micro 2. The conversation surfaced a real tension between convenience and control, with several community members offering thoughtful use cases; it was a nice example of the group thinking carefully about developer experience.&lt;/p&gt;

&lt;p&gt;There was also some cheerful design brainstorming in &lt;code&gt;#game-ideas&lt;/code&gt;, where &lt;strong&gt;Midsubspace&lt;/strong&gt; floated the idea of making a MiniScript Mancala game. Joe gave it an encouraging “go for it,” which feels like the perfect nudge for a good community project.&lt;/p&gt;

&lt;p&gt;Thanks for reading — happy scripting, and keep sharing what you’re building!&lt;/p&gt;

&lt;h2&gt;
  
  
  Upcoming Game Jams
&lt;/h2&gt;

&lt;p&gt;These upcoming jams look like a great fit for Mini Micro:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/mini-choco-jam-1" rel="noopener noreferrer"&gt;Mini Choco Jam&lt;/a&gt;&lt;/strong&gt; (starts 2026-02-28 23:00:00) — A romance-focused, story-first jam with 2D-friendly requirements and no need for 3D or networking is an excellent fit for Mini Micro, especially for visual-novel or text-based games.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/16bits-2nd-caravan-jam" rel="noopener noreferrer"&gt;16bits 2nd Caravan Jam&lt;/a&gt;&lt;/strong&gt; (starts 2026-05-05 13:30:17) — A great fit for a fast, score-chasing arcade game: the jam is built around short, easy-to-pick-up runs with high skill ceilings, especially in the spirit of classic Caravan-style shoot ’em ups.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/three-button-jam-2026" rel="noopener noreferrer"&gt;Three Button Jam 2026 (8 Bits to Infinity)&lt;/a&gt;&lt;/strong&gt; (starts 2026-05-08 17:00:00) — A highly accessible restriction jam with a fun twist: build a complete game using only three buttons, making it perfect for inventive controls, tight design, and clever feedback loops.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/ak-gaming-game-jam-6" rel="noopener noreferrer"&gt;Ak Gaming Game Jam #6&lt;/a&gt;&lt;/strong&gt; — A very accessible jam with free engine choice, no 3D or networking demands, and a strong emphasis on playable, theme-driven entries—great for retro 2D or text-based game ideas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/aeiougamejam" rel="noopener noreferrer"&gt;AEIOU GameJam 2026&lt;/a&gt;&lt;/strong&gt; (starts 2026-05-01 03:45:00) — A creativity-first jam with a clever twist theme, encouraging illusions, hidden mechanics, and unexpected gameplay that fits retro 2D experimentation perfectly.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>miniscript</category>
      <category>minimicro</category>
      <category>programming</category>
      <category>news</category>
    </item>
    <item>
      <title>Make a Mini Micro Kaleidoscope</title>
      <dc:creator>JoeStrout</dc:creator>
      <pubDate>Wed, 29 Apr 2026 20:11:14 +0000</pubDate>
      <link>https://dev.to/joestrout/make-a-mini-micro-kaleidoscope-1kbc</link>
      <guid>https://dev.to/joestrout/make-a-mini-micro-kaleidoscope-1kbc</guid>
      <description>&lt;p&gt;You have &lt;em&gt;got&lt;/em&gt; to try this.&lt;/p&gt;

&lt;p&gt;Inspired by a &lt;a href="https://www.facebook.com/share/v/18j8zCBMcK/" rel="noopener noreferrer"&gt;Facebook post&lt;/a&gt;, I decided this morning to make a kaleidoscope demo for Mini Micro.  And man, this thing is trippy!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa6690hy7m23s8i7gds8f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa6690hy7m23s8i7gds8f.png" alt="Screen shot of kaleidoscope program" width="800" height="535"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are a lot of knobs to tweak and settings to explore, so fire up Mini Micro (download it free &lt;a href="https://miniscript.org/MiniMicro/#download" rel="noopener noreferrer"&gt;here&lt;/a&gt; if you don't have it already), and follow along!&lt;/p&gt;

&lt;h2&gt;
  
  
  The Big Idea
&lt;/h2&gt;

&lt;p&gt;A kaleidoscope is a set of mirrors that reflect onto some interesting "stuff" (traditionally, colorful little bits of plastic at the end of the tube) to provide a multiple views of the same content.  In Mini Micro, we're going to provide those views by using Sprites, each using the same image, and stretched out to a diamond shape.  Those are arranged in a circle, providing a star shape overall, like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2u7lwfs2xgqfzuwsa58d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2u7lwfs2xgqfzuwsa58d.png" alt="Screen shot of Mini Micro showing six diamonds arranged into a 6-pointed star." width="800" height="536"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I've made the diamonds smaller, and shifted one of the diamonds out a bit so you can see it in the image above.  In the real program, we'll scale these up enough that they fill the screen without gaps.&lt;/p&gt;

&lt;p&gt;Then, we set the texture coordinates or "UVs" on each diamond to the same portion of a colorful texture, which represents the "interesting stuff" at the end of the tube.  Importantly, the UV coordinates are &lt;em&gt;flipped&lt;/em&gt; on alternating diamonds.  That causes the texture at the edge of one diamond to match up perfectly with the texture on its neighbor, and results in the trippy symmetrical patterns.&lt;/p&gt;

&lt;p&gt;Finally, we just move those UV coordinates around on the texture, causing the pattern to whirl and change.  It's mesmerizing!&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;Start by downloading one or both of these images: &lt;/p&gt;


&lt;div class="ltag-slides ltag-slides--carousel"&gt;
  &lt;div class="ltag-slides__track"&gt;
    &lt;div class="ltag-slide"&gt;
      &lt;img class="ltag-slide__image" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvexyvzi2fwmf7jmdktkb.png" alt="kaltex1.png" width="800" height="800"&gt;
&lt;/div&gt;


&lt;div class="ltag-slide"&gt;
      &lt;img class="ltag-slide__image" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7f1yw4aytfjsawuzi2od.png" alt="kaltex2.png" width="800" height="800"&gt;
&lt;/div&gt;



  &lt;/div&gt;
    ‹
    ›
    &lt;div class="ltag-slides__dots"&gt;&lt;/div&gt;
    
      (function() {
        var container = document.currentScript.closest('.ltag-slides--carousel');
        var track = container.querySelector('.ltag-slides__track');
        var slides = track.querySelectorAll('.ltag-slide');
        var prevBtn = container.querySelector('.ltag-slides__nav--prev');
        var nextBtn = container.querySelector('.ltag-slides__nav--next');
        var dotsContainer = container.querySelector('.ltag-slides__dots');
        var current = 0;
        var total = slides.length;

        for (var i = 0; i &amp;lt; total; i++) {
          var dot = document.createElement('button');
          dot.className = 'ltag-slides__dot' + (i === 0 ? ' ltag-slides__dot--active' : '');
          dot.setAttribute('aria-label', 'Go to slide ' + (i + 1));
          dot.dataset.index = i;
          dot.addEventListener('click', function() { goTo(parseInt(this.dataset.index)); });
          dotsContainer.appendChild(dot);
        }

        function goTo(index) {
          current = ((index % total) + total) % total;
          track.style.transform = 'translateX(-' + (current * 100) + '%)';
          var dots = dotsContainer.querySelectorAll('.ltag-slides__dot');
          for (var i = 0; i &amp;lt; dots.length; i++) {
            dots[i].classList.toggle('ltag-slides__dot--active', i === current);
          }
        }

        prevBtn.addEventListener('click', function() { goTo(current - 1); });
        nextBtn.addEventListener('click', function() { goTo(current + 1); });
      })();
    
&lt;/div&gt;


&lt;p&gt;I called them "kaltex1.png" and "kaltex2.png".  Save them to whatever folder you want to do this project in.  Then launch Mini Micro, and mount that same folder (using the disk-slot icon below the screen; or on Mac/Windows, you can just drop the folder onto the Mini Micro window to mount it).&lt;/p&gt;

&lt;p&gt;Type &lt;code&gt;view "kaltex1.png"&lt;/code&gt; and press Return in Mini Micro to verify that you're set up with everything in the right place.  Then use the &lt;code&gt;edit&lt;/code&gt; command, and paste in this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;clear
texture = file.loadImage("kaltex1.png")
cx = 480; cy = 320; r = 600  // screen center and radius
n = 6  // number of wedges

for i in range(n-1)
    sp = new Sprite
    sp.image = texture
    a = i * 2*pi/n
    a1 = a + pi/n
    a2 = a1 + pi/n
    sp.setCorners [[cx, cy],
      [cx+cos(a)*r, cy+sin(a)*r],
      [cx+cos(a1)*r*2, cy+sin(a1)*r*2],  
      [cx+cos(a2)*r, cy+sin(a2)*r]]
    display(4).sprites.push sp
end for
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save that as "kaleidoscope" (or whatever you like), then run it.  It should fill your screen with repeating copies of the full texture.&lt;/p&gt;

&lt;p&gt;This code mostly just figures out the angle (in radians) to the corners of each diamond, and then calculates the positions of those using &lt;code&gt;cos&lt;/code&gt; and &lt;code&gt;sin&lt;/code&gt;.  If you need a review of how angles, &lt;code&gt;sin&lt;/code&gt;, and &lt;code&gt;cos&lt;/code&gt; work, run &lt;code&gt;/sys/demo/angles&lt;/code&gt;.  (And you thought you'd never need trigonometry in real life!)&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting UVs
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;edit&lt;/code&gt; your program again, and append this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;uvs = function(t, flip=false)
    cx = 0.5 + 0.25 * sin(t * 0.13)
    cy = 0.5 + 0.25 * cos(t * 0.17)
    a = t * 0.21
    r = 0.25 + 0.08 * sin(t * 0.31)
    result = []
    for i in range(0,3)
        result.push [cx + cos(a)*r, cy + sin(a)*r]
        if flip then a -= pi/2 else a += pi/2
    end for
    return result
end function
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We're just defining a function here, not actually calling it, so if you run now it shouldn't behave any differently.  But let's take a moment to understand what's going on.&lt;/p&gt;

&lt;p&gt;This code is somewhat similar to the diamond-positioning code we had before.  It's basically defining a four points arranged in a square that moves around, scales, and rotates, sampling different areas of the sprite texture.&lt;/p&gt;

&lt;p&gt;First we calculate a center (&lt;code&gt;cx&lt;/code&gt;, &lt;code&gt;cy&lt;/code&gt;) position that depends on the value &lt;code&gt;t&lt;/code&gt; (representing "time").  When you read &lt;code&gt;cx = 0.5 + 0.25 * sin(t * 0.13)&lt;/code&gt;, think "cx is going to vary around 0.5, by up to 0.25 in either direction".  The factor &lt;code&gt;0.13&lt;/code&gt; controls how &lt;em&gt;quickly&lt;/em&gt; &lt;code&gt;cx&lt;/code&gt; varies with time.  &lt;code&gt;cy&lt;/code&gt; is similar but varies at a different rate.&lt;/p&gt;

&lt;p&gt;Then we calculate an angle &lt;code&gt;a&lt;/code&gt;, as a straight-up multiple of &lt;code&gt;t&lt;/code&gt;.  This makes our square rotate steadily with time.  (What would happen if you threw a factor of &lt;code&gt;sin&lt;/code&gt; in this one too?)  Finally, we calculate a radius &lt;code&gt;r&lt;/code&gt; that uses the same &lt;code&gt;sin&lt;/code&gt; trick to vary by +/- 0.08 around 0.25.&lt;/p&gt;

&lt;p&gt;With our center, angle, and radius ready to go, the &lt;code&gt;for&lt;/code&gt; loop just calculates each point and stuffs them into &lt;code&gt;result&lt;/code&gt;.  But note the &lt;code&gt;if&lt;/code&gt; statement that adjusts our angle after each point.  When &lt;code&gt;flip&lt;/code&gt; is true, we &lt;em&gt;subtract&lt;/em&gt; &lt;code&gt;pi/2&lt;/code&gt; (90°, or a quarter circle) as we go; otherwise we &lt;em&gt;add&lt;/em&gt; it.  This is what flips the texture on every other diamond, so that they mesh properly at the edges.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy2ulcea4yexg4cz4plsy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy2ulcea4yexg4cz4plsy.png" alt="Screenshot of kaleidoscope program" width="800" height="535"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Animation!
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;edit&lt;/code&gt; your code again, and paste in this final piece:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;while not key.pressed("escape")
    yield
    t = time
    //t = mouse.x/100 + mouse.y/71
    for i in range(n-1)
        display(4).sprites[i].setUVs uvs(t, i%2)
    end for
end while
key.clear
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the main loop.  We start with a &lt;code&gt;yield&lt;/code&gt;, as all good main loops do, fixing the animation rate to 60 frames/sec.  Then we choose a &lt;code&gt;t&lt;/code&gt; value equal to the &lt;code&gt;time&lt;/code&gt; (or, if you uncomment the line after that, a &lt;code&gt;t&lt;/code&gt; value that depends on the mouse!).  Then we just call &lt;code&gt;setUVs&lt;/code&gt; for each of our diamond sprites, passing in &lt;code&gt;t&lt;/code&gt;, and with &lt;code&gt;flip&lt;/code&gt; set to true (1) for the odd-numbered diamonds.&lt;/p&gt;

&lt;p&gt;That's it.  Run the program now, and you'll be in trippy kaleidoscope land!  But you're not done.  Now you get to do the fun part:&lt;/p&gt;

&lt;h2&gt;
  
  
  Tinkering
&lt;/h2&gt;

&lt;p&gt;This is code that just begs to be played with!  Here are some places to start:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Change the texture loaded at the top of the program!  This makes a dramatic difference in the overall feel.  Try both of the ones above, or try making your own.  (Or ask an AI to make one for you.)&lt;/li&gt;
&lt;li&gt;Change the value of &lt;code&gt;n&lt;/code&gt; (number of diamonds) at the top.  4, 6, 8, and 10 all work well.  But push it till it breaks!  What happens if you use 5 or 7 or 30?&lt;/li&gt;
&lt;li&gt;Uncomment that &lt;code&gt;t = mouse&lt;/code&gt; line, and instead of animating with time, you can actually control the thing by moving your mouse around.  Play with the constants on that line.  Or, can you think of useful ways to combine time &lt;em&gt;and&lt;/em&gt; mouse position?&lt;/li&gt;
&lt;li&gt;Change the constants in the &lt;code&gt;uvs&lt;/code&gt; method.  Can you find values you like better?&lt;/li&gt;
&lt;li&gt;Throw a .mp3 or .ogg file of background music into your folder, and have your program load and play it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's such a small program, but so fun to mess with.  There's a good chance this will end up being one of the built-in demos in Mini Micro 2, but for now, only those sharp enough to follow this blog post will get to have that fun.  Enjoy!&lt;/p&gt;

</description>
      <category>miniscript</category>
      <category>minimicro</category>
      <category>programming</category>
      <category>graphics</category>
    </item>
    <item>
      <title>MiniScript Weekly News — April 22, 2026</title>
      <dc:creator>JoeStrout</dc:creator>
      <pubDate>Wed, 22 Apr 2026 23:31:54 +0000</pubDate>
      <link>https://dev.to/joestrout/miniscript-weekly-news-april-22-2026-3oep</link>
      <guid>https://dev.to/joestrout/miniscript-weekly-news-april-22-2026-3oep</guid>
      <description>&lt;h2&gt;
  
  
  Development Updates
&lt;/h2&gt;

&lt;p&gt;MiniScript 2 made a big step forward this week with the new &lt;code&gt;error&lt;/code&gt; type landing in the language. Errors can now be created with &lt;code&gt;err(...)&lt;/code&gt;, checked with &lt;code&gt;isa error&lt;/code&gt;, and even subtyped for more specific handling — a major improvement to one of MiniScript’s longtime weak spots.&lt;br&gt;&lt;br&gt;
Read more in the dev log and discussion thread: &lt;a href="https://github.com/JoeStrout/miniscript2/blob/main/notes/DEV_LOG.md" rel="noopener noreferrer"&gt;miniscript2 DEV_LOG&lt;/a&gt; and &lt;a href="https://forums.miniscript.org/d/617-an-error-handling-proposal-for-miniscript-20/6" rel="noopener noreferrer"&gt;error handling proposal&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There was also active design discussion around Mini Micro 2, especially whether display mode should keep using the current “magic assignment” style or move to a clearer function call like &lt;code&gt;setMode&lt;/code&gt;. Joe is leaning toward preserving compatibility while introducing the cleaner API, which seems like a thoughtful path for existing projects.&lt;br&gt;&lt;br&gt;
Related discussion: &lt;a href="https://discord.com/channels/" rel="noopener noreferrer"&gt;#minimicro-2&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;On the platform side, raylib-miniscript got more polished documentation and continues to evolve quickly. The API docs now include autogenerated sections for custom intrinsics, plus &lt;code&gt;http.post&lt;/code&gt;, &lt;code&gt;file.loadRaw&lt;/code&gt;, and &lt;code&gt;file.saveRaw&lt;/code&gt; support for practical app and game integration.&lt;br&gt;&lt;br&gt;
Repo: &lt;a href="https://github.com/JoeStrout/raylib-miniscript" rel="noopener noreferrer"&gt;raylib-miniscript&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Community Projects
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;maho_citrus&lt;/strong&gt; published a new utility library, &lt;strong&gt;utf-8-for-miniscript&lt;/strong&gt;, for environments (like GreyHack) without native UTF8 encode/decode support.&lt;br&gt;
Repo: &lt;a href="https://github.com/mahocitrus/utf-8-for-miniscript" rel="noopener noreferrer"&gt;utf-8-for-miniscript&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dat_One_Dev&lt;/strong&gt; updated a personal site with a growing collection of Mini Micro articles and courses, including multiple tutorial series. They also mentioned training a model on their site’s content, which is a neat sign that Mini Micro resources are becoming substantial enough to support discovery and reuse.&lt;br&gt;&lt;br&gt;
Links: &lt;a href="https://cbsemastery.in/tutorial/game-development/mini-micro" rel="noopener noreferrer"&gt;Mini Micro tutorial hub&lt;/a&gt;, &lt;a href="https://cbsemastery.in/course/tech/zero-to-game-dev" rel="noopener noreferrer"&gt;Zero to Game Dev&lt;/a&gt;, &lt;a href="https://cbsemastery.in/course/tech/learn-by-code" rel="noopener noreferrer"&gt;Learn by Code&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Zaxabock&lt;/strong&gt; continued building out logic and automata projects in Mini Micro, including a logic engine template, finite-state automata work, and a Mini-Micro-based logic engine repo. These are the kind of deep, playful technical projects that show how flexible the language can be.&lt;br&gt;&lt;br&gt;
Repo: &lt;a href="https://github.com/Marutzo/Mini-Micro/blob/main/LogicEngineV4" rel="noopener noreferrer"&gt;LogicEngineV4&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Joe also shared progress on &lt;strong&gt;MiniClaw&lt;/strong&gt;, a tiny LLM agent built in Mini Micro for working with text files. There’s already a write-up on dev.to, and it’s a fun example of MiniScript being used for something modern while still keeping that compact, readable style.&lt;br&gt;&lt;br&gt;
Article: &lt;a href="https://dev.to/joestrout/miniclaw-a-tiny-llm-agent-for-mini-micro-4akf"&gt;MiniClaw: A Tiny LLM Agent for Mini Micro&lt;/a&gt;&lt;br&gt;&lt;br&gt;
Code: &lt;a href="https://github.com/JoeStrout/miniclaw" rel="noopener noreferrer"&gt;miniclaw on GitHub&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Discussion Highlights
&lt;/h2&gt;

&lt;p&gt;There were lots of helpful embedding questions this week, especially from &lt;strong&gt;Frib&lt;/strong&gt;, who is integrating MiniScript into a Unity-based project. Joe confirmed that &lt;code&gt;_foo&lt;/code&gt;-style globals are fine for host code, but suggested using intrinsics when possible for safer exposure to user scripts.  &lt;/p&gt;

&lt;p&gt;MiniScript 2 also sparked some classic language-design brainstorming, from better error propagation to compiler/source-location tracking and stack traces. It’s great to see the community stress-testing the new features and helping shape them before release.&lt;/p&gt;

&lt;p&gt;In Mini Micro circles, there’s ongoing interest in tutorials, docs, and even a community book built around expanding existing demos. That kind of “learn by remixing” idea feels very on-brand for MiniScript, and it’s wonderful to see people building on the demos as teaching material.&lt;/p&gt;

&lt;p&gt;Thanks for reading — and as always, keep sharing your experiments, tools, and little sparks of weirdness. See you next week!&lt;/p&gt;

&lt;h2&gt;
  
  
  Upcoming Game Jams
&lt;/h2&gt;

&lt;p&gt;These upcoming jams look like a great fit for Mini Micro:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/mini-choco-jam-1" rel="noopener noreferrer"&gt;Mini Choco Jam&lt;/a&gt;&lt;/strong&gt; (starts 2026-02-28 23:00:00) — A romance-focused, story-first jam with 2D-friendly requirements and no need for 3D or networking is an excellent fit for Mini Micro, especially for visual-novel or text-based games.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/trigamedev-monthly-game-jam-6" rel="noopener noreferrer"&gt;TriGameDev Monthly Game Jam #6&lt;/a&gt;&lt;/strong&gt; (starts 2026-04-24 21:00:00) — A 48-hour theme-driven jam about imprisonment and escape, with flexible interpretation and optional challenges like a Panopticon concept or dual perspectives, making it a strong fit for concise 2D retro-style games.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/portfolio-builders-jam-week-70" rel="noopener noreferrer"&gt;Portfolio Builders Jam - Week #70&lt;/a&gt;&lt;/strong&gt; (starts 2026-04-27 11:00:00) — A very flexible weekly jam focused on portfolio pieces, with room for small playable demos or even standalone art, audio, or code samples—great for polished 2D, retro-style projects and skill-building experiments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/deltarune-undertale-jam" rel="noopener noreferrer"&gt;Deltarune + Undertale Jam&lt;/a&gt;&lt;/strong&gt; — A strong fit for a retro 2D project: this jam centers on turn-based battles, dialogue-driven storytelling, and the emotional, quirky atmosphere that pairs perfectly with pixel art and simple RPG mechanics.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/aeiougamejam" rel="noopener noreferrer"&gt;AEIOU GameJam 2026&lt;/a&gt;&lt;/strong&gt; (starts 2026-05-01 03:45:00) — A creativity-first jam with a clever twist theme, encouraging illusions, hidden mechanics, and unexpected gameplay that fits retro 2D experimentation perfectly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/oink-jam-2" rel="noopener noreferrer"&gt;Oink Jam 2 ($3000+ in Prizes)&lt;/a&gt;&lt;/strong&gt; (starts 2026-04-30 13:00:00) — A short, beginner-friendly four-day jam with flexible themes, light rules, and a welcoming community—great for making a polished retro-style 2D game fast.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>miniscript</category>
      <category>minimicro</category>
      <category>news</category>
      <category>programming</category>
    </item>
    <item>
      <title>MiniClaw: A Tiny LLM Agent for Mini Micro</title>
      <dc:creator>JoeStrout</dc:creator>
      <pubDate>Thu, 16 Apr 2026 18:13:14 +0000</pubDate>
      <link>https://dev.to/joestrout/miniclaw-a-tiny-llm-agent-for-mini-micro-4akf</link>
      <guid>https://dev.to/joestrout/miniclaw-a-tiny-llm-agent-for-mini-micro-4akf</guid>
      <description>&lt;p&gt;Agents are all the rage these days.  &lt;a href="https://code.claude.com/docs/en/overview" rel="noopener noreferrer"&gt;Claude Code&lt;/a&gt; was one of the first, and perhaps still the most heavily used, specialized for coding.  Then OpenClaw burst onto the scene, able to do all sorts of general computer-use things, and caused a &lt;a href="https://www.tomshardware.com/tech-industry/artificial-intelligence/openclaw-fueled-ordering-frenzy-creates-apple-mac-shortage-delivery-for-high-unified-memory-units-now-ranges-from-6-days-to-6-weeks" rel="noopener noreferrer"&gt;shortage of Mac Minis&lt;/a&gt;.  More recently, &lt;a href="https://github.com/nousresearch/hermes-agent" rel="noopener noreferrer"&gt;Hermes Agent&lt;/a&gt; is a common favorite, with over 93 thousand stars on GitHub.&lt;/p&gt;

&lt;p&gt;All of these agents work in fundamentally the same way.  A "harness" acts as both the main program for an LLM, controlling its context so that it always knows what it needs to know; and provides tools the LLM can use so that it can always do what it needs to do.&lt;/p&gt;

&lt;p&gt;I covered &lt;a href="https://dev.to/joestrout/use-gpt-3-in-mini-micro-1h63"&gt;accessing LLMs from Mini Micro&lt;/a&gt; back in 2022, and &lt;a href="https://dev.to/joestrout/combining-gpt-and-wolfram-alpha-ma2"&gt;again in 2023&lt;/a&gt;, so why don't we take it to the logical next step, and &lt;strong&gt;create an agent in Mini Micro&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwfsemryrv3042zq40a1v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwfsemryrv3042zq40a1v.png" alt="MiniClaw logo" width="512" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing MiniClaw
&lt;/h2&gt;

&lt;p&gt;Yesterday I sat down and created &lt;a href="https://github.com/JoeStrout/miniclaw" rel="noopener noreferrer"&gt;MiniClaw&lt;/a&gt;.  It consists mainly of three files:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://github.com/JoeStrout/miniclaw/blob/main/instructions.txt" rel="noopener noreferrer"&gt;instructions.txt&lt;/a&gt;: these are the instructions to the LLM&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/JoeStrout/miniclaw/blob/main/agent.ms" rel="noopener noreferrer"&gt;agent.ms&lt;/a&gt;: the main program, which invokes the LLM and manages its context&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/JoeStrout/miniclaw/blob/main/tools.ms" rel="noopener noreferrer"&gt;tools.ms&lt;/a&gt;: code for the tools the agent can use to read, write, and manipulate files&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So what can it do?  Well, MiniClaw can read any file accessible within Mini Micro, which means the &lt;code&gt;/sys&lt;/code&gt; disk, plus whatever minidisk or folder you have mounted as &lt;code&gt;/usr&lt;/code&gt; and &lt;code&gt;/usr2&lt;/code&gt;.  It can also write files (only) under &lt;code&gt;/usr/workspace&lt;/code&gt;.  So, similar to Claude Code or most other agents, you can use it to create and modify pretty much any kind of text file.  Or you can just ask it to explain and summarize things for you.  For example, I asked it "tell me about the pictures on the sys disk", and it wrote out a nice summary:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fie14mbok8oxwe5pv97qc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fie14mbok8oxwe5pv97qc.png" alt="Screen shot of /sys/pics summary" width="800" height="639"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On another occasion, I asked it to create a &lt;code&gt;.md&lt;/code&gt; (Markdown) file describing all the demos found in /sys/demo.  But then, in a later session, I decided that the document it created was too wordy, so I asked it to shorten it:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu9ycpkf1fyi66le5aftv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu9ycpkf1fyi66le5aftv.png" alt="Screen shot of agent shortening DEMO_GUIDE.md" width="800" height="639"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The gray text gives us some hints as to what the code is doing: it shows when we call the LLM, how much data we get back as a response, and what tool the LLM is using (and why).&lt;/p&gt;

&lt;p&gt;Some tasks, like this one, take only a couple of tool calls.  Others take more.  The LLM will keep invoking tools, occasionally printing some messages for us about its work, until it figures the task is complete (or that it's unable to complete it).&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;The complete &lt;a href="https://github.com/JoeStrout/miniclaw/blob/main/agent.ms" rel="noopener noreferrer"&gt;agent.ms&lt;/a&gt; file is only 263 lines long, divided into 14 functions.  That's a bit too long to go over line by line here, but we'll hit the highlights, and I encourage you to check the source file for details.&lt;/p&gt;

&lt;p&gt;The big picture is this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each time we call the LLM, we give it our instructions (always the same), and the prompt (varies each turn).&lt;/li&gt;
&lt;li&gt;The prompt includes messages from the user, previous tool calls made by the agent, and the results of those calls -- all this stuff is called the "history".  It also includes the current task, so the LLM is clear on what it's supposed to be doing.&lt;/li&gt;
&lt;li&gt;The LLM gives us a response in JSON format: either a tool call, a question for the user, an intermediate message, or a final message (indicating it's done).&lt;/li&gt;
&lt;li&gt;We run any tool calls the LLM has asked for, and append the call and results to the history.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And that's pretty much it.  The main loop looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;currentUserInput&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
            &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gray&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="s2"&gt;"==&amp;gt; "&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
            &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"#00AA00"&lt;/span&gt;
            &lt;span class="n"&gt;globals&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;currentUserInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;
            &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gray&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getResponse&lt;/span&gt;
        &lt;span class="n"&gt;respData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;respData&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;null&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
            &lt;span class="n"&gt;addToHistory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"**IMPORTANT:** You must format your response as a JSON object!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;
            &lt;span class="n"&gt;handleResponse&lt;/span&gt; &lt;span class="n"&gt;respData&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="k"&gt;while&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;currentUserInput&lt;/code&gt; is the instruction the agent is working on; it's empty at the start of the run, or when the agent says it's finished.  So then we get more input from the user.  (Half the code above is just fiddling with the text color to be fancy.)&lt;/p&gt;

&lt;p&gt;Then we call &lt;code&gt;getResponse&lt;/code&gt; to get the LLM's response to the current context (instructions plus prompt as described above), and try to parse it as JSON.  Occasionally the LLM will forget to format its response as JSON; if that happens, we just add a stern reminder to the history (so the LLM will see it) and try again.  Otherwise, we call &lt;code&gt;handleResponse&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="n"&gt;handleResponse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;addToHistory&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"message"&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="n"&gt;printNicely&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;
        &lt;span class="n"&gt;globals&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lastMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"question"&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="n"&gt;printNicely&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;
        &lt;span class="n"&gt;addToHistory&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"--- User response ---"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"--- End user response ---"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EOL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"finish"&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="n"&gt;printNicely&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;
        &lt;span class="n"&gt;globals&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;currentUserInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"tool_call"&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="n"&gt;handleToolCall&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="n"&gt;addToHistory&lt;/span&gt; &lt;span class="s2"&gt;"ERROR: invalid response type """&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;
          &lt;span class="s2"&gt;"""; must be ""message"", ""question"", ""finish"", or ""tool_call""."&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt;  
&lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've removed some of the error handling and text-coloring above for clarity, but this is the gist of it.  We just switch based on the &lt;code&gt;type&lt;/code&gt; of response we got from the LLM; it should be one of the four types we put in the instructions.  Again, note that when we want to give the LLM more information -- like the user's response to a question -- we just add it to the history.  &lt;/p&gt;

&lt;p&gt;Let's talk about that &lt;code&gt;addHistory&lt;/code&gt; method a moment.  Its job is mainly just to append the given string(s) to a list of strings, so they can be included in the context.  But for any agent, context management is very important!  Too much context burns through tokens, and degrades LLM performance.  So, our &lt;code&gt;addHistory&lt;/code&gt; method limits how much history it remembers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="n"&gt;addToHistory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;
    &lt;span class="n"&gt;globals&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;historyLen&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;historyLen&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;4096&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;
        &lt;span class="n"&gt;globals&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;historyLen&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;history&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;
        &lt;span class="n"&gt;history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pull&lt;/span&gt;  &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;discard&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="k"&gt;while&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Probably the next most important function is &lt;code&gt;promptInput&lt;/code&gt;, which calculates the "prompt" part of the context -- the part that varies from turn to turn.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="n"&gt;promptInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;
    &lt;span class="nf"&gt;lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt; &lt;span class="s2"&gt;"# Task/User Input"&lt;/span&gt;
    &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt; &lt;span class="n"&gt;currentUserInput&lt;/span&gt;
    &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
    &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt; &lt;span class="s2"&gt;"# Current State"&lt;/span&gt;
    &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt; &lt;span class="s2"&gt;"Date/time: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;dateTime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;history&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
        &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push&lt;/span&gt; &lt;span class="s2"&gt;"# Recent history"&lt;/span&gt;
        &lt;span class="n"&gt;lines&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;history&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EOL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simple, right?  It's just composing a bit of Markdown calling out the current user input, the current state (which for this version of MiniClaw, is only the date/time), and the history.  This stuff is appended to the static &lt;a href="https://github.com/JoeStrout/miniclaw/blob/main/instructions.txt" rel="noopener noreferrer"&gt;instructions&lt;/a&gt;, and sent to the LLM.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Tools
&lt;/h2&gt;

&lt;p&gt;The functions above are going to be pretty standard for any agent.  What determines what the agent actually &lt;em&gt;does&lt;/em&gt; are the tools and instructions provided to it.  In MiniClaw, the tools are separated out into their own file, &lt;a href="https://github.com/JoeStrout/miniclaw/blob/main/tools.ms" rel="noopener noreferrer"&gt;tools.ms&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This file begins with some little helper functions: &lt;code&gt;err&lt;/code&gt;, &lt;code&gt;errMissingArg&lt;/code&gt;, and &lt;code&gt;okResult&lt;/code&gt;, which all generate little result maps to be returned to the LLM; plus &lt;code&gt;resolvePath&lt;/code&gt; and &lt;code&gt;isWriteable&lt;/code&gt;, which help the tool code deal with files properly.  Then, it has a function for each tool:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;list_files&lt;/li&gt;
&lt;li&gt;read_file&lt;/li&gt;
&lt;li&gt;head_file&lt;/li&gt;
&lt;li&gt;tail_file&lt;/li&gt;
&lt;li&gt;write_file&lt;/li&gt;
&lt;li&gt;delete_file&lt;/li&gt;
&lt;li&gt;move_file&lt;/li&gt;
&lt;li&gt;make_dir&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each of these takes a map containing arguments (which we've gotten by parsing the JSON from the LLM), does its thing if it can, and then returns a map of results -- usually from one of the &lt;code&gt;err&lt;/code&gt; functions, or from &lt;code&gt;okResult&lt;/code&gt;, with details (like the path of the affected file) added in.  This lets the LLM know whether its attempt to use a tool was successful.&lt;/p&gt;

&lt;p&gt;As an example, let's look at &lt;code&gt;head_file&lt;/code&gt;, whose job it is to return the first so-many lines of a text file.  This tool is described in the instructions file as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"head_file"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"desc"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Return the first n lines of a UTF-8 file.  Use this to examine large or unknown text files."&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"arguments"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"lines"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"int"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We give the agent the name of the tool, a description including advice on when to use it, and info on the expected arguments.  So, the actual MiniScript function is expecting its &lt;code&gt;args&lt;/code&gt; map to contain &lt;code&gt;"path"&lt;/code&gt; and &lt;code&gt;"lines"&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight lua"&gt;&lt;code&gt;&lt;span class="n"&gt;head_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;errMissingArg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Invalid path `"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;"`"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;lines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"lines"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;readLines&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;lines&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="n"&gt;lines&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;okResult&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EOL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It pulls those arguments out of the map, does some simple validation on them, reads the file, and returns the requested data as the "content" string of the result map.&lt;/p&gt;

&lt;p&gt;The other tools all work in a similar fashion.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trying it out
&lt;/h2&gt;

&lt;p&gt;You can download the MiniClaw source files from &lt;a href="https://github.com/JoeStrout/miniclaw" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;, but in order to access the LLM (gpt-5.4-nano) it uses, you'll need to set up an API key:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Log in to &lt;a href="https://platform.openai.com/" rel="noopener noreferrer"&gt;platform.openai.com&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Click on &lt;strong&gt;API Keys&lt;/strong&gt; on the left.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create new secret key&lt;/strong&gt;, give it a name like "MiniClaw", and copy the key it shows you.&lt;/li&gt;
&lt;li&gt;Paste that into a file called &lt;code&gt;api_key.secret&lt;/code&gt; next to &lt;code&gt;agent.ms&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Then you can mount that directory in Mini Micro, and &lt;code&gt;run "agent"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As for cost, I wouldn't worry about it too much... I used this thing a &lt;em&gt;lot&lt;/em&gt; yesterday and today while developing it, and it cost under 40 cents.  &lt;code&gt;gpt-5.4-nano&lt;/code&gt; is pretty cheap, and seems smart enough for everything I've tried so far.&lt;/p&gt;

&lt;h2&gt;
  
  
  Taking it further
&lt;/h2&gt;

&lt;p&gt;This is where it gets fun: &lt;strong&gt;add your own tools!&lt;/strong&gt;  This version of MiniClaw only does basic file creation/manipulation, as you can see from the tool list above.  But you could make your own MiniClaw do anything Mini Micro is capable of.  Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Display a picture&lt;/li&gt;
&lt;li&gt;Play a sound (or series of sounds — making music?)&lt;/li&gt;
&lt;li&gt;Launch a program&lt;/li&gt;
&lt;li&gt;Access the web or web services via &lt;code&gt;http&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Do math&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dev.to/joestrout/combining-gpt-and-wolfram-alpha-ma2"&gt;Call Wolfram Alpha&lt;/a&gt; for help&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And adding more tools is pretty easy: just create a function for it in &lt;code&gt;tools.ms&lt;/code&gt;, and add a description of the tool to &lt;code&gt;instructions.txt&lt;/code&gt;.  That's it; the LLM should be smart enough to invoke it when the time is right.&lt;/p&gt;

&lt;p&gt;If you want to switch to a different LLM provider (here's a handy guide to &lt;a href="https://get-hermes.ai/models/" rel="noopener noreferrer"&gt;AI models for Hermes&lt;/a&gt;), you might have to adjust or rewrite the &lt;code&gt;getResponse&lt;/code&gt; function, which formats the input for the LLM and then digs the actual response text out of the JSON package it's buried in.  But this is totally doable.  You could even run a local LLM, if that's your thing, and connect to it at &lt;code&gt;localhost&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There's also a lot that could be done to improve MiniClaw's user interface.  Right now it just prints (albeit with pretty colors, supporting basic markdown commonly used by LLMs) stuff to the text display as it comes in.  You could instead make a structured display, keeping the current task up top, showing some info about the context on the side, and neatly formatted responses (perhaps drawn with proportional fonts into a PixelDisplay) below.&lt;/p&gt;

&lt;p&gt;My main goal with MiniClaw was to create an agent that is simple and small enough (and MiniScript enough!) to be easily understood and modified.  And the great thing is, Mini Micro is a safe sandbox environment, assuming you only mount minidisks or folders you aren't worried about.  So go nuts and have fun!&lt;/p&gt;

</description>
      <category>miniscript</category>
      <category>minimicro</category>
      <category>agents</category>
      <category>programming</category>
    </item>
    <item>
      <title>MiniScript Weekly News — Apr 9, 2026</title>
      <dc:creator>JoeStrout</dc:creator>
      <pubDate>Thu, 09 Apr 2026 23:01:27 +0000</pubDate>
      <link>https://dev.to/joestrout/miniscript-weekly-news-apr-9-2027-456o</link>
      <guid>https://dev.to/joestrout/miniscript-weekly-news-apr-9-2027-456o</guid>
      <description>&lt;p&gt;&lt;em&gt;Correction: the headline originally said 2027... now corrected, before the temporal police could find me.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Development Updates
&lt;/h2&gt;

&lt;p&gt;MiniScript 2 saw a nice round of progress this week, with function metadata support being the big new feature. The new &lt;code&gt;info(@func)&lt;/code&gt; intrinsic can now expose a function’s name, note, and params: &lt;a href="https://github.com/JoeStrout/miniscript2" rel="noopener noreferrer"&gt;JoeStrout/miniscript2&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;On the raylib side, Joe added &lt;code&gt;http.post&lt;/code&gt; support, plus &lt;code&gt;file.loadRaw&lt;/code&gt; and &lt;code&gt;file.saveRaw&lt;/code&gt; for binary data. That should make it easier to talk to REST services and handle non-text assets in &lt;a href="https://github.com/JoeStrout/raylib-miniscript" rel="noopener noreferrer"&gt;raylib-miniscript&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The alchemy UI toolkit keeps taking shape too. Joe shared the first functional UI demo, and the dev log notes working progress on buttons, static text, spinner controls, and a coordinate-system-agnostic &lt;code&gt;Rect&lt;/code&gt; class: &lt;a href="https://github.com/JoeStrout/alchemy-ui" rel="noopener noreferrer"&gt;alchemy-ui&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Community Projects
&lt;/h2&gt;

&lt;p&gt;A big update for the Mini Micro showcase: Joe built a tool to scan itch.io pages and auto-fill missing entries, then expanded the catalog to 80 programs. If you’ve got a MiniScript or Mini Micro game or demo to share, he’s still asking for links to add to the catalog: &lt;a href="https://miniscript.org/MiniMicro/#programs" rel="noopener noreferrer"&gt;Mini Micro programs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Several community-made itch.io projects were highlighted this week. If you want to browse or share them, check out &lt;a href="https://dslower.itch.io/march-of-the-zomblez" rel="noopener noreferrer"&gt;March of the Zomblez&lt;/a&gt;, &lt;a href="https://dslower.itch.io/two-souls" rel="noopener noreferrer"&gt;Two Souls&lt;/a&gt;, and &lt;a href="https://dslower.itch.io/going-viral" rel="noopener noreferrer"&gt;Going Viral&lt;/a&gt;, all by &lt;a class="mentioned-user" href="https://dev.to/dslower"&gt;@dslower&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Other community submissions that came up include &lt;a href="https://dat-one-dev.itch.io/chaturanga" rel="noopener noreferrer"&gt;Chaturanga&lt;/a&gt;, and &lt;a href="https://dat-one-dev.itch.io/color-crash" rel="noopener noreferrer"&gt;Color Crash&lt;/a&gt; by @dat-one-dev, and &lt;a href="https://bibleclinger.itch.io/color-smash-tank" rel="noopener noreferrer"&gt;Color Smash Tank&lt;/a&gt;, and &lt;a href="https://bibleclinger.itch.io/space-fighter-85" rel="noopener noreferrer"&gt;Space Fighter 85&lt;/a&gt; by &lt;a class="mentioned-user" href="https://dev.to/bibleclinger"&gt;@bibleclinger&lt;/a&gt;. It’s great to see so many jam entries and experiments getting some love.&lt;/p&gt;

&lt;h2&gt;
  
  
  Discussion Highlights
&lt;/h2&gt;

&lt;p&gt;There was some fun brainstorming around a possible physical Mini Micro device. Ideas ranged from a compact keyboard (with arrow keys a must-have), to SD card storage, to even a rounded case with arcade buttons or bundled gamepads.&lt;/p&gt;

&lt;p&gt;In the MiniScript 2 forum discussion, Joe floated the new &lt;code&gt;info&lt;/code&gt; intrinsic before implementing it, and got a warm response. It’s a promising direction for making introspection and tooling much more pleasant in MS2: &lt;a href="https://forums.miniscript.org/d/618-accessing-function-metadata" rel="noopener noreferrer"&gt;forum thread&lt;/a&gt;.  There was also more discussion of a new &lt;a href="https://forums.miniscript.org/d/617-an-error-handling-proposal-for-miniscript-20/5" rel="noopener noreferrer"&gt;error handling system&lt;/a&gt;, which may see implementation next week — stay tuned!&lt;/p&gt;

&lt;h2&gt;
  
  
  Game Jam Notes
&lt;/h2&gt;

&lt;p&gt;This week’s jam theme was “one light source,” and the community quickly pointed folks toward the &lt;code&gt;/sys/demo/2dVis&lt;/code&gt; demo and the &lt;a href="https://itch.io/jam/micro-jam-056" rel="noopener noreferrer"&gt;micro-jam-056&lt;/a&gt; page. Joe also pointed out Florian’s earlier gem, &lt;a href="https://florian-castel.itch.io/in-my-bubble" rel="noopener noreferrer"&gt;In My Bubble&lt;/a&gt;, as another brilliant example of what can be done with a focused idea.&lt;/p&gt;

&lt;h2&gt;
  
  
  From the Community
&lt;/h2&gt;

&lt;p&gt;BibleClinger also kicked around an interesting idea for a community-authored MiniScript book, where experienced users could each contribute a chapter. That sounds like a wonderful way to share knowledge and celebrate the depth of the community.&lt;/p&gt;

&lt;p&gt;Thanks for reading, and keep those MiniScript projects coming!&lt;/p&gt;

&lt;h2&gt;
  
  
  Upcoming Game Jams
&lt;/h2&gt;

&lt;p&gt;These upcoming jams look like a great fit for Mini Micro:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/impressions-composing-jam-season-4-melody-jam" rel="noopener noreferrer"&gt;Impressions Composing Jam Season 4: Melody Jam&lt;/a&gt;&lt;/strong&gt; (starts 2026-04-10 22:00:00) — A focused music jam centered on crafting a memorable melody from a provided theme, with clear, simple requirements and plenty of room for creative interpretation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/kbgames-game-boys-chillin-on-a-grid-jam" rel="noopener noreferrer"&gt;KBGames "Game Boys Chillin' On A Grid" Jam&lt;/a&gt;&lt;/strong&gt; (starts 2026-04-13 22:18:30) — A super flexible jam centered on Game Boy vibes, chill/cozy energy, and grid-based ideas—an excellent match for retro pixel art, tile grids, and simple 2D gameplay.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/smashthefash" rel="noopener noreferrer"&gt;Games Transformed 2026 - 'Smash The Fash' Game Jam&lt;/a&gt;&lt;/strong&gt; — A politically charged jam inviting all kinds of antifascist games, from activist tactics and mutual aid to surreal puzzles and hopeful visions of solidarity, with room for serious, playful, or experimental takes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/dtj36-25" rel="noopener noreferrer"&gt;Devs That Jam 36-hour Challenge #25: Anniversary Edition&lt;/a&gt;&lt;/strong&gt; (starts 2026-04-25 10:00:00) — A fast, beginner-friendly 36-hour jam with a community-chosen theme, flexible use of pre-made assets, and judging that rewards fun, clarity, visuals, audio, and polish.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/panafrican2026" rel="noopener noreferrer"&gt;Pan-African Jam with Lagos Games Week 2026&lt;/a&gt;&lt;/strong&gt; (starts 2026-04-23 22:00:00) — A highly welcoming, fully virtual jam centered on creativity, cross-border collaboration, and game discovery—open to any genre and especially appealing for developers who want a community-driven event with real visibility and prizes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/portfolio-builders-jam-week-69" rel="noopener noreferrer"&gt;Portfolio Builders Jam - Week #69&lt;/a&gt;&lt;/strong&gt; (starts 2026-04-20 11:00:00) — A very flexible weekly jam focused on building portfolio pieces, with room for playable demos, polished art, audio, or code showcases—ideal if you want to make something small, skill-focused, and retro-friendly.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>miniscript</category>
      <category>minimicro</category>
      <category>news</category>
      <category>programming</category>
    </item>
    <item>
      <title>The Master Algorithm</title>
      <dc:creator>JoeStrout</dc:creator>
      <pubDate>Tue, 07 Apr 2026 17:03:14 +0000</pubDate>
      <link>https://dev.to/joestrout/the-master-algorithm-2oie</link>
      <guid>https://dev.to/joestrout/the-master-algorithm-2oie</guid>
      <description>&lt;p&gt;In 2015, a book by AI researcher Pedro Domingos came out called &lt;a href="https://www.hachettebookgroup.com/titles/pedro-domingos/the-master-algorithm/9780465061921" rel="noopener noreferrer"&gt;&lt;em&gt;The Master Algorithm: How the Quest for the Ultimate Learning Machine Will Remake Our World&lt;/em&gt;&lt;/a&gt;.  The author explored the "five tribes" of artificial intelligence (AI), and how each one might develop into the "Master Algorithm" of intelligence itself — the algorithm that could learn to do virtually anything humans and other animals can learn to do.  The five tribes are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;inductive reasoning&lt;/li&gt;
&lt;li&gt;connectionism (aka neural networks)&lt;/li&gt;
&lt;li&gt;evolutionary computation&lt;/li&gt;
&lt;li&gt;Bayesian networks&lt;/li&gt;
&lt;li&gt;analogical modelling&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This was ten years ago.  It was very much not obvious, at that time, which of these — or what combination of them — or even whether something entirely different — might turn out to be the Master Algorithm.&lt;/p&gt;

&lt;p&gt;But it's clear now.  I'm calling it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Master Algorithm is neural networks.
&lt;/h2&gt;

&lt;p&gt;It turns out, the master algorithm is connectionism.  A neural network, when it's big enough, structured appropriately, and trained on enough data, can do it all: language, reasoning, translation, programming, answering questions, following instructions, understanding pictures and videos, &lt;em&gt;generating&lt;/em&gt; pictures and videos, solving complex math problems, and on and on.&lt;/p&gt;

&lt;p&gt;The goalpost-movers like to pick at each of those and say "yes, but, it doesn't do &lt;em&gt;this thing&lt;/em&gt; very well and &lt;em&gt;that thing&lt;/em&gt; doesn't really count because of the following hand-wavy reasons."  But if you read the book, it's obvious that everything we all take for granted nowadays was far-off science fiction in 2015.  AI researchers literally &lt;em&gt;dreamed&lt;/em&gt; of machines that could do half of what ChatGPT or Claude does before breakfast, or what &lt;a href="https://deepmind.google/models/gemma/" rel="noopener noreferrer"&gt;Gemma&lt;/a&gt; does running locally &lt;em&gt;on my cell phone&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The other four approaches?  They still have their uses in specialized cases, and they're still doing more or less what they were doing in 2015.  None of them turned out to be able to do pretty much everything, nor did any of them turn out to get a lot smarter and more capable when you simply scale them up.  (Indeed, most of them explode when you try to do that.)&lt;/p&gt;

&lt;h2&gt;
  
  
  This was not obvious.
&lt;/h2&gt;

&lt;p&gt;I've considered myself a "connectionist" since middle school, when I did my first neural networks science fair project.  (Fun fact: my junior year of high school, I went to the International Science &amp;amp; Engineering Fair with my novel algorithm for recursive neural networks, and won the U.S. Army's top prize and a 2-week trip to Japan... and I still practice Japanese every day today.)&lt;/p&gt;

&lt;p&gt;But I did not expect neural networks, on their own, to be the master algorithm.  Hardly anyone expected that.  Neural networks were very good at perception (identifying/classifying patterns in raw data), and at prediction (which is really the same thing).  But it was not at all clear how a neural network would ever be able to carry on a real conversation, reason through problems, etc.  I thought you'd probably need some combination of a neural network and symbolic (e.g. inductive) reasoning.&lt;/p&gt;

&lt;p&gt;I mean, of course our own brains are made entirely of neurons.  So as a raw proof of concept, yes, it was obvious that neural networks &lt;em&gt;could&lt;/em&gt; do it all.  But I assumed that evolution had equipped our brains with very specialized circuits for language, logic, &amp;amp; reasoning, and that you would not get these facilities out of a general-purpose neural network running some general-purpose learning algorithm.&lt;/p&gt;

&lt;p&gt;But nope.  It turns out that you do get exactly that.&lt;/p&gt;

&lt;h2&gt;
  
  
  The moment this happened.
&lt;/h2&gt;

&lt;p&gt;In &lt;a href="https://mitpress.mit.edu/9780262049955/what-is-intelligence/" rel="noopener noreferrer"&gt;What Is Intelligence?&lt;/a&gt; (2025), Google AI researcher Blaise Agüera y Arcas writes about the moment that I would consider the pivotal turning point.  They were training a neural network to predict the next word after a bunch of previous words, so that they could make a better autocomplete function.  This is a natural and obvious application of neural networks' strengths, and because people are terrible (and terribly slow) at typing messages on cell phones, better autocomplete was worth investing in.&lt;/p&gt;

&lt;p&gt;But they had trained a very &lt;em&gt;large&lt;/em&gt; model.  On a very large amount of text.  And the model started talking to them.  They discovered that they could ask it questions, and it would answer.  The could even ask it things that had certainly never been in its training data — like, how to translate a specific made-up sentence from one language to another — and, with a bit of urging, it would do it, and do it correctly.&lt;/p&gt;

&lt;p&gt;I can only imagine the complex emotions they must have felt at that moment.  They realized what some deniers still haven't understood today: a sufficiently deep language model isn't just parroting its training data; it is &lt;em&gt;understanding&lt;/em&gt; and responding with real intelligence.&lt;/p&gt;

&lt;p&gt;Now, a raw language model, without additional reinforcement learning to shape its behavior, is rather schizophrenic; it slips in and out of different personalities, carries on both halves of a conversation all by itself, etc.  Few people get to interact with a network in this state, because (as Agüera y Arcas explains) it is quite disturbing.  But the behavioral training fixes that, improves reasoning skills, and gives us the AI coworkers we use daily today.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prediction, all the way down
&lt;/h2&gt;

&lt;p&gt;So how is this possible?  How &lt;em&gt;does&lt;/em&gt; a neural network act as the master algorithm?&lt;/p&gt;

&lt;p&gt;It turns out, intelligence is fundamentally just prediction.  It's prediction at all levels: cortical columns predict what their next inputs are going to be; our visual system learns to predict what the world is going to look like in the next moment; our language system learns to predict the next word we are going to hear or say.  In a literal sense, LLMs like Claude do nothing but predict the next token, based on all the tokens in the session so far.&lt;/p&gt;

&lt;p&gt;But prediction is all you need.  When Claude generates a string of tokens working through a problem, it is not fundamentally different from the string of thoughts (mostly in the form of words) that you and I would generate working through a similar problem.  Reinforcement learning biases the network so that these strings of predictions tend to go in &lt;em&gt;useful&lt;/em&gt; directions, ones that were successful during training.  In humans (unlike current LLMs), training is an ongoing process, so we are constantly tweaking our own neural networks to make these trains of predictions more successful.  But fundamentally, moment to moment, it's still just predicting the next thing, at every level of the network.&lt;/p&gt;

&lt;p&gt;We now understand that some problems are what Agüera y Arcas calls &lt;strong&gt;AI complete&lt;/strong&gt;.  Solving an AI complete problem requires actually understanding the world that the problem represents; no shallower, surface-features sort of representation can do it.  Examples of AI complete problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Next word prediction: it's impossible to predict the next word in a string of text with any accuracy unless you understand what those words actually mean.&lt;/li&gt;
&lt;li&gt;Language translation: ditto; you can't just look up individual words in a dictionary.&lt;/li&gt;
&lt;li&gt;Video next-frame prediction: requires understanding what the objects in the video are, how they behave, what gravity does, etc.&lt;/li&gt;
&lt;li&gt;Picture or video captioning: requires understanding both what the objects are, and how they are referred to in language.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A sufficiently big neural network, given sufficient training data, will eventually solve almost any problem you give it.  So if you give it an AI complete problem, which can only be solved by understanding the world... it will understand the world.&lt;/p&gt;

&lt;p&gt;Is its understanding perfect?  Of course not.  But then, that's &lt;a href="https://spyscape.com/article/illuminati-qanon-lizard-people-and-other-conspiracy-theories" rel="noopener noreferrer"&gt;true of humans&lt;/a&gt;, too.&lt;/p&gt;

&lt;h2&gt;
  
  
  So that's it for AI research
&lt;/h2&gt;

&lt;p&gt;Haha, just kidding!  LLMs are &lt;a href="https://www.noemamag.com/artificial-general-intelligence-is-already-here/" rel="noopener noreferrer"&gt;general intelligence&lt;/a&gt;, and already &lt;a href="https://scitechdaily.com/for-the-first-time-chatgpt-has-solved-an-unproven-math-problem-in-geometry/" rel="noopener noreferrer"&gt;smarter than humans&lt;/a&gt; in some ways.  But they have glaring limitations: in particular, "training" and "inference" are completely separated processes.  The LLMs we use every day do not learn from experience, except insofar as that experience can be crammed into the context window.  &lt;/p&gt;

&lt;p&gt;The addition of &lt;a href="https://cameronrwolfe.substack.com/p/rl-continual-learning" rel="noopener noreferrer"&gt;continual learning&lt;/a&gt; will allow them to get better at tasks with practice, just like we do.  But there are a lot of tricky open questions: how do you avoid forgetting too much old knowledge while acquiring new knowledge?  How do you keep the AI's personality stable over time?  And how do you even learn this new stuff quickly enough to matter?&lt;/p&gt;

&lt;p&gt;Moreover, there really &lt;em&gt;are&lt;/em&gt; things that neural networks are terrible at.  And ironically, those are exactly the things that most AI research has been doing for the last 80 years: game playing, deep search, complex logical reasoning, optimization, etc.  We (and other neural networks) can &lt;em&gt;approximately&lt;/em&gt; do those things, with a lot of training and practice, but there are classical (GOFAI or "Good Old-Fashioned AI") algorithms that do them much better and faster.  We'll continue to need progress on these, and on ways to integrate them with neural networks to get the best of both worlds.&lt;/p&gt;

&lt;p&gt;This is just a random sampling; in fact there are many, many open research directions.  We've cracked the code of intelligence; we know now what intelligence &lt;em&gt;is&lt;/em&gt; and how to produce it in a machine.  But that's only the tip of the iceberg.  It is the beginning of wisdom, not the end.&lt;/p&gt;

&lt;p&gt;The next 5 or 10 years are going to be very exciting.  Hold on tight!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>discuss</category>
      <category>science</category>
    </item>
    <item>
      <title>MiniScript Weekly News — Apr 1, 2026</title>
      <dc:creator>JoeStrout</dc:creator>
      <pubDate>Thu, 02 Apr 2026 00:36:09 +0000</pubDate>
      <link>https://dev.to/joestrout/miniscript-weekly-news-apr-1-2026-7b1</link>
      <guid>https://dev.to/joestrout/miniscript-weekly-news-apr-1-2026-7b1</guid>
      <description>&lt;h2&gt;
  
  
  Development Updates
&lt;/h2&gt;

&lt;p&gt;Work on &lt;strong&gt;MiniScript 2&lt;/strong&gt; continues to pick up speed, and the team shared that a working &lt;strong&gt;REPL&lt;/strong&gt; is now in place in both C# and C++. The latest dev log also mentions a refactor to better preserve globals across REPL entries, plus a fix for multi-function REPL handling and Ctrl-D to exit.&lt;br&gt;&lt;br&gt;
GitHub: &lt;a href="https://github.com/JoeStrout/miniscript2" rel="noopener noreferrer"&gt;miniscript2&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the &lt;strong&gt;raylib-miniscript&lt;/strong&gt; side, there were a few useful updates landed this week: &lt;code&gt;resourceCounts&lt;/code&gt; now reports loaded resources, &lt;code&gt;FileHandle&lt;/code&gt; was added, and the text mutation intrinsics were refreshed with new &lt;code&gt;...Alloc&lt;/code&gt; variants. These changes should help with debugging leaks and keeping the bindings in step with newer raylib APIs.  &lt;/p&gt;

&lt;p&gt;An important change this week: raylib-miniscript now requires scripts to call &lt;code&gt;rl.InitWindow&lt;/code&gt; themselves instead of the engine doing it behind the scenes. Joe also added a direct MiniScript translation of the raylib high-DPI demo, which should make window setup clearer for developers who want to support high-res displays like the Apple Retina or MacBook display.&lt;br&gt;
GitHub: &lt;a href="https://github.com/JoeStrout/raylib-miniscript" rel="noopener noreferrer"&gt;raylib-miniscript&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Community Projects
&lt;/h2&gt;

&lt;p&gt;Joe shared a fresh tutorial on Dev.to: &lt;strong&gt;&lt;a href="https://dev.to/joestrout/create-a-maze-game-in-mini-micro-4j32"&gt;Create a Maze Game in Mini Micro&lt;/a&gt;&lt;/strong&gt;. It walks through turning the built-in maze demo into a custom game, and it’s a great example of how approachable Mini Micro development can be for new creators.&lt;/p&gt;

&lt;p&gt;Also in the Mini Micro ecosystem, &lt;strong&gt;Dat_One_Dev&lt;/strong&gt; highlighted the possibility of listing Mini Micro, Soda, and the upcoming Raylib project on a game-distribution site so community-made games can be more discoverable. That came up in the context of showcasing user projects like &lt;strong&gt;SPACE EVADERS&lt;/strong&gt; by community member DSlower — always exciting to see MiniScript games getting attention.&lt;/p&gt;

&lt;h2&gt;
  
  
  Discussion Highlights
&lt;/h2&gt;

&lt;p&gt;There was a lively MiniScript 2 design discussion about language minimalism, type hints, and the role of &lt;code&gt;@&lt;/code&gt; in function references. Joe reaffirmed the project’s “mini” philosophy while also noting that assertions can already help catch errors today, and might even inform future optimizations.  But he also outlined a proposal for a more extensive error-handling system based on a new "error" data type, with strict rules about how it interacts with other types.&lt;/p&gt;

&lt;p&gt;The community also brainstormed about broader tooling and extensibility, including ideas for terminal color customization, configurable prompts, and even an eventual FFI-style integration for things like Ollama or other external libraries. Joe’s response was encouraging: it’s a neat direction for “eventually,” though beyond the language core for now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Mini Micro &amp;amp; Raylib Chatter
&lt;/h2&gt;

&lt;p&gt;A few Raylib-related debugging threads were especially productive this week. The team tracked down an HDPI issue to window initialization order, and Joe wrapped up the fix by moving the config flag setup earlier and clarifying that scripts should initialize the window themselves.&lt;/p&gt;

&lt;p&gt;There was also some good old-fashioned collaborative troubleshooting on the breakout demo and audio init behavior, with fixes landing for Windows build issues and asset handling along the way. It’s great to see community members jumping in with bug reports, PRs, and real-world testing.&lt;/p&gt;

&lt;p&gt;Until next week, happy scripting!&lt;/p&gt;

&lt;h2&gt;
  
  
  Upcoming Game Jams
&lt;/h2&gt;

&lt;p&gt;These upcoming jams look like a great fit for Mini Micro:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/pixelforge" rel="noopener noreferrer"&gt;Pixel Forge JAM 2026 [PRIZES]&lt;/a&gt;&lt;/strong&gt; (starts 2026-04-18 07:30:00) — A strong fit for retro, pixel-art, or tile-based ideas, with a 7-day format that encourages fast, creative experimentation and accessible gameplay.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/micro-jam-057" rel="noopener noreferrer"&gt;Micro Jam 057: Symmetry ($400 Prizes)&lt;/a&gt;&lt;/strong&gt; (starts 2026-04-18 01:00:00) — A strong fit for 2D pixel, tile, or text-driven ideas, with the symmetry theme inviting clever puzzle, action, or visual-design twists and a forgiving jam format that’s easy to jump into.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/smashthefash" rel="noopener noreferrer"&gt;Games Transformed 2026 - 'Smash The Fash' Game Jam&lt;/a&gt;&lt;/strong&gt; — A politically charged jam inviting all kinds of antifascist games, from activist tactics and mutual aid to surreal puzzles and hopeful visions of solidarity, with room for serious, playful, or experimental takes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/reagent-game-jam-2026" rel="noopener noreferrer"&gt;Reagent Game Jam 2026&lt;/a&gt;&lt;/strong&gt; (starts 2026-04-10 07:00:00) — An accessible beginner-friendly jam with lots of freedom in tools and style, making it a great chance to build a creative 2D game in a low-pressure setting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/gaminglejam" rel="noopener noreferrer"&gt;GamingleJam&lt;/a&gt;&lt;/strong&gt; (starts 2026-04-10 17:14:37) — A low-pressure, any-engine jam that encourages collaboration and welcomes solo creators too, making it a great excuse to build a stylish 2D game and maybe team up with artists, musicians, or writers along the way.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/avantbeetles-protest-games-jam" rel="noopener noreferrer"&gt;AvantBeetle's Protest Games Jam&lt;/a&gt;&lt;/strong&gt; (starts 2026-04-04 04:00:00) — An open-ended protest-themed jam that welcomes experimental, symbolic, and small-scale games, making it a great chance to turn a strong message into a creative playable statement.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>miniscript</category>
      <category>minimicro</category>
      <category>news</category>
    </item>
    <item>
      <title>Create a Maze Game in Mini Micro</title>
      <dc:creator>JoeStrout</dc:creator>
      <pubDate>Wed, 01 Apr 2026 18:17:19 +0000</pubDate>
      <link>https://dev.to/joestrout/create-a-maze-game-in-mini-micro-4j32</link>
      <guid>https://dev.to/joestrout/create-a-maze-game-in-mini-micro-4j32</guid>
      <description>&lt;p&gt;In the classic arcade days, there were a lot of maze games.  That's because mazes are &lt;em&gt;fun!&lt;/em&gt;  They give the player interesting choices at every point, and force you to look and plan globally while also paying attention to local hazards and opportunities.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9z79nqu3difu85jnh1q0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9z79nqu3difu85jnh1q0.png" alt="Maze game screen shots" width="800" height="781"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Clockwise from top left: Pac-Man (1980), Wizard of Wor (1980), Nibbler (1982), Mouse Trap (1981).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You don't see this as much in modern games.  A 3D shooter or adventure game might be in a maze, but with a first-person view, you miss out on that global planning because you can only see what's directly in front of you.&lt;/p&gt;

&lt;p&gt;All of which is to say, &lt;strong&gt;people should make more maze games.&lt;/strong&gt;  And &lt;a href="https://miniscript.org/MiniMicro" rel="noopener noreferrer"&gt;Mini Micro&lt;/a&gt; is a great environment for making them.  Let's make one right now!&lt;/p&gt;
&lt;h2&gt;
  
  
  Start with the maze demo
&lt;/h2&gt;

&lt;p&gt;Mini Micro has a handy demo of displaying and editing a maze at &lt;code&gt;/sys/demo/maze&lt;/code&gt;.  Start by running that.  You can run it online &lt;a href="https://miniscript.org/MiniMicro/index.html?cmd=run%20%22%2Fsys%2Fdemo%2Fmaze%22" rel="noopener noreferrer"&gt;here&lt;/a&gt;, but better to &lt;a href="https://miniscript.org/MiniMicro/index.html#download" rel="noopener noreferrer"&gt;download&lt;/a&gt; Mini Micro if you don't have it already, and then just type &lt;code&gt;run "/sys/demo/maze"&lt;/code&gt; and press Enter.  The demo looks like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs7kxovlmfxg83oxjvrgx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs7kxovlmfxg83oxjvrgx.png" alt="Screen shot of /sys/demo/maze in Mini Micro" width="800" height="601"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can click and drag with the mouse to edit the maze.  It's important to understand that you're adding and deleting &lt;em&gt;wall corners&lt;/em&gt;, not walls or rooms.  These are the intersections of two (potential or actual) walls &lt;em&gt;between&lt;/em&gt; rooms.&lt;/p&gt;

&lt;p&gt;An important thing to understand is how what you see relates to the actual &lt;a href="https://miniscript.org/wiki/TileDisplay" rel="noopener noreferrer"&gt;TileDisplay&lt;/a&gt; creating it.  The best way to get that understanding is to press G in the demo, which toggles a visible grid (by shrinking the cells and spacing them out slightly).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj1tlypp099h92yu5n15q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj1tlypp099h92yu5n15q.png" alt="Screen shot of image with grid" width="514" height="364"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These are Wang 2-corner tiles, which are explained in &lt;a href="https://dev.to/joestrout/wang-2-corner-tiles-544k"&gt;this post&lt;/a&gt;, so I won't go into detail here.  But they're very neat and easy once you get the hang of them.&lt;/p&gt;
&lt;h2&gt;
  
  
  Start your program!
&lt;/h2&gt;

&lt;p&gt;Now let's leverage the code in this demo to make our own maze game.  If you were running the demo on the web, now you really should &lt;a href="https://miniscript.org/MiniMicro/index.html#download" rel="noopener noreferrer"&gt;download&lt;/a&gt; it so that you can save your work.&lt;/p&gt;

&lt;p&gt;We're going to use the &lt;em&gt;build a little, test a little&lt;/em&gt; approach here, building up the program bit by bit.  This is a great habit to have in all your coding; it's much easier and more successful than trying to write out an entire program at once.&lt;/p&gt;

&lt;p&gt;So if you're still in the demo, exit out of it by pressing &lt;code&gt;Esc&lt;/code&gt;, then type &lt;code&gt;clear&lt;/code&gt; and &lt;code&gt;reset&lt;/code&gt; to clear the screen and program.  Then &lt;code&gt;edit&lt;/code&gt;, and type or paste in this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;clear

if env.importPaths.indexOf("/sys/demo") == null then
    env.importPaths.push "/sys/demo"
end if
import "maze"

maze.generate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This clears the screen, and then checks whether our import paths already include "/sys/demo".  That's not normally a directory that &lt;code&gt;import&lt;/code&gt; searches, but it's where &lt;code&gt;maze.ms&lt;/code&gt; lives, so we need it to check there.  Then we &lt;code&gt;import "maze"&lt;/code&gt;, which loads the code from maze.ms into a map called &lt;code&gt;maze&lt;/code&gt; in our program.  Finally, we call &lt;code&gt;maze.generate&lt;/code&gt; to make and display a random maze, just like the demo.&lt;/p&gt;

&lt;p&gt;Save this program (I called mine "mouseMaze", for reasons that will become apparent), and then run it.  You should see a maze appear.&lt;/p&gt;

&lt;h2&gt;
  
  
  Customize the maze
&lt;/h2&gt;

&lt;p&gt;The maze generated so far is a "pure" maze, i.e., one with exactly one path between any two points.  That's not actually much fun to play in; we want the player to have choices.  You could manually edit your maze layout, save it to disk in some way, and load it into your game; this would be most similar to what the classic games above did.  But for now, let's just knock out a random selection of walls.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tiles = maze.tiles
cellSize = tiles.cellSize
extent = tiles.extent
maxCol = (extent[0] / 2) - 1
maxRow = (extent[1] / 2) - 1
tiles.setCellTint range(extent[0]-1), range(extent[1]-1), "#44FF44"

// Delete some extra walls so it's not a "pure" maze
for i in range(20)
    room = maze.rooms[rnd*maze.Room.cols][rnd*maze.Room.rows]
    if rnd &amp;lt; 0.5 then wall = "north" else wall = "east"
    room[wall] = false
end for
maze.setCornersFromRooms
maze.updateTiles
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;edit&lt;/code&gt; your program and add the above code, below what you wrote before.  This code begins by copying &lt;code&gt;maze.tiles&lt;/code&gt; into a &lt;code&gt;tiles&lt;/code&gt; variable, just to make it easier to refer to.  Then we also copy &lt;code&gt;cellSize&lt;/code&gt; and &lt;code&gt;extent&lt;/code&gt; out of that.  We also compute the &lt;code&gt;maxRow&lt;/code&gt; and &lt;code&gt;maxCol&lt;/code&gt; of rooms (rooms are the little spaces between the walls — there are only half as many rooms as walls in any direction).  Then we use &lt;code&gt;tiles.setCellTint&lt;/code&gt; to color the maze green.&lt;/p&gt;

&lt;p&gt;Then, the &lt;code&gt;for&lt;/code&gt; loop repeatedly selects a random room, and sets either the north or east wall to &lt;code&gt;false&lt;/code&gt;, removing it.  The code in maze.ms defines rooms this way, each room only responsible for the walls to its north and east side.  How would you be expected to know this?  Why, by reading the maze.ms code, of course!  (Or by reading this blog post.)&lt;/p&gt;

&lt;p&gt;Once the rooms have been edited, we call &lt;code&gt;maze.setCornersFromRooms&lt;/code&gt; and &lt;code&gt;maze.updateTiles&lt;/code&gt; to update the actual display on screen.&lt;/p&gt;

&lt;p&gt;Run the program again, and you should see a green maze with extra missing walls (sometimes even producing a dot, where a corner isn't attached to any walls at all).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foanf6ykye8ud7orm0igh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foanf6ykye8ud7orm0igh.png" alt="Screen shot of program result at this point" width="800" height="530"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a MazeSprite class
&lt;/h2&gt;

&lt;p&gt;Now to make this maze into a game, we need some sprites to move around in it.  And we want those things to move only in valid ways, i.e. not through walls.  We'll use the same Room data structure that the maze demo already defined for creating the maze, to determine where sprites can move.&lt;/p&gt;

&lt;p&gt;So, &lt;code&gt;edit&lt;/code&gt; your program again, and append this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MazeSprite = new Sprite
MazeSprite.col = 0
MazeSprite.row = 0
MazeSprite.goToRoom = function(roomCol, roomRow)
    self.col = roomCol; self.row = roomRow
    self.x = cellSize * (roomCol * 2 + 1)
    self.y = cellSize * (roomRow * 2 + 1)
end function

MazeSprite.canMove = function(dx, dy)
    col = self.col; row = self.row
    if dx and dy then return false
    if not 0 &amp;lt;= round(col + dx) &amp;lt;= maxCol then return false
    if not 0 &amp;lt;= round(row + dy) &amp;lt;= maxRow then return false
    if dx &amp;lt; 0 then return not maze.rooms[self.col-1][self.row].east
    if dx &amp;gt; 0 then return not maze.rooms[self.col][self.row].east
    if dy &amp;lt; 0 then return not maze.rooms[self.col][self.row-1].north
    if dy &amp;gt; 0 then return not maze.rooms[self.col][self.row].north
end function

MazeSprite.move = function(dx, dy)
    if not self.canMove(dx, dy) then return
    col = self.col; row = self.row
    for t in range(0, 1, 0.1)
        self.goToRoom col + dx*t, row + dy*t
        yield
    end for
    self.goToRoom round(self.col), round(self.row)
end function
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a Sprite subclass called MazeSprite.  A MazeSprite knows what room column and row it's in, and in the &lt;code&gt;goToRoom&lt;/code&gt; method, it also converts those to screen coordinates.  Then there's the &lt;code&gt;canMove&lt;/code&gt; method, which determines whether the sprite can move in a given direction.  This includes bounds checks, as well as checking the appropriate wall.&lt;/p&gt;

&lt;p&gt;Finally, we have a &lt;code&gt;move&lt;/code&gt; method that, if the sprite is able to move in the given direction at all, does so smoothly over 10 frames.  (In a full game you might need a fancier approach that does not block the rest of the game while moving -- but for today's game, there is only one sprite moving at a time, so this works fine.)&lt;/p&gt;

&lt;p&gt;You can run your program again at this point, just to ensure you haven't made any typos.  But if everything is good, it won't look any different from before.  We've defined the MazeSprite class, but we're not actually doing anything with it yet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add the sprites
&lt;/h2&gt;

&lt;p&gt;It's time to add our characters to the maze!  I chose to make my game about a mouse questing for cheese, but feel free to explore the pictures available in /sys/pics and make it a bunny chasing carrots, or whatever you like.  (The &lt;code&gt;findFile&lt;/code&gt; command is a great way to explore!)&lt;/p&gt;

&lt;p&gt;So &lt;code&gt;edit&lt;/code&gt; your program again, and add this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;player = new MazeSprite
player.image = file.loadImage("/sys/pics/animals/mouse.png")
player.scale = 1/3
player.goToRoom 0,0
display(4).sprites.push player

cheese = new MazeSprite
cheese.image = file.loadImage("/sys/pics/food/Cheese.png")
cheese.scale = 1/2
cheese.goToRoom round(rnd*maxCol), round(rnd*maxRow)
display(4).sprites.push cheese
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is pretty straightforward: we create a player sprite in room 0,0, and a cheese sprite in some random room.  Both sprites are scaled down in order to fit into the maze.  Run your program now, and you should see these new additions to the game.  But the program still exits immediately to the blinking cursor.&lt;/p&gt;

&lt;h2&gt;
  
  
  The main loop
&lt;/h2&gt;

&lt;p&gt;We're almost done!  Let's just load a sound to play when the mouse gets the cheese, and then add the main loop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gotSound = file.loadSound("/sys/sounds/munch.wav")

while not key.pressed("escape")
    yield
    dx = sign(round(key.axis("Horizontal", false)))
    dy = sign(round(key.axis("Vertical", false)))
    if not dx and not dy then continue
    player.move dx, dy
    if player.row == cheese.row and player.col == cheese.col then
        cheese.goToRoom round(rnd*maxCol), round(rnd*maxRow)
        gotSound.play
    end if
end while
key.clear
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our main loop here is pretty simple.  We start by getting the horizontal (&lt;code&gt;dx&lt;/code&gt;) and vertical (&lt;code&gt;dy&lt;/code&gt;) axis inputs.  Using &lt;code&gt;key.axis&lt;/code&gt; allows the player to use arrow keys, WASD, or even a game pad.  We &lt;code&gt;round&lt;/code&gt; that and take the &lt;code&gt;sign&lt;/code&gt; so that we get clean input values of -1, 0, or 1 for each axis.  And if we don't have any input, we just &lt;code&gt;continue&lt;/code&gt; at the top of the loop (where we included a &lt;code&gt;yield&lt;/code&gt;, as all good main loops do).&lt;/p&gt;

&lt;p&gt;When we &lt;em&gt;do&lt;/em&gt; have an input, then we call &lt;code&gt;player.move&lt;/code&gt;, and then check whether the player is now in the same location as the cheese.  When that's the case, we play the &lt;em&gt;munch&lt;/em&gt; sound and teleport the cheese to a different room.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6fjezubvf5of2qi85pv4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6fjezubvf5of2qi85pv4.png" alt="Screen shot of the final game" width="800" height="536"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try it!&lt;/strong&gt;  It's such a simple game, and yet it is immediately engaging.  You will see how you could build on this in all sorts of ways: make the goal move around, add enemies, add some sort of shooting, provide doors that can open or close or pivot, add sub-goals like visiting every part of the maze, etc.&lt;/p&gt;

&lt;h2&gt;
  
  
  Comments?  Questions?
&lt;/h2&gt;

&lt;p&gt;What was your favorite maze game?  What sort of maze game would you like to see in Mini Micro?  And what's stopping you from creating that game right now?  Share your thoughts in the comments below!&lt;/p&gt;

</description>
      <category>miniscript</category>
      <category>minimicro</category>
      <category>programming</category>
      <category>gamedev</category>
    </item>
    <item>
      <title>Parameter Objects in MiniScript</title>
      <dc:creator>JoeStrout</dc:creator>
      <pubDate>Wed, 25 Mar 2026 15:44:23 +0000</pubDate>
      <link>https://dev.to/joestrout/parameter-objects-in-miniscript-358j</link>
      <guid>https://dev.to/joestrout/parameter-objects-in-miniscript-358j</guid>
      <description>&lt;p&gt;Sometimes a function starts out with a reasonable number of parameters, but as the code grows and more features are added, it ends up with more and more — like &lt;a href="https://miniscript.org/wiki/PixelDisplay.drawImage" rel="noopener noreferrer"&gt;PixelDisplay.drawImage&lt;/a&gt; in &lt;a href="https://miniscript.org/MiniMicro" rel="noopener noreferrer"&gt;Mini Micro&lt;/a&gt;, which has 10 parameters.&lt;/p&gt;

&lt;p&gt;Arguments in a function call in MiniScript are passed by position, not by name, which means that even if some of those parameters are optional, you have to specify all arguments that come before one you actually care about.  And of course you have to remember what order they're in.  (So many times I have typed &lt;code&gt;@gfx.saveImage&lt;/code&gt; at the Mini Micro prompt just to remind myself of the order of the parameters!)&lt;/p&gt;

&lt;p&gt;
  Why not passing parameters by name is a &lt;em&gt;good&lt;/em&gt; thing
  &lt;blockquote&gt;
&lt;p&gt;Languages that support passing parameters by name encourage developers to make functions with &lt;em&gt;lots&lt;/em&gt; of parameters.  And then it will turn out that only certain combinations of those parameters make sense, and the function sprouts pages of parameter-checking logic just to ensure that the user is calling it properly, and more pages of documentation or comments to help them do so.&lt;/p&gt;

&lt;p&gt;This is not just academic; I had to work with &lt;a href="https://github.com/ZettaAI/zetta_utils/blob/1992f681e2ec0bdf324ba54b971a278ef621e936/zetta_utils/layer/volumetric/cloudvol/build.py#L23" rel="noopener noreferrer"&gt;this 25-parameter monster&lt;/a&gt; for a while, and it was a nightmare.&lt;/p&gt;

&lt;p&gt;I have rarely seen any language feature so quickly lead to bad code as named parameters; it may even take the lead from GOTO in this department.&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;
&lt;br&gt;
&lt;br&gt;
&lt;/p&gt;
&lt;br&gt;


&lt;p&gt;What can be done when you find yourself needing more than a handful of parameters?  Or, what if it's only a handful, but you find yourself frequently passing the same values from one function to another (helper methods for example)?  There is a standard solution: the &lt;a href="https://www.innovate.uc.edu/coding/refactorings/introduce-parameter-object/" rel="noopener noreferrer"&gt;&lt;em&gt;Introduce Parameter Object&lt;/em&gt; refactoring&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduce Parameter Object
&lt;/h2&gt;

&lt;p&gt;The idea here is simple: take that big batch of parameters you need, and replace them with a single object containing the same information.&lt;/p&gt;

&lt;p&gt;As an example, the &lt;code&gt;PixelDisplay.drawImage&lt;/code&gt; function looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FUNCTION(self, image, left=0, bottom=0, width=-1, height=-1, srcLeft
=0, srcBottom=0, srcWidth=-1, srcHeight=-1, tint="#FFFFFF")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not counting &lt;code&gt;self&lt;/code&gt; (which is just whatever object comes before the dot when you call it), that's 10 parameters.  You need all 10 if you're going to tint the image, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;img = file.loadImage("/sys/pics/Block.png")
gfx.drawImage img, 500, 200, -1, -1, 0, 0, -1, -1, color.aqua
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(I encourage you to fire up Mini Micro, either locally or &lt;a href="https://miniscript.org/MiniMicro/#playnow" rel="noopener noreferrer"&gt;on the web&lt;/a&gt;, and follow along for yourself.)&lt;/p&gt;

&lt;p&gt;Let's make a parameter-object version of this method.  (In your own code, you could actually replace the original method with the refactored one; but since you can't change the Mini Micro API, let's just make a new method.)  Use the &lt;code&gt;edit&lt;/code&gt; command and enter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import "mapUtil" // for map.get
drawImage = function(params)
    g = params.get("gfx", gfx)
    g.drawImage params.image,
      params.get("left", 0),
      params.get("bottom", 0),
      params.get("width", -1),
      params.get("height", -1),
      params.get("srcLeft", 0),
      params.get("srcBottom", 0),
      params.get("srcWidth", -1),
      params.get("srcHeight", -1),
      params.get("tint", "#FFFFFF")
end function
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Close the editor and &lt;code&gt;run&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
Now we have a &lt;code&gt;drawImage&lt;/code&gt; method that takes a single parameter.  You can call it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;params = {}
params.image = img
params.left = 500
params.bottom = 200
params.tint = color.aqua
drawImage params
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice how this time, we only needed to specify the parameters that differ from the defaults.  We could also call it using a map literal, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;drawImage {"image":img, "left":600, "bottom":200, "tint": color.pink}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That works too.  Either way, the calling code is more clear, and the function interface is simpler.&lt;/p&gt;

&lt;h2&gt;
  
  
  Output Parameters
&lt;/h2&gt;

&lt;p&gt;There's a related pattern that is helpful when you need to (perhaps optionally) provide some extra detail on the result of a function call, and that is to use an &lt;em&gt;output&lt;/em&gt; parameter object.&lt;/p&gt;

&lt;p&gt;To make it more concrete, let's suppose you make a method that loads an image... but you want it to do some extra sanity checks, and report details on what it found to callers who care.  You could write it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import "mapUtil" // for map.get
loadImage = function(path, outResults)
    r = outResults  // (shorthand)
    if r != null then
        r.path = path
        r.size = 0
        r.err = ""
    end if
    info = file.info(path)
    if info == null then
        if r then r.err = "File not found"
        return null
    end if
    if r then r.size = info.size
    directory = file.parent(path)
    name = file.name(path)
    if name[-4:] != ".png" and name[-4:] != ".jpg" then
        if r then r.err = "Path does not end with .png or .jpg"
        return null
    end if
    if file.children(directory).indexOf(name) == null then
        if r then r.err = "Case mismatch"
        return null
    end if
    return file.loadImage(path)
end function
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This &lt;code&gt;loadImage&lt;/code&gt; method takes the path to the function to load, but optionally, it also takes a map into which we will place some details: the path, the file size, and an error string.&lt;/p&gt;

&lt;p&gt;So callers who don't care about the details can just do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;img = loadImage("/sys/pics/Wumpus.png")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;...and they will get back the image or &lt;code&gt;null&lt;/code&gt;, but with no way of knowing why.  More careful callers could instead do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;result = {}
img = loadImage("/sys/pics/Wampus.png", result)
if not img then print "Couldn't load " + result.path +
  " because: " + result.err
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And (because I mistyped the image name) this will print "Couldn't load /sys/pics/Wampus.png because: File not found".&lt;/p&gt;

&lt;p&gt;(We might make use of exactly this pattern in some Mini Micro 2 APIs; see &lt;a href="https://github.com/JoeStrout/MiniMicro2/issues/1" rel="noopener noreferrer"&gt;this feature request&lt;/a&gt;.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't Over Do It!
&lt;/h2&gt;

&lt;p&gt;There are two drawbacks to introducing parameter objects:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;They make calling the function more of a hassle for simple cases.
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;drawImage img&lt;/code&gt; is easier than &lt;code&gt;drawImage {"image":img}&lt;/code&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;They encourage parameter proliferation, just like named parameters.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Don't create beasts with 20 or 30 parameters, even with this refactoring.  Instead consider smaller, more focused methods that do only one thing in one way.  Or at the very least, add wrapper methods that make the common use cases easy.&lt;/p&gt;

&lt;p&gt;But with those caveats in mind, parameter objects (including &lt;em&gt;output&lt;/em&gt; parameter objects) are a powerful tool in your toolbox.  Happy coding!&lt;/p&gt;

</description>
      <category>miniscript</category>
      <category>minimicro</category>
      <category>refactoring</category>
      <category>programming</category>
    </item>
    <item>
      <title>MiniScript Weekly News — March 24, 2026</title>
      <dc:creator>JoeStrout</dc:creator>
      <pubDate>Tue, 24 Mar 2026 21:32:26 +0000</pubDate>
      <link>https://dev.to/joestrout/miniscript-weekly-news-march-24-2026-1jlj</link>
      <guid>https://dev.to/joestrout/miniscript-weekly-news-march-24-2026-1jlj</guid>
      <description>&lt;p&gt;&lt;em&gt;Editor's Note: I've developed an AI agent to help me gather and write this weekly newsletter, keeping you informed while still giving me time to work on things like MiniScript 2.0.  I hope you enjoy it!  -- Joe&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Development Updates
&lt;/h2&gt;

&lt;p&gt;Joe has launched a MiniScript News bot to help gather highlights from GitHub, Discord, forums, itch.io, and more, with the goal of making it easier to follow the growing community. That should be a big help as MiniScript activity spreads across so many places.&lt;/p&gt;

&lt;p&gt;MiniScript 2 continues to move forward with solid progress on performance and language/runtime cleanup. Recent work included adding &lt;code&gt;wait&lt;/code&gt; and &lt;code&gt;yield&lt;/code&gt;, refactoring the intrinsic API toward MiniScript 1 compatibility, committing to insertion-order maps, and making good headway toward a REPL and broader usability: &lt;a href="https://github.com/JoeStrout/miniscript2/blob/main/notes/DEV_LOG.md" rel="noopener noreferrer"&gt;miniScript2 dev log&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;On the Raylib side, &lt;code&gt;raylib-miniscript&lt;/code&gt; picked up several useful upgrades, including &lt;code&gt;run&lt;/code&gt;, improved &lt;code&gt;import&lt;/code&gt; path handling, &lt;code&gt;exit&lt;/code&gt;, more low-level APIs, shader demos, 3D model support, and full API docs. If you’re following the new foundation for Mini Micro 2 / Soda, there’s lots to explore: &lt;a href="https://github.com/JoeStrout/raylib-miniscript" rel="noopener noreferrer"&gt;raylib-miniscript&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Community Projects
&lt;/h2&gt;

&lt;p&gt;Trey Tomes has been sharing a lot of exciting Mini Micro work, including a roguelike/world-generation project, a VS Code extension that can execute MiniScript, and a MiniScript-based Perlin noise library. If you’re building in MiniScript, these are great examples of practical tools and ambitious gameplay systems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/treytomes/miniscript-perlin-noise" rel="noopener noreferrer"&gt;miniScript Perlin Noise&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/treytomes/micro-critters/blob/main/src/World.ms" rel="noopener noreferrer"&gt;micro-critters world demo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/treytomes/micro-hack" rel="noopener noreferrer"&gt;micro-hack&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also from the community, Blanket shared a work-in-progress Mini Micro file manager, with a very sensible warning to back up your files before trying anything risky. It’s always fun to see tools that help make the ecosystem more usable.&lt;/p&gt;

&lt;p&gt;A special shout-out to &lt;strong&gt;lagoon&lt;/strong&gt;, who showed up with a MiniScript-written Lisp implementation, &lt;a href="https://github.com/lattiahirvio/Clojette" rel="noopener noreferrer"&gt;Clojette&lt;/a&gt;. That’s exactly the kind of delightfully unexpected project that makes this community so fun.&lt;/p&gt;

&lt;p&gt;Finally, there were a couple of cool new game jam games in the last week:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dslower.itch.io/march-of-the-zomblez" rel="noopener noreferrer"&gt;March of the Zomblez by DSlower&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bleapew.itch.io/angels-dont-blink" rel="noopener noreferrer"&gt;Angels: Don't Blink by Bleapew&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Discussion Highlights
&lt;/h2&gt;

&lt;p&gt;A big theme this week was input, layout, and UI design. Joe sketched out a promising layout system based on choosing two positioning constraints and using formulas for the rest, and the discussion around it drew a lot of enthusiasm from others who see how useful it could be for both game UI and desktop-style tools.&lt;/p&gt;

&lt;p&gt;There was also a lively thread about MiniScript 2 equality semantics, including the idea of an “approximately equal” operator. The consensus leaned toward keeping that logic in a function rather than baking too much ambiguity into the language, which feels very in the MiniScript spirit.&lt;/p&gt;

&lt;p&gt;On the Mini Micro side, there was a helpful reminder that tight loops need &lt;code&gt;yield&lt;/code&gt;, and a few useful tips for input handling and file creation. Community members kept helping one another troubleshoot, prototype, and think through the best patterns — a great sign of a healthy, collaborative space.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learning &amp;amp; Writing
&lt;/h2&gt;

&lt;p&gt;Kartik Patel published two more chapters of the “Zero To Game Dev” series, introducing Mini Micro and the first line of MiniScript in a beginner-friendly way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/kartik_patel/zero-to-game-dev-understanding-mini-micro-k8p"&gt;Understanding Mini Micro&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/kartik_patel/zero-to-game-dev-first-line-of-code-5efk"&gt;First Line Of Code&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s great to see more approachable learning material appearing for newcomers. Posts like these make MiniScript feel even more welcoming to beginners.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sign-off
&lt;/h2&gt;

&lt;p&gt;Lots of steady progress, lots of creative experiments, and plenty of helpful back-and-forth this week — exactly what makes the MiniScript community special. Thanks to everyone building, testing, sharing, and cheering each other on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Upcoming Game Jams
&lt;/h2&gt;

&lt;p&gt;These upcoming jams look like a great fit for Mini Micro:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/gone-fishing-game-jam" rel="noopener noreferrer"&gt;Gone Fishing Game Jam&lt;/a&gt;&lt;/strong&gt; (starts 2026-03-27 12:00:00) — A flexible, theme-light jam centered on fishing that leaves plenty of room for clever interpretations, from cozy pixel-art outings to quirky text adventures or tabletop-style ideas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/jerbobs-silly-game-jam" rel="noopener noreferrer"&gt;Jerbob's SILLY JAM&lt;/a&gt;&lt;/strong&gt; (starts 2026-03-27 13:00:00) — A free-form chaos jam that celebrates weird, silly, low-budget creativity—perfect for making something absurd, experimental, and charmingly janky.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/aristos-interactive-jam-2" rel="noopener noreferrer"&gt;Aristos Interactive Jam #2&lt;/a&gt;&lt;/strong&gt; (starts 2026-03-27 21:00:00) — A beginner-friendly weekend jam focused on finishing a fun, playable game, with browser play required but no engine restrictions and plenty of freedom to use premade assets or AI support.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/jam-chula-i" rel="noopener noreferrer"&gt;Jam Chula I&lt;/a&gt;&lt;/strong&gt; (starts 2026-04-01 10:01:00) — A creative, inclusive art jam centered on the evocative theme of Hell, with complete freedom in format and plenty of room for stylized 2D games, interactive fiction, or other expressive retro-friendly ideas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/a-century-of-spells-a-fantasy-jam" rel="noopener noreferrer"&gt;A Century of Spells: A Fantasy Jam&lt;/a&gt;&lt;/strong&gt; (starts 2026-03-07 20:00:00) — A thoughtful fantasy jam centered on magic, memory, and the passage of time, with a strong emphasis on emotional storytelling, non-combat spells, and atmospheric worldbuilding.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/mini-jame-gam-53" rel="noopener noreferrer"&gt;Mini Jame Gam #53&lt;/a&gt;&lt;/strong&gt; (starts 2026-04-03 11:00:00) — A beginner-friendly, fully 2D jam with flexible engine rules, a theme-and-special-object twist, and room for quick prototypes makes this a great chance to build something fun, polished, and creative in a short time.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>miniscript</category>
      <category>minimicro</category>
      <category>news</category>
    </item>
    <item>
      <title>MiniScript Roadmap Update (March 2026)</title>
      <dc:creator>JoeStrout</dc:creator>
      <pubDate>Wed, 11 Mar 2026 20:54:08 +0000</pubDate>
      <link>https://dev.to/joestrout/miniscript-roadmap-update-march-2026-41a4</link>
      <guid>https://dev.to/joestrout/miniscript-roadmap-update-march-2026-41a4</guid>
      <description>&lt;p&gt;At the end of 2025, I posted a &lt;a href="https://dev.to/joestrout/miniscript-road-map-for-2026-17mh"&gt;MiniScript Road Map for 2026&lt;/a&gt; (and beyond).  We're now almost one quarter into 2026.  Let's see how it's going!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2a2cb0oc1ff4x5jzfd5f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2a2cb0oc1ff4x5jzfd5f.png" alt="MiniScript chinchilla logo" width="128" height="128"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  MiniScript 2.0
&lt;/h2&gt;

&lt;p&gt;The biggest work planned for this year is MiniScript 2, a complete rewrite of the MiniScript language, focused on performance.  I'm pleased to report that MiniScript 2 is &lt;strong&gt;ahead of schedule&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The goal for the first quarter was "MS2 compiles &amp;amp; runs a subset of MiniScript", while the Q2 (end of June) goal was "MS2 feature complete (whole language implemented)".  We've pretty much achieved the Q2 goal already!  MS2 has an extensive &lt;a href="https://github.com/JoeStrout/miniscript2/blob/main/tests/testSuite.txt" rel="noopener noreferrer"&gt;test suite&lt;/a&gt; that exercise every part of the language, and longer test programs and benchmarks that put it to work in more realistic ways.  We don't yet have &lt;code&gt;import&lt;/code&gt;, but technically that's not part of the language; that's added by host apps (like &lt;a href="https://miniscript.org/MiniMicro" rel="noopener noreferrer"&gt;Mini Micro&lt;/a&gt;.  We have a short list of &lt;a href="https://github.com/JoeStrout/miniscript2/blob/main/notes/LANGUAGE_CHANGES.md" rel="noopener noreferrer"&gt;new language features&lt;/a&gt; and minor changes, all of which are tested and working except for one (doc strings on functions — we're still thinking about whether and how we want that to work).&lt;/p&gt;

&lt;p&gt;But what about performance, you ask?&lt;/p&gt;

&lt;p&gt;Yesterday I ran three benchmarks -- two using iteration and one using recursion (a particularly challenging benchmark for MiniScript 1.x).  I ran them in MiniScript 1 (C++ version), MiniScript 2 (both C# and C++ version), and for comparison's sake, also ran equivalent code in Python and Lua.  Here's the result, with the Y axis representing speed relative to Python.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy8iwh6cu0kfk0o42451u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy8iwh6cu0kfk0o42451u.png" alt="Bar chart showing benchmarks by language" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are a couple important things to note here.  First, the C++ version of MS2 is significantly faster (like 15X faster) than the C# version.  That's how it &lt;em&gt;should&lt;/em&gt; be, since C# is managed code run by a bytecode interpreter, but in MS1, those times were about the same.  (I didn't include a MS1 C# benchmark but trust me, it's always been roughly the same as the C++ version.)&lt;/p&gt;

&lt;p&gt;But this doesn't mean the C# version is slow.  Compare the blue bars (MS2 C#) to the teeny gray bars (MS1 C++).  Even the C# version of MiniScript 2 is much faster than the C++ version of MS1, by a factor of 10.&lt;/p&gt;

&lt;p&gt;Now compare the green bar (the C++ version of MS2) to Python (orange bar).  We are much faster on 2 of 3 tests, and about the same on the third.  Recursion still costs a little more than we'd like, but it now merely drags us down to "about the same speed as Python," which is pretty fast.&lt;/p&gt;

&lt;p&gt;Of course there's Lua over there (red bars), feeling pretty good about itself.  Yes, Lua is fast, especially on recursion tests.  On the iterative benchmarks, we're faster on one, a bit slower on the other.  But we're not done yet!&lt;/p&gt;

&lt;p&gt;I also ran some tests where, instead of starting with MiniScript source code, I used hand-written assembly code.  This tests how fast the VM can go, separate from how good the compiler is at emitting optimized bytecode.  Here are the results for that:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk5tq4em63ftdl5fr8x7p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk5tq4em63ftdl5fr8x7p.png" alt="Bar chart showing asm vs. src" width="800" height="491"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here the bright bars are hand-written assembly, and the darker bars are MiniScript source.  You can see that the hand-written assembly runs faster, by a factor of 2-3.  This reflects the opportunity for improvement we could get just by improving the compiler, entirely separate from the VM.  &lt;em&gt;We've barely begun to do compiler optimizations yet.&lt;/em&gt;  So I think we'll be able to capture much of that potential improvement.&lt;/p&gt;

&lt;p&gt;To summarize: MiniScript 2 is already fast (comparable or better than Python; nearly as fast or faster than Lua).  And I expect it to get faster before 2.0 ships.&lt;/p&gt;

&lt;h2&gt;
  
  
  Raylib-MiniScript
&lt;/h2&gt;

&lt;p&gt;Another goal for the year was a full set of bindings for MiniScript, and not just for the web, but for desktop (and maybe other) platforms too.  Here I am pleased to report that &lt;strong&gt;we are even &lt;em&gt;more&lt;/em&gt; ahead of schedule&lt;/strong&gt;.  This was a goal for the 4th quarter (end of the year), but, well, some of us got excited and it's nearly done!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F22bhovp9j5qfmguvpuph.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F22bhovp9j5qfmguvpuph.gif" alt="Animated gif of raylib-miniscript demo menu" width="480" height="317"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the aid of helpful community members (especially &lt;a href="https://github.com/dcrawl" rel="noopener noreferrer"&gt;Dcrawl&lt;/a&gt;), essentially the entire Raylib library has now been wrapped -- all &lt;a href="https://github.com/JoeStrout/raylib-miniscript/blob/main/API_DOC.md" rel="noopener noreferrer"&gt;736 functions&lt;/a&gt;.  These include support for shaders and even 3D graphics:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fku9ftmz1br45i4zjl28o.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fku9ftmz1br45i4zjl28o.gif" alt="Animated gif of 3D graphics demo" width="508" height="348"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Like &lt;a href="https://github.com/JoeStrout/MSRLWeb" rel="noopener noreferrer"&gt;MSRLWeb&lt;/a&gt;, on which it is based, the new &lt;a href="https://github.com/JoeStrout/raylib-miniscript" rel="noopener noreferrer"&gt;raylib-miniscript&lt;/a&gt; library performs shockingly well.  This despite it being currently built on MiniScript 1.  As soon as possible, we'll shift it over to MiniScript 2, for a substantial boost in performance.&lt;/p&gt;

&lt;p&gt;The raylib-miniscript library is currently available only in source form, and has only seen substantial testing on MacOS and Linux.  Nonetheless, several users are not waiting, but are already writing or porting projects to use it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Soda
&lt;/h2&gt;

&lt;p&gt;I'm among those porting projects to raylib-miniscript; in my case, it's &lt;a href="https://joestrout.itch.io/inversion-institute" rel="noopener noreferrer"&gt;Inversion Institute&lt;/a&gt;, a logic/puzzle game that's been on the back burner since 2023.  To port this Mini Micro game to Raylib, I am writing classes (in MiniScript) that mimic the Mini Micro APIs... in other words, I am (re)writing Soda on the way to updating my game.&lt;/p&gt;

&lt;p&gt;You can find the files for that currently in the Inversion Institute repo, for example &lt;a href="https://github.com/JoeStrout/InversionInstitute/blob/main/rlms/assets/lib/PixelDisplay.ms" rel="noopener noreferrer"&gt;PixelDisplay.ms&lt;/a&gt; and &lt;a href="https://github.com/JoeStrout/InversionInstitute/blob/main/rlms/assets/lib/SpriteDisplay.ms" rel="noopener noreferrer"&gt;SpriteDisplay.ms&lt;/a&gt;.  So, while I originally had no actual intention of starting on the Soda rewrite until MiniScript 2 is done, in fact I'm already writing and testing the code that will end up becoming Soda.&lt;/p&gt;

&lt;h2&gt;
  
  
  So what's next?
&lt;/h2&gt;

&lt;p&gt;The broad 50,000-foot ambitions outlined a couple months ago have largely been reduced to a laundry list of smaller, more specific remaining to-do items:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MiniScript 2:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Further optimize the MiniScript 2 compiler&lt;/li&gt;
&lt;li&gt;Write &lt;strong&gt;moar tests&lt;/strong&gt; and benchmarks to ensure it works properly&lt;/li&gt;
&lt;li&gt;Modify or wrap the internal APIs so that people embedding MiniScript in their C#/C++ apps can easily update to MS2&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Raylib-MiniScript:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;update to a MiniScript 2 backend&lt;/li&gt;
&lt;li&gt;set up build scripts/procedures for Mac/Win/Linux/Web&lt;/li&gt;
&lt;li&gt;publish prebuilt binaries, so users don't have to build it themselves&lt;/li&gt;
&lt;li&gt;improve documentation/examples&lt;/li&gt;
&lt;li&gt;retire MSRLWeb (now superceded by this project)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Soda:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;retire existing SDL code, replace with raylib-miniscript foundation&lt;/li&gt;
&lt;li&gt;get API coverage at or beyond Soda's current status (enabling trivial porting of current Soda apps)&lt;/li&gt;
&lt;li&gt;continue to API parity (or beyond) with Mini Micro&lt;/li&gt;
&lt;li&gt;publish prebuilt binaries&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Mini Micro 2:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;continue the &lt;a href="https://github.com/JoeStrout/minimicro2" rel="noopener noreferrer"&gt;rewrite&lt;/a&gt; once MiniScript 2 is done (and Raylib-MiniScript is using it)&lt;/li&gt;
&lt;li&gt;release for current platforms&lt;/li&gt;
&lt;li&gt;release for new platforms (Raspberry Pi, phones, tablets)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Summoner Game Platform:&lt;/strong&gt;&lt;br&gt;
This one is still at the 50,000-foot level.  It will be built on the technologies above, so... it has to wait.  But while previously I didn't expect to even start on this until 2027, now I think we might see it sooner than that.&lt;/p&gt;

&lt;p&gt;So that's where we are.  I'm really quite excited about how far we've come so far in 2026, and what is now on the near horizon.  What about you?  Which of this stuff are you most looking forward to?  Please leave your comments below!&lt;/p&gt;

</description>
      <category>miniscript</category>
      <category>minimicro</category>
      <category>programming</category>
      <category>roadmap</category>
    </item>
  </channel>
</rss>
