<?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.us-east-2.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>The Mini Micro Desktop GUI</title>
      <dc:creator>JoeStrout</dc:creator>
      <pubDate>Wed, 01 Jul 2026 23:26:19 +0000</pubDate>
      <link>https://dev.to/joestrout/the-mini-micro-desktop-gui-2gbm</link>
      <guid>https://dev.to/joestrout/the-mini-micro-desktop-gui-2gbm</guid>
      <description>&lt;p&gt;&lt;a href="https://dev.toMini%20Micro"&gt;https://miniscript.org/MiniMicro&lt;/a&gt; is a virtual home computer with a primarily command-line interface.  It boots into a prompt with a friendly blinking cursor, where you can type MiniScript commands or code to navigate around the system and get things 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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkkl0g31g44hetavn7502.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkkl0g31g44hetavn7502.png" alt="Screen shot of Mini Micro, freshly booted" width="799" height="639"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But, among the demos in the &lt;code&gt;/sys/demo&lt;/code&gt; directory is a program called &lt;code&gt;desktop&lt;/code&gt;.  You can run it from there like any other demo, or you can use the convenient &lt;code&gt;desktop&lt;/code&gt; function, built right in as one of the globals defined in &lt;code&gt;/sys/startup.ms&lt;/code&gt;.  Just type:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;and Mini Micro will load up the desktop GUI (graphical user interface)!&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fomsowqwmgbzlfzcbrc6e.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fomsowqwmgbzlfzcbrc6e.png" alt="Screen shot of desktop initial state" width="799" height="639"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The initial state has one window open, showing the mounted disks -- in my case that is &lt;code&gt;/sys&lt;/code&gt;, &lt;code&gt;/usr&lt;/code&gt;, and &lt;code&gt;/usr2&lt;/code&gt;.  You can drag the window around by any part of the gray border, except the textured lower-right corner, which stretches the window out.  You can double-click folders to open them in new windows:&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkpnw0nst0on98tlhjll6.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkpnw0nst0on98tlhjll6.png" alt="Screen shot of desktop with several windows open" width="799" height="639"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
  Power-user Tip
  &lt;p&gt;If you hold the Alt/Option key while double-clicking a folder, it will simultaneously open that folder and close the previous window.  This is known as "Tunneling". &lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Scrollbars appear on disk/folder windows, which can be used to scroll around the files therein.  You can double-click some files (for examples, pictures and text files) to preview them with the &lt;code&gt;view&lt;/code&gt; command, or double-click MiniScript files to run them.  The desktop acts as a &lt;a href="https://miniscript.org/wiki/Env.shell" rel="noopener noreferrer"&gt;shell&lt;/a&gt;, so when the program exits normally, the desktop should reappear.  If the program aborts due to an error, or you press Control-C, then you can type &lt;code&gt;exit&lt;/code&gt; to return to the desktop (or just use the &lt;code&gt;desktop&lt;/code&gt; command again).&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;File&lt;/strong&gt; menu has three commands, all functional: &lt;strong&gt;New Window&lt;/strong&gt;, &lt;strong&gt;Close Window&lt;/strong&gt;, and &lt;strong&gt;Exit to Shell&lt;/strong&gt; (which really means, exit to the standard command-line prompt).  &lt;strong&gt;Close Window&lt;/strong&gt; closes the frontmost window; you can also do that from the keyboard by pressing the &lt;code&gt;W&lt;/code&gt; key.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Window&lt;/strong&gt; menu also works, and provides quick access to any of the windows you have open.&lt;/p&gt;

&lt;p&gt;And that's about it.  &lt;code&gt;/sys/demo/desktop&lt;/code&gt; is more of a demo than a fully functional GUI.  But maybe, in Mini Micro 2.0, it could be.&lt;/p&gt;

&lt;h2&gt;
  
  
  A fully functional desktop?
&lt;/h2&gt;

&lt;p&gt;I have big plans for Mini Micro 2.0... probably &lt;em&gt;too&lt;/em&gt; big, if I'm being honest.  But among them is the idea of turning this demo into a proper, full-fledge desktop environment you can actually use to browse and manage your files.  &lt;a href="https://github.com/JoeStrout/minimicro-sysdisk/issues/61" rel="noopener noreferrer"&gt;GitHub issue #61&lt;/a&gt; is all about this possibility, which would include ways to move/rename files, desk accessories you could add to or replace yourself, etc.&lt;/p&gt;

&lt;p&gt;But what do you think?  Is this worth spending time on, or would you rather use the command line anyway?  And if you do want to spend significant time in the desktop environment, what features are most important to you?&lt;/p&gt;

&lt;p&gt;Let us know in the comments below, or chime in on &lt;a href="https://github.com/JoeStrout/minimicro-sysdisk/issues/61" rel="noopener noreferrer"&gt;on GitHub&lt;/a&gt;.  I can't wait to hear your thoughts!&lt;/p&gt;

</description>
      <category>miniscript</category>
      <category>minimicro</category>
      <category>programming</category>
      <category>gui</category>
    </item>
    <item>
      <title>MiniScript Weekly News — June 25, 2026</title>
      <dc:creator>JoeStrout</dc:creator>
      <pubDate>Thu, 25 Jun 2026 20:50:45 +0000</pubDate>
      <link>https://dev.to/joestrout/miniscript-weekly-news-june-25-2026-3ghh</link>
      <guid>https://dev.to/joestrout/miniscript-weekly-news-june-25-2026-3ghh</guid>
      <description>&lt;h2&gt;
  
  
  Development Updates
&lt;/h2&gt;

&lt;p&gt;MiniScript 2 kept moving fast this week, with Preview 5 now available: &lt;a href="https://github.com/JoeStrout/miniscript2/releases/tag/v2.0-preview-5" rel="noopener noreferrer"&gt;https://github.com/JoeStrout/miniscript2/releases/tag/v2.0-preview-5&lt;/a&gt;. Joe has been polishing error handling, tightening up stack traces, and adding a &lt;code&gt;key&lt;/code&gt; module for console input along the way. If you’ve been testing the previews, now’s a great time to keep poking at edge cases and reporting what you find.&lt;/p&gt;

&lt;p&gt;A big performance highlight landed with &lt;strong&gt;computed lists&lt;/strong&gt;, which make things like &lt;code&gt;range(...)&lt;/code&gt; and list repetition much faster without changing how they behave in normal code. Joe also wrote up the idea in a new Dev.to post: &lt;a href="https://dev.to/joestrout/computed-lists-in-miniscript-2-j4"&gt;Computed Lists in MiniScript 2&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;key&lt;/code&gt; module has landed for console apps too, with &lt;code&gt;.available&lt;/code&gt; and &lt;code&gt;.get&lt;/code&gt; mimicking their behavior in Mini Micro. That should open the door for more interactive command-line MiniScript tools and games.&lt;/p&gt;

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

&lt;p&gt;Congratulations to &lt;strong&gt;Venti&lt;/strong&gt; for shipping a tutorial update to their game, &lt;strong&gt;&lt;a href="https://store.steampowered.com/app/3681230/Observe/" rel="noopener noreferrer"&gt;Observe&lt;/a&gt;&lt;/strong&gt;. It now teaches MiniScript in-game, which is a fantastic way to bring new players into the community while showing off what can be built with the language.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;maho_citrus&lt;/strong&gt; shared &lt;strong&gt;&lt;a href="https://github.com/mahocitrus/Regicide.ms-unofficial" rel="noopener noreferrer"&gt;Regicide.ms-unofficial&lt;/a&gt;&lt;/strong&gt;, a MiniScript take on the card game Regicide. Joe immediately recognized it as a neat find and even suggested a Mini Micro GUI version—great encouragement all around.&lt;/p&gt;

&lt;h2&gt;
  
  
  Show and Tell
&lt;/h2&gt;

&lt;p&gt;In &lt;code&gt;#mini-micro&lt;/code&gt;, &lt;strong&gt;Trey Tomes&lt;/strong&gt; showed off progress on his SVG renderer, which now handles the &lt;code&gt;&amp;lt;animate&amp;gt;&lt;/code&gt; tag: &lt;a href="https://github.com/treytomes/micro-svg/blob/main/demo/constellation2.svg" rel="noopener noreferrer"&gt;demo/constellation2.svg&lt;/a&gt;. It’s a lovely example of experimentation leading to something genuinely useful and expressive.&lt;/p&gt;

&lt;p&gt;Meanwhile &lt;strong&gt;shellrider&lt;/strong&gt; has been pushing on 3D rendering experiments, adding a z-buffer and intersecting triangles. Joe chimed in with encouragement and a bit of nostalgia about older software renderers, which feels very on-brand for this community.&lt;/p&gt;

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

&lt;p&gt;There was a lively thread around the new MiniScript 2 previews, including testing on Windows and Linux, stack traces, ANSI terminal behavior, and consistency across builds. Community testing quickly found and helped fix a few early crashes, which is exactly the kind of collaboration that makes preview releases so valuable.&lt;/p&gt;

&lt;p&gt;Joe also shared that MiniScript 2 is coming along well for embedding, but he’s recommending a little patience before others start integrating it heavily. In the meantime, he’s working toward a smoother path for raylib-miniscript and other targets, including better build support and more portable tooling.&lt;/p&gt;




&lt;p&gt;Thanks for reading, and thanks to everyone sharing code, tests, ideas, and projects. 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/the-52-card-pickup-jam-1" rel="noopener noreferrer"&gt;The 52 Card Pickup Jam #1&lt;/a&gt;&lt;/strong&gt; (starts 2026-06-29 11:00:00) — A perfect excuse to build a stylish card game or clever twist on classic decks, with plenty of room for polished visuals, sound, and inventive mechanics.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/killyourdarlingsno1" rel="noopener noreferrer"&gt;KILL YOUR DARLINGS Mini Jam No. 1&lt;/a&gt;&lt;/strong&gt; (starts 2026-06-26 05:01:00) — A perfect anti-scope-creep jam that celebrates tiny, finished, weirdly personal projects over polish—ideal for making something bold, simple, and delightfully unexpected in just three days.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/8gameaweek" rel="noopener noreferrer"&gt;One Game A Week Jam #8&lt;/a&gt;&lt;/strong&gt; (starts 2026-06-29 16:00:00) — A fast, small-scope jam built around clever puzzle design and unusual weekly prompts, perfect for making a polished retro-style brainteaser with a striking mirror-and-path twist.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/mini-jame-gam-56" rel="noopener noreferrer"&gt;Mini Jame Gam #56&lt;/a&gt;&lt;/strong&gt; (starts 2026-06-26 11:00:00) — A beginner-friendly jam with a flexible theme, a required special object, and a short prototype-friendly format makes this a great place to build something creative, polished, and fun.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/fake-update-jam" rel="noopener noreferrer"&gt;Fake Update Jam&lt;/a&gt;&lt;/strong&gt; (starts 2026-06-29 11:00:00) — A delightfully meta jam where the game itself can pretend to boot, patch, glitch, and rewrite its own rules—perfect for inventive UI tricks, fake system screens, and story-driven surprises.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>miniscript</category>
      <category>minimicro</category>
      <category>programming</category>
      <category>news</category>
    </item>
    <item>
      <title>Computed Lists in MiniScript 2</title>
      <dc:creator>JoeStrout</dc:creator>
      <pubDate>Wed, 24 Jun 2026 22:39:19 +0000</pubDate>
      <link>https://dev.to/joestrout/computed-lists-in-miniscript-2-j4</link>
      <guid>https://dev.to/joestrout/computed-lists-in-miniscript-2-j4</guid>
      <description>&lt;p&gt;Progress on MiniScript 2 has been rapid lately, and it's now in the "final polish" stage.  Today that included adding a cool new feature, an optimization that many users will never consciously notice, but which will be quietly improving things in almost every MiniScript program.  This feature is &lt;em&gt;computed lists.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Computed What, Now?
&lt;/h2&gt;

&lt;p&gt;Here's the issue we set out to solve: a &lt;code&gt;for&lt;/code&gt; loop in MiniScript must iterate over a list, string, or map; and very often, that's a list that comes from the &lt;code&gt;range&lt;/code&gt; function.  Here's a typical example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nb"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;
&lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That &lt;code&gt;range&lt;/code&gt; function, until today, would allocate a million-and-one-element list and store the numbers from 1 million down to zero in it, just so we can assign each number to &lt;code&gt;i&lt;/code&gt; in turn.  And then it would release that list, to be garbage collected at some point.  This is a lot of extra work that we really didn't need to do.  Instead of storing all those numbers, we could instead just store the information we need to compute any element on demand.  This saves a ton of allocation and deallocation, and in many cases (like when you bail out of your loop early) it saves computation too.&lt;/p&gt;

&lt;p&gt;Python faced the same problem, and chose (starting with Python 3.0) to make &lt;code&gt;range&lt;/code&gt; return an &lt;em&gt;iterable&lt;/em&gt; rather than a list.  That's fine for cases like the above, but in cases where you actually needed a list, you have to cast it through the &lt;code&gt;list()&lt;/code&gt; function to get one.  This is a gotcha that everybody trips over initially, and just extra noise in the code even once you're used to it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Our Solution: Computed List
&lt;/h2&gt;

&lt;p&gt;For MiniScript 2, we have chosen a different solution: a list may, under the hood, be a &lt;em&gt;computed&lt;/em&gt; list.  Rather than storing individual values, a computed list stores just three: the base, the step, and the count.  But unlike Python, this is completely transparent to your code; it is still a real list, and may be used exactly like any other list.&lt;/p&gt;

&lt;p&gt;So now when you run the code above in MiniScript 2, it no longer allocates and precomputes over a million elements.  Instead it allocates space for just 3 elements.  But it &lt;em&gt;acts&lt;/em&gt; like it has a million and one elements, in every way (unless you use the &lt;code&gt;info&lt;/code&gt; intrinsic to peek at its &lt;em&gt;computed&lt;/em&gt; flag).&lt;/p&gt;

&lt;p&gt;You get such a computed list, currently, in two ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The &lt;code&gt;range&lt;/code&gt; function always returns a computed list.&lt;/li&gt;
&lt;li&gt;List replication, i.e. &lt;code&gt;[x] * n&lt;/code&gt;, returns a computed list if &lt;code&gt;x&lt;/code&gt; is any immutable value and &lt;code&gt;n&lt;/code&gt; is an integer.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What Stays Computed
&lt;/h2&gt;

&lt;p&gt;There are lots of things you can do with a computed list that leave the list in computed form, and just calculate the answer (very quickly).  If &lt;code&gt;foo&lt;/code&gt; is such a list, then all of these work directly on the computed data:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;foo.len&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;foo[i]&lt;/code&gt; for any index &lt;code&gt;i&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;foo[i:j]&lt;/code&gt; slicing from &lt;code&gt;i&lt;/code&gt; up to &lt;code&gt;j&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;foo.pop&lt;/code&gt; (yes, it mutates the computed list!)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;foo.sum&lt;/code&gt; and other non-mutating intrinsics&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;freeze foo&lt;/code&gt; (making it into a &lt;em&gt;frozen&lt;/em&gt; computed list)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That loop above could have been written as simply &lt;code&gt;range(1000000).sum&lt;/code&gt;, and it very quickly computes the right answer, without ever allocating a million-element list.&lt;/p&gt;

&lt;h2&gt;
  
  
  When It Can't Stay Computed
&lt;/h2&gt;

&lt;p&gt;However, unless you freeze the list, it's still a mutable object and you can change its contents.  This generally requires "materializing" the list, i.e., at this point MiniScript goes ahead and allocates as much space as needed to hold all the values.  (The exception to this rule is &lt;code&gt;pop&lt;/code&gt;, which keeps it computed and merely reduces the count.)  So, any of these operations will materialize the list:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;foo.push x&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;foo.remove i&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;foo.insert i, x&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;foo[i] = x&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;foo.sort&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At this point you lose the benefit of having a computed list, but that's OK.  You're no worse off than we were yesterday, when we didn't have computed lists at all.  And critically, &lt;em&gt;you don't have to think about this.&lt;/em&gt;  You ask for a list, you get a list, MiniScript keeps it computed when it can and materializes it when it must.  Everything just works.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance
&lt;/h2&gt;

&lt;p&gt;We built some benchmarks to measure code that relies heavily on big lists without mutating them, as well as code that does need to mutate them (and so can't take advantage of computed lists).  This new feature brought about a 100X speedup in the first case, and had no measurable impact on the second.&lt;/p&gt;

&lt;p&gt;Of course the improvement will depend greatly on the details of what the code is doing, but the key point is, as expected, this is an overall win.  Not only do we avoid allocating and deallocating big hunks of RAM, but also a computed list (which is only 3 elements) fits comfortably into all levels of the memory cache hierarchy, unlike bigger lists.  Cache misses are a major bottleneck in a lot of compute-heavy code, so this optimization wins both ways.&lt;/p&gt;

&lt;h2&gt;
  
  
  Life is Good
&lt;/h2&gt;

&lt;p&gt;I'm proud of this solution because it gives us enormous benefits in cases that were needlessly slow before, but doesn't require the user to learn or remember anything new.  I mean, I just told you all about it, but that was for sheer "Gee Whiz"-ism — nobody &lt;em&gt;needs&lt;/em&gt; to understand what you now know!&lt;/p&gt;

&lt;p&gt;And it does all this in a way that is relatively simple and didn't require a ton of new code under the hood, either.&lt;/p&gt;

&lt;p&gt;This new feature will ship with MiniScript 2 Preview 6 (probably tomorrow).  If you use &lt;a href="https://miniscript.org/cmdline/" rel="noopener noreferrer"&gt;command-line MiniScript&lt;/a&gt;, or would like to, keep your eye on the &lt;a href="https://github.com/JoeStrout/miniscript2/releases/" rel="noopener noreferrer"&gt;releases&lt;/a&gt; page, and give it a try!&lt;/p&gt;

</description>
      <category>miniscript</category>
      <category>programming</category>
      <category>performance</category>
      <category>news</category>
    </item>
    <item>
      <title>Announcing MiniScript 2 Preview Builds!</title>
      <dc:creator>JoeStrout</dc:creator>
      <pubDate>Thu, 18 Jun 2026 00:03:03 +0000</pubDate>
      <link>https://dev.to/joestrout/announcing-miniscript-2-preview-builds-2p40</link>
      <guid>https://dev.to/joestrout/announcing-miniscript-2-preview-builds-2p40</guid>
      <description>&lt;p&gt;As announced in our &lt;a href="https://dev.to/joestrout/miniscript-road-map-for-2026-17mh"&gt;MiniScript Road Map for 2026&lt;/a&gt;, the big push this year is working on &lt;strong&gt;MiniScript version 2.0&lt;/strong&gt;.  This first major update to the MiniScript language will be substantially faster than MiniScript 1.x, and include some important new language features too.&lt;/p&gt;

&lt;p&gt;I'm pleased to say it's going very well -- we have MiniScript 2 written in both C# and C++ now (in a more clever way than before), and it's right on schedule, or even ahead.&lt;/p&gt;

&lt;p&gt;If you are impatient and want to download MiniScript 2 immediately, please do!  You can find the latest releases &lt;a href="https://github.com/JoeStrout/miniscript2/releases" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Improved REPL
&lt;/h2&gt;

&lt;p&gt;The first thing you'll notice when you run MiniScript 2 interactively (i.e., without giving it a script to run) is a much fancier user experience in the REPL (read-eval-print loop).&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqgswp3m61zmq2n23w38i.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqgswp3m61zmq2n23w38i.png" alt="Screen shot of MiniScript 2.0 preview 4" width="800" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are two main differences from the 1.x REPL:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Every input goes onto an &lt;code&gt;_in&lt;/code&gt; list (as a string); every result goes onto an &lt;code&gt;_out&lt;/code&gt; list (as whatever data type the result was). You can refer to these in your code, which is often quite convenient when you want to build on a previous result, write the whole input history out to a file, etc.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Terminal control codes are used to display less-relevant text (like the initial version info and input/output labels) in subdued text, your inputs as ordinary text, and outputs as bold text.  This helps you focus on the most important info (and is also quite pretty!).&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  New &lt;code&gt;error&lt;/code&gt; Data Type
&lt;/h2&gt;

&lt;p&gt;Error handling in MiniScript 1.x was rather weak; mostly it involved functions returning something unexpected when things went wrong, like &lt;code&gt;null&lt;/code&gt; or a string error message instead of the usual result map.&lt;/p&gt;

&lt;p&gt;After a lot of community discussion (and yes, we &lt;em&gt;did&lt;/em&gt; consider exceptions and try/catch), we settled on an approach to error handling that I think is very elegant.  There is a new &lt;code&gt;error&lt;/code&gt; data type, equal in status to &lt;code&gt;number&lt;/code&gt;, &lt;code&gt;string&lt;/code&gt;, &lt;code&gt;list&lt;/code&gt;, &lt;code&gt;map&lt;/code&gt;, etc.  Error values have some special behaviors: trying to &lt;em&gt;use&lt;/em&gt; an error value in almost any way will terminate your program, but you can inspect it to see what the error is, where in the code it occurred, etc.&lt;/p&gt;

&lt;p&gt;Read more about this (and other features) in the &lt;a href="https://github.com/JoeStrout/miniscript2/blob/main/notes/LANGUAGE_CHANGES.md" rel="noopener noreferrer"&gt;Language Changes doc&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frozen Maps &amp;amp; Lists
&lt;/h2&gt;

&lt;p&gt;Another language enhancement in 2.0 is &lt;em&gt;frozen lists and maps&lt;/em&gt;.  Lists and maps are normally "mutable," which means they can be changed in place; if you have two references to the same list, and you change the list via one of them, you see the change in the other.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; _in[17]: a = [1,2,3]

 _in[18]: b = a

 _in[19]: a[0] = 999

 _in[20]: b
_out[20]: [999, 2, 3]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is often exactly what you want.  But sometimes you want to build a list or map that &lt;em&gt;can't&lt;/em&gt; be changed; i.e. is "immutable".  In Python, they have a whole other data type for an immutable list (the "tuple"), with different syntax, just for this purpose.&lt;/p&gt;

&lt;p&gt;In MiniScript 2, you can instead &lt;em&gt;freeze&lt;/em&gt; a list or map.  A frozen list or map is immutable and can't be changed.  Some intrinsic APIs return frozen maps now, like &lt;code&gt;version&lt;/code&gt; for example.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; _in[21]: version 
_out[21]: {"miniscript": "2.0", "buildDate": "2026-06-17", "platform": 
"macOS 13.6.4", "host": "2.0 Preview", "hostName": "Command-Line (Unix)", 
"hostInfo": "https://miniscript.org/cmdline/"}

 _in[22]: version.host = "2.1"
Runtime Error: Attempt to modify a frozen map
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;MiniScript will also use a frozen copy of a list or map when you use it as a map key, since mutating a map key is very bad juju.&lt;/p&gt;

&lt;p&gt;This is one of those refinements that new users probably won't even notice, but for serious MiniScript users, it will save a lot of headaches.&lt;/p&gt;

&lt;h2&gt;
  
  
  Function Notes &amp;amp; &lt;code&gt;info&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Another nifty new feature of MiniScript two is &lt;em&gt;function notes&lt;/em&gt;.  If the first statement in a function evaluates to a constant string, then this string is stored on the function, and can be accessed via the new &lt;code&gt;info&lt;/code&gt; intrinsic, like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; _in[4]: f = function(x,y)
    ...:   "Return the magnitude of vector x,y"
    ...:   return sqrt(x^2 + y^2)
    ...:   end function

 _in[7]: info(@f)
_out[7]: {"type": "funcRef", "name": "f", "note": "Return the magnitude 
of vector x,y", "params": [{"name": "x", "default": null}, {"name": "y", 
"default": null}], "closure": 1}

 _in[10]: info(@f).note
_out[10]: Return the magnitude of vector x,y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This provides a standard, convenient place to give a little hint or reminder to users about what the function does.  (Note to self: I'll need to go through all the &lt;a href="https://github.com/JoeStrout/minimicro-sysdisk" rel="noopener noreferrer"&gt;/sys disk&lt;/a&gt; modules and add function notes!)&lt;/p&gt;

&lt;h2&gt;
  
  
  Improved Performance
&lt;/h2&gt;

&lt;p&gt;I already discussed performance in our &lt;a href="https://dev.to/joestrout/miniscript-roadmap-update-march-2026-41a4"&gt;March update&lt;/a&gt;, so I won't repeat that here.  Suffice to say, MiniScript 2.0 is many times faster than 1.x, comparable to Python, and we still have plenty of opportunities for pushing it further.&lt;/p&gt;

&lt;h2&gt;
  
  
  Right On Track
&lt;/h2&gt;

&lt;p&gt;The schedule from December laid out these milestones:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Date&lt;/th&gt;
&lt;th&gt;Milestone&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2026 Q1&lt;/td&gt;
&lt;td&gt;MS2 compiles &amp;amp; runs a subset of MiniScript&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2026 Q2&lt;/td&gt;
&lt;td&gt;MS2 feature complete (whole language implemented)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2026 Q3&lt;/td&gt;
&lt;td&gt;MS2 testing, refinement, &amp;amp; polish&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2026 Q4&lt;/td&gt;
&lt;td&gt;MS2 released 🥳&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;We're at the end of Q2 now, and the first two steps above are done.  A lot of stuff in the "testing, refinement, &amp;amp; polish" category has already been done too (for example, the terminal colors/styles and in/out value lists in the REPL).  So we're actually a little ahead of schedule.  It's time now for some serious testing -- but we're also going to start in on Raylib bindings within the next month, which wasn't expected until Q2.&lt;/p&gt;

&lt;h2&gt;
  
  
  Please Help!
&lt;/h2&gt;

&lt;p&gt;Did I mention that it's now &lt;strong&gt;time for some serious testing&lt;/strong&gt;?  That means you!  I will do what I can, but I can't do it all by myself.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fms0pe00ve7j9pl25gaaa.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fms0pe00ve7j9pl25gaaa.gif" alt="That's why it's got to be you!" width="500" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(Indeed, we wouldn't be where we are today without some very helpful testing of Windows and Linux builds by Discord users BibleClinger, minerobber, shellrider, and MoTrix -- thanks guys!)&lt;/p&gt;

&lt;p&gt;So please download the preview release for your platform, and take it for a spin.  Throw some of your older scripts at it.  Write some new scripts.  Explore the &lt;a href="https://github.com/JoeStrout/miniscript2/blob/main/notes/LANGUAGE_CHANGES.md" rel="noopener noreferrer"&gt;new language features&lt;/a&gt;.  Try to break it!  This is a large amount of brand new code, much of it quite complex, so there are almost certainly bugs to be found.&lt;/p&gt;

&lt;p&gt;When you find a problem, either bring it up on &lt;a href="https://discord.gg/7s6zajx" rel="noopener noreferrer"&gt;Discord&lt;/a&gt; (in the &lt;strong&gt;#miniscript-2&lt;/strong&gt; channel), or file an issue &lt;a href="https://github.com/JoeStrout/miniscript2/issues" rel="noopener noreferrer"&gt;on GitHub&lt;/a&gt;.  Do the same if you have some suggestion or feature request -- we're &lt;em&gt;mostly&lt;/em&gt; feature-frozen at this point, but it's not too late for small refinements, especially if they bring important quality-of-life improvements.&lt;/p&gt;

&lt;p&gt;I hope you're excited as I am for this major milestone.  MiniScript 2 unlocks all the other cool stuff in the &lt;a href="https://dev.to/joestrout/miniscript-road-map-for-2026-17mh"&gt;Road Map&lt;/a&gt;.  Let's go!!&lt;/p&gt;

</description>
      <category>miniscript</category>
      <category>programming</category>
      <category>gamedev</category>
      <category>devops</category>
    </item>
    <item>
      <title>MiniScript Weekly News — June 05, 2026</title>
      <dc:creator>JoeStrout</dc:creator>
      <pubDate>Fri, 05 Jun 2026 18:12:46 +0000</pubDate>
      <link>https://dev.to/joestrout/miniscript-weekly-news-june-05-2026-1l0d</link>
      <guid>https://dev.to/joestrout/miniscript-weekly-news-june-05-2026-1l0d</guid>
      <description>&lt;h2&gt;
  
  
  Development Updates
&lt;/h2&gt;

&lt;p&gt;MiniScript 2 kept moving forward this week with a solid round of cleanup and polish. The dev log mentions Unicode improvements, faster string handling, O(1) intrinsic lookup, a &lt;code&gt;!help&lt;/code&gt; metacommand for the REPL, and a few opcode / naming cleanups to make the internals more consistent.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Dev log: &lt;a href="https://github.com/JoeStrout/miniscript2" rel="noopener noreferrer"&gt;JoeStrout/miniscript2&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There was also useful progress on cross-platform builds. After some back-and-forth with compiler quirks, the project is now building on more than one platform, and Joe is weighing the best Windows strategy going forward: MSVC, MinGW-w64, or potentially clang-cl.  &lt;/p&gt;

&lt;p&gt;The Mini Micro sysdisk also got a nice little refactor. The LCARS demo now has its app modules split into &lt;code&gt;/sys/lcarsApps&lt;/code&gt;, and the new structure can also load modules from &lt;code&gt;/usr/lcarsApps&lt;/code&gt;, opening the door for community-made add-ons.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Commit: &lt;a href="https://github.com/JoeStrout/minimicro-sysdisk/commit/9fdc95a" rel="noopener noreferrer"&gt;Extract LCARS app modules into sys/lcarsApps&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Trey Tomes has been building a Mini Micro SVG experiment, and it’s looking really fun. He shared parser and renderer work for circles, colors, and XML handling, along with a constellation-style SVG demo — a great example of diving into a new graphics idea in MiniScript.&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%2Fl2z0yvhc2wtjlm8lh7fu.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%2Fl2z0yvhc2wtjlm8lh7fu.png" alt="Screenshot of SVG renderer in action" width="800" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Parser: &lt;a href="https://github.com/treytomes/micro-svg/blob/main/parseSvgColor.ms" rel="noopener noreferrer"&gt;parseSvgColor.ms&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;XML helper: &lt;a href="https://github.com/treytomes/micro-svg/blob/main/xml.ms" rel="noopener noreferrer"&gt;xml.ms&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Renderer: &lt;a href="https://github.com/treytomes/micro-svg/blob/main/render.ms" rel="noopener noreferrer"&gt;render.ms&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We also saw a new MiniScript-powered game called &lt;em&gt;Touhou Creator&lt;/em&gt; on Steam, which is exciting news for the ecosystem. Huge congrats to hachimi for sharing it — always wonderful to see MiniScript reaching a broader audience.&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%2Fe25a7jd0p5gynqgkrfzx.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%2Fe25a7jd0p5gynqgkrfzx.png" alt="Screenshot of Touhou Creator" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Steam link: &lt;a href="https://store.steampowered.com/app/4191130/_/" rel="noopener noreferrer"&gt;Store page&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;A few newcomers stopped by looking for tutorials and next steps, and the community had some good recommendations ready. Joe pointed people toward the Mini Micro getting-started guide, the intro-to-programming resource, and the language try-it page, while also reminding everyone that MiniScript is best learned by doing.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://miniscript.org/wiki/How_to_get_started_with_Mini_Micro" rel="noopener noreferrer"&gt;How to get started with Mini Micro&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://introtocomputerprogramming.online/#cover" rel="noopener noreferrer"&gt;Intro to Computer Programming&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://miniscript.org/tryit/" rel="noopener noreferrer"&gt;Try-It!&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There was also some useful discussion around tooling and distribution. People talked about a potential Lutris runner for Mini Micro on Linux, and Joe clarified that a Mini Micro mobile version is still on the roadmap, just not ready yet.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Roadmap update: &lt;a href="https://dev.to/joestrout/miniscript-roadmap-update-march-2026-41a4"&gt;MiniScript roadmap update — March 2026&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Events &amp;amp; Outreach
&lt;/h2&gt;

&lt;p&gt;A new Micro Jam was announced with an ANIMALS theme, which sounds like a great excuse to explore Mini Micro’s built-in sprite resources. If you’ve been waiting for a gentle prompt to make something small and playful, this is a lovely one.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Jam: &lt;a href="https://itch.io/jam/micro-jam-059" rel="noopener noreferrer"&gt;Micro Jam #059 — ANIMALS&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On the outreach side, Dat_One_Dev reported encouraging movement on getting Mini Micro covered by GameFromScratch. It’s always great to see community members helping spread the word beyond our usual circles.  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Channel: &lt;a href="https://youtube.com/@gamefromscratch?si=sTPFK_Di_zZm6m8u" rel="noopener noreferrer"&gt;GameFromScratch on YouTube&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s it for this week — thanks to everyone building, testing, sharing, and welcoming new folks. 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/slop-jam-2-electric-boogaloo" rel="noopener noreferrer"&gt;Slop Jam 2: Electric Boogaloo&lt;/a&gt;&lt;/strong&gt; (starts 2026-06-12 22:00:00) — An anything-goes, low-pressure jam with no engine restrictions and a theme revealed at the start, making it a great place to whip up a quirky 2D, pixel, or text-based game over a weekend.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/the-demo" rel="noopener noreferrer"&gt;The Demo Jam&lt;/a&gt;&lt;/strong&gt; (starts 2026-06-07 23:00:00) — A strong fit for a retro-style, bite-sized vertical slice with lots of room for polished presentation, teaser content, and playful demo-only limitations like locked features or a mock ‘full version’ hook.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/turtley-in-love-pride-2026" rel="noopener noreferrer"&gt;Turtley in Love - Pride 2026&lt;/a&gt;&lt;/strong&gt; (starts 2026-06-12 20:00:00) — A one-week Pride-themed jam with a cozy, celebratory vibe and an open theme makes this a great chance to create something heartfelt, playful, and approachable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/district-jam-7" rel="noopener noreferrer"&gt;District Jam VII&lt;/a&gt;&lt;/strong&gt; (starts 2026-06-12 23:00:00) — A relaxed, short-form jam with any engine allowed and no technical constraints, making it an excellent chance to build a pixel-art, tile-based, or text-driven game in a friendly community setting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/tiny-game-big-twist-jam" rel="noopener noreferrer"&gt;Tiny Game, Big Twist Jam&lt;/a&gt;&lt;/strong&gt; (starts 2026-06-08 11:00:00) — A 3-day jam built around small, surprising games with a meaningful twist, leaving lots of room for clever mechanics, experimental storytelling, and memorable genre shifts.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>miniscript</category>
      <category>minimicro</category>
      <category>news</category>
      <category>programming</category>
    </item>
    <item>
      <title>MiniScript Weekly News — May 27, 2026</title>
      <dc:creator>JoeStrout</dc:creator>
      <pubDate>Thu, 28 May 2026 02:05:15 +0000</pubDate>
      <link>https://dev.to/joestrout/miniscript-weekly-news-may-27-2026-5570</link>
      <guid>https://dev.to/joestrout/miniscript-weekly-news-may-27-2026-5570</guid>
      <description>&lt;h2&gt;
  
  
  Development Updates
&lt;/h2&gt;

&lt;p&gt;The MiniScript 2 work continues to move forward at a brisk pace. Joe’s latest dev log shows major progress on shell intrinsics like &lt;code&gt;file&lt;/code&gt; and &lt;code&gt;import&lt;/code&gt;, plus support for &lt;code&gt;RawData&lt;/code&gt; and &lt;code&gt;GCHandle&lt;/code&gt;, while also tightening up compiler behavior around globals, &lt;code&gt;super&lt;/code&gt;, short-circuiting, and error handling. The recent commit trail is especially busy, with fixes for function storage, variable naming in conditionals, and a cleanup to remove &lt;code&gt;extern "C"&lt;/code&gt; from &lt;code&gt;CS_value_util.h&lt;/code&gt; for better compiler compatibility.&lt;/p&gt;

&lt;p&gt;There’s also been a healthy round of real-world testing against existing demos and code. In particular, &lt;code&gt;superstartrek&lt;/code&gt; has been a great stress test for edge cases, helping uncover and resolve a cluster of bugs that made the system stronger overall.&lt;/p&gt;

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

&lt;p&gt;A quick update from &lt;strong&gt;Redspark&lt;/strong&gt; on &lt;em&gt;Emberfall&lt;/em&gt;: the engine has nearly been converted to Raylib-MiniScript, and work is underway on the 3D renderer. That’s the kind of behind-the-scenes momentum that makes a future show-and-tell post especially exciting.&lt;/p&gt;

&lt;p&gt;A big shout-out to everyone helping push &lt;strong&gt;MiniScript 2&lt;/strong&gt; across different platforms. &lt;strong&gt;MoTrix&lt;/strong&gt; and &lt;strong&gt;minerobber&lt;/strong&gt; have both been digging into build issues, with fixes and PRs emerging for Linux, Ubuntu, and Windows/MSVC compatibility — a fantastic example of community-powered portability work.&lt;/p&gt;

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

&lt;p&gt;The community had a lively discussion about decorators and argument unpacking in MiniScript. Joe floated the idea of a “decorators in MiniScript” article, and the conversation turned into a practical look at wrappers, &lt;code&gt;apply&lt;/code&gt;-style functions, and how argument packing/unpacking might work without too much syntactic sugar.&lt;/p&gt;

&lt;p&gt;Mini Micro users also weighed in on documentation ideas, with suggestions ranging from a “Getting Started” guide to a whimsical 1980s-style manual for the virtual computer. Separately, Joe is exploring hardware possibilities for a future “hardware Mini Micro” setup, including Intel N100 mini-PCs and Orange Pi options.&lt;/p&gt;

&lt;h2&gt;
  
  
  Community Notes
&lt;/h2&gt;

&lt;p&gt;Welcome to all the new folks joining the server this week! It’s always nice to see more people arriving with game-dev ideas, curiosity about MiniScript, and interest in helping shape what comes next.&lt;/p&gt;

&lt;p&gt;There were also some fun project ideas in the mix, including a sci-fi cloaked-ship combat game and even a tongue-in-cheek dystopian tale about the “Spacers” versus the “Tabbers.” That kind of playful creativity is exactly what makes the MiniScript community so enjoyable.&lt;/p&gt;

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

&lt;p&gt;Joe also shared a fun new mini-project on DEV: &lt;a href="https://dev.to/joestrout/where-in-the-world-am-i-53bo"&gt;Where in the World Am I?&lt;/a&gt;. It shows how to use web services and simple 3D rendering to pinpoint your location on a rotating globe.&lt;/p&gt;

&lt;p&gt;And on the Mini Micro side, Joe’s been thinking about future documentation and accessibility features, including possible TTS/STT support for Mini Micro 2. A promising model was shared here: &lt;a href="https://github.com/supertone-inc/supertonic" rel="noopener noreferrer"&gt;Supertonic&lt;/a&gt;, with voice samples at &lt;a href="https://supertone-inc.github.io/supertonic-py/voices/" rel="noopener noreferrer"&gt;supertone-inc.github.io/supertonic-py/voices&lt;/a&gt;.&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/you-can-play-this-game-jam" rel="noopener noreferrer"&gt;YOU CAN PLAY THIS GAME JAM&lt;/a&gt;&lt;/strong&gt; (starts 2026-05-30 04:00:00) — A highly accessible, beginner-friendly jam centered on pitching great ideas and designing for inclusivity, with no requirement to build a full playable prototype.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/smilejam" rel="noopener noreferrer"&gt;smilejam&lt;/a&gt;&lt;/strong&gt; (starts 2026-05-17 23:00:00) — A perfect match for quick, intimate, experimental games: short playable pieces, strong mood, prose, collage, and low-pressure creativity all line up beautifully.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/cgdct-jam-2026" rel="noopener noreferrer"&gt;Cute Girls Doing Cool Things VN Jam 2026&lt;/a&gt;&lt;/strong&gt; (starts 2026-06-01 04:00:00) — A strong fit for a story-first project: the jam’s visual novel focus, cute-character premise, and summer-blockbuster energy all lend themselves to expressive 2D scenes, branching dialogue, and stylish presentation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/never-joined-a-game-jam-game-jam" rel="noopener noreferrer"&gt;Never Joined A Game Jam Game Jam&lt;/a&gt;&lt;/strong&gt; (starts 2026-05-29 14:00:00) — A beginner-friendly, no-theme jam focused on learning by doing, with plenty of room for a straightforward top-down shooter, simple UI, scoring, and extra polish like particles or enemy variants.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/trijam-374" rel="noopener noreferrer"&gt;Trijam #374: The 3 hour game jam&lt;/a&gt;&lt;/strong&gt; (starts 2026-05-28 21:00:00) — A fast, friendly jam built around making something fun in just 3 hours, with flexible rules, room for pre-made assets, and an emphasis on simple, playable ideas that are perfect for quick 2D projects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/romance-game-jam-01" rel="noopener noreferrer"&gt;Romance Game Jam #01&lt;/a&gt;&lt;/strong&gt; (starts 2026-06-01 06:00:00) — A very welcoming romance-focused jam with a four-week window, no voting pressure, and plenty of room for anything from sweet SFW stories to weird, esoteric love games.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>miniscript</category>
      <category>minimicro</category>
      <category>programming</category>
      <category>news</category>
    </item>
    <item>
      <title>Where in the World Am I?</title>
      <dc:creator>JoeStrout</dc:creator>
      <pubDate>Wed, 20 May 2026 23:09:33 +0000</pubDate>
      <link>https://dev.to/joestrout/where-in-the-world-am-i-53bo</link>
      <guid>https://dev.to/joestrout/where-in-the-world-am-i-53bo</guid>
      <description>&lt;p&gt;There are so many fun things you can do with web services, and most of them are trivial to use in &lt;a href="https://miniscript.org/MiniMicro" rel="noopener noreferrer"&gt;Mini Micro&lt;/a&gt;.  Today, let's use a couple of these together to plot your location on a map of the world!&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding Your Place In the World
&lt;/h2&gt;

&lt;p&gt;...begins by finding your &lt;em&gt;external (or public) IP address&lt;/em&gt;.  This is the Internet Protocol address by which you are seen on the internet, outside your local network.  It's probably different from your &lt;em&gt;internal&lt;/em&gt; (or private) IP address, which is what probably appears when you look at the network settings on your computer.  We don't care how your computer is known to other computers in your house or neighborhood; we only care how packets are routed to it from the great wide world beyond.  Fire up Mini Micro (available free &lt;a href="https://miniscript.org/MiniMicro/#download" rel="noopener noreferrer"&gt;here&lt;/a&gt;, and type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http.get("https://api.ipify.org")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This should return an IP address, something like &lt;code&gt;66.212.203.27&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now, to get information about that IP address, including the city it's in and an approximate latitude/longitude, we'll use a different web service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http.get("http://ip-api.com/json/66.212.203.27")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can replace the IP address above with whatever you got from the first query.  The result will be a string of JSON code that contains your city, region, country, latitude, and longitude, along with the name of your internet service provider (ISP) and other details.&lt;/p&gt;

&lt;p&gt;Putting this all together into a little program.  Use &lt;code&gt;edit&lt;/code&gt; to enter the code editor, then paste in the following:&lt;br&gt;
&lt;/p&gt;

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

// What's my external IP address?
myIP = http.get("https://api.ipify.org")

// And where am I?
locJson = http.get("http://ip-api.com/json/" + myIP)
locInfo = json.parse(locJson)

pprint locInfo
print "You are in {city}, {region} ({country})".fill(locInfo)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run this, and it should tell you where you are (along with all those other details).  Neat, right?&lt;/p&gt;

&lt;h2&gt;
  
  
  Don't Tell Me, Show Me!
&lt;/h2&gt;

&lt;p&gt;But we can make it more fun.  Let's pinpoint you on a map of the Earth!  &lt;code&gt;edit&lt;/code&gt; your program again, delete the last two lines (&lt;code&gt;pprint&lt;/code&gt; and &lt;code&gt;print&lt;/code&gt;), and add in this additional code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mapImage = file.loadImage("/sys/pics/earth_day.jpg")

// Find the pixel coordinates of our lat/long in this image
px = (locInfo.lon + 180) / 360 * mapImage.width
py = mapImage.height - (90 - locInfo.lat) / 180 * mapImage.height

// Draw a marker (using an offscreen PixelDisplay)
g = new PixelDisplay
g.clear color.black, mapImage.width, mapImage.height
g.drawImage mapImage
g.line 0, py, g.width, py, "#00FFFF88", 3
g.line px, 0, px, g.height, "#00FFFF88", 3
g.fillEllipse px-10, py-10, 20, 20, "#00FFFFFF"
g.drawEllipse px-15, py-15, 30, 30, "#00FFFFAA"
g.drawEllipse px-20, py-20, 40, 40, "#00FFFF88"
markedMap = g.getImage(0, 0, g.width, g.height)

// And draw the mapImage, fit to the screen!
scale = 960/mapImage.width
gfx.drawImage markedMap,
  480 - mapImage.width*scale/2, 320 - mapImage.height*scale/2,
  mapImage.width*scale, mapImage.height*scale

s = "{city}, {region}, ({countryCode})".fill(locInfo)
text.row = 2
text.column = 34 - s.len/2
print s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result, if you happen to be my neighbor right now, 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%2Fcfvyunv5oihji1vifsop.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%2Fcfvyunv5oihji1vifsop.png" alt="World map with Tucson pinpointed" width="800" height="537"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The trick here is knowing that the map image uses a standard &lt;strong&gt;equiprectangular projection&lt;/strong&gt;, where longitude and latitude both map linearly to x and y.  That lets us convert from lat/long to pixel coordinates with some reasonably simple math.  Most of the code above is then drawing the pinpoint lines and circles on top of the map.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Note: if you are reading this in the future and live somewhere other than Earth, this code will need adjustment.)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Now in Animated 3D!
&lt;/h2&gt;

&lt;p&gt;Let's take it one step further: combine what you've done so far with the &lt;code&gt;globe&lt;/code&gt; demo!  Follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Save your program, if you haven't already.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;edit "/sys/demo/globe"&lt;/code&gt; to load the globe demo code.&lt;/li&gt;
&lt;li&gt;Select All (&lt;code&gt;^A&lt;/code&gt;) and then Copy (&lt;code&gt;^C&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Exit the editor, then edit your program.&lt;/li&gt;
&lt;li&gt;Scroll to the bottom, and Paste (&lt;code&gt;^V&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Find the line (at the top of the pasted code) that says &lt;code&gt;bigMapImg = file.loadImage("/sys/pics/earth_day.jpg")&lt;/code&gt;, and change it to just say &lt;code&gt;bigMapImg = markedMap&lt;/code&gt; instead.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's it.  Now run your program, and you should see your location on a beautiful rotating globe.&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%2F7rai0o20jhny387el2n1.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%2F7rai0o20jhny387el2n1.gif" alt="Globe animation with Tucson pinpointed" width="434" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Never Be Lost Again
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;http&lt;/code&gt; module is an often-overlooked gem in the Mini Micro APIs.  With one little call we can get our external IP address, and with a second little call, get all sorts of information about that, including the info we need to place ourselves on a map.  We also looked at how you are able — nay, &lt;em&gt;encouraged!&lt;/em&gt; — to steal from the demo code and make it your own.&lt;/p&gt;

&lt;p&gt;What do you think of this?  Let me know in the comments below!&lt;/p&gt;

</description>
      <category>programming</category>
      <category>miniscript</category>
      <category>minimicro</category>
      <category>geolocation</category>
    </item>
    <item>
      <title>MiniScript Weekly News — May 14, 2026</title>
      <dc:creator>JoeStrout</dc:creator>
      <pubDate>Thu, 14 May 2026 20:24:30 +0000</pubDate>
      <link>https://dev.to/joestrout/miniscript-weekly-news-may-14-2026-454h</link>
      <guid>https://dev.to/joestrout/miniscript-weekly-news-may-14-2026-454h</guid>
      <description>&lt;h2&gt;
  
  
  Development Updates
&lt;/h2&gt;

&lt;p&gt;MiniScript 2.0 saw a bunch of steady progress this week, especially around garbage collection and string handling. Joe landed a new &lt;code&gt;gc&lt;/code&gt; intrinsic with &lt;code&gt;gc.collect&lt;/code&gt; and &lt;code&gt;gc.stats&lt;/code&gt; methods, plus fixes for runtime error reporting and several VM/refactoring issues in the &lt;code&gt;miniscript2&lt;/code&gt; branch. The dev log and recent commits are worth a look if you enjoy following the architecture work: &lt;a href="https://github.com/JoeStrout/miniscript2/blob/main/notes/DEV_LOG.md" rel="noopener noreferrer"&gt;DEV_LOG&lt;/a&gt;, &lt;a href="https://github.com/JoeStrout/miniscript2/commits/main/" rel="noopener noreferrer"&gt;recent commits&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A notable performance decision also got locked in: separate &lt;code&gt;int&lt;/code&gt; storage was removed, and all numbers are now &lt;code&gt;double&lt;/code&gt;. Joe reported no meaningful benchmark difference, so the simpler design wins here — a great example of keeping the internals elegant without sacrificing speed.&lt;/p&gt;

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

&lt;p&gt;If you’ve been meaning to get started with Mini Micro, Joe’s been actively pointing newcomers toward the quickstart and the built-in demos. The best launch point is still the getting-started guide: &lt;a href="https://miniscript.org/wiki/How_to_get_started_with_Mini_Micro" rel="noopener noreferrer"&gt;How to get started with Mini Micro&lt;/a&gt;, and Joe specifically reminded folks to try running things like &lt;code&gt;run "asteroids"&lt;/code&gt; in &lt;code&gt;/sys/demo&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There was also a fun new wave of interest around MiniScript on Godot. Community members shared the extension repo &lt;a href="https://github.com/Mo-Tx/Godot-X-MiniScript" rel="noopener noreferrer"&gt;Godot-X-MiniScript&lt;/a&gt; and a broader GitHub search for related projects: &lt;a href="https://github.com/search?q=miniscript+godot&amp;amp;type=repositories" rel="noopener noreferrer"&gt;MiniScript + Godot repos&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;Several great technical conversations happened this week around embedding and runtime design. People asked about using MiniScript as an embedded language in games, and Joe pointed to the Unity package while noting that the Unity plugin is a bit behind and may need the latest source folder from GitHub. He also shared the language quick reference: &lt;a href="https://miniscript.org/files/MiniScript-QuickRef.pdf" rel="noopener noreferrer"&gt;MiniScript QuickRef PDF&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;On the Mini Micro side, there was a lively discussion about performance benchmarks, palette handling, and low-level 6502-inspired hardware ideas. Joe also highlighted a useful public API list providing online services usable from Mini Micro apps: &lt;a href="https://github.com/public-apis/public-apis" rel="noopener noreferrer"&gt;public-apis/public-apis&lt;/a&gt;.&lt;/p&gt;

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

&lt;p&gt;Joe published a new Mini Micro tutorial, &lt;a href="https://dev.to/joestrout/hwydt-turning-the-page-24dm"&gt;HWYDT: Turning the Page&lt;/a&gt;, showing how to build a convincing page-flip animation using nothing but math, sprites, and texture mapping. It’s a fun, practical example of what Mini Micro can do — and a nice companion to &lt;a href="https://dev.to/joestrout/hwydt-swinging-from-vines-31ei"&gt;HWYDT: Swinging from Vines&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks for reading, and 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/make-literally-anything-jam-2026" rel="noopener noreferrer"&gt;Make Literally Anything Jam '26&lt;/a&gt;&lt;/strong&gt; (starts 2026-05-15 04:00:00) — A wildly open-ended jam with a loose theme and total freedom to make almost anything you want, perfect for experimenting, getting weird, or shipping something small and fun in just a week.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/micro-jam-058" rel="noopener noreferrer"&gt;Micro Jam 058: Tides ($400+ Prizes)&lt;/a&gt;&lt;/strong&gt; (starts 2026-05-16 02:00:00) — A highly approachable theme with lots of room for clever interpretation, making it ideal for a compact 2D game built around atmosphere, movement, or shifting conditions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/utc-arcadia-jam-4" rel="noopener noreferrer"&gt;ARCADIA JAM #4&lt;/a&gt;&lt;/strong&gt; (starts 2026-05-15 17:00:00) — A short, open 48-hour jam with permissive rules and no engine restrictions, making it a great chance to build a polished web-friendly game and compete on art, gameplay, and originality.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/the-shorter-the-better" rel="noopener noreferrer"&gt;The Shorter, The Better&lt;/a&gt;&lt;/strong&gt; (starts 2026-05-15 17:30:00) — A very friendly fit for a compact, story-driven game: the 5-minute limit encourages tight pacing, a single ending keeps scope manageable, and web playability makes it easy to share and test.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/metroidvania-month-super-32" rel="noopener noreferrer"&gt;MVM 32 - Super edition&lt;/a&gt;&lt;/strong&gt; (starts 2026-05-16 02:00:00) — A long-running metroidvania-focused jam with a relaxed three-month window, open engine rules, and room to iterate on exploration, abilities, and level design.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://itch.io/jam/campfire-creators-jam-2" rel="noopener noreferrer"&gt;Campfire Creators Jam #2&lt;/a&gt;&lt;/strong&gt; (starts 2026-05-21 21:00:00) — A highly flexible jam with a retro-friendly campfire theme, welcoming everything from cozy story games to survival, puzzle, and strategy concepts while only requiring a single animated campfire sprite.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>miniscript</category>
      <category>minimicro</category>
      <category>programming</category>
      <category>news</category>
    </item>
    <item>
      <title>HWYDT: Turning the Page</title>
      <dc:creator>JoeStrout</dc:creator>
      <pubDate>Wed, 13 May 2026 17:23:37 +0000</pubDate>
      <link>https://dev.to/joestrout/hwydt-turning-the-page-24dm</link>
      <guid>https://dev.to/joestrout/hwydt-turning-the-page-24dm</guid>
      <description>&lt;p&gt;On the MiniScript Discord this week, one of our users (Luckythespacecat) shared an animation he made for his Steam game &lt;em&gt;Wishlist Boreal&lt;/em&gt;.  It looks like an open book, with the page turning as if advancing through the book, including a nice paper-ish curl as it goes.  That led to another user (&lt;a class="mentioned-user" href="https://dev.to/dslower"&gt;@dslower&lt;/a&gt;) pointing out &lt;a href="https://www.instagram.com/reel/DUQ4KC2EnHe/?igsh=MWNibWZmZjRxb2Y5bA==" rel="noopener noreferrer"&gt;this Instagram reel&lt;/a&gt; in which somebody makes a texture-mapped page flip animation, also with a nice curvy page.  &lt;/p&gt;

&lt;p&gt;And then he had the audacity to opine that you &lt;em&gt;couldn't do such a thing in Mini Micro&lt;/em&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%2Fpu1bcjc0pm3bt4dqxarw.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%2Fpu1bcjc0pm3bt4dqxarw.gif" alt="Oh really?" width="350" height="306"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Challenge Accepted
&lt;/h2&gt;

&lt;p&gt;In fact we &lt;em&gt;can&lt;/em&gt; do such things in Mini Micro!  The trick is just to break the curving surface up into flat quadrilaterals, and then render each quad as a Sprite.&lt;/p&gt;

&lt;p&gt;Normally in these tutorials I walk through developing the code step by step — build a little, test a little.  But this program is short enough that I think I'll try the opposite: present the full code, and then just explain how it works.&lt;/p&gt;

&lt;p&gt;So, for maximum fun, fire up your copy of &lt;a href="https://miniscript.org/MiniMicro/#download" rel="noopener noreferrer"&gt;Mini Micro&lt;/a&gt;, &lt;code&gt;edit&lt;/code&gt; a new program, and paste in the following code.&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
display(2).mode = displayMode.pixel
gfx = display(2)
gfx.clear color.clear
debug = false

pageTextures = [
  file.loadImage("page1.png"),
  file.loadImage("page2.png")]

pageWidth = 250
pageHeight = 400
xDivs = [0, 0.025, 0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 0.7, 1]

pageSprites = []
lastU = 0
for i in range(1, xDivs.len - 1)
    sp = new Sprite
    sp.image = pageTextures[0]
    sp.setUVs [[lastU, 0], [xDivs[i], 0], [xDivs[i],1], [lastU, 1]]
    pageSprites.push sp
    lastU = xDivs[i]
end for
display(4).sprites += pageSprites

getPolarPoint = function(pagePt, t, forward=true)
    radius = pageWidth * pagePt * (cos(t*2*pi)*0.2 + 0.9)
    if not forward then
        t2 = t^pagePt
        angle = mathUtil.lerp(0, 180, (t+t2)/2)
    else
        t = 1 - t
        t2 = t^pagePt
        angle = mathUtil.lerp(180, 0, (t+t2)/2)
    end if
    return [radius, angle]
end function

polarToXY = function(polarPt, baseX=480, baseY=320)
    radius = polarPt[0]
    ang = polarPt[1] * pi/180
    x = baseX + cos(ang) * radius
    y = baseY + sin(ang) * radius
    // apply a minimum representing the thickness of the pages
    // underneath, leaving a "dip" at the binding in the center
    thickness = 16
    q = abs(x - baseX) / pageWidth * 10
    if q &amp;lt; 1 then
        thickness *= sqrt(1 - (1-q)^2)  // (section of a circle)
    end if
    y = mathUtil.max(y, baseY + thickness)
    return [x,y]
end function

framePoly = function(corners)
    for i in range(-1, corners.len-2)
        p0 = corners[i]
        p1 = corners[i+1]
        gfx.line p0[0], p0[1], p1[0], p1[1], "#FF00FF", 2
    end for
end function

render = function(t, forward=true)
    if debug then gfx.clear color.clear
    topPts = []
    botPts = []
    for pagePt in xDivs
        p = getPolarPoint(pagePt, t, forward)
        topPts.push polarToXY(p, 480, 50 + pageHeight)
        botPts.push polarToXY(p, 480, 50)
    end for
    for i in pageSprites.indexes
        pageSprites[i].setCorners [
          [botPts[i][0], botPts[i][1]],
          [botPts[i+1][0], botPts[i+1][1]],
          [topPts[i+1][0], topPts[i+1][1]],
          [topPts[i][0], topPts[i][1]] ]
        if topPts[i+1][0] &amp;gt;= topPts[i][0] then
            // front surface
            pageSprites[i].image = pageTextures[0]
            u0 = xDivs[i]
            u1 = xDivs[i+1]
        else
            // back surface
            pageSprites[i].image = pageTextures[1]          
            u0 = 1 - xDivs[i]
            u1 = 1 - xDivs[i+1]
        end if
        sp.setUVs [[u0, 0], [u1, 0], [u1, 1], [u0, 1]]
        if debug then framePoly pageSprites[i].corners
    end for
end function

pageState = 0  // 0: page on the right; 1: flipped to the left
render pageState

turnPage = function(toState=1)
    delta = sign(toState - 0.5) * 0.02
    while pageState != toState and not key.available
        yield
        outer.pageState += delta
        if pageState &amp;lt; 0 or pageState &amp;gt; 1 then
            outer.pageState = mathUtil.clamp(pageState)
        end if
        render pageState, toState
    end while
end function

// Main loop
while true
    k = key.get
    if k == char(27) or k == "q" then break  // Esc or Q to quit
    if k == "d" then
        debug = not debug
        gfx.clear color.clear
        render pageState
    end if
    if k == char(17) then turnPage 1
    if k == char(18) then turnPage 0
    if k == char(10) or k == " " then turnPage not pageState
end while
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll also need two page images: one for the front, and one for the back of the turning page.  You can use whatever you like, but to match my demo, download these and save them as &lt;code&gt;page1.png&lt;/code&gt; and &lt;code&gt;page2.png&lt;/code&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%2Fz4mz3f4vnrui3ddytt6g.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%2Fz4mz3f4vnrui3ddytt6g.png" alt="page1.png" width="553" height="746"&gt;&lt;/a&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%2Fnypyhj6c42zn458rpxx0.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%2Fnypyhj6c42zn458rpxx0.png" alt="page2.png" width="553" height="746"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now &lt;code&gt;run&lt;/code&gt; the program, and press the left/right arrow keys to flip the page.  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%2Fnbxl611vr3ta7pazs37d.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%2Fnbxl611vr3ta7pazs37d.gif" alt="Page-flip animation in Mini Micro" width="604" height="586"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Neat, right?&lt;/p&gt;

&lt;h2&gt;
  
  
  Carving up the Page
&lt;/h2&gt;

&lt;p&gt;The secret sauce here is to divide the page into vertical strips, each of which is flat.  In the demo, if you press the "d" (for "debug") key, it will actually draw the outlines of those quads, so you can see them.&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%2F5kd7iwsbm8ddumun141a.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%2F5kd7iwsbm8ddumun141a.png" alt="Screen shot of curly page with quad outlines" width="310" height="511"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can divide the page however you like, but in my animation, I found that the curvature is much greater near the book binding (the left side of the original page) than on the outer (right) side of the page.  So I made the divisions smaller on the left, and larger on the right.  If we use &lt;code&gt;0&lt;/code&gt; to refer to the left side of the page image, and &lt;code&gt;1&lt;/code&gt; to refer to the right, then a sensible set of key points (dividing lines between the quads) might be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;xDivs = [0, 0.025, 0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 0.7, 1]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;...which in fact you will find as line 15 in the code.&lt;/p&gt;

&lt;p&gt;To render any textured quad in Mini Micro, just make a Sprite, set its &lt;code&gt;image&lt;/code&gt; property to the texture image, and then use &lt;code&gt;setCorners&lt;/code&gt; and &lt;code&gt;setUVs&lt;/code&gt; to position the quad on the screen, and select what part of the texture it displays.  &lt;code&gt;setCorners&lt;/code&gt; takes a list of four &lt;code&gt;[x,y]&lt;/code&gt; pairs, in screen coordinates.  &lt;code&gt;setUVs&lt;/code&gt; takes a list of four &lt;code&gt;[u,v]&lt;/code&gt; pairs, where &lt;code&gt;u&lt;/code&gt; goes from 0-1 horizontally across the image (exactly like our &lt;code&gt;xDivs&lt;/code&gt; values above), and &lt;code&gt;v&lt;/code&gt; goes from 0-1 up the image vertically.&lt;/p&gt;

&lt;p&gt;If you need a review on &lt;code&gt;setCorners&lt;/code&gt; and &lt;code&gt;setUVs&lt;/code&gt;, play around with the &lt;strong&gt;spriteStretch&lt;/strong&gt; demo found in &lt;code&gt;/sys/demo/&lt;/code&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%2Fb8e6wwxpmbd01w45aq9m.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%2Fb8e6wwxpmbd01w45aq9m.png" alt="Screen shot of spriteStretch demo" width="800" height="407"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In our page-flip demo, you'll find a loop at lines 17-26 which prepares our sprites based on the &lt;code&gt;xDivs&lt;/code&gt; we defined above.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pageSprites = []
lastU = 0
for i in range(1, xDivs.len - 1)
    sp = new Sprite
    sp.image = pageTextures[0]
    sp.setUVs [[lastU, 0], [xDivs[i], 0], [xDivs[i],1], [lastU, 1]]
    pageSprites.push sp
    lastU = xDivs[i]
end for
display(4).sprites += pageSprites
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Later (starting at line 65), we have a &lt;code&gt;render&lt;/code&gt; function that updates those same sprites to reflect the current state of the animation.  It begins by building a set of &lt;code&gt;x,y&lt;/code&gt; coordinates for the points along the top and bottom of the page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    topPts = []
    botPts = []
    for pagePt in xDivs
        p = getPolarPoint(pagePt, t, forward)
        topPts.push polarToXY(p, 480, 50 + pageHeight)
        botPts.push polarToXY(p, 480, 50)
    end for
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The heavy lifting here is being done by &lt;code&gt;getPolarPoint&lt;/code&gt; and &lt;code&gt;polarToXY&lt;/code&gt;, which we'll get to in a moment.  For now, just understand that we're taking our &lt;code&gt;xDivs&lt;/code&gt; points along the page, and converting them into screen coordinates for the top (&lt;code&gt;topPts&lt;/code&gt;) and bottom (&lt;code&gt;botPts&lt;/code&gt;) of the page.  Then we just use those to update the corners of each corresponding sprite.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    for i in pageSprites.indexes
        pageSprites[i].setCorners [
          [botPts[i][0], botPts[i][1]],
          [botPts[i+1][0], botPts[i+1][1]],
          [topPts[i+1][0], topPts[i+1][1]],
          [topPts[i][0], topPts[i][1]] ]
    end for
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we wanted to show the same content (but reversed) on the back of the page, this would be all we need.  But really we want to show a different image on the back of the page, and because the sprites are flipped horizontally by that point, we need to invert the U coordinates as well.  So we need to insert some extra code into the above &lt;code&gt;for&lt;/code&gt; loop to update the image and UV coordinates:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        if topPts[i+1][0] &amp;gt;= topPts[i][0] then
            // front surface
            pageSprites[i].image = pageTextures[0]
            u0 = xDivs[i]
            u1 = xDivs[i+1]
        else
            // back surface
            pageSprites[i].image = pageTextures[1]          
            u0 = 1 - xDivs[i]
            u1 = 1 - xDivs[i+1]
        end if
        sp.setUVs [[u0, 0], [u1, 0], [u1, 1], [u0, 1]]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now each section not only draws in the right position, but also shows the correct part of the right texture, depending on whether it's flipped.&lt;/p&gt;

&lt;h2&gt;
  
  
  Computing the Page Shape
&lt;/h2&gt;

&lt;p&gt;For me, drawing the texture-mapped quads was the easy part.  The hard part was actually animating the shape of the page throughout the flip.&lt;/p&gt;

&lt;p&gt;You could just use keyframe animation: that is, make a tool (similar to that spriteStretch demo) that lets you drag the top and bottom points around by hand, and record the correct position for key frames throughout the flip.  Alternatively, you could use some external animation tool that writes to a file you can read in your Mini Micro program.  Then just play those positions back, interpolating as needed for in-between frames.&lt;/p&gt;

&lt;p&gt;But I didn't have the patience (nor, most likely, the art skills) for all that, so I went for a more mathematical approach.  Since the page is essentially rotating around its attachment point (the left side of the unflipped page), I found it easier to think about it in polar (&lt;strong&gt;radius&lt;/strong&gt; and &lt;strong&gt;angle&lt;/strong&gt;) rather than Cartesian (&lt;strong&gt;x&lt;/strong&gt; and &lt;strong&gt;y&lt;/strong&gt;) coordinates.  Some trial and error led me to this function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;getPolarPoint = function(pagePt, t, forward=true)
    radius = pageWidth * pagePt * (cos(t*2*pi)*0.2 + 0.9)
    if not forward then
        t2 = t^pagePt
        angle = mathUtil.lerp(0, 180, (t+t2)/2)
    else
        t = 1 - t
        t2 = t^pagePt
        angle = mathUtil.lerp(180, 0, (t+t2)/2)
    end if
    return [radius, angle]
end function
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;getPolarPoint&lt;/code&gt; takes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a page point, i.e., one of those &lt;code&gt;xDivs&lt;/code&gt; points along the page from 0 (left) to (1) right&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;t&lt;/code&gt;, how far we are in the flip animation from 0 (starting position) to 1 (complete)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;forward&lt;/code&gt;, which is &lt;code&gt;true&lt;/code&gt; when flipping forward (right to left) and &lt;code&gt;false&lt;/code&gt; when flipping back the other way.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first version of this function had just &lt;code&gt;radius = pageWidth * pagePt; angle = mathUtil.lerp(0, 180, t)&lt;/code&gt; -- that is, a constant radius, and an angle that interpolates smoothly between 0 and 180 degrees.  This creates a stiff page that flips without bending.  The rest of the final code was just to fancy it up: make the radius a little smaller towards the center of the animation, and add a bit of curl by changing the angle based on how far along the page we are (and how far we are in the animation).&lt;/p&gt;

&lt;p&gt;But to actually use this, we have to convert from polar coordinates back to XY coordinates.  The basic function for that would be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;polarToXY = function(polarPt, baseX=480, baseY=320)
    radius = polarPt[0]
    ang = polarPt[1] * pi/180
    x = baseX + cos(ang) * radius
    y = baseY + sin(ang) * radius
    return [x,y]
end function
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But while I was at it, I decided to have this conversion function &lt;em&gt;also&lt;/em&gt; apply some "thickness" to the book, by calculating a minimum &lt;code&gt;Y&lt;/code&gt; that varies with our distance along the page.  This was to make the endpoints of the animation include a bit of a curl down where the page connects to the rest of the book, so it looks like an actual book with a binding, rather than a thin magazine or something.&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%2Fzeb13m3wbho1kxyzyhb9.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%2Fzeb13m3wbho1kxyzyhb9.png" alt="Close-up of bottom of book, showing binding curl" width="322" height="50"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The code for this (inserted into the function above) is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    // apply a minimum representing the thickness of the pages
    // underneath, leaving a "dip" at the binding in the center
    thickness = 16
    q = abs(x - baseX) / pageWidth * 10
    if q &amp;lt; 1 then
        thickness *= sqrt(1 - (1-q)^2)  // (section of a circle)
    end if
    y = mathUtil.max(y, baseY + thickness)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Incorporating Into Your Game
&lt;/h2&gt;

&lt;p&gt;That's all our demo does.  To incorporate this into a full game, you would need to draw the "rest" of the book (the open cover and pages underneath the turning page, and ensure that your page sprites are topmost.&lt;/p&gt;

&lt;p&gt;Also, you'll probably have more than just one (front and back page).  You might have &lt;em&gt;lots&lt;/em&gt; of pages in your book.  I would implement that with just three sets of page sprites:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one that shows the resting right-hand page&lt;/li&gt;
&lt;li&gt;one for the resting left-hand page&lt;/li&gt;
&lt;li&gt;one for the actively turning page&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At rest, you don't actually need the third one.  But as soon as it's time to turn the page, you would add it to the view.  If advancing through the book, the right-hand page is going to flip left.  So you would set your third page with the content on the right, plus the subsequent page as its back; and update the resting right-hand page to show the page after that.  Then animate.  At the end of the animation, update the left-hand page to show the same thing as the animation page, and hide the animation page.  If going backwards, you'd do something similar, but animating from left to right.&lt;/p&gt;

&lt;p&gt;I toyed with the idea of making this into its own little library on GitHub that manages multiple pages, provides different ways of specifying the page animation, etc.  But maybe it's not worth it; the core ideas are in this demo, and you can take it from here.  Let me know what you think in the comments below, or join us on Discord to discuss more.  I can't wait to see what you do with it!&lt;/p&gt;

</description>
      <category>miniscript</category>
      <category>minimicro</category>
      <category>programming</category>
      <category>gamedev</category>
    </item>
    <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;&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;/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>
  </channel>
</rss>
